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