1 //===--- HexagonGenMemAbsolute.cpp - Generate Load/Store Set Absolute ---===// 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 // This pass traverses through all the basic blocks in a function and converts 10 // an indexed load/store with offset "0" to a absolute-set load/store 11 // instruction as long as the use of the register in the new instruction 12 // dominates the rest of the uses and there are more than 2 uses. 13 14 #include "HexagonTargetMachine.h" 15 #include "llvm/ADT/Statistic.h" 16 #include "llvm/CodeGen/MachineDominators.h" 17 #include "llvm/CodeGen/MachineFunctionPass.h" 18 #include "llvm/CodeGen/MachineInstrBuilder.h" 19 #include "llvm/CodeGen/MachineRegisterInfo.h" 20 #include "llvm/CodeGen/Passes.h" 21 #include "llvm/CodeGen/TargetInstrInfo.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include "llvm/Target/TargetMachine.h" 25 26 #define DEBUG_TYPE "hexagon-abs" 27 28 using namespace llvm; 29 30 STATISTIC(HexagonNumLoadAbsConversions, 31 "Number of Load instructions converted to absolute-set form"); 32 STATISTIC(HexagonNumStoreAbsConversions, 33 "Number of Store instructions converted to absolute-set form"); 34 35 namespace llvm { 36 FunctionPass *createHexagonGenMemAbsolute(); 37 void initializeHexagonGenMemAbsolutePass(PassRegistry &Registry); 38 } // namespace llvm 39 40 namespace { 41 42 class HexagonGenMemAbsolute : public MachineFunctionPass { 43 const HexagonInstrInfo *TII; 44 MachineRegisterInfo *MRI; 45 const TargetRegisterInfo *TRI; 46 47 public: 48 static char ID; 49 HexagonGenMemAbsolute() : MachineFunctionPass(ID), TII(0), MRI(0), TRI(0) { 50 initializeHexagonGenMemAbsolutePass(*PassRegistry::getPassRegistry()); 51 } 52 53 StringRef getPassName() const override { 54 return "Hexagon Generate Load/Store Set Absolute Address Instruction"; 55 } 56 57 void getAnalysisUsage(AnalysisUsage &AU) const override { 58 MachineFunctionPass::getAnalysisUsage(AU); 59 AU.addRequired<MachineDominatorTreeWrapperPass>(); 60 AU.addPreserved<MachineDominatorTreeWrapperPass>(); 61 } 62 63 bool runOnMachineFunction(MachineFunction &Fn) override; 64 65 private: 66 static bool isValidIndexedLoad(int &Opcode, int &NewOpcode); 67 static bool isValidIndexedStore(int &Opcode, int &NewOpcode); 68 }; 69 } // namespace 70 71 char HexagonGenMemAbsolute::ID = 0; 72 73 INITIALIZE_PASS(HexagonGenMemAbsolute, "hexagon-gen-load-absolute", 74 "Hexagon Generate Load/Store Set Absolute Address Instruction", 75 false, false) 76 77 bool HexagonGenMemAbsolute::runOnMachineFunction(MachineFunction &Fn) { 78 if (skipFunction(Fn.getFunction())) 79 return false; 80 81 TII = Fn.getSubtarget<HexagonSubtarget>().getInstrInfo(); 82 MRI = &Fn.getRegInfo(); 83 TRI = Fn.getRegInfo().getTargetRegisterInfo(); 84 85 MachineDominatorTree &MDT = 86 getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 87 88 // Loop over all of the basic blocks 89 for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end(); 90 MBBb != MBBe; ++MBBb) { 91 MachineBasicBlock *MBB = &*MBBb; 92 // Traverse the basic block 93 for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end(); 94 ++MII) { 95 MachineInstr *MI = &*MII; 96 int Opc = MI->getOpcode(); 97 if (Opc != Hexagon::CONST32 && Opc != Hexagon::A2_tfrsi) 98 continue; 99 100 const MachineOperand &MO = MI->getOperand(0); 101 if (!MO.isReg() || !MO.isDef()) 102 continue; 103 104 unsigned DstReg = MO.getReg(); 105 if (MRI->use_nodbg_empty(DstReg)) 106 continue; 107 108 typedef MachineRegisterInfo::use_nodbg_iterator use_iterator; 109 use_iterator NextUseMI = MRI->use_nodbg_begin(DstReg); 110 111 MachineInstr *NextMI = NextUseMI->getParent(); 112 int NextOpc = NextMI->getOpcode(); 113 int NewOpc; 114 bool IsLoad = isValidIndexedLoad(NextOpc, NewOpc); 115 116 if (!IsLoad && !isValidIndexedStore(NextOpc, NewOpc)) 117 continue; 118 119 // Base and Offset positions for load and store instructions 120 // Load R(dest), R(base), Imm -> R(dest) = mem(R(base) + Imm) 121 // Store R(base), Imm, R (src) -> mem(R(base) + Imm) = R(src) 122 unsigned BaseRegPos, ImmPos, RegPos; 123 if (!TII->getBaseAndOffsetPosition(*NextMI, BaseRegPos, ImmPos)) 124 continue; 125 RegPos = IsLoad ? 0 : 2; 126 127 bool IsGlobal = MI->getOperand(1).isGlobal(); 128 if (!MI->getOperand(1).isImm() && !IsGlobal) 129 continue; 130 131 const MachineOperand *BaseOp = nullptr; 132 int64_t Offset; 133 bool Scalable; 134 TII->getMemOperandWithOffset(*NextMI, BaseOp, Offset, Scalable, TRI); 135 136 // Ensure BaseOp is non-null and register type. 137 if (!BaseOp || !BaseOp->isReg()) 138 continue; 139 140 if (Scalable) 141 continue; 142 143 unsigned BaseReg = BaseOp->getReg(); 144 if ((DstReg != BaseReg) || (Offset != 0)) 145 continue; 146 147 const MachineOperand &MO0 = NextMI->getOperand(RegPos); 148 149 if (!MO0.isReg()) 150 continue; 151 152 unsigned LoadStoreReg = MO0.getReg(); 153 154 // Store: Bail out if the src and base are same (def and use on same 155 // register). 156 if (LoadStoreReg == BaseReg) 157 continue; 158 159 // Insert the absolute-set instruction "I" only if the use of the 160 // BaseReg in "I" dominates the rest of the uses of BaseReg and if 161 // there are more than 2 uses of this BaseReg. 162 bool Dominates = true; 163 unsigned Counter = 0; 164 for (use_iterator I = NextUseMI, E = MRI->use_nodbg_end(); I != E; ++I) { 165 Counter++; 166 if (!MDT.dominates(NextMI, I->getParent())) 167 Dominates = false; 168 } 169 170 if ((!Dominates) || (Counter < 3)) 171 continue; 172 173 // If we reach here, we have met all the conditions required for the 174 // replacement of the absolute instruction. 175 LLVM_DEBUG({ 176 dbgs() << "Found a pair of instructions for absolute-set " 177 << (IsLoad ? "load" : "store") << "\n"; 178 dbgs() << *MI; 179 dbgs() << *NextMI; 180 }); 181 MachineBasicBlock *ParentBlock = NextMI->getParent(); 182 MachineInstrBuilder MIB; 183 if (IsLoad) { // Insert absolute-set load instruction 184 ++HexagonNumLoadAbsConversions; 185 MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(), 186 TII->get(NewOpc), LoadStoreReg) 187 .addReg(DstReg, RegState::Define); 188 } else { // Insert absolute-set store instruction 189 ++HexagonNumStoreAbsConversions; 190 MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(), 191 TII->get(NewOpc), DstReg); 192 } 193 194 MachineOperand ImmOperand = MI->getOperand(1); 195 if (IsGlobal) 196 MIB.addGlobalAddress(ImmOperand.getGlobal(), ImmOperand.getOffset(), 197 ImmOperand.getTargetFlags()); 198 else 199 MIB.addImm(ImmOperand.getImm()); 200 201 if (IsLoad) 202 MIB->getOperand(0).setSubReg(MO0.getSubReg()); 203 else 204 MIB.addReg(LoadStoreReg, 0, MO0.getSubReg()); 205 206 LLVM_DEBUG(dbgs() << "Replaced with " << *MIB << "\n"); 207 // Erase the instructions that got replaced. 208 MII = MBB->erase(MI); 209 --MII; 210 NextMI->getParent()->erase(NextMI); 211 } 212 } 213 214 return true; 215 } 216 217 bool HexagonGenMemAbsolute::isValidIndexedLoad(int &Opc, int &NewOpc) { 218 219 bool Result = true; 220 switch (Opc) { 221 case Hexagon::L2_loadrb_io: 222 NewOpc = Hexagon::L4_loadrb_ap; 223 break; 224 case Hexagon::L2_loadrh_io: 225 NewOpc = Hexagon::L4_loadrh_ap; 226 break; 227 case Hexagon::L2_loadri_io: 228 NewOpc = Hexagon::L4_loadri_ap; 229 break; 230 case Hexagon::L2_loadrd_io: 231 NewOpc = Hexagon::L4_loadrd_ap; 232 break; 233 case Hexagon::L2_loadruh_io: 234 NewOpc = Hexagon::L4_loadruh_ap; 235 break; 236 case Hexagon::L2_loadrub_io: 237 NewOpc = Hexagon::L4_loadrub_ap; 238 break; 239 default: 240 Result = false; 241 } 242 243 return Result; 244 } 245 246 bool HexagonGenMemAbsolute::isValidIndexedStore(int &Opc, int &NewOpc) { 247 248 bool Result = true; 249 switch (Opc) { 250 case Hexagon::S2_storerd_io: 251 NewOpc = Hexagon::S4_storerd_ap; 252 break; 253 case Hexagon::S2_storeri_io: 254 NewOpc = Hexagon::S4_storeri_ap; 255 break; 256 case Hexagon::S2_storerh_io: 257 NewOpc = Hexagon::S4_storerh_ap; 258 break; 259 case Hexagon::S2_storerb_io: 260 NewOpc = Hexagon::S4_storerb_ap; 261 break; 262 default: 263 Result = false; 264 } 265 266 return Result; 267 } 268 269 //===----------------------------------------------------------------------===// 270 // Public Constructor Functions 271 //===----------------------------------------------------------------------===// 272 273 FunctionPass *llvm::createHexagonGenMemAbsolute() { 274 return new HexagonGenMemAbsolute(); 275 } 276