Allocate the RS spill slot for any PPC function with spills and a large stack frame

For spills into a large stack frame, the FI-elimination code uses the register
scavenger to obtain a free GPR for use with an r+r-addressed load or store.
When there are no available GPRs, the scavenger gets one by using its spill
slot. Previously, we were not always allocating that spill slot and the RS
would assert when the spill slot was needed.

I don't currently have a small test that triggered the assert, but I've
created a small regression test that verifies that the spill slot is now
added when the stack frame is sufficiently large.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177140 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hal Finkel
2013-03-15 05:06:04 +00:00
parent c6aa834836
commit 0cfb42adb5
6 changed files with 107 additions and 38 deletions

View File

@ -188,13 +188,21 @@ static bool spillsCR(const MachineFunction &MF) {
return FuncInfo->isCRSpilled(); return FuncInfo->isCRSpilled();
} }
static bool hasSpills(const MachineFunction &MF) {
const PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
return FuncInfo->hasSpills();
}
/// determineFrameLayout - Determine the size of the frame and maximum call /// determineFrameLayout - Determine the size of the frame and maximum call
/// frame size. /// frame size.
void PPCFrameLowering::determineFrameLayout(MachineFunction &MF) const { unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
bool UpdateMF,
bool UseEstimate) const {
MachineFrameInfo *MFI = MF.getFrameInfo(); MachineFrameInfo *MFI = MF.getFrameInfo();
// Get the number of bytes to allocate from the FrameInfo // Get the number of bytes to allocate from the FrameInfo
unsigned FrameSize = MFI->getStackSize(); unsigned FrameSize =
UseEstimate ? MFI->estimateStackSize(MF) : MFI->getStackSize();
// Get the alignments provided by the target, and the maximum alignment // Get the alignments provided by the target, and the maximum alignment
// (if any) of the fixed frame objects. // (if any) of the fixed frame objects.
@ -223,8 +231,9 @@ void PPCFrameLowering::determineFrameLayout(MachineFunction &MF) const {
&& spillsCR(MF)) && && spillsCR(MF)) &&
(!ALIGN_STACK || MaxAlign <= TargetAlign)) { // No special alignment. (!ALIGN_STACK || MaxAlign <= TargetAlign)) { // No special alignment.
// No need for frame // No need for frame
if (UpdateMF)
MFI->setStackSize(0); MFI->setStackSize(0);
return; return 0;
} }
// Get the maximum call frame size of all the calls. // Get the maximum call frame size of all the calls.
@ -241,6 +250,7 @@ void PPCFrameLowering::determineFrameLayout(MachineFunction &MF) const {
maxCallFrameSize = (maxCallFrameSize + AlignMask) & ~AlignMask; maxCallFrameSize = (maxCallFrameSize + AlignMask) & ~AlignMask;
// Update maximum call frame size. // Update maximum call frame size.
if (UpdateMF)
MFI->setMaxCallFrameSize(maxCallFrameSize); MFI->setMaxCallFrameSize(maxCallFrameSize);
// Include call frame size in total. // Include call frame size in total.
@ -250,7 +260,10 @@ void PPCFrameLowering::determineFrameLayout(MachineFunction &MF) const {
FrameSize = (FrameSize + AlignMask) & ~AlignMask; FrameSize = (FrameSize + AlignMask) & ~AlignMask;
// Update frame info. // Update frame info.
if (UpdateMF)
MFI->setStackSize(FrameSize); MFI->setStackSize(FrameSize);
return FrameSize;
} }
// hasFP - Return true if the specified function actually has a dedicated frame // hasFP - Return true if the specified function actually has a dedicated frame
@ -311,11 +324,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const {
MBBI = MBB.begin(); MBBI = MBB.begin();
// Work out frame sizes. // Work out frame sizes.
// FIXME: determineFrameLayout() may change the frame size. This should be unsigned FrameSize = determineFrameLayout(MF);
// moved upper, to some hook.
determineFrameLayout(MF);
unsigned FrameSize = MFI->getStackSize();
int NegFrameSize = -FrameSize; int NegFrameSize = -FrameSize;
// Get processor type. // Get processor type.
@ -780,7 +789,7 @@ static bool MustSaveLR(const MachineFunction &MF, unsigned LR) {
void void
PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const { RegScavenger *) const {
const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
// Save and clear the LR state. // Save and clear the LR state.
@ -822,30 +831,15 @@ PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
int FrameIdx = MFI->CreateFixedObject((uint64_t)4, (int64_t)-4, true); int FrameIdx = MFI->CreateFixedObject((uint64_t)4, (int64_t)-4, true);
FI->setCRSpillFrameIndex(FrameIdx); FI->setCRSpillFrameIndex(FrameIdx);
} }
// Reserve a slot closest to SP or frame pointer if we have a dynalloc or
// a large stack, which will require scavenging a register to materialize a
// large offset.
// FIXME: this doesn't actually check stack size, so is a bit pessimistic
// FIXME: doesn't detect whether or not we need to spill vXX, which requires
// r0 for now.
if (RegInfo->requiresRegisterScavenging(MF))
if (MFI->hasVarSizedObjects() || spillsCR(MF)) {
const TargetRegisterClass *GPRC = &PPC::GPRCRegClass;
const TargetRegisterClass *G8RC = &PPC::G8RCRegClass;
const TargetRegisterClass *RC = isPPC64 ? G8RC : GPRC;
RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
RC->getAlignment(),
false));
}
} }
void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF, void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *) const { RegScavenger *RS) const {
// Early exit if not using the SVR4 ABI. // Early exit if not using the SVR4 ABI.
if (!Subtarget.isSVR4ABI()) if (!Subtarget.isSVR4ABI()) {
addScavengingSpillSlot(MF, RS);
return; return;
}
// Get callee saved register information. // Get callee saved register information.
MachineFrameInfo *FFI = MF.getFrameInfo(); MachineFrameInfo *FFI = MF.getFrameInfo();
@ -853,6 +847,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
// Early exit if no callee saved registers are modified! // Early exit if no callee saved registers are modified!
if (CSI.empty() && !needsFP(MF)) { if (CSI.empty() && !needsFP(MF)) {
addScavengingSpillSlot(MF, RS);
return; return;
} }
@ -1031,6 +1026,37 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI)); FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
} }
} }
addScavengingSpillSlot(MF, RS);
}
void
PPCFrameLowering::addScavengingSpillSlot(MachineFunction &MF,
RegScavenger *RS) const {
// Reserve a slot closest to SP or frame pointer if we have a dynalloc or
// a large stack, which will require scavenging a register to materialize a
// large offset.
// We need to have a scavenger spill slot for spills if the frame size is
// large. In case there is no free register for large-offset addressing,
// this slot is used for the necessary emergency spill. Also, we need the
// slot for dynamic stack allocations.
// The scavenger might be invoked if the frame offset does not fit into
// the 16-bit immediate. We don't know the complete frame size here
// because we've not yet computed callee-saved register spills or the
// needed alignment padding.
unsigned StackSize = determineFrameLayout(MF, false, true);
MachineFrameInfo *MFI = MF.getFrameInfo();
if (MFI->hasVarSizedObjects() || spillsCR(MF) ||
(hasSpills(MF) && !isInt<16>(StackSize))) {
const TargetRegisterClass *GPRC = &PPC::GPRCRegClass;
const TargetRegisterClass *G8RC = &PPC::G8RCRegClass;
const TargetRegisterClass *RC = Subtarget.isPPC64() ? G8RC : GPRC;
RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
RC->getAlignment(),
false));
}
} }
bool bool

