1*0b57cec5SDimitry Andric //===-- MipsMachineFunctionInfo.cpp - Private data used for Mips ----------===// 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 #include "MipsMachineFunction.h" 10*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsABIInfo.h" 11*0b57cec5SDimitry Andric #include "MipsSubtarget.h" 12*0b57cec5SDimitry Andric #include "MipsTargetMachine.h" 13*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 14*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 15*0b57cec5SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h" 16*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric using namespace llvm; 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric static cl::opt<bool> 22*0b57cec5SDimitry Andric FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true), 23*0b57cec5SDimitry Andric cl::desc("Always use $gp as the global base register.")); 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric MipsFunctionInfo::~MipsFunctionInfo() = default; 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric bool MipsFunctionInfo::globalBaseRegSet() const { 28*0b57cec5SDimitry Andric return GlobalBaseReg; 29*0b57cec5SDimitry Andric } 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric static const TargetRegisterClass &getGlobalBaseRegClass(MachineFunction &MF) { 32*0b57cec5SDimitry Andric auto &STI = static_cast<const MipsSubtarget &>(MF.getSubtarget()); 33*0b57cec5SDimitry Andric auto &TM = static_cast<const MipsTargetMachine &>(MF.getTarget()); 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric if (STI.inMips16Mode()) 36*0b57cec5SDimitry Andric return Mips::CPU16RegsRegClass; 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric if (STI.inMicroMipsMode()) 39*0b57cec5SDimitry Andric return Mips::GPRMM16RegClass; 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric if (TM.getABI().IsN64()) 42*0b57cec5SDimitry Andric return Mips::GPR64RegClass; 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric return Mips::GPR32RegClass; 45*0b57cec5SDimitry Andric } 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric Register MipsFunctionInfo::getGlobalBaseReg() { 48*0b57cec5SDimitry Andric if (!GlobalBaseReg) 49*0b57cec5SDimitry Andric GlobalBaseReg = 50*0b57cec5SDimitry Andric MF.getRegInfo().createVirtualRegister(&getGlobalBaseRegClass(MF)); 51*0b57cec5SDimitry Andric return GlobalBaseReg; 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric Register MipsFunctionInfo::getGlobalBaseRegForGlobalISel() { 55*0b57cec5SDimitry Andric if (!GlobalBaseReg) { 56*0b57cec5SDimitry Andric getGlobalBaseReg(); 57*0b57cec5SDimitry Andric initGlobalBaseReg(); 58*0b57cec5SDimitry Andric } 59*0b57cec5SDimitry Andric return GlobalBaseReg; 60*0b57cec5SDimitry Andric } 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric void MipsFunctionInfo::initGlobalBaseReg() { 63*0b57cec5SDimitry Andric if (!GlobalBaseReg) 64*0b57cec5SDimitry Andric return; 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric MachineBasicBlock &MBB = MF.front(); 67*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.begin(); 68*0b57cec5SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 69*0b57cec5SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); 70*0b57cec5SDimitry Andric DebugLoc DL; 71*0b57cec5SDimitry Andric unsigned V0, V1; 72*0b57cec5SDimitry Andric const TargetRegisterClass *RC; 73*0b57cec5SDimitry Andric const MipsABIInfo &ABI = 74*0b57cec5SDimitry Andric static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI(); 75*0b57cec5SDimitry Andric RC = (ABI.IsN64()) ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric V0 = RegInfo.createVirtualRegister(RC); 78*0b57cec5SDimitry Andric V1 = RegInfo.createVirtualRegister(RC); 79*0b57cec5SDimitry Andric 80*0b57cec5SDimitry Andric if (ABI.IsN64()) { 81*0b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(Mips::T9_64); 82*0b57cec5SDimitry Andric MBB.addLiveIn(Mips::T9_64); 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric // lui $v0, %hi(%neg(%gp_rel(fname))) 85*0b57cec5SDimitry Andric // daddu $v1, $v0, $t9 86*0b57cec5SDimitry Andric // daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) 87*0b57cec5SDimitry Andric const GlobalValue *FName = &MF.getFunction(); 88*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0) 89*0b57cec5SDimitry Andric .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); 90*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0) 91*0b57cec5SDimitry Andric .addReg(Mips::T9_64); 92*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1) 93*0b57cec5SDimitry Andric .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); 94*0b57cec5SDimitry Andric return; 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric if (!MF.getTarget().isPositionIndependent()) { 98*0b57cec5SDimitry Andric // Set global register to __gnu_local_gp. 99*0b57cec5SDimitry Andric // 100*0b57cec5SDimitry Andric // lui $v0, %hi(__gnu_local_gp) 101*0b57cec5SDimitry Andric // addiu $globalbasereg, $v0, %lo(__gnu_local_gp) 102*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) 103*0b57cec5SDimitry Andric .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI); 104*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0) 105*0b57cec5SDimitry Andric .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO); 106*0b57cec5SDimitry Andric return; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(Mips::T9); 110*0b57cec5SDimitry Andric MBB.addLiveIn(Mips::T9); 111*0b57cec5SDimitry Andric 112*0b57cec5SDimitry Andric if (ABI.IsN32()) { 113*0b57cec5SDimitry Andric // lui $v0, %hi(%neg(%gp_rel(fname))) 114*0b57cec5SDimitry Andric // addu $v1, $v0, $t9 115*0b57cec5SDimitry Andric // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) 116*0b57cec5SDimitry Andric const GlobalValue *FName = &MF.getFunction(); 117*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) 118*0b57cec5SDimitry Andric .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); 119*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9); 120*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1) 121*0b57cec5SDimitry Andric .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); 122*0b57cec5SDimitry Andric return; 123*0b57cec5SDimitry Andric } 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric assert(ABI.IsO32()); 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric // For O32 ABI, the following instruction sequence is emitted to initialize 128*0b57cec5SDimitry Andric // the global base register: 129*0b57cec5SDimitry Andric // 130*0b57cec5SDimitry Andric // 0. lui $2, %hi(_gp_disp) 131*0b57cec5SDimitry Andric // 1. addiu $2, $2, %lo(_gp_disp) 132*0b57cec5SDimitry Andric // 2. addu $globalbasereg, $2, $t9 133*0b57cec5SDimitry Andric // 134*0b57cec5SDimitry Andric // We emit only the last instruction here. 135*0b57cec5SDimitry Andric // 136*0b57cec5SDimitry Andric // GNU linker requires that the first two instructions appear at the beginning 137*0b57cec5SDimitry Andric // of a function and no instructions be inserted before or between them. 138*0b57cec5SDimitry Andric // The two instructions are emitted during lowering to MC layer in order to 139*0b57cec5SDimitry Andric // avoid any reordering. 140*0b57cec5SDimitry Andric // 141*0b57cec5SDimitry Andric // Register $2 (Mips::V0) is added to the list of live-in registers to ensure 142*0b57cec5SDimitry Andric // the value instruction 1 (addiu) defines is valid when instruction 2 (addu) 143*0b57cec5SDimitry Andric // reads it. 144*0b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(Mips::V0); 145*0b57cec5SDimitry Andric MBB.addLiveIn(Mips::V0); 146*0b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::ADDu), GlobalBaseReg) 147*0b57cec5SDimitry Andric .addReg(Mips::V0).addReg(Mips::T9); 148*0b57cec5SDimitry Andric } 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric void MipsFunctionInfo::createEhDataRegsFI() { 151*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 152*0b57cec5SDimitry Andric for (int I = 0; I < 4; ++I) { 153*0b57cec5SDimitry Andric const TargetRegisterClass &RC = 154*0b57cec5SDimitry Andric static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsN64() 155*0b57cec5SDimitry Andric ? Mips::GPR64RegClass 156*0b57cec5SDimitry Andric : Mips::GPR32RegClass; 157*0b57cec5SDimitry Andric 158*0b57cec5SDimitry Andric EhDataRegFI[I] = MF.getFrameInfo().CreateStackObject(TRI.getSpillSize(RC), 159*0b57cec5SDimitry Andric TRI.getSpillAlignment(RC), false); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric void MipsFunctionInfo::createISRRegFI() { 164*0b57cec5SDimitry Andric // ISRs require spill slots for Status & ErrorPC Coprocessor 0 registers. 165*0b57cec5SDimitry Andric // The current implementation only supports Mips32r2+ not Mips64rX. Status 166*0b57cec5SDimitry Andric // is always 32 bits, ErrorPC is 32 or 64 bits dependent on architecture, 167*0b57cec5SDimitry Andric // however Mips32r2+ is the supported architecture. 168*0b57cec5SDimitry Andric const TargetRegisterClass &RC = Mips::GPR32RegClass; 169*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric for (int I = 0; I < 2; ++I) 172*0b57cec5SDimitry Andric ISRDataRegFI[I] = MF.getFrameInfo().CreateStackObject( 173*0b57cec5SDimitry Andric TRI.getSpillSize(RC), TRI.getSpillAlignment(RC), false); 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric bool MipsFunctionInfo::isEhDataRegFI(int FI) const { 177*0b57cec5SDimitry Andric return CallsEhReturn && (FI == EhDataRegFI[0] || FI == EhDataRegFI[1] 178*0b57cec5SDimitry Andric || FI == EhDataRegFI[2] || FI == EhDataRegFI[3]); 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric bool MipsFunctionInfo::isISRRegFI(int FI) const { 182*0b57cec5SDimitry Andric return IsISR && (FI == ISRDataRegFI[0] || FI == ISRDataRegFI[1]); 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric MachinePointerInfo MipsFunctionInfo::callPtrInfo(const char *ES) { 185*0b57cec5SDimitry Andric return MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)); 186*0b57cec5SDimitry Andric } 187*0b57cec5SDimitry Andric 188*0b57cec5SDimitry Andric MachinePointerInfo MipsFunctionInfo::callPtrInfo(const GlobalValue *GV) { 189*0b57cec5SDimitry Andric return MachinePointerInfo(MF.getPSVManager().getGlobalValueCallEntry(GV)); 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric int MipsFunctionInfo::getMoveF64ViaSpillFI(const TargetRegisterClass *RC) { 193*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 194*0b57cec5SDimitry Andric if (MoveF64ViaSpillFI == -1) { 195*0b57cec5SDimitry Andric MoveF64ViaSpillFI = MF.getFrameInfo().CreateStackObject( 196*0b57cec5SDimitry Andric TRI.getSpillSize(*RC), TRI.getSpillAlignment(*RC), false); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric return MoveF64ViaSpillFI; 199*0b57cec5SDimitry Andric } 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric void MipsFunctionInfo::anchor() {} 202