Skip to content

Commit 82879c2

Browse files
committed
[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
1 parent e9997cf commit 82879c2

File tree

8 files changed

+242
-93
lines changed

8 files changed

+242
-93
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,21 +2007,19 @@ void Clang::AddSystemZTargetArgs(const ArgList &Args,
20072007
options::OPT_mno_backchain, false);
20082008
bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack,
20092009
options::OPT_mno_packed_stack, false);
2010-
if (HasBackchain && HasPackedStack) {
2010+
systemz::FloatABI FloatABI =
2011+
systemz::getSystemZFloatABI(getToolChain().getDriver(), Args);
2012+
bool HasSoftFloat = (FloatABI == systemz::FloatABI::Soft);
2013+
if (HasBackchain && HasPackedStack && !HasSoftFloat) {
20112014
const Driver &D = getToolChain().getDriver();
20122015
D.Diag(diag::err_drv_unsupported_opt)
2013-
<< Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) +
2014-
" " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args);
2016+
<< "-mpacked-stack -mbackchain -mhard-float";
20152017
}
20162018
if (HasBackchain)
20172019
CmdArgs.push_back("-mbackchain");
20182020
if (HasPackedStack)
20192021
CmdArgs.push_back("-mpacked-stack");
2020-
2021-
systemz::FloatABI FloatABI =
2022-
systemz::getSystemZFloatABI(getToolChain().getDriver(), Args);
2023-
2024-
if (FloatABI == systemz::FloatABI::Soft) {
2022+
if (HasSoftFloat) {
20252023
// Floating point operations and argument passing are soft.
20262024
CmdArgs.push_back("-msoft-float");
20272025
CmdArgs.push_back("-mfloat-abi");

clang/test/Driver/mbackchain.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
// RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain 2>&1 | FileCheck %s
2+
// RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain -msoft-float \
3+
// RUN: 2>&1 | FileCheck %s --check-prefix=KERNEL-BUILD
4+
// REQUIRES: systemz-registered-target
25

3-
// CHECK: error: unsupported option '-mpacked-stack -mbackchain'
6+
// CHECK: error: unsupported option '-mpacked-stack -mbackchain -mhard-float'
7+
// KERNEL-BUILD-NOT: error: unsupported option

llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp

Lines changed: 68 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,6 @@ SystemZFrameLowering::SystemZFrameLowering()
6262
RegSpillOffsets[SpillOffsetTable[I].Reg] = SpillOffsetTable[I].Offset;
6363
}
6464

65-
static bool usePackedStack(MachineFunction &MF) {
66-
bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack");
67-
bool IsVarArg = MF.getFunction().isVarArg();
68-
bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC;
69-
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
70-
bool FramAddressTaken = MF.getFrameInfo().isFrameAddressTaken();
71-
if (HasPackedStackAttr && BackChain)
72-
report_fatal_error("packed-stack with backchain is currently unsupported.");
73-
return HasPackedStackAttr && !IsVarArg && CallConv && !BackChain &&
74-
!FramAddressTaken;
75-
}
76-
7765
bool SystemZFrameLowering::
7866
assignCalleeSavedSpillSlots(MachineFunction &MF,
7967
const TargetRegisterInfo *TRI,
@@ -87,71 +75,44 @@ assignCalleeSavedSpillSlots(MachineFunction &MF,
8775
unsigned LowGPR = 0;
8876
unsigned HighGPR = SystemZ::R15D;
8977
int StartSPOffset = SystemZMC::CallFrameSize;
90-
int CurrOffset;
91-
if (!usePackedStack(MF)) {
92-
for (auto &CS : CSI) {
93-
unsigned Reg = CS.getReg();
94-
int Offset = RegSpillOffsets[Reg];
95-
if (Offset) {
96-
if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) {
97-
LowGPR = Reg;
98-
StartSPOffset = Offset;
99-
}
100-
Offset -= SystemZMC::CallFrameSize;
101-
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
102-
CS.setFrameIdx(FrameIdx);
103-
} else
104-
CS.setFrameIdx(INT32_MAX);
105-
}
78+
for (auto &CS : CSI) {
79+
unsigned Reg = CS.getReg();
80+
int Offset = getRegSpillOffset(MF, Reg);
81+
if (Offset) {
82+
if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) {
83+
LowGPR = Reg;
84+
StartSPOffset = Offset;
85+
}
86+
Offset -= SystemZMC::CallFrameSize;
87+
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
88+
CS.setFrameIdx(FrameIdx);
89+
} else
90+
CS.setFrameIdx(INT32_MAX);
91+
}
10692

107-
// Save the range of call-saved registers, for use by the
108-
// prologue/epilogue inserters.
109-
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
110-
if (IsVarArg) {
111-
// Also save the GPR varargs, if any. R6D is call-saved, so would
112-
// already be included, but we also need to handle the call-clobbered
113-
// argument registers.
114-
unsigned FirstGPR = ZFI->getVarArgsFirstGPR();
115-
if (FirstGPR < SystemZ::NumArgGPRs) {
116-
unsigned Reg = SystemZ::ArgGPRs[FirstGPR];
117-
int Offset = RegSpillOffsets[Reg];
118-
if (StartSPOffset > Offset) {
119-
LowGPR = Reg; StartSPOffset = Offset;
120-
}
93+
// Save the range of call-saved registers, for use by the
94+
// prologue/epilogue inserters.
95+
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
96+
if (IsVarArg) {
97+
// Also save the GPR varargs, if any. R6D is call-saved, so would
98+
// already be included, but we also need to handle the call-clobbered
99+
// argument registers.
100+
unsigned FirstGPR = ZFI->getVarArgsFirstGPR();
101+
if (FirstGPR < SystemZ::NumArgGPRs) {
102+
unsigned Reg = SystemZ::ArgGPRs[FirstGPR];
103+
int Offset = getRegSpillOffset(MF, Reg);
104+
if (StartSPOffset > Offset) {
105+
LowGPR = Reg; StartSPOffset = Offset;
121106
}
122107
}
123-
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
124-
125-
CurrOffset = -SystemZMC::CallFrameSize;
126-
} else {
127-
// Packed stack: put all the GPRs at the top of the Register save area.
128-
uint32_t LowGR64Num = UINT32_MAX;
129-
for (auto &CS : CSI) {
130-
unsigned Reg = CS.getReg();
131-
if (SystemZ::GR64BitRegClass.contains(Reg)) {
132-
unsigned GR64Num = SystemZMC::getFirstReg(Reg);
133-
int Offset = -8 * (15 - GR64Num + 1);
134-
if (LowGR64Num > GR64Num) {
135-
LowGR64Num = GR64Num;
136-
StartSPOffset = SystemZMC::CallFrameSize + Offset;
137-
}
138-
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
139-
CS.setFrameIdx(FrameIdx);
140-
} else
141-
CS.setFrameIdx(INT32_MAX);
142-
}
143-
if (LowGR64Num < UINT32_MAX)
144-
LowGPR = SystemZMC::GR64Regs[LowGR64Num];
145-
146-
// Save the range of call-saved registers, for use by the
147-
// prologue/epilogue inserters.
148-
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
149-
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
150-
151-
CurrOffset = LowGPR ? -(SystemZMC::CallFrameSize - StartSPOffset) : 0;
152108
}
109+
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
153110

154111
// Create fixed stack objects for the remaining registers.
112+
int CurrOffset = -SystemZMC::CallFrameSize;
113+
if (usePackedStack(MF))
114+
CurrOffset += StartSPOffset;
115+
155116
for (auto &CS : CSI) {
156117
if (CS.getFrameIdx() != INT32_MAX)
157118
continue;
@@ -511,10 +472,13 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
511472
.addCFIIndex(CFIIndex);
512473
SPOffsetFromCFA += Delta;
513474

514-
if (StoreBackchain)
475+
if (StoreBackchain) {
476+
// The back chain is stored topmost with packed-stack.
477+
int Offset = usePackedStack(MF) ? SystemZMC::CallFrameSize - 8 : 0;
515478
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG))
516-
.addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D).addImm(0)
517-
.addReg(0);
479+
.addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D)
480+
.addImm(Offset).addReg(0);
481+
}
518482
}
519483

