diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2007,21 +2007,19 @@ 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); + << "-mpacked-stack -mbackchain -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"); diff --git a/clang/test/Driver/mbackchain.c b/clang/test/Driver/mbackchain.c --- a/clang/test/Driver/mbackchain.c +++ b/clang/test/Driver/mbackchain.c @@ -1,3 +1,7 @@ // 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 +// REQUIRES: systemz-registered-target -// CHECK: error: unsupported option '-mpacked-stack -mbackchain' +// CHECK: error: unsupported option '-mpacked-stack -mbackchain -mhard-float' +// KERNEL-BUILD-NOT: error: unsupported option diff --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.h b/llvm/lib/Target/SystemZ/SystemZFrameLowering.h --- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.h @@ -52,13 +52,14 @@ MachineBasicBlock::iterator MI) const override; // Return the byte offset from the incoming stack pointer of Reg's - // ABI-defined save slot. Return 0 if no slot is defined for Reg. - unsigned getRegSpillOffset(unsigned Reg) const { - return RegSpillOffsets[Reg]; - } + // ABI-defined save slot. Return 0 if no slot is defined for Reg. Adjust + // the offset in case MF has packed-stack. + unsigned getRegSpillOffset(MachineFunction &MF, unsigned Reg) const; // Get or create the frame index of where the old frame pointer is stored. int getOrCreateFramePointerSaveIndex(MachineFunction &MF) const; + + bool usePackedStack(MachineFunction &MF) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp --- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -62,18 +62,6 @@ RegSpillOffsets[SpillOffsetTable[I].Reg] = SpillOffsetTable[I].Offset; } -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 SystemZFrameLowering:: assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, @@ -87,71 +75,44 @@ unsigned LowGPR = 0; 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); - } + for (auto &CS : CSI) { + unsigned Reg = CS.getReg(); + int Offset = getRegSpillOffset(MF, 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); + } - // 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 = getRegSpillOffset(MF, Reg); + 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); // Create fixed stack objects for the remaining registers. + int CurrOffset = -SystemZMC::CallFrameSize; + if (usePackedStack(MF)) + CurrOffset += StartSPOffset; + for (auto &CS : CSI) { if (CS.getFrameIdx() != INT32_MAX) continue; @@ -511,10 +472,13 @@ .addCFIIndex(CFIIndex); SPOffsetFromCFA += Delta; - if (StoreBackchain) + if (StoreBackchain) { + // The back chain is stored topmost with packed-stack. + int Offset = usePackedStack(MF) ? SystemZMC::CallFrameSize - 8 : 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) { @@ -662,14 +626,43 @@ } } +unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF, + unsigned Reg) const { + bool IsVarArg = MF.getFunction().isVarArg(); + bool BackChain = MF.getFunction().hasFnAttribute("backchain"); + bool SoftFloat = MF.getSubtarget().hasSoftFloat(); + unsigned Offset = RegSpillOffsets[Reg]; + if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) { + if (SystemZ::GR64BitRegClass.contains(Reg)) + // Put all GPRs at the top of the Register save area with packed + // stack. Make room for the backchain if needed. + Offset += BackChain ? 24 : 32; + else + Offset = 0; + } + return Offset; +} + int SystemZFrameLowering:: getOrCreateFramePointerSaveIndex(MachineFunction &MF) const { SystemZMachineFunctionInfo *ZFI = MF.getInfo(); 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; } + +bool SystemZFrameLowering::usePackedStack(MachineFunction &MF) const { + bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack"); + bool BackChain = MF.getFunction().hasFnAttribute("backchain"); + 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; +} diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1464,7 +1464,8 @@ // ...and a similar frame index for the caller-allocated save area // that will be used to store the incoming registers. - int64_t RegSaveOffset = -SystemZMC::CallFrameSize; + int64_t RegSaveOffset = + -SystemZMC::CallFrameSize + TFL->getRegSpillOffset(MF, SystemZ::R2D) - 16; unsigned RegSaveIndex = MFI.CreateFixedObject(1, RegSaveOffset, true); FuncInfo->setRegSaveFrameIndex(RegSaveIndex); @@ -1473,8 +1474,9 @@ if (NumFixedFPRs < SystemZ::NumArgFPRs && !useSoftFloat()) { SDValue MemOps[SystemZ::NumArgFPRs]; for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) { - unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]); - int FI = MFI.CreateFixedObject(8, RegSaveOffset + Offset, true); + unsigned Offset = TFL->getRegSpillOffset(MF, SystemZ::ArgFPRs[I]); + int FI = + MFI.CreateFixedObject(8, -SystemZMC::CallFrameSize + Offset, true); SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); unsigned VReg = MF.addLiveIn(SystemZ::ArgFPRs[I], &SystemZ::FP64BitRegClass); @@ -3241,6 +3243,8 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { + auto *TFL = + static_cast(Subtarget.getFrameLowering()); MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); MFI.setFrameAddressIsTaken(true); @@ -3249,9 +3253,12 @@ unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); EVT PtrVT = getPointerTy(DAG.getDataLayout()); + // Return null if the back chain is not present. + bool HasBackChain = MF.getFunction().hasFnAttribute("backchain"); + if (TFL->usePackedStack(MF) && !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()); int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF); SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT); diff --git a/llvm/test/CodeGen/SystemZ/frame-23.ll b/llvm/test/CodeGen/SystemZ/frame-23.ll new file mode 100644 --- /dev/null +++ b/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) diff --git a/llvm/test/CodeGen/SystemZ/frame-24.ll b/llvm/test/CodeGen/SystemZ/frame-24.ll new file mode 100644 --- /dev/null +++ b/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 +} + diff --git a/llvm/test/CodeGen/SystemZ/frameaddr-02.ll b/llvm/test/CodeGen/SystemZ/frameaddr-02.ll new file mode 100644 --- /dev/null +++ b/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