Add an option to use a virtual register as the global base register instead of

reserving a physical register ($gp or $28) for that purpose.

This will completely eliminate loads that restore the value of $gp after every
function call, if the register allocator assigns a callee-saved register, or
eliminate unnecessary loads if it assigns a temporary register. 

example:

.cpload $25       // set $gp.
...
.cprestore 16     // store $gp to stack slot 16($sp).
...
jalr $25          // function call. clobbers $gp.
lw $gp, 16($sp)   // not emitted if callee-saved reg is chosen.
...
lw $2, 4($gp)
...
jalr $25          // function call.
lw $gp, 16($sp)   // not emitted if $gp is not live after this instruction.
...

llvm-svn: 151402
This commit is contained in:
Akira Hatanaka 2012-02-24 22:34:47 +00:00
parent 324df5564e
commit b049aef2d1
18 changed files with 275 additions and 98 deletions

View File

@ -244,12 +244,12 @@ def : Pat<(add CPU64Regs:$hi, (MipsLo tconstpool:$lo)),
def : Pat<(add CPU64Regs:$hi, (MipsLo tglobaltlsaddr:$lo)),
(DADDiu CPU64Regs:$hi, tglobaltlsaddr:$lo)>;
def : WrapperPat<tglobaladdr, DADDiu, GP_64>;
def : WrapperPat<tconstpool, DADDiu, GP_64>;
def : WrapperPat<texternalsym, DADDiu, GP_64>;
def : WrapperPat<tblockaddress, DADDiu, GP_64>;
def : WrapperPat<tjumptable, DADDiu, GP_64>;
def : WrapperPat<tglobaltlsaddr, DADDiu, GP_64>;
def : WrapperPat<tglobaladdr, DADDiu, CPU64Regs>;
def : WrapperPat<tconstpool, DADDiu, CPU64Regs>;
def : WrapperPat<texternalsym, DADDiu, CPU64Regs>;
def : WrapperPat<tblockaddress, DADDiu, CPU64Regs>;
def : WrapperPat<tjumptable, DADDiu, CPU64Regs>;
def : WrapperPat<tglobaltlsaddr, DADDiu, CPU64Regs>;
defm : BrcondPats<CPU64Regs, BEQ64, BNE64, SLT64, SLTu64, SLTi64, SLTiu64,
ZERO_64>;

View File

@ -34,6 +34,8 @@
#include "llvm/Instructions.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/TargetRegistry.h"
@ -116,6 +118,16 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
}
}
if (Opc == Mips::SETGP01) {
MCInstLowering.LowerSETGP01(MI, MCInsts);
for (SmallVector<MCInst, 4>::iterator I = MCInsts.begin();
I != MCInsts.end(); ++I)
OutStreamer.EmitInstruction(*I);
return;
}
OutStreamer.EmitInstruction(TmpInst0);
}

View File

