Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit affbafe

Browse files
committed
[SystemZ] Support Swift Calling Convention
Summary: Port rL265480, rL264754, rL265997 and rL266252 to SystemZ, in order to enable the Swift port on the architecture. SwiftSelf and SwiftError are assigned to R10 and R9, respectively, which are normally callee-saved registers. For more information, see: RFC: Implementing the Swift calling convention in LLVM and Clang https://groups.google.com/forum/#!topic/llvm-dev/epDd2w93kZ0 Reviewers: kbarton, manmanren, rjmccall, uweigand Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D19414 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267823 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f3fd7df commit affbafe

File tree

7 files changed

+658
-3
lines changed

7 files changed

+658
-3
lines changed

lib/Target/SystemZ/SystemZCallingConv.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ def RetCC_SystemZ : CallingConv<[
3333
// Promote i32 to i64 if it has an explicit extension type.
3434
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
3535

36+
// A SwiftError is returned in R9.
37+
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,
38+
3639
// ABI-compliant code returns 64-bit integers in R2. Make the other
3740
// call-clobbered argument registers available for code that doesn't
3841
// care about the ABI. (R6 is an argument register too, but is
@@ -65,6 +68,12 @@ def CC_SystemZ : CallingConv<[
6568
// are smaller than 64 bits shouldn't.
6669
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
6770

71+
// A SwiftSelf is passed in callee-saved R10.
72+
CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10D]>>>,
73+
74+
// A SwiftError is passed in callee-saved R9.
75+
CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,
76+
6877
// Force long double values to the stack and pass i64 pointers to them.
6978
CCIfType<[f128], CCPassIndirect<i64>>,
7079

@@ -105,3 +114,6 @@ def CC_SystemZ : CallingConv<[
105114
//===----------------------------------------------------------------------===//
106115
def CSR_SystemZ : CalleeSavedRegs<(add (sequence "R%dD", 6, 15),
107116
(sequence "F%dD", 8, 15))>;
117+
118+
// R9 is used to return SwiftError; remove it from CSR.
119+
def CSR_SystemZ_SwiftError : CalleeSavedRegs<(sub CSR_SystemZ, R9D)>;

lib/Target/SystemZ/SystemZISelLowering.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -989,9 +989,11 @@ LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
989989
}
990990

991991
static bool canUseSiblingCall(const CCState &ArgCCInfo,
992-
SmallVectorImpl<CCValAssign> &ArgLocs) {
992+
SmallVectorImpl<CCValAssign> &ArgLocs,
993+
SmallVectorImpl<ISD::OutputArg> &Outs) {
993994
// Punt if there are any indirect or stack arguments, or if the call
994-
// needs the call-saved argument register R6.
995+
// needs the callee-saved argument register R6, or if the call uses
996+
// the callee-saved register arguments SwiftSelf and SwiftError.
995997
for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) {
996998
CCValAssign &VA = ArgLocs[I];
997999
if (VA.getLocInfo() == CCValAssign::Indirect)
@@ -1001,6 +1003,8 @@ static bool canUseSiblingCall(const CCState &ArgCCInfo,
10011003
unsigned Reg = VA.getLocReg();
10021004
if (Reg == SystemZ::R6H || Reg == SystemZ::R6L || Reg == SystemZ::R6D)
10031005
return false;
1006+
if (Outs[I].Flags.isSwiftSelf() || Outs[I].Flags.isSwiftError())
1007+
return false;
10041008
}
10051009
return true;
10061010
}
@@ -1034,7 +1038,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
10341038

10351039
// We don't support GuaranteedTailCallOpt, only automatically-detected
10361040
// sibling calls.
1037-
if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs))
1041+
if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs, Outs))
10381042
IsTailCall = false;
10391043

10401044
// Get a count of how many bytes are to be pushed on the stack.

lib/Target/SystemZ/SystemZISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,10 @@ class SystemZTargetLowering : public TargetLowering {
452452
SelectionDAG &DAG) const override;
453453
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
454454

455+
bool supportSwiftError() const override {
456+
return true;
457+
}
458+
455459
private:
456460
const SystemZSubtarget &Subtarget;
457461

