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 @@ -1800,11 +1800,19 @@ } // For 32-bit SVR4, allocate the nonvolatile CR spill slot iff the - // function uses CR 2, 3, or 4. - if (Subtarget.is32BitELFABI() && + // function uses CR 2, 3, or 4. For 64-bit SVR4 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) || SavedRegs.test(PPC::CR4))) { - int FrameIdx = MFI.CreateFixedObject((uint64_t)4, (int64_t)-4, true); + const uint64_t SpillSize = 4; // Condition register is always 4 bytes. + const int64_t SpillOffset = Subtarget.isPPC64() ? 8 : -4; + int FrameIdx = + MFI.CreateFixedObject(SpillSize, SpillOffset, + /* IsImmutable */ true, /* IsAliased */ false); FI->setCRSpillFrameIndex(FrameIdx); } } 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 @@ -929,16 +929,12 @@ 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 at SP+8; the value of FrameIdx = 0 - // is arbitrary and will be subsequently ignored. For 32-bit, we have - // previously created the stack slot if needed, so return its FrameIdx. + // 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) { - if (TM.isPPC64()) - FrameIdx = 0; - else { - const PPCFunctionInfo *FI = MF.getInfo(); - FrameIdx = FI->getCRSpillFrameIndex(); - } + FrameIdx = MF.getInfo()->getCRSpillFrameIndex(); return true; } return false; diff --git a/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll b/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ppc64-alloca-crspill.ll @@ -0,0 +1,66 @@ +; 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 new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ppc64-crsave.mir @@ -0,0 +1,68 @@ +# 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: llc -mtriple powerpc64-unknown-linux-gnu -x mir -mcpu=pwr7 \ +# RUN: -run-pass=prologepilog --verify-machineinstrs < %s | \ +# RUN: FileCheck %s --check-prefixes=CHECK,PWR7 + +--- +name: CRAllSave +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$x3', virtual-reg: '' } +body: | + bb.0.entry: + liveins: $x3 + renamable $x29 = ANDI8_rec killed renamable $x3, 1, implicit-def dead $cr0, implicit-def $cr0gt + renamable $cr2lt = COPY $cr0gt + renamable $cr4lt = COPY $cr0gt + renamable $x3 = COPY $x29 + BLR8 implicit $lr8, implicit $rm, implicit $x3 + + ; 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) + ; CHECK-DAG: STW8 killed $x12, 8, $x1 + + ; CHECK: $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 +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$x3', virtual-reg: '' } +body: | + bb.0.entry: + liveins: $x3 + renamable $x14 = ANDI8_rec killed renamable $x3, 1, implicit-def dead $cr0, implicit-def $cr0gt + renamable $cr2lt = COPY $cr0gt + renamable $x3 = COPY $x14 + BLR8 implicit $lr8, implicit $rm, implicit $x3 + + ; CHECK: CR2Save + ; 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 + + ; CHECK-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) + ; CHECK: $x12 = LWZ8 8, $x1 + ; CHECK: $cr2 = MTOCRF8 killed $x12 + + +... +