@ -44,11 +44,14 @@ namespace {
} // end of anonymous namespace
bool Inserter::runOnMachineFunction(MachineFunction &F) {
if (TM.getRelocationModel() != Reloc::PIC_)
MipsFunctionInfo *MipsFI = F.getInfo<MipsFunctionInfo>();
if ((TM.getRelocationModel() != Reloc::PIC_) ||
(!MipsFI->globalBaseRegFixed()))
return false;
bool Changed = false;
int FI = F.getInfo<MipsFunctionInfo>()->getGPFI();
int FI = MipsFI->getGPFI();
for (MachineFunction::iterator MFI = F.begin(), MFE = F.end();
MFI != MFE; ++MFI) {

View File

@ -67,6 +67,12 @@ bool MipsExpandPseudo::runOnMachineBasicBlock(MachineBasicBlock& MBB) {
default:
++I;
continue;
case Mips::SETGP2:
// Convert "setgp2 $globalreg, $t9" to "addu $globalreg, $v0, $t9"
BuildMI(MBB, I, I->getDebugLoc(), TII->get(Mips::ADDu),
I->getOperand(0).getReg())
.addReg(Mips::V0).addReg(I->getOperand(1).getReg());
break;
case Mips::BuildPairF64:
ExpandBuildPairF64(MBB, I);
break;

View File

@ -136,20 +136,16 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const {
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
const MipsRegisterInfo *RegInfo =
static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo());
MachineRegisterInfo& MRI = MF.getRegInfo();
const MipsInstrInfo &TII =
*static_cast<const MipsInstrInfo*>(MF.getTarget().getInstrInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
bool isPIC = (MF.getTarget().getRelocationModel() == Reloc::PIC_);
unsigned GP = STI.isABI_N64() ? Mips::GP_64 : Mips::GP;
unsigned T9 = STI.isABI_N64() ? Mips::T9_64 : Mips::T9;
unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP;
unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP;
unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO;
unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu;
unsigned ADDiu = STI.isABI_N64() ? Mips::DADDiu : Mips::ADDiu;
unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi;
// First, compute final stack size.
unsigned RegSize = STI.isGP32bit() ? 4 : 8;
@ -164,17 +160,19 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const {
MFI->setStackSize(StackSize);
BuildMI(MBB, MBBI, dl, TII.get(Mips::NOREORDER));
// Emit instructions that set $gp using the the value of $t9.
// O32 uses the directive .cpload while N32/64 requires three instructions to
// do this.
// TODO: Do not emit these instructions if no instructions use $gp.
if (isPIC && STI.isABI_O32())
BuildMI(MBB, MBBI, dl, TII.get(Mips::CPLOAD))
.addReg(RegInfo->getPICCallReg());
BuildMI(MBB, MBBI, dl, TII.get(Mips::NOMACRO));
// Emit instructions that set the global base register if the target ABI is
// O32.
if (isPIC && MipsFI->globalBaseRegSet() && STI.isABI_O32()) {
if (MipsFI->globalBaseRegFixed())
BuildMI(MBB, llvm::prior(MBBI), dl, TII.get(Mips::CPLOAD))
.addReg(RegInfo->getPICCallReg());
else
// See MipsInstrInfo.td for explanation.
BuildMI(MBB, MBBI, dl, TII.get(Mips:: SETGP01), Mips::V0);
}
// No need to allocate space on the stack.
if (StackSize == 0 && !MFI->adjustsStack()) return;
@ -239,21 +237,6 @@ void MipsFrameLowering::emitPrologue(MachineFunction &MF) const {
}
}
if ((STI.isABI_N64() || (isPIC && STI.isABI_N32())) &&
MRI.isPhysRegUsed(GP)) {
// lui $28,%hi(%neg(%gp_rel(fname)))
// addu $28,$28,$25
// addiu $28,$28,%lo(%neg(%gp_rel(fname)))
MachineBasicBlock::iterator InsPos = llvm::prior(MBBI);
const GlobalValue *FName = MF.getFunction();
BuildMI(MBB, MBBI, dl, TII.get(LUi), GP)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
BuildMI(MBB, MBBI, dl, TII.get(ADDu), GP).addReg(GP).addReg(T9);
BuildMI(MBB, MBBI, dl, TII.get(ADDiu), GP).addReg(GP)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
MBBI = ++InsPos;
}
// if framepointer enabled, set it to point to the stack pointer.
if (hasFP(MF)) {
// Insert instruction "move $fp, $sp" at this location.

View File

@ -18,6 +18,7 @@
#include "MipsRegisterInfo.h"
#include "MipsSubtarget.h"
#include "MipsTargetMachine.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "llvm/GlobalValue.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
@ -64,6 +65,7 @@ public:
return "MIPS DAG->DAG Pattern Instruction Selection";
}
virtual bool runOnMachineFunction(MachineFunction &MF);
private:
// Include the pieces autogenerated from the target description.
@ -96,6 +98,8 @@ private:
return CurDAG->getTargetConstant(Imm, Node->getValueType(0));
}
void InitGlobalBaseReg(MachineFunction &MF);
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
char ConstraintCode,
std::vector<SDValue> &OutOps);
@ -103,11 +107,90 @@ private:
}
// Insert instructions to initialize the global base register in the
// first MBB of the function. When the ABI is O32 and the relocation model is
// PIC, the necessary instructions are emitted later to prevent optimization
// passes from moving them.
void MipsDAGToDAGISel::InitGlobalBaseReg(MachineFunction &MF) {
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
if (!MipsFI->globalBaseRegSet())
return;
MachineBasicBlock &MBB = MF.front();
MachineBasicBlock::iterator I = MBB.begin();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg();
bool FixGlobalBaseReg = MipsFI->globalBaseRegFixed();
if (FixGlobalBaseReg) // $gp is the global base register.
V0 = V1 = GlobalBaseReg;
else {
const TargetRegisterClass *RC;
RC = Subtarget.isABI_N64() ?
Mips::CPU64RegsRegisterClass : Mips::CPURegsRegisterClass;
V0 = RegInfo.createVirtualRegister(RC);
V1 = RegInfo.createVirtualRegister(RC);
}
if (Subtarget.isABI_N64()) {
MF.getRegInfo().addLiveIn(Mips::T9_64);
// lui $v0, %hi(%neg(%gp_rel(fname)))
// daddu $v1, $v0, $t9
// daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname)))
const GlobalValue *FName = MF.getFunction();
BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0).addReg(Mips::T9_64);
BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
} else if (MF.getTarget().getRelocationModel() == Reloc::Static) {
// Set global register to __gnu_local_gp.
//
// lui $v0, %hi(__gnu_local_gp)
// addiu $globalbasereg, $v0, %lo(__gnu_local_gp)
BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0)
.addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI);
BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0)
.addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO);
} else {
MF.getRegInfo().addLiveIn(Mips::T9);
if (Subtarget.isABI_N32()) {
// lui $v0, %hi(%neg(%gp_rel(fname)))
// addu $v1, $v0, $t9
// addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname)))
const GlobalValue *FName = MF.getFunction();
BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9);
BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
} else if (!MipsFI->globalBaseRegFixed()) {
assert(Subtarget.isABI_O32());
BuildMI(MBB, I, DL, TII.get(Mips::SETGP2), GlobalBaseReg)
.addReg(Mips::T9);
}
}
}
bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
bool Ret = SelectionDAGISel::runOnMachineFunction(MF);
InitGlobalBaseReg(MF);
return Ret;
}
/// getGlobalBaseReg - Output the instructions required to put the
/// GOT address into a register.
SDNode *MipsDAGToDAGISel::getGlobalBaseReg() {
unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
unsigned GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg();
return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
}
@ -116,7 +199,6 @@ SDNode *MipsDAGToDAGISel::getGlobalBaseReg() {
bool MipsDAGToDAGISel::
SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
EVT ValTy = Addr.getValueType();
unsigned GPReg = ValTy == MVT::i32 ? Mips::GP : Mips::GP_64;
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
@ -127,8 +209,8 @@ SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
// on PIC code Load GA
if (Addr.getOpcode() == MipsISD::Wrapper) {
Base = CurDAG->getRegister(GPReg, ValTy);
Offset = Addr.getOperand(0);
Base = Addr.getOperand(0);
Offset = Addr.getOperand(1);
return true;
}

View File

@ -48,6 +48,11 @@ static bool IsShiftedMask(uint64_t I, uint64_t &Pos, uint64_t &Size) {
return true;
}
static SDValue GetGlobalReg(SelectionDAG &DAG, EVT Ty) {
MipsFunctionInfo *FI = DAG.getMachineFunction().getInfo<MipsFunctionInfo>();
return DAG.getRegister(FI->getGlobalBaseReg(), Ty);
}
const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
case MipsISD::JmpLink: return "MipsISD::JmpLink";
@ -1496,7 +1501,7 @@ SDValue MipsTargetLowering::LowerGlobalAddress(SDValue Op,
(HasGotOfst ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT_DISP) :
(HasGotOfst ? MipsII::MO_GOT : MipsII::MO_GOT16);
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, ValTy, 0, GotFlag);
GA = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GA);
GA = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), GA);
SDValue ResNode = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), GA,
MachinePointerInfo(), false, false, false, 0);
// On functions and global targets not internal linked only
@ -1529,7 +1534,8 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op,
unsigned GOTFlag = IsN64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT;
unsigned OFSTFlag = IsN64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO;
SDValue BAGOTOffset = DAG.getBlockAddress(BA, ValTy, true, GOTFlag);
BAGOTOffset = DAG.getNode(MipsISD::Wrapper, dl, ValTy, BAGOTOffset);
BAGOTOffset = DAG.getNode(MipsISD::Wrapper, dl, ValTy,
GetGlobalReg(DAG, ValTy), BAGOTOffset);
SDValue BALOOffset = DAG.getBlockAddress(BA, ValTy, true, OFSTFlag);
SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), BAGOTOffset,
MachinePointerInfo(), false, false, false, 0);
@ -1554,7 +1560,8 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
bool LocalDynamic = GV->hasInternalLinkage();
unsigned Flag = LocalDynamic ? MipsII::MO_TLSLDM :MipsII::MO_TLSGD;
SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Flag);
SDValue Argument = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, TGA);
SDValue Argument = DAG.getNode(MipsISD::Wrapper, dl, PtrVT,
GetGlobalReg(DAG, PtrVT), TGA);
unsigned PtrSize = PtrVT.getSizeInBits();
IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize);
@ -1591,7 +1598,8 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
// Initial Exec TLS Model
SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
MipsII::MO_GOTTPREL);
TGA = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, TGA);
TGA = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT),
TGA);
Offset = DAG.getLoad(PtrVT, dl,
DAG.getEntryNode(), TGA, MachinePointerInfo(),
false, false, false, 0);
@ -1628,7 +1636,8 @@ LowerJumpTable(SDValue Op, SelectionDAG &DAG) const
unsigned GOTFlag = IsN64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT;
unsigned OfstFlag = IsN64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO;
JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, GOTFlag);
JTI = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, JTI);
JTI = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT),
JTI);
HiPart = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), JTI,
MachinePointerInfo(), false, false, false, 0);
JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OfstFlag);
@ -1671,7 +1680,7 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) const
unsigned OFSTFlag = IsN64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO;
SDValue CP = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(),
N->getOffset(), GOTFlag);
CP = DAG.getNode(MipsISD::Wrapper, dl, ValTy, CP);
CP = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), CP);
SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), CP,
MachinePointerInfo::getConstantPool(), false,
false, false, 0);
@ -2210,7 +2219,7 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee,
// If this is the first call, create a stack frame object that points to
// a location to which .cprestore saves $gp.
if (IsO32 && IsPIC && !MipsFI->getGPFI())
if (IsO32 && IsPIC && MipsFI->globalBaseRegFixed() && !MipsFI->getGPFI())
MipsFI->setGPFI(MFI->CreateFixedObject(4, 0, true));
// Get the frame index of the stack frame object that points to the location
@ -2384,7 +2393,8 @@ MipsTargetLowering::LowerCall(SDValue InChain, SDValue Callee,
if (IsPICCall) {
if (GlobalOrExternal) {
// Load callee address
Callee = DAG.getNode(MipsISD::Wrapper, dl, getPointerTy(), Callee);
Callee = DAG.getNode(MipsISD::Wrapper, dl, getPointerTy(),
GetGlobalReg(DAG, getPointerTy()), Callee);
SDValue LoadValue = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
Callee, MachinePointerInfo::getGOT(),
false, false, false, 0);

View File

@ -454,30 +454,3 @@ ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const
return false;
}
/// getGlobalBaseReg - Return a virtual register initialized with the
/// the global base register value. Output instructions required to
/// initialize the register in the function entry block, if necessary.
///
unsigned MipsInstrInfo::getGlobalBaseReg(MachineFunction *MF) const {
MipsFunctionInfo *MipsFI = MF->getInfo<MipsFunctionInfo>();
unsigned GlobalBaseReg = MipsFI->getGlobalBaseReg();
if (GlobalBaseReg != 0)
return GlobalBaseReg;
// Insert the set of GlobalBaseReg into the first MBB of the function
MachineBasicBlock &FirstMBB = MF->front();
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
MachineRegisterInfo &RegInfo = MF->getRegInfo();
const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
unsigned GP = IsN64 ? Mips::GP_64 : Mips::GP;
const TargetRegisterClass *RC
= IsN64 ? Mips::CPU64RegsRegisterClass : Mips::CPURegsRegisterClass;
GlobalBaseReg = RegInfo.createVirtualRegister(RC);
BuildMI(FirstMBB, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY),
GlobalBaseReg).addReg(GP);
RegInfo.addLiveIn(GP);
MipsFI->setGlobalBaseReg(GlobalBaseReg);
return GlobalBaseReg;
}

