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
diff --git a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 73533eb..281399e 100644
--- a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -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 @@
     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 @@
     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 @@
 
 }
 
+// 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 @@
 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 @@
 
   // 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;
   }