diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.h b/llvm/lib/Target/PowerPC/PPCFrameLowering.h --- a/llvm/lib/Target/PowerPC/PPCFrameLowering.h +++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.h @@ -153,10 +153,6 @@ /// base pointer. 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. /// unsigned getLinkageSize() const { return LinkageSize; } diff --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp @@ -79,9 +79,8 @@ : STI.getTargetMachine().isPositionIndependent() ? -12U : -8U; } -static unsigned computeCRSaveOffset() { - // The condition register save offset needs to be updated for AIX PPC32. - return 8; +static unsigned computeCRSaveOffset(const PPCSubtarget &STI) { + return (STI.isAIXABI() && !STI.isPPC64()) ? 4 : 8; } PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI) @@ -92,7 +91,7 @@ FramePointerSaveOffset(computeFramePointerSaveOffset(Subtarget)), LinkageSize(computeLinkageSize(Subtarget)), BasePointerSaveOffset(computeBasePointerSaveOffset(Subtarget)), - CRSaveOffset(computeCRSaveOffset()) {} + CRSaveOffset(computeCRSaveOffset(Subtarget)) {} // With the SVR4 ABI, callee-saved registers have fixed offsets on the stack. const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots( @@ -741,7 +740,8 @@ MachineModuleInfo &MMI = MF.getMMI(); const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); DebugLoc dl; - bool needsCFI = MF.needsFrameMoves(); + // AIX assembler does not support cfi directives. + const bool needsCFI = MF.needsFrameMoves() && !Subtarget.isAIXABI(); // Get processor type. bool isPPC64 = Subtarget.isPPC64(); @@ -812,6 +812,9 @@ : 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); // 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 @@ -873,12 +876,6 @@ // indexed into with a simple STDU/STWU/STD/STW immediate offset operand. 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 // 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. @@ -918,49 +915,42 @@ } } - // 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 - if (MustSaveCR && SingleScratchReg && MustSaveLR) { + // 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 or two CR fields are clobbered, it is more efficient to use - // mfocrf to selectively save just those fields, because mfocrf has short + // 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. - unsigned MfcrOpcode = PPC::MFCR8; - unsigned CrState = RegState::ImplicitKill; - if (isELFv2ABI && MustSaveCRs.size() == 1) { - MfcrOpcode = PPC::MFOCRF8; - CrState = RegState::Kill; + 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); } - 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)) - .addImm(getCRSaveOffset()) - .addReg(SPReg); + }; + + // 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 + 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)) { // will only occur for PPC64 - // 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 (MustSaveCR && !(SingleScratchReg && MustSaveLR)) + BuildMoveFromCR(); if (HasRedZone) { if (HasFP) @@ -987,11 +977,11 @@ .addReg(SPReg); if (MustSaveCR && - !(SingleScratchReg && MustSaveLR)) { // will only occur for PPC64 + !(SingleScratchReg && MustSaveLR)) { 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)) - .addImm(getCRSaveOffset()) + .addImm(CRSaveOffset) .addReg(SPReg); } @@ -1295,7 +1285,7 @@ // actually saved gets its own CFI record. unsigned CRReg = isELFv2ABI? Reg : (unsigned) PPC::CR2; 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)) .addCFIIndex(CFIIndex); continue; @@ -1376,7 +1366,10 @@ : 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); int LROffset = getReturnSaveOffset(); int FPOffset = 0; @@ -1551,20 +1544,17 @@ // value (although not the base register). Make sure it is not overwritten // too early. - assert((isPPC64 || !MustSaveCR) && - "Epilogue CR restoring supported only in 64-bit mode"); - // If we need to restore both the LR and the CR and we only have one // available scratch register, we must do them one at a time. if (MustSaveCR && SingleScratchReg && MustSaveLR) { // Here TempReg == ScratchReg, and in the absence of red zone ScratchReg // is live here. assert(HasRedZone && "Expecting red zone"); - BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg) - .addImm(getCRSaveOffset()) + BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg) + .addImm(CRSaveOffset) .addReg(SPReg); 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)); } @@ -1581,11 +1571,9 @@ } if (MustSaveCR && !(SingleScratchReg && MustSaveLR)) { - // This will only occur for PPC64. - assert(isPPC64 && "Expecting 64-bit mode"); assert(RBReg == SPReg && "Should be using SP as a base register"); - BuildMI(MBB, MBBI, dl, TII.get(PPC::LWZ8), TempReg) - .addImm(getCRSaveOffset()) + BuildMI(MBB, MBBI, dl, LoadWordInst, TempReg) + .addImm(CRSaveOffset) .addReg(RBReg); } @@ -1640,9 +1628,9 @@ } if (MustSaveCR && - !(SingleScratchReg && MustSaveLR)) // will only occur for PPC64 + !(SingleScratchReg && MustSaveLR)) 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)); if (MustSaveLR) @@ -1780,17 +1768,17 @@ MFI.CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true); } - // For 32-bit SVR4, allocate the nonvolatile CR spill slot iff the - // function uses CR 2, 3, or 4. For 64-bit SVR4 we create a FixedStack + // Allocate the nonvolatile CR spill slot iff the function uses CR 2, 3, or 4. + // 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 // 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 // keep the CalleSavedInfo valid. - if (Subtarget.isSVR4ABI() && - (SavedRegs.test(PPC::CR2) || SavedRegs.test(PPC::CR3) || + if ((SavedRegs.test(PPC::CR2) || SavedRegs.test(PPC::CR3) || SavedRegs.test(PPC::CR4))) { 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 = MFI.CreateFixedObject(SpillSize, SpillOffset, /* IsImmutable */ true, /* IsAliased */ false); @@ -2141,11 +2129,6 @@ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef 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(); const PPCInstrInfo &TII = *Subtarget.getInstrInfo(); PPCFunctionInfo *FI = MF->getInfo(); @@ -2185,7 +2168,7 @@ // Insert the spill to the stack frame. if (IsCRField) { PPCFunctionInfo *FuncInfo = MF->getInfo(); - if (Subtarget.isPPC64()) { + if (!Subtarget.is32BitELFABI()) { // The actual spill will happen at the start of the prologue. FuncInfo->addMustSaveCR(Reg); } else { @@ -2305,12 +2288,6 @@ MachineBasicBlock::iterator MI, std::vector &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(); const PPCInstrInfo &TII = *Subtarget.getInstrInfo(); PPCFunctionInfo *FI = MF->getInfo(); @@ -2356,7 +2333,7 @@ CR4Spilled = true; continue; } 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. if (CR2Spilled || CR3Spilled || CR4Spilled) { bool is31 = needsFP(*MF); diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp --- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -926,14 +926,15 @@ bool PPCRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF, unsigned Reg, int &FrameIdx) const { - const PPCSubtarget &Subtarget = MF.getSubtarget(); - // For the nonvolatile condition registers (CR2, CR3, CR4) in an SVR4 - // ABI, return true to prevent allocating an additional frame slot. - // For 64-bit, the CR save area is in the linkage area at SP+8; but we have - // created a FrameIndex to that spill slot to keep the CalleSaveInfos valid. - // For 32-bit, we have previously created the stack slot if needed, so return - // its FrameIdx. - if (Subtarget.isSVR4ABI() && PPC::CR2 <= Reg && Reg <= PPC::CR4) { + // For the nonvolatile condition registers (CR2, CR3, CR4) 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 32-bit AIX the CR save area is in the linkage area at SP+4. + // We have created a FrameIndex to that spill slot to keep the CalleSaveInfos + // valid. + // For 32-bit ELF, we have previously created the stack slot if needed, so + // return its FrameIdx. + if (PPC::CR2 <= Reg && Reg <= PPC::CR4) { FrameIdx = MF.getInfo()->getCRSpillFrameIndex(); return true; } diff --git a/llvm/test/CodeGen/PowerPC/aix-crspill.ll b/llvm/test/CodeGen/PowerPC/aix-crspill.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-crspill.ll @@ -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 diff --git a/llvm/test/CodeGen/PowerPC/aix32-crsave.mir b/llvm/test/CodeGen/PowerPC/aix32-crsave.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix32-crsave.mir @@ -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 diff --git a/llvm/test/CodeGen/PowerPC/alloca-crspill.ll b/llvm/test/CodeGen/PowerPC/alloca-crspill.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/alloca-crspill.ll @@ -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: '', 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: '', 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 diff --git a/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll b/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll deleted file mode 100644 --- a/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll +++ /dev/null @@ -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: '', 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 - diff --git a/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir b/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir --- a/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir +++ b/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir @@ -1,10 +1,18 @@ # RUN: llc -mtriple powerpc64le-unknown-linux-gnu -x mir -mcpu=pwr8 \ # 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: -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 @@ -21,19 +29,26 @@ renamable $x3 = COPY $x29 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. ; CHECK: liveins: $x3, $x29, $cr2, $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: $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: $cr2 = MTOCRF8 $x12 ; CHECK: $cr4 = MTOCRF8 killed $x12 - ... --- name: CR2Save @@ -49,17 +64,28 @@ renamable $x3 = COPY $x14 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. ; CHECK: liveins: $x3, $x14, $cr2 - ; PWR8: $x12 = MFOCRF8 killed $cr2 - ; PWR7: $x12 = MFCR8 implicit killed $cr2 + ; ELF V2 ABI allows saving only the clobbered cr fields, + ; 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: $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: $cr2 = MTOCRF8 killed $x12