Files
clang-p2996/llvm/test/CodeGen/SystemZ/swifterror.ll
Jonas Paulsson 16b7cc69ef [SystemZ] Eliminate call sequence instructions early. (#77812)
On SystemZ, the outgoing argument area which is big enough for all calls
in the function is created once during the prolog, as opposed to
adjusting the stack around each call. The call-sequence instructions are
therefore not really useful any more than to compute the maximum call
frame size, which has so far been done by PEI, but can just as well be
done at an earlier point.

This patch removes the mapping of the CallFrameSetupOpcode and
CallFrameDestroyOpcode and instead computes the MaxCallFrameSize
directly after instruction selection and then removes the ADJCALLSTACK
pseudos. This removes the confusing pseudos and also avoids the problem
of having to keep the call frame size accurate when creating new MBBs.

This fixes #76618 which exposed the need to maintain the call frame size
when splitting blocks (which was not done).
2024-03-28 18:26:38 +01:00

344 lines
10 KiB
LLVM

; RUN: llc < %s -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck %s
; RUN: llc < %s -O0 -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck --check-prefix=CHECK-O0 %s
declare ptr @malloc(i64)
declare void @free(ptr)
%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(ptr 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 [[T0:%r[0-9]+]], %r2
; CHECK-O0: mvi 8(%r2), 1
entry:
%call = call ptr @malloc(i64 16)
store ptr %call, ptr %error_ptr_ref
%tmp = getelementptr inbounds i8, ptr %call, i64 8
store i8 1, ptr %tmp
ret float 1.0
}
; "caller" calls "foo" that takes a swifterror parameter.
define float @caller(ptr %error_ref) {
; CHECK-LABEL: caller:
; Make a copy of error_ref because r2 is getting clobbered
; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2
; CHECK-DAG: lghi %r9, 0
; CHECK: brasl %r14, foo
; CHECK: %r2, %r9
; CHECK: jlh
; Access part of the error object and save it to error_ref
; CHECK: lb %r[[REG2:[0-9]+]], 8(%r2)
; CHECK: stc %r[[REG2]], 0(%r[[REG1]])
; 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 ptr
store ptr null, ptr %error_ptr_ref
%call = call float @foo(ptr swifterror %error_ptr_ref)
%error_from_foo = load ptr, ptr %error_ptr_ref
%had_error_from_foo = icmp ne ptr %error_from_foo, null
br i1 %had_error_from_foo, label %handler, label %cont
cont:
%v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
%t = load i8, ptr %v1
store i8 %t, ptr %error_ref
br label %handler
handler:
call void @free(ptr %error_from_foo)
ret float 1.0
}
; "caller2" is the caller of "foo", it calls "foo" inside a loop.
define float @caller2(ptr %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 ptr
br label %bb_loop
bb_loop:
store ptr null, ptr %error_ptr_ref
%call = call float @foo(ptr swifterror %error_ptr_ref)
%error_from_foo = load ptr, ptr %error_ptr_ref
%had_error_from_foo = icmp ne ptr %error_from_foo, null
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, ptr %error_from_foo, i64 0, i32 1
%t = load i8, ptr %v1
store i8 %t, ptr %error_ref
br label %handler
handler:
call void @free(ptr %error_from_foo)
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(ptr 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:
; spill to stack
; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15)
; CHECK-O0: chi %r2, 0
; CHECK-O0: je
; CHECK-O0: lghi %r2, 16
; CHECK-O0: brasl %r14, malloc
; CHECK-O0: lgr %r9, %r2
; CHECK-O0: mvi 8(%r2), 1
; 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 ptr @malloc(i64 16)
store ptr %call, ptr %error_ptr_ref
%tmp = getelementptr inbounds i8, ptr %call, i64 8
store i8 1, ptr %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(ptr 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(%r[[REG1]]), 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 ptr @malloc(i64 16)
store ptr %call, ptr %error_ptr_ref
%tmp = getelementptr inbounds i8, ptr %call, i64 8
store i8 1, ptr %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(ptr sret(%struct.S) %agg.result, i32 %val1, ptr 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-DAG: 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:
; spill sret to stack
; CHECK-O0-DAG: stg %r2, [[OFFS1:[0-9]+]](%r15)
; CHECK-O0-DAG: st %r3, [[OFFS2:[0-9]+]](%r15)
; CHECK-O0: lghi %r2, 16
; CHECK-O0: brasl %r14, malloc
; CHECK-O0-DAG: lgr %r[[REG3:[0-9]+]], %r2
; CHECK-O0-DAG: mvi 8(%r[[REG3]]), 1
; CHECK-O0-DAG: lg %r[[REG1:[0-9]+]], [[OFFS1]](%r15)
; CHECK-O0-DAG: lgr %r9, %r[[REG3]]
; CHECK-O0-DAG: l %r[[REG2:[0-9]+]], [[OFFS2]](%r15)
; CHECK-O0: st %r[[REG2]], 4(%r[[REG1]])
; CHECK-O0: br %r14
entry:
%call = call ptr @malloc(i64 16)
store ptr %call, ptr %error_ptr_ref
%tmp = getelementptr inbounds i8, ptr %call, i64 8
store i8 1, ptr %tmp
%v2 = getelementptr inbounds %struct.S, ptr %agg.result, i32 0, i32 1
store i32 %val1, ptr %v2
ret void
}
; "caller3" calls "foo_sret" that takes a swifterror parameter.
define float @caller3(ptr %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: jlh
; Access part of the error object and save it to error_ref
; CHECK: lb %r0, 8(%r2)
; CHECK: stc %r0, 0(%r[[REG1]])
; CHECK: brasl %r14, free
; CHECK-O0-LABEL: caller3:
; CHECK-O0: lghi %r9, 0
; CHECK-O0: lhi %r3, 1
; 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 ptr
store ptr null, ptr %error_ptr_ref
call void @foo_sret(ptr sret(%struct.S) %s, i32 1, ptr swifterror %error_ptr_ref)
%error_from_foo = load ptr, ptr %error_ptr_ref
%had_error_from_foo = icmp ne ptr %error_from_foo, null
br i1 %had_error_from_foo, label %handler, label %cont
cont:
%v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
%t = load i8, ptr %v1
store i8 %t, ptr %error_ref
br label %handler
handler:
call void @free(ptr %error_from_foo)
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(ptr %error_ref, ptr %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-DAG: lghi %r9, 0
; CHECK: brasl %r14, foo
; CHECK: ltgr %r2, %r9
; CHECK: jlh
; Access part of the error object and save it to error_ref
; CHECK: lb %r0, 8(%r2)
; CHECK: stc %r0, 0(%r[[REG1]])
; CHECK: brasl %r14, free
; The second swifterror value:
; CHECK: lghi %r9, 0
; CHECK: brasl %r14, foo
; CHECK: ltgr %r2, %r9
; CHECK: jlh
; Access part of the error object and save it to error_ref
; CHECK: lb %r0, 8(%r2)
; CHECK: stc %r0, 0(%r[[REG2]])
; 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 ptr
store ptr null, ptr %error_ptr_ref
%call = call float @foo(ptr swifterror %error_ptr_ref)
%error_from_foo = load ptr, ptr %error_ptr_ref
%had_error_from_foo = icmp ne ptr %error_from_foo, null
br i1 %had_error_from_foo, label %handler, label %cont
cont:
%v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
%t = load i8, ptr %v1
store i8 %t, ptr %error_ref
br label %handler
handler:
call void @free(ptr %error_from_foo)
%error_ptr_ref2 = alloca swifterror ptr
store ptr null, ptr %error_ptr_ref2
%call2 = call float @foo(ptr swifterror %error_ptr_ref2)
%error_from_foo2 = load ptr, ptr %error_ptr_ref2
%had_error_from_foo2 = icmp ne ptr %error_from_foo2, null
br i1 %had_error_from_foo2, label %handler2, label %cont2
cont2:
%v2 = getelementptr inbounds %swift_error, ptr %error_from_foo2, i64 0, i32 1
%t2 = load i8, ptr %v2
store i8 %t2, ptr %error_ref2
br label %handler2
handler2:
call void @free(ptr %error_from_foo2)
ret float 1.0
}