View File

@ -103,12 +103,6 @@ public:
/// Insert nop instruction when hazard condition is found
virtual void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const;
/// getGlobalBaseReg - Return a virtual register initialized with the
/// the global base register value. Output instructions required to
/// initialize the register in the function entry block, if necessary.
///
unsigned getGlobalBaseReg(MachineFunction *MF) const;
};
}

View File

@ -107,7 +107,7 @@ def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsDivRem,
// movn %got(d)($gp), %got(c)($gp), $4
// This instruction is illegal since movn can take only register operands.
def MipsWrapper : SDNode<"MipsISD::Wrapper", SDTIntUnaryOp>;
def MipsWrapper : SDNode<"MipsISD::Wrapper", SDTIntBinOp>;
// Pointer to dynamically allocated stack area.
def MipsDynAlloc : SDNode<"MipsISD::DynAlloc", SDT_MipsDynAlloc,
@ -739,6 +739,22 @@ def ATMACRO : MipsPseudo<(outs), (ins), ".set\tat", []>;
def CPLOAD : MipsPseudo<(outs), (ins CPURegs:$picreg), ".cpload\t$picreg", []>;
def CPRESTORE : MipsPseudo<(outs), (ins i32imm:$loc), ".cprestore\t$loc", []>;
// For O32 ABI & PIC & non-fixed global base register, the following instruction
// seqeunce is emitted to set the global base register:
//
// 0. lui $2, %hi(_gp_disp)
// 1. addiu $2, $2, %lo(_gp_disp)
// 2. addu $globalbasereg, $2, $t9
//
// SETGP01 is emitted during Prologue/Epilogue insertion and then converted to
// instructions 0 and 1 in the sequence above during MC lowering.
// SETGP2 is emitted just before register allocation and converted to
// instruction 2 just prior to post-RA scheduling.
def SETGP01 : MipsPseudo<(outs CPURegs:$dst), (ins), "", []>;
def SETGP2 : MipsPseudo<(outs CPURegs:$globalreg), (ins CPURegs:$picreg), "",
[]>;
let usesCustomInserter = 1 in {
defm ATOMIC_LOAD_ADD_I8 : Atomic2Ops32<atomic_load_add_8, "load_add_8">;
defm ATOMIC_LOAD_ADD_I16 : Atomic2Ops32<atomic_load_add_16, "load_add_16">;
@ -995,16 +1011,16 @@ def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)),
(ADDiu CPURegs:$gp, tconstpool:$in)>;
// wrapper_pic
class WrapperPat<SDNode node, Instruction ADDiuOp, Register GPReg>:
Pat<(MipsWrapper node:$in),
(ADDiuOp GPReg, node:$in)>;
class WrapperPat<SDNode node, Instruction ADDiuOp, RegisterClass RC>:
Pat<(MipsWrapper RC:$gp, node:$in),
(ADDiuOp RC:$gp, node:$in)>;
def : WrapperPat<tglobaladdr, ADDiu, GP>;
def : WrapperPat<tconstpool, ADDiu, GP>;
def : WrapperPat<texternalsym, ADDiu, GP>;
def : WrapperPat<tblockaddress, ADDiu, GP>;
def : WrapperPat<tjumptable, ADDiu, GP>;
def : WrapperPat<tglobaltlsaddr, ADDiu, GP>;
def : WrapperPat<tglobaladdr, ADDiu, CPURegs>;
def : WrapperPat<tconstpool, ADDiu, CPURegs>;
def : WrapperPat<texternalsym, ADDiu, CPURegs>;
def : WrapperPat<tblockaddress, ADDiu, CPURegs>;
def : WrapperPat<tjumptable, ADDiu, CPURegs>;
def : WrapperPat<tglobaltlsaddr, ADDiu, CPURegs>;
// Mips does not have "not", so we expand our way
def : Pat<(not CPURegs:$in),

