#include "PPCFrameLowering.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/Function.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
#define DEBUG_TYPE "framelowering"
STATISTIC(NumPESpillVSR, "Number of spills to vector in prologue");
STATISTIC(NumPEReloadVSR, "Number of reloads from vector in epilogue");
STATISTIC(NumPrologProbed, "Number of prologues probed");
static cl::opt<bool>
EnablePEVectorSpills("ppc-enable-pe-vector-spills",
cl::desc("Enable spills in prologue to vector registers."),
cl::init(false), cl::Hidden);
static unsigned computeReturnSaveOffset(const PPCSubtarget &STI) {
if (STI.isAIXABI())
return STI.isPPC64() ? 16 : 8;
return STI.isPPC64() ? 16 : 4;
}
static unsigned computeTOCSaveOffset(const PPCSubtarget &STI) {
if (STI.isAIXABI())
return STI.isPPC64() ? 40 : 20;
return STI.isELFv2ABI() ? 24 : 40;
}
static unsigned computeFramePointerSaveOffset(const PPCSubtarget &STI) {
return STI.isPPC64() ? -8U : -4U;
}
static unsigned computeLinkageSize(const PPCSubtarget &STI) {
if (STI.isAIXABI() || STI.isPPC64())
return (STI.isELFv2ABI() ? 4 : 6) * (STI.isPPC64() ? 8 : 4);
return 8;
}
static unsigned computeBasePointerSaveOffset(const PPCSubtarget &STI) {
if (STI.is32BitELFABI() && STI.getTargetMachine().isPositionIndependent())
return -12U;
return STI.isPPC64() ? -16U : -8U;
}
static unsigned computeCRSaveOffset(const PPCSubtarget &STI) {
return (STI.isAIXABI() && !STI.isPPC64()) ? 4 : 8;
}
PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
STI.getPlatformStackAlignment(), 0),
Subtarget(STI), ReturnSaveOffset(computeReturnSaveOffset(Subtarget)),
TOCSaveOffset(computeTOCSaveOffset(Subtarget)),
FramePointerSaveOffset(computeFramePointerSaveOffset(Subtarget)),
LinkageSize(computeLinkageSize(Subtarget)),
BasePointerSaveOffset(computeBasePointerSaveOffset(Subtarget)),
CRSaveOffset(computeCRSaveOffset(Subtarget)) {}
const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots(
unsigned &NumEntries) const {
#define CALLEE_SAVED_FPRS \
{PPC::F31, -8}, \
{PPC::F30, -16}, \
{PPC::F29, -24}, \
{PPC::F28, -32}, \
{PPC::F27, -40}, \
{PPC::F26, -48}, \
{PPC::F25, -56}, \
{PPC::F24, -64}, \
{PPC::F23, -72}, \
{PPC::F22, -80}, \
{PPC::F21, -88}, \
{PPC::F20, -96}, \
{PPC::F19, -104}, \
{PPC::F18, -112}, \
{PPC::F17, -120}, \
{PPC::F16, -128}, \
{PPC::F15, -136}, \
{PPC::F14, -144}
#define CALLEE_SAVED_GPRS32 \
{PPC::R31, -4}, \
{PPC::R30, -8}, \
{PPC::R29, -12}, \
{PPC::R28, -16}, \
{PPC::R27, -20}, \
{PPC::R26, -24}, \
{PPC::R25, -28}, \
{PPC::R24, -32}, \
{PPC::R23, -36}, \
{PPC::R22, -40}, \
{PPC::R21, -44}, \
{PPC::R20, -48}, \
{PPC::R19, -52}, \
{PPC::R18, -56}, \
{PPC::R17, -60}, \
{PPC::R16, -64}, \
{PPC::R15, -68}, \
{PPC::R14, -72}
#define CALLEE_SAVED_GPRS64 \
{PPC::X31, -8}, \
{PPC::X30, -16}, \
{PPC::X29, -24}, \
{PPC::X28, -32}, \
{PPC::X27, -40}, \
{PPC::X26, -48}, \
{PPC::X25, -56}, \
{PPC::X24, -64}, \
{PPC::X23, -72}, \
{PPC::X22, -80}, \
{PPC::X21, -88}, \
{PPC::X20, -96}, \
{PPC::X19, -104}, \
{PPC::X18, -112}, \
{PPC::X17, -120}, \
{PPC::X16, -128}, \
{PPC::X15, -136}, \
{PPC::X14, -144}
#define CALLEE_SAVED_VRS \
{PPC::V31, -16}, \
{PPC::V30, -32}, \
{PPC::V29, -48}, \
{PPC::V28, -64}, \
{PPC::V27, -80}, \
{PPC::V26, -96}, \
{PPC::V25, -112}, \
{PPC::V24, -128}, \
{PPC::V23, -144}, \
{PPC::V22, -160}, \
{PPC::V21, -176}, \
{PPC::V20, -192}
static const SpillSlot ELFOffsets32[] = {
CALLEE_SAVED_FPRS,
CALLEE_SAVED_GPRS32,
{PPC::CR2, -4},
{PPC::VRSAVE, -4},
CALLEE_SAVED_VRS,
{PPC::S31, -8},
{PPC::S30, -16},
{PPC::S29, -24},
{PPC::S28, -32},
{PPC::S27, -40},
{PPC::S26, -48},
{PPC::S25, -56},
{PPC::S24, -64},
{PPC::S23, -72},
{PPC::S22, -80},
{PPC::S21, -88},
{PPC::S20, -96},
{PPC::S19, -104},
{PPC::S18, -112},
{PPC::S17, -120},
{PPC::S16, -128},
{PPC::S15, -136},
{PPC::S14, -144}};
static const SpillSlot ELFOffsets64[] = {
CALLEE_SAVED_FPRS,
CALLEE_SAVED_GPRS64,
{PPC::VRSAVE, -4},
CALLEE_SAVED_VRS
};
static const SpillSlot AIXOffsets32[] = {CALLEE_SAVED_FPRS,
CALLEE_SAVED_GPRS32,
{PPC::R13, -76},
CALLEE_SAVED_VRS};
static const SpillSlot AIXOffsets64[] = {
CALLEE_SAVED_FPRS, CALLEE_SAVED_GPRS64, CALLEE_SAVED_VRS};
if (Subtarget.is64BitELFABI()) {
NumEntries = array_lengthof(ELFOffsets64);
return ELFOffsets64;
}
if (Subtarget.is32BitELFABI()) {
NumEntries = array_lengthof(ELFOffsets32);
return ELFOffsets32;
}
assert(Subtarget.isAIXABI() && "Unexpected ABI.");
if (Subtarget.isPPC64()) {
NumEntries = array_lengthof(AIXOffsets64);
return AIXOffsets64;
}
NumEntries = array_lengthof(AIXOffsets32);
return AIXOffsets32;
}
static bool spillsCR(const MachineFunction &MF) {
const PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
return FuncInfo->isCRSpilled();
}
static bool hasSpills(const MachineFunction &MF) {
const PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
return FuncInfo->hasSpills();
}
static bool hasNonRISpills(const MachineFunction &MF) {
const PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
return FuncInfo->hasNonRISpills();
}
static bool MustSaveLR(const MachineFunction &MF, unsigned LR) {
const PPCFunctionInfo *MFI = MF.getInfo<PPCFunctionInfo>();
MachineRegisterInfo::def_iterator RI = MF.getRegInfo().def_begin(LR);
return RI !=MF.getRegInfo().def_end() || MFI->isLRStoreRequired();
}
uint64_t
PPCFrameLowering::determineFrameLayoutAndUpdate(MachineFunction &MF,
bool UseEstimate) const {
unsigned NewMaxCallFrameSize = 0;
uint64_t FrameSize = determineFrameLayout(MF, UseEstimate,
&NewMaxCallFrameSize);
MF.getFrameInfo().setStackSize(FrameSize);
MF.getFrameInfo().setMaxCallFrameSize(NewMaxCallFrameSize);
return FrameSize;
}
uint64_t
PPCFrameLowering::determineFrameLayout(const MachineFunction &MF,
bool UseEstimate,
unsigned *NewMaxCallFrameSize) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
uint64_t FrameSize =
UseEstimate ? MFI.estimateStackSize(MF) : MFI.getStackSize();
Align TargetAlign = getStackAlign(); Align MaxAlign = MFI.getMaxAlign(); Align Alignment = std::max(TargetAlign, MaxAlign);
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
unsigned LR = RegInfo->getRARegister();
bool DisableRedZone = MF.getFunction().hasFnAttribute(Attribute::NoRedZone);
bool CanUseRedZone = !MFI.hasVarSizedObjects() && !MFI.adjustsStack() && !MustSaveLR(MF, LR) && !FI->mustSaveTOC() && !RegInfo->hasBasePointer(MF);
bool FitsInRedZone = FrameSize <= Subtarget.getRedZoneSize();
if (!DisableRedZone && CanUseRedZone && FitsInRedZone) {
return 0;
}
unsigned maxCallFrameSize = MFI.getMaxCallFrameSize();
unsigned minCallFrameSize = getLinkageSize();
maxCallFrameSize = std::max(maxCallFrameSize, minCallFrameSize);
if (MFI.hasVarSizedObjects())
maxCallFrameSize = alignTo(maxCallFrameSize, Alignment);
if (NewMaxCallFrameSize)
*NewMaxCallFrameSize = maxCallFrameSize;
FrameSize += maxCallFrameSize;
FrameSize = alignTo(FrameSize, Alignment);
return FrameSize;
}
bool PPCFrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
return (MFI.getStackSize()) && needsFP(MF);
}
bool PPCFrameLowering::needsFP(const MachineFunction &MF) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (MF.getFunction().hasFnAttribute(Attribute::Naked))
return false;
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
MFI.hasVarSizedObjects() || MFI.hasStackMap() || MFI.hasPatchPoint() ||
MF.exposesReturnsTwice() ||
(MF.getTarget().Options.GuaranteedTailCallOpt &&
MF.getInfo<PPCFunctionInfo>()->hasFastCall());
}
void PPCFrameLowering::replaceFPWithRealFP(MachineFunction &MF) const {
bool is31 = needsFP(MF);
unsigned FPReg = is31 ? PPC::R31 : PPC::R1;
unsigned FP8Reg = is31 ? PPC::X31 : PPC::X1;
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
bool HasBP = RegInfo->hasBasePointer(MF);
unsigned BPReg = HasBP ? (unsigned) RegInfo->getBaseRegister(MF) : FPReg;
unsigned BP8Reg = HasBP ? (unsigned) PPC::X30 : FP8Reg;
for (MachineBasicBlock &MBB : MF)
for (MachineBasicBlock::iterator MBBI = MBB.end(); MBBI != MBB.begin();) {
--MBBI;
for (unsigned I = 0, E = MBBI->getNumOperands(); I != E; ++I) {
MachineOperand &MO = MBBI->getOperand(I);
if (!MO.isReg())
continue;
switch (MO.getReg()) {
case PPC::FP:
MO.setReg(FPReg);
break;
case PPC::FP8:
MO.setReg(FP8Reg);
break;
case PPC::BP:
MO.setReg(BPReg);
break;
case PPC::BP8:
MO.setReg(BP8Reg);
break;
}
}
}
}
bool
PPCFrameLowering::findScratchRegister(MachineBasicBlock *MBB,
bool UseAtEnd,
bool TwoUniqueRegsRequired,
Register *SR1,
Register *SR2) const {
RegScavenger RS;
Register R0 = Subtarget.isPPC64() ? PPC::X0 : PPC::R0;
Register R12 = Subtarget.isPPC64() ? PPC::X12 : PPC::R12;
if (SR1)
*SR1 = R0;
if (SR2) {
assert (SR1 && "Asking for the second scratch register but not the first?");
*SR2 = R12;
}
if ((UseAtEnd && MBB->isReturnBlock()) ||
(!UseAtEnd && (&MBB->getParent()->front() == MBB)))
return true;
RS.enterBasicBlock(*MBB);
if (UseAtEnd && !MBB->empty()) {
MachineBasicBlock::iterator MBBI = MBB->getFirstTerminator();
if (MBBI == MBB->end())
MBBI = std::prev(MBBI);
if (MBBI != MBB->begin())
RS.forward(MBBI);
}
if (!RS.isRegUsed(R0) && !RS.isRegUsed(R12))
return true;
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(MBB->getParent());
BitVector BV = RS.getRegsAvailable(Subtarget.isPPC64() ? &PPC::G8RCRegClass :
&PPC::GPRCRegClass);
for (int i = 0; CSRegs[i]; ++i)
BV.reset(CSRegs[i]);
if (SR1) {
int FirstScratchReg = BV.find_first();
*SR1 = FirstScratchReg == -1 ? (unsigned)PPC::NoRegister : FirstScratchReg;
}
if (SR2) {
int SecondScratchReg = BV.find_next(*SR1);
if (SecondScratchReg != -1)
*SR2 = SecondScratchReg;
else
*SR2 = TwoUniqueRegsRequired ? Register() : *SR1;
}
if (BV.count() < (TwoUniqueRegsRequired ? 2U : 1U))
return false;
return true;
}
bool
PPCFrameLowering::twoUniqueScratchRegsRequired(MachineBasicBlock *MBB) const {
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
MachineFunction &MF = *(MBB->getParent());
bool HasBP = RegInfo->hasBasePointer(MF);
unsigned FrameSize = determineFrameLayout(MF);
int NegFrameSize = -FrameSize;
bool IsLargeFrame = !isInt<16>(NegFrameSize);
MachineFrameInfo &MFI = MF.getFrameInfo();
Align MaxAlign = MFI.getMaxAlign();
bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
const PPCTargetLowering &TLI = *Subtarget.getTargetLowering();
return ((IsLargeFrame || !HasRedZone) && HasBP && MaxAlign > 1) ||
TLI.hasInlineStackProbe(MF);
}
bool PPCFrameLowering::canUseAsPrologue(const MachineBasicBlock &MBB) const {
MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
return findScratchRegister(TmpMBB, false,
twoUniqueScratchRegsRequired(TmpMBB));
}
bool PPCFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
return findScratchRegister(TmpMBB, true);
}
bool PPCFrameLowering::stackUpdateCanBeMoved(MachineFunction &MF) const {
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
if (!RegInfo || !FI)
return false;
if (!Subtarget.isELFv2ABI() || !Subtarget.isPPC64())
return false;
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned FrameSize = MFI.getStackSize();
if (!FrameSize || FrameSize > Subtarget.getRedZoneSize())
return false;
if (hasFP(MF) || RegInfo->hasBasePointer(MF) || MF.exposesReturnsTwice())
return false;
if (FI->hasFastCall() || FI->usesPICBase())
return false;
return !RegInfo->requiresFrameIndexScavenging(MF);
}
void PPCFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
MachineFrameInfo &MFI = MF.getFrameInfo();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const PPCTargetLowering &TLI = *Subtarget.getTargetLowering();
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
DebugLoc dl;
const bool needsCFI = MF.needsFrameMoves() && !Subtarget.isAIXABI();
bool isPPC64 = Subtarget.isPPC64();
bool isSVR4ABI = Subtarget.isSVR4ABI();
bool isELFv2ABI = Subtarget.isELFv2ABI();
assert((isSVR4ABI || Subtarget.isAIXABI()) && "Unsupported PPC ABI.");
uint64_t FrameSize = determineFrameLayoutAndUpdate(MF);
int64_t NegFrameSize = -FrameSize;
if (!isPPC64 && (!isInt<32>(FrameSize) || !isInt<32>(NegFrameSize)))
llvm_unreachable("Unhandled stack size!");
if (MFI.isFrameAddressTaken())
replaceFPWithRealFP(MF);
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
bool MustSaveLR = FI->mustSaveLR();
bool MustSaveTOC = FI->mustSaveTOC();
const SmallVectorImpl<Register> &MustSaveCRs = FI->getMustSaveCRs();
bool MustSaveCR = !MustSaveCRs.empty();
bool HasFP = hasFP(MF);
bool HasBP = RegInfo->hasBasePointer(MF);
bool HasRedZone = isPPC64 || !isSVR4ABI;
bool HasROPProtect = Subtarget.hasROPProtect();
bool HasPrivileged = Subtarget.hasPrivileged();
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
Register BPReg = RegInfo->getBaseRegister(MF);
Register FPReg = isPPC64 ? PPC::X31 : PPC::R31;
Register LRReg = isPPC64 ? PPC::LR8 : PPC::LR;
Register TOCReg = isPPC64 ? PPC::X2 : PPC::R2;
Register ScratchReg;
Register TempReg = isPPC64 ? PPC::X12 : PPC::R12; const MCInstrDesc& MFLRInst = TII.get(isPPC64 ? PPC::MFLR8
: PPC::MFLR );
const MCInstrDesc& StoreInst = TII.get(isPPC64 ? PPC::STD
: PPC::STW );
const MCInstrDesc& StoreUpdtInst = TII.get(isPPC64 ? PPC::STDU
: PPC::STWU );
const MCInstrDesc& StoreUpdtIdxInst = TII.get(isPPC64 ? PPC::STDUX
: PPC::STWUX);
const MCInstrDesc& OrInst = TII.get(isPPC64 ? PPC::OR8
: PPC::OR );
const MCInstrDesc& SubtractCarryingInst = TII.get(isPPC64 ? PPC::SUBFC8
: PPC::SUBFC);
const MCInstrDesc& SubtractImmCarryingInst = TII.get(isPPC64 ? PPC::SUBFIC8
: PPC::SUBFIC);
const MCInstrDesc &MoveFromCondRegInst = TII.get(isPPC64 ? PPC::MFCR8
: PPC::MFCR);
const MCInstrDesc &StoreWordInst = TII.get(isPPC64 ? PPC::STW8 : PPC::STW);
const MCInstrDesc &HashST =
TII.get(isPPC64 ? (HasPrivileged ? PPC::HASHSTP8 : PPC::HASHST8)
: (HasPrivileged ? PPC::HASHSTP : PPC::HASHST));
assert((isPPC64 || !isSVR4ABI || !(!FrameSize && (MustSaveLR || HasFP))) &&
"FrameSize must be >0 to save/restore the FP or LR for 32-bit SVR4.");
bool SingleScratchReg = findScratchRegister(
&MBB, false, twoUniqueScratchRegsRequired(&MBB), &ScratchReg, &TempReg);
assert(SingleScratchReg &&
"Required number of registers not available in this block");
SingleScratchReg = ScratchReg == TempReg;
int64_t LROffset = getReturnSaveOffset();
int64_t FPOffset = 0;
if (HasFP) {
MachineFrameInfo &MFI = MF.getFrameInfo();
int FPIndex = FI->getFramePointerSaveIndex();
assert(FPIndex && "No Frame Pointer Save Slot!");
FPOffset = MFI.getObjectOffset(FPIndex);
}
int64_t BPOffset = 0;
if (HasBP) {
MachineFrameInfo &MFI = MF.getFrameInfo();
int BPIndex = FI->getBasePointerSaveIndex();
assert(BPIndex && "No Base Pointer Save Slot!");
BPOffset = MFI.getObjectOffset(BPIndex);
}
int64_t PBPOffset = 0;
if (FI->usesPICBase()) {
MachineFrameInfo &MFI = MF.getFrameInfo();
int PBPIndex = FI->getPICBasePointerSaveIndex();
assert(PBPIndex && "No PIC Base Pointer Save Slot!");
PBPOffset = MFI.getObjectOffset(PBPIndex);
}
Align MaxAlign = MFI.getMaxAlign();
if (HasBP && MaxAlign > 1)
assert(Log2(MaxAlign) < 16 && "Invalid alignment!");
bool isLargeFrame = !isInt<16>(NegFrameSize);
MachineBasicBlock::iterator StackUpdateLoc = MBBI;
bool MovingStackUpdateDown = false;
if (stackUpdateCanBeMoved(MF)) {
const std::vector<CalleeSavedInfo> &Info = MFI.getCalleeSavedInfo();
for (CalleeSavedInfo CSI : Info) {
if (CSI.isSpilledToReg()) {
StackUpdateLoc = MBBI;
MovingStackUpdateDown = false;
break;
}
int FrIdx = CSI.getFrameIdx();
if (FrIdx >= 0)
continue;
if (MFI.isFixedObjectIndex(FrIdx) && MFI.getObjectOffset(FrIdx) < 0) {
StackUpdateLoc++;
MovingStackUpdateDown = true;
} else {
StackUpdateLoc = MBBI;
MovingStackUpdateDown = false;
break;
}
}
if (MovingStackUpdateDown) {
for (CalleeSavedInfo CSI : Info) {
int FrIdx = CSI.getFrameIdx();
if (FrIdx < 0)
MFI.setObjectOffset(FrIdx, MFI.getObjectOffset(FrIdx) + NegFrameSize);
}
}
}
auto BuildMoveFromCR = [&]() {
if (isELFv2ABI && MustSaveCRs.size() == 1) {
assert(isPPC64 && "V2 ABI is 64-bit only.");
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, dl, TII.get(PPC::MFOCRF8), TempReg);
MIB.addReg(MustSaveCRs[0], RegState::Kill);
} else {
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, dl, MoveFromCondRegInst, TempReg);
for (unsigned CRfield : MustSaveCRs)
MIB.addReg(CRfield, RegState::ImplicitKill);
}
};
if (MustSaveCR && SingleScratchReg && MustSaveLR) {
BuildMoveFromCR();
BuildMI(MBB, MBBI, dl, StoreWordInst)
.addReg(TempReg, getKillRegState(true))
.addImm(CRSaveOffset)
.addReg(SPReg);
}
if (MustSaveLR)
BuildMI(MBB, MBBI, dl, MFLRInst, ScratchReg);
if (MustSaveCR && !(SingleScratchReg && MustSaveLR))
BuildMoveFromCR();
if (HasRedZone) {
if (HasFP)
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(FPReg)
.addImm(FPOffset)
.addReg(SPReg);
if (FI->usesPICBase())
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(PPC::R30)
.addImm(PBPOffset)
.addReg(SPReg);
if (HasBP)
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(BPReg)
.addImm(BPOffset)
.addReg(SPReg);
}
if (MustSaveLR) {
BuildMI(MBB, StackUpdateLoc, dl, StoreInst)
.addReg(ScratchReg, getKillRegState(!HasROPProtect))
.addImm(LROffset)
.addReg(SPReg);
if (HasROPProtect) {
const int SaveIndex = FI->getROPProtectionHashSaveIndex();
const int64_t ImmOffset = MFI.getObjectOffset(SaveIndex);
assert((ImmOffset <= -8 && ImmOffset >= -512) &&
"ROP hash save offset out of range.");
assert(((ImmOffset & 0x7) == 0) &&
"ROP hash save offset must be 8 byte aligned.");
BuildMI(MBB, StackUpdateLoc, dl, HashST)
.addReg(ScratchReg, getKillRegState(true))
.addImm(ImmOffset)
.addReg(SPReg);
}
}
if (MustSaveCR &&
!(SingleScratchReg && MustSaveLR)) {
assert(HasRedZone && "A red zone is always available on PPC64");
BuildMI(MBB, MBBI, dl, StoreWordInst)
.addReg(TempReg, getKillRegState(true))
.addImm(CRSaveOffset)
.addReg(SPReg);
}
if (!FrameSize)
return;
if (HasBP && HasRedZone) {
BuildMI(MBB, MBBI, dl, OrInst, BPReg)
.addReg(SPReg)
.addReg(SPReg);
}
bool HasSTUX = false;
if (TLI.hasInlineStackProbe(MF) && FrameSize > TLI.getStackProbeSize(MF)) {
BuildMI(MBB, MBBI, dl,
TII.get(isPPC64 ? PPC::PROBED_STACKALLOC_64
: PPC::PROBED_STACKALLOC_32))
.addDef(TempReg)
.addDef(ScratchReg) .addImm(NegFrameSize);
if (!HasRedZone) {
BuildMI(MBB, MBBI, dl, TII.get(PPC::SUBF), ScratchReg)
.addReg(ScratchReg)
.addReg(SPReg);
HasSTUX = true;
}
} else {
if (HasBP && MaxAlign > 1) {
if (isPPC64)
BuildMI(MBB, MBBI, dl, TII.get(PPC::RLDICL), ScratchReg)
.addReg(SPReg)
.addImm(0)
.addImm(64 - Log2(MaxAlign));
else BuildMI(MBB, MBBI, dl, TII.get(PPC::RLWINM), ScratchReg)
.addReg(SPReg)
.addImm(0)
.addImm(32 - Log2(MaxAlign))
.addImm(31);
if (!isLargeFrame) {
BuildMI(MBB, MBBI, dl, SubtractImmCarryingInst, ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addImm(NegFrameSize);
} else {
assert(!SingleScratchReg && "Only a single scratch reg available");
TII.materializeImmPostRA(MBB, MBBI, dl, TempReg, NegFrameSize);
BuildMI(MBB, MBBI, dl, SubtractCarryingInst, ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addReg(TempReg, RegState::Kill);
}
BuildMI(MBB, MBBI, dl, StoreUpdtIdxInst, SPReg)
.addReg(SPReg, RegState::Kill)
.addReg(SPReg)
.addReg(ScratchReg);
HasSTUX = true;
} else if (!isLargeFrame) {
BuildMI(MBB, StackUpdateLoc, dl, StoreUpdtInst, SPReg)
.addReg(SPReg)
.addImm(NegFrameSize)
.addReg(SPReg);
} else {
TII.materializeImmPostRA(MBB, MBBI, dl, ScratchReg, NegFrameSize);
BuildMI(MBB, MBBI, dl, StoreUpdtIdxInst, SPReg)
.addReg(SPReg, RegState::Kill)
.addReg(SPReg)
.addReg(ScratchReg);
HasSTUX = true;
}
}
if (MustSaveTOC) {
assert(isELFv2ABI && "TOC saves in the prologue only supported on ELFv2");
BuildMI(MBB, StackUpdateLoc, dl, TII.get(PPC::STD))
.addReg(TOCReg, getKillRegState(true))
.addImm(TOCSaveOffset)
.addReg(SPReg);
}
if (!HasRedZone) {
assert(!isPPC64 && "A red zone is always available on PPC64");
if (HasSTUX) {
BuildMI(MBB, MBBI, dl, TII.get(PPC::SUBF), ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addReg(SPReg);
if (ScratchReg == PPC::R0) {
int LastOffset = 0;
if (HasFP) {
BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), ScratchReg)
.addReg(ScratchReg)
.addImm(FPOffset-LastOffset);
LastOffset = FPOffset;
BuildMI(MBB, MBBI, dl, TII.get(PPC::STWX))
.addReg(FPReg, RegState::Kill) .addReg(PPC::ZERO)
.addReg(ScratchReg); }
if (FI->usesPICBase()) {
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) .addReg(PPC::ZERO)
.addReg(ScratchReg); }
if (HasBP) {
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) .addReg(PPC::ZERO)
.addReg(ScratchReg); BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDIC), BPReg)
.addReg(ScratchReg, RegState::Kill)
.addImm(-LastOffset);
}
} else {
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 {
if (HasFP)
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(FPReg)
.addImm(FrameSize + FPOffset)
.addReg(SPReg);
if (FI->usesPICBase())
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(PPC::R30)
.addImm(FrameSize + PBPOffset)
.addReg(SPReg);
if (HasBP) {
BuildMI(MBB, MBBI, dl, StoreInst)
.addReg(BPReg)
.addImm(FrameSize + BPOffset)
.addReg(SPReg);
BuildMI(MBB, MBBI, dl, TII.get(PPC::ADDI), BPReg)
.addReg(SPReg)
.addImm(FrameSize);
}
}
}
if (needsCFI) {
unsigned CFIIndex;
if (HasBP) {
unsigned Reg = MRI->getDwarfRegNum(BPReg, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, Reg));
} else {
assert(NegFrameSize);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, -NegFrameSize));
}
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
if (HasFP) {
unsigned Reg = MRI->getDwarfRegNum(FPReg, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, FPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
if (FI->usesPICBase()) {
unsigned Reg = MRI->getDwarfRegNum(PPC::R30, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, PBPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
if (HasBP) {
unsigned Reg = MRI->getDwarfRegNum(BPReg, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, BPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
if (MustSaveLR) {
unsigned Reg = MRI->getDwarfRegNum(LRReg, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, LROffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}
if (HasFP) {
BuildMI(MBB, MBBI, dl, OrInst, FPReg)
.addReg(SPReg)
.addReg(SPReg);
if (!HasBP && needsCFI) {
unsigned Reg = MRI->getDwarfRegNum(FPReg, true);
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, Reg));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}
if (needsCFI) {
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
for (const CalleeSavedInfo &I : CSI) {
Register Reg = I.getReg();
if (Reg == PPC::LR || Reg == PPC::LR8 || Reg == PPC::RM) continue;
if (PPC::CRBITRCRegClass.contains(Reg))
continue;
if ((Reg == PPC::X2 || Reg == PPC::R2) && MustSaveTOC)
continue;
if (isSVR4ABI && (PPC::CR2 <= Reg && Reg <= PPC::CR4)
&& !MustSaveCR)
continue;
if (isSVR4ABI && isPPC64 && (PPC::CR2 <= Reg && Reg <= PPC::CR4)) {
Register CRReg = isELFv2ABI? Reg : PPC::CR2;
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(CRReg, true), CRSaveOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
continue;
}
if (I.isSpilledToReg()) {
unsigned SpilledReg = I.getDstReg();
unsigned CFIRegister = MF.addFrameInst(MCCFIInstruction::createRegister(
nullptr, MRI->getDwarfRegNum(Reg, true),
MRI->getDwarfRegNum(SpilledReg, true)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIRegister);
} else {
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
if (MovingStackUpdateDown)
Offset -= NegFrameSize;
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}
}
}
void PPCFrameLowering::inlineStackProbe(MachineFunction &MF,
MachineBasicBlock &PrologMBB) const {
bool isPPC64 = Subtarget.isPPC64();
const PPCTargetLowering &TLI = *Subtarget.getTargetLowering();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
MachineFrameInfo &MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
const bool needsCFI = MF.needsFrameMoves() && !Subtarget.isAIXABI();
auto StackAllocMIPos = llvm::find_if(PrologMBB, [](MachineInstr &MI) {
int Opc = MI.getOpcode();
return Opc == PPC::PROBED_STACKALLOC_64 || Opc == PPC::PROBED_STACKALLOC_32;
});
if (StackAllocMIPos == PrologMBB.end())
return;
const BasicBlock *ProbedBB = PrologMBB.getBasicBlock();
MachineBasicBlock *CurrentMBB = &PrologMBB;
DebugLoc DL = PrologMBB.findDebugLoc(StackAllocMIPos);
MachineInstr &MI = *StackAllocMIPos;
int64_t NegFrameSize = MI.getOperand(2).getImm();
unsigned ProbeSize = TLI.getStackProbeSize(MF);
int64_t NegProbeSize = -(int64_t)ProbeSize;
assert(isInt<32>(NegProbeSize) && "Unhandled probe size");
int64_t NumBlocks = NegFrameSize / NegProbeSize;
int64_t NegResidualSize = NegFrameSize % NegProbeSize;
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
Register ScratchReg = MI.getOperand(0).getReg();
Register FPReg = MI.getOperand(1).getReg();
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
bool HasBP = RegInfo->hasBasePointer(MF);
Register BPReg = RegInfo->getBaseRegister(MF);
Align MaxAlign = MFI.getMaxAlign();
bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
const MCInstrDesc &CopyInst = TII.get(isPPC64 ? PPC::OR8 : PPC::OR);
auto buildDefCFAReg = [&](MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, Register Reg) {
unsigned RegNum = MRI->getDwarfRegNum(Reg, true);
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, RegNum));
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
};
auto buildDefCFA = [&](MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, Register Reg,
int Offset) {
unsigned RegNum = MRI->getDwarfRegNum(Reg, true);
unsigned CFIIndex = MBB.getParent()->addFrameInst(
MCCFIInstruction::cfiDefCfa(nullptr, RegNum, Offset));
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
};
auto CanUseDForm = [](int64_t Imm) { return isInt<16>(Imm) && Imm % 4 == 0; };
auto MaterializeImm = [&](MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, int64_t Imm,
Register &TempReg) {
assert(isInt<32>(Imm) && "Unhandled imm");
if (isInt<16>(Imm))
BuildMI(MBB, MBBI, DL, TII.get(isPPC64 ? PPC::LI8 : PPC::LI), TempReg)
.addImm(Imm);
else {
BuildMI(MBB, MBBI, DL, TII.get(isPPC64 ? PPC::LIS8 : PPC::LIS), TempReg)
.addImm(Imm >> 16);
BuildMI(MBB, MBBI, DL, TII.get(isPPC64 ? PPC::ORI8 : PPC::ORI), TempReg)
.addReg(TempReg)
.addImm(Imm & 0xFFFF);
}
};
auto allocateAndProbe = [&](MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, int64_t NegSize,
Register NegSizeReg, bool UseDForm,
Register StoreReg) {
if (UseDForm)
BuildMI(MBB, MBBI, DL, TII.get(isPPC64 ? PPC::STDU : PPC::STWU), SPReg)
.addReg(StoreReg)
.addImm(NegSize)
.addReg(SPReg);
else
BuildMI(MBB, MBBI, DL, TII.get(isPPC64 ? PPC::STDUX : PPC::STWUX), SPReg)
.addReg(StoreReg)
.addReg(SPReg)
.addReg(NegSizeReg);
};
auto probeRealignedStack = [&](MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
Register ScratchReg, Register TempReg) {
assert(HasBP && "The function is supposed to have base pointer when its "
"stack is realigned.");
assert(isPowerOf2_64(ProbeSize) && "Probe size should be power of 2");
assert(ProbeSize >= Subtarget.getRedZoneSize() &&
"Probe size should be larger or equal to the size of red-zone so "
"that red-zone is not clobbered by probing.");
Register &FinalStackPtr = TempReg;
NegProbeSize = std::max(NegProbeSize, -((int64_t)1 << 15));
assert(isInt<16>(NegProbeSize) &&
"NegProbeSize should be materializable by DForm");
Register CRReg = PPC::CR0;
MachineFunction::iterator MBBInsertPoint = std::next(MBB.getIterator());
MachineBasicBlock *ProbeLoopBodyMBB = MF.CreateMachineBasicBlock(ProbedBB);
MF.insert(MBBInsertPoint, ProbeLoopBodyMBB);
MachineBasicBlock *ProbeExitMBB = MF.CreateMachineBasicBlock(ProbedBB);
MF.insert(MBBInsertPoint, ProbeExitMBB);
{
Register BackChainPointer = HasRedZone ? BPReg : TempReg;
allocateAndProbe(*ProbeExitMBB, ProbeExitMBB->end(), 0, ScratchReg, false,
BackChainPointer);
if (HasRedZone)
BuildMI(*ProbeExitMBB, ProbeExitMBB->end(), DL, CopyInst, TempReg)
.addReg(BPReg)
.addReg(BPReg);
ProbeExitMBB->splice(ProbeExitMBB->end(), &MBB, MBBI, MBB.end());
ProbeExitMBB->transferSuccessorsAndUpdatePHIs(&MBB);
}
{
BuildMI(&MBB, DL, TII.get(isPPC64 ? PPC::SUBF8 : PPC::SUBF), ScratchReg)
.addReg(SPReg)
.addReg(FinalStackPtr);
if (!HasRedZone)
BuildMI(&MBB, DL, CopyInst, TempReg).addReg(SPReg).addReg(SPReg);
BuildMI(&MBB, DL, TII.get(isPPC64 ? PPC::CMPDI : PPC::CMPWI), CRReg)
.addReg(ScratchReg)
.addImm(NegProbeSize);
BuildMI(&MBB, DL, TII.get(PPC::BCC))
.addImm(PPC::PRED_GE)
.addReg(CRReg)
.addMBB(ProbeExitMBB);
MBB.addSuccessor(ProbeLoopBodyMBB);
MBB.addSuccessor(ProbeExitMBB);
}
{
Register BackChainPointer = HasRedZone ? BPReg : TempReg;
allocateAndProbe(*ProbeLoopBodyMBB, ProbeLoopBodyMBB->end(), NegProbeSize,
0, true , BackChainPointer);
BuildMI(ProbeLoopBodyMBB, DL, TII.get(isPPC64 ? PPC::ADDI8 : PPC::ADDI),
ScratchReg)
.addReg(ScratchReg)
.addImm(-NegProbeSize);
BuildMI(ProbeLoopBodyMBB, DL, TII.get(isPPC64 ? PPC::CMPDI : PPC::CMPWI),
CRReg)
.addReg(ScratchReg)
.addImm(NegProbeSize);
BuildMI(ProbeLoopBodyMBB, DL, TII.get(PPC::BCC))
.addImm(PPC::PRED_LT)
.addReg(CRReg)
.addMBB(ProbeLoopBodyMBB);
ProbeLoopBodyMBB->addSuccessor(ProbeExitMBB);
ProbeLoopBodyMBB->addSuccessor(ProbeLoopBodyMBB);
}
recomputeLiveIns(*ProbeLoopBodyMBB);
recomputeLiveIns(*ProbeExitMBB);
return ProbeExitMBB;
};
if (HasBP && MaxAlign > 1) {
if (isPPC64)
BuildMI(*CurrentMBB, {MI}, DL, TII.get(PPC::RLDICL), ScratchReg)
.addReg(SPReg)
.addImm(0)
.addImm(64 - Log2(MaxAlign));
else
BuildMI(*CurrentMBB, {MI}, DL, TII.get(PPC::RLWINM), ScratchReg)
.addReg(SPReg)
.addImm(0)
.addImm(32 - Log2(MaxAlign))
.addImm(31);
BuildMI(*CurrentMBB, {MI}, DL, TII.get(isPPC64 ? PPC::SUBF8 : PPC::SUBF),
FPReg)
.addReg(ScratchReg)
.addReg(SPReg);
MaterializeImm(*CurrentMBB, {MI}, NegFrameSize, ScratchReg);
BuildMI(*CurrentMBB, {MI}, DL, TII.get(isPPC64 ? PPC::ADD8 : PPC::ADD4),
FPReg)
.addReg(ScratchReg)
.addReg(FPReg);
CurrentMBB = probeRealignedStack(*CurrentMBB, {MI}, ScratchReg, FPReg);
if (needsCFI)
buildDefCFAReg(*CurrentMBB, {MI}, FPReg);
} else {
BuildMI(*CurrentMBB, {MI}, DL, CopyInst, FPReg).addReg(SPReg).addReg(SPReg);
if (needsCFI)
buildDefCFA(*CurrentMBB, {MI}, FPReg, 0);
if (NegResidualSize) {
bool ResidualUseDForm = CanUseDForm(NegResidualSize);
if (!ResidualUseDForm)
MaterializeImm(*CurrentMBB, {MI}, NegResidualSize, ScratchReg);
allocateAndProbe(*CurrentMBB, {MI}, NegResidualSize, ScratchReg,
ResidualUseDForm, FPReg);
}
bool UseDForm = CanUseDForm(NegProbeSize);
if (NumBlocks < 3) {
if (!UseDForm)
MaterializeImm(*CurrentMBB, {MI}, NegProbeSize, ScratchReg);
for (int i = 0; i < NumBlocks; ++i)
allocateAndProbe(*CurrentMBB, {MI}, NegProbeSize, ScratchReg, UseDForm,
FPReg);
if (needsCFI) {
buildDefCFAReg(*CurrentMBB, {MI}, SPReg);
}
} else {
MaterializeImm(*CurrentMBB, {MI}, NumBlocks, ScratchReg);
BuildMI(*CurrentMBB, {MI}, DL, TII.get(isPPC64 ? PPC::MTCTR8 : PPC::MTCTR))
.addReg(ScratchReg, RegState::Kill);
if (!UseDForm)
MaterializeImm(*CurrentMBB, {MI}, NegProbeSize, ScratchReg);
MachineFunction::iterator MBBInsertPoint =
std::next(CurrentMBB->getIterator());
MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(ProbedBB);
MF.insert(MBBInsertPoint, LoopMBB);
MachineBasicBlock *ExitMBB = MF.CreateMachineBasicBlock(ProbedBB);
MF.insert(MBBInsertPoint, ExitMBB);
allocateAndProbe(*LoopMBB, LoopMBB->end(), NegProbeSize, ScratchReg,
UseDForm, FPReg);
BuildMI(LoopMBB, DL, TII.get(isPPC64 ? PPC::BDNZ8 : PPC::BDNZ))
.addMBB(LoopMBB);
LoopMBB->addSuccessor(ExitMBB);
LoopMBB->addSuccessor(LoopMBB);
ExitMBB->splice(ExitMBB->end(), CurrentMBB,
std::next(MachineBasicBlock::iterator(MI)),
CurrentMBB->end());
ExitMBB->transferSuccessorsAndUpdatePHIs(CurrentMBB);
CurrentMBB->addSuccessor(LoopMBB);
if (needsCFI) {
buildDefCFAReg(*ExitMBB, ExitMBB->begin(), SPReg);
}
recomputeLiveIns(*LoopMBB);
recomputeLiveIns(*ExitMBB);
}
}
++NumPrologProbed;
MI.eraseFromParent();
}
void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
DebugLoc dl;
if (MBBI != MBB.end())
dl = MBBI->getDebugLoc();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const MachineFrameInfo &MFI = MF.getFrameInfo();
int64_t FrameSize = MFI.getStackSize();
bool isPPC64 = Subtarget.isPPC64();
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
bool MustSaveLR = FI->mustSaveLR();
const SmallVectorImpl<Register> &MustSaveCRs = FI->getMustSaveCRs();
bool MustSaveCR = !MustSaveCRs.empty();
bool HasFP = hasFP(MF);
bool HasBP = RegInfo->hasBasePointer(MF);
bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
bool HasROPProtect = Subtarget.hasROPProtect();
bool HasPrivileged = Subtarget.hasPrivileged();
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
Register BPReg = RegInfo->getBaseRegister(MF);
Register FPReg = isPPC64 ? PPC::X31 : PPC::R31;
Register ScratchReg;
Register TempReg = isPPC64 ? PPC::X12 : PPC::R12; const MCInstrDesc& MTLRInst = TII.get( isPPC64 ? PPC::MTLR8
: PPC::MTLR );
const MCInstrDesc& LoadInst = TII.get( isPPC64 ? PPC::LD
: 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
: PPC::ADDI );
const MCInstrDesc& AddInst = TII.get( isPPC64 ? PPC::ADD8
: PPC::ADD4 );
const MCInstrDesc& LoadWordInst = TII.get( isPPC64 ? PPC::LWZ8
: PPC::LWZ);
const MCInstrDesc& MoveToCRInst = TII.get( isPPC64 ? PPC::MTOCRF8
: PPC::MTOCRF);
const MCInstrDesc &HashChk =
TII.get(isPPC64 ? (HasPrivileged ? PPC::HASHCHKP8 : PPC::HASHCHK8)
: (HasPrivileged ? PPC::HASHCHKP : PPC::HASHCHK));
int64_t LROffset = getReturnSaveOffset();
int64_t FPOffset = 0;
bool SingleScratchReg = findScratchRegister(&MBB, true, false, &ScratchReg,
&TempReg);
assert(SingleScratchReg &&
"Could not find an available scratch register");
SingleScratchReg = ScratchReg == TempReg;
if (HasFP) {
int FPIndex = FI->getFramePointerSaveIndex();
assert(FPIndex && "No Frame Pointer Save Slot!");
FPOffset = MFI.getObjectOffset(FPIndex);
}
int64_t BPOffset = 0;
if (HasBP) {
int BPIndex = FI->getBasePointerSaveIndex();
assert(BPIndex && "No Base Pointer Save Slot!");
BPOffset = MFI.getObjectOffset(BPIndex);
}
int64_t PBPOffset = 0;
if (FI->usesPICBase()) {
int PBPIndex = FI->getPICBasePointerSaveIndex();
assert(PBPIndex && "No PIC Base Pointer Save Slot!");
PBPOffset = MFI.getObjectOffset(PBPIndex);
}
bool IsReturnBlock = (MBBI != MBB.end() && MBBI->isReturn());
if (IsReturnBlock) {
unsigned RetOpcode = MBBI->getOpcode();
bool UsesTCRet = RetOpcode == PPC::TCRETURNri ||
RetOpcode == PPC::TCRETURNdi ||
RetOpcode == PPC::TCRETURNai ||
RetOpcode == PPC::TCRETURNri8 ||
RetOpcode == PPC::TCRETURNdi8 ||
RetOpcode == PPC::TCRETURNai8;
if (UsesTCRet) {
int MaxTCRetDelta = FI->getTailCallSPDelta();
MachineOperand &StackAdjust = MBBI->getOperand(1);
assert(StackAdjust.isImm() && "Expecting immediate value.");
int StackAdj = StackAdjust.getImm();
int Delta = StackAdj - MaxTCRetDelta;
assert((Delta >= 0) && "Delta must be positive");
if (MaxTCRetDelta>0)
FrameSize += (StackAdj +Delta);
else
FrameSize += StackAdj;
}
}
bool isLargeFrame = !isInt<16>(FrameSize);
unsigned RBReg = SPReg;
uint64_t SPAdd = 0;
MachineBasicBlock::iterator StackUpdateLoc = MBBI;
if (stackUpdateCanBeMoved(MF)) {
const std::vector<CalleeSavedInfo> & Info = MFI.getCalleeSavedInfo();
for (CalleeSavedInfo CSI : Info) {
if (CSI.isSpilledToReg()) {
StackUpdateLoc = MBBI;
break;
}
int FrIdx = CSI.getFrameIdx();
if (FrIdx >= 0)
continue;
if (MFI.isFixedObjectIndex(FrIdx) && MFI.getObjectOffset(FrIdx) < 0)
StackUpdateLoc--;
else {
StackUpdateLoc = MBBI;
break;
}
}
}
if (FrameSize) {
if (HasRedZone && HasBP) {
BuildMI(MBB, MBBI, dl, OrInst, RBReg).
addReg(BPReg).
addReg(BPReg);
}
else if (FI->hasFastCall() || MF.exposesReturnsTwice()) {
assert(HasFP && "Expecting a valid frame pointer.");
if (!HasRedZone)
RBReg = FPReg;
if (!isLargeFrame) {
BuildMI(MBB, MBBI, dl, AddImmInst, RBReg)
.addReg(FPReg).addImm(FrameSize);
} else {
TII.materializeImmPostRA(MBB, MBBI, dl, ScratchReg, FrameSize);
BuildMI(MBB, MBBI, dl, AddInst)
.addReg(RBReg)
.addReg(FPReg)
.addReg(ScratchReg);
}
} else if (!isLargeFrame && !HasBP && !MFI.hasVarSizedObjects()) {
if (HasRedZone) {
BuildMI(MBB, StackUpdateLoc, dl, AddImmInst, SPReg)
.addReg(SPReg)
.addImm(FrameSize);
} else {
assert(FPOffset <= 0 && BPOffset <= 0 && PBPOffset <= 0 &&
"Local offsets should be negative");
SPAdd = FrameSize;
FPOffset += FrameSize;
BPOffset += FrameSize;
PBPOffset += FrameSize;
}
} else {
if (!HasRedZone) {
if (!HasFP)
BuildMI(MBB, MBBI, dl, OrInst, ScratchReg)
.addReg(FPReg)
.addReg(FPReg);
RBReg = FPReg;
}
BuildMI(MBB, StackUpdateLoc, dl, LoadInst, RBReg)
.addImm(0)
.addReg(SPReg);
}
}
assert(RBReg != ScratchReg && "Should have avoided ScratchReg");
if (MustSaveCR && SingleScratchReg && MustSaveLR) {
assert(HasRedZone && "Expecting red zone");
BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg)
.addImm(CRSaveOffset)
.addReg(SPReg);
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
BuildMI(MBB, MBBI, dl, MoveToCRInst, MustSaveCRs[i])
.addReg(TempReg, getKillRegState(i == e-1));
}
bool LoadedLR = false;
if (MustSaveLR && RBReg == SPReg && isInt<16>(LROffset+SPAdd)) {
BuildMI(MBB, StackUpdateLoc, dl, LoadInst, ScratchReg)
.addImm(LROffset+SPAdd)
.addReg(RBReg);
LoadedLR = true;
}
if (MustSaveCR && !(SingleScratchReg && MustSaveLR)) {
assert(RBReg == SPReg && "Should be using SP as a base register");
BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg)
.addImm(CRSaveOffset)
.addReg(RBReg);
}
if (HasFP) {
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())
BuildMI(MBB, MBBI, dl, LoadInst, PPC::R30)
.addImm(PBPOffset)
.addReg(RBReg);
if (HasBP)
BuildMI(MBB, MBBI, dl, LoadInst, BPReg)
.addImm(BPOffset)
.addReg(RBReg);
if (RBReg != SPReg || SPAdd != 0) {
assert(!HasRedZone && "This should not happen with red zone");
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);
if (MustSaveLR && !LoadedLR)
BuildMI(MBB, MBBI, dl, LoadInst, ScratchReg)
.addImm(LROffset)
.addReg(SPReg);
}
if (MustSaveCR &&
!(SingleScratchReg && MustSaveLR))
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
BuildMI(MBB, MBBI, dl, MoveToCRInst, MustSaveCRs[i])
.addReg(TempReg, getKillRegState(i == e-1));
if (MustSaveLR) {
if (HasROPProtect) {
const int SaveIndex = FI->getROPProtectionHashSaveIndex();
const int64_t ImmOffset = MFI.getObjectOffset(SaveIndex);
assert((ImmOffset <= -8 && ImmOffset >= -512) &&
"ROP hash check location offset out of range.");
assert(((ImmOffset & 0x7) == 0) &&
"ROP hash check location offset must be 8 byte aligned.");
BuildMI(MBB, StackUpdateLoc, dl, HashChk)
.addReg(ScratchReg)
.addImm(ImmOffset)
.addReg(SPReg);
}
BuildMI(MBB, StackUpdateLoc, dl, MTLRInst).addReg(ScratchReg);
}
if (IsReturnBlock) {
unsigned RetOpcode = MBBI->getOpcode();
if (MF.getTarget().Options.GuaranteedTailCallOpt &&
(RetOpcode == PPC::BLR || RetOpcode == PPC::BLR8) &&
MF.getFunction().getCallingConv() == CallingConv::Fast) {
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
unsigned CallerAllocatedAmt = FI->getMinReservedArea();
if (CallerAllocatedAmt && isInt<16>(CallerAllocatedAmt)) {
BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
.addReg(SPReg).addImm(CallerAllocatedAmt);
} else {
BuildMI(MBB, MBBI, dl, LoadImmShiftedInst, ScratchReg)
.addImm(CallerAllocatedAmt >> 16);
BuildMI(MBB, MBBI, dl, OrImmInst, ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addImm(CallerAllocatedAmt & 0xFFFF);
BuildMI(MBB, MBBI, dl, AddInst)
.addReg(SPReg)
.addReg(FPReg)
.addReg(ScratchReg);
}
} else {
createTailCallBranchInstr(MBB);
}
}
}
void PPCFrameLowering::createTailCallBranchInstr(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
assert(MBBI != MBB.end() && "Failed to find the first terminator.");
DebugLoc dl = MBBI->getDebugLoc();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
unsigned RetOpcode = MBBI->getOpcode();
if (RetOpcode == PPC::TCRETURNdi) {
MBBI = MBB.getLastNonDebugInstr();
MachineOperand &JumpTarget = MBBI->getOperand(0);
if (JumpTarget.isGlobal())
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB)).
addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset());
else if (JumpTarget.isSymbol())
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB)).
addExternalSymbol(JumpTarget.getSymbolName());
else
llvm_unreachable("Expecting Global or External Symbol");
} else if (RetOpcode == PPC::TCRETURNri) {
MBBI = MBB.getLastNonDebugInstr();
assert(MBBI->getOperand(0).isReg() && "Expecting register operand.");
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBCTR));
} else if (RetOpcode == PPC::TCRETURNai) {
MBBI = MBB.getLastNonDebugInstr();
MachineOperand &JumpTarget = MBBI->getOperand(0);
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBA)).addImm(JumpTarget.getImm());
} else if (RetOpcode == PPC::TCRETURNdi8) {
MBBI = MBB.getLastNonDebugInstr();
MachineOperand &JumpTarget = MBBI->getOperand(0);
if (JumpTarget.isGlobal())
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB8)).
addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset());
else if (JumpTarget.isSymbol())
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILB8)).
addExternalSymbol(JumpTarget.getSymbolName());
else
llvm_unreachable("Expecting Global or External Symbol");
} else if (RetOpcode == PPC::TCRETURNri8) {
MBBI = MBB.getLastNonDebugInstr();
assert(MBBI->getOperand(0).isReg() && "Expecting register operand.");
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBCTR8));
} else if (RetOpcode == PPC::TCRETURNai8) {
MBBI = MBB.getLastNonDebugInstr();
MachineOperand &JumpTarget = MBBI->getOperand(0);
BuildMI(MBB, MBBI, dl, TII.get(PPC::TAILBA8)).addImm(JumpTarget.getImm());
}
}
void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
SavedRegs.reset(PPC::VSRp26);
SavedRegs.reset(PPC::VSRp27);
SavedRegs.reset(PPC::VSRp28);
SavedRegs.reset(PPC::VSRp29);
SavedRegs.reset(PPC::VSRp30);
SavedRegs.reset(PPC::VSRp31);
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
unsigned LR = RegInfo->getRARegister();
FI->setMustSaveLR(MustSaveLR(MF, LR));
SavedRegs.reset(LR);
int FPSI = FI->getFramePointerSaveIndex();
const bool isPPC64 = Subtarget.isPPC64();
MachineFrameInfo &MFI = MF.getFrameInfo();
if (!FPSI && needsFP(MF)) {
int FPOffset = getFramePointerSaveOffset();
FPSI = MFI.CreateFixedObject(isPPC64? 8 : 4, FPOffset, true);
FI->setFramePointerSaveIndex(FPSI);
}
int BPSI = FI->getBasePointerSaveIndex();
if (!BPSI && RegInfo->hasBasePointer(MF)) {
int BPOffset = getBasePointerSaveOffset();
BPSI = MFI.CreateFixedObject(isPPC64? 8 : 4, BPOffset, true);
FI->setBasePointerSaveIndex(BPSI);
}
if (FI->usesPICBase()) {
int PBPSI = MFI.CreateFixedObject(4, -8, true);
FI->setPICBasePointerSaveIndex(PBPSI);
}
if (needsFP(MF))
SavedRegs.reset(isPPC64 ? PPC::X31 : PPC::R31);
if (RegInfo->hasBasePointer(MF))
SavedRegs.reset(RegInfo->getBaseRegister(MF));
if (FI->usesPICBase())
SavedRegs.reset(PPC::R30);
int TCSPDelta = 0;
if (MF.getTarget().Options.GuaranteedTailCallOpt &&
(TCSPDelta = FI->getTailCallSPDelta()) < 0) {
MFI.CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true);
}
if ((SavedRegs.test(PPC::CR2) || SavedRegs.test(PPC::CR3) ||
SavedRegs.test(PPC::CR4))) {
const uint64_t SpillSize = 4; const int64_t SpillOffset =
Subtarget.isPPC64() ? 8 : Subtarget.isAIXABI() ? 4 : -4;
int FrameIdx =
MFI.CreateFixedObject(SpillSize, SpillOffset,
true, false);
FI->setCRSpillFrameIndex(FrameIdx);
}
}
void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (MFI.getSavePoint() && MFI.hasTailCall()) {
MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
for (MachineBasicBlock &MBB : MF) {
if (MBB.isReturnBlock() && (&MBB) != RestoreBlock)
createTailCallBranchInstr(MBB);
}
}
if (CSI.empty() && !needsFP(MF)) {
addScavengingSpillSlot(MF, RS);
return;
}
unsigned MinGPR = PPC::R31;
unsigned MinG8R = PPC::X31;
unsigned MinFPR = PPC::F31;
unsigned MinVR = Subtarget.hasSPE() ? PPC::S31 : PPC::V31;
bool HasGPSaveArea = false;
bool HasG8SaveArea = false;
bool HasFPSaveArea = false;
bool HasVRSaveArea = false;
SmallVector<CalleeSavedInfo, 18> GPRegs;
SmallVector<CalleeSavedInfo, 18> G8Regs;
SmallVector<CalleeSavedInfo, 18> FPRegs;
SmallVector<CalleeSavedInfo, 18> VRegs;
for (const CalleeSavedInfo &I : CSI) {
Register Reg = I.getReg();
assert((!MF.getInfo<PPCFunctionInfo>()->mustSaveTOC() ||
(Reg != PPC::X2 && Reg != PPC::R2)) &&
"Not expecting to try to spill R2 in a function that must save TOC");
if (PPC::GPRCRegClass.contains(Reg)) {
HasGPSaveArea = true;
GPRegs.push_back(I);
if (Reg < MinGPR) {
MinGPR = Reg;
}
} else if (PPC::G8RCRegClass.contains(Reg)) {
HasG8SaveArea = true;
G8Regs.push_back(I);
if (Reg < MinG8R) {
MinG8R = Reg;
}
} else if (PPC::F8RCRegClass.contains(Reg)) {
HasFPSaveArea = true;
FPRegs.push_back(I);
if (Reg < MinFPR) {
MinFPR = Reg;
}
} else if (PPC::CRBITRCRegClass.contains(Reg) ||
PPC::CRRCRegClass.contains(Reg)) {
; } else if (PPC::VRRCRegClass.contains(Reg) ||
PPC::SPERCRegClass.contains(Reg)) {
HasVRSaveArea = true;
VRegs.push_back(I);
if (Reg < MinVR) {
MinVR = Reg;
}
} else {
llvm_unreachable("Unknown RegisterClass!");
}
}
PPCFunctionInfo *PFI = MF.getInfo<PPCFunctionInfo>();
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
int64_t LowerBound = 0;
int TCSPDelta = 0;
if (MF.getTarget().Options.GuaranteedTailCallOpt &&
(TCSPDelta = PFI->getTailCallSPDelta()) < 0) {
LowerBound = TCSPDelta;
}
if (HasFPSaveArea) {
for (unsigned i = 0, e = FPRegs.size(); i != e; ++i) {
int FI = FPRegs[i].getFrameIdx();
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
LowerBound -= (31 - TRI->getEncodingValue(MinFPR) + 1) * 8;
}
if (needsFP(MF)) {
int FI = PFI->getFramePointerSaveIndex();
assert(FI && "No Frame Pointer Save Slot!");
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
HasGPSaveArea = true;
}
if (PFI->usesPICBase()) {
int FI = PFI->getPICBasePointerSaveIndex();
assert(FI && "No PIC Base Pointer Save Slot!");
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
MinGPR = std::min<unsigned>(MinGPR, PPC::R30);
HasGPSaveArea = true;
}
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
if (RegInfo->hasBasePointer(MF)) {
int FI = PFI->getBasePointerSaveIndex();
assert(FI && "No Base Pointer Save Slot!");
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
Register BP = RegInfo->getBaseRegister(MF);
if (PPC::G8RCRegClass.contains(BP)) {
MinG8R = std::min<unsigned>(MinG8R, BP);
HasG8SaveArea = true;
} else if (PPC::GPRCRegClass.contains(BP)) {
MinGPR = std::min<unsigned>(MinGPR, BP);
HasGPSaveArea = true;
}
}
if (HasGPSaveArea || HasG8SaveArea) {
for (unsigned i = 0, e = GPRegs.size(); i != e; ++i) {
if (!GPRegs[i].isSpilledToReg()) {
int FI = GPRegs[i].getFrameIdx();
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
for (unsigned i = 0, e = G8Regs.size(); i != e; ++i) {
if (!G8Regs[i].isSpilledToReg()) {
int FI = G8Regs[i].getFrameIdx();
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
unsigned MinReg =
std::min<unsigned>(TRI->getEncodingValue(MinGPR),
TRI->getEncodingValue(MinG8R));
const unsigned GPRegSize = Subtarget.isPPC64() ? 8 : 4;
LowerBound -= (31 - MinReg + 1) * GPRegSize;
}
if (spillsCR(MF) && Subtarget.is32BitELFABI()) {
for (const auto &CSInfo : CSI) {
if (CSInfo.getReg() == PPC::CR2) {
int FI = CSInfo.getFrameIdx();
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
break;
}
}
LowerBound -= 4; }
if (HasVRSaveArea) {
assert(LowerBound <= 0 && "Expect LowerBound have a non-positive value!");
LowerBound &= ~(15);
for (unsigned i = 0, e = VRegs.size(); i != e; ++i) {
int FI = VRegs[i].getFrameIdx();
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
addScavengingSpillSlot(MF, RS);
}
void
PPCFrameLowering::addScavengingSpillSlot(MachineFunction &MF,
RegScavenger *RS) const {
unsigned StackSize = determineFrameLayout(MF, true);
MachineFrameInfo &MFI = MF.getFrameInfo();
if (MFI.hasVarSizedObjects() || spillsCR(MF) || hasNonRISpills(MF) ||
(hasSpills(MF) && !isInt<16>(StackSize))) {
const TargetRegisterClass &GPRC = PPC::GPRCRegClass;
const TargetRegisterClass &G8RC = PPC::G8RCRegClass;
const TargetRegisterClass &RC = Subtarget.isPPC64() ? G8RC : GPRC;
const TargetRegisterInfo &TRI = *Subtarget.getRegisterInfo();
unsigned Size = TRI.getSpillSize(RC);
Align Alignment = TRI.getSpillAlign(RC);
RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Alignment, false));
bool HasAlVars =
MFI.hasVarSizedObjects() && MFI.getMaxAlign() > getStackAlign();
if (spillsCR(MF) || HasAlVars)
RS->addScavengingFrameIndex(
MFI.CreateStackObject(Size, Alignment, false));
}
}
bool PPCFrameLowering::assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const {
if (CSI.empty())
return true;
MachineFrameInfo &MFI = MF.getFrameInfo();
if (!EnablePEVectorSpills || MFI.hasCalls() || !Subtarget.hasP9Vector())
return false;
BitVector BVAllocatable = TRI->getAllocatableSet(MF);
BitVector BVCalleeSaved(TRI->getNumRegs());
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
for (unsigned i = 0; CSRegs[i]; ++i)
BVCalleeSaved.set(CSRegs[i]);
for (unsigned Reg : BVAllocatable.set_bits()) {
if (BVCalleeSaved[Reg] || !PPC::VSRCRegClass.contains(Reg) ||
MF.getRegInfo().isPhysRegUsed(Reg))
BVAllocatable.reset(Reg);
}
bool AllSpilledToReg = true;
unsigned LastVSRUsedForSpill = 0;
for (auto &CS : CSI) {
if (BVAllocatable.none())
return false;
Register Reg = CS.getReg();
if (!PPC::G8RCRegClass.contains(Reg)) {
AllSpilledToReg = false;
continue;
}
if (LastVSRUsedForSpill != 0) {
CS.setDstReg(LastVSRUsedForSpill);
BVAllocatable.reset(LastVSRUsedForSpill);
LastVSRUsedForSpill = 0;
continue;
}
unsigned VolatileVFReg = BVAllocatable.find_first();
if (VolatileVFReg < BVAllocatable.size()) {
CS.setDstReg(VolatileVFReg);
LastVSRUsedForSpill = VolatileVFReg;
} else {
AllSpilledToReg = false;
}
}
return AllSpilledToReg;
}
bool PPCFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
bool MustSaveTOC = FI->mustSaveTOC();
DebugLoc DL;
bool CRSpilled = false;
MachineInstrBuilder CRMIB;
BitVector Spilled(TRI->getNumRegs());
VSRContainingGPRs.clear();
for (const CalleeSavedInfo &Info : CSI) {
if (Info.isSpilledToReg()) {
auto &SpilledVSR =
VSRContainingGPRs.FindAndConstruct(Info.getDstReg()).second;
assert(SpilledVSR.second == 0 &&
"Can't spill more than two GPRs into VSR!");
if (SpilledVSR.first == 0)
SpilledVSR.first = Info.getReg();
else
SpilledVSR.second = Info.getReg();
}
}
for (const CalleeSavedInfo &I : CSI) {
Register Reg = I.getReg();
bool IsCRField = PPC::CR2 <= Reg && Reg <= PPC::CR4;
const MachineRegisterInfo &MRI = MF->getRegInfo();
bool IsLiveIn = MRI.isLiveIn(Reg);
if (!IsLiveIn)
MBB.addLiveIn(Reg);
if (CRSpilled && IsCRField) {
CRMIB.addReg(Reg, RegState::ImplicitKill);
continue;
}
if ((Reg == PPC::X2 || Reg == PPC::R2) && MustSaveTOC)
continue;
if (IsCRField) {
PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>();
if (!Subtarget.is32BitELFABI()) {
FuncInfo->addMustSaveCR(Reg);
} else {
CRSpilled = true;
FuncInfo->setSpillsCR();
CRMIB = BuildMI(*MF, DL, TII.get(PPC::MFCR), PPC::R12)
.addReg(Reg, RegState::ImplicitKill);
MBB.insert(MI, CRMIB);
MBB.insert(MI, addFrameReference(BuildMI(*MF, DL, TII.get(PPC::STW))
.addReg(PPC::R12,
getKillRegState(true)),
I.getFrameIdx()));
}
} else {
if (I.isSpilledToReg()) {
unsigned Dst = I.getDstReg();
if (Spilled[Dst])
continue;
if (VSRContainingGPRs[Dst].second != 0) {
assert(Subtarget.hasP9Vector() &&
"mtvsrdd is unavailable on pre-P9 targets.");
NumPESpillVSR += 2;
BuildMI(MBB, MI, DL, TII.get(PPC::MTVSRDD), Dst)
.addReg(VSRContainingGPRs[Dst].first, getKillRegState(true))
.addReg(VSRContainingGPRs[Dst].second, getKillRegState(true));
} else if (VSRContainingGPRs[Dst].second == 0) {
assert(Subtarget.hasP8Vector() &&
"Can't move GPR to VSR on pre-P8 targets.");
++NumPESpillVSR;
BuildMI(MBB, MI, DL, TII.get(PPC::MTVSRD),
TRI->getSubReg(Dst, PPC::sub_64))
.addReg(VSRContainingGPRs[Dst].first, getKillRegState(true));
} else {
llvm_unreachable("More than two GPRs spilled to a VSR!");
}
Spilled.set(Dst);
} else {
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
if (Subtarget.needsSwapsForVSXMemOps() &&
!MF->getFunction().hasFnAttribute(Attribute::NoUnwind))
TII.storeRegToStackSlotNoUpd(MBB, MI, Reg, !IsLiveIn,
I.getFrameIdx(), RC, TRI);
else
TII.storeRegToStackSlot(MBB, MI, Reg, !IsLiveIn, I.getFrameIdx(),
RC, TRI);
}
}
}
return true;
}
static void restoreCRs(bool is31, bool CR2Spilled, bool CR3Spilled,
bool CR4Spilled, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, unsigned CSIIndex) {
MachineFunction *MF = MBB.getParent();
const PPCInstrInfo &TII = *MF->getSubtarget<PPCSubtarget>().getInstrInfo();
DebugLoc DL;
unsigned MoveReg = PPC::R12;
MBB.insert(MI,
addFrameReference(BuildMI(*MF, DL, TII.get(PPC::LWZ), MoveReg),
CSI[CSIIndex].getFrameIdx()));
unsigned RestoreOp = PPC::MTOCRF;
if (CR2Spilled)
MBB.insert(MI, BuildMI(*MF, DL, TII.get(RestoreOp), PPC::CR2)
.addReg(MoveReg, getKillRegState(!CR3Spilled && !CR4Spilled)));
if (CR3Spilled)
MBB.insert(MI, BuildMI(*MF, DL, TII.get(RestoreOp), PPC::CR3)
.addReg(MoveReg, getKillRegState(!CR4Spilled)));
if (CR4Spilled)
MBB.insert(MI, BuildMI(*MF, DL, TII.get(RestoreOp), PPC::CR4)
.addReg(MoveReg, getKillRegState(true)));
}
MachineBasicBlock::iterator PPCFrameLowering::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
if (MF.getTarget().Options.GuaranteedTailCallOpt &&
I->getOpcode() == PPC::ADJCALLSTACKUP) {
if (int CalleeAmt = I->getOperand(1).getImm()) {
bool is64Bit = Subtarget.isPPC64();
CalleeAmt *= -1;
unsigned StackReg = is64Bit ? PPC::X1 : PPC::R1;
unsigned TmpReg = is64Bit ? PPC::X0 : PPC::R0;
unsigned ADDIInstr = is64Bit ? PPC::ADDI8 : PPC::ADDI;
unsigned ADDInstr = is64Bit ? PPC::ADD8 : PPC::ADD4;
unsigned LISInstr = is64Bit ? PPC::LIS8 : PPC::LIS;
unsigned ORIInstr = is64Bit ? PPC::ORI8 : PPC::ORI;
const DebugLoc &dl = I->getDebugLoc();
if (isInt<16>(CalleeAmt)) {
BuildMI(MBB, I, dl, TII.get(ADDIInstr), StackReg)
.addReg(StackReg, RegState::Kill)
.addImm(CalleeAmt);
} else {
MachineBasicBlock::iterator MBBI = I;
BuildMI(MBB, MBBI, dl, TII.get(LISInstr), TmpReg)
.addImm(CalleeAmt >> 16);
BuildMI(MBB, MBBI, dl, TII.get(ORIInstr), TmpReg)
.addReg(TmpReg, RegState::Kill)
.addImm(CalleeAmt & 0xFFFF);
BuildMI(MBB, MBBI, dl, TII.get(ADDInstr), StackReg)
.addReg(StackReg, RegState::Kill)
.addReg(TmpReg);
}
}
}
return MBB.erase(I);
}
static bool isCalleeSavedCR(unsigned Reg) {
return PPC::CR2 == Reg || Reg == PPC::CR3 || Reg == PPC::CR4;
}
bool PPCFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
bool MustSaveTOC = FI->mustSaveTOC();
bool CR2Spilled = false;
bool CR3Spilled = false;
bool CR4Spilled = false;
unsigned CSIIndex = 0;
BitVector Restored(TRI->getNumRegs());
MachineBasicBlock::iterator I = MI, BeforeI = I;
bool AtStart = I == MBB.begin();
if (!AtStart)
--BeforeI;
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
Register Reg = CSI[i].getReg();
if ((Reg == PPC::X2 || Reg == PPC::R2) && MustSaveTOC)
continue;
if (isCalleeSavedCR(Reg) && !Subtarget.is32BitELFABI())
continue;
if (Reg == PPC::CR2) {
CR2Spilled = true;
CSIIndex = i;
continue;
} else if (Reg == PPC::CR3) {
CR3Spilled = true;
continue;
} else if (Reg == PPC::CR4) {
CR4Spilled = true;
continue;
} else {
if (CR2Spilled || CR3Spilled || CR4Spilled) {
bool is31 = needsFP(*MF);
restoreCRs(is31, CR2Spilled, CR3Spilled, CR4Spilled, MBB, I, CSI,
CSIIndex);
CR2Spilled = CR3Spilled = CR4Spilled = false;
}
if (CSI[i].isSpilledToReg()) {
DebugLoc DL;
unsigned Dst = CSI[i].getDstReg();
if (Restored[Dst])
continue;
if (VSRContainingGPRs[Dst].second != 0) {
assert(Subtarget.hasP9Vector());
NumPEReloadVSR += 2;
BuildMI(MBB, I, DL, TII.get(PPC::MFVSRLD),
VSRContainingGPRs[Dst].second)
.addReg(Dst);
BuildMI(MBB, I, DL, TII.get(PPC::MFVSRD),
VSRContainingGPRs[Dst].first)
.addReg(TRI->getSubReg(Dst, PPC::sub_64), getKillRegState(true));
} else if (VSRContainingGPRs[Dst].second == 0) {
assert(Subtarget.hasP8Vector());
++NumPEReloadVSR;
BuildMI(MBB, I, DL, TII.get(PPC::MFVSRD),
VSRContainingGPRs[Dst].first)
.addReg(TRI->getSubReg(Dst, PPC::sub_64), getKillRegState(true));
} else {
llvm_unreachable("More than two GPRs spilled to a VSR!");
}
Restored.set(Dst);
} else {
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
if (Subtarget.needsSwapsForVSXMemOps() &&
!MF->getFunction().hasFnAttribute(Attribute::NoUnwind))
TII.loadRegFromStackSlotNoUpd(MBB, I, Reg, CSI[i].getFrameIdx(), RC,
TRI);
else
TII.loadRegFromStackSlot(MBB, I, Reg, CSI[i].getFrameIdx(), RC, TRI);
assert(I != MBB.begin() &&
"loadRegFromStackSlot didn't insert any code!");
}
}
if (AtStart)
I = MBB.begin();
else {
I = BeforeI;
++I;
}
}
if (CR2Spilled || CR3Spilled || CR4Spilled) {
assert(Subtarget.is32BitELFABI() &&
"Only set CR[2|3|4]Spilled on 32-bit SVR4.");
bool is31 = needsFP(*MF);
restoreCRs(is31, CR2Spilled, CR3Spilled, CR4Spilled, MBB, I, CSI, CSIIndex);
}
return true;
}
uint64_t PPCFrameLowering::getTOCSaveOffset() const {
return TOCSaveOffset;
}
uint64_t PPCFrameLowering::getFramePointerSaveOffset() const {
return FramePointerSaveOffset;
}
uint64_t PPCFrameLowering::getBasePointerSaveOffset() const {
return BasePointerSaveOffset;
}
bool PPCFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const {
if (MF.getInfo<PPCFunctionInfo>()->shrinkWrapDisabled())
return false;
return !MF.getSubtarget<PPCSubtarget>().is32BitELFABI();
}