1 //===-- MVEVPTBlockPass.cpp - Insert MVE VPT blocks -----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ARM.h" 10 #include "ARMMachineFunctionInfo.h" 11 #include "ARMSubtarget.h" 12 #include "MCTargetDesc/ARMBaseInfo.h" 13 #include "Thumb2InstrInfo.h" 14 #include "llvm/ADT/SmallSet.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/Statistic.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/CodeGen/MachineBasicBlock.h" 19 #include "llvm/CodeGen/MachineFunction.h" 20 #include "llvm/CodeGen/MachineFunctionPass.h" 21 #include "llvm/CodeGen/MachineInstr.h" 22 #include "llvm/CodeGen/MachineInstrBuilder.h" 23 #include "llvm/CodeGen/MachineInstrBundle.h" 24 #include "llvm/CodeGen/MachineOperand.h" 25 #include "llvm/CodeGen/ReachingDefAnalysis.h" 26 #include "llvm/IR/DebugLoc.h" 27 #include "llvm/MC/MCInstrDesc.h" 28 #include "llvm/Support/Debug.h" 29 #include <cassert> 30 #include <new> 31 32 using namespace llvm; 33 34 #define DEBUG_TYPE "arm-mve-vpt" 35 36 namespace { 37 class MVEVPTBlock : public MachineFunctionPass { 38 public: 39 static char ID; 40 41 MVEVPTBlock() : MachineFunctionPass(ID) {} 42 43 bool runOnMachineFunction(MachineFunction &Fn) override; 44 45 void getAnalysisUsage(AnalysisUsage &AU) const override { 46 AU.setPreservesCFG(); 47 AU.addRequired<ReachingDefAnalysis>(); 48 MachineFunctionPass::getAnalysisUsage(AU); 49 } 50 51 MachineFunctionProperties getRequiredProperties() const override { 52 return MachineFunctionProperties().set( 53 MachineFunctionProperties::Property::NoVRegs).set( 54 MachineFunctionProperties::Property::TracksLiveness); 55 } 56 57 StringRef getPassName() const override { 58 return "MVE VPT block insertion pass"; 59 } 60 61 private: 62 bool InsertVPTBlocks(MachineBasicBlock &MBB); 63 64 const Thumb2InstrInfo *TII = nullptr; 65 ReachingDefAnalysis *RDA = nullptr; 66 }; 67 68 char MVEVPTBlock::ID = 0; 69 70 } // end anonymous namespace 71 72 INITIALIZE_PASS(MVEVPTBlock, DEBUG_TYPE, "ARM MVE VPT block pass", false, false) 73 74 static MachineInstr *findVCMPToFoldIntoVPST(MachineInstr *MI, 75 ReachingDefAnalysis *RDA, 76 unsigned &NewOpcode) { 77 // First, search backwards to the instruction that defines VPR 78 auto *Def = RDA->getReachingMIDef(MI, ARM::VPR); 79 if (!Def) 80 return nullptr; 81 82 // Now check that Def is a VCMP 83 if (!(NewOpcode = VCMPOpcodeToVPT(Def->getOpcode()))) 84 return nullptr; 85 86 // Check that Def's operands are not defined between the VCMP and MI, i.e. 87 // check that they have the same reaching def. 88 if (!RDA->hasSameReachingDef(Def, MI, Def->getOperand(1).getReg()) || 89 !RDA->hasSameReachingDef(Def, MI, Def->getOperand(2).getReg())) 90 return nullptr; 91 92 return Def; 93 } 94 95 bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) { 96 bool Modified = false; 97 MachineBasicBlock::instr_iterator MBIter = Block.instr_begin(); 98 MachineBasicBlock::instr_iterator EndIter = Block.instr_end(); 99 SmallSet<MachineInstr *, 4> RemovedVCMPs; 100 101 while (MBIter != EndIter) { 102 MachineInstr *MI = &*MBIter; 103 unsigned PredReg = 0; 104 DebugLoc dl = MI->getDebugLoc(); 105 106 ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg); 107 108 // The idea of the predicate is that None, Then and Else are for use when 109 // handling assembly language: they correspond to the three possible 110 // suffixes "", "t" and "e" on the mnemonic. So when instructions are read 111 // from assembly source or disassembled from object code, you expect to see 112 // a mixture whenever there's a long VPT block. But in code generation, we 113 // hope we'll never generate an Else as input to this pass. 114 assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds"); 115 116 if (Pred == ARMVCC::None) { 117 ++MBIter; 118 continue; 119 } 120 121 LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump()); 122 int VPTInstCnt = 1; 123 ARMVCC::VPTCodes NextPred; 124 125 // Look at subsequent instructions, checking if they can be in the same VPT 126 // block. 127 ++MBIter; 128 while (MBIter != EndIter && VPTInstCnt < 4) { 129 NextPred = getVPTInstrPredicate(*MBIter, PredReg); 130 assert(NextPred != ARMVCC::Else && 131 "VPT block pass does not expect Else preds"); 132 if (NextPred != Pred) 133 break; 134 LLVM_DEBUG(dbgs() << " adding : "; MBIter->dump()); 135 ++VPTInstCnt; 136 ++MBIter; 137 }; 138 139 unsigned BlockMask = getARMVPTBlockMask(VPTInstCnt); 140 141 // Search back for a VCMP that can be folded to create a VPT, or else create 142 // a VPST directly 143 MachineInstrBuilder MIBuilder; 144 unsigned NewOpcode; 145 MachineInstr *VCMP = findVCMPToFoldIntoVPST(MI, RDA, NewOpcode); 146 if (VCMP) { 147 LLVM_DEBUG(dbgs() << " folding VCMP into VPST: "; VCMP->dump()); 148 MIBuilder = BuildMI(Block, MI, dl, TII->get(NewOpcode)); 149 MIBuilder.addImm(BlockMask); 150 MIBuilder.add(VCMP->getOperand(1)); 151 MIBuilder.add(VCMP->getOperand(2)); 152 MIBuilder.add(VCMP->getOperand(3)); 153 // We delay removing the actual VCMP instruction by saving it to a list 154 // and deleting all instructions in this list in one go after we have 155 // created the VPT blocks. We do this in order not to invalidate the 156 // ReachingDefAnalysis that is queried by 'findVCMPToFoldIntoVPST'. 157 RemovedVCMPs.insert(VCMP); 158 } else { 159 MIBuilder = BuildMI(Block, MI, dl, TII->get(ARM::MVE_VPST)); 160 MIBuilder.addImm(BlockMask); 161 } 162 163 finalizeBundle( 164 Block, MachineBasicBlock::instr_iterator(MIBuilder.getInstr()), MBIter); 165 166 Modified = true; 167 } 168 169 for (auto *I : RemovedVCMPs) 170 I->eraseFromParent(); 171 172 return Modified; 173 } 174 175 bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) { 176 if (skipFunction(Fn.getFunction())) 177 return false; 178 179 const ARMSubtarget &STI = 180 static_cast<const ARMSubtarget &>(Fn.getSubtarget()); 181 182 if (!STI.isThumb2() || !STI.hasMVEIntegerOps()) 183 return false; 184 185 TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo()); 186 RDA = &getAnalysis<ReachingDefAnalysis>(); 187 188 LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n" 189 << "********** Function: " << Fn.getName() << '\n'); 190 191 bool Modified = false; 192 for (MachineBasicBlock &MBB : Fn) 193 Modified |= InsertVPTBlocks(MBB); 194 195 LLVM_DEBUG(dbgs() << "**************************************\n"); 196 return Modified; 197 } 198 199 /// createMVEVPTBlock - Returns an instance of the MVE VPT block 200 /// insertion pass. 201 FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); } 202