View File

@ -321,3 +321,29 @@ void MipsMCInstLower::LowerUnalignedLoadStore(const MachineInstr *MI,
if (!TwoInstructions) MCInsts.push_back(Instr3);
}
// Convert
// "setgp01 $reg"
// to
// "lui $reg, %hi(_gp_disp)"
// "addiu $reg, $reg, %lo(_gp_disp)"
void MipsMCInstLower::LowerSETGP01(const MachineInstr *MI,
SmallVector<MCInst, 4>& MCInsts) {
const MachineOperand &MO = MI->getOperand(0);
assert(MO.isReg());
MCOperand RegOpnd = MCOperand::CreateReg(MO.getReg());
StringRef SymName("_gp_disp");
const MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName);
const MCSymbolRefExpr *MCSym;
MCInsts.resize(2);
MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, Ctx);
MCInsts[0].setOpcode(Mips::LUi);
MCInsts[0].addOperand(RegOpnd);
MCInsts[0].addOperand(MCOperand::CreateExpr(MCSym));
MCSym = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, Ctx);
MCInsts[1].setOpcode(Mips::ADDiu);
MCInsts[1].addOperand(RegOpnd);
MCInsts[1].addOperand(RegOpnd);
MCInsts[1].addOperand(MCOperand::CreateExpr(MCSym));
}