520484
if (HasFP) {
@@ -662,14 +626,43 @@ eliminateCallFramePseudoInstr(MachineFunction &MF,
662626
}
663627
}
664628

629+
unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF,
630+
unsigned Reg) const {
631+
bool IsVarArg = MF.getFunction().isVarArg();
632+
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
633+
bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat();
634+
unsigned Offset = RegSpillOffsets[Reg];
635+
if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) {
636+
if (SystemZ::GR64BitRegClass.contains(Reg))
637+
// Put all GPRs at the top of the Register save area with packed
638+
// stack. Make room for the backchain if needed.
639+
Offset += BackChain ? 24 : 32;
640+
else
641+
Offset = 0;
642+
}
643+
return Offset;
644+
}
645+
665646
int SystemZFrameLowering::
666647
getOrCreateFramePointerSaveIndex(MachineFunction &MF) const {
667648
SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
668649
int FI = ZFI->getFramePointerSaveIndex();
669650
if (!FI) {
670651
MachineFrameInfo &MFFrame = MF.getFrameInfo();
671-
FI = MFFrame.CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
652+
// The back chain is stored topmost with packed-stack.
653+
int Offset = usePackedStack(MF) ? -8 : -SystemZMC::CallFrameSize;
654+
FI = MFFrame.CreateFixedObject(8, Offset, false);
672655
ZFI->setFramePointerSaveIndex(FI);
673656
}
674657
return FI;
675658
}
659+
660+
bool SystemZFrameLowering::usePackedStack(MachineFunction &MF) const {
661+
bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack");
662+
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
663+
bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat();
664+
if (HasPackedStackAttr && BackChain && !SoftFloat)
665+
report_fatal_error("packed-stack + backchain + hard-float is unsupported.");
666+
bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC;
667+
return HasPackedStackAttr && CallConv;
668+
}

