Index: lib/Target/SystemZ/SystemZFrameLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZFrameLowering.cpp +++ lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -354,6 +354,15 @@ uint64_t StackSize = getAllocatedStackSize(MF); if (StackSize) { + // Determine if we want to store a backchain. + bool StoreBackchain = MF.getFunction()->hasFnAttribute("backchain"); + + // If we need backchain, save current stack pointer. R1 is free at this + // point. + if (StoreBackchain) + BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::LGR)) + .addReg(SystemZ::R1D).addReg(SystemZ::R15D); + // Allocate StackSize bytes. int64_t Delta = -int64_t(StackSize); emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII); @@ -364,6 +373,10 @@ BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); SPOffsetFromCFA += Delta; + + if (StoreBackchain) + BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG)) + .addReg(SystemZ::R1D).addReg(SystemZ::R15D).addImm(0).addReg(0); } if (HasFP) { Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2835,8 +2835,9 @@ SDValue SystemZTargetLowering:: lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { const TargetFrameLowering *TFI = Subtarget.getFrameLowering(); - bool RealignOpt = !DAG.getMachineFunction().getFunction()-> - hasFnAttribute("no-realign-stack"); + MachineFunction &MF = DAG.getMachineFunction(); + bool RealignOpt = !MF.getFunction()-> hasFnAttribute("no-realign-stack"); + bool StoreBackchain = MF.getFunction()->hasFnAttribute("backchain"); SDValue Chain = Op.getOperand(0); SDValue Size = Op.getOperand(1); @@ -2858,6 +2859,12 @@ // Get a reference to the stack pointer. SDValue OldSP = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i64); + // If we need a backchain, save it now. + SDValue Backchain; + if (StoreBackchain) + Backchain = DAG.getLoad(MVT::i64, DL, Chain, OldSP, MachinePointerInfo(), + false, false, false, 0); + // Add extra space for alignment if needed. if (ExtraAlignSpace) NeededSpace = DAG.getNode(ISD::ADD, DL, MVT::i64, NeededSpace, @@ -2885,6 +2892,10 @@ DAG.getConstant(~(RequiredAlign - 1), DL, MVT::i64)); } + if (StoreBackchain) + Chain = DAG.getStore(Chain, DL, Backchain, NewSP, MachinePointerInfo(), + false, false, 0); + SDValue Ops[2] = { Result, Chain }; return DAG.getMergeValues(Ops, DL); } @@ -3336,8 +3347,26 @@ SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); MF.getInfo()->setManipulatesSP(true); - return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), - SystemZ::R15D, Op.getOperand(1)); + bool StoreBackchain = MF.getFunction()->hasFnAttribute("backchain"); + + SDValue Chain = Op.getOperand(0); + SDValue NewSP = Op.getOperand(1); + SDValue Backchain; + SDLoc DL(Op); + + if (StoreBackchain) { + SDValue OldSP = DAG.getCopyFromReg(Chain, DL, SystemZ::R15D, MVT::i64); + Backchain = DAG.getLoad(MVT::i64, DL, Chain, OldSP, MachinePointerInfo(), + false, false, false, 0); + } + + Chain = DAG.getCopyToReg(Chain, DL, SystemZ::R15D, NewSP); + + if (StoreBackchain) + Chain = DAG.getStore(Chain, DL, Backchain, NewSP, MachinePointerInfo(), + false, false, 0); + + return Chain; } SDValue SystemZTargetLowering::lowerPREFETCH(SDValue Op, Index: test/CodeGen/SystemZ/backchain.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/backchain.ll @@ -0,0 +1,84 @@ +; Test the backchain attribute. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +declare i8 *@llvm.stacksave() +declare void @llvm.stackrestore(i8 *) +declare void @g() + +; nothing should happen if no stack frame is needed. +define void @f1() "backchain" { +; CHECK-LABEL: f1: +; CHECK-NOT: stg + ret void +} + +; check that backchain is saved if we call someone +define void @f2() "backchain" { +; CHECK-LABEL: f2: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK: lgr %r1, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r1, 0(%r15) + call void @g() + call void @g() + ret void +} + +; check that backchain is saved if we have an alloca +define void @f3() "backchain" { +; CHECK-LABEL: f3: +; CHECK-NOT: stmg +; CHECK: lgr %r1, %r15 +; CHECK: aghi %r15, -168 +; CHECK: stg %r1, 0(%r15) + %ign = alloca i8, i32 4 + ret void +} + +; check that alloca copies the backchain +define void @f4(i32 %len) "backchain" { +; CHECK-LABEL: f4: +; CHECK: stmg %r11, %r15, 88(%r15) +; CHECK: lgr %r1, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r1, 0(%r15) +; CHECK: lgr %r11, %r15 +; CHECK: lg [[BC:%r[0-9]+]], 0(%r15) +; CHECK: lgr [[NEWSP:%r[0-9]+]], %r15 +; CHECK: lgr %r15, [[NEWSP]] +; CHECK: stg [[BC]], 0([[NEWSP]]) + %ign = alloca i8, i32 %len + ret void +} + +; check that llvm.stackrestore restores the backchain +define void @f5(i32 %count1, i32 %count2) "backchain" { +; CHECK-LABEL: f5: +; CHECK: stmg %r11, %r15, 88(%r15) +; CHECK: lgr %r1, %r15 +; CHECK: aghi %r15, -160 +; CHECK: stg %r1, 0(%r15) +; CHECK: lgr %r11, %r15 +; CHECK: lgr [[SAVESP:%r[0-9]+]], %r15 +; CHECK: lg [[BC:%r[0-9]+]], 0(%r15) +; CHECK: lgr [[NEWSP:%r[0-9]+]], %r15 +; CHECK: lgr %r15, [[NEWSP]] +; CHECK: stg [[BC]], 0([[NEWSP]]) +; CHECK: lg [[BC2:%r[0-9]+]], 0(%r15) +; CHECK: lgr %r15, [[SAVESP]] +; CHECK: stg [[BC2]], 0([[SAVESP]]) +; CHECK: lg [[BC3:%r[0-9]+]], 0(%r15) +; CHECK: lgr [[NEWSP2:%r[0-9]+]], %r15 +; CHECK: lgr %r15, [[NEWSP2]] +; CHECK: stg [[BC3]], 0([[NEWSP2]]) +; CHECK: lmg %r11, %r15, 248(%r11) +; CHECK: br %r14 + %src = call i8 *@llvm.stacksave() + %array1 = alloca i8, i32 %count1 + store volatile i8 0, i8 *%array1 + call void @llvm.stackrestore(i8 *%src) + %array2 = alloca i8, i32 %count2 + store volatile i8 0, i8 *%array2 + ret void +}