1 //===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup Pass -------===// 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 // This pass is to address a situation that appears after register allocaion 9 // evey now and then, namely a register copy from a source that was defined 10 // as an immediate value in the same block (usually just before the copy). 11 // 12 // Here is an example of actual code emitted that shows this problem: 13 // 14 // .LBB0_5: 15 // { 16 // r5 = zxtb(r8) 17 // r6 = or(r6, ##12345) 18 // } 19 // { 20 // r3 = xor(r1, r2) 21 // r1 = #0 <-- r1 set to #0 22 // } 23 // { 24 // r7 = r1 <-- r7 set to r1 25 // r0 = zxtb(r3) 26 // } 27 28 #define DEBUG_TYPE "tfr-cleanup" 29 #include "HexagonTargetMachine.h" 30 31 #include "llvm/CodeGen/LiveIntervals.h" 32 #include "llvm/CodeGen/MachineFunction.h" 33 #include "llvm/CodeGen/MachineInstrBuilder.h" 34 #include "llvm/CodeGen/Passes.h" 35 #include "llvm/CodeGen/TargetInstrInfo.h" 36 #include "llvm/CodeGen/TargetRegisterInfo.h" 37 38 using namespace llvm; 39 40 namespace llvm { 41 FunctionPass *createHexagonTfrCleanup(); 42 void initializeHexagonTfrCleanupPass(PassRegistry &); 43 } // namespace llvm 44 45 namespace { 46 class HexagonTfrCleanup : public MachineFunctionPass { 47 public: 48 static char ID; 49 HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) { 50 PassRegistry &R = *PassRegistry::getPassRegistry(); 51 initializeHexagonTfrCleanupPass(R); 52 } 53 StringRef getPassName() const override { return "Hexagon TFR Cleanup"; } 54 void getAnalysisUsage(AnalysisUsage &AU) const override { 55 AU.setPreservesAll(); 56 MachineFunctionPass::getAnalysisUsage(AU); 57 } 58 bool runOnMachineFunction(MachineFunction &MF) override; 59 60 private: 61 const HexagonInstrInfo *HII; 62 const TargetRegisterInfo *TRI; 63 64 typedef DenseMap<unsigned, uint64_t> ImmediateMap; 65 66 bool isIntReg(unsigned Reg, bool &Is32); 67 void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap); 68 bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap); 69 bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap); 70 bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes); 71 bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes); 72 }; 73 } // namespace 74 75 char HexagonTfrCleanup::ID = 0; 76 77 namespace llvm { 78 char &HexagonTfrCleanupID = HexagonTfrCleanup::ID; 79 } 80 81 bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) { 82 Is32 = Hexagon::IntRegsRegClass.contains(Reg); 83 return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg); 84 } 85 86 // Assign given value V32 to the specified the register R32 in the map. Only 87 // 32-bit registers are valid arguments. 88 void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) { 89 IMap[R32] = V32; 90 } 91 92 // Retrieve a value of the provided register Reg and store it into Val. 93 // Return "true" if a value was found, "false" otherwise. 94 bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val, 95 ImmediateMap &IMap) { 96 bool Is32; 97 if (!isIntReg(Reg, Is32)) 98 return false; 99 100 if (Is32) { 101 ImmediateMap::iterator F = IMap.find(Reg); 102 if (F == IMap.end()) 103 return false; 104 Val = F->second; 105 return true; 106 } 107 108 // For 64-bit registers, compose the value from the values of its 109 // subregisters. 110 unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo); 111 unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi); 112 ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH); 113 if (FL == IMap.end() || FH == IMap.end()) 114 return false; 115 Val = (FH->second << 32) | FL->second; 116 return true; 117 } 118 119 // Process an instruction and record the relevant information in the imme- 120 // diate map. 121 bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) { 122 using namespace Hexagon; 123 124 if (MI->isCall()) { 125 IMap.clear(); 126 return true; 127 } 128 129 // If this is an instruction that loads a constant into a register, 130 // record this information in IMap. 131 unsigned Opc = MI->getOpcode(); 132 if (Opc == A2_tfrsi || Opc == A2_tfrpi) { 133 unsigned DefR = MI->getOperand(0).getReg(); 134 bool Is32; 135 if (!isIntReg(DefR, Is32)) 136 return false; 137 if (!MI->getOperand(1).isImm()) { 138 if (!Is32) { 139 IMap.erase(TRI->getSubReg(DefR, isub_lo)); 140 IMap.erase(TRI->getSubReg(DefR, isub_hi)); 141 } else { 142 IMap.erase(DefR); 143 } 144 return false; 145 } 146 uint64_t Val = MI->getOperand(1).getImm(); 147 // If it's a 64-bit register, break it up into subregisters. 148 if (!Is32) { 149 uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU); 150 setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap); 151 setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap); 152 } else { 153 setReg(DefR, Val, IMap); 154 } 155 return true; 156 } 157 158 // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap. 159 for (MachineInstr::mop_iterator Mo = MI->operands_begin(), 160 E = MI->operands_end(); 161 Mo != E; ++Mo) { 162 if (Mo->isRegMask()) { 163 IMap.clear(); 164 return true; 165 } 166 if (!Mo->isReg() || !Mo->isDef()) 167 continue; 168 unsigned R = Mo->getReg(); 169 for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR) { 170 ImmediateMap::iterator F = IMap.find(*AR); 171 if (F != IMap.end()) 172 IMap.erase(F); 173 } 174 } 175 return true; 176 } 177 178 // Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that 179 // has a known constant value. 180 bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, 181 SlotIndexes *Indexes) { 182 using namespace Hexagon; 183 unsigned Opc = MI->getOpcode(); 184 switch (Opc) { 185 case A2_tfr: 186 case A2_tfrp: 187 case COPY: 188 break; 189 default: 190 return false; 191 } 192 193 unsigned DstR = MI->getOperand(0).getReg(); 194 unsigned SrcR = MI->getOperand(1).getReg(); 195 bool Tmp, Is32; 196 if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp)) 197 return false; 198 assert(Tmp == Is32 && "Register size mismatch"); 199 uint64_t Val; 200 bool Found = getReg(SrcR, Val, IMap); 201 if (!Found) 202 return false; 203 204 MachineBasicBlock &B = *MI->getParent(); 205 DebugLoc DL = MI->getDebugLoc(); 206 int64_t SVal = Is32 ? int32_t(Val) : Val; 207 auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>(); 208 MachineInstr *NewMI; 209 if (Is32) 210 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal); 211 else if (isInt<8>(SVal)) 212 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal); 213 else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL))) 214 NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR) 215 .addImm(int32_t(SVal >> 32)) 216 .addImm(int32_t(Val & 0xFFFFFFFFLL)); 217 else if (HST.isTinyCore()) 218 // Disable generating CONST64 since it requires load resource. 219 return false; 220 else 221 NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val); 222 223 // Replace the MI to reuse the same slot index 224 if (Indexes) 225 Indexes->replaceMachineInstrInMaps(*MI, *NewMI); 226 MI->eraseFromParent(); 227 return true; 228 } 229 230 // Remove the instruction if it is a self-assignment. 231 bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI, 232 SlotIndexes *Indexes) { 233 unsigned Opc = MI->getOpcode(); 234 unsigned DefR, SrcR; 235 bool IsUndef = false; 236 switch (Opc) { 237 case Hexagon::A2_tfr: 238 // Rd = Rd 239 DefR = MI->getOperand(0).getReg(); 240 SrcR = MI->getOperand(1).getReg(); 241 IsUndef = MI->getOperand(1).isUndef(); 242 break; 243 case Hexagon::A2_tfrt: 244 case Hexagon::A2_tfrf: 245 // if ([!]Pu) Rd = Rd 246 DefR = MI->getOperand(0).getReg(); 247 SrcR = MI->getOperand(2).getReg(); 248 IsUndef = MI->getOperand(2).isUndef(); 249 break; 250 default: 251 return false; 252 } 253 if (DefR != SrcR) 254 return false; 255 if (IsUndef) { 256 MachineBasicBlock &B = *MI->getParent(); 257 DebugLoc DL = MI->getDebugLoc(); 258 auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR); 259 for (auto &Op : MI->operands()) 260 if (Op.isReg() && Op.isDef() && Op.isImplicit()) 261 DefI->addOperand(Op); 262 } 263 264 if (Indexes) 265 Indexes->removeMachineInstrFromMaps(*MI); 266 MI->eraseFromParent(); 267 return true; 268 } 269 270 bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) { 271 bool Changed = false; 272 // Map: 32-bit register -> immediate value. 273 // 64-bit registers are stored through their subregisters. 274 ImmediateMap IMap; 275 auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>(); 276 SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr; 277 278 auto &HST = MF.getSubtarget<HexagonSubtarget>(); 279 HII = HST.getInstrInfo(); 280 TRI = HST.getRegisterInfo(); 281 282 for (MachineBasicBlock &B : MF) { 283 MachineBasicBlock::iterator J, F, NextJ; 284 IMap.clear(); 285 bool Inserted = false, Erased = false; 286 for (J = B.begin(), F = B.end(); J != F; J = NextJ) { 287 NextJ = std::next(J); 288 MachineInstr *MI = &*J; 289 bool E = eraseIfRedundant(MI, Indexes); 290 Erased |= E; 291 if (E) 292 continue; 293 Inserted |= rewriteIfImm(MI, IMap, Indexes); 294 MachineBasicBlock::iterator NewJ = std::prev(NextJ); 295 updateImmMap(&*NewJ, IMap); 296 } 297 bool BlockC = Inserted | Erased; 298 Changed |= BlockC; 299 if (BlockC && Indexes) 300 Indexes->repairIndexesInRange(&B, B.begin(), B.end()); 301 } 302 303 return Changed; 304 } 305 306 //===----------------------------------------------------------------------===// 307 // Public Constructor Functions 308 //===----------------------------------------------------------------------===// 309 INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false, 310 false) 311 312 FunctionPass *llvm::createHexagonTfrCleanup() { 313 return new HexagonTfrCleanup(); 314 } 315