1*0b57cec5SDimitry Andric //===- MipsOptimizePICCall.cpp - Optimize PIC Calls -----------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This pass eliminates unnecessary instructions that set up $gp and replace 10*0b57cec5SDimitry Andric // instructions that load target function addresses with copy instructions. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h" 15*0b57cec5SDimitry Andric #include "Mips.h" 16*0b57cec5SDimitry Andric #include "MipsRegisterInfo.h" 17*0b57cec5SDimitry Andric #include "MipsSubtarget.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/PointerUnion.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/ScopedHashTable.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 33*0b57cec5SDimitry Andric #include "llvm/Support/Allocator.h" 34*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 35*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 36*0b57cec5SDimitry Andric #include "llvm/Support/MachineValueType.h" 37*0b57cec5SDimitry Andric #include "llvm/Support/RecyclingAllocator.h" 38*0b57cec5SDimitry Andric #include <cassert> 39*0b57cec5SDimitry Andric #include <utility> 40*0b57cec5SDimitry Andric #include <vector> 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric using namespace llvm; 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric #define DEBUG_TYPE "optimize-mips-pic-call" 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric static cl::opt<bool> LoadTargetFromGOT("mips-load-target-from-got", 47*0b57cec5SDimitry Andric cl::init(true), 48*0b57cec5SDimitry Andric cl::desc("Load target address from GOT"), 49*0b57cec5SDimitry Andric cl::Hidden); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric static cl::opt<bool> EraseGPOpnd("mips-erase-gp-opnd", 52*0b57cec5SDimitry Andric cl::init(true), cl::desc("Erase GP Operand"), 53*0b57cec5SDimitry Andric cl::Hidden); 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric namespace { 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>; 58*0b57cec5SDimitry Andric using CntRegP = std::pair<unsigned, unsigned>; 59*0b57cec5SDimitry Andric using AllocatorTy = RecyclingAllocator<BumpPtrAllocator, 60*0b57cec5SDimitry Andric ScopedHashTableVal<ValueType, CntRegP>>; 61*0b57cec5SDimitry Andric using ScopedHTType = ScopedHashTable<ValueType, CntRegP, 62*0b57cec5SDimitry Andric DenseMapInfo<ValueType>, AllocatorTy>; 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric class MBBInfo { 65*0b57cec5SDimitry Andric public: 66*0b57cec5SDimitry Andric MBBInfo(MachineDomTreeNode *N); 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric const MachineDomTreeNode *getNode() const; 69*0b57cec5SDimitry Andric bool isVisited() const; 70*0b57cec5SDimitry Andric void preVisit(ScopedHTType &ScopedHT); 71*0b57cec5SDimitry Andric void postVisit(); 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric private: 74*0b57cec5SDimitry Andric MachineDomTreeNode *Node; 75*0b57cec5SDimitry Andric ScopedHTType::ScopeTy *HTScope; 76*0b57cec5SDimitry Andric }; 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric class OptimizePICCall : public MachineFunctionPass { 79*0b57cec5SDimitry Andric public: 80*0b57cec5SDimitry Andric OptimizePICCall() : MachineFunctionPass(ID) {} 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric StringRef getPassName() const override { return "Mips OptimizePICCall"; } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &F) override; 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 87*0b57cec5SDimitry Andric AU.addRequired<MachineDominatorTree>(); 88*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric private: 92*0b57cec5SDimitry Andric /// Visit MBB. 93*0b57cec5SDimitry Andric bool visitNode(MBBInfo &MBBI); 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric /// Test if MI jumps to a function via a register. 96*0b57cec5SDimitry Andric /// 97*0b57cec5SDimitry Andric /// Also, return the virtual register containing the target function's address 98*0b57cec5SDimitry Andric /// and the underlying object in Reg and Val respectively, if the function's 99*0b57cec5SDimitry Andric /// address can be resolved lazily. 100*0b57cec5SDimitry Andric bool isCallViaRegister(MachineInstr &MI, unsigned &Reg, 101*0b57cec5SDimitry Andric ValueType &Val) const; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric /// Return the number of instructions that dominate the current 104*0b57cec5SDimitry Andric /// instruction and load the function address from object Entry. 105*0b57cec5SDimitry Andric unsigned getCount(ValueType Entry); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric /// Return the destination virtual register of the last instruction 108*0b57cec5SDimitry Andric /// that loads from object Entry. 109*0b57cec5SDimitry Andric unsigned getReg(ValueType Entry); 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric /// Update ScopedHT. 112*0b57cec5SDimitry Andric void incCntAndSetReg(ValueType Entry, unsigned Reg); 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric ScopedHTType ScopedHT; 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric static char ID; 117*0b57cec5SDimitry Andric }; 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric } // end of anonymous namespace 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric char OptimizePICCall::ID = 0; 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric /// Return the first MachineOperand of MI if it is a used virtual register. 124*0b57cec5SDimitry Andric static MachineOperand *getCallTargetRegOpnd(MachineInstr &MI) { 125*0b57cec5SDimitry Andric if (MI.getNumOperands() == 0) 126*0b57cec5SDimitry Andric return nullptr; 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric MachineOperand &MO = MI.getOperand(0); 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric if (!MO.isReg() || !MO.isUse() || 131*0b57cec5SDimitry Andric !TargetRegisterInfo::isVirtualRegister(MO.getReg())) 132*0b57cec5SDimitry Andric return nullptr; 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric return &MO; 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric /// Return type of register Reg. 138*0b57cec5SDimitry Andric static MVT::SimpleValueType getRegTy(unsigned Reg, MachineFunction &MF) { 139*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 140*0b57cec5SDimitry Andric const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(Reg); 141*0b57cec5SDimitry Andric assert(TRI.legalclasstypes_end(*RC) - TRI.legalclasstypes_begin(*RC) == 1); 142*0b57cec5SDimitry Andric return *TRI.legalclasstypes_begin(*RC); 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric /// Do the following transformation: 146*0b57cec5SDimitry Andric /// 147*0b57cec5SDimitry Andric /// jalr $vreg 148*0b57cec5SDimitry Andric /// => 149*0b57cec5SDimitry Andric /// copy $t9, $vreg 150*0b57cec5SDimitry Andric /// jalr $t9 151*0b57cec5SDimitry Andric static void setCallTargetReg(MachineBasicBlock *MBB, 152*0b57cec5SDimitry Andric MachineBasicBlock::iterator I) { 153*0b57cec5SDimitry Andric MachineFunction &MF = *MBB->getParent(); 154*0b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 155*0b57cec5SDimitry Andric unsigned SrcReg = I->getOperand(0).getReg(); 156*0b57cec5SDimitry Andric unsigned DstReg = getRegTy(SrcReg, MF) == MVT::i32 ? Mips::T9 : Mips::T9_64; 157*0b57cec5SDimitry Andric BuildMI(*MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), DstReg) 158*0b57cec5SDimitry Andric .addReg(SrcReg); 159*0b57cec5SDimitry Andric I->getOperand(0).setReg(DstReg); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric /// Search MI's operands for register GP and erase it. 163*0b57cec5SDimitry Andric static void eraseGPOpnd(MachineInstr &MI) { 164*0b57cec5SDimitry Andric if (!EraseGPOpnd) 165*0b57cec5SDimitry Andric return; 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 168*0b57cec5SDimitry Andric MVT::SimpleValueType Ty = getRegTy(MI.getOperand(0).getReg(), MF); 169*0b57cec5SDimitry Andric unsigned Reg = Ty == MVT::i32 ? Mips::GP : Mips::GP_64; 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric for (unsigned I = 0; I < MI.getNumOperands(); ++I) { 172*0b57cec5SDimitry Andric MachineOperand &MO = MI.getOperand(I); 173*0b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == Reg) { 174*0b57cec5SDimitry Andric MI.RemoveOperand(I); 175*0b57cec5SDimitry Andric return; 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric } 178*0b57cec5SDimitry Andric 179*0b57cec5SDimitry Andric llvm_unreachable(nullptr); 180*0b57cec5SDimitry Andric } 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric MBBInfo::MBBInfo(MachineDomTreeNode *N) : Node(N), HTScope(nullptr) {} 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric const MachineDomTreeNode *MBBInfo::getNode() const { return Node; } 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric bool MBBInfo::isVisited() const { return HTScope; } 187*0b57cec5SDimitry Andric 188*0b57cec5SDimitry Andric void MBBInfo::preVisit(ScopedHTType &ScopedHT) { 189*0b57cec5SDimitry Andric HTScope = new ScopedHTType::ScopeTy(ScopedHT); 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric void MBBInfo::postVisit() { 193*0b57cec5SDimitry Andric delete HTScope; 194*0b57cec5SDimitry Andric } 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric // OptimizePICCall methods. 197*0b57cec5SDimitry Andric bool OptimizePICCall::runOnMachineFunction(MachineFunction &F) { 198*0b57cec5SDimitry Andric if (static_cast<const MipsSubtarget &>(F.getSubtarget()).inMips16Mode()) 199*0b57cec5SDimitry Andric return false; 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric // Do a pre-order traversal of the dominator tree. 202*0b57cec5SDimitry Andric MachineDominatorTree *MDT = &getAnalysis<MachineDominatorTree>(); 203*0b57cec5SDimitry Andric bool Changed = false; 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric SmallVector<MBBInfo, 8> WorkList(1, MBBInfo(MDT->getRootNode())); 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric while (!WorkList.empty()) { 208*0b57cec5SDimitry Andric MBBInfo &MBBI = WorkList.back(); 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric // If this MBB has already been visited, destroy the scope for the MBB and 211*0b57cec5SDimitry Andric // pop it from the work list. 212*0b57cec5SDimitry Andric if (MBBI.isVisited()) { 213*0b57cec5SDimitry Andric MBBI.postVisit(); 214*0b57cec5SDimitry Andric WorkList.pop_back(); 215*0b57cec5SDimitry Andric continue; 216*0b57cec5SDimitry Andric } 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric // Visit the MBB and add its children to the work list. 219*0b57cec5SDimitry Andric MBBI.preVisit(ScopedHT); 220*0b57cec5SDimitry Andric Changed |= visitNode(MBBI); 221*0b57cec5SDimitry Andric const MachineDomTreeNode *Node = MBBI.getNode(); 222*0b57cec5SDimitry Andric const std::vector<MachineDomTreeNode *> &Children = Node->getChildren(); 223*0b57cec5SDimitry Andric WorkList.append(Children.begin(), Children.end()); 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric return Changed; 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric bool OptimizePICCall::visitNode(MBBInfo &MBBI) { 230*0b57cec5SDimitry Andric bool Changed = false; 231*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MBBI.getNode()->getBlock(); 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; 234*0b57cec5SDimitry Andric ++I) { 235*0b57cec5SDimitry Andric unsigned Reg; 236*0b57cec5SDimitry Andric ValueType Entry; 237*0b57cec5SDimitry Andric 238*0b57cec5SDimitry Andric // Skip instructions that are not call instructions via registers. 239*0b57cec5SDimitry Andric if (!isCallViaRegister(*I, Reg, Entry)) 240*0b57cec5SDimitry Andric continue; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric Changed = true; 243*0b57cec5SDimitry Andric unsigned N = getCount(Entry); 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric if (N != 0) { 246*0b57cec5SDimitry Andric // If a function has been called more than twice, we do not have to emit a 247*0b57cec5SDimitry Andric // load instruction to get the function address from the GOT, but can 248*0b57cec5SDimitry Andric // instead reuse the address that has been loaded before. 249*0b57cec5SDimitry Andric if (N >= 2 && !LoadTargetFromGOT) 250*0b57cec5SDimitry Andric getCallTargetRegOpnd(*I)->setReg(getReg(Entry)); 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric // Erase the $gp operand if this isn't the first time a function has 253*0b57cec5SDimitry Andric // been called. $gp needs to be set up only if the function call can go 254*0b57cec5SDimitry Andric // through a lazy binding stub. 255*0b57cec5SDimitry Andric eraseGPOpnd(*I); 256*0b57cec5SDimitry Andric } 257*0b57cec5SDimitry Andric 258*0b57cec5SDimitry Andric if (Entry) 259*0b57cec5SDimitry Andric incCntAndSetReg(Entry, Reg); 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric setCallTargetReg(MBB, I); 262*0b57cec5SDimitry Andric } 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric return Changed; 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric bool OptimizePICCall::isCallViaRegister(MachineInstr &MI, unsigned &Reg, 268*0b57cec5SDimitry Andric ValueType &Val) const { 269*0b57cec5SDimitry Andric if (!MI.isCall()) 270*0b57cec5SDimitry Andric return false; 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric MachineOperand *MO = getCallTargetRegOpnd(MI); 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric // Return if MI is not a function call via a register. 275*0b57cec5SDimitry Andric if (!MO) 276*0b57cec5SDimitry Andric return false; 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric // Get the instruction that loads the function address from the GOT. 279*0b57cec5SDimitry Andric Reg = MO->getReg(); 280*0b57cec5SDimitry Andric Val = nullptr; 281*0b57cec5SDimitry Andric MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); 282*0b57cec5SDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(Reg); 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric assert(DefMI); 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric // See if DefMI is an instruction that loads from a GOT entry that holds the 287*0b57cec5SDimitry Andric // address of a lazy binding stub. 288*0b57cec5SDimitry Andric if (!DefMI->mayLoad() || DefMI->getNumOperands() < 3) 289*0b57cec5SDimitry Andric return true; 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric unsigned Flags = DefMI->getOperand(2).getTargetFlags(); 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric if (Flags != MipsII::MO_GOT_CALL && Flags != MipsII::MO_CALL_LO16) 294*0b57cec5SDimitry Andric return true; 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric // Return the underlying object for the GOT entry in Val. 297*0b57cec5SDimitry Andric assert(DefMI->hasOneMemOperand()); 298*0b57cec5SDimitry Andric Val = (*DefMI->memoperands_begin())->getValue(); 299*0b57cec5SDimitry Andric if (!Val) 300*0b57cec5SDimitry Andric Val = (*DefMI->memoperands_begin())->getPseudoValue(); 301*0b57cec5SDimitry Andric return true; 302*0b57cec5SDimitry Andric } 303*0b57cec5SDimitry Andric 304*0b57cec5SDimitry Andric unsigned OptimizePICCall::getCount(ValueType Entry) { 305*0b57cec5SDimitry Andric return ScopedHT.lookup(Entry).first; 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric unsigned OptimizePICCall::getReg(ValueType Entry) { 309*0b57cec5SDimitry Andric unsigned Reg = ScopedHT.lookup(Entry).second; 310*0b57cec5SDimitry Andric assert(Reg); 311*0b57cec5SDimitry Andric return Reg; 312*0b57cec5SDimitry Andric } 313*0b57cec5SDimitry Andric 314*0b57cec5SDimitry Andric void OptimizePICCall::incCntAndSetReg(ValueType Entry, unsigned Reg) { 315*0b57cec5SDimitry Andric CntRegP P = ScopedHT.lookup(Entry); 316*0b57cec5SDimitry Andric ScopedHT.insert(Entry, std::make_pair(P.first + 1, Reg)); 317*0b57cec5SDimitry Andric } 318*0b57cec5SDimitry Andric 319*0b57cec5SDimitry Andric /// Return an OptimizeCall object. 320*0b57cec5SDimitry Andric FunctionPass *llvm::createMipsOptimizePICCallPass() { 321*0b57cec5SDimitry Andric return new OptimizePICCall(); 322*0b57cec5SDimitry Andric } 323