Index: lib/Target/SystemZ/SystemZCallingConv.td =================================================================== --- lib/Target/SystemZ/SystemZCallingConv.td +++ lib/Target/SystemZ/SystemZCallingConv.td @@ -33,6 +33,9 @@ // Promote i32 to i64 if it has an explicit extension type. CCIfType<[i32], CCIfExtend>>, + // A SwiftError is returned in R9. + CCIfSwiftError>>, + // 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 @@ // are smaller than 64 bits shouldn't. CCIfType<[i32], CCIfExtend>>, + // A SwiftSelf is passed in callee-saved R10. + CCIfSwiftSelf>>, + + // A SwiftError is passed in callee-saved R9. + CCIfSwiftError>>, + // Force long double values to the stack and pass i64 pointers to them. CCIfType<[f128], CCPassIndirect>, // Same for i128 values. These are already split into two i64 here, @@ -108,3 +117,6 @@ //===----------------------------------------------------------------------===// 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)>; Index: lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.h +++ lib/Target/SystemZ/SystemZISelLowering.h @@ -452,6 +452,10 @@ SelectionDAG &DAG) const override; SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + bool supportSwiftError() const override { + return true; + } + private: const SystemZSubtarget &Subtarget; Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1005,9 +1005,11 @@ } static bool canUseSiblingCall(const CCState &ArgCCInfo, - SmallVectorImpl &ArgLocs) { + SmallVectorImpl &ArgLocs, + SmallVectorImpl &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) @@ -1017,6 +1019,8 @@ 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; } @@ -1050,7 +1054,7 @@ // 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. Index: lib/Target/SystemZ/SystemZRegisterInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZRegisterInfo.cpp +++ lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -24,12 +24,20 @@ 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; } Index: test/CodeGen/SystemZ/swift-return.ll =================================================================== --- /dev/null +++ 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() Index: test/CodeGen/SystemZ/swifterror.ll =================================================================== --- /dev/null +++ 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 +} Index: test/CodeGen/SystemZ/swiftself.ll =================================================================== --- /dev/null +++ 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 +}