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 enum VPTMaskValue { 75 T = 8, // 0b1000 76 TT = 4, // 0b0100 77 TE = 12, // 0b1100 78 TTT = 2, // 0b0010 79 TTE = 6, // 0b0110 80 TEE = 10, // 0b1010 81 TET = 14, // 0b1110 82 TTTT = 1, // 0b0001 83 TTTE = 3, // 0b0011 84 TTEE = 5, // 0b0101 85 TTET = 7, // 0b0111 86 TEEE = 9, // 0b1001 87 TEET = 11, // 0b1011 88 TETT = 13, // 0b1101 89 TETE = 15 // 0b1111 90 }; 91 92 static unsigned VCMPOpcodeToVPT(unsigned Opcode) { 93 switch (Opcode) { 94 case ARM::MVE_VCMPf32: 95 return ARM::MVE_VPTv4f32; 96 case ARM::MVE_VCMPf16: 97 return ARM::MVE_VPTv8f16; 98 case ARM::MVE_VCMPi8: 99 return ARM::MVE_VPTv16i8; 100 case ARM::MVE_VCMPi16: 101 return ARM::MVE_VPTv8i16; 102 case ARM::MVE_VCMPi32: 103 return ARM::MVE_VPTv4i32; 104 case ARM::MVE_VCMPu8: 105 return ARM::MVE_VPTv16u8; 106 case ARM::MVE_VCMPu16: 107 return ARM::MVE_VPTv8u16; 108 case ARM::MVE_VCMPu32: 109 return ARM::MVE_VPTv4u32; 110 case ARM::MVE_VCMPs8: 111 return ARM::MVE_VPTv16s8; 112 case ARM::MVE_VCMPs16: 113 return ARM::MVE_VPTv8s16; 114 case ARM::MVE_VCMPs32: 115 return ARM::MVE_VPTv4s32; 116 117 case ARM::MVE_VCMPf32r: 118 return ARM::MVE_VPTv4f32r; 119 case ARM::MVE_VCMPf16r: 120 return ARM::MVE_VPTv8f16r; 121 case ARM::MVE_VCMPi8r: 122 return ARM::MVE_VPTv16i8r; 123 case ARM::MVE_VCMPi16r: 124 return ARM::MVE_VPTv8i16r; 125 case ARM::MVE_VCMPi32r: 126 return ARM::MVE_VPTv4i32r; 127 case ARM::MVE_VCMPu8r: 128 return ARM::MVE_VPTv16u8r; 129 case ARM::MVE_VCMPu16r: 130 return ARM::MVE_VPTv8u16r; 131 case ARM::MVE_VCMPu32r: 132 return ARM::MVE_VPTv4u32r; 133 case ARM::MVE_VCMPs8r: 134 return ARM::MVE_VPTv16s8r; 135 case ARM::MVE_VCMPs16r: 136 return ARM::MVE_VPTv8s16r; 137 case ARM::MVE_VCMPs32r: 138 return ARM::MVE_VPTv4s32r; 139 140 default: 141 return 0; 142 } 143 } 144 145 static MachineInstr *findVCMPToFoldIntoVPST(MachineInstr *MI, 146 ReachingDefAnalysis *RDA, 147 unsigned &NewOpcode) { 148 // First, search backwards to the instruction that defines VPR 149 auto *Def = RDA->getReachingMIDef(MI, ARM::VPR); 150 if (!Def) 151 return nullptr; 152 153 // Now check that Def is a VCMP 154 if (!(NewOpcode = VCMPOpcodeToVPT(Def->getOpcode()))) 155 return nullptr; 156 157 // Check that Def's operands are not defined between the VCMP and MI, i.e. 158 // check that they have the same reaching def. 159 if (!RDA->hasSameReachingDef(Def, MI, Def->getOperand(1).getReg()) || 160 !RDA->hasSameReachingDef(Def, MI, Def->getOperand(2).getReg())) 161 return nullptr; 162 163 return Def; 164 } 165 166 bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) { 167 bool Modified = false; 168 MachineBasicBlock::instr_iterator MBIter = Block.instr_begin(); 169 MachineBasicBlock::instr_iterator EndIter = Block.instr_end(); 170 171 while (MBIter != EndIter) { 172 MachineInstr *MI = &*MBIter; 173 unsigned PredReg = 0; 174 DebugLoc dl = MI->getDebugLoc(); 175 176 ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg); 177 178 // The idea of the predicate is that None, Then and Else are for use when 179 // handling assembly language: they correspond to the three possible 180 // suffixes "", "t" and "e" on the mnemonic. So when instructions are read 181 // from assembly source or disassembled from object code, you expect to see 182 // a mixture whenever there's a long VPT block. But in code generation, we 183 // hope we'll never generate an Else as input to this pass. 184 assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds"); 185 186 if (Pred == ARMVCC::None) { 187 ++MBIter; 188 continue; 189 } 190 191 LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump()); 192 int VPTInstCnt = 1; 193 ARMVCC::VPTCodes NextPred; 194 195 // Look at subsequent instructions, checking if they can be in the same VPT 196 // block. 197 ++MBIter; 198 while (MBIter != EndIter && VPTInstCnt < 4) { 199 NextPred = getVPTInstrPredicate(*MBIter, PredReg); 200 assert(NextPred != ARMVCC::Else && 201 "VPT block pass does not expect Else preds"); 202 if (NextPred != Pred) 203 break; 204 LLVM_DEBUG(dbgs() << " adding : "; MBIter->dump()); 205 ++VPTInstCnt; 206 ++MBIter; 207 }; 208 209 unsigned BlockMask = 0; 210 switch (VPTInstCnt) { 211 case 1: 212 BlockMask = VPTMaskValue::T; 213 break; 214 case 2: 215 BlockMask = VPTMaskValue::TT; 216 break; 217 case 3: 218 BlockMask = VPTMaskValue::TTT; 219 break; 220 case 4: 221 BlockMask = VPTMaskValue::TTTT; 222 break; 223 default: 224 llvm_unreachable("Unexpected number of instruction in a VPT block"); 225 }; 226 227 // Search back for a VCMP that can be folded to create a VPT, or else create 228 // a VPST directly 229 MachineInstrBuilder MIBuilder; 230 unsigned NewOpcode; 231 MachineInstr *VCMP = findVCMPToFoldIntoVPST(MI, RDA, NewOpcode); 232 if (VCMP) { 233 LLVM_DEBUG(dbgs() << " folding VCMP into VPST: "; VCMP->dump()); 234 MIBuilder = BuildMI(Block, MI, dl, TII->get(NewOpcode)); 235 MIBuilder.addImm(BlockMask); 236 MIBuilder.add(VCMP->getOperand(1)); 237 MIBuilder.add(VCMP->getOperand(2)); 238 MIBuilder.add(VCMP->getOperand(3)); 239 VCMP->eraseFromParent(); 240 } else { 241 MIBuilder = BuildMI(Block, MI, dl, TII->get(ARM::MVE_VPST)); 242 MIBuilder.addImm(BlockMask); 243 } 244 245 finalizeBundle( 246 Block, MachineBasicBlock::instr_iterator(MIBuilder.getInstr()), MBIter); 247 248 Modified = true; 249 } 250 return Modified; 251 } 252 253 bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) { 254 const ARMSubtarget &STI = 255 static_cast<const ARMSubtarget &>(Fn.getSubtarget()); 256 257 if (!STI.isThumb2() || !STI.hasMVEIntegerOps()) 258 return false; 259 260 TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo()); 261 RDA = &getAnalysis<ReachingDefAnalysis>(); 262 263 LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n" 264 << "********** Function: " << Fn.getName() << '\n'); 265 266 bool Modified = false; 267 for (MachineBasicBlock &MBB : Fn) 268 Modified |= InsertVPTBlocks(MBB); 269 270 LLVM_DEBUG(dbgs() << "**************************************\n"); 271 return Modified; 272 } 273 274 /// createMVEVPTBlock - Returns an instance of the MVE VPT block 275 /// insertion pass. 276 FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); } 277