[SystemZ] Support the kernel back chain.

In order to build the Linux kernel, the back chain must be supported with
packed-stack. The back chain is then stored topmost in the register save
area.

Review: Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D74506
This commit is contained in:
Jonas Paulsson 2020-02-19 14:54:12 -08:00
parent e9997cfb4d
commit 82879c2913
8 changed files with 244 additions and 95 deletions

View File

@ -2007,21 +2007,19 @@ void Clang::AddSystemZTargetArgs(const ArgList &Args,
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");

View File

@ -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

View File

@ -62,18 +62,6 @@ SystemZFrameLowering::SystemZFrameLowering()
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 @@ assignCalleeSavedSpillSlots(MachineFunction &MF,
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);
}
// 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;
}
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;
}
}
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;
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 = getRegSpillOffset(MF, Reg);
if (StartSPOffset > Offset) {
LowGPR = Reg; StartSPOffset = Offset;
}
}
}
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 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
.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 @@ eliminateCallFramePseudoInstr(MachineFunction &MF,
}
}
unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF,
unsigned Reg) const {
bool IsVarArg = MF.getFunction().isVarArg();
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().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<SystemZMachineFunctionInfo>();
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<SystemZSubtarget>().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;
}

View File

@ -52,13 +52,14 @@ public:
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

View File

@ -1464,7 +1464,8 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
// ...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 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
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::lowerConstantPool(ConstantPoolSDNode *CP,
SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
auto *TFL =
static_cast<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setFrameAddressIsTaken(true);
@ -3249,9 +3253,12 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
unsigned Depth = cast<ConstantSDNode>(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<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF);
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);

View File

@ -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)

View File

@ -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
}

View File

@ -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