Emit callee-saved regs spills / restores

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75943 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 53f8d29..335d460 100644
--- a/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -26,7 +26,30 @@
 
 SystemZInstrInfo::SystemZInstrInfo(SystemZTargetMachine &tm)
   : TargetInstrInfoImpl(SystemZInsts, array_lengthof(SystemZInsts)),
-    RI(tm, *this), TM(tm) {}
+    RI(tm, *this), TM(tm) {
+  // Fill the spill offsets map
+  static const unsigned SpillOffsTab[][2] = {
+    { SystemZ::R2D,  0x10 },
+    { SystemZ::R3D,  0x18 },
+    { SystemZ::R4D,  0x20 },
+    { SystemZ::R5D,  0x28 },
+    { SystemZ::R6D,  0x30 },
+    { SystemZ::R7D,  0x38 },
+    { SystemZ::R8D,  0x40 },
+    { SystemZ::R9D,  0x48 },
+    { SystemZ::R10D, 0x50 },
+    { SystemZ::R11D, 0x58 },
+    { SystemZ::R12D, 0x60 },
+    { SystemZ::R13D, 0x68 },
+    { SystemZ::R14D, 0x70 },
+    { SystemZ::R15D, 0x78 }
+  };
+
+  RegSpillOffsets.grow(SystemZ::NUM_TARGET_REGS);
+
+  for (unsigned i = 0, e = array_lengthof(SpillOffsTab); i != e; ++i)
+    RegSpillOffsets[SpillOffsTab[i][0]] = SpillOffsTab[i][1];
+}
 
 void SystemZInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                           MachineBasicBlock::iterator MI,
@@ -117,13 +140,52 @@
 SystemZInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
                                            MachineBasicBlock::iterator MI,
                                 const std::vector<CalleeSavedInfo> &CSI) const {
-  if (CSI.empty())
-    return false;
+  DebugLoc DL = DebugLoc::getUnknownLoc();
+  if (MI != MBB.end()) DL = MI->getDebugLoc();
 
   MachineFunction &MF = *MBB.getParent();
   SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
   MFI->setCalleeSavedFrameSize(CSI.size() * 8);
 
+  // Scan the callee-saved and find the bounds of register spill area.
+  unsigned LowReg = 0, HighReg = 0, StartOffset = -1U, EndOffset = 0;
+  for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
+    unsigned Reg = CSI[i].getReg();
+    unsigned Offset = RegSpillOffsets[Reg];
+    if (StartOffset > Offset) {
+      LowReg = Reg; StartOffset = Offset;
+    }
+    if (EndOffset < Offset) {
+      HighReg = Reg; EndOffset = RegSpillOffsets[Reg];
+    }
+  }
+
+  // Save information for epilogue inserter.
+  MFI->setLowReg(LowReg); MFI->setHighReg(HighReg);
+
+  // Build a store instruction. Use STORE MULTIPLE instruction if there are many
+  // registers to store, otherwise - just STORE.
+  MachineInstrBuilder MIB =
+    BuildMI(MBB, MI, DL, get((LowReg == HighReg ?
+                              SystemZ::MOV64mr : SystemZ::MOV64mrm)));
+
+  // Add store operands.
+  MIB.addReg(SystemZ::R15D).addImm(StartOffset);
+  if (LowReg == HighReg)
+    MIB.addReg(0);
+  MIB.addReg(LowReg, RegState::Kill);
+  if (LowReg != HighReg)
+    MIB.addReg(HighReg, RegState::Kill);
+
+  // Do a second scan adding regs as being killed by instruction
+  for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
+    unsigned Reg = CSI[i].getReg();
+    // Add the callee-saved register as live-in. It's killed at the spill.
+    MBB.addLiveIn(Reg);
+    if (Reg != LowReg && Reg != HighReg)
+      MIB.addReg(Reg, RegState::ImplicitKill);
+  }
+
   return true;
 }
 
@@ -131,6 +193,41 @@
 SystemZInstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
                                              MachineBasicBlock::iterator MI,
                                 const std::vector<CalleeSavedInfo> &CSI) const {
+  if (CSI.empty())
+    return false;
+
+  DebugLoc DL = DebugLoc::getUnknownLoc();
+  if (MI != MBB.end()) DL = MI->getDebugLoc();
+
+  MachineFunction &MF = *MBB.getParent();
+  const TargetRegisterInfo *RegInfo= MF.getTarget().getRegisterInfo();
+  SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
+
+  unsigned LowReg = MFI->getLowReg(), HighReg = MFI->getHighReg();
+  unsigned StartOffset = RegSpillOffsets[LowReg];
+
+  // Build a load instruction. Use LOAD MULTIPLE instruction if there are many
+  // registers to load, otherwise - just LOAD.
+  MachineInstrBuilder MIB =
+    BuildMI(MBB, MI, DL, get((LowReg == HighReg ?
+                              SystemZ::MOV64rm : SystemZ::MOV64rmm)));
+  // Add store operands.
+  MIB.addReg(LowReg, RegState::Define);
+  if (LowReg != HighReg)
+    MIB.addReg(HighReg, RegState::Define);
+
+  MIB.addReg((RegInfo->hasFP(MF) ? SystemZ::R11D : SystemZ::R15D));
+  MIB.addImm(StartOffset);
+  if (LowReg == HighReg)
+    MIB.addReg(0);
+
+  // Do a second scan adding regs as being defined by instruction
+  for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
+    unsigned Reg = CSI[i].getReg();
+    if (Reg != LowReg && Reg != HighReg)
+      MIB.addReg(Reg, RegState::ImplicitDefine);
+  }
+
   return true;
 }