View File

@ -32,7 +32,9 @@ public:
Subtarget(sti) { Subtarget(sti) {
} }
void determineFrameLayout(MachineFunction &MF) const; unsigned determineFrameLayout(MachineFunction &MF,
bool UpdateMF = true,
bool UseEstimate = false) const;
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
/// the function. /// the function.
@ -46,6 +48,7 @@ public:
RegScavenger *RS = NULL) const; RegScavenger *RS = NULL) const;
void processFunctionBeforeFrameFinalized(MachineFunction &MF, void processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS = NULL) const; RegScavenger *RS = NULL) const;
void addScavengingSpillSlot(MachineFunction &MF, RegScavenger *RS) const;
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, MachineBasicBlock::iterator MI,

View File

@ -554,10 +554,11 @@ PPCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineFunction &MF = *MBB.getParent(); MachineFunction &MF = *MBB.getParent();
SmallVector<MachineInstr*, 4> NewMIs; SmallVector<MachineInstr*, 4> NewMIs;
if (StoreRegToStackSlot(MF, SrcReg, isKill, FrameIdx, RC, NewMIs)) {
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>(); PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
FuncInfo->setHasSpills();
if (StoreRegToStackSlot(MF, SrcReg, isKill, FrameIdx, RC, NewMIs))
FuncInfo->setSpillsCR(); FuncInfo->setSpillsCR();
}
for (unsigned i = 0, e = NewMIs.size(); i != e; ++i) for (unsigned i = 0, e = NewMIs.size(); i != e; ++i)
MBB.insert(MI, NewMIs[i]); MBB.insert(MI, NewMIs[i]);

View File

