summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/SystemZ/SystemZCallingConv.td12
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelLowering.cpp10
-rw-r--r--llvm/lib/Target/SystemZ/SystemZISelLowering.h4
-rw-r--r--llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp8
-rw-r--r--llvm/test/CodeGen/SystemZ/swift-return.ll203
-rw-r--r--llvm/test/CodeGen/SystemZ/swifterror.ll358
-rw-r--r--llvm/test/CodeGen/SystemZ/swiftself.ll66
7 files changed, 658 insertions, 3 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 2404b96642c..2bf5ac29865 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -33,6 +33,9 @@ def RetCC_SystemZ : CallingConv<[
// Promote i32 to i64 if it has an explicit extension type.
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
+ // A SwiftError is returned in R9.
+ CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,
+
// ABI-compliant code returns 64-bit integers in R2. Make the other
// call-clobbered argument registers available for code that doesn't
// care about the ABI. (R6 is an argument register too, but is
@@ -65,6 +68,12 @@ def CC_SystemZ : CallingConv<[
// are smaller than 64 bits shouldn't.
CCIfType<[i32], CCIfExtend<CCPromoteToType<i64>>>,
+ // A SwiftSelf is passed in callee-saved R10.
+ CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10D]>>>,
+
+ // A SwiftError is passed in callee-saved R9.
+ CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R9D]>>>,
+
// Force long double values to the stack and pass i64 pointers to them.
CCIfType<[f128], CCPassIndirect<i64>>,
// Same for i128 values. These are already split into two i64 here,
@@ -108,3 +117,6 @@ def CC_SystemZ : CallingConv<[
//===----------------------------------------------------------------------===//
def CSR_SystemZ : CalleeSavedRegs<(add (sequence "R%dD", 6, 15),
(sequence "F%dD", 8, 15))>;
+
+// R9 is used to return SwiftError; remove it from CSR.
+def CSR_SystemZ_SwiftError : CalleeSavedRegs<(sub CSR_SystemZ, R9D)>;
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 51ef0d208ff..7eaa3ee73a1 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1004,9 +1004,11 @@ LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
}
static bool canUseSiblingCall(const CCState &ArgCCInfo,
- SmallVectorImpl<CCValAssign> &ArgLocs) {
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ SmallVectorImpl<ISD::OutputArg> &Outs) {
// Punt if there are any indirect or stack arguments, or if the call
- // needs the call-saved argument register R6.
+ // needs the callee-saved argument register R6, or if the call uses
+ // the callee-saved register arguments SwiftSelf and SwiftError.
for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) {
CCValAssign &VA = ArgLocs[I];
if (VA.getLocInfo() == CCValAssign::Indirect)
@@ -1016,6 +1018,8 @@ static bool canUseSiblingCall(const CCState &ArgCCInfo,
unsigned Reg = VA.getLocReg();
if (Reg == SystemZ::R6H || Reg == SystemZ::R6L || Reg == SystemZ::R6D)
return false;
+ if (Outs[I].Flags.isSwiftSelf() || Outs[I].Flags.isSwiftError())
+ return false;
}
return true;
}
@@ -1049,7 +1053,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
// We don't support GuaranteedTailCallOpt, only automatically-detected
// sibling calls.
- if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs))
+ if (IsTailCall && !canUseSiblingCall(ArgCCInfo, ArgLocs, Outs))
IsTailCall = false;
// Get a count of how many bytes are to be pushed on the stack.
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index ae761758b84..fe6966aafe2 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -459,6 +459,10 @@ public:
SelectionDAG &DAG) const override;
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
+ bool supportSwiftError() const override {
+ return true;
+ }
+
private:
const SystemZSubtarget &Subtarget;
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
index 8d872b75d2e..b5e5fd4bfc4 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -24,12 +24,20 @@ SystemZRegisterInfo::SystemZRegisterInfo()
const MCPhysReg *
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
+ if (MF->getSubtarget().getTargetLowering()->supportSwiftError() &&
+ MF->getFunction()->getAttributes().hasAttrSomewhere(
+ Attribute::SwiftError))
+ return CSR_SystemZ_SwiftError_SaveList;
return CSR_SystemZ_SaveList;
}
const uint32_t *
SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
+ if (MF.getSubtarget().getTargetLowering()->supportSwiftError() &&
+ MF.getFunction()->getAttributes().hasAttrSomewhere(
+ Attribute::SwiftError))
+ return CSR_SystemZ_SwiftError_RegMask;
return CSR_SystemZ_RegMask;
}
diff --git a/llvm/test/CodeGen/SystemZ/swift-return.ll b/llvm/test/CodeGen/SystemZ/swift-return.ll
new file mode 100644
index 00000000000..e72d6def84e
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/swift-return.ll
@@ -0,0 +1,203 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -mtriple=s390x-linux-gnu -O0 -verify-machineinstrs | FileCheck --check-prefix=CHECK-O0 %s
+
+@var = global i32 0
+
+; Test how llvm handles return type of {i16, i8}. The return value will be
+; passed in %r2 and %r3.
+; CHECK-LABEL: test:
+; CHECK: st %r2
+; CHECK: brasl %r14, gen
+; CHECK-DAG: lhr %r2, %r2
+; CHECK-DAG: lbr %[[REG1:r[0-9]+]], %r3
+; CHECK: ar %r2, %[[REG1]]
+; CHECK-O0-LABEL: test
+; CHECK-O0: st %r2
+; CHECK-O0: brasl %r14, gen
+; CHECK-O0-DAG: lhr %[[REG1:r[0-9]+]], %r2
+; CHECK-O0-DAG: lbr %[[REG2:r[0-9]+]], %r3
+; CHECK-O0: ar %[[REG1]], %[[REG2]]
+; CHECK-O0: lr %r2, %[[REG1]]
+define i16 @test(i32 %key) {
+entry:
+ %key.addr = alloca i32, align 4
+ store i32 %key, i32* %key.addr, align 4
+ %0 = load i32, i32* %key.addr, align 4
+ %call = call swiftcc { i16, i8 } @gen(i32 %0)
+ %v3 = extractvalue { i16, i8 } %call, 0
+ %v1 = sext i16 %v3 to i32
+ %v5 = extractvalue { i16, i8 } %call, 1
+ %v2 = sext i8 %v5 to i32
+ %add = add nsw i32 %v1, %v2
+ %conv = trunc i32 %add to i16
+ ret i16 %conv
+}
+
+declare swiftcc { i16, i8 } @gen(i32)
+
+; If we can't pass every return value in registers, we will pass everything
+; in memroy. The caller provides space for the return value and passes
+; the address in %r2. The first input argument will be in %r3.
+; CHECK-LABEL: test2:
+; CHECK: lr %[[REG1:r[0-9]+]], %r2
+; CHECK-DAG: la %r2, 160(%r15)
+; CHECK-DAG: lr %r3, %[[REG1]]
+; CHECK: brasl %r14, gen2
+; CHECK: l %r2, 160(%r15)
+; CHECK: a %r2, 164(%r15)
+; CHECK: a %r2, 168(%r15)
+; CHECK: a %r2, 172(%r15)
+; CHECK: a %r2, 176(%r15)
+; CHECK-O0-LABEL: test2:
+; CHECK-O0: la %[[REG1:r[0-9]+]], 168(%r15)
+; CHECK-O0: st %r2, [[SPILL1:[0-9]+]](%r15)
+; CHECK-O0: lgr %r2, %[[REG1]]
+; CHECK-O0: l %r3, [[SPILL1]](%r15)
+; CHECK-O0: brasl %r14, gen2
+; CHECK-O0-DAG: l %r{{.*}}, 184(%r15)
+; CHECK-O0-DAG: l %r{{.*}}, 180(%r15)
+; CHECK-O0-DAG: l %r{{.*}}, 176(%r15)
+; CHECK-O0-DAG: l %r{{.*}}, 172(%r15)
+; CHECK-O0-DAG: l %r{{.*}}, 168(%r15)
+; CHECK-O0: ar
+; CHECK-O0: ar
+; CHECK-O0: ar
+; CHECK-O0: ar
+; CHECK-O0: lr %r2
+define i32 @test2(i32 %key) #0 {
+entry:
+ %key.addr = alloca i32, align 4
+ store i32 %key, i32* %key.addr, align 4
+ %0 = load i32, i32* %key.addr, align 4
+ %call = call swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %0)
+
+ %v3 = extractvalue { i32, i32, i32, i32, i32 } %call, 0
+ %v5 = extractvalue { i32, i32, i32, i32, i32 } %call, 1
+ %v6 = extractvalue { i32, i32, i32, i32, i32 } %call, 2
+ %v7 = extractvalue { i32, i32, i32, i32, i32 } %call, 3
+ %v8 = extractvalue { i32, i32, i32, i32, i32 } %call, 4
+
+ %add = add nsw i32 %v3, %v5
+ %add1 = add nsw i32 %add, %v6
+ %add2 = add nsw i32 %add1, %v7
+ %add3 = add nsw i32 %add2, %v8
+ ret i32 %add3
+}
+
+; The address of the return value is passed in %r2.
+; On return, %r2 will contain the adddress that has been passed in by the caller in %r2.
+; CHECK-LABEL: gen2:
+; CHECK: st %r3, 16(%r2)
+; CHECK: st %r3, 12(%r2)
+; CHECK: st %r3, 8(%r2)
+; CHECK: st %r3, 4(%r2)
+; CHECK: st %r3, 0(%r2)
+; CHECK-O0-LABEL: gen2:
+; CHECK-O0-DAG: st %r3, 16(%r2)
+; CHECK-O0-DAG: st %r3, 12(%r2)
+; CHECK-O0-DAG: st %r3, 8(%r2)
+; CHECK-O0-DAG: st %r3, 4(%r2)
+; CHECK-O0-DAG: st %r3, 0(%r2)
+define swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %key) {
+ %Y = insertvalue { i32, i32, i32, i32, i32 } undef, i32 %key, 0
+ %Z = insertvalue { i32, i32, i32, i32, i32 } %Y, i32 %key, 1
+ %Z2 = insertvalue { i32, i32, i32, i32, i32 } %Z, i32 %key, 2
+ %Z3 = insertvalue { i32, i32, i32, i32, i32 } %Z2, i32 %key, 3
+ %Z4 = insertvalue { i32, i32, i32, i32, i32 } %Z3, i32 %key, 4
+ ret { i32, i32, i32, i32, i32 } %Z4
+}
+
+; The return value {i32, i32, i32, i32} will be returned via registers
+; %r2, %r3, %r4, %r5.
+; CHECK-LABEL: test3:
+; CHECK: brasl %r14, gen3
+; CHECK: ar %r2, %r3
+; CHECK: ar %r2, %r4
+; CHECK: ar %r2, %r5
+; CHECK-O0-LABEL: test3:
+; CHECK-O0: brasl %r14, gen3
+; CHECK-O0: ar %r2, %r3
+; CHECK-O0: ar %r2, %r4
+; CHECK-O0: ar %r2, %r5
+define i32 @test3(i32 %key) #0 {
+entry:
+ %key.addr = alloca i32, align 4
+ store i32 %key, i32* %key.addr, align 4
+ %0 = load i32, i32* %key.addr, align 4
+ %call = call swiftcc { i32, i32, i32, i32 } @gen3(i32 %0)
+
+ %v3 = extractvalue { i32, i32, i32, i32 } %call, 0
+ %v5 = extractvalue { i32, i32, i32, i32 } %call, 1
+ %v6 = extractvalue { i32, i32, i32, i32 } %call, 2
+ %v7 = extractvalue { i32, i32, i32, i32 } %call, 3
+
+ %add = add nsw i32 %v3, %v5
+ %add1 = add nsw i32 %add, %v6
+ %add2 = add nsw i32 %add1, %v7
+ ret i32 %add2
+}
+
+declare swiftcc { i32, i32, i32, i32 } @gen3(i32 %key)
+
+; The return value {float, float, float, float} will be returned via registers
+; %f0, %f2, %f4, %f6.
+; CHECK-LABEL: test4:
+; CHECK: brasl %r14, gen4
+; CHECK: aebr %f0, %f2
+; CHECK: aebr %f0, %f4
+; CHECK: aebr %f0, %f6
+; CHECK-O0-LABEL: test4:
+; CHECK-O0: brasl %r14, gen4
+; CHECK-O0: aebr %f0, %f2
+; CHECK-O0: aebr %f0, %f4
+; CHECK-O0: aebr %f0, %f6
+define float @test4(float %key) #0 {
+entry:
+ %key.addr = alloca float, align 4
+ store float %key, float* %key.addr, align 4
+ %0 = load float, float* %key.addr, align 4
+ %call = call swiftcc { float, float, float, float } @gen4(float %0)
+
+ %v3 = extractvalue { float, float, float, float } %call, 0
+ %v5 = extractvalue { float, float, float, float } %call, 1
+ %v6 = extractvalue { float, float, float, float } %call, 2
+ %v7 = extractvalue { float, float, float, float } %call, 3
+
+ %add = fadd float %v3, %v5
+ %add1 = fadd float %add, %v6
+ %add2 = fadd float %add1, %v7
+ ret float %add2
+}
+
+declare swiftcc { float, float, float, float } @gen4(float %key)
+
+; CHECK-LABEL: consume_i1_ret:
+; CHECK: brasl %r14, produce_i1_ret
+; CHECK: nilf %r2, 1
+; CHECK: nilf %r3, 1
+; CHECK: nilf %r4, 1
+; CHECK: nilf %r5, 1
+; CHECK-O0-LABEL: consume_i1_ret:
+; CHECK-O0: brasl %r14, produce_i1_ret
+; CHECK-O0: nilf %r2, 1
+; CHECK-O0: nilf %r3, 1
+; CHECK-O0: nilf %r4, 1
+; CHECK-O0: nilf %r5, 1
+define void @consume_i1_ret() {
+ %call = call swiftcc { i1, i1, i1, i1 } @produce_i1_ret()
+ %v3 = extractvalue { i1, i1, i1, i1 } %call, 0
+ %v5 = extractvalue { i1, i1, i1, i1 } %call, 1
+ %v6 = extractvalue { i1, i1, i1, i1 } %call, 2
+ %v7 = extractvalue { i1, i1, i1, i1 } %call, 3
+ %val = zext i1 %v3 to i32
+ store i32 %val, i32* @var
+ %val2 = zext i1 %v5 to i32
+ store i32 %val2, i32* @var
+ %val3 = zext i1 %v6 to i32
+ store i32 %val3, i32* @var
+ %val4 = zext i1 %v7 to i32
+ store i32 %val4, i32* @var
+ ret void
+}
+
+declare swiftcc { i1, i1, i1, i1 } @produce_i1_ret()
diff --git a/llvm/test/CodeGen/SystemZ/swifterror.ll b/llvm/test/CodeGen/SystemZ/swifterror.ll
new file mode 100644
index 00000000000..90d55eef4ae
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/swifterror.ll
@@ -0,0 +1,358 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu| FileCheck %s
+; RUN: llc < %s -O0 -mtriple=s390x-linux-gnu | FileCheck --check-prefix=CHECK-O0 %s
+
+declare i8* @malloc(i64)
+declare void @free(i8*)
+%swift_error = type {i64, i8}
+
+; This tests the basic usage of a swifterror parameter. "foo" is the function
+; that takes a swifterror parameter and "caller" is the caller of "foo".
+define float @foo(%swift_error** swifterror %error_ptr_ref) {
+; CHECK-LABEL: foo:
+; CHECK: lghi %r2, 16
+; CHECK: brasl %r14, malloc
+; CHECK: mvi 8(%r2), 1
+; CHECK: lgr %r9, %r2
+; CHECK-O0-LABEL: foo:
+; CHECK-O0: lghi %r2, 16
+; CHECK-O0: brasl %r14, malloc
+; CHECK-O0: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK-O0: mvi 8(%r2), 1
+; CHECK-O0: lgr %r9, %r[[REG1]]
+entry:
+ %call = call i8* @malloc(i64 16)
+ %call.0 = bitcast i8* %call to %swift_error*
+ store %swift_error* %call.0, %swift_error** %error_ptr_ref
+ %tmp = getelementptr inbounds i8, i8* %call, i64 8
+ store i8 1, i8* %tmp
+ ret float 1.0
+}
+
+; "caller" calls "foo" that takes a swifterror parameter.
+define float @caller(i8* %error_ref) {
+; CHECK-LABEL: caller:
+; Make a copy of error_ref because r2 is getting clobbered
+; CHECK: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK: lghi %r9, 0
+; CHECK: brasl %r14, foo
+; CHECK: cgijlh %r9, 0,
+; Access part of the error object and save it to error_ref
+; CHECK: lb %r[[REG2:[0-9]+]], 8(%r9)
+; CHECK: stc %r[[REG2]], 0(%r[[REG1]])
+; CHECK: lgr %r2, %r9
+; CHECK: brasl %r14, free
+; CHECK-O0-LABEL: caller:
+; CHECK-O0: lghi %r9, 0
+; CHECK-O0: brasl %r14, foo
+; CHECK-O0: cghi %r9, 0
+; CHECK-O0: jlh
+entry:
+ %error_ptr_ref = alloca swifterror %swift_error*
+ store %swift_error* null, %swift_error** %error_ptr_ref
+ %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
+ %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
+ %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
+ %tmp = bitcast %swift_error* %error_from_foo to i8*
+ br i1 %had_error_from_foo, label %handler, label %cont
+cont:
+ %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
+ %t = load i8, i8* %v1
+ store i8 %t, i8* %error_ref
+ br label %handler
+handler:
+ call void @free(i8* %tmp)
+ ret float 1.0
+}
+
+; "caller2" is the caller of "foo", it calls "foo" inside a loop.
+define float @caller2(i8* %error_ref) {
+; CHECK-LABEL: caller2:
+; Make a copy of error_ref because r2 is getting clobbered
+; CHECK: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK: lghi %r9, 0
+; CHECK: brasl %r14, foo
+; CHECK: cgijlh %r9, 0,
+; CHECK: ceb %f0,
+; CHECK: jnh
+; Access part of the error object and save it to error_ref
+; CHECK: lb %r[[REG2:[0-9]+]], 8(%r9)
+; CHECK: stc %r[[REG2]], 0(%r[[REG1]])
+; CHECK: lgr %r2, %r9
+; CHECK: brasl %r14, free
+; CHECK-O0-LABEL: caller2:
+; CHECK-O0: lghi %r9, 0
+; CHECK-O0: brasl %r14, foo
+; CHECK-O0: cghi %r9, 0
+; CHECK-O0: jlh
+entry:
+ %error_ptr_ref = alloca swifterror %swift_error*
+ br label %bb_loop
+bb_loop:
+ store %swift_error* null, %swift_error** %error_ptr_ref
+ %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
+ %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
+ %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
+ %tmp = bitcast %swift_error* %error_from_foo to i8*
+ br i1 %had_error_from_foo, label %handler, label %cont
+cont:
+ %cmp = fcmp ogt float %call, 1.000000e+00
+ br i1 %cmp, label %bb_end, label %bb_loop
+bb_end:
+ %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
+ %t = load i8, i8* %v1
+ store i8 %t, i8* %error_ref
+ br label %handler
+handler:
+ call void @free(i8* %tmp)
+ ret float 1.0
+}
+
+; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
+; under a certain condition.
+define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
+; CHECK-LABEL: foo_if:
+; CHECK: cije %r2, 0
+; CHECK: lghi %r2, 16
+; CHECK: brasl %r14, malloc
+; CHECK: mvi 8(%r2), 1
+; CHECK: lgr %r9, %r2
+; CHECK-NOT: %r9
+; CHECK: br %r14
+; CHECK-O0-LABEL: foo_if:
+; CHECK-O0: chi %r2, 0
+; spill to stack
+; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15)
+; CHECK-O0: je
+; CHECK-O0: lghi %r2, 16
+; CHECK-O0: brasl %r14, malloc
+; CHECK-O0: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK-O0: mvi 8(%r2), 1
+; CHECK-O0: lgr %r9, %r[[REG1]]
+; CHECK-O0: br %r14
+; reload from stack
+; CHECK-O0: lg %r9, [[OFFS]](%r15)
+; CHECK-O0: br %r14
+entry:
+ %cond = icmp ne i32 %cc, 0
+ br i1 %cond, label %gen_error, label %normal
+
+gen_error:
+ %call = call i8* @malloc(i64 16)
+ %call.0 = bitcast i8* %call to %swift_error*
+ store %swift_error* %call.0, %swift_error** %error_ptr_ref
+ %tmp = getelementptr inbounds i8, i8* %call, i64 8
+ store i8 1, i8* %tmp
+ ret float 1.0
+
+normal:
+ ret float 0.0
+}
+
+; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
+; under a certain condition inside a loop.
+define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
+; CHECK-LABEL: foo_loop:
+; CHECK: lr %r[[REG1:[0-9]+]], %r2
+; CHECK: cije %r[[REG1]], 0
+; CHECK: lghi %r2, 16
+; CHECK: brasl %r14, malloc
+; CHECK: mvi 8(%r2), 1
+; CHECK: ceb %f8,
+; CHECK: jnh
+; CHECK: lgr %r9, %r2
+; CHECK: br %r14
+; CHECK-O0-LABEL: foo_loop:
+; spill to stack
+; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15)
+; CHECK-O0: chi %r{{.*}}, 0
+; CHECK-O0: je
+; CHECK-O0: lghi %r2, 16
+; CHECK-O0: brasl %r14, malloc
+; CHECK-O0: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK-O0: mvi 8(%r2), 1
+; CHECK-O0: jnh
+; reload from stack
+; CHECK-O0: lg %r9, [[OFFS:[0-9]+]](%r15)
+; CHECK-O0: br %r14
+entry:
+ br label %bb_loop
+
+bb_loop:
+ %cond = icmp ne i32 %cc, 0
+ br i1 %cond, label %gen_error, label %bb_cont
+
+gen_error:
+ %call = call i8* @malloc(i64 16)
+ %call.0 = bitcast i8* %call to %swift_error*
+ store %swift_error* %call.0, %swift_error** %error_ptr_ref
+ %tmp = getelementptr inbounds i8, i8* %call, i64 8
+ store i8 1, i8* %tmp
+ br label %bb_cont
+
+bb_cont:
+ %cmp = fcmp ogt float %cc2, 1.000000e+00
+ br i1 %cmp, label %bb_end, label %bb_loop
+bb_end:
+ ret float 0.0
+}
+
+%struct.S = type { i32, i32, i32, i32, i32, i32 }
+
+; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
+; parameter.
+define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
+; CHECK-LABEL: foo_sret:
+; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK-DAG: lr %r[[REG2:[0-9]+]], %r3
+; CHECK: lghi %r2, 16
+; CHECK: brasl %r14, malloc
+; CHECK: mvi 8(%r2), 1
+; CHECK: st %r[[REG2]], 4(%r[[REG1]])
+; CHECK: lgr %r9, %r2
+; CHECK-NOT: %r9
+; CHECK: br %r14
+
+; CHECK-O0-LABEL: foo_sret:
+; CHECK-O0: lghi %r{{.*}}, 16
+; spill sret to stack
+; CHECK-O0: stg %r2, [[OFFS1:[0-9]+]](%r15)
+; CHECK-O0: lgr %r2, %r{{.*}}
+; CHECK-O0: st %r3, [[OFFS2:[0-9]+]](%r15)
+; CHECK-O0: brasl %r14, malloc
+; CHECK-O0: lgr {{.*}}, %r2
+; CHECK-O0: mvi 8(%r2), 1
+; CHECK-O0-DAG: lg %r[[REG1:[0-9]+]], [[OFFS1]](%r15)
+; CHECK-O0-DAG: l %r[[REG2:[0-9]+]], [[OFFS2]](%r15)
+; CHECK-O0: st %r[[REG2]], 4(%r[[REG1]])
+; CHECK-O0: lgr %r9, {{.*}}
+; CHECK-O0: br %r14
+entry:
+ %call = call i8* @malloc(i64 16)
+ %call.0 = bitcast i8* %call to %swift_error*
+ store %swift_error* %call.0, %swift_error** %error_ptr_ref
+ %tmp = getelementptr inbounds i8, i8* %call, i64 8
+ store i8 1, i8* %tmp
+ %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
+ store i32 %val1, i32* %v2
+ ret void
+}
+
+; "caller3" calls "foo_sret" that takes a swifterror parameter.
+define float @caller3(i8* %error_ref) {
+; CHECK-LABEL: caller3:
+; Make a copy of error_ref because r2 is getting clobbered
+; CHECK: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK: lhi %r3, 1
+; CHECK: lghi %r9, 0
+; CHECK: brasl %r14, foo_sret
+; CHECK: cgijlh %r9, 0,
+; Access part of the error object and save it to error_ref
+; CHECK: lb %r0, 8(%r9)
+; CHECK: stc %r0, 0(%r[[REG1]])
+; CHECK: lgr %r2, %r9
+; CHECK: brasl %r14, free
+
+; CHECK-O0-LABEL: caller3:
+; CHECK-O0: lghi %r9, 0
+; CHECK-O0: lhi %r3, 1
+; CHECK-O0: stg %r2, {{.*}}(%r15)
+; CHECK-O0: lgr %r2, {{.*}}
+; CHECK-O0: brasl %r14, foo_sret
+; CHECK-O0: lgr {{.*}}, %r9
+; CHECK-O0: cghi %r9, 0
+; CHECK-O0: jlh
+; Access part of the error object and save it to error_ref
+; CHECK-O0: lb %r0, 8(%r{{.*}})
+; CHECK-O0: stc %r0, 0(%r{{.*}})
+; reload from stack
+; CHECK-O0: lg %r2, {{.*}}(%r15)
+; CHECK-O0: brasl %r14, free
+entry:
+ %s = alloca %struct.S, align 8
+ %error_ptr_ref = alloca swifterror %swift_error*
+ store %swift_error* null, %swift_error** %error_ptr_ref
+ call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref)
+ %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
+ %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
+ %tmp = bitcast %swift_error* %error_from_foo to i8*
+ br i1 %had_error_from_foo, label %handler, label %cont
+cont:
+ %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
+ %t = load i8, i8* %v1
+ store i8 %t, i8* %error_ref
+ br label %handler
+handler:
+ call void @free(i8* %tmp)
+ ret float 1.0
+}
+
+; This is a caller with multiple swifterror values, it calls "foo" twice, each
+; time with a different swifterror value, from "alloca swifterror".
+define float @caller_with_multiple_swifterror_values(i8* %error_ref, i8* %error_ref2) {
+; CHECK-LABEL: caller_with_multiple_swifterror_values:
+; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2
+; CHECK-DAG: lgr %r[[REG2:[0-9]+]], %r3
+; The first swifterror value:
+; CHECK: lghi %r9, 0
+; CHECK: brasl %r14, foo
+; CHECK: cgijlh %r9, 0,
+; Access part of the error object and save it to error_ref
+; CHECK: lb %r0, 8(%r9)
+; CHECK: stc %r0, 0(%r[[REG1]])
+; CHECK: lgr %r2, %r9
+; CHECK: brasl %r14, free
+
+; The second swifterror value:
+; CHECK: lghi %r9, 0
+; CHECK: brasl %r14, foo
+; CHECK: cgijlh %r9, 0,
+; Access part of the error object and save it to error_ref
+; CHECK: lb %r0, 8(%r9)
+; CHECK: stc %r0, 0(%r[[REG2]])
+; CHECK: lgr %r2, %r9
+; CHECK: brasl %r14, free
+
+; CHECK-O0-LABEL: caller_with_multiple_swifterror_values:
+
+; The first swifterror value:
+; CHECK-O0: lghi %r9, 0
+; CHECK-O0: brasl %r14, foo
+; CHECK-O0: jlh
+
+; The second swifterror value:
+; CHECK-O0: lghi %r9, 0
+; CHECK-O0: brasl %r14, foo
+; CHECK-O0: jlh
+entry:
+ %error_ptr_ref = alloca swifterror %swift_error*
+ store %swift_error* null, %swift_error** %error_ptr_ref
+ %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
+ %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
+ %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
+ %tmp = bitcast %swift_error* %error_from_foo to i8*
+ br i1 %had_error_from_foo, label %handler, label %cont
+cont:
+ %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
+ %t = load i8, i8* %v1
+ store i8 %t, i8* %error_ref
+ br label %handler
+handler:
+ call void @free(i8* %tmp)
+
+ %error_ptr_ref2 = alloca swifterror %swift_error*
+ store %swift_error* null, %swift_error** %error_ptr_ref2
+ %call2 = call float @foo(%swift_error** swifterror %error_ptr_ref2)
+ %error_from_foo2 = load %swift_error*, %swift_error** %error_ptr_ref2
+ %had_error_from_foo2 = icmp ne %swift_error* %error_from_foo2, null
+ %bitcast2 = bitcast %swift_error* %error_from_foo2 to i8*
+ br i1 %had_error_from_foo2, label %handler2, label %cont2
+cont2:
+ %v2 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo2, i64 0, i32 1
+ %t2 = load i8, i8* %v2
+ store i8 %t2, i8* %error_ref2
+ br label %handler2
+handler2:
+ call void @free(i8* %bitcast2)
+
+ ret float 1.0
+}
diff --git a/llvm/test/CodeGen/SystemZ/swiftself.ll b/llvm/test/CodeGen/SystemZ/swiftself.ll
new file mode 100644
index 00000000000..ee6104ad203
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/swiftself.ll
@@ -0,0 +1,66 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+; Parameter with swiftself should be allocated to r10.
+; CHECK-LABEL: swiftself_param:
+; CHECK: lgr %r2, %r10
+define i8 *@swiftself_param(i8* swiftself %addr0) {
+ ret i8 *%addr0
+}
+
+; Check that r10 is used to pass a swiftself argument.
+; CHECK-LABEL: call_swiftself:
+; CHECK: lgr %r10, %r2
+; CHECK: brasl %r14, swiftself_param
+define i8 *@call_swiftself(i8* %arg) {
+ %res = call i8 *@swiftself_param(i8* swiftself %arg)
+ ret i8 *%res
+}
+
+; r10 should be saved by the callee even if used for swiftself
+; CHECK-LABEL: swiftself_clobber:
+; CHECK: stmg %r10,
+; ...
+; CHECK: lmg %r10,
+; CHECK: br %r14
+define i8 *@swiftself_clobber(i8* swiftself %addr0) {
+ call void asm sideeffect "", "~{r10}"()
+ ret i8 *%addr0
+}
+
+; Demonstrate that we do not need any loads when calling multiple functions
+; with swiftself argument.
+; CHECK-LABEL: swiftself_passthrough:
+; CHECK-NOT: lg{{.*}}r10,
+; CHECK: brasl %r14, swiftself_param
+; CHECK-NOT: lg{{.*}}r10,
+; CHECK-NEXT: brasl %r14, swiftself_param
+define void @swiftself_passthrough(i8* swiftself %addr0) {
+ call i8 *@swiftself_param(i8* swiftself %addr0)
+ call i8 *@swiftself_param(i8* swiftself %addr0)
+ ret void
+}
+
+; Normally, we can use a tail call if the callee swiftself is the same as the
+; caller one. Not yet supported on SystemZ.
+; CHECK-LABEL: swiftself_tail:
+; CHECK: lgr %r[[REG1:[0-9]+]], %r10
+; CHECK: lgr %r10, %r[[REG1]]
+; CHECK: brasl %r14, swiftself_param
+; CHECK: br %r14
+define i8* @swiftself_tail(i8* swiftself %addr0) {
+ call void asm sideeffect "", "~{r10}"()
+ %res = tail call i8* @swiftself_param(i8* swiftself %addr0)
+ ret i8* %res
+}
+
+; We can not use a tail call if the callee swiftself is not the same as the
+; caller one.
+; CHECK-LABEL: swiftself_notail:
+; CHECK: lgr %r10, %r2
+; CHECK: brasl %r14, swiftself_param
+; CHECK: lmg %r10,
+; CHECK: br %r14
+define i8* @swiftself_notail(i8* swiftself %addr0, i8* %addr1) nounwind {
+ %res = tail call i8* @swiftself_param(i8* swiftself %addr1)
+ ret i8* %res
+}
OpenPOWER on IntegriCloud