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

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 24 08:26:01 PST 2020


Author: Sean Fertile
Date: 2020-02-24T11:24:46-05:00
New Revision: 8efc2f5723b0892d0518bdac441c674b7d850ac6

URL: https://github.com/llvm/llvm-project/commit/8efc2f5723b0892d0518bdac441c674b7d850ac6
DIFF: https://github.com/llvm/llvm-project/commit/8efc2f5723b0892d0518bdac441c674b7d850ac6.diff

LOG: [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

Added: 
    llvm/test/CodeGen/PowerPC/aix-crspill.ll
    llvm/test/CodeGen/PowerPC/aix32-crsave.mir
    llvm/test/CodeGen/PowerPC/alloca-crspill.ll

Modified: 
    llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
    llvm/lib/Target/PowerPC/PPCFrameLowering.h
    llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
    llvm/test/CodeGen/PowerPC/ppc64-crsave.mir

Removed: 
    llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll


################################################################################
diff  --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index de79752541dd..02503faaafad 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -79,9 +79,8 @@ static unsigned computeBasePointerSaveOffset(const PPCSubtarget &STI) {
              : 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 @@ PPCFrameLowering::PPCFrameLowering(const PPCSubtarget &STI)
       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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
   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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
                                                             : 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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
   // 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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
     }
   }
 
-  // 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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
       .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 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
         // 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 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
                                                    : 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 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
   // 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 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
   }
 
   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 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
   }
 
   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 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
     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 @@ bool PPCFrameLowering::spillCalleeSavedRegisters(
     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
     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();
   const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
   PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
@@ -2185,7 +2168,7 @@ bool PPCFrameLowering::spillCalleeSavedRegisters(
     // Insert the spill to the stack frame.
     if (IsCRField) {
       PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>();
-      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 @@ PPCFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         std::vector<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();
   const PPCInstrInfo &TII = *Subtarget.getInstrInfo();
   PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
@@ -2356,7 +2333,7 @@ PPCFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
       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/PPCFrameLowering.h b/llvm/lib/Target/PowerPC/PPCFrameLowering.h
index ecddcedf58b3..573f3256edbc 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.h
@@ -153,10 +153,6 @@ class PPCFrameLowering: public TargetFrameLowering {
   /// 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/PPCRegisterInfo.cpp b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
index f0c070c89d0f..caa9d7b6b869 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -926,14 +926,15 @@ void PPCRegisterInfo::lowerVRSAVERestore(MachineBasicBlock::iterator II,
 
 bool PPCRegisterInfo::hasReservedSpillSlot(const MachineFunction &MF,
                                            unsigned Reg, int &FrameIdx) const {
-  const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
-  // 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<PPCFunctionInfo>()->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
index 000000000000..af41620e7507
--- /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
index 000000000000..5a82bff33e97
--- /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
index 000000000000..f52e305fb05c
--- /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: '<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

diff  --git a/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll b/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll
deleted file mode 100644
index e2df5b4c0cda..000000000000
--- 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: '<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
-

diff  --git a/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir b/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir
index 6ddaca01eb59..b6a8748c8e3e 100644
--- 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 @@ body:             |
     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 @@ body:             |
     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
 


        


More information about the llvm-commits mailing list