llvm/lib/Target/SystemZ/SystemZFrameLowering.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ class SystemZFrameLowering : public TargetFrameLowering {
5252
MachineBasicBlock::iterator MI) const override;
5353

5454
// Return the byte offset from the incoming stack pointer of Reg's
55-
// ABI-defined save slot. Return 0 if no slot is defined for Reg.
56-
unsigned getRegSpillOffset(unsigned Reg) const {
57-
return RegSpillOffsets[Reg];
58-
}
55+
// ABI-defined save slot. Return 0 if no slot is defined for Reg. Adjust
56+
// the offset in case MF has packed-stack.
57+
unsigned getRegSpillOffset(MachineFunction &MF, unsigned Reg) const;
5958

6059
// Get or create the frame index of where the old frame pointer is stored.
6160
int getOrCreateFramePointerSaveIndex(MachineFunction &MF) const;
61+
62+
bool usePackedStack(MachineFunction &MF) const;
6263
};
6364
} // end namespace llvm
6465

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,8 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
14641464

14651465
// ...and a similar frame index for the caller-allocated save area
14661466
// that will be used to store the incoming registers.
1467-
int64_t RegSaveOffset = -SystemZMC::CallFrameSize;
1467+
int64_t RegSaveOffset =
1468+
-SystemZMC::CallFrameSize + TFL->getRegSpillOffset(MF, SystemZ::R2D) - 16;
14681469
unsigned RegSaveIndex = MFI.CreateFixedObject(1, RegSaveOffset, true);
14691470
FuncInfo->setRegSaveFrameIndex(RegSaveIndex);
14701471

@@ -1473,8 +1474,9 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
14731474
if (NumFixedFPRs < SystemZ::NumArgFPRs && !useSoftFloat()) {
14741475
SDValue MemOps[SystemZ::NumArgFPRs];
14751476
for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) {
1476-
unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]);
1477-
int FI = MFI.CreateFixedObject(8, RegSaveOffset + Offset, true);
1477+
unsigned Offset = TFL->getRegSpillOffset(MF, SystemZ::ArgFPRs[I]);
1478+
int FI =
1479+
MFI.CreateFixedObject(8, -SystemZMC::CallFrameSize + Offset, true);
14781480
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
14791481
unsigned VReg = MF.addLiveIn(SystemZ::ArgFPRs[I],
14801482
&SystemZ::FP64BitRegClass);
@@ -3241,6 +3243,8 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
32413243

32423244
SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
32433245
SelectionDAG &DAG) const {
3246+
auto *TFL =
3247+
static_cast<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
32443248
MachineFunction &MF = DAG.getMachineFunction();
32453249
MachineFrameInfo &MFI = MF.getFrameInfo();
32463250
MFI.setFrameAddressIsTaken(true);
@@ -3249,9 +3253,12 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
32493253
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
32503254
EVT PtrVT = getPointerTy(DAG.getDataLayout());
32513255

3256+
// Return null if the back chain is not present.
3257+
bool HasBackChain = MF.getFunction().hasFnAttribute("backchain");
3258+
if (TFL->usePackedStack(MF) && !HasBackChain)
3259+
return DAG.getConstant(0, DL, PtrVT);
3260+
32523261
// By definition, the frame address is the address of the back chain.
3253-
auto *TFL =
3254-
static_cast<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
32553262
int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF);
32563263
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);
32573264

