CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
653 lines
20 KiB
C
653 lines
20 KiB
C
// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c23 -fdefer-ts -emit-llvm %s -o - | FileCheck %s
|
|
|
|
#define defer _Defer
|
|
|
|
void a();
|
|
void b();
|
|
void c();
|
|
void x(int q);
|
|
bool q(int q);
|
|
[[noreturn]] void noreturn();
|
|
|
|
// CHECK-LABEL: define {{.*}} void @f1()
|
|
void f1() {
|
|
// CHECK: call void @c()
|
|
// CHECK: call void @b()
|
|
// CHECK: call void @a()
|
|
defer a();
|
|
defer b();
|
|
defer c();
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @f2()
|
|
void f2() {
|
|
// CHECK: call void @x(i32 {{.*}} 1)
|
|
// CHECK: call void @x(i32 {{.*}} 2)
|
|
// CHECK: call void @x(i32 {{.*}} 3)
|
|
// CHECK: call void @x(i32 {{.*}} 4)
|
|
// CHECK: call void @x(i32 {{.*}} 5)
|
|
defer x(5);
|
|
{
|
|
defer x(4);
|
|
{
|
|
defer x(2);
|
|
defer x(1);
|
|
}
|
|
x(3);
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @f3(i1 {{.*}} %ret)
|
|
void f3(bool ret) {
|
|
// CHECK: entry:
|
|
// CHECK: %ret.addr = alloca i8, align 1
|
|
// CHECK: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK: %storedv = zext i1 %ret to i8
|
|
// CHECK: store i8 %storedv, ptr %ret.addr, align 1
|
|
// CHECK: %0 = load i8, ptr %ret.addr, align 1
|
|
// CHECK: %loadedv = icmp ne i8 %0, 0
|
|
// CHECK: br i1 %loadedv, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK: store i32 1, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: br label %cleanup
|
|
// CHECK: if.end:
|
|
// CHECK: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: call void @x(i32 {{.*}} 1)
|
|
// CHECK: store i32 %cleanup.dest.saved, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: store i32 0, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: br label %cleanup
|
|
// CHECK: cleanup:
|
|
// CHECK: %cleanup.dest.saved1 = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: call void @x(i32 {{.*}} 2)
|
|
// CHECK: store i32 %cleanup.dest.saved1, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: switch i32 %cleanup.dest, label %unreachable [
|
|
// CHECK: i32 0, label %cleanup.cont
|
|
// CHECK: i32 1, label %cleanup.cont
|
|
// CHECK: ]
|
|
// CHECK: cleanup.cont:
|
|
// CHECK: ret void
|
|
// CHECK: unreachable:
|
|
// CHECK: unreachable
|
|
defer x(2);
|
|
if (ret) return;
|
|
defer x(1);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_g()
|
|
void ts_g() {
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: ret void
|
|
// CHECK-NEXT: }
|
|
return;
|
|
defer x(42);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_h()
|
|
void ts_h() {
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: br label %b
|
|
// CHECK-EMPTY:
|
|
goto b;
|
|
{
|
|
defer x(42);
|
|
}
|
|
|
|
// CHECK-NEXT: b:
|
|
// CHECK-NEXT: ret void
|
|
// CHECK-NEXT: }
|
|
b:
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_i()
|
|
void ts_i() {
|
|
// CHECK: entry:
|
|
// CHECK: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK: store i32 2, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: call void @x(i32 {{.*}} 42)
|
|
// CHECK: store i32 %cleanup.dest.saved, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: switch i32 %cleanup.dest, label %unreachable [
|
|
// CHECK: i32 2, label %b
|
|
// CHECK: ]
|
|
// CHECK: b:
|
|
// CHECK: ret void
|
|
// CHECK: unreachable:
|
|
// CHECK: unreachable
|
|
{
|
|
defer { x(42); }
|
|
goto b;
|
|
}
|
|
b:
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_m()
|
|
void ts_m() {
|
|
// CHECK: entry:
|
|
// CHECK: br label %b
|
|
// CHECK: b:
|
|
// CHECK: call void @x(i32 {{.*}} 1)
|
|
// CHECK: ret void
|
|
goto b;
|
|
{
|
|
b:
|
|
defer x(1);
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_p()
|
|
void ts_p() {
|
|
// CHECK: entry:
|
|
// CHECK: br label %b
|
|
// CHECK: b:
|
|
// CHECK: ret void
|
|
{
|
|
goto b;
|
|
defer x(42);
|
|
}
|
|
b:
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @ts_r()
|
|
void ts_r() {
|
|
// CHECK: entry:
|
|
// CHECK: br label %b
|
|
// CHECK: b:
|
|
// CHECK: call void @x(i32 {{.*}} 42)
|
|
// CHECK: br label %b
|
|
{
|
|
b:
|
|
defer x(42);
|
|
}
|
|
goto b;
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @return_value()
|
|
int return_value() {
|
|
// CHECK: entry:
|
|
// CHECK: %r = alloca i32, align 4
|
|
// CHECK: %p = alloca ptr, align 8
|
|
// CHECK: store i32 4, ptr %r, align 4
|
|
// CHECK: store ptr %r, ptr %p, align 8
|
|
// CHECK: %0 = load ptr, ptr %p, align 8
|
|
// CHECK: %1 = load i32, ptr %0, align 4
|
|
// CHECK: %2 = load ptr, ptr %p, align 8
|
|
// CHECK: store i32 5, ptr %2, align 4
|
|
// CHECK: ret i32 %1
|
|
int r = 4;
|
|
int* p = &r;
|
|
defer { *p = 5; }
|
|
return *p;
|
|
}
|
|
|
|
void* malloc(__SIZE_TYPE__ size);
|
|
void free(void* ptr);
|
|
int use_buffer(__SIZE_TYPE__ size, void* ptr);
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @malloc_free_example()
|
|
int malloc_free_example() {
|
|
// CHECK: entry:
|
|
// CHECK: %size = alloca i32, align 4
|
|
// CHECK: %buf = alloca ptr, align 8
|
|
// CHECK: store i32 20, ptr %size, align 4
|
|
// CHECK: %call = call ptr @malloc(i64 {{.*}} 20)
|
|
// CHECK: store ptr %call, ptr %buf, align 8
|
|
// CHECK: %0 = load ptr, ptr %buf, align 8
|
|
// CHECK: %call1 = call i32 @use_buffer(i64 {{.*}} 20, ptr {{.*}} %0)
|
|
// CHECK: %1 = load ptr, ptr %buf, align 8
|
|
// CHECK: call void @free(ptr {{.*}} %1)
|
|
// CHECK: ret i32 %call1
|
|
const int size = 20;
|
|
void* buf = malloc(size);
|
|
defer { free(buf); }
|
|
return use_buffer(size, buf);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @sequencing_1()
|
|
void sequencing_1() {
|
|
// CHECK: entry:
|
|
// CHECK: call void @x(i32 {{.*}} 1)
|
|
// CHECK: call void @x(i32 {{.*}} 2)
|
|
// CHECK: call void @x(i32 {{.*}} 3)
|
|
// CHECK: ret void
|
|
{
|
|
defer {
|
|
x(3);
|
|
}
|
|
if (true)
|
|
defer x(1);
|
|
x(2);
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @sequencing_2()
|
|
void sequencing_2() {
|
|
// CHECK: entry:
|
|
// CHECK: %arr = alloca [3 x i32], align 4
|
|
// CHECK: %i = alloca i32, align 4
|
|
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %arr, ptr align 4 @__const.sequencing_2.arr, i64 12, i1 false)
|
|
// CHECK: store i32 0, ptr %i, align 4
|
|
// CHECK: br label %for.cond
|
|
// CHECK: for.cond:
|
|
// CHECK: %0 = load i32, ptr %i, align 4
|
|
// CHECK: %cmp = icmp ult i32 %0, 3
|
|
// CHECK: br i1 %cmp, label %for.body, label %for.end
|
|
// CHECK: for.body:
|
|
// CHECK: %1 = load i32, ptr %i, align 4
|
|
// CHECK: %idxprom = zext i32 %1 to i64
|
|
// CHECK: %arrayidx = getelementptr inbounds nuw [3 x i32], ptr %arr, i64 0, i64 %idxprom
|
|
// CHECK: %2 = load i32, ptr %arrayidx, align 4
|
|
// CHECK: call void @x(i32 {{.*}} %2)
|
|
// CHECK: br label %for.inc
|
|
// CHECK: for.inc:
|
|
// CHECK: %3 = load i32, ptr %i, align 4
|
|
// CHECK: %inc = add i32 %3, 1
|
|
// CHECK: store i32 %inc, ptr %i, align 4
|
|
// CHECK: br label %for.cond
|
|
// CHECK: for.end:
|
|
// CHECK: call void @x(i32 {{.*}} 4)
|
|
// CHECK: call void @x(i32 {{.*}} 5)
|
|
// CHECK: ret void
|
|
{
|
|
int arr[] = {1, 2, 3};
|
|
defer {
|
|
x(5);
|
|
}
|
|
for (unsigned i = 0; i < 3; ++i)
|
|
defer x(arr[i]);
|
|
x(4);
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @sequencing_3()
|
|
void sequencing_3() {
|
|
// CHECK: entry:
|
|
// CHECK: %r = alloca i32, align 4
|
|
// CHECK: store i32 0, ptr %r, align 4
|
|
// CHECK: %0 = load i32, ptr %r, align 4
|
|
// CHECK: %add = add nsw i32 %0, 1
|
|
// CHECK: store i32 %add, ptr %r, align 4
|
|
// CHECK: %1 = load i32, ptr %r, align 4
|
|
// CHECK: %mul = mul nsw i32 %1, 2
|
|
// CHECK: store i32 %mul, ptr %r, align 4
|
|
// CHECK: %2 = load i32, ptr %r, align 4
|
|
// CHECK: %add1 = add nsw i32 %2, 3
|
|
// CHECK: store i32 %add1, ptr %r, align 4
|
|
// CHECK: %3 = load i32, ptr %r, align 4
|
|
// CHECK: %mul2 = mul nsw i32 %3, 4
|
|
// CHECK: store i32 %mul2, ptr %r, align 4
|
|
// CHECK: ret void
|
|
int r = 0;
|
|
{
|
|
defer {
|
|
defer r *= 4;
|
|
r *= 2;
|
|
defer {
|
|
r += 3;
|
|
}
|
|
}
|
|
defer r += 1;
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @defer_stmt(i32 {{.*}} %q)
|
|
void defer_stmt(int q) {
|
|
// CHECK: entry:
|
|
// CHECK: %q.addr = alloca i32, align 4
|
|
// CHECK: store i32 %q, ptr %q.addr, align 4
|
|
// CHECK: %0 = load i32, ptr %q.addr, align 4
|
|
// CHECK: %cmp = icmp eq i32 %0, 3
|
|
// CHECK: br i1 %cmp, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK: call void @x(i32 {{.*}} 42)
|
|
// CHECK: br label %if.end
|
|
// CHECK: if.end:
|
|
// CHECK: ret void
|
|
defer if (q == 3) x(42);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @defer_defer()
|
|
void defer_defer() {
|
|
// CHECK: entry:
|
|
// CHECK: call void @x(i32 {{.*}} 0)
|
|
// CHECK: call void @x(i32 {{.*}} 1)
|
|
// CHECK: call void @x(i32 {{.*}} 2)
|
|
// CHECK: call void @x(i32 {{.*}} 3)
|
|
// CHECK: call void @x(i32 {{.*}} 4)
|
|
// CHECK: ret void
|
|
defer x(4);
|
|
defer defer x(3);
|
|
defer defer defer x(2);
|
|
defer defer defer defer x(1);
|
|
x(0);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @vla(ptr {{.*}} %p, i32 {{.*}} %x)
|
|
int vla(int* p, int x) {
|
|
// CHECK: entry:
|
|
// CHECK: %retval = alloca i32, align 4
|
|
// CHECK: %p.addr = alloca ptr, align 8
|
|
// CHECK: %x.addr = alloca i32, align 4
|
|
// CHECK: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK: %saved_stack = alloca ptr, align 8
|
|
// CHECK: %__vla_expr0 = alloca i64, align 8
|
|
// CHECK: %saved_stack3 = alloca ptr, align 8
|
|
// CHECK: %__vla_expr1 = alloca i64, align 8
|
|
// CHECK: store ptr %p, ptr %p.addr, align 8
|
|
// CHECK: store i32 %x, ptr %x.addr, align 4
|
|
// CHECK: %0 = load i32, ptr %x.addr, align 4
|
|
// CHECK: %cmp = icmp slt i32 %0, 5
|
|
// CHECK: br i1 %cmp, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK: store i32 10, ptr %retval, align 4
|
|
// CHECK: store i32 1, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: br label %cleanup
|
|
// CHECK: if.end:
|
|
// CHECK: store i32 7, ptr %retval, align 4
|
|
// CHECK: store i32 1, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %1 = load i32, ptr %x.addr, align 4
|
|
// CHECK: %2 = zext i32 %1 to i64
|
|
// CHECK: %3 = call ptr @llvm.stacksave.p0()
|
|
// CHECK: store ptr %3, ptr %saved_stack, align 8
|
|
// CHECK: %vla = alloca i32, i64 %2, align 16
|
|
// CHECK: store i64 %2, ptr %__vla_expr0, align 8
|
|
// CHECK: %arrayidx = getelementptr inbounds i32, ptr %vla, i64 2
|
|
// CHECK: store i32 4, ptr %arrayidx, align 8
|
|
// CHECK: %arrayidx1 = getelementptr inbounds i32, ptr %vla, i64 2
|
|
// CHECK: %4 = load i32, ptr %arrayidx1, align 8
|
|
// CHECK: %5 = load ptr, ptr %p.addr, align 8
|
|
// CHECK: store i32 %4, ptr %5, align 4
|
|
// CHECK: %6 = load ptr, ptr %saved_stack, align 8
|
|
// CHECK: call void @llvm.stackrestore.p0(ptr %6)
|
|
// CHECK: store i32 %cleanup.dest.saved, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: br label %cleanup
|
|
// CHECK: cleanup:
|
|
// CHECK: %cleanup.dest.saved2 = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %7 = load i32, ptr %x.addr, align 4
|
|
// CHECK: %8 = zext i32 %7 to i64
|
|
// CHECK: %9 = call ptr @llvm.stacksave.p0()
|
|
// CHECK: store ptr %9, ptr %saved_stack3, align 8
|
|
// CHECK: %vla4 = alloca i32, i64 %8, align 16
|
|
// CHECK: store i64 %8, ptr %__vla_expr1, align 8
|
|
// CHECK: %arrayidx5 = getelementptr inbounds i32, ptr %vla4, i64 2
|
|
// CHECK: store i32 3, ptr %arrayidx5, align 8
|
|
// CHECK: %arrayidx6 = getelementptr inbounds i32, ptr %vla4, i64 2
|
|
// CHECK: %10 = load i32, ptr %arrayidx6, align 8
|
|
// CHECK: %11 = load ptr, ptr %p.addr, align 8
|
|
// CHECK: store i32 %10, ptr %11, align 4
|
|
// CHECK: %12 = load ptr, ptr %saved_stack3, align 8
|
|
// CHECK: call void @llvm.stackrestore.p0(ptr %12)
|
|
// CHECK: store i32 %cleanup.dest.saved2, ptr %cleanup.dest.slot, align 4
|
|
// CHECK: %13 = load i32, ptr %retval, align 4
|
|
// CHECK: ret i32 %13
|
|
defer {
|
|
int a[x];
|
|
a[2] = 3;
|
|
*p = a[2];
|
|
}
|
|
if (x < 5) { return 10; }
|
|
defer {
|
|
int b[x];
|
|
b[2] = 4;
|
|
*p = b[2];
|
|
}
|
|
return 7;
|
|
}
|
|
|
|
[[noreturn]] void exit();
|
|
[[noreturn]] void _Exit();
|
|
[[noreturn]] void foobar();
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @call_exit()
|
|
int call_exit() {
|
|
// CHECK: entry:
|
|
// CHECK: call void @exit()
|
|
// CHECK: unreachable
|
|
defer x(1);
|
|
exit();
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @call__Exit()
|
|
int call__Exit() {
|
|
// CHECK: entry:
|
|
// CHECK: call void @_Exit()
|
|
// CHECK: unreachable
|
|
defer x(1);
|
|
_Exit();
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @call_foobar()
|
|
int call_foobar() {
|
|
// CHECK: entry:
|
|
// CHECK: call void @foobar()
|
|
// CHECK: unreachable
|
|
defer x(1);
|
|
foobar();
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} i32 @main()
|
|
int main() {
|
|
// CHECK: entry:
|
|
// CHECK: %retval = alloca i32, align 4
|
|
// CHECK: store i32 0, ptr %retval, align 4
|
|
// CHECK: store i32 5, ptr %retval, align 4
|
|
// CHECK: call void @x(i32 {{.*}} 42)
|
|
// CHECK: %0 = load i32, ptr %retval, align 4
|
|
// CHECK: ret i32 %0
|
|
defer x(42);
|
|
return 5;
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @t()
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: %count = alloca i32, align 4
|
|
// CHECK-NEXT: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK-NEXT: store i32 0, ptr %count, align 4
|
|
// CHECK-NEXT: br label %target
|
|
// CHECK: target:
|
|
// CHECK-NEXT: %0 = load i32, ptr %count, align 4
|
|
// CHECK-NEXT: %inc = add nsw i32 %0, 1
|
|
// CHECK-NEXT: store i32 %inc, ptr %count, align 4
|
|
// CHECK-NEXT: %1 = load i32, ptr %count, align 4
|
|
// CHECK-NEXT: %cmp = icmp sle i32 %1, 2
|
|
// CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i32 2, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 1)
|
|
// CHECK-NEXT: store i32 %cleanup.dest.saved, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: switch i32 %cleanup.dest, label %unreachable [
|
|
// CHECK-NEXT: i32 0, label %cleanup.cont
|
|
// CHECK-NEXT: i32 2, label %target
|
|
// CHECK-NEXT: ]
|
|
// CHECK: cleanup.cont:
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 2)
|
|
// CHECK-NEXT: ret void
|
|
// CHECK: unreachable:
|
|
// CHECK-NEXT: unreachable
|
|
void t() {
|
|
int count = 0;
|
|
|
|
{
|
|
target:
|
|
_Defer { x(1); }
|
|
++count;
|
|
if (count <= 2) {
|
|
goto target;
|
|
}
|
|
}
|
|
|
|
x(2);
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @stmt_expr()
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: %tmp = alloca i32, align 4
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 1)
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 2)
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 3)
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 4)
|
|
// CHECK-NEXT: store i32 6, ptr %tmp, align 4
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} 5)
|
|
// CHECK-NEXT: %0 = load i32, ptr %tmp, align 4
|
|
// CHECK-NEXT: call void @x(i32 {{.*}} %0)
|
|
// CHECK-NEXT: ret void
|
|
void stmt_expr() {
|
|
({
|
|
_Defer x(4);
|
|
_Defer ({
|
|
_Defer x(3);
|
|
x(2);
|
|
});
|
|
x(1);
|
|
});
|
|
|
|
x(({
|
|
_Defer x(5);
|
|
6;
|
|
}));
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @cleanup_no_insert_point()
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK-NEXT: br label %while.cond
|
|
// CHECK: while.cond:
|
|
// CHECK-NEXT: %call = call {{.*}} i1 @q(i32 {{.*}} 1)
|
|
// CHECK-NEXT: br i1 %call, label %while.body, label %while.end
|
|
// CHECK: while.body:
|
|
// CHECK-NEXT: %call1 = call {{.*}} i1 @q(i32 {{.*}} 2)
|
|
// CHECK-NEXT: br i1 %call1, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i32 2, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: %call2 = call {{.*}} i1 @q(i32 {{.*}} 3)
|
|
// CHECK-NEXT: br i1 %call2, label %if.then3, label %if.end4
|
|
// CHECK: if.then3:
|
|
// CHECK-NEXT: store i32 3, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: if.end4:
|
|
// CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: call void @noreturn()
|
|
// CHECK-NEXT: unreachable
|
|
// CHECK: 0:
|
|
// CHECK-NEXT: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: switch i32 %cleanup.dest, label %unreachable [
|
|
// CHECK-NEXT: i32 0, label %cleanup.cont
|
|
// CHECK-NEXT: i32 2, label %while.cond
|
|
// CHECK-NEXT: i32 3, label %while.end
|
|
// CHECK-NEXT: ]
|
|
// CHECK: cleanup.cont:
|
|
// CHECK-NEXT: br label %while.cond
|
|
// CHECK: while.end:
|
|
// CHECK-NEXT: ret void
|
|
// CHECK: unreachable:
|
|
// CHECK-NEXT: unreachable
|
|
void cleanup_no_insert_point() {
|
|
while (q(1)) {
|
|
_Defer {
|
|
noreturn();
|
|
};
|
|
if (q(2)) continue;
|
|
if (q(3)) break;
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: define {{.*}} void @cleanup_nested()
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: %cleanup.dest.slot = alloca i32, align 4
|
|
// CHECK-NEXT: br label %while.cond
|
|
// CHECK: while.cond:
|
|
// CHECK-NEXT: %call = call {{.*}} i1 @q(i32 {{.*}} 1)
|
|
// CHECK-NEXT: br i1 %call, label %while.body, label %while.end19
|
|
// CHECK: while.body:
|
|
// CHECK-NEXT: %call1 = call {{.*}} i1 @q(i32 {{.*}} 6)
|
|
// CHECK-NEXT: br i1 %call1, label %if.then, label %if.end
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i32 2, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: %call2 = call {{.*}} i1 @q(i32 {{.*}} 7)
|
|
// CHECK-NEXT: br i1 %call2, label %if.then3, label %if.end4
|
|
// CHECK: if.then3:
|
|
// CHECK-NEXT: store i32 3, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: if.end4:
|
|
// CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: %cleanup.dest.saved = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %while.cond5
|
|
// CHECK: while.cond5:
|
|
// CHECK-NEXT: %call6 = call {{.*}} i1 @q(i32 {{.*}} 2)
|
|
// CHECK-NEXT: br i1 %call6, label %while.body7, label %while.end
|
|
// CHECK: while.body7:
|
|
// CHECK-NEXT: %call8 = call {{.*}} i1 @q(i32 {{.*}} 4)
|
|
// CHECK-NEXT: br i1 %call8, label %if.then9, label %if.end10
|
|
// CHECK: if.then9:
|
|
// CHECK-NEXT: store i32 4, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup14
|
|
// CHECK: if.end10:
|
|
// CHECK-NEXT: %call11 = call {{.*}} i1 @q(i32 {{.*}} 5)
|
|
// CHECK-NEXT: br i1 %call11, label %if.then12, label %if.end13
|
|
// CHECK: if.then12:
|
|
// CHECK-NEXT: store i32 5, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup14
|
|
// CHECK: if.end13:
|
|
// CHECK-NEXT: store i32 0, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: br label %cleanup14
|
|
// CHECK: cleanup14:
|
|
// CHECK-NEXT: %cleanup.dest.saved15 = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: %call16 = call {{.*}} i1 @q(i32 {{.*}} 3)
|
|
// CHECK-NEXT: store i32 %cleanup.dest.saved15, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: %cleanup.dest = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: switch i32 %cleanup.dest, label %unreachable [
|
|
// CHECK-NEXT: i32 0, label %cleanup.cont
|
|
// CHECK-NEXT: i32 4, label %while.cond5
|
|
// CHECK-NEXT: i32 5, label %while.end
|
|
// CHECK-NEXT: ]
|
|
// CHECK: cleanup.cont:
|
|
// CHECK-NEXT: br label %while.cond5
|
|
// CHECK: while.end:
|
|
// CHECK-NEXT: store i32 %cleanup.dest.saved, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: %cleanup.dest17 = load i32, ptr %cleanup.dest.slot, align 4
|
|
// CHECK-NEXT: switch i32 %cleanup.dest17, label %unreachable [
|
|
// CHECK-NEXT: i32 0, label %cleanup.cont18
|
|
// CHECK-NEXT: i32 2, label %while.cond
|
|
// CHECK-NEXT: i32 3, label %while.end19
|
|
// CHECK-NEXT: ]
|
|
// CHECK: cleanup.cont18:
|
|
// CHECK-NEXT: br label %while.cond
|
|
// CHECK: while.end19:
|
|
// CHECK-NEXT: ret void
|
|
// CHECK: unreachable:
|
|
// CHECK-NEXT: unreachable
|
|
void cleanup_nested() {
|
|
while (q(1)) {
|
|
_Defer {
|
|
while (q(2)) {
|
|
_Defer {
|
|
q(3);
|
|
}
|
|
if (q(4)) continue;
|
|
if (q(5)) break;
|
|
}
|
|
};
|
|
if (q(6)) continue;
|
|
if (q(7)) break;
|
|
}
|
|
}
|