View File

@ -39,6 +39,7 @@ public:
void LowerCPRESTORE(const MachineInstr *MI, SmallVector<MCInst, 4>& MCInsts);
void LowerUnalignedLoadStore(const MachineInstr *MI,
SmallVector<MCInst, 4>& MCInsts);
void LowerSETGP01(const MachineInstr *MI, SmallVector<MCInst, 4>& MCInsts);
private:
MCOperand LowerSymbolOperand(const MachineOperand &MO,
MachineOperandType MOTy, unsigned Offset) const;

View File

@ -8,7 +8,43 @@
//===----------------------------------------------------------------------===//
#include "MipsMachineFunction.h"
#include "MipsInstrInfo.h"
#include "MipsSubtarget.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
static cl::opt<bool>
FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true),
cl::desc("Always use $gp as the global base register."));
bool MipsFunctionInfo::globalBaseRegFixed() const {
return FixGlobalBaseReg;
}
bool MipsFunctionInfo::globalBaseRegSet() const {
return GlobalBaseReg;
}
unsigned MipsFunctionInfo::getGlobalBaseReg() {
// Return if it has already been initialized.
if (GlobalBaseReg)
return GlobalBaseReg;
const MipsSubtarget &ST = MF.getTarget().getSubtarget<MipsSubtarget>();
if (FixGlobalBaseReg) // $gp is the global base register.
return GlobalBaseReg = ST.isABI_N64() ? Mips::GP_64 : Mips::GP;
const TargetRegisterClass *RC;
RC = ST.isABI_N64() ?
Mips::CPU64RegsRegisterClass : Mips::CPURegsRegisterClass;
return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC);
}
void MipsFunctionInfo::anchor() { }