llvm/test/CodeGen/SystemZ/frame-23.ll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
2+
;
3+
; Test backchain with packed-stack, which requires soft-float.
4+
5+
attributes #0 = { nounwind "backchain" "packed-stack" "use-soft-float"="true" }
6+
define i64 @fun0(i64 %a) #0 {
7+
; CHECK-LABEL: fun0:
8+
; CHECK: stmg %r14, %r15, 136(%r15)
9+
; CHECK-NEXT: lgr %r1, %r15
10+
; CHECK-NEXT: aghi %r15, -24
11+
; CHECK-NEXT: stg %r1, 152(%r15)
12+
; CHECK-NEXT: brasl %r14, foo@PLT
13+
; CHECK-NEXT: lmg %r14, %r15, 160(%r15)
14+
; CHECK-NEXT: br %r14
15+
entry:
16+
%call = call i64 @foo(i64 %a)
17+
ret i64 %call
18+
}
19+
20+
declare i64 @foo(i64)

llvm/test/CodeGen/SystemZ/frame-24.ll

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
2+
;
3+
; Test saving of vararg registers and backchain with packed stack.
4+
5+
%struct.__va_list_tag = type { i64, i64, i8*, i8* }
6+
declare void @llvm.va_start(i8*)
7+
8+
attributes #0 = { nounwind "packed-stack"="true" }
9+
define void @fun0(i64 %g0, double %d0, i64 %n, ...) #0 {
10+
; CHECK-LABEL: fun0:
11+
; CHECK: stmg %r4, %r15, 32(%r15)
12+
; CHECK-NEXT: aghi %r15, -192
13+
; CHECK-NEXT: std %f2, 328(%r15)
14+
; CHECK-NEXT: std %f4, 336(%r15)
15+
; CHECK-NEXT: std %f6, 344(%r15)
16+
; CHECK-NEXT: la %r0, 352(%r15)
17+
; CHECK-NEXT: stg %r0, 176(%r15)
18+
; CHECK-NEXT: la %r0, 192(%r15)
19+
; CHECK-NEXT: stg %r0, 184(%r15)
20+
; CHECK-NEXT: mvghi 160(%r15), 2
21+
; CHECK-NEXT: mvghi 168(%r15), 1
22+
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
23+
; CHECK-NEXT: br %r14
24+
entry:
25+
%vl = alloca [1 x %struct.__va_list_tag], align 8
26+
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
27+
call void @llvm.va_start(i8* nonnull %0)
28+
ret void
29+
}
30+
31+
attributes #1 = { nounwind "packed-stack"="true" "use-soft-float"="true" }
32+
define void @fun1(i64 %g0, double %d0, i64 %n, ...) #1 {
33+
; CHECK-LABEL: fun1:
34+
; CHECK: stmg %r5, %r15, 72(%r15)
35+
; CHECK-NEXT: aghi %r15, -160
36+
; CHECK-NEXT: la %r0, 192(%r15)
37+
; CHECK-NEXT: stg %r0, 184(%r15)
38+
; CHECK-NEXT: la %r0, 320(%r15)
39+
; CHECK-NEXT: stg %r0, 176(%r15)
40+
; CHECK-NEXT: mvghi 168(%r15), 0
41+
; CHECK-NEXT: mvghi 160(%r15), 3
42+
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
43+
; CHECK-NEXT: br %r14
44+
entry:
45+
%vl = alloca [1 x %struct.__va_list_tag], align 8
46+
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
47+
call void @llvm.va_start(i8* nonnull %0)
48+
ret void
49+
}
50+
51+
attributes #2 = { nounwind "packed-stack"="true" "use-soft-float"="true" "backchain"}
52+
define void @fun2(i64 %g0, double %d0, i64 %n, ...) #2 {
53+
; CHECK-LABEL: fun2:
54+
; CHECK: stmg %r5, %r15, 64(%r15)
55+
; CHECK-NEXT: lgr %r1, %r15
56+
; CHECK-NEXT: aghi %r15, -168
57+
; CHECK-NEXT: stg %r1, 152(%r15)
58+
; CHECK-NEXT: la %r0, 192(%r15)
59+
; CHECK-NEXT: stg %r0, 184(%r15)
60+
; CHECK-NEXT: la %r0, 328(%r15)
61+
; CHECK-NEXT: stg %r0, 176(%r15)
62+
; CHECK-NEXT: mvghi 168(%r15), 0
63+
; CHECK-NEXT: mvghi 160(%r15), 3
64+
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
65+
; CHECK-NEXT: br %r14
66+
entry:
67+
%vl = alloca [1 x %struct.__va_list_tag], align 8
68+
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
69+
call void @llvm.va_start(i8* nonnull %0)
70+
ret void
71+
}
72+

0 commit comments

Comments
 (0)