Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2007,21 +2007,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:: @@ -81,6 +79,8 @@ SystemZMachineFunctionInfo *ZFI = MF.getInfo(); MachineFrameInfo &MFFrame = MF.getFrameInfo(); bool IsVarArg = MF.getFunction().isVarArg(); + bool BackChain = MF.getFunction().hasFnAttribute("backchain"); + bool SoftFloat = MF.getSubtarget().hasSoftFloat(); if (CSI.empty()) return true; // Early exit if no callee saved registers are modified! @@ -88,68 +88,55 @@ unsigned HighGPR = SystemZ::R15D; int StartSPOffset = SystemZMC::CallFrameSize; int CurrOffset; - if (!usePackedStack(MF)) { - for (auto &CS : CSI) { - unsigned Reg = CS.getReg(); - int Offset = RegSpillOffsets[Reg]; - if (Offset) { - if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) { - LowGPR = Reg; - StartSPOffset = Offset; - } - Offset -= SystemZMC::CallFrameSize; - int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset); - CS.setFrameIdx(FrameIdx); - } else - CS.setFrameIdx(INT32_MAX); + int PackGPRsAdjust = 0; + if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) { + // Put all GPRs at the top of the Register save area with packed + // stack. Make room for the backchain if needed. + PackGPRsAdjust = BackChain ? 24 : 32; + } + + for (auto &CS : CSI) { + unsigned Reg = CS.getReg(); + int Offset = RegSpillOffsets[Reg]; + if (usePackedStack(MF)) { + if (SystemZ::GR64BitRegClass.contains(Reg)) + Offset += PackGPRsAdjust; + else + Offset = 0; } + if (Offset) { + if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) { + LowGPR = Reg; + StartSPOffset = Offset; + } + Offset -= SystemZMC::CallFrameSize; + int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset); + CS.setFrameIdx(FrameIdx); + } else + CS.setFrameIdx(INT32_MAX); + } - // Save the range of call-saved registers, for use by the - // prologue/epilogue inserters. - ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset); - if (IsVarArg) { - // Also save the GPR varargs, if any. R6D is call-saved, so would - // already be included, but we also need to handle the call-clobbered - // argument registers. - unsigned FirstGPR = ZFI->getVarArgsFirstGPR(); - if (FirstGPR < SystemZ::NumArgGPRs) { - unsigned Reg = SystemZ::ArgGPRs[FirstGPR]; - int Offset = RegSpillOffsets[Reg]; - if (StartSPOffset > Offset) { - LowGPR = Reg; StartSPOffset = Offset; - } + // Save the range of call-saved registers, for use by the + // prologue/epilogue inserters. + ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset); + if (IsVarArg) { + // Also save the GPR varargs, if any. R6D is call-saved, so would + // already be included, but we also need to handle the call-clobbered + // argument registers. + unsigned FirstGPR = ZFI->getVarArgsFirstGPR(); + if (FirstGPR < SystemZ::NumArgGPRs) { + unsigned Reg = SystemZ::ArgGPRs[FirstGPR]; + int Offset = RegSpillOffsets[Reg] + PackGPRsAdjust; + if (StartSPOffset > Offset) { + LowGPR = Reg; StartSPOffset = Offset; } } - ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset); - - CurrOffset = -SystemZMC::CallFrameSize; - } else { - // Packed stack: put all the GPRs at the top of the Register save area. - 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); - if (LowGR64Num > GR64Num) { - LowGR64Num = GR64Num; - StartSPOffset = SystemZMC::CallFrameSize + Offset; - } - int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset); - CS.setFrameIdx(FrameIdx); - } else - CS.setFrameIdx(INT32_MAX); - } - if (LowGR64Num < UINT32_MAX) - LowGPR = SystemZMC::GR64Regs[LowGR64Num]; - - // Save the range of call-saved registers, for use by the - // prologue/epilogue inserters. - ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset); - ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset); - - CurrOffset = LowGPR ? -(SystemZMC::CallFrameSize - StartSPOffset) : 0; } + ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset); + + CurrOffset = !usePackedStack(MF) + ? -SystemZMC::CallFrameSize + : -(SystemZMC::CallFrameSize - StartSPOffset); // Create fixed stack objects for the remaining registers. for (auto &CS : CSI) { @@ -511,10 +498,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 +658,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 @@ -1464,7 +1464,13 @@ // ...and a similar frame index for the caller-allocated save area // that will be used to store the incoming registers. + bool PackedStack = MF.getFunction().hasFnAttribute("packed-stack"); + bool BackChain = MF.getFunction().hasFnAttribute("backchain"); + bool SoftFloat = MF.getSubtarget().hasSoftFloat(); int64_t RegSaveOffset = -SystemZMC::CallFrameSize; + if (PackedStack && SoftFloat) + RegSaveOffset += (BackChain ? 24 : 32); + unsigned RegSaveIndex = MFI.CreateFixedObject(1, RegSaveOffset, true); FuncInfo->setRegSaveFrameIndex(RegSaveIndex); @@ -3249,6 +3255,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,20 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; +; Test backchain with packed-stack, which requires soft-float. + +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 +} + +declare i64 @foo(i64) Index: llvm/test/CodeGen/SystemZ/frame-24.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/frame-24.ll @@ -0,0 +1,72 @@ +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; +; Test saving of vararg registers and backchain with packed stack. + +%struct.__va_list_tag = type { i64, i64, i8*, i8* } +declare void @llvm.va_start(i8*) + +attributes #0 = { nounwind "packed-stack"="true" } +define void @fun0(i64 %g0, double %d0, i64 %n, ...) #0 { +; CHECK-LABEL: fun0: +; CHECK: stmg %r4, %r15, 32(%r15) +; CHECK-NEXT: aghi %r15, -192 +; CHECK-NEXT: std %f2, 328(%r15) +; CHECK-NEXT: std %f4, 336(%r15) +; CHECK-NEXT: std %f6, 344(%r15) +; CHECK-NEXT: la %r0, 352(%r15) +; CHECK-NEXT: stg %r0, 176(%r15) +; CHECK-NEXT: la %r0, 192(%r15) +; CHECK-NEXT: stg %r0, 184(%r15) +; CHECK-NEXT: mvghi 160(%r15), 2 +; CHECK-NEXT: mvghi 168(%r15), 1 +; CHECK-NEXT: lmg %r6, %r15, 240(%r15) +; CHECK-NEXT: br %r14 +entry: + %vl = alloca [1 x %struct.__va_list_tag], align 8 + %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8* + call void @llvm.va_start(i8* nonnull %0) + ret void +} + +attributes #1 = { nounwind "packed-stack"="true" "use-soft-float"="true" } +define void @fun1(i64 %g0, double %d0, i64 %n, ...) #1 { +; CHECK-LABEL: fun1: +; CHECK: stmg %r5, %r15, 72(%r15) +; CHECK-NEXT: aghi %r15, -160 +; CHECK-NEXT: la %r0, 192(%r15) +; CHECK-NEXT: stg %r0, 184(%r15) +; CHECK-NEXT: la %r0, 320(%r15) +; CHECK-NEXT: stg %r0, 176(%r15) +; CHECK-NEXT: mvghi 168(%r15), 0 +; CHECK-NEXT: mvghi 160(%r15), 3 +; CHECK-NEXT: lmg %r6, %r15, 240(%r15) +; CHECK-NEXT: br %r14 +entry: + %vl = alloca [1 x %struct.__va_list_tag], align 8 + %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8* + call void @llvm.va_start(i8* nonnull %0) + ret void +} + +attributes #2 = { nounwind "packed-stack"="true" "use-soft-float"="true" "backchain"} +define void @fun2(i64 %g0, double %d0, i64 %n, ...) #2 { +; CHECK-LABEL: fun2: +; CHECK: stmg %r5, %r15, 64(%r15) +; CHECK-NEXT: lgr %r1, %r15 +; CHECK-NEXT: aghi %r15, -168 +; CHECK-NEXT: stg %r1, 152(%r15) +; CHECK-NEXT: la %r0, 192(%r15) +; CHECK-NEXT: stg %r0, 184(%r15) +; CHECK-NEXT: la %r0, 328(%r15) +; CHECK-NEXT: stg %r0, 176(%r15) +; CHECK-NEXT: mvghi 168(%r15), 0 +; CHECK-NEXT: mvghi 160(%r15), 3 +; CHECK-NEXT: lmg %r6, %r15, 240(%r15) +; CHECK-NEXT: br %r14 +entry: + %vl = alloca [1 x %struct.__va_list_tag], align 8 + %0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8* + call void @llvm.va_start(i8* nonnull %0) + ret void +} + 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