View File

@ -91,8 +91,9 @@ public:
unsigned getSRetReturnReg() const { return SRetReturnReg; }
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
bool globalBaseRegFixed() const;
bool globalBaseRegSet() const;
unsigned getGlobalBaseReg();
int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; }

View File

@ -101,12 +101,12 @@ BitVector MipsRegisterInfo::
getReservedRegs(const MachineFunction &MF) const {
static const unsigned ReservedCPURegs[] = {
Mips::ZERO, Mips::AT, Mips::K0, Mips::K1,
Mips::GP, Mips::SP, Mips::FP, Mips::RA
Mips::SP, Mips::FP, Mips::RA
};
static const unsigned ReservedCPU64Regs[] = {
Mips::ZERO_64, Mips::AT_64, Mips::K0_64, Mips::K1_64,
Mips::GP_64, Mips::SP_64, Mips::FP_64, Mips::RA_64
Mips::SP_64, Mips::FP_64, Mips::RA_64
};
BitVector Reserved(getNumRegs());
@ -135,6 +135,12 @@ getReservedRegs(const MachineFunction &MF) const {
Reserved.set(*Reg);
}
// If GP is dedicated as a global base register, reserve it.
if (MF.getInfo<MipsFunctionInfo>()->globalBaseRegFixed()) {
Reserved.set(Mips::GP);
Reserved.set(Mips::GP_64);
}
return Reserved;
}

