1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[PowerPC][AIX] Spill/restore the callee-saved condition register bits.

Extends the existing support for spilling and restoring the condition
register to the linkage area for 32-bit targets, and enables for AIX.

Differential Revision: https://reviews.llvm.org/D74349
This commit is contained in:
Sean Fertile 2020-02-24 10:48:45 -05:00
parent 417ce65d08
commit 876805ea19
8 changed files with 386 additions and 169 deletions

View File

@ -79,9 +79,8 @@ static unsigned computeBasePointerSaveOffset(const PPCSubtarget &STI) {
: STI.getTargetMachine().isPositionIndependent() ? -12U : -8U; : STI.getTargetMachine().isPositionIndependent() ? -12U : -8U;
} }
static unsigned computeCRSaveOffset() { static unsigned computeCRSaveOffset(const PPCSubtarget &STI) {
// The condition register save offset needs to be updated for AIX PPC32. return (STI.isAIXABI() && !STI.isPPC64()) ? 4 : 8;
return 8;
} }
PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI) PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI)
@ -92,7 +91,7 @@ PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI)
FramePointerSaveOffset(computeFramePointerSaveOffset(Subtarget)), FramePointerSaveOffset(computeFramePointerSaveOffset(Subtarget)),
LinkageSize(computeLinkageSize(Subtarget)), LinkageSize(computeLinkageSize(Subtarget)),
BasePointerSaveOffset(computeBasePointerSaveOffset(Subtarget)), BasePointerSaveOffset(computeBasePointerSaveOffset(Subtarget)),
CRSaveOffset(computeCRSaveOffset()) {} CRSaveOffset(computeCRSaveOffset(Subtarget)) {}
// With the SVR4 ABI, callee-saved registers have fixed offsets on the stack. // With the SVR4 ABI, callee-saved registers have fixed offsets on the stack.
const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots( const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots(
@ -741,7 +740,8 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
MachineModuleInfo &MMI = MF.getMMI(); MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
DebugLoc dl; DebugLoc dl;
bool needsCFI = MF.needsFrameMoves(); // AIX assembler does not support cfi directives.
const bool needsCFI = MF.needsFrameMoves() && !Subtarget.isAIXABI();
// Get processor type. // Get processor type.
bool isPPC64 = Subtarget.isPPC64(); bool isPPC64 = Subtarget.isPPC64();
@ -812,6 +812,9 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
: PPC::SUBFC); : PPC::SUBFC);
const MCInstrDesc& SubtractImmCarryingInst = TII.get(isPPC64 ? PPC::SUBFIC8 const MCInstrDesc& SubtractImmCarryingInst = TII.get(isPPC64 ? PPC::SUBFIC8
: PPC::SUBFIC); : PPC::SUBFIC);
const MCInstrDesc &MoveFromCondRegInst = TII.get(isPPC64 ? PPC::MFCR8
: PPC::MFCR);
const MCInstrDesc &StoreWordInst = TII.get(isPPC64 ? PPC::STW8 : PPC::STW);
// Regarding this assert: Even though LR is saved in the caller's frame (i.e., // Regarding this assert: Even though LR is saved in the caller's frame (i.e.,
// LROffset is positive), that slot is callee-owned. Because PPC32 SVR4 has no // LROffset is positive), that slot is callee-owned. Because PPC32 SVR4 has no
@ -873,12 +876,6 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
// indexed into with a simple STDU/STWU/STD/STW immediate offset operand. // indexed into with a simple STDU/STWU/STD/STW immediate offset operand.
bool isLargeFrame = !isInt<16>(NegFrameSize); bool isLargeFrame = !isInt<16>(NegFrameSize);
assert((isPPC64 || !MustSaveCR) &&
"Prologue CR saving supported only in 64-bit mode");
if (MustSaveCR && isAIXABI)
report_fatal_error("Prologue CR saving is unimplemented on AIX.");
// Check if we can move the stack update instruction (stdu) down the prologue // Check if we can move the stack update instruction (stdu) down the prologue
// past the callee saves. Hopefully this will avoid the situation where the // past the callee saves. Hopefully this will avoid the situation where the
// saves are waiting for the update on the store with update to complete. // saves are waiting for the update on the store with update to complete.
@ -918,49 +915,42 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
} }
} }
// Where in the prologue we move the CR fields depends on how many scratch
// registers we have, and if we need to save the link register or not. This
// lambda is to avoid duplicating the logic in 2 places.
auto BuildMoveFromCR = [&]() {
if (isELFv2ABI && MustSaveCRs.size() == 1) {
// In the ELFv2 ABI, we are not required to save all CR fields.
// If only one CR field is clobbered, it is more efficient to use
// mfocrf to selectively save just that field, because mfocrf has short
// latency compares to mfcr.
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 we need to spill the CR and the LR but we don't have two separate // If we need to spill the CR and the LR but we don't have two separate
// registers available, we must spill them one at a time // registers available, we must spill them one at a time
if (MustSaveCR && SingleScratchReg && MustSaveLR) { if (MustSaveCR && SingleScratchReg && MustSaveLR) {
// In the ELFv2 ABI, we are not required to save all CR fields. BuildMoveFromCR();
// If only one or two CR fields are clobbered, it is more efficient to use BuildMI(MBB, MBBI, dl, StoreWordInst)
// mfocrf to selectively save just those fields, because mfocrf has short
// latency compares to mfcr.
unsigned MfcrOpcode = PPC::MFCR8;
unsigned CrState = RegState::ImplicitKill;
if (isELFv2ABI && MustSaveCRs.size() == 1) {
MfcrOpcode = PPC::MFOCRF8;
CrState = RegState::Kill;
}
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, dl, TII.get(MfcrOpcode), TempReg);
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
MIB.addReg(MustSaveCRs[i], CrState);
BuildMI(MBB, MBBI, dl, TII.get(PPC::STW8))
.addReg(TempReg, getKillRegState(true)) .addReg(TempReg, getKillRegState(true))
.addImm(getCRSaveOffset()) .addImm(CRSaveOffset)
.addReg(SPReg); .addReg(SPReg);
} }
if (MustSaveLR) if (MustSaveLR)
BuildMI(MBB, MBBI, dl, MFLRInst, ScratchReg); BuildMI(MBB, MBBI, dl, MFLRInst, ScratchReg);
if (MustSaveCR && if (MustSaveCR && !(SingleScratchReg && MustSaveLR))
!(SingleScratchReg && MustSaveLR)) { // will only occur for PPC64 BuildMoveFromCR();
// In the ELFv2 ABI, we are not required to save all CR fields.
// If only one or two CR fields are clobbered, it is more efficient to use
// mfocrf to selectively save just those fields, because mfocrf has short
// latency compares to mfcr.
unsigned MfcrOpcode = PPC::MFCR8;
unsigned CrState = RegState::ImplicitKill;
if (isELFv2ABI && MustSaveCRs.size() == 1) {
MfcrOpcode = PPC::MFOCRF8;
CrState = RegState::Kill;
}
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, dl, TII.get(MfcrOpcode), TempReg);
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
MIB.addReg(MustSaveCRs[i], CrState);
}
if (HasRedZone) { if (HasRedZone) {
if (HasFP) if (HasFP)
@ -987,11 +977,11 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(SPReg); .addReg(SPReg);
if (MustSaveCR && if (MustSaveCR &&
!(SingleScratchReg && MustSaveLR)) { // will only occur for PPC64 !(SingleScratchReg && MustSaveLR)) {
assert(HasRedZone && "A red zone is always available on PPC64"); assert(HasRedZone && "A red zone is always available on PPC64");
BuildMI(MBB, MBBI, dl, TII.get(PPC::STW8)) BuildMI(MBB, MBBI, dl, StoreWordInst)
.addReg(TempReg, getKillRegState(true)) .addReg(TempReg, getKillRegState(true))
.addImm(getCRSaveOffset()) .addImm(CRSaveOffset)
.addReg(SPReg); .addReg(SPReg);
} }
@ -1295,7 +1285,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
// actually saved gets its own CFI record. // actually saved gets its own CFI record.
unsigned CRReg = isELFv2ABI? Reg : (unsigned) PPC::CR2; unsigned CRReg = isELFv2ABI? Reg : (unsigned) PPC::CR2;
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(CRReg, true), getCRSaveOffset())); nullptr, MRI->getDwarfRegNum(CRReg, true), CRSaveOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex); .addCFIIndex(CFIIndex);
continue; continue;
@ -1376,7 +1366,10 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
: PPC::ADDI ); : PPC::ADDI );
const MCInstrDesc& AddInst = TII.get( isPPC64 ? PPC::ADD8 const MCInstrDesc& AddInst = TII.get( isPPC64 ? PPC::ADD8
: PPC::ADD4 ); : PPC::ADD4 );
const MCInstrDesc& LoadWordInst = TII.get( isPPC64 ? PPC::LWZ8
: PPC::LWZ);
const MCInstrDesc& MoveToCRInst = TII.get( isPPC64 ? PPC::MTOCRF8
: PPC::MTOCRF);
int LROffset = getReturnSaveOffset(); int LROffset = getReturnSaveOffset();
int FPOffset = 0; int FPOffset = 0;
@ -1551,20 +1544,17 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
// value (although not the base register). Make sure it is not overwritten // value (although not the base register). Make sure it is not overwritten
// too early. // too early.
assert((isPPC64 || !MustSaveCR) &&
"Epilogue CR restoring supported only in 64-bit mode");
// If we need to restore both the LR and the CR and we only have one // 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. // available scratch register, we must do them one at a time.
if (MustSaveCR && SingleScratchReg && MustSaveLR) { if (MustSaveCR && SingleScratchReg && MustSaveLR) {
// Here TempReg == ScratchReg, and in the absence of red zone ScratchReg // Here TempReg == ScratchReg, and in the absence of red zone ScratchReg
// is live here. // is live here.
assert(HasRedZone && "Expecting red zone"); assert(HasRedZone && "Expecting red zone");
BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg) BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg)
.addImm(getCRSaveOffset()) .addImm(CRSaveOffset)
.addReg(SPReg); .addReg(SPReg);
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i) for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
BuildMI(MBB, MBBI, dl, TII.get(PPC::MTOCRF8), MustSaveCRs[i]) BuildMI(MBB, MBBI, dl, MoveToCRInst, MustSaveCRs[i])
.addReg(TempReg, getKillRegState(i == e-1)); .addReg(TempReg, getKillRegState(i == e-1));
} }
@ -1581,11 +1571,9 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
} }
if (MustSaveCR && !(SingleScratchReg && MustSaveLR)) { 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"); assert(RBReg == SPReg && "Should be using SP as a base register");
BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg) BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg)
.addImm(getCRSaveOffset()) .addImm(CRSaveOffset)
.addReg(RBReg); .addReg(RBReg);
} }
@ -1640,9 +1628,9 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
} }
if (MustSaveCR && if (MustSaveCR &&
!(SingleScratchReg && MustSaveLR)) // will only occur for PPC64 !(SingleScratchReg && MustSaveLR))
for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i) for (unsigned i = 0, e = MustSaveCRs.size(); i != e; ++i)
BuildMI(MBB, MBBI, dl, TII.get(PPC::MTOCRF8), MustSaveCRs[i]) BuildMI(MBB, MBBI, dl, MoveToCRInst, MustSaveCRs[i])
.addReg(TempReg, getKillRegState(i == e-1)); .addReg(TempReg, getKillRegState(i == e-1));
if (MustSaveLR) if (MustSaveLR)
@ -1780,17 +1768,17 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
MFI.CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true); MFI.CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true);
} }
// For 32-bit SVR4, allocate the nonvolatile CR spill slot iff the // Allocate the nonvolatile CR spill slot iff the function uses CR 2, 3, or 4.
// function uses CR 2, 3, or 4. For 64-bit SVR4 we create a FixedStack // For 64-bit SVR4, and all flavors of AIX we create a FixedStack
// object at the offset of the CR-save slot in the linkage area. The actual // object at the offset of the CR-save slot in the linkage area. The actual
// save and restore of the condition register will be created as part of the // save and restore of the condition register will be created as part of the
// prologue and epilogue insertion, but the FixedStack object is needed to // prologue and epilogue insertion, but the FixedStack object is needed to
// keep the CalleSavedInfo valid. // keep the CalleSavedInfo valid.
if (Subtarget.isSVR4ABI() && if ((SavedRegs.test(PPC::CR2) || SavedRegs.test(PPC::CR3) ||
(SavedRegs.test(PPC::CR2) || SavedRegs.test(PPC::CR3) ||
SavedRegs.test(PPC::CR4))) { SavedRegs.test(PPC::CR4))) {
const uint64_t SpillSize = 4; // Condition register is always 4 bytes. const uint64_t SpillSize = 4; // Condition register is always 4 bytes.
const int64_t SpillOffset = Subtarget.isPPC64() ? 8 : -4; const int64_t SpillOffset =
Subtarget.isPPC64() ? 8 : Subtarget.isAIXABI() ? 4 : -4;
int FrameIdx = int FrameIdx =
MFI.CreateFixedObject(SpillSize, SpillOffset, MFI.CreateFixedObject(SpillSize, SpillOffset,
/* IsImmutable */ true, /* IsAliased */ false); /* IsImmutable */ true, /* IsAliased */ false);
@ -2141,11 +2129,6 @@ bool PPCFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
// Currently, this function only handles SVR4 32- and 64-bit ABIs.
// Return false otherwise to maintain pre-existing behavior.
if (!Subtarget.isSVR4ABI())
return false;
MachineFunction *MF = MBB.getParent(); MachineFunction *MF = MBB.getParent();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo(); const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>(); PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
@ -2185,7 +2168,7 @@ bool PPCFrameLowering::spillCalleeSavedRegisters(
// Insert the spill to the stack frame. // Insert the spill to the stack frame.
if (IsCRField) { if (IsCRField) {
PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>(); PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>();
if (Subtarget.isPPC64()) { if (!Subtarget.is32BitELFABI()) {
// The actual spill will happen at the start of the prologue. // The actual spill will happen at the start of the prologue.
FuncInfo->addMustSaveCR(Reg); FuncInfo->addMustSaveCR(Reg);
} else { } else {
@ -2305,12 +2288,6 @@ PPCFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, MachineBasicBlock::iterator MI,
std::vector<CalleeSavedInfo> &CSI, std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const { const TargetRegisterInfo *TRI) const {
// Currently, this function only handles SVR4 32- and 64-bit ABIs.
// Return false otherwise to maintain pre-existing behavior.
if (!Subtarget.isSVR4ABI())
return false;
MachineFunction *MF = MBB.getParent(); MachineFunction *MF = MBB.getParent();
const PPCInstrInfo &TII = *Subtarget.getInstrInfo(); const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>(); PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
@ -2356,7 +2333,7 @@ PPCFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
CR4Spilled = true; CR4Spilled = true;
continue; continue;
} else { } else {
// When we first encounter a non-CR register after seeing at // On 32-bit ELF when we first encounter a non-CR register after seeing at
// least one CR register, restore all spilled CRs together. // least one CR register, restore all spilled CRs together.
if (CR2Spilled || CR3Spilled || CR4Spilled) { if (CR2Spilled || CR3Spilled || CR4Spilled) {
bool is31 = needsFP(*MF); bool is31 = needsFP(*MF);

View File

@ -153,10 +153,6 @@ public:
/// base pointer. /// base pointer.
unsigned getBasePointerSaveOffset() const; unsigned getBasePointerSaveOffset() const;
/// getCRSaveOffset - Return the previous frame offset to save the
/// CR register.
unsigned getCRSaveOffset() const { return CRSaveOffset; }
/// getLinkageSize - Return the size of the PowerPC ABI linkage area. /// getLinkageSize - Return the size of the PowerPC ABI linkage area.
/// ///
unsigned getLinkageSize() const { return LinkageSize; } unsigned getLinkageSize() const { return LinkageSize; }

View File

@ -926,14 +926,15 @@ void PPCRegisterInfo::lowerVRSAVERestore(MachineBasicBlock::iterator II,
bool PPCRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF, bool PPCRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF,
unsigned Reg, int &FrameIdx) const { unsigned Reg, int &FrameIdx) const {
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>(); // For the nonvolatile condition registers (CR2, CR3, CR4) return true to
// For the nonvolatile condition registers (CR2, CR3, CR4) in an SVR4 // prevent allocating an additional frame slot.
// ABI, return true to prevent allocating an additional frame slot. // For 64-bit ELF and AIX, the CR save area is in the linkage area at SP+8,
// For 64-bit, the CR save area is in the linkage area at SP+8; but we have // for 32-bit AIX the CR save area is in the linkage area at SP+4.
// created a FrameIndex to that spill slot to keep the CalleSaveInfos valid. // We have created a FrameIndex to that spill slot to keep the CalleSaveInfos
// For 32-bit, we have previously created the stack slot if needed, so return // valid.
// its FrameIdx. // For 32-bit ELF, we have previously created the stack slot if needed, so
if (Subtarget.isSVR4ABI() && PPC::CR2 <= Reg && Reg <= PPC::CR4) { // return its FrameIdx.
if (PPC::CR2 <= Reg && Reg <= PPC::CR4) {
FrameIdx = MF.getInfo<PPCFunctionInfo>()->getCRSpillFrameIndex(); FrameIdx = MF.getInfo<PPCFunctionInfo>()->getCRSpillFrameIndex();
return true; return true;
} }

View File

@ -0,0 +1,81 @@
; RUN: llc -mtriple=powerpc64-unknown-aix-xcoff -mcpu=pwr4 --mattr=-altivec \
; RUN: --verify-machineinstrs < %s | FileCheck --check-prefix=64BIT %s
; RUN: llc -mtriple=powerpc-unknown-aix-xcoff -mcpu=pwr4 --mattr=-altivec \
; RUN: --verify-machineinstrs < %s | FileCheck --check-prefix=32BIT %s
define dso_local signext i32 @killOne(i32 signext %i) {
entry:
tail call void asm sideeffect "# Clobber CR", "~{cr4}"()
%call = call signext i32 @do_something(i32 %i)
ret i32 %call
}
define dso_local signext i32 @killAll(i32 signext %i) {
entry:
tail call void asm sideeffect "# Clobber CR", "~{cr0},~{cr1},~{cr2},~{cr3},~{cr4},~{cr5},~{cr6},~{cr7}" ()
%call = call signext i32 @do_something(i32 %i)
ret i32 %call
}
declare signext i32 @do_something(i32 signext)
; 64BIT-LABEL: .killOne:
; 64BIT: mflr 0
; 64BIT-NEXT: std 0, 16(1)
; 64BIT-NEXT: mfcr 12
; 64BIT-NEXT: stw 12, 8(1)
; 64BIT: stdu 1, -112(1)
; 64BIT: # Clobber CR
; 64BIT: bl .do_something
; 64BIT: addi 1, 1, 112
; 64BIT-NEXT: ld 0, 16(1)
; 64BIT-NEXT: lwz 12, 8(1)
; 64BIT-NEXT: mtlr 0
; 64BIT-NEXT: mtocrf 8, 12
; 64BIT: blr
; 32BIT-LABEL: .killOne:
; 32BIT: mflr 0
; 32BIT-NEXT: stw 0, 8(1)
; 32BIT-NEXT: mfcr 12
; 32BIT-NEXT: stw 12, 4(1)
; 32BIT: stwu 1, -64(1)
; 32BIT: # Clobber CR
; 32BIT: bl .do_something
; 32BIT: addi 1, 1, 64
; 32BIT-NEXT: lwz 0, 8(1)
; 32BIT-NEXT: lwz 12, 4(1)
; 32BIT-NEXT: mtlr 0
; 32BIT-NEXT: mtocrf 8, 12
; 32BIT: blr
; 64BIT-LABEL: .killAll:
; 64BIT: addi 1, 1, 112
; 64BIT-NEXT: ld 0, 16(1)
; 64BIT-NEXT: lwz 12, 8(1)
; 64BIT-NEXT: mtlr 0
; 64BIT-NEXT: mtocrf 32, 12
; 64BIT-NEXT: mtocrf 16, 12
; 64BIT-NEXT: mtocrf 8, 12
; 64BIT-NEXT: blr
; 32BIT-LABEL: .killAll:
; 32BIT: addi 1, 1, 64
; 32BIT-NEXT: lwz 0, 8(1)
; 32BIT-NEXT: lwz 12, 4(1)
; 32BIT-NEXT: mtlr 0
; 32BIT-NEXT: mtocrf 32, 12
; 32BIT-NEXT: mtocrf 16, 12
; 32BIT-NEXT: mtocrf 8, 12
; 32BIT-NEXT: blr

View File

@ -0,0 +1,66 @@
# RUN: llc -mtriple powerpc-unknown-aix-xcoff -x mir -mcpu=pwr4 \
# RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \
# RUN: FileCheck %s --check-prefixes=CHECK
---
name: CRMultiSave
alignment: 16
tracksRegLiveness: true
liveins:
- { reg: '$r3', virtual-reg: '' }
body: |
bb.0.entry:
liveins: $r3
renamable $r29 = ANDI_rec killed renamable $r3, 1, implicit-def dead $cr0, implicit-def $cr0gt
renamable $cr2lt = COPY $cr0gt
renamable $cr4lt = COPY $cr0gt
renamable $r3 = COPY $r29
BLR implicit $lr, implicit $rm, implicit $r3
; CHECK-LABEL: fixedStack:
; CHECK: - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: default,
; CHECK-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '$cr4',
; CHECK-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-LABEL: stack:
; CHECK: bb.0.entry:
; CHECK-NEXT: liveins: $r3, $r29, $cr2, $cr4
; CHECK: $r12 = MFCR implicit killed $cr2, implicit killed $cr4
; CHECK-NEXT: STW killed $r12, 4, $r1
; CHECK: $r12 = LWZ 4, $r1
; CHECK-NEXT: $cr2 = MTOCRF $r12
; CHECK-NEXT: $cr4 = MTOCRF killed $r12
...
---
name: CR3Save
alignment: 16
tracksRegLiveness: true
liveins:
- { reg: '$r3', virtual-reg: '' }
body: |
bb.0.entry:
liveins: $r3
renamable $r14 = ANDI_rec killed renamable $r3, 1, implicit-def dead $cr0, implicit-def $cr0gt
renamable $cr3lt = COPY $cr0gt
renamable $r3 = COPY $r14
BLR implicit $lr, implicit $rm, implicit $r3
; CHECK-LABEL: fixedStack:
; CHECK: - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: default,
; CHECK-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '$cr3',
; CHECK-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-LABEL: stack:
; CHECK: bb.0.entry:
; CHECK-NEXT: liveins: $r3, $r14, $cr3
; CHECK: $r12 = MFCR implicit killed $cr3
; CHECK-NEXT: STW killed $r12, 4, $r1
; CHECK: $r12 = LWZ 4, $r1
; CHECK-NEXT: $cr3 = MTOCRF killed $r12

View File

@ -0,0 +1,136 @@
; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu --verify-machineinstrs \
; RUN: -stop-after=prologepilog < %s | FileCheck \
; RUN: --check-prefixes=CHECK,CHECK64,ELFV2 %s
; RUN: llc -mtriple=powerpc64-unknown-aix-xcoff -mcpu=pwr4 \
; RUN: --verify-machineinstrs --mattr=-altivec -stop-after=prologepilog < %s | \
; RUN: FileCheck --check-prefixes=CHECK,CHECK64,V1ANDAIX %s
; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 --verify-machineinstrs \
; RUN: -stop-after=prologepilog < %s | FileCheck \
; RUN: --check-prefixes=CHECK,CHECK64,V1ANDAIX %s
; RUN: llc -mtriple=powerpc-unknown-aix-xcoff -mcpu=pwr4 \
; RUN: --verify-machineinstrs --mattr=-altivec -stop-after=prologepilog < %s | \
; RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s
define dso_local signext i32 @test(i32 signext %n) {
entry:
%conv = sext i32 %n to i64
%0 = alloca double, i64 %conv, align 16
tail call void asm sideeffect "", "~{cr2}"()
%call = call signext i32 @do_something(double* nonnull %0)
ret i32 %call
}
declare signext i32 @do_something(double*)
; CHECK: name: test
; CHECK: alignment: 16
; CHECK: liveins:
; CHECK64: - { reg: '$x3', virtual-reg: '' }
; CHECK32: - { reg: '$r3', virtual-reg: '' }
; ELFV2: stackSize: 48
; V1ANDAIX: stackSize: 128
; CHECK32: stackSize: 80
; ELFV2: maxCallFrameSize: 32
; V1ANDAIX: maxCallFrameSize: 112
; CHECK32: maxCallFrameSize: 64
; CHECK64: fixedStack:
; CHECK64-NEXT: - { id: 0, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; CHECK64-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '$cr2',
; CHECK64-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK64-NEXT: debug-info-location: '' }
; CHECK64-NEXT: - { id: 1, type: default, offset: -8, size: 8, alignment: 8, stack-id: default,
; CHECK64-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
; CHECK64-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK64-NEXT: stack:
; CHECK64-NEXT: - { id: 0, name: '<unnamed alloca>', type: variable-sized, offset: -8,
; CHECK64-NEXT: alignment: 1, stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK64-NEXT: local-offset: 0, debug-info-variable: '', debug-info-expression: '',
; CHECK64-NEXT: debug-info-location: '' }
; CHECK64-NEXT: - { id: 1, name: '', type: default, offset: -16, size: 8, alignment: 8,
; CHECK64-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK64-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK32: fixedStack:
; CHECK32-NEXT: - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: default,
; CHECK32-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '$cr2',
; CHECK32-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK32-NEXT: debug-info-location: '' }
; CHECK32-NEXT: - { id: 1, type: default, offset: -4, size: 4, alignment: 4, stack-id: default,
; CHECK32-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
; CHECK32-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK32-NEXT: stack:
; CHECK32-NEXT: - { id: 0, name: '<unnamed alloca>', type: variable-sized, offset: -4,
; CHECK32-NEXT: alignment: 1, stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK32-NEXT: local-offset: 0, debug-info-variable: '', debug-info-expression: '',
; CHECK32-NEXT: debug-info-location: '' }
; CHECK32-NEXT: - { id: 1, name: '', type: default, offset: -8, size: 4, alignment: 4,
; CHECK32-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK32-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK64: bb.0.entry:
; CHECK64-NEXT: liveins: $x3, $cr2
; Prologue:
; CHECK64: $x0 = MFLR8 implicit $lr8
; ELFV2-NEXT: $x12 = MFOCRF8 killed $cr2
; V1ANDAIX-NEXT: $x12 = MFCR8 implicit killed $cr2
; CHECK64-DAG: STD $x31, -8, $x1
; CHECK64-DAG: STD killed $x0, 16, $x1
; CHECK64-DAG: STW8 killed $x12, 8, $x1
; ELFV2-NEXT: $x1 = STDU $x1, -48, $x1
; V1ANDAIX-NEXT: x1 = STDU $x1, -128, $x1
; CHECK64: $x31 = OR8 $x1, $x1
; ELFV2: $[[ORIGSP:x[0-9]+]] = ADDI8 $x31, 48
; V1ANDAIX: $[[ORIGSP:x[0-9]+]] = ADDI8 $x31, 128
; CHECK64: $x1 = STDUX killed $[[ORIGSP]], $x1, killed $x{{[0-9]}}
; CHECK64: INLINEASM {{.*}} early-clobber $cr2
; CHECK64: BL8_NOP
; Epilogue:
; CHECK64: $x1 = LD 0, $x1
; CHECK64-DAG: $x0 = LD 16, $x1
; CHECK64-DAG: $x12 = LWZ8 8, $x1
; CHECK64-DAG: $x31 = LD -8, $x1
; CHECK64: $cr2 = MTOCRF8 killed $x12
; CHECK64-NEXT: MTLR8 $x0, implicit-def $lr8
; CHECK64-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3
; CHECK32: bb.0.entry:
; CHECK32-NEXT: liveins: $r3, $cr2
; Prologue:
; CHECK32: $r0 = MFLR implicit $lr
; CHECK32-NEXT: $r12 = MFCR implicit killed $cr2
; CHECK32-DAG: STW $r31, -4, $r1
; CHECK32-DAG: STW killed $r0, 8, $r1
; CHECK32-DAG: STW killed $r12, 4, $r1
; CHECK32: $r1 = STWU $r1, -80, $r1
; CHECK32: $r31 = OR $r1, $r1
; CHECK32: $[[ORIGSP:r[0-9]+]] = ADDI $r31, 80
; CHECK32: $r1 = STWUX killed $[[ORIGSP]], $r1, killed $r{{[0-9]}}
; CHECK32: INLINEASM {{.*}} early-clobber $cr2
; CHECK32: BL_NOP
; Epilogue:
; CHECK32: $r1 = LWZ 0, $r1
; CHECK32-DAG: $r0 = LWZ 8, $r1
; CHECK32-DAG: $r12 = LWZ 4, $r1
; CHECK32-DAG: $r31 = LWZ -4, $r1
; CHECK32: $cr2 = MTOCRF killed $r12
; CHECK32-NEXT: MTLR $r0, implicit-def $lr
; CHECK32-NEXT: BLR implicit $lr, implicit $rm, implicit $r3

View File

@ -1,66 +0,0 @@
; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu --verify-machineinstrs \
; RUN: -stop-after=prologepilog < %s | FileCheck %s
define dso_local signext i32 @test(i32 signext %n) {
entry:
%conv = sext i32 %n to i64
%0 = alloca double, i64 %conv, align 16
tail call void asm sideeffect "", "~{cr2}"()
%call = call signext i32 @do_something(double* nonnull %0)
ret i32 %call
}
declare signext i32 @do_something(double*)
; CHECK: name: test
; CHECK: alignment: 16
; CHECK: liveins:
; CHECK: - { reg: '$x3', virtual-reg: '' }
; CHECK: stackSize: 48
; CHECK: maxCallFrameSize: 32
; CHECK: fixedStack:
; CHECK-NEXT: - { id: 0, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; CHECK-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '$cr2',
; CHECK-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-NEXT: - { id: 1, type: default, offset: -8, size: 8, alignment: 8, stack-id: default,
; CHECK-NEXT: isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true,
; CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK-NEXT: stack:
; CHECK-NEXT: - { id: 0, name: '<unnamed alloca>', type: variable-sized, offset: -8,
; CHECK-NEXT: alignment: 1, stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK-NEXT: local-offset: 0, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-NEXT: - { id: 1, name: '', type: default, offset: -16, size: 8, alignment: 8,
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
; CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
; CHECK: bb.0.entry:
; CHECK-NEXT: liveins: $x3, $cr2
; Prologue:
; CHECK: $x0 = MFLR8 implicit $lr8
; CHECK-NEXT: $x12 = MFOCRF8 killed $cr2
; CHECK-DAG: STD $x31, -8, $x1
; CHECK-DAG: STD killed $x0, 16, $x1
; CHECK-DAG: STW8 killed $x12, 8, $x1
; CHECK-NEXT: $x1 = STDU $x1, -48, $x1
; CHECK: $x31 = OR8 $x1, $x1
; CHECK: $[[ORIGSP:x[0-9]+]] = ADDI8 $x31, 48
; CHECK: $x1 = STDUX killed $[[ORIGSP]], $x1, killed $x{{[0-9]}}
; CHECK: INLINEASM {{.*}} early-clobber $cr2
; CHECK: BL8_NOP @do_something
; Epilogue:
; CHECK: $x1 = LD 0, $x1
; CHECK-DAG: $x0 = LD 16, $x1
; CHECK-DAG: $x12 = LWZ8 8, $x1
; CHECK-DAG: $x31 = LD -8, $x1
; CHECK: $cr2 = MTOCRF8 killed $x12
; CHECK-NEXT: MTLR8 $x0, implicit-def $lr8
; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3

View File

@ -1,10 +1,18 @@
# RUN: llc -mtriple powerpc64le-unknown-linux-gnu -x mir -mcpu=pwr8 \ # RUN: llc -mtriple powerpc64le-unknown-linux-gnu -x mir -mcpu=pwr8 \
# RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \ # RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \
# RUN: FileCheck %s --check-prefixes=CHECK,PWR8 # RUN: FileCheck %s --check-prefixes=CHECK,SAVEONE,ELF
# RUN: llc -mtriple powerpc64-unknown-linux-gnu -x mir -mcpu=pwr7 \ # RUN: llc -mtriple powerpc64-unknown-linux-gnu -x mir -mcpu=pwr7 \
# RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \ # RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \
# RUN: FileCheck %s --check-prefixes=CHECK,PWR7 # RUN: FileCheck %s --check-prefixes=CHECK,SAVEALL,ELF
# RUN: llc -mtriple powerpc64-unknown-aix-xcoff -x mir -mcpu=pwr4 \
# RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \
# RUN: FileCheck %s --check-prefixes=CHECK,SAVEALL
# TODO FIXME: We only check the save and restores of the callee saved gpr for
# ELF becuase AIX callee saved registers haven't been properly implemented yet.
--- ---
name: CRAllSave name: CRAllSave
@ -21,19 +29,26 @@ body: |
renamable $x3 = COPY $x29 renamable $x3 = COPY $x29
BLR8 implicit $lr8, implicit $rm, implicit $x3 BLR8 implicit $lr8, implicit $rm, implicit $x3
; CHECK-LABEL: fixedStack:
; ELF: - { id: 1, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; AIX: - { id: 0, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; CHECK: isImmutable: true, isAliased: false, callee-saved-register: '$cr4',
; CHECK-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-LABEL: stack:
; Verify the proper live-ins have been added in the prologue. ; Verify the proper live-ins have been added in the prologue.
; CHECK: liveins: $x3, $x29, $cr2, $cr4 ; CHECK: liveins: $x3, $x29, $cr2, $cr4
; CHECK: $x12 = MFCR8 implicit killed $cr2, implicit killed $cr4 ; CHECK: $x12 = MFCR8 implicit killed $cr2, implicit killed $cr4
; CHECK-DAG: STD killed $x29, -24, $x1 :: (store 8 into %fixed-stack.0) ; ELF-DAG: STD killed $x29, -24, $x1 :: (store 8 into %fixed-stack.0)
; CHECK-DAG: STW8 killed $x12, 8, $x1 ; CHECK-DAG: STW8 killed $x12, 8, $x1
; CHECK: $x29 = LD -24, $x1 :: (load 8 from %fixed-stack.0) ; ELF: $x29 = LD -24, $x1 :: (load 8 from %fixed-stack.0)
; CHECK: $x12 = LWZ8 8, $x1 ; CHECK: $x12 = LWZ8 8, $x1
; CHECK: $cr2 = MTOCRF8 $x12 ; CHECK: $cr2 = MTOCRF8 $x12
; CHECK: $cr4 = MTOCRF8 killed $x12 ; CHECK: $cr4 = MTOCRF8 killed $x12
... ...
--- ---
name: CR2Save name: CR2Save
@ -49,17 +64,28 @@ body: |
renamable $x3 = COPY $x14 renamable $x3 = COPY $x14
BLR8 implicit $lr8, implicit $rm, implicit $x3 BLR8 implicit $lr8, implicit $rm, implicit $x3
; CHECK: CR2Save ; CHECK-LABEL: CR2Save
; CHECK-LABEL: fixedStack:
; ELF: - { id: 1, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; AIX: - { id: 0, type: default, offset: 8, size: 4, alignment: 8, stack-id: default,
; CHECK: isImmutable: true, isAliased: false, callee-saved-register: '$cr2',
; CHECK-NEXT: callee-saved-restored: true, debug-info-variable: '', debug-info-expression: '',
; CHECK-NEXT: debug-info-location: '' }
; CHECK-LABEL: stack:
; Verify the proper live-ins have been added in the prologue. ; Verify the proper live-ins have been added in the prologue.
; CHECK: liveins: $x3, $x14, $cr2 ; CHECK: liveins: $x3, $x14, $cr2
; PWR8: $x12 = MFOCRF8 killed $cr2 ; ELF V2 ABI allows saving only the clobbered cr fields,
; PWR7: $x12 = MFCR8 implicit killed $cr2 ; whereas the other ABIs do not.
; SAVEONE: $x12 = MFOCRF8 killed $cr2
; SAVEALL: $x12 = MFCR8 implicit killed $cr2
; CHECK-DAG: STD killed $x14, -144, $x1 :: (store 8 into %fixed-stack.0, align 16) ; ELF-DAG: STD killed $x14, -144, $x1 :: (store 8 into %fixed-stack.0, align 16)
; CHECK-DAG: STW8 killed $x12, 8, $x1 ; CHECK-DAG: STW8 killed $x12, 8, $x1
; CHECK: $x14 = LD -144, $x1 :: (load 8 from %fixed-stack.0, align 16) ; ELF: $x14 = LD -144, $x1 :: (load 8 from %fixed-stack.0, align 16)
; CHECK: $x12 = LWZ8 8, $x1 ; CHECK: $x12 = LWZ8 8, $x1
; CHECK: $cr2 = MTOCRF8 killed $x12 ; CHECK: $cr2 = MTOCRF8 killed $x12