lib/Target/SystemZ/SystemZRegisterInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,20 @@ SystemZRegisterInfo::SystemZRegisterInfo()
2424

2525
const MCPhysReg *
2626
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
27+
if (MF->getSubtarget().getTargetLowering()->supportSwiftError() &&
28+
MF->getFunction()->getAttributes().hasAttrSomewhere(
29+
Attribute::SwiftError))
30+
return CSR_SystemZ_SwiftError_SaveList;
2731
return CSR_SystemZ_SaveList;
2832
}
2933

3034
const uint32_t *
3135
SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
3236
CallingConv::ID CC) const {
37+
if (MF.getSubtarget().getTargetLowering()->supportSwiftError() &&
38+
MF.getFunction()->getAttributes().hasAttrSomewhere(
39+
Attribute::SwiftError))
40+
return CSR_SystemZ_SwiftError_RegMask;
3341
return CSR_SystemZ_RegMask;
3442
}
3543

test/CodeGen/SystemZ/swift-return.ll

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s
2+
; RUN: llc < %s -mtriple=s390x-linux-gnu -O0 -verify-machineinstrs | FileCheck --check-prefix=CHECK-O0 %s
3+
4+
@var = global i32 0
5+
6+
; Test how llvm handles return type of {i16, i8}. The return value will be
7+
; passed in %r2 and %r3.
8+
; CHECK-LABEL: test:
9+
; CHECK: st %r2
10+
; CHECK: brasl %r14, gen
11+
; CHECK-DAG: lhr %r2, %r2
12+
; CHECK-DAG: lbr %[[REG1:r[0-9]+]], %r3
13+
; CHECK: ar %r2, %[[REG1]]
14+
; CHECK-O0-LABEL: test
15+
; CHECK-O0: st %r2
16+
; CHECK-O0: brasl %r14, gen
17+
; CHECK-O0-DAG: lhr %[[REG1:r[0-9]+]], %r2
18+
; CHECK-O0-DAG: lbr %[[REG2:r[0-9]+]], %r3
19+
; CHECK-O0: ar %[[REG1]], %[[REG2]]
20+
; CHECK-O0: lr %r2, %[[REG1]]
21+
define i16 @test(i32 %key) {
22+
entry:
23+
%key.addr = alloca i32, align 4
24+
store i32 %key, i32* %key.addr, align 4
25+
%0 = load i32, i32* %key.addr, align 4
26+
%call = call swiftcc { i16, i8 } @gen(i32 %0)
27+
%v3 = extractvalue { i16, i8 } %call, 0
28+
%v1 = sext i16 %v3 to i32
29+
%v5 = extractvalue { i16, i8 } %call, 1
30+
%v2 = sext i8 %v5 to i32
31+
%add = add nsw i32 %v1, %v2
32+
%conv = trunc i32 %add to i16
33+
ret i16 %conv
34+
}
35+
36+
declare swiftcc { i16, i8 } @gen(i32)
37+
38+
; If we can't pass every return value in registers, we will pass everything
39+
; in memroy. The caller provides space for the return value and passes
40+
; the address in %r2. The first input argument will be in %r3.
41+
; CHECK-LABEL: test2:
42+
; CHECK: lr %[[REG1:r[0-9]+]], %r2
43+
; CHECK-DAG: la %r2, 160(%r15)
44+
; CHECK-DAG: lr %r3, %[[REG1]]
45+
; CHECK: brasl %r14, gen2
46+
; CHECK: l %r2, 160(%r15)
47+
; CHECK: a %r2, 164(%r15)
48+
; CHECK: a %r2, 168(%r15)
49+
; CHECK: a %r2, 172(%r15)
50+
; CHECK: a %r2, 176(%r15)
51+
; CHECK-O0-LABEL: test2:
52+
; CHECK-O0: la %[[REG1:r[0-9]+]], 168(%r15)
53+
; CHECK-O0: st %r2, [[SPILL1:[0-9]+]](%r15)
54+
; CHECK-O0: lgr %r2, %[[REG1]]
55+
; CHECK-O0: l %r3, [[SPILL1]](%r15)
56+
; CHECK-O0: brasl %r14, gen2
57+
; CHECK-O0-DAG: l %r{{.*}}, 184(%r15)
58+
; CHECK-O0-DAG: l %r{{.*}}, 180(%r15)
59+
; CHECK-O0-DAG: l %r{{.*}}, 176(%r15)
60+
; CHECK-O0-DAG: l %r{{.*}}, 172(%r15)
61+
; CHECK-O0-DAG: l %r{{.*}}, 168(%r15)
62+
; CHECK-O0: ar
63+
; CHECK-O0: ar
64+
; CHECK-O0: ar
65+
; CHECK-O0: ar
66+
; CHECK-O0: lr %r2
67+
define i32 @test2(i32 %key) #0 {
68+
entry:
69+
%key.addr = alloca i32, align 4
70+
store i32 %key, i32* %key.addr, align 4
71+
%0 = load i32, i32* %key.addr, align 4
72+
%call = call swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %0)
73+
74+
%v3 = extractvalue { i32, i32, i32, i32, i32 } %call, 0
75+
%v5 = extractvalue { i32, i32, i32, i32, i32 } %call, 1
76+
%v6 = extractvalue { i32, i32, i32, i32, i32 } %call, 2
77+
%v7 = extractvalue { i32, i32, i32, i32, i32 } %call, 3
78+
%v8 = extractvalue { i32, i32, i32, i32, i32 } %call, 4
79+
80+
%add = add nsw i32 %v3, %v5
81+
%add1 = add nsw i32 %add, %v6
82+
%add2 = add nsw i32 %add1, %v7
83+
%add3 = add nsw i32 %add2, %v8
84+
ret i32 %add3
85+
}
86+
87+
; The address of the return value is passed in %r2.
88+
; On return, %r2 will contain the adddress that has been passed in by the caller in %r2.
89+
; CHECK-LABEL: gen2:
90+
; CHECK: st %r3, 16(%r2)
91+
; CHECK: st %r3, 12(%r2)
92+
; CHECK: st %r3, 8(%r2)
93+
; CHECK: st %r3, 4(%r2)
94+
; CHECK: st %r3, 0(%r2)
95+
; CHECK-O0-LABEL: gen2:
96+
; CHECK-O0-DAG: st %r3, 16(%r2)
97+
; CHECK-O0-DAG: st %r3, 12(%r2)
98+
; CHECK-O0-DAG: st %r3, 8(%r2)
99+
; CHECK-O0-DAG: st %r3, 4(%r2)
100+
; CHECK-O0-DAG: st %r3, 0(%r2)
101+
define swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %key) {
102+
%Y = insertvalue { i32, i32, i32, i32, i32 } undef, i32 %key, 0
103+
%Z = insertvalue { i32, i32, i32, i32, i32 } %Y, i32 %key, 1
104+
%Z2 = insertvalue { i32, i32, i32, i32, i32 } %Z, i32 %key, 2
105+
%Z3 = insertvalue { i32, i32, i32, i32, i32 } %Z2, i32 %key, 3
106+
%Z4 = insertvalue { i32, i32, i32, i32, i32 } %Z3, i32 %key, 4
107+
ret { i32, i32, i32, i32, i32 } %Z4
108+
}
109+
110+
; The return value {i32, i32, i32, i32} will be returned via registers
111+
; %r2, %r3, %r4, %r5.
112+
; CHECK-LABEL: test3:
113+
; CHECK: brasl %r14, gen3
114+
; CHECK: ar %r2, %r3
115+
; CHECK: ar %r2, %r4
116+
; CHECK: ar %r2, %r5
117+
; CHECK-O0-LABEL: test3:
118+
; CHECK-O0: brasl %r14, gen3
119+
; CHECK-O0: ar %r2, %r3
120+
; CHECK-O0: ar %r2, %r4
121+
; CHECK-O0: ar %r2, %r5
122+
define i32 @test3(i32 %key) #0 {
123+
entry:
124+
%key.addr = alloca i32, align 4
125+
store i32 %key, i32* %key.addr, align 4
126+
%0 = load i32, i32* %key.addr, align 4
127+
%call = call swiftcc { i32, i32, i32, i32 } @gen3(i32 %0)
128+
129+
%v3 = extractvalue { i32, i32, i32, i32 } %call, 0
130+
%v5 = extractvalue { i32, i32, i32, i32 } %call, 1
131+
%v6 = extractvalue { i32, i32, i32, i32 } %call, 2
132+
%v7 = extractvalue { i32, i32, i32, i32 } %call, 3
133+
134+
%add = add nsw i32 %v3, %v5
135+
%add1 = add nsw i32 %add, %v6
136+
%add2 = add nsw i32 %add1, %v7
137+
ret i32 %add2
138+
}
139+
140+
declare swiftcc { i32, i32, i32, i32 } @gen3(i32 %key)
141+
142+
; The return value {float, float, float, float} will be returned via registers
143+
; %f0, %f2, %f4, %f6.
144+
; CHECK-LABEL: test4:
145+
; CHECK: brasl %r14, gen4
146+
; CHECK: aebr %f0, %f2
147+
; CHECK: aebr %f0, %f4
148+
; CHECK: aebr %f0, %f6
149+
; CHECK-O0-LABEL: test4:
150+
; CHECK-O0: brasl %r14, gen4
151+
; CHECK-O0: aebr %f0, %f2
152+
; CHECK-O0: aebr %f0, %f4
153+
; CHECK-O0: aebr %f0, %f6
154+
define float @test4(float %key) #0 {
155+
entry:
156+
%key.addr = alloca float, align 4
157+
store float %key, float* %key.addr, align 4
158+
%0 = load float, float* %key.addr, align 4
159+
%call = call swiftcc { float, float, float, float } @gen4(float %0)
160+
161+
%v3 = extractvalue { float, float, float, float } %call, 0
162+
%v5 = extractvalue { float, float, float, float } %call, 1
163+
%v6 = extractvalue { float, float, float, float } %call, 2
164+
%v7 = extractvalue { float, float, float, float } %call, 3
165+
166+
%add = fadd float %v3, %v5
167+
%add1 = fadd float %add, %v6
168+
%add2 = fadd float %add1, %v7
169+
ret float %add2
170+
}
171+
172+
declare swiftcc { float, float, float, float } @gen4(float %key)
173+
174+
; CHECK-LABEL: consume_i1_ret:
175+
; CHECK: brasl %r14, produce_i1_ret
176+
; CHECK: nilf %r2, 1
177+
; CHECK: nilf %r3, 1
178+
; CHECK: nilf %r4, 1
179+
; CHECK: nilf %r5, 1
180+
; CHECK-O0-LABEL: consume_i1_ret:
181+
; CHECK-O0: brasl %r14, produce_i1_ret
182+
; CHECK-O0: nilf %r2, 1
183+
; CHECK-O0: nilf %r3, 1
184+
; CHECK-O0: nilf %r4, 1
185+
; CHECK-O0: nilf %r5, 1
186+
define void @consume_i1_ret() {
187+
%call = call swiftcc { i1, i1, i1, i1 } @produce_i1_ret()
188+
%v3 = extractvalue { i1, i1, i1, i1 } %call, 0
189+
%v5 = extractvalue { i1, i1, i1, i1 } %call, 1
190+
%v6 = extractvalue { i1, i1, i1, i1 } %call, 2
191+
%v7 = extractvalue { i1, i1, i1, i1 } %call, 3
192+
%val = zext i1 %v3 to i32
193+
store i32 %val, i32* @var
194+
%val2 = zext i1 %v5 to i32
195+
store i32 %val2, i32* @var
196+
%val3 = zext i1 %v6 to i32
197+
store i32 %val3, i32* @var
198+
%val4 = zext i1 %v7 to i32
199+
store i32 %val4, i32* @var
200+
ret void
201+
}
202+
203+
declare swiftcc { i1, i1, i1, i1 } @produce_i1_ret()

0 commit comments

Comments
 (0)