@ -37,6 +37,9 @@ class PPCFunctionInfo : public MachineFunctionInfo {
/// PEI. /// PEI.
bool MustSaveLR; bool MustSaveLR;
/// Does this function have any stack spills.
bool HasSpills;
/// SpillsCR - Indicates whether CR is spilled in the current function. /// SpillsCR - Indicates whether CR is spilled in the current function.
bool SpillsCR; bool SpillsCR;
@ -78,6 +81,7 @@ public:
explicit PPCFunctionInfo(MachineFunction &MF) explicit PPCFunctionInfo(MachineFunction &MF)
: FramePointerSaveIndex(0), : FramePointerSaveIndex(0),
ReturnAddrSaveIndex(0), ReturnAddrSaveIndex(0),
HasSpills(false),
SpillsCR(false), SpillsCR(false),
LRStoreRequired(false), LRStoreRequired(false),
MinReservedArea(0), MinReservedArea(0),
@ -109,6 +113,9 @@ public:
void setMustSaveLR(bool U) { MustSaveLR = U; } void setMustSaveLR(bool U) { MustSaveLR = U; }
bool mustSaveLR() const { return MustSaveLR; } bool mustSaveLR() const { return MustSaveLR; }
void setHasSpills() { HasSpills = true; }
bool hasSpills() const { return HasSpills; }
void setSpillsCR() { SpillsCR = true; } void setSpillsCR() { SpillsCR = true; }
bool isCRSpilled() const { return SpillsCR; } bool isCRSpilled() const { return SpillsCR; }

View File

@ -9,12 +9,12 @@ entry:
;CHECK: mfcr r0 ;CHECK: mfcr r0
;CHECK: lis r2, 1 ;CHECK: lis r2, 1
;CHECK: rlwinm r0, r0, 8, 0, 31 ;CHECK: rlwinm r0, r0, 8, 0, 31
;CHECK: ori r2, r2, 34524 ;CHECK: ori r2, r2, 34540
;CHECK: stwx r0, r1, r2 ;CHECK: stwx r0, r1, r2
; Make sure that the register scavenger returns the same temporary register. ; Make sure that the register scavenger returns the same temporary register.
;CHECK: lis r2, 1 ;CHECK: lis r2, 1
;CHECK: mfcr r0 ;CHECK: mfcr r0
;CHECK: ori r2, r2, 34520 ;CHECK: ori r2, r2, 34536
;CHECK: rlwinm r0, r0, 12, 0, 31 ;CHECK: rlwinm r0, r0, 12, 0, 31
;CHECK: stwx r0, r1, r2 ;CHECK: stwx r0, r1, r2
%x = alloca [100000 x i8] ; <[100000 x i8]*> [#uses=1] %x = alloca [100000 x i8] ; <[100000 x i8]*> [#uses=1]
@ -26,7 +26,7 @@ entry:
return: ; preds = %entry return: ; preds = %entry
;CHECK: lis r2, 1 ;CHECK: lis r2, 1
;CHECK: ori r2, r2, 34524 ;CHECK: ori r2, r2, 34540
;CHECK: lwzx r0, r1, r2 ;CHECK: lwzx r0, r1, r2
;CHECK: rlwinm r0, r0, 24, 0, 31 ;CHECK: rlwinm r0, r0, 24, 0, 31
;CHECK: mtcrf 32, r0 ;CHECK: mtcrf 32, r0

View File

@ -0,0 +1,32 @@
; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=a2 | FileCheck %s
target datalayout = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f128:64:128-n32"
define i64 @foo() nounwind {
entry:
%x = alloca [32568 x i8]
%"alloca point" = bitcast i32 0 to i32
%x1 = bitcast [32568 x i8]* %x to i8*
; Check that the RS spill slot has been allocated (because the estimate
; will fail the small-frame-size check and the function has spills).
; CHECK: @foo
; CHECK: stdu 1, -32768(1)
%s1 = call i64 @bar(i8* %x1) nounwind
%s2 = call i64 @bar(i8* %x1) nounwind
%s3 = call i64 @bar(i8* %x1) nounwind
%s4 = call i64 @bar(i8* %x1) nounwind
%s5 = call i64 @bar(i8* %x1) nounwind
%s6 = call i64 @bar(i8* %x1) nounwind
%s7 = call i64 @bar(i8* %x1) nounwind
%s8 = call i64 @bar(i8* %x1) nounwind
%r = call i64 @can(i64 %s1, i64 %s2, i64 %s3, i64 %s4, i64 %s5, i64 %s6, i64 %s7, i64 %s8) nounwind
br label %return
return:
ret i64 %r
}
declare i64 @bar(i8*)
declare i64 @can(i64, i64, i64, i64, i64, i64, i64, i64)