View File

@ -106,7 +106,7 @@ public:
virtual bool addInstSelector();
virtual bool addPreRegAlloc();
virtual bool addPostRegAlloc();
virtual bool addPreSched2();
virtual bool addPreEmitPass();
};
} // namespace
@ -140,7 +140,7 @@ bool MipsPassConfig::addPreRegAlloc() {
return true;
}
bool MipsPassConfig::addPostRegAlloc() {
bool MipsPassConfig::addPreSched2() {
PM.add(createMipsExpandPseudoPass(getMipsTargetMachine()));
return true;
}

View File

@ -0,0 +1,22 @@
; RUN: llc < %s -march=mipsel -mips-fix-global-base-reg=false | FileCheck %s
@g0 = external global i32
@g1 = external global i32
@g2 = external global i32
define void @foo1() nounwind {
entry:
; CHECK-NOT: .cpload
; CHECK-NOT: .cprestore
; CHECK: lui $[[R0:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[R1:[0-9]+]], $[[R0]], %lo(_gp_disp)
; CHECK: addu $[[GP:[0-9]+]], $[[R1]], $25
; CHECK: lw ${{[0-9]+}}, %call16(foo2)($[[GP]])
tail call void @foo2(i32* @g0) nounwind
tail call void @foo2(i32* @g1) nounwind
tail call void @foo2(i32* @g2) nounwind
ret void
}
declare void @foo2(i32*)

View File

@ -1,7 +1,8 @@
; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=PIC
; RUN: llc -march=mipsel -relocation-model=static < %s \
; RUN: | FileCheck %s -check-prefix=STATIC
; RUN: llc -march=mipsel -relocation-model=static < %s \
; RUN: -mips-fix-global-base-reg=false | FileCheck %s -check-prefix=STATICGP
@t1 = thread_local global i32 0, align 4
@ -39,6 +40,11 @@ entry:
; PIC: jalr $25
; PIC: lw $2, 0($2)
; STATICGP: lui $[[R0:[0-9]+]], %hi(__gnu_local_gp)
; STATICGP: addiu $[[GP:[0-9]+]], $[[R0]], %lo(__gnu_local_gp)
; STATICGP: lw ${{[0-9]+}}, %gottprel(t2)($[[GP]])
; STATIC: lui $gp, %hi(__gnu_local_gp)
; STATIC: addiu $gp, $gp, %lo(__gnu_local_gp)
; STATIC: rdhwr $3, $29
; STATIC: lw $[[R0:[0-9]+]], %gottprel(t2)($gp)
; STATIC: addu $[[R1:[0-9]+]], $3, $[[R0]]