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