svn commit: r309147 - head/contrib/llvm/lib/Target/PowerPC
Dimitry Andric
dim at FreeBSD.org
Fri Nov 25 18:01:33 UTC 2016
Author: dim
Date: Fri Nov 25 18:01:32 2016
New Revision: 309147
URL: https://svnweb.freebsd.org/changeset/base/309147
Log:
Pull in r282174 from upstream llvm trunk (by Krzysztof Parzyszek):
[PPC] Set SP after loading data from stack frame, if no red zone is
present
Follow-up to r280705: Make sure that the SP is only restored after
all data is loaded from the stack frame, if there is no red zone.
This completes the fix for
https://llvm.org/bugs/show_bug.cgi?id=26519.
Differential Revision: https://reviews.llvm.org/D24466
Reported by: Mark Millard
PR: 214433
Modified:
head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
Modified: head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
==============================================================================
--- head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp Fri Nov 25 17:20:23 2016 (r309146)
+++ head/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp Fri Nov 25 18:01:32 2016 (r309147)
@@ -927,7 +927,7 @@ void PPCFrameLowering::emitPrologue(Mach
}
// Have we generated a STUX instruction to claim stack frame? If so,
- // the frame size will be placed in ScratchReg.
+ // the negated frame size will be placed in ScratchReg.
bool HasSTUX = false;
// This condition must be kept in sync with canUseAsPrologue.
@@ -987,33 +987,88 @@ void PPCFrameLowering::emitPrologue(Mach
if (!HasRedZone) {
assert(!isPPC64 && "A red zone is always available on PPC64");
if (HasSTUX) {
- // The frame size is in ScratchReg, and the SPReg has been advanced
- // (downwards) by the frame size: SPReg = old SPReg + ScratchReg.
- // Set ScratchReg to the original SPReg: ScratchReg = SPReg - ScratchReg.
+ // The negated frame size is in ScratchReg, and the SPReg has been
+ // decremented by the frame size: SPReg = old SPReg + ScratchReg.
+ // Since FPOffset, PBPOffset, etc. are relative to the beginning of
+ // the stack frame (i.e. the old SP), ideally, we would put the old
+ // SP into a register and use it as the base for the stores. The
+ // problem is that the only available register may be ScratchReg,
+ // which could be R0, and R0 cannot be used as a base address.
+
+ // First, set ScratchReg to the old SP. This may need to be modified
+ // later.
BuildMI(MBB, MBBI, dl, TII.get(PPC::SUBF), ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addReg(SPReg);
- // Now that the stack frame has been allocated, save all the necessary
- // registers using ScratchReg as the base address.
- if (HasFP)
- BuildMI(MBB, MBBI, dl, StoreInst)
- .addReg(FPReg)
- .addImm(FPOffset)
- .addReg(ScratchReg);
- if (FI->usesPICBase())
- BuildMI(MBB, MBBI, dl, StoreInst)
- .addReg(PPC::R30)
- .addImm(PBPOffset)
- .addReg(ScratchReg);
- if (HasBP) {
- BuildMI(MBB, MBBI, dl, StoreInst)
- .addReg(BPReg)
- .addImm(BPOffset)
- .addReg(ScratchReg);
- BuildMI(MBB, MBBI, dl, OrInst, BPReg)
- .addReg(ScratchReg, RegState::Kill)
- .addReg(ScratchReg);
+ if (ScratchReg == PPC::R0) {
+ // R0 cannot be used as a base register, but it can be used as an
+ // index in a store-indexed.
+ int LastOffset = 0;
+ if (HasFP) {
+ // R0 += (FPOffset-LastOffset).
+ // Need addic, since addi treats R0 as 0.
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), ScratchReg)
+ .addReg(ScratchReg)
+ .addImm(FPOffset-LastOffset);
+ LastOffset = FPOffset;
+ // Store FP into *R0.
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::STWX))
+ .addReg(FPReg, RegState::Kill) // Save FP.
+ .addReg(PPC::ZERO)
+ .addReg(ScratchReg); // This will be the index (R0 is ok here).
+ }
+ if (FI->usesPICBase()) {
+ // R0 += (PBPOffset-LastOffset).
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), ScratchReg)
+ .addReg(ScratchReg)
+ .addImm(PBPOffset-LastOffset);
+ LastOffset = PBPOffset;
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::STWX))
+ .addReg(PPC::R30, RegState::Kill) // Save PIC base pointer.
+ .addReg(PPC::ZERO)
+ .addReg(ScratchReg); // This will be the index (R0 is ok here).
+ }
+ if (HasBP) {
+ // R0 += (BPOffset-LastOffset).
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), ScratchReg)
+ .addReg(ScratchReg)
+ .addImm(BPOffset-LastOffset);
+ LastOffset = BPOffset;
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::STWX))
+ .addReg(BPReg, RegState::Kill) // Save BP.
+ .addReg(PPC::ZERO)
+ .addReg(ScratchReg); // This will be the index (R0 is ok here).
+ // BP = R0-LastOffset
+ BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), BPReg)
+ .addReg(ScratchReg, RegState::Kill)
+ .addImm(-LastOffset);
+ }
+ } else {
+ // ScratchReg is not R0, so use it as the base register. It is
+ // already set to the old SP, so we can use the offsets directly.
+
+ // Now that the stack frame has been allocated, save all the necessary
+ // registers using ScratchReg as the base address.
+ if (HasFP)
+ BuildMI(MBB, MBBI, dl, StoreInst)
+ .addReg(FPReg)
+ .addImm(FPOffset)
+ .addReg(ScratchReg);
+ if (FI->usesPICBase())
+ BuildMI(MBB, MBBI, dl, StoreInst)
+ .addReg(PPC::R30)
+ .addImm(PBPOffset)
+ .addReg(ScratchReg);
+ if (HasBP) {
+ BuildMI(MBB, MBBI, dl, StoreInst)
+ .addReg(BPReg)
+ .addImm(BPOffset)
+ .addReg(ScratchReg);
+ BuildMI(MBB, MBBI, dl, OrInst, BPReg)
+ .addReg(ScratchReg, RegState::Kill)
+ .addReg(ScratchReg);
+ }
}
} else {
// The frame size is a known 16-bit constant (fitting in the immediate
@@ -1191,6 +1246,7 @@ void PPCFrameLowering::emitEpilogue(Mach
// Do we have a frame pointer and/or base pointer for this function?
bool HasFP = hasFP(MF);
bool HasBP = RegInfo->hasBasePointer(MF);
+ bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
unsigned SPReg = isPPC64 ? PPC::X1 : PPC::R1;
unsigned BPReg = RegInfo->getBaseRegister(MF);
@@ -1203,6 +1259,8 @@ void PPCFrameLowering::emitEpilogue(Mach
: PPC::LWZ );
const MCInstrDesc& LoadImmShiftedInst = TII.get( isPPC64 ? PPC::LIS8
: PPC::LIS );
+ const MCInstrDesc& OrInst = TII.get(isPPC64 ? PPC::OR8
+ : PPC::OR );
const MCInstrDesc& OrImmInst = TII.get( isPPC64 ? PPC::ORI8
: PPC::ORI );
const MCInstrDesc& AddImmInst = TII.get( isPPC64 ? PPC::ADDI8
@@ -1224,10 +1282,9 @@ void PPCFrameLowering::emitEpilogue(Mach
if (HasFP) {
if (isSVR4ABI) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
int FPIndex = FI->getFramePointerSaveIndex();
assert(FPIndex && "No Frame Pointer Save Slot!");
- FPOffset = FFI->getObjectOffset(FPIndex);
+ FPOffset = MFI->getObjectOffset(FPIndex);
} else {
FPOffset = getFramePointerSaveOffset();
}
@@ -1236,10 +1293,9 @@ void PPCFrameLowering::emitEpilogue(Mach
int BPOffset = 0;
if (HasBP) {
if (isSVR4ABI) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
int BPIndex = FI->getBasePointerSaveIndex();
assert(BPIndex && "No Base Pointer Save Slot!");
- BPOffset = FFI->getObjectOffset(BPIndex);
+ BPOffset = MFI->getObjectOffset(BPIndex);
} else {
BPOffset = getBasePointerSaveOffset();
}
@@ -1247,10 +1303,9 @@ void PPCFrameLowering::emitEpilogue(Mach
int PBPOffset = 0;
if (FI->usesPICBase()) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
int PBPIndex = FI->getPICBasePointerSaveIndex();
assert(PBPIndex && "No PIC Base Pointer Save Slot!");
- PBPOffset = FFI->getObjectOffset(PBPIndex);
+ PBPOffset = MFI->getObjectOffset(PBPIndex);
}
bool IsReturnBlock = (MBBI != MBB.end() && MBBI->isReturn());
@@ -1283,9 +1338,25 @@ void PPCFrameLowering::emitEpilogue(Mach
// indexed into with a simple LD/LWZ immediate offset operand.
bool isLargeFrame = !isInt<16>(FrameSize);
+ // On targets without red zone, the SP needs to be restored last, so that
+ // all live contents of the stack frame are upwards of the SP. This means
+ // that we cannot restore SP just now, since there may be more registers
+ // to restore from the stack frame (e.g. R31). If the frame size is not
+ // a simple immediate value, we will need a spare register to hold the
+ // restored SP. If the frame size is known and small, we can simply adjust
+ // the offsets of the registers to be restored, and still use SP to restore
+ // them. In such case, the final update of SP will be to add the frame
+ // size to it.
+ // To simplify the code, set RBReg to the base register used to restore
+ // values from the stack, and set SPAdd to the value that needs to be added
+ // to the SP at the end. The default values are as if red zone was present.
+ unsigned RBReg = SPReg;
+ unsigned SPAdd = 0;
+
if (FrameSize) {
- // In the prologue, the loaded (or persistent) stack pointer value is offset
- // by the STDU/STDUX/STWU/STWUX instruction. Add this offset back now.
+ // In the prologue, the loaded (or persistent) stack pointer value is
+ // offset by the STDU/STDUX/STWU/STWUX instruction. For targets with red
+ // zone add this offset back now.
// If this function contained a fastcc call and GuaranteedTailCallOpt is
// enabled (=> hasFastCall()==true) the fastcc call might contain a tail
@@ -1293,8 +1364,10 @@ void PPCFrameLowering::emitEpilogue(Mach
// value of R31 in this case.
if (FI->hasFastCall()) {
assert(HasFP && "Expecting a valid frame pointer.");
+ if (!HasRedZone)
+ RBReg = FPReg;
if (!isLargeFrame) {
- BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
+ BuildMI(MBB, MBBI, dl, AddImmInst, RBReg)
.addReg(FPReg).addImm(FrameSize);
} else {
BuildMI(MBB, MBBI, dl, LoadImmShiftedInst, ScratchReg)
@@ -1303,27 +1376,55 @@ void PPCFrameLowering::emitEpilogue(Mach
.addReg(ScratchReg, RegState::Kill)
.addImm(FrameSize & 0xFFFF);
BuildMI(MBB, MBBI, dl, AddInst)
- .addReg(SPReg)
+ .addReg(RBReg)
.addReg(FPReg)
.addReg(ScratchReg);
}
} else if (!isLargeFrame && !HasBP && !MFI->hasVarSizedObjects()) {
- BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
- .addReg(SPReg)
- .addImm(FrameSize);
+ if (HasRedZone) {
+ BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
+ .addReg(SPReg)
+ .addImm(FrameSize);
+ } else {
+ // Make sure that adding FrameSize will not overflow the max offset
+ // size.
+ assert(FPOffset <= 0 && BPOffset <= 0 && PBPOffset <= 0 &&
+ "Local offsets should be negative");
+ SPAdd = FrameSize;
+ FPOffset += FrameSize;
+ BPOffset += FrameSize;
+ PBPOffset += FrameSize;
+ }
} else {
- BuildMI(MBB, MBBI, dl, LoadInst, SPReg)
+ // We don't want to use ScratchReg as a base register, because it
+ // could happen to be R0. Use FP instead, but make sure to preserve it.
+ if (!HasRedZone) {
+ // If FP is not saved, copy it to ScratchReg.
+ if (!HasFP)
+ BuildMI(MBB, MBBI, dl, OrInst, ScratchReg)
+ .addReg(FPReg)
+ .addReg(FPReg);
+ RBReg = FPReg;
+ }
+ BuildMI(MBB, MBBI, dl, LoadInst, RBReg)
.addImm(0)
.addReg(SPReg);
}
}
+ assert(RBReg != ScratchReg && "Should have avoided ScratchReg");
+ // If there is no red zone, ScratchReg may be needed for holding a useful
+ // value (although not the base register). Make sure it is not overwritten
+ // too early.
assert((isPPC64 || !MustSaveCR) &&
"Epilogue CR restoring supported only in 64-bit mode");
- // If we need to save both the LR and the CR and we only have one available
- // scratch register, we must do them one at a time.
+ // If we need to restore both the LR and the CR and we only have one
+ // available scratch register, we must do them one at a time.
if (MustSaveCR && SingleScratchReg && MustSaveLR) {
+ // Here TempReg == ScratchReg, and in the absence of red zone ScratchReg
+ // is live here.
+ assert(HasRedZone && "Expecting red zone");
BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg)
.addImm(8)
.addReg(SPReg);
@@ -1332,33 +1433,77 @@ void PPCFrameLowering::emitEpilogue(Mach
.addReg(TempReg, getKillRegState(i == e-1));
}
- if (MustSaveLR)
+ // Delay restoring of the LR if ScratchReg is needed. This is ok, since
+ // LR is stored in the caller's stack frame. ScratchReg will be needed
+ // if RBReg is anything other than SP. We shouldn't use ScratchReg as
+ // a base register anyway, because it may happen to be R0.
+ bool LoadedLR = false;
+ if (MustSaveLR && RBReg == SPReg && isInt<16>(LROffset+SPAdd)) {
BuildMI(MBB, MBBI, dl, LoadInst, ScratchReg)
- .addImm(LROffset)
- .addReg(SPReg);
+ .addImm(LROffset+SPAdd)
+ .addReg(RBReg);
+ LoadedLR = true;
+ }
- if (MustSaveCR &&
- !(SingleScratchReg && MustSaveLR)) // will only occur for PPC64
+ if (MustSaveCR && !(SingleScratchReg && MustSaveLR)) {
+ // This will only occur for PPC64.
+ assert(isPPC64 && "Expecting 64-bit mode");
+ assert(RBReg == SPReg && "Should be using SP as a base register");
BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg)
.addImm(8)
- .addReg(SPReg);
+ .addReg(RBReg);
+ }
- if (HasFP)
- BuildMI(MBB, MBBI, dl, LoadInst, FPReg)
- .addImm(FPOffset)
- .addReg(SPReg);
+ if (HasFP) {
+ // If there is red zone, restore FP directly, since SP has already been
+ // restored. Otherwise, restore the value of FP into ScratchReg.
+ if (HasRedZone || RBReg == SPReg)
+ BuildMI(MBB, MBBI, dl, LoadInst, FPReg)
+ .addImm(FPOffset)
+ .addReg(SPReg);
+ else
+ BuildMI(MBB, MBBI, dl, LoadInst, ScratchReg)
+ .addImm(FPOffset)
+ .addReg(RBReg);
+ }
if (FI->usesPICBase())
- // FIXME: On PPC32 SVR4, we must not spill before claiming the stackframe.
BuildMI(MBB, MBBI, dl, LoadInst)
.addReg(PPC::R30)
.addImm(PBPOffset)
- .addReg(SPReg);
+ .addReg(RBReg);
if (HasBP)
BuildMI(MBB, MBBI, dl, LoadInst, BPReg)
.addImm(BPOffset)
- .addReg(SPReg);
+ .addReg(RBReg);
+
+ // There is nothing more to be loaded from the stack, so now we can
+ // restore SP: SP = RBReg + SPAdd.
+ if (RBReg != SPReg || SPAdd != 0) {
+ assert(!HasRedZone && "This should not happen with red zone");
+ // If SPAdd is 0, generate a copy.
+ if (SPAdd == 0)
+ BuildMI(MBB, MBBI, dl, OrInst, SPReg)
+ .addReg(RBReg)
+ .addReg(RBReg);
+ else
+ BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
+ .addReg(RBReg)
+ .addImm(SPAdd);
+
+ assert(RBReg != ScratchReg && "Should be using FP or SP as base register");
+ if (RBReg == FPReg)
+ BuildMI(MBB, MBBI, dl, OrInst, FPReg)
+ .addReg(ScratchReg)
+ .addReg(ScratchReg);
+
+ // Now load the LR from the caller's stack frame.
+ if (MustSaveLR && !LoadedLR)
+ BuildMI(MBB, MBBI, dl, LoadInst, ScratchReg)
+ .addImm(LROffset)
+ .addReg(SPReg);
+ }
if (MustSaveCR &&
!(SingleScratchReg && MustSaveLR)) // will only occur for PPC64
More information about the svn-src-all
mailing list