Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2002,21 +2002,21 @@ options::OPT_mno_backchain, false); bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, options::OPT_mno_packed_stack, false); - if (HasBackchain && HasPackedStack) { + systemz::FloatABI FloatABI = + systemz::getSystemZFloatABI(getToolChain().getDriver(), Args); + bool HasSoftFloat = (FloatABI == systemz::FloatABI::Soft); + if (HasBackchain && HasPackedStack && !HasSoftFloat) { const Driver &D = getToolChain().getDriver(); D.Diag(diag::err_drv_unsupported_opt) << Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) + - " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args); + " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args) + + " " + "-mhard-float"; } if (HasBackchain) CmdArgs.push_back("-mbackchain"); if (HasPackedStack) CmdArgs.push_back("-mpacked-stack"); - - systemz::FloatABI FloatABI = - systemz::getSystemZFloatABI(getToolChain().getDriver(), Args); - - if (FloatABI == systemz::FloatABI::Soft) { + if (HasSoftFloat) { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); Index: clang/test/Driver/mbackchain.c =================================================================== --- clang/test/Driver/mbackchain.c +++ clang/test/Driver/mbackchain.c @@ -1,3 +1,6 @@ // RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain 2>&1 | FileCheck %s +// RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain -msoft-float \ +// RUN: 2>&1 | FileCheck %s --check-prefix=KERNEL-BUILD -// CHECK: error: unsupported option '-mpacked-stack -mbackchain' +// CHECK: error: unsupported option '-mpacked-stack -mbackchain -mhard-float' +// KERNEL-BUILD-NOT: error: unsupported option Index: llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp +++ llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -64,14 +64,12 @@ static bool usePackedStack(MachineFunction &MF) { bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); - bool IsVarArg = MF.getFunction().isVarArg(); - bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC; bool BackChain = MF.getFunction().hasFnAttribute("backchain"); - bool FramAddressTaken = MF.getFrameInfo().isFrameAddressTaken(); - if (HasPackedStackAttr && BackChain) - report_fatal_error("packed-stack with backchain is currently unsupported."); - return HasPackedStackAttr && !IsVarArg && CallConv && !BackChain && - !FramAddressTaken; + bool SoftFloat = MF.getSubtarget().hasSoftFloat(); + if (HasPackedStackAttr && BackChain && !SoftFloat) + report_fatal_error("packed-stack + backchain + hard-float is unsupported."); + bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC; + return HasPackedStackAttr && CallConv; } bool SystemZFrameLowering:: @@ -88,7 +86,8 @@ unsigned HighGPR = SystemZ::R15D; int StartSPOffset = SystemZMC::CallFrameSize; int CurrOffset; - if (!usePackedStack(MF)) { + // Save the registers on the normal slots in case of VarArg with packed-stack. + if (!usePackedStack(MF) || IsVarArg) { for (auto &CS : CSI) { unsigned Reg = CS.getReg(); int Offset = RegSpillOffsets[Reg]; @@ -125,12 +124,14 @@ CurrOffset = -SystemZMC::CallFrameSize; } else { // Packed stack: put all the GPRs at the top of the Register save area. + unsigned FirstGPRDistance = + MF.getFunction().hasFnAttribute("backchain") ? -8 : 0; uint32_t LowGR64Num = UINT32_MAX; for (auto &CS : CSI) { unsigned Reg = CS.getReg(); if (SystemZ::GR64BitRegClass.contains(Reg)) { unsigned GR64Num = SystemZMC::getFirstReg(Reg); - int Offset = -8 * (15 - GR64Num + 1); + int Offset = FirstGPRDistance - 8 * (15 - GR64Num + 1); if (LowGR64Num > GR64Num) { LowGR64Num = GR64Num; StartSPOffset = SystemZMC::CallFrameSize + Offset; @@ -511,10 +512,13 @@ .addCFIIndex(CFIIndex); SPOffsetFromCFA += Delta; - if (StoreBackchain) + if (StoreBackchain) { + // The back chain is stored topmost with packed-stack. + int Offset = usePackedStack(MF) ? 152 : 0; BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG)) - .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D).addImm(0) - .addReg(0); + .addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D) + .addImm(Offset).addReg(0); + } } if (HasFP) { @@ -668,7 +672,9 @@ int FI = ZFI->getFramePointerSaveIndex(); if (!FI) { MachineFrameInfo &MFFrame = MF.getFrameInfo(); - FI = MFFrame.CreateFixedObject(8, -SystemZMC::CallFrameSize, false); + // The back chain is stored topmost with packed-stack. + int Offset = usePackedStack(MF) ? -8 : -SystemZMC::CallFrameSize; + FI = MFFrame.CreateFixedObject(8, Offset, false); ZFI->setFramePointerSaveIndex(FI); } return FI; Index: llvm/lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -3249,6 +3249,12 @@ unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); EVT PtrVT = getPointerTy(DAG.getDataLayout()); + // Return null if the back chain is not present. + bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); + bool HasBackChain = MF.getFunction().hasFnAttribute("backchain"); + if (HasPackedStackAttr && !HasBackChain) + return DAG.getConstant(0, DL, PtrVT); + // By definition, the frame address is the address of the back chain. auto *TFL = static_cast(Subtarget.getFrameLowering()); Index: llvm/test/CodeGen/SystemZ/frame-23.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/frame-23.ll @@ -0,0 +1,61 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; +; Test possible combinations of backchain and packed-stack. + +attributes #0 = { nounwind "backchain" "packed-stack" "use-soft-float"="true" } +define i64 @fun0(i64 %a) #0 { +; CHECK-LABEL: fun0: +; CHECK: stmg %r14, %r15, 136(%r15) +; CHECK-NEXT: lgr %r1, %r15 +; CHECK-NEXT: aghi %r15, -24 +; CHECK-NEXT: stg %r1, 152(%r15) +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r14, %r15, 160(%r15) +; CHECK-NEXT: br %r14 +entry: + %call = call i64 @foo(i64 %a) + ret i64 %call +} + +attributes #1 = { nounwind "backchain" } +define i64 @fun1(i64 %a) #1 { +; CHECK-LABEL: fun1: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: lgr %r1, %r15 +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: stg %r1, 0(%r15) +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r14, %r15, 272(%r15) +; CHECK-NEXT: br %r14 +entry: + %call = call i64 @foo(i64 %a) + ret i64 %call +} + +attributes #2 = { nounwind "packed-stack" } +define i64 @fun2(i64 %a) #2 { +; CHECK-LABEL: fun2: +; CHECK: stmg %r14, %r15, 144(%r15) +; CHECK-NEXT: aghi %r15, -16 +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r14, %r15, 160(%r15) +; CHECK-NEXT: br %r14 +entry: + %call = call i64 @foo(i64 %a) + ret i64 %call +} + +attributes #3 = { nounwind } +define i64 @fun3(i64 %a) #3 { +; CHECK-LABEL: fun3: +; CHECK: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r14, %r15, 272(%r15) +; CHECK-NEXT: br %r14 +entry: + %call = call i64 @foo(i64 %a) + ret i64 %call +} + +declare i64 @foo(i64) Index: llvm/test/CodeGen/SystemZ/frame-24.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/frame-24.ll @@ -0,0 +1,38 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; +; Test that vararg registers are saved in the default positions with +; packed-stack. + +attributes #0 = {nounwind "packed-stack"="true" } +define void @fun0(...) #0 { +; CHECK-LABEL: fun0: +; CHECK: stmg %r2, %r15, 16(%r15) +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: std %f0, 288(%r15) +; CHECK-NEXT: std %f2, 296(%r15) +; CHECK-NEXT: std %f4, 304(%r15) +; CHECK-NEXT: std %f6, 312(%r15) +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r6, %r15, 208(%r15) +; CHECK-NEXT: br %r14 + %call = call i64 @foo() + ret void +} + +; Test that the backchain is saved as expected in a vararg function with +; packed-stack. +attributes #1 = { nounwind "backchain" "packed-stack" "use-soft-float"="true" } +define void @fun1(...) #1 { +; CHECK-LABEL: fun1: +; CHECK: stmg %r2, %r15, 16(%r15) +; CHECK-NEXT: lgr %r1, %r15 +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: stg %r1, 152(%r15) +; CHECK-NEXT: brasl %r14, foo@PLT +; CHECK-NEXT: lmg %r6, %r15, 208(%r15) +; CHECK-NEXT: br %r14 + %call = call i64 @foo() + ret void +} + +declare i64 @foo() Index: llvm/test/CodeGen/SystemZ/frameaddr-02.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/frameaddr-02.ll @@ -0,0 +1,54 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Test lowering of @llvm.frameaddress with packed-stack. + +; With back chain +attributes #0 = { nounwind "packed-stack" "backchain" "use-soft-float"="true" } +define i8* @fp0() #0 { +entry: +; CHECK-LABEL: fp0: +; CHECK: la %r2, 152(%r15) +; CHECK-NEXT: br %r14 + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 +} + +define i8* @fp0f() #0 { +entry: +; CHECK-LABEL: fp0f: +; CHECK: lgr %r1, %r15 +; CHECK-NEXT: aghi %r15, -16 +; CHECK-NEXT: stg %r1, 152(%r15) +; CHECK-NEXT: la %r2, 168(%r15) +; CHECK-NEXT: aghi %r15, 16 +; CHECK-NEXT: br %r14 + %0 = alloca i64, align 8 + %1 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %1 +} + +; Without back chain + +attributes #1 = { nounwind "packed-stack" } +define i8* @fp1() #1 { +entry: +; CHECK-LABEL: fp1: +; CHECK: lghi %r2, 0 +; CHECK-NEXT: br %r14 + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 +} + +define i8* @fp1f() #1 { +entry: +; CHECK-LABEL: fp1f: +; CHECK: aghi %r15, -8 +; CHECK-NEXT: lghi %r2, 0 +; CHECK-NEXT: aghi %r15, 8 +; CHECK-NEXT: br %r14 + %0 = alloca i64, align 8 + %1 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %1 +} + +declare i8* @llvm.frameaddress(i32) nounwind readnone