Emit callee-saved regs spills / restores

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75943 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anton Korobeynikov 2009-07-16 13:51:12 +00:00
parent 33b350bf24
commit ef5decab53
8 changed files with 189 additions and 37 deletions

View File

@ -26,7 +26,30 @@ using namespace llvm;
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 @@ bool
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 @@ bool
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;
}

View File

@ -14,8 +14,9 @@
#ifndef LLVM_TARGET_SYSTEMZINSTRINFO_H
#define LLVM_TARGET_SYSTEMZINSTRINFO_H
#include "llvm/Target/TargetInstrInfo.h"
#include "SystemZRegisterInfo.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/Target/TargetInstrInfo.h"
namespace llvm {
@ -24,6 +25,7 @@ class SystemZTargetMachine;
class SystemZInstrInfo : public TargetInstrInfoImpl {
const SystemZRegisterInfo RI;
SystemZTargetMachine &TM;
IndexedMap<unsigned> RegSpillOffsets;
public:
explicit SystemZInstrInfo(SystemZTargetMachine &TM);

View File

@ -195,19 +195,12 @@ def laaddr : Operand<i64>,
//===----------------------------------------------------------------------===//
// Instruction list..
// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into
// a stack adjustment and the codegen must know that they may modify the stack
// pointer before prolog-epilog rewriting occurs.
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
// sub / add which can clobber R15D.
let Defs = [R15D], Uses = [R15D] in {
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt),
"#ADJCALLSTACKDOWN",
[(SystemZcallseq_start timm:$amt)]>;
def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
"#ADJCALLSTACKUP",
[(SystemZcallseq_end timm:$amt1, timm:$amt2)]>;
}
//===----------------------------------------------------------------------===//
@ -215,7 +208,7 @@ def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
//
// FIXME: Provide proper encoding!
let isReturn = 1, isTerminator = 1, Uses = [R14D] in {
let isReturn = 1, isTerminator = 1 in {
def RET : Pseudo<(outs), (ins), "br\t%r14", [(SystemZretflag)]>;
}
@ -224,12 +217,9 @@ let isReturn = 1, isTerminator = 1, Uses = [R14D] in {
//
let isCall = 1 in
// All calls clobber the non-callee saved registers. R15 is marked as
// a use to prevent stack-pointer assignments that appear immediately
// before calls from potentially appearing dead. Uses for argument
// registers are added manually.
let Defs = [R0D, R1D, R3D, R4D, R5D, R14D, R15D],
Uses = [R15D] in {
// All calls clobber the non-callee saved registers (except R14 which we
// handle separately). Uses for argument registers are added manually.
let Defs = [R0D, R1D, R3D, R4D, R5D] in {
def CALLi : Pseudo<(outs), (ins i64imm:$dst, variable_ops),
"brasl\t%r14, $dst", [(SystemZcall imm:$dst)]>;
def CALLr : Pseudo<(outs), (ins ADDR64:$dst, variable_ops),
@ -370,6 +360,22 @@ def MOV64m32r : Pseudo<(outs), (ins rriaddr:$dst, GR64:$src),
"sty\t{$src, $dst}",
[(truncstorei32 GR64:$src, rriaddr:$dst)]>;
// multiple regs moves
// FIXME: should we use multiple arg nodes?
def MOV32mrm : Pseudo<(outs), (ins riaddr:$dst, GR32:$from, GR32:$to),
"stmy\t{$from, $to, $dst}",
[]>;
def MOV64mrm : Pseudo<(outs), (ins riaddr:$dst, GR64:$from, GR64:$to),
"stmg\t{$from, $to, $dst}",
[]>;
def MOV32rmm : Pseudo<(outs GR32:$from, GR32:$to), (ins riaddr:$dst),
"lmy\t{$from, $to, $dst}",
[]>;
def MOV64rmm : Pseudo<(outs GR64:$from, GR64:$to), (ins riaddr:$dst),
"lmg\t{$from, $to, $dst}",
[]>;
//===----------------------------------------------------------------------===//
// Arithmetic Instructions

View File

@ -25,6 +25,11 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
/// stack frame in bytes.
unsigned CalleeSavedFrameSize;
/// LowReg - Low register of range of callee-saved registers to store.
unsigned LowReg;
/// HighReg - High register of range of callee-saved registers to store.
unsigned HighReg;
public:
SystemZMachineFunctionInfo() : CalleeSavedFrameSize(0) {}
@ -32,6 +37,12 @@ public:
unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; }
void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; }
unsigned getLowReg() const { return LowReg; }
void setLowReg(unsigned Reg) { LowReg = Reg; }
unsigned getHighReg() const { return HighReg; }
void setHighReg(unsigned Reg) { HighReg = Reg; }
};
} // End llvm namespace

View File

@ -18,6 +18,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
@ -35,7 +36,8 @@ const unsigned*
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
static const unsigned CalleeSavedRegs[] = {
SystemZ::R6D, SystemZ::R7D, SystemZ::R8D, SystemZ::R9D,
SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D, SystemZ::R14D,
SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D,
SystemZ::R14D, SystemZ::R15D,
SystemZ::F1, SystemZ::F3, SystemZ::F5, SystemZ::F7,
0
};
@ -50,7 +52,7 @@ SystemZRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass,
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::FP64RegClass, &SystemZ::FP64RegClass,
&SystemZ::FP64RegClass, &SystemZ::FP64RegClass, 0
};
@ -66,16 +68,16 @@ BitVector SystemZRegisterInfo::getReservedRegs(const MachineFunction &MF) const
return Reserved;
}
// needsFP - Return true if the specified function should have a dedicated frame
// pointer register. This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
/// needsFP - Return true if the specified function should have a dedicated
/// frame pointer register. This is true if the function has variable sized
/// allocas or if frame pointer elimination is disabled.
bool SystemZRegisterInfo::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
return NoFramePointerElim || MFI->hasVarSizedObjects();
}
bool SystemZRegisterInfo::hasReservedCallFrame(MachineFunction &MF) const {
// FIXME: Should we always have reserved call frame?
return !MF.getFrameInfo()->hasVarSizedObjects();
}
@ -137,6 +139,25 @@ void SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
MI.getOperand(i+1).ChangeToImmediate(Offset);
}
void
SystemZRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const {
// Determine whether R15/R14 will ever be clobbered inside the function. And
// if yes - mark it as 'callee' saved.
MachineFrameInfo *FFI = MF.getFrameInfo();
if (FFI->hasCalls()
/* FIXME: function is varargs */
/* FIXME: function grabs RA */
/* FIXME: function calls eh_return */)
MF.getRegInfo().setPhysRegUsed(SystemZ::R14D);
if (FFI->getObjectIndexEnd() != 0 || // Contains automatic variables
FFI->hasVarSizedObjects() // Function calls dynamic alloca's
/* FIXME: function is varargs */)
MF.getRegInfo().setPhysRegUsed(SystemZ::R15D);
}
/// emitSPUpdate - Emit a series of instructions to increment / decrement the
/// stack pointer by a constant value.
static
@ -177,7 +198,11 @@ void SystemZRegisterInfo::emitPrologue(MachineFunction &MF) const {
uint64_t StackSize =
MFI->getStackSize() - SystemZMFI->getCalleeSavedFrameSize();
// FIXME: Skip the callee-saved push instructions.
// Skip the callee-saved push instructions.
while (MBBI != MBB.end() &&
(MBBI->getOpcode() == SystemZ::MOV64mr ||
MBBI->getOpcode() == SystemZ::MOV64mrm))
++MBBI;
if (MBBI != MBB.end())
DL = MBBI->getDebugLoc();
@ -223,23 +248,30 @@ void SystemZRegisterInfo::emitEpilogue(MachineFunction &MF,
MFI->getStackSize() - SystemZMFI->getCalleeSavedFrameSize();
uint64_t NumBytes = StackSize - TFI.getOffsetOfLocalArea();
// Skip the callee-saved regs load instructions.
MachineBasicBlock::iterator LastCSPop = MBBI;
// Skip the final terminator instruction.
while (MBBI != MBB.begin()) {
MachineBasicBlock::iterator PI = prior(MBBI);
--MBBI;
if (!PI->getDesc().isTerminator())
break;
--MBBI;
}
DL = MBBI->getDebugLoc();
// During callee-saved restores emission stack frame was not yet finialized
// (and thus - the stack size was unknown). Tune the offset having full stack
// size in hands.
if (SystemZMFI->getCalleeSavedFrameSize()) {
assert((MBBI->getOpcode() == SystemZ::MOV64rmm ||
MBBI->getOpcode() == SystemZ::MOV64rm) &&
"Expected to see callee-save register restore code");
if (MFI->hasVarSizedObjects()) {
assert(0 && "Not implemented yet!");
} else {
// adjust stack pointer back: R15 += numbytes
if (StackSize)
emitSPUpdate(MBB, MBBI, NumBytes, TII);
unsigned i = 0;
MachineInstr &MI = *MBBI;
while (!MI.getOperand(i).isImm()) {
++i;
assert(i < MI.getNumOperands() && "Unexpected restore code!");
}
MI.getOperand(i).ChangeToImmediate(NumBytes + MI.getOperand(i).getImm());
}
}

View File

@ -49,6 +49,10 @@ struct SystemZRegisterInfo : public SystemZGenRegisterInfo {
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS = NULL) const;
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const;
void emitPrologue(MachineFunction &MF) const;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;

View File

@ -1,4 +1,4 @@
; RUN: llvm-as < %s | llc | grep 168 | count 2
; RUN: llvm-as < %s | llc | grep 168 | count 1
; RUN: llvm-as < %s | llc | grep 160 | count 3
; RUN: llvm-as < %s | llc | grep 328 | count 1

View File

@ -1,6 +1,6 @@
; RUN: llvm-as < %s | llc | grep 160 | count 1
; RUN: llvm-as < %s | llc | grep 328 | count 1
; RUN: llvm-as < %s | llc | grep 168 | count 2
; RUN: llvm-as < %s | llc | grep 168 | count 1
target datalayout = "E-p:64:64:64-i1:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128"
target triple = "s390x-unknown-linux-gnu"