diff options
Diffstat (limited to 'clang/test/CIR/CodeGen')
-rw-r--r-- | clang/test/CIR/CodeGen/agg-expr-lvalue.c | 111 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/atomic.c | 593 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/binassign.c | 48 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/builtin_inline.c | 91 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/complex.cpp | 63 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/compound_literal.cpp | 27 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/dtors.cpp | 14 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/lambda.cpp | 24 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/new.cpp | 121 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/opaque.cpp | 163 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/statement-exprs.c | 10 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/struct-init.cpp | 16 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/struct.cpp | 66 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/ternary-throw.cpp | 197 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/ternary.cpp | 233 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/try-catch.cpp | 87 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/vla.c | 59 |
17 files changed, 1881 insertions, 42 deletions
diff --git a/clang/test/CIR/CodeGen/agg-expr-lvalue.c b/clang/test/CIR/CodeGen/agg-expr-lvalue.c new file mode 100644 index 0000000..c826f8f --- /dev/null +++ b/clang/test/CIR/CodeGen/agg-expr-lvalue.c @@ -0,0 +1,111 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct Point { + int x, y; +}; + +struct Line { + struct Point start; + struct Point end; +}; + +// AggExprEmitter::VisitMemberExpr +void test_member_in_array(void) { + struct Line line = {{1, 2}, {3, 4}}; + struct Point arr[1] = {line.start}; +} + +// CIR-LABEL: cir.func{{.*}} @test_member_in_array +// CIR: %[[LINE:.*]] = cir.alloca !rec_Line{{.*}}, ["line", init] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_Point x 1>{{.*}}, ["arr", init] +// CIR: %[[MEMBER:.*]] = cir.get_member %[[LINE]][0] {name = "start"} +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_member_in_array +// LLVM: %[[LINE:.*]] = alloca %struct.Line +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0 +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_member_in_array +// OGCG: %[[LINE:.*]] = alloca %struct.Line +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0 +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitMemberExpr +void test_member_arrow_in_array(void) { + struct Line *line_ptr; + struct Point arr[1] = {line_ptr->start}; +} + +// CIR-LABEL: cir.func{{.*}} @test_member_arrow_in_array +// CIR: %[[PTR:.*]] = cir.alloca !cir.ptr<!rec_Line>{{.*}}, ["line_ptr"] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_Point x 1>{{.*}}, ["arr", init] +// CIR: %[[LOADED:.*]] = cir.load{{.*}}%[[PTR]] +// CIR: %[[MEMBER:.*]] = cir.get_member %[[LOADED]][0] {name = "start"} +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_member_arrow_in_array +// LLVM: %[[PTR:.*]] = alloca ptr +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// LLVM: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LOADED]]{{.*}}i32 0, i32 0 +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_member_arrow_in_array +// OGCG: %[[PTR:.*]] = alloca ptr +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// OGCG: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LOADED]]{{.*}}i32 0, i32 0 +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitUnaryDeref +void test_deref_in_array(void) { + struct Point *ptr; + struct Point arr[1] = {*ptr}; +} + +// CIR-LABEL: cir.func{{.*}} @test_deref_in_array +// CIR: %[[PTR:.*]] = cir.alloca !cir.ptr<!rec_Point>{{.*}}, ["ptr"] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_Point x 1>{{.*}}, ["arr", init] +// CIR: %[[LOADED:.*]] = cir.load{{.*}}%[[PTR]] +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_deref_in_array +// LLVM: %[[PTR:.*]] = alloca ptr +// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point] +// LLVM: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_deref_in_array +// OGCG: %[[PTR:.*]] = alloca ptr +// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point] +// OGCG: %[[LOADED:.*]] = load ptr{{.*}}%[[PTR]] +// OGCG: call void @llvm.memcpy + +// AggExprEmitter::VisitStringLiteral +void test_string_array_in_array(void) { + char matrix[2][6] = {"hello", "world"}; +} + +// CIR-LABEL: cir.func{{.*}} @test_string_array_in_array +// CIR: cir.alloca !cir.array<!cir.array<!s8i x 6> x 2>, {{.*}}, ["matrix", init] +// CIR: cir.get_global +// CIR: cir.copy +// CIR: cir.get_global +// CIR: cir.copy + +// LLVM-LABEL: define{{.*}} @test_string_array_in_array +// LLVM: alloca [2 x [6 x i8]] +// LLVM: call void @llvm.memcpy +// LLVM: call void @llvm.memcpy + +// OGCG-LABEL: define{{.*}} @test_string_array_in_array +// OGCG: alloca [2 x [6 x i8]] +// OGCG: call void @llvm.memcpy{{.*}}@__const.test_string_array_in_array diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 440010a..6579988 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -514,3 +514,596 @@ void atomic_exchange_n(int *ptr, int value) { // OGCG: %{{.+}} = atomicrmw xchg ptr %{{.+}}, i32 %{{.+}} acq_rel, align 4 // OGCG: %{{.+}} = atomicrmw xchg ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 } + +void test_and_set(void *p) { + // CIR-LABEL: @test_and_set + // LLVM-LABEL: @test_and_set + // OGCG-LABEL: @test_and_set + + __atomic_test_and_set(p, __ATOMIC_SEQ_CST); + // CIR: %[[VOID_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR-NEXT: %[[PTR:.+]] = cir.cast bitcast %[[VOID_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s8i> + // CIR-NEXT: %[[RES:.+]] = cir.atomic.test_and_set seq_cst %[[PTR]] : !cir.ptr<!s8i> -> !cir.bool + // CIR-NEXT: cir.store align(1) %[[RES]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool> + + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i8 1 seq_cst, align 1 + // LLVM-NEXT: %{{.+}} = icmp ne i8 %[[RES]], 0 + + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i8 1 seq_cst, align 1 + // OGCG-NEXT: %{{.+}} = icmp ne i8 %[[RES]], 0 +} + +void test_and_set_volatile(volatile void *p) { + // CIR-LABEL: @test_and_set_volatile + // LLVM-LABEL: @test_and_set_volatile + // OGCG-LABEL: @test_and_set_volatile + + __atomic_test_and_set(p, __ATOMIC_SEQ_CST); + // CIR: %[[VOID_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR-NEXT: %[[PTR:.+]] = cir.cast bitcast %[[VOID_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s8i> + // CIR-NEXT: %[[RES:.+]] = cir.atomic.test_and_set seq_cst %[[PTR]] volatile : !cir.ptr<!s8i> -> !cir.bool + // CIR-NEXT: cir.store align(1) %[[RES]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool> + + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw volatile xchg ptr %[[PTR]], i8 1 seq_cst, align 1 + // LLVM-NEXT: %{{.+}} = icmp ne i8 %[[RES]], 0 + + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw volatile xchg ptr %[[PTR]], i8 1 seq_cst, align 1 + // OGCG-NEXT: %{{.+}} = icmp ne i8 %[[RES]], 0 +} + +void clear(void *p) { + // CIR-LABEL: @clear + // LLVM-LABEL: @clear + // OGCG-LABEL: @clear + + __atomic_clear(p, __ATOMIC_SEQ_CST); + // CIR: %[[VOID_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR-NEXT: %[[PTR:.+]] = cir.cast bitcast %[[VOID_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s8i> + // CIR: cir.atomic.clear seq_cst %[[PTR]] : !cir.ptr<!s8i> + + // LLVM: store atomic i8 0, ptr %{{.+}} seq_cst, align 1 + + // OGCG: store atomic i8 0, ptr %{{.+}} seq_cst, align 1 +} + +void clear_volatile(volatile void *p) { + // CIR-LABEL: @clear_volatile + // LLVM-LABEL: @clear_volatile + // OGCG-LABEL: @clear_volatile + + __atomic_clear(p, __ATOMIC_SEQ_CST); + // CIR: %[[VOID_PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR-NEXT: %[[PTR:.+]] = cir.cast bitcast %[[VOID_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s8i> + // CIR: cir.atomic.clear seq_cst %[[PTR]] volatile : !cir.ptr<!s8i> + + // LLVM: store atomic volatile i8 0, ptr %{{.+}} seq_cst, align 1 + + // OGCG: store atomic volatile i8 0, ptr %{{.+}} seq_cst, align 1 +} + +int atomic_fetch_add(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_add + // LLVM-LABEL: @atomic_fetch_add + // OGCG-LABEL: @atomic_fetch_add + + return __atomic_fetch_add(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw add ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw add ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_add_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_add_fetch + // LLVM-LABEL: @atomic_add_fetch + // OGCG-LABEL: @atomic_add_fetch + + return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw add ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = add i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw add ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = add i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_add(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_add + // LLVM-LABEL: @c11_atomic_fetch_add + // OGCG-LABEL: @c11_atomic_fetch_add + + return __c11_atomic_fetch_add(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw add ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw add ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_sub(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_sub + // LLVM-LABEL: @atomic_fetch_sub + // OGCG-LABEL: @atomic_fetch_sub + + return __atomic_fetch_sub(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch sub seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw sub ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw sub ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_sub_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_sub_fetch + // LLVM-LABEL: @atomic_sub_fetch + // OGCG-LABEL: @atomic_sub_fetch + + return __atomic_sub_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch sub seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw sub ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = sub i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw sub ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = sub i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_sub(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_sub + // LLVM-LABEL: @c11_atomic_fetch_sub + // OGCG-LABEL: @c11_atomic_fetch_sub + + return __c11_atomic_fetch_sub(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch sub seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw sub ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw sub ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_fetch_add_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_fetch_add_fp + // LLVM-LABEL: @atomic_fetch_add_fp + // OGCG-LABEL: @atomic_fetch_add_fp + + return __atomic_fetch_add(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fadd ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fadd ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_add_fetch_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_add_fetch_fp + // LLVM-LABEL: @atomic_add_fetch_fp + // OGCG-LABEL: @atomic_add_fetch_fp + + return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[OLD:.+]] = atomicrmw fadd ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = fadd float %[[OLD]], %[[VAL]] + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw fadd ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = fadd float %[[OLD]], %[[VAL]] + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float c11_atomic_fetch_sub_fp(_Atomic(float) *ptr, float value) { + // CIR-LABEL: @c11_atomic_fetch_sub_fp + // LLVM-LABEL: @c11_atomic_fetch_sub_fp + // OGCG-LABEL: @c11_atomic_fetch_sub_fp + + return __c11_atomic_fetch_sub(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch sub seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fsub ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fsub ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_min(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_min + // LLVM-LABEL: @atomic_fetch_min + // OGCG-LABEL: @atomic_fetch_min + + return __atomic_fetch_min(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw min ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw min ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_min_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_min_fetch + // LLVM-LABEL: @atomic_min_fetch + // OGCG-LABEL: @atomic_min_fetch + + return __atomic_min_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw min ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[OLD_LESS:.+]] = icmp slt i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: %[[RES:.+]] = select i1 %[[OLD_LESS]], i32 %[[OLD]], i32 %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw min ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[OLD_LESS:.+]] = icmp slt i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: %[[RES:.+]] = select i1 %[[OLD_LESS]], i32 %[[OLD]], i32 %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_min(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_min + // LLVM-LABEL: @c11_atomic_fetch_min + // OGCG-LABEL: @c11_atomic_fetch_min + + return __c11_atomic_fetch_min(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw min ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw min ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_fetch_min_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_fetch_min_fp + // LLVM-LABEL: @atomic_fetch_min_fp + // OGCG-LABEL: @atomic_fetch_min_fp + + return __atomic_fetch_min(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fmin ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fmin ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_min_fetch_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_min_fetch_fp + // LLVM-LABEL: @atomic_min_fetch_fp + // OGCG-LABEL: @atomic_min_fetch_fp + + return __atomic_min_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[OLD:.+]] = atomicrmw fmin ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = call float @llvm.minnum.f32(float %[[OLD]], float %[[VAL]]) + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw fmin ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = call float @llvm.minnum.f32(float %[[OLD]], float %[[VAL]]) + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float c11_atomic_fetch_min_fp(_Atomic(float) *ptr, float value) { + // CIR-LABEL: @c11_atomic_fetch_min_fp + // LLVM-LABEL: @c11_atomic_fetch_min_fp + // OGCG-LABEL: @c11_atomic_fetch_min_fp + + return __c11_atomic_fetch_min(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch min seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fmin ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fmin ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_max(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_max + // LLVM-LABEL: @atomic_fetch_max + // OGCG-LABEL: @atomic_fetch_max + + return __atomic_fetch_max(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw max ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw max ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_max_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_max_fetch + // LLVM-LABEL: @atomic_max_fetch + // OGCG-LABEL: @atomic_max_fetch + + return __atomic_max_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw max ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[OLD_GREATER:.+]] = icmp sgt i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: %[[RES:.+]] = select i1 %[[OLD_GREATER]], i32 %[[OLD]], i32 %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw max ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[OLD_GREATER:.+]] = icmp sgt i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: %[[RES:.+]] = select i1 %[[OLD_GREATER]], i32 %[[OLD]], i32 %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_max(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_max + // LLVM-LABEL: @c11_atomic_fetch_max + // OGCG-LABEL: @c11_atomic_fetch_max + + return __c11_atomic_fetch_max(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw max ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw max ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_fetch_max_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_fetch_max_fp + // LLVM-LABEL: @atomic_fetch_max_fp + // OGCG-LABEL: @atomic_fetch_max_fp + + return __atomic_fetch_max(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fmax ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fmax ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float atomic_max_fetch_fp(float *ptr, float value) { + // CIR-LABEL: @atomic_max_fetch_fp + // LLVM-LABEL: @atomic_max_fetch_fp + // OGCG-LABEL: @atomic_max_fetch_fp + + return __atomic_max_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[OLD:.+]] = atomicrmw fmax ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = call float @llvm.maxnum.f32(float %[[OLD]], float %[[VAL]]) + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw fmax ptr %{{.+}}, float %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = call float @llvm.maxnum.f32(float %[[OLD]], float %[[VAL]]) + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +float c11_atomic_fetch_max_fp(_Atomic(float) *ptr, float value) { + // CIR-LABEL: @c11_atomic_fetch_max_fp + // LLVM-LABEL: @c11_atomic_fetch_max_fp + // OGCG-LABEL: @c11_atomic_fetch_max_fp + + return __c11_atomic_fetch_max(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch max seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!cir.float>, !cir.float) -> !cir.float + + // LLVM: %[[RES:.+]] = atomicrmw fmax ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw fmax ptr %{{.+}}, float %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store float %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_and(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_and + // LLVM-LABEL: @atomic_fetch_and + // OGCG-LABEL: @atomic_fetch_and + + return __atomic_fetch_and(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch and seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw and ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw and ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_and_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_and_fetch + // LLVM-LABEL: @atomic_and_fetch + // OGCG-LABEL: @atomic_and_fetch + + return __atomic_and_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch and seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw and ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = and i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw and ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = and i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_and(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_and + // LLVM-LABEL: @c11_atomic_fetch_and + // OGCG-LABEL: @c11_atomic_fetch_and + + return __c11_atomic_fetch_and(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch and seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw and ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw and ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_or(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_or + // LLVM-LABEL: @atomic_fetch_or + // OGCG-LABEL: @atomic_fetch_or + + return __atomic_fetch_or(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch or seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw or ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw or ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_or_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_or_fetch + // LLVM-LABEL: @atomic_or_fetch + // OGCG-LABEL: @atomic_or_fetch + + return __atomic_or_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch or seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw or ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = or i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw or ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = or i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_or(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_or + // LLVM-LABEL: @c11_atomic_fetch_or + // OGCG-LABEL: @c11_atomic_fetch_or + + return __c11_atomic_fetch_or(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch or seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw or ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw or ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_xor(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_xor + // LLVM-LABEL: @atomic_fetch_xor + // OGCG-LABEL: @atomic_fetch_xor + + return __atomic_fetch_xor(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch xor seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw xor ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw xor ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_xor_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_xor_fetch + // LLVM-LABEL: @atomic_xor_fetch + // OGCG-LABEL: @atomic_xor_fetch + + return __atomic_xor_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch xor seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw xor ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[RES:.+]] = xor i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw xor ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[RES:.+]] = xor i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_xor(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_xor + // LLVM-LABEL: @c11_atomic_fetch_xor + // OGCG-LABEL: @c11_atomic_fetch_xor + + return __c11_atomic_fetch_xor(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch xor seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw xor ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw xor ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_fetch_nand(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_nand + // LLVM-LABEL: @atomic_fetch_nand + // OGCG-LABEL: @atomic_fetch_nand + + return __atomic_fetch_nand(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch nand seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int atomic_nand_fetch(int *ptr, int value) { + // CIR-LABEL: @atomic_nand_fetch + // LLVM-LABEL: @atomic_nand_fetch + // OGCG-LABEL: @atomic_nand_fetch + + return __atomic_nand_fetch(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch nand seq_cst %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[OLD:.+]] = atomicrmw nand ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // LLVM-NEXT: %[[TMP:.+]] = and i32 %[[OLD]], %[[VAL]] + // LLVM-NEXT: %[[RES:.+]] = xor i32 %[[TMP]], -1 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[OLD:.+]] = atomicrmw nand ptr %{{.+}}, i32 %[[VAL:.+]] seq_cst, align 4 + // OGCG-NEXT: %[[TMP:.+]] = and i32 %[[OLD]], %[[VAL]] + // OGCG-NEXT: %[[RES:.+]] = xor i32 %[[TMP]], -1 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} + +int c11_atomic_fetch_nand(_Atomic(int) *ptr, int value) { + // CIR-LABEL: @c11_atomic_fetch_nand + // LLVM-LABEL: @c11_atomic_fetch_nand + // OGCG-LABEL: @c11_atomic_fetch_nand + + return __c11_atomic_fetch_nand(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch nand seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 + + // OGCG: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 +} diff --git a/clang/test/CIR/CodeGen/binassign.c b/clang/test/CIR/CodeGen/binassign.c index dab9879..44c54b4 100644 --- a/clang/test/CIR/CodeGen/binassign.c +++ b/clang/test/CIR/CodeGen/binassign.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before-lp.cir // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM @@ -54,3 +54,49 @@ void binary_assign(void) { // OGCG: store float 0x40091EB860000000, ptr %[[F_PTR]] // OGCG: store i32 42, ptr %[[I_PTR]] // OGCG: ret void + +struct S { + int a; + float b; +}; + +struct SV { + int a; + volatile float b; +}; + +struct S gs; +struct SV gsv; + +void binary_assign_struct() { + // Test normal struct assignment + struct S ls; + ls = gs; + + // Test assignment of a struct with a volatile member + struct SV lsv; + lsv = gsv; +} + +// CIR: cir.func{{.*}} @binary_assign_struct() +// CIR: %[[LS:.*]] = cir.alloca ![[REC_S:.*]], !cir.ptr<![[REC_S]]>, ["ls"] +// CIR: %[[LSV:.*]] = cir.alloca ![[REC_SV:.*]], !cir.ptr<![[REC_SV]]>, ["lsv"] +// CIR: %[[GS_PTR:.*]] = cir.get_global @gs : !cir.ptr<![[REC_S]]> +// CIR: cir.copy %[[GS_PTR]] to %[[LS]] : !cir.ptr<![[REC_S]]> +// CIR: %[[GSV_PTR:.*]] = cir.get_global @gsv : !cir.ptr<![[REC_SV]]> +// CIR: cir.copy %[[GSV_PTR]] to %[[LSV]] volatile : !cir.ptr<![[REC_SV]]> +// CIR: cir.return + +// LLVM: define {{.*}}void @binary_assign_struct() +// LLVM: %[[LS_PTR:.*]] = alloca %struct.S +// LLVM: %[[LSV_PTR:.*]] = alloca %struct.SV +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[LS_PTR]], ptr @gs, i32 8, i1 false) +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[LSV_PTR]], ptr @gsv, i32 8, i1 true) +// LLVM: ret void + +// OGCG: define {{.*}}void @binary_assign_struct() +// OGCG: %[[LS_PTR:.*]] = alloca %struct.S +// OGCG: %[[LSV_PTR:.*]] = alloca %struct.SV +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[LS_PTR]], ptr align 4 @gs, i64 8, i1 false) +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[LSV_PTR]], ptr align 4 @gsv, i64 8, i1 true) +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/builtin_inline.c b/clang/test/CIR/CodeGen/builtin_inline.c new file mode 100644 index 0000000..83a3ba6 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin_inline.c @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -disable-llvm-passes %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +typedef unsigned long size_t; + +// Normal inline builtin declaration +// When a builtin is redefined with extern inline + always_inline attributes, +// the compiler creates a .inline version to avoid conflicts with the builtin + +extern inline __attribute__((always_inline)) __attribute__((gnu_inline)) +void *memcpy(void *a, const void *b, size_t c) { + return __builtin_memcpy(a, b, c); +} + +void *test_inline_builtin_memcpy(void *a, const void *b, size_t c) { + return memcpy(a, b, c); +} + +// CIR: cir.func internal private{{.*}}@memcpy.inline({{.*}}) -> !cir.ptr<!void> inline(always) + +// CIR-LABEL: @test_inline_builtin_memcpy( +// CIR: cir.call @memcpy.inline( +// CIR: } + +// LLVM: define internal ptr @memcpy.inline(ptr{{.*}}, ptr{{.*}}, i64{{.*}}) #{{[0-9]+}} + +// LLVM-LABEL: @test_inline_builtin_memcpy( +// LLVM: call ptr @memcpy.inline( + +// OGCG-LABEL: @test_inline_builtin_memcpy( +// OGCG: call ptr @memcpy.inline( + +// OGCG: define internal ptr @memcpy.inline(ptr{{.*}} %a, ptr{{.*}} %b, i64{{.*}} %c) #{{[0-9]+}} + +// Shadowing case +// When a non-inline function definition shadows an inline builtin declaration, +// the .inline version should be replaced with the regular function and removed. + +extern inline __attribute__((always_inline)) __attribute__((gnu_inline)) +void *memmove(void *a, const void *b, size_t c) { + return __builtin_memmove(a, b, c); +} + +void *memmove(void *a, const void *b, size_t c) { + char *dst = (char *)a; + const char *src = (const char *)b; + if (dst < src) { + for (size_t i = 0; i < c; i++) { + dst[i] = src[i]; + } + } else { + for (size_t i = c; i > 0; i--) { + dst[i-1] = src[i-1]; + } + } + return a; +} + +void *test_shadowed_memmove(void *a, const void *b, size_t c) { + return memmove(a, b, c); +} + +// CIR: cir.func{{.*}}@memmove({{.*}}) -> !cir.ptr<!void>{{.*}}{ +// CIR-NOT: @memmove.inline + +// CIR-LABEL: @test_shadowed_memmove( +// CIR: cir.call @memmove( +// CIR-NOT: @memmove.inline +// CIR: } + +// LLVM: define dso_local ptr @memmove(ptr{{.*}}, ptr{{.*}}, i64{{.*}}) #{{[0-9]+}} +// LLVM-NOT: @memmove.inline + +// LLVM-LABEL: @test_shadowed_memmove( +// TODO - this deviation from OGCG is expected until we implement the nobuiltin +// attribute. See CIRGenFunction::emitDirectCallee +// LLVM: call ptr @memmove( +// LLVM-NOT: @memmove.inline +// LLVM: } + +// OGCG: define dso_local ptr @memmove(ptr{{.*}} %a, ptr{{.*}} %b, i64{{.*}} %c) #{{[0-9]+}} +// OGCG-NOT: @memmove.inline + +// OGCG-LABEL: @test_shadowed_memmove( +// OGCG: call void @llvm.memmove.p0.p0.i64( +// OGCG-NOT: @memmove.inline +// OGCG: } diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 083d438..4e89af4 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1360,6 +1360,30 @@ void complex_type_argument() { // OGCG: %[[TMP_ARG:.*]] = load <2 x float>, ptr %[[ARG_ADDR]], align 4 // OGCG: call void @_Z22complex_type_parameterCf(<2 x float> noundef %[[TMP_ARG]]) +float _Complex complex_type_return_type() { + return { 1.0f, 2.0f }; +} + +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["__retval"] +// CIR: %[[RET_VAL:.*]] = cir.const #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float> : !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[RET_VAL]], %[[RET_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: cir.return %[[TMP_RET]] : !cir.complex<!cir.float> + +// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering, +// LLVM: %[[RET_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } { float 1.000000e+00, float 2.000000e+00 }, ptr %[[RET_ADDR]], align 4 +// LLVM: %[[TMP_RET:.*]] = load { float, float }, ptr %[[RET_ADDR]], align 4 +// LLVM: ret { float, float } %[[TMP_RET]] + +// OGCG: %[[RET_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[RET_VAL_REAL:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RET_ADDR]], i32 0, i32 0 +// OGCG: %[[RET_VAL_IMAG:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RET_ADDR]], i32 0, i32 1 +// OGCG: store float 1.000000e+00, ptr %[[RET_VAL_REAL]], align 4 +// OGCG: store float 2.000000e+00, ptr %[[RET_VAL_IMAG]], align 4 +// OGCG: %[[TMP_RET:.*]] = load <2 x float>, ptr %[[RET_ADDR]], align 4 +// OGCG: ret <2 x float> %[[TMP_RET]] + void real_on_scalar_bool() { bool a; bool b = __real__ a; @@ -1405,3 +1429,42 @@ void imag_on_scalar_bool() { // OGCG: %[[A_ADDR:.*]] = alloca i8, align 1 // OGCG: %[[B_ADDR:.*]] = alloca i8, align 1 // OGCG: store i8 0, ptr %[[B_ADDR]], align 1 + +void function_with_complex_default_arg( + float _Complex a = __builtin_complex(1.0f, 2.2f)) {} + +// CIR: %[[ARG_0_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: cir.store %{{.*}}, %[[ARG_0_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering, + +// LLVM: %[[ARG_0_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } %{{.*}}, ptr %[[ARG_0_ADDR]], align 4 + +// OGCG: %[[ARG_0_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: store <2 x float> %{{.*}}, ptr %[[ARG_0_ADDR]], align 4 + +void calling_function_with_default_arg() { + function_with_complex_default_arg(); +} + +// CIR: %[[DEFAULT_ARG_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["coerce"] +// CIR: %[[DEFAULT_ARG_VAL:.*]] = cir.const #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.200000e+00> : !cir.float> : !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[DEFAULT_ARG_VAL]], %[[DEFAULT_ARG_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[TMP_DEFAULT_ARG:.*]] = cir.load{{.*}} %[[DEFAULT_ARG_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: cir.call @_Z33function_with_complex_default_argCf(%[[TMP_DEFAULT_ARG]]) : (!cir.complex<!cir.float>) -> () + +// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering, + +// LLVM: %[[DEFAULT_ARG_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } { float 1.000000e+00, float 0x40019999A0000000 }, ptr %[[DEFAULT_ARG_ADDR]], align 4 +// LLVM: %[[TMP_DEFAULT_ARG:.*]] = load { float, float }, ptr %[[DEFAULT_ARG_ADDR]], align 4 +// LLVM: call void @_Z33function_with_complex_default_argCf({ float, float } %[[TMP_DEFAULT_ARG]]) + +// OGCG: %[[DEFAULT_ARG_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[DEFAULT_ARG_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DEFAULT_ARG_ADDR]], i32 0, i32 0 +// OGCG: %[[DEFAULT_ARG_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DEFAULT_ARG_ADDR]], i32 0, i32 1 +// OGCG: store float 1.000000e+00, ptr %[[DEFAULT_ARG_REAL_PTR]], align 4 +// OGCG: store float 0x40019999A0000000, ptr %[[DEFAULT_ARG_IMAG_PTR]], align 4 +// OGCG: %[[TMP_DEFAULT_ARG:.*]] = load <2 x float>, ptr %[[DEFAULT_ARG_ADDR]], align 4 +// OGCG: call void @_Z33function_with_complex_default_argCf(<2 x float> {{.*}} %[[TMP_DEFAULT_ARG]]) diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp index a92af95..30a1dc0 100644 --- a/clang/test/CIR/CodeGen/compound_literal.cpp +++ b/clang/test/CIR/CodeGen/compound_literal.cpp @@ -97,3 +97,30 @@ void foo3() { // OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[CL_ADDR]], align 16 // OGCG: store <4 x i32> %[[TMP]], ptr %[[A_ADDR]], align 16 +struct Point { + int x, y; +}; + +void foo4() { + Point p = (Point){5, 10}; +} + +// CIR-LABEL: @_Z4foo4v +// CIR: %[[P:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["p", init] +// CIR: %[[P_X:.*]] = cir.get_member %[[P]][0] {name = "x"} +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store{{.*}} %[[FIVE]], %[[P_X]] +// CIR: %[[P_Y:.*]] = cir.get_member %[[P]][1] {name = "y"} +// CIR: %[[TEN:.*]] = cir.const #cir.int<10> : !s32i +// CIR: cir.store{{.*}} %[[TEN]], %[[P_Y]] + +// LLVM-LABEL: @_Z4foo4v +// LLVM: %[[P:.*]] = alloca %struct.Point +// LLVM: %[[P_X:.*]] = getelementptr %struct.Point, ptr %[[P]], i32 0, i32 0 +// LLVM: store i32 5, ptr %[[P_X]] +// LLVM: %[[P_Y:.*]] = getelementptr %struct.Point, ptr %[[P]], i32 0, i32 1 +// LLVM: store i32 10, ptr %[[P_Y]] + +// OGCG-LABEL: @_Z4foo4v +// OGCG: %[[P:.*]] = alloca %struct.Point +// OGCG: call void @llvm.memcpy{{.*}}(ptr{{.*}} %[[P]], ptr{{.*}} @__const._Z4foo4v.p diff --git a/clang/test/CIR/CodeGen/dtors.cpp b/clang/test/CIR/CodeGen/dtors.cpp index cb3886b..1fe048b7 100644 --- a/clang/test/CIR/CodeGen/dtors.cpp +++ b/clang/test/CIR/CodeGen/dtors.cpp @@ -14,7 +14,7 @@ void test_temporary_dtor() { } // CIR: cir.func dso_local @_Z19test_temporary_dtorv() -// CIR: %[[ALLOCA:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["agg.tmp0"] +// CIR: %[[ALLOCA:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["agg.tmp.ensured"] // CIR: cir.call @_ZN1AD1Ev(%[[ALLOCA]]) nothrow : (!cir.ptr<!rec_A>) -> () // LLVM: define dso_local void @_Z19test_temporary_dtorv(){{.*}} @@ -35,7 +35,7 @@ bool make_temp(const B &) { return false; } bool test_temp_or() { return make_temp(1) || make_temp(2); } // CIR: cir.func{{.*}} @_Z12test_temp_orv() -// CIR: %[[SCOPE:.*]] = cir.scope { +// CIR: cir.scope { // CIR: %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"] // CIR: %[[ONE:.*]] = cir.const #cir.int<1> // CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]]) @@ -51,9 +51,9 @@ bool test_temp_or() { return make_temp(1) || make_temp(2); } // CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP1]]) // CIR: cir.yield %[[MAKE_TEMP1]] : !cir.bool // CIR: }) +// CIR: cir.store{{.*}} %[[TERNARY]], %[[RETVAL:.*]] // CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP0]]) -// CIR: cir.yield %[[TERNARY]] : !cir.bool -// CIR: } : !cir.bool +// CIR: } // LLVM: define{{.*}} i1 @_Z12test_temp_orv(){{.*}} { // LLVM: %[[REF_TMP0:.*]] = alloca %struct.B @@ -105,7 +105,7 @@ bool test_temp_or() { return make_temp(1) || make_temp(2); } bool test_temp_and() { return make_temp(1) && make_temp(2); } // CIR: cir.func{{.*}} @_Z13test_temp_andv() -// CIR: %[[SCOPE:.*]] = cir.scope { +// CIR: cir.scope { // CIR: %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"] // CIR: %[[ONE:.*]] = cir.const #cir.int<1> // CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]]) @@ -121,9 +121,9 @@ bool test_temp_and() { return make_temp(1) && make_temp(2); } // CIR: %[[FALSE:.*]] = cir.const #false // CIR: cir.yield %[[FALSE]] : !cir.bool // CIR: }) +// CIR: cir.store{{.*}} %[[TERNARY]], %[[RETVAL:.*]] // CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP0]]) -// CIR: cir.yield %[[TERNARY]] : !cir.bool -// CIR: } : !cir.bool +// CIR: } // LLVM: define{{.*}} i1 @_Z13test_temp_andv(){{.*}} { // LLVM: %[[REF_TMP0:.*]] = alloca %struct.B diff --git a/clang/test/CIR/CodeGen/lambda.cpp b/clang/test/CIR/CodeGen/lambda.cpp index 0c32ceb1..91380b9 100644 --- a/clang/test/CIR/CodeGen/lambda.cpp +++ b/clang/test/CIR/CodeGen/lambda.cpp @@ -219,14 +219,13 @@ int f() { // CIR: cir.func dso_local @_Z1fv() -> !s32i {{.*}} { // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] -// CIR: %[[SCOPE_RET:.*]] = cir.scope { +// CIR: cir.scope { // CIR: %[[TMP:.*]] = cir.alloca ![[REC_LAM_G2]], !cir.ptr<![[REC_LAM_G2]]>, ["ref.tmp0"] // CIR: %[[G2:.*]] = cir.call @_Z2g2v() : () -> ![[REC_LAM_G2]] // CIR: cir.store{{.*}} %[[G2]], %[[TMP]] // CIR: %[[RESULT:.*]] = cir.call @_ZZ2g2vENK3$_0clEv(%[[TMP]]) -// CIR: cir.yield %[[RESULT]] +// CIR: cir.store{{.*}} %[[RESULT]], %[[RETVAL]] // CIR: } -// CIR: cir.store{{.*}} %[[SCOPE_RET]], %[[RETVAL]] // CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL]] // CIR: cir.return %[[RET]] @@ -255,10 +254,9 @@ int f() { // LLVM: %[[G2:.*]] = call %[[REC_LAM_G2]] @_Z2g2v() // LLVM: store %[[REC_LAM_G2]] %[[G2]], ptr %[[TMP]] // LLVM: %[[RESULT:.*]] = call i32 @"_ZZ2g2vENK3$_0clEv"(ptr %[[TMP]]) +// LLVM: store i32 %[[RESULT]], ptr %[[RETVAL]] // LLVM: br label %[[RET_BB:.*]] // LLVM: [[RET_BB]]: -// LLVM: %[[RETPHI:.*]] = phi i32 [ %[[RESULT]], %[[SCOPE_BB]] ] -// LLVM: store i32 %[[RETPHI]], ptr %[[RETVAL]] // LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] // LLVM: ret i32 %[[RET]] @@ -333,14 +331,13 @@ struct A { // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] // CIR: %[[THIS]] = cir.load deref %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> -// CIR: %[[SCOPE_RET:.*]] = cir.scope { +// CIR: cir.scope { // CIR: %[[LAM_ADDR:.*]] = cir.alloca ![[REC_LAM_A]], !cir.ptr<![[REC_LAM_A]]>, ["ref.tmp0"] // CIR: %[[STRUCT_A:.*]] = cir.get_member %[[LAM_ADDR]][0] {name = "this"} : !cir.ptr<![[REC_LAM_A]]> -> !cir.ptr<!rec_A> // CIR: cir.call @_ZN1AC1ERKS_(%[[STRUCT_A]], %[[THIS]]){{.*}} : (!cir.ptr<!rec_A>, !cir.ptr<!rec_A>){{.*}} -> () // CIR: %[[LAM_RET:.*]] = cir.call @_ZZN1A3fooEvENKUlvE_clEv(%[[LAM_ADDR]]) -// CIR: cir.yield %[[LAM_RET]] +// CIR: cir.store{{.*}} %[[LAM_RET]], %[[RETVAL]] // CIR: } -// CIR: cir.store{{.*}} %[[SCOPE_RET]], %[[RETVAL]] // CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL]] // CIR: cir.return %[[RET]] @@ -355,10 +352,9 @@ struct A { // LLVM: %[[STRUCT_A:.*]] = getelementptr %[[REC_LAM_A]], ptr %[[LAM_ALLOCA]], i32 0, i32 0 // LLVM: call void @_ZN1AC1ERKS_(ptr %[[STRUCT_A]], ptr %[[THIS]]) // LLVM: %[[LAM_RET:.*]] = call i32 @_ZZN1A3fooEvENKUlvE_clEv(ptr %[[LAM_ALLOCA]]) +// LLVM: store i32 %[[LAM_RET]], ptr %[[RETVAL]] // LLVM: br label %[[RET_BB:.*]] // LLVM: [[RET_BB]]: -// LLVM: %[[RETPHI:.*]] = phi i32 [ %[[LAM_RET]], %[[SCOPE_BB]] ] -// LLVM: store i32 %[[RETPHI]], ptr %[[RETVAL]] // LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] // LLVM: ret i32 %[[RET]] @@ -407,14 +403,13 @@ struct A { // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] // CIR: %[[THIS]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> -// CIR: %[[SCOPE_RET:.*]] = cir.scope { +// CIR: cir.scope { // CIR: %[[LAM_ADDR:.*]] = cir.alloca ![[REC_LAM_PTR_A]], !cir.ptr<![[REC_LAM_PTR_A]]>, ["ref.tmp0"] // CIR: %[[A_ADDR_ADDR:.*]] = cir.get_member %[[LAM_ADDR]][0] {name = "this"} : !cir.ptr<![[REC_LAM_PTR_A]]> -> !cir.ptr<!cir.ptr<!rec_A>> // CIR: cir.store{{.*}} %[[THIS]], %[[A_ADDR_ADDR]] // CIR: %[[LAM_RET:.*]] = cir.call @_ZZN1A3barEvENKUlvE_clEv(%[[LAM_ADDR]]) -// CIR: cir.yield %[[LAM_RET]] +// CIR: cir.store{{.*}} %[[LAM_RET]], %[[RETVAL]] // CIR: } -// CIR: cir.store{{.*}} %[[SCOPE_RET]], %[[RETVAL]] // CIR: %[[RET:.*]] = cir.load{{.*}} %[[RETVAL]] // CIR: cir.return %[[RET]] @@ -429,10 +424,9 @@ struct A { // LLVM: %[[A_ADDR_ADDR:.*]] = getelementptr %[[REC_LAM_PTR_A]], ptr %[[LAM_ALLOCA]], i32 0, i32 0 // LLVM: store ptr %[[THIS]], ptr %[[A_ADDR_ADDR]] // LLVM: %[[LAM_RET:.*]] = call i32 @_ZZN1A3barEvENKUlvE_clEv(ptr %[[LAM_ALLOCA]]) +// LLVM: store i32 %[[LAM_RET]], ptr %[[RETVAL]] // LLVM: br label %[[RET_BB:.*]] // LLVM: [[RET_BB]]: -// LLVM: %[[RETPHI:.*]] = phi i32 [ %[[LAM_RET]], %[[SCOPE_BB]] ] -// LLVM: store i32 %[[RETPHI]], ptr %[[RETVAL]] // LLVM: %[[RET:.*]] = load i32, ptr %[[RETVAL]] // LLVM: ret i32 %[[RET]] diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 000ea5b..2efad10 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -208,6 +208,127 @@ void t_new_constant_size() { // OGCG: %[[CALL:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 128) // OGCG: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8 +class C { + public: + ~C(); +}; + +void t_constant_size_nontrivial() { + auto p = new C[3]; +} + +// CHECK: cir.func{{.*}} @_Z26t_constant_size_nontrivialv() +// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["p", init] {alignment = 8 : i64} +// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i +// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<3> : !u64i +// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<11> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> +// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> +// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_C> +// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>> +// CHECK: cir.return +// CHECK: } + +// LLVM: @_Z26t_constant_size_nontrivialv() +// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[COOKIE_PTR:.*]] = call ptr @_Znam(i64 11) +// LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8 +// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8 +// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 + +// OGCG: @_Z26t_constant_size_nontrivialv() +// OGCG: %[[ALLOCA:.*]] = alloca ptr, align 8 +// OGCG: %[[COOKIE_PTR:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 11) +// OGCG: store i64 3, ptr %[[COOKIE_PTR]], align 8 +// OGCG: %[[ALLOCATED_PTR:.*]] = getelementptr inbounds i8, ptr %[[COOKIE_PTR]], i64 8 +// OGCG: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 + +class D { + public: + int x; + ~D(); +}; + +void t_constant_size_nontrivial2() { + auto p = new D[3]; +} + +// In this test SIZE_WITHOUT_COOKIE isn't used, but it would be if there were +// an initializer. + +// CHECK: cir.func{{.*}} @_Z27t_constant_size_nontrivial2v() +// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>>, ["p", init] {alignment = 8 : i64} +// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i +// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<12> : !u64i +// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<20> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> +// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> +// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_D> +// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>> +// CHECK: cir.return +// CHECK: } + +// LLVM: @_Z27t_constant_size_nontrivial2v() +// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[COOKIE_PTR:.*]] = call ptr @_Znam(i64 20) +// LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8 +// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8 +// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 + +struct alignas(16) E { + int x; + ~E(); +}; + +void t_align16_nontrivial() { + auto p = new E[2]; +} + +// CHECK: cir.func{{.*}} @_Z20t_align16_nontrivialv() +// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>>, ["p", init] {alignment = 8 : i64} +// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<2> : !u64i +// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<32> : !u64i +// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<48> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[COOKIE_OFFSET:.*]] = cir.const #cir.int<8> : !s32i +// CHECK: %[[COOKIE_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_OFFSET]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> +// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<16> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> +// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_E> +// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>> +// CHECK: cir.return +// CHECK: } + +// LLVM: @_Z20t_align16_nontrivialv() +// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[RAW_PTR:.*]] = call ptr @_Znam(i64 48) +// LLVM: %[[COOKIE_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 8 +// LLVM: store i64 2, ptr %[[COOKIE_PTR]], align 8 +// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 16 +// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 + +// OGCG: define{{.*}} void @_Z20t_align16_nontrivialv +// OGCG: %[[ALLOCA:.*]] = alloca ptr, align 8 +// OGCG: %[[RAW_PTR:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 48) +// OGCG: %[[COOKIE_PTR:.*]] = getelementptr inbounds i8, ptr %[[RAW_PTR]], i64 8 +// OGCG: store i64 2, ptr %[[COOKIE_PTR]], align 8 +// OGCG: %[[ALLOCATED_PTR:.*]] = getelementptr inbounds i8, ptr %[[RAW_PTR]], i64 16 +// OGCG: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 +// OGCG: ret void void t_new_multidim_constant_size() { auto p = new double[2][3][4]; diff --git a/clang/test/CIR/CodeGen/opaque.cpp b/clang/test/CIR/CodeGen/opaque.cpp index 028bfd9..eac0dfa 100644 --- a/clang/test/CIR/CodeGen/opaque.cpp +++ b/clang/test/CIR/CodeGen/opaque.cpp @@ -154,3 +154,166 @@ void foo3() { // OGCG: [[COND_END]]: // OGCG: %[[RESULT:.*]] = phi i32 [ %[[TMP_A]], %[[COND_TRUE]] ], [ %[[TMP_B]], %[[COND_FALSE]] ] // OGCG: store i32 %[[RESULT]], ptr %[[C_ADDR]], align 4 + +void test_gnu_binary_lvalue_assign() { + int a = 5; + int b = 10; + (a ?: b) = 42; +} + +// CIR-LABEL: cir.func{{.*}} @_Z29test_gnu_binary_lvalue_assignv( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[A_VAL:.*]] = cir.load{{.*}} %[[A]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[A_BOOL:.*]] = cir.cast int_to_bool %[[A_VAL]] : !s32i -> !cir.bool +// CIR: %[[TERNARY_PTR:.*]] = cir.ternary(%[[A_BOOL]], true { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: cir.yield %[[B]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %{{.*}}, %[[TERNARY_PTR]] : !s32i, !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} void @_Z29test_gnu_binary_lvalue_assignv( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM: %[[A_VAL:.*]] = load i32, ptr %[[A]] +// LLVM: %[[COND:.*]] = icmp ne i32 %[[A_VAL]], 0 +// LLVM: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PHI_PTR:.*]] = phi ptr [ %[[B]], %[[FALSE_BB]] ], [ %[[A]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT_BB:.*]] +// LLVM: [[CONT_BB]]: +// LLVM: store i32 42, ptr %[[PHI_PTR]] + +// OGCG-LABEL: define{{.*}} void @_Z29test_gnu_binary_lvalue_assignv( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A]] +// OGCG: %[[COND:.*]] = icmp ne i32 %[[A_VAL]], 0 +// OGCG: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PHI_PTR:.*]] = phi ptr [ %[[A]], %[[TRUE_BB]] ], [ %[[B]], %[[FALSE_BB]] ] +// OGCG: store i32 42, ptr %[[PHI_PTR]] + +void test_gnu_binary_lvalue_compound() { + int a = 7; + int b = 14; + (a ?: b) += 5; +} + +// CIR-LABEL: cir.func{{.*}} @_Z31test_gnu_binary_lvalue_compoundv( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[A_VAL:.*]] = cir.load{{.*}} %[[A]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[A_BOOL:.*]] = cir.cast int_to_bool %[[A_VAL]] : !s32i -> !cir.bool +// CIR: %[[LVAL_PTR:.*]] = cir.ternary(%[[A_BOOL]], true { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: cir.yield %[[B]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: %[[OLD_VAL:.*]] = cir.load{{.*}} %[[LVAL_PTR]] +// CIR: %[[NEW_VAL:.*]] = cir.binop(add, %[[OLD_VAL]], %{{.*}}) +// CIR: cir.store{{.*}} %[[NEW_VAL]], %[[LVAL_PTR]] + +// LLVM-LABEL: define{{.*}} void @_Z31test_gnu_binary_lvalue_compoundv( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM: %[[A_VAL:.*]] = load i32, ptr %[[A]] +// LLVM: %[[COND:.*]] = icmp ne i32 %[[A_VAL]], 0 +// LLVM: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PTR:.*]] = phi ptr [ %[[B]], %[[FALSE_BB]] ], [ %[[A]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT:.*]] +// LLVM: [[CONT]]: +// LLVM: %[[OLD:.*]] = load i32, ptr %[[PTR]] +// LLVM: %[[NEW:.*]] = add{{.*}} i32 %[[OLD]], 5 +// LLVM: store i32 %[[NEW]], ptr %[[PTR]] + +// OGCG-LABEL: define{{.*}} void @_Z31test_gnu_binary_lvalue_compoundv( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG: %[[A_VAL:.*]] = load i32, ptr %[[A]] +// OGCG: %[[COND:.*]] = icmp ne i32 %[[A_VAL]], 0 +// OGCG: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PTR:.*]] = phi ptr [ %[[A]], %[[TRUE_BB]] ], [ %[[B]], %[[FALSE_BB]] ] +// OGCG: %[[OLD:.*]] = load i32, ptr %[[PTR]] +// OGCG: %[[NEW:.*]] = add{{.*}} i32 %[[OLD]], 5 +// OGCG: store i32 %[[NEW]], ptr %[[PTR]] + +void test_gnu_binary_lvalue_ptr() { + int x = 1, y = 2; + int *p = &x; + int *q = nullptr; + *(p ?: q) = 99; +} + +// CIR-LABEL: cir.func{{.*}} @_Z26test_gnu_binary_lvalue_ptrv( +// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// CIR: %[[Y:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] +// CIR: %[[P:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p", init] +// CIR: %[[Q:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["q", init] +// CIR: %[[P_VAL:.*]] = cir.load{{.*}} %[[P]] +// CIR: %[[P_BOOL:.*]] = cir.cast ptr_to_bool %[[P_VAL]] +// CIR: %[[PTR_RESULT:.*]] = cir.ternary(%[[P_BOOL]], true { +// CIR: %[[P_LOAD:.*]] = cir.load{{.*}} %[[P]] +// CIR: cir.yield %[[P_LOAD]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: %[[Q_LOAD:.*]] = cir.load{{.*}} %[[Q]] +// CIR: cir.yield %[[Q_LOAD]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %{{.*}}, %[[PTR_RESULT]] + +// LLVM-LABEL: define{{.*}} void @_Z26test_gnu_binary_lvalue_ptrv( +// LLVM: %[[X:.*]] = alloca i32 +// LLVM: %[[Y:.*]] = alloca i32 +// LLVM: %[[P:.*]] = alloca ptr +// LLVM: %[[Q:.*]] = alloca ptr +// LLVM: %[[P_VAL:.*]] = load ptr, ptr %[[P]] +// LLVM: %[[COND:.*]] = icmp ne ptr %[[P_VAL]], null +// LLVM: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: %[[P_LOAD:.*]] = load ptr, ptr %[[P]] +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: %[[Q_LOAD:.*]] = load ptr, ptr %[[Q]] +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PHI:.*]] = phi ptr [ %[[Q_LOAD]], %[[FALSE_BB]] ], [ %[[P_LOAD]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT:.*]] +// LLVM: [[CONT]]: +// LLVM: store i32 99, ptr %[[PHI]] + +// OGCG-LABEL: define{{.*}} void @_Z26test_gnu_binary_lvalue_ptrv( +// OGCG: %[[X:.*]] = alloca i32 +// OGCG: %[[Y:.*]] = alloca i32 +// OGCG: %[[P:.*]] = alloca ptr +// OGCG: %[[Q:.*]] = alloca ptr +// OGCG: %[[P_VAL:.*]] = load ptr, ptr %[[P]] +// OGCG: %[[COND:.*]] = icmp ne ptr %[[P_VAL]], null +// OGCG: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: %[[P_LOAD:.*]] = load ptr, ptr %[[P]] +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: %[[Q_LOAD:.*]] = load ptr, ptr %[[Q]] +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PHI:.*]] = phi ptr [ %[[P_LOAD]], %[[TRUE_BB]] ], [ %[[Q_LOAD]], %[[FALSE_BB]] ] +// OGCG: store i32 99, ptr %[[PHI]] diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c index f6ec9ec..c784ec9 100644 --- a/clang/test/CIR/CodeGen/statement-exprs.c +++ b/clang/test/CIR/CodeGen/statement-exprs.c @@ -218,7 +218,7 @@ struct S { int x; }; int test3() { return ({ struct S s = {1}; s; }).x; } // CIR: cir.func no_proto dso_local @test3() -> !s32i // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] -// CIR: %[[YIELDVAL:.+]] = cir.scope { +// CIR: cir.scope { // CIR: %[[REF_TMP0:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["ref.tmp0"] // CIR: %[[TMP:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["tmp"] // CIR: cir.scope { @@ -230,9 +230,8 @@ int test3() { return ({ struct S s = {1}; s; }).x; } // CIR: } // CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i> // CIR: %[[XVAL:.+]] = cir.load {{.*}} %[[GEP_X_TMP]] : !cir.ptr<!s32i>, !s32i -// CIR: cir.yield %[[XVAL]] : !s32i -// CIR: } : !s32i -// CIR: cir.store %[[YIELDVAL]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[XVAL]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: } // CIR: %[[RES:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i // CIR: cir.return %[[RES]] : !s32i @@ -252,10 +251,9 @@ int test3() { return ({ struct S s = {1}; s; }).x; } // LLVM: [[LBL8]]: // LLVM: %[[GEP_VAR1:.+]] = getelementptr %struct.S, ptr %[[VAR1]], i32 0, i32 0 // LLVM: %[[LOAD_X:.+]] = load i32, ptr %[[GEP_VAR1]] +// LLVM: store i32 %[[LOAD_X]], ptr %[[VAR4]] // LLVM: br label %[[LBL11:.+]] // LLVM: [[LBL11]]: -// LLVM: %[[PHI:.+]] = phi i32 [ %[[LOAD_X]], %[[LBL8]] ] -// LLVM: store i32 %[[PHI]], ptr %[[VAR4]] // LLVM: %[[RES:.+]] = load i32, ptr %[[VAR4]] // LLVM: ret i32 %[[RES]] diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp index a47ef53..cb50999 100644 --- a/clang/test/CIR/CodeGen/struct-init.cpp +++ b/clang/test/CIR/CodeGen/struct-init.cpp @@ -9,6 +9,22 @@ struct S { int a, b, c; }; +S partial_init = { 1 }; + +// CIR: cir.global external @partial_init = #cir.const_record<{#cir.int<1> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : !s32i}> : !rec_S +// LLVM: @partial_init = global %struct.S { i32 1, i32 0, i32 0 } +// OGCG: @partial_init = global %struct.S { i32 1, i32 0, i32 0 } + +struct StructWithDefaultInit { + int a = 2; +}; + +StructWithDefaultInit swdi = {}; + +// CIR: cir.global external @swdi = #cir.const_record<{#cir.int<2> : !s32i}> : !rec_StructWithDefaultInit +// LLVM: @swdi = global %struct.StructWithDefaultInit { i32 2 }, align 4 +// OGCG: @swdi = global %struct.StructWithDefaultInit { i32 2 }, align 4 + void init() { S s1 = {1, 2, 3}; S s2 = {4, 5}; diff --git a/clang/test/CIR/CodeGen/struct.cpp b/clang/test/CIR/CodeGen/struct.cpp index 263799f..c8db714 100644 --- a/clang/test/CIR/CodeGen/struct.cpp +++ b/clang/test/CIR/CodeGen/struct.cpp @@ -265,7 +265,7 @@ void bin_comma() { // CIR: cir.func{{.*}} @_Z9bin_commav() // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] -// CIR: %[[TMP_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["agg.tmp0"] +// CIR: %[[TMP_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["agg.tmp.ensured"] // CIR: %[[ZERO:.*]] = cir.const #cir.zero : !rec_CompleteS // CIR: cir.store{{.*}} %[[ZERO]], %[[TMP_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> // CIR: %[[ZERO:.*]] = cir.const #cir.zero : !rec_CompleteS @@ -280,3 +280,67 @@ void bin_comma() { // OGCG: define{{.*}} void @_Z9bin_commav() // OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 // OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false) + +void compound_literal_expr() { CompleteS a = (CompleteS){}; } + +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] +// CIR: %[[A_ELEM_0_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[A_ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[A_ELEM_1_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s8i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[A_ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i> + +// TODO(cir): zero-initialize the padding + +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: %[[A_ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0 +// LLVM: store i32 0, ptr %[[A_ELEM_0_PTR]], align 4 +// LLVM: %[[A_ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1 +// LLVM: store i8 0, ptr %[[A_ELEM_1_PTR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false) + +struct StructWithConstMember { + int a : 1; +}; + +void struct_with_const_member_expr() { + int a = (StructWithConstMember){}.a; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[RESULT:.*]] = cir.scope { +// CIR: %[[REF_ADDR:.*]] = cir.alloca !rec_StructWithConstMember, !cir.ptr<!rec_StructWithConstMember>, ["ref.tmp0"] +// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[REF_ADDR]][0] {name = "a"} : !cir.ptr<!rec_StructWithConstMember> -> !cir.ptr<!u8i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: %[[SET_BF:.*]] = cir.set_bitfield{{.*}} (#bfi_a, %[[ELEM_0_PTR]] : !cir.ptr<!u8i>, %[[CONST_0]] : !s32i) -> !s32i +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.yield %[[CONST_0]] : !s32i +// CIR: } : !s32i +// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> + +// TODO(cir): zero-initialize the padding + +// LLVM: %[[REF_ADDR:.*]] = alloca %struct.StructWithConstMember, i64 1, align 4 +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: br label %[[BF_LABEL:.*]] +// LLVM: [[BF_LABEL]]: +// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.StructWithConstMember, ptr %[[REF_ADDR]], i32 0, i32 0 +// LLVM: %[[TMP_REF:.*]] = load i8, ptr %[[ELEM_0_PTR]], align 4 +// LLVM: %[[BF_CLEAR:.*]] = and i8 %[[TMP_REF]], -2 +// LLVM: %[[BF_SET:.*]] = or i8 %[[BF_CLEAR]], 0 +// LLVM: store i8 %[[BF_SET]], ptr %[[ELEM_0_PTR]], align 4 +// LLVM: br label %[[RESULT_LABEL:.*]] +// LLVM: [[RESULT_LABEL]]: +// LLVM: %[[RESULT:.*]] = phi i32 [ 0, %[[BF_LABEL]] ] +// LLVM: store i32 %[[RESULT]], ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[REF_ADDR:.*]] = alloca %struct.StructWithConstMember, align 4 +// OGCG: %[[TMP_REF:.*]] = load i8, ptr %[[REF_ADDR]], align 4 +// OGCG: %[[BF_CLEAR:.*]] = and i8 %[[TMP_REF]], -2 +// OGCG: %[[BF_SET:.*]] = or i8 %[[BF_CLEAR]], 0 +// OGCG: store i8 %[[BF_SET]], ptr %[[REF_ADDR]], align 4 +// OGCG: store i32 0, ptr %[[A_ADDR]], align 4 diff --git a/clang/test/CIR/CodeGen/ternary-throw.cpp b/clang/test/CIR/CodeGen/ternary-throw.cpp new file mode 100644 index 0000000..fb8897f --- /dev/null +++ b/clang/test/CIR/CodeGen/ternary-throw.cpp @@ -0,0 +1,197 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fexceptions -fcxx-exceptions -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fexceptions -fcxx-exceptions -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +const int& test_cond_throw_false(bool flag) { + const int a = 10; + return flag ? a : throw 0; +} + +// CIR-LABEL: cir.func{{.*}} @_Z21test_cond_throw_falseb( +// CIR: %[[FLAG:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["flag", init] +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init, const] +// CIR: %[[TEN:.*]] = cir.const #cir.int<10> : !s32i +// CIR: cir.store{{.*}} %[[TEN]], %[[A]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] : !cir.ptr<!cir.bool>, !cir.bool +// CIR: %[[RESULT:.*]] = cir.ternary(%[[FLAG_VAL]], true { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: %[[EXCEPTION:.*]] = cir.alloc.exception{{.*}} -> !cir.ptr<!s32i> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[ZERO]], %[[EXCEPTION]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.throw %[[EXCEPTION]] : !cir.ptr<!s32i>, @_ZTIi +// CIR: cir.unreachable +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z21test_cond_throw_falseb( +// LLVM: %[[FLAG_ALLOCA:.*]] = alloca i8 +// LLVM: %[[RET_ALLOCA:.*]] = alloca ptr +// LLVM: %[[A_ALLOCA:.*]] = alloca i32 +// LLVM: %[[ZEXT:.*]] = zext i1 %{{.*}} to i8 +// LLVM: store i8 %[[ZEXT]], ptr %[[FLAG_ALLOCA]] +// LLVM: store i32 10, ptr %[[A_ALLOCA]] +// LLVM: %[[LOAD:.*]] = load i8, ptr %[[FLAG_ALLOCA]] +// LLVM: %[[BOOL:.*]] = trunc i8 %[[LOAD]] to i1 +// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[PHI_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception +// LLVM: store i32 0, ptr %[[EXC]] +// LLVM: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi +// LLVM: unreachable +// LLVM: [[PHI_BB]]: +// LLVM: %[[PHI:.*]] = phi ptr [ %[[A_ALLOCA]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT_BB:.*]] +// LLVM: [[CONT_BB]]: +// LLVM: store ptr %[[A_ALLOCA]], ptr %[[RET_ALLOCA]] +// LLVM: %[[RET:.*]] = load ptr, ptr %[[RET_ALLOCA]] +// LLVM: ret ptr %[[RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z21test_cond_throw_falseb( +// OGCG: %{{.*}} = alloca i8 +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: store i32 10, ptr %[[A]] +// OGCG: %{{.*}} = load i8, ptr %{{.*}} +// OGCG: %[[BOOL:.*]] = trunc i8 %{{.*}} to i1 +// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[END:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: %{{.*}} = call{{.*}} ptr @__cxa_allocate_exception +// OGCG: store i32 0, ptr %{{.*}} +// OGCG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIi +// OGCG: unreachable +// OGCG: [[END]]: +// OGCG: ret ptr %[[A]] + +const int& test_cond_throw_true(bool flag) { + const int a = 10; + return flag ? throw 0 : a; +} + +// CIR-LABEL: cir.func{{.*}} @_Z20test_cond_throw_trueb( +// CIR: %[[FLAG:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["flag", init] +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init, const] +// CIR: %[[TEN:.*]] = cir.const #cir.int<10> : !s32i +// CIR: cir.store{{.*}} %[[TEN]], %[[A]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] : !cir.ptr<!cir.bool>, !cir.bool +// CIR: %[[RESULT:.*]] = cir.ternary(%[[FLAG_VAL]], true { +// CIR: %[[EXCEPTION:.*]] = cir.alloc.exception{{.*}} -> !cir.ptr<!s32i> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[ZERO]], %[[EXCEPTION]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.throw %[[EXCEPTION]] : !cir.ptr<!s32i>, @_ZTIi +// CIR: cir.unreachable +// CIR: }, false { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z20test_cond_throw_trueb( +// LLVM: %[[FLAG_ALLOCA:.*]] = alloca i8 +// LLVM: %[[RET_ALLOCA:.*]] = alloca ptr +// LLVM: %[[A_ALLOCA:.*]] = alloca i32 +// LLVM: %[[ZEXT:.*]] = zext i1 %{{.*}} to i8 +// LLVM: store i8 %[[ZEXT]], ptr %[[FLAG_ALLOCA]] +// LLVM: store i32 10, ptr %[[A_ALLOCA]] +// LLVM: %[[LOAD:.*]] = load i8, ptr %[[FLAG_ALLOCA]] +// LLVM: %[[BOOL:.*]] = trunc i8 %[[LOAD]] to i1 +// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception +// LLVM: store i32 0, ptr %[[EXC]] +// LLVM: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi +// LLVM: unreachable +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[PHI_BB:.*]] +// LLVM: [[PHI_BB]]: +// LLVM: %[[PHI:.*]] = phi ptr [ %[[A_ALLOCA]], %[[FALSE_BB]] ] +// LLVM: br label %[[CONT_BB:.*]] +// LLVM: [[CONT_BB]]: +// LLVM: store ptr %[[A_ALLOCA]], ptr %[[RET_ALLOCA]] +// LLVM: %[[RET:.*]] = load ptr, ptr %[[RET_ALLOCA]] +// LLVM: ret ptr %[[RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z20test_cond_throw_trueb( +// OGCG: %{{.*}} = alloca i8 +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: store i32 10, ptr %[[A]] +// OGCG: %{{.*}} = load i8, ptr %{{.*}} +// OGCG: %[[BOOL:.*]] = trunc i8 %{{.*}} to i1 +// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: %{{.*}} = call{{.*}} ptr @__cxa_allocate_exception +// OGCG: store i32 0, ptr %{{.*}} +// OGCG: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTIi +// OGCG: unreachable +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[END:.*]] +// OGCG: [[END]]: +// OGCG: ret ptr %[[A]] + +// Test constant folding with throw - compile-time true condition, dead throw in false branch +const int& test_cond_const_true_throw_false() { + const int a = 20; + return true ? a : throw 0; +} + +// CIR-LABEL: cir.func{{.*}} @_Z32test_cond_const_true_throw_falsev( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init, const] +// CIR: %[[TWENTY:.*]] = cir.const #cir.int<20> : !s32i +// CIR: cir.store{{.*}} %[[TWENTY]], %[[A]] : !s32i, !cir.ptr<!s32i> +// CIR-NOT: cir.ternary +// CIR-NOT: cir.throw +// CIR: cir.store %[[A]] +// CIR: %[[RET:.*]] = cir.load +// CIR: cir.return %[[RET]] : !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z32test_cond_const_true_throw_falsev( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: store i32 20, ptr %[[A]] +// LLVM-NOT: br i1 +// LLVM-NOT: __cxa_throw +// LLVM: store ptr %[[A]] +// LLVM: %[[RET:.*]] = load ptr +// LLVM: ret ptr %[[RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z32test_cond_const_true_throw_falsev( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: store i32 20, ptr %[[A]] +// OGCG-NOT: br i1 +// OGCG-NOT: __cxa_throw +// OGCG: ret ptr %[[A]] + +// Test constant folding with throw - compile-time false condition, dead throw in true branch +const int& test_cond_const_false_throw_true() { + const int a = 30; + return false ? throw 0 : a; +} + +// CIR-LABEL: cir.func{{.*}} @_Z32test_cond_const_false_throw_truev( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init, const] +// CIR: %[[THIRTY:.*]] = cir.const #cir.int<30> : !s32i +// CIR: cir.store{{.*}} %[[THIRTY]], %[[A]] : !s32i, !cir.ptr<!s32i> +// CIR-NOT: cir.ternary +// CIR-NOT: cir.throw +// CIR: cir.store %[[A]] +// CIR: %[[RET:.*]] = cir.load +// CIR: cir.return %[[RET]] : !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z32test_cond_const_false_throw_truev( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: store i32 30, ptr %[[A]] +// LLVM-NOT: br i1 +// LLVM-NOT: __cxa_throw +// LLVM: store ptr %[[A]] +// LLVM: %[[RET:.*]] = load ptr +// LLVM: ret ptr %[[RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z32test_cond_const_false_throw_truev( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: store i32 30, ptr %[[A]] +// OGCG-NOT: br i1 +// OGCG-NOT: __cxa_throw +// OGCG: ret ptr %[[A]] + diff --git a/clang/test/CIR/CodeGen/ternary.cpp b/clang/test/CIR/CodeGen/ternary.cpp index e7b7270..847c0b4 100644 --- a/clang/test/CIR/CodeGen/ternary.cpp +++ b/clang/test/CIR/CodeGen/ternary.cpp @@ -10,11 +10,11 @@ int x(int y) { } // CIR-LABEL: cir.func{{.*}} @_Z1xi( -// CIR-SAME: %[[ARG0:.*]]: !s32i {{.*}}) -> !s32i -// CIR: [[Y:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] {alignment = 4 : i64} -// CIR: [[RETVAL:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64} +// CIR-SAME: %[[ARG0:.*]]: !s32i {{.*}}) -> !s32i{{.*}}{ +// CIR: [[Y:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] +// CIR: [[RETVAL:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[ARG0]], [[Y]] : !s32i, !cir.ptr<!s32i> -// CIR: [[YVAL:%.+]] = cir.load align(4) [[Y]] : !cir.ptr<!s32i>, !s32i +// CIR: [[YVAL:%.+]] = cir.load{{.*}} [[Y]] : !cir.ptr<!s32i>, !s32i // CIR: [[ZERO:%.+]] = cir.const #cir.int<0> : !s32i // CIR: [[CMP:%.+]] = cir.cmp(gt, [[YVAL]], [[ZERO]]) : !s32i, !cir.bool // CIR: [[THREE:%.+]] = cir.const #cir.int<3> : !s32i @@ -52,21 +52,21 @@ int foo(int a, int b) { } // CIR-LABEL: cir.func{{.*}} @_Z3fooii( -// CIR-SAME: %[[ARG0:.*]]: !s32i {{.*}}, %[[ARG1:.*]]: !s32i {{.*}}) -> !s32i -// CIR: [[A:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64} -// CIR: [[B:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64} -// CIR: [[RETVAL:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64} +// CIR-SAME: %[[ARG0:.*]]: !s32i {{.*}}, %[[ARG1:.*]]: !s32i {{.*}}) -> !s32i{{.*}}{ +// CIR: [[A:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: [[B:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: [[RETVAL:%.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[ARG0]], [[A]] : !s32i, !cir.ptr<!s32i> // CIR: cir.store %[[ARG1]], [[B]] : !s32i, !cir.ptr<!s32i> // CIR: cir.scope { -// CIR: [[ALOAD:%.+]] = cir.load align(4) [[A]] : !cir.ptr<!s32i>, !s32i -// CIR: [[BLOAD:%.+]] = cir.load align(4) [[B]] : !cir.ptr<!s32i>, !s32i +// CIR: [[ALOAD:%.+]] = cir.load{{.*}} [[A]] : !cir.ptr<!s32i>, !s32i +// CIR: [[BLOAD:%.+]] = cir.load{{.*}} [[B]] : !cir.ptr<!s32i>, !s32i // CIR: [[CMP:%.+]] = cir.cmp(lt, [[ALOAD]], [[BLOAD]]) : !s32i, !cir.bool // CIR: [[TERNARY_RES:%.+]] = cir.ternary([[CMP]], true { // CIR: [[ZERO:%.+]] = cir.const #cir.int<0> : !s32i // CIR: cir.yield [[ZERO]] : !s32i // CIR: }, false { -// CIR: [[ALOAD2:%.+]] = cir.load align(4) [[A]] : !cir.ptr<!s32i>, !s32i +// CIR: [[ALOAD2:%.+]] = cir.load{{.*}} [[A]] : !cir.ptr<!s32i>, !s32i // CIR: cir.yield [[ALOAD2]] : !s32i // CIR: }) : (!cir.bool) -> !s32i // CIR: [[CAST:%.+]] = cir.cast int_to_bool [[TERNARY_RES]] : !s32i -> !cir.bool @@ -145,3 +145,214 @@ int foo(int a, int b) { // OGCG: [[RETURN]]: // OGCG: %[[RET2:.*]] = load i32, ptr %[[RETVAL]] // OGCG: ret i32 %[[RET2]] + +void test_cond_lvalue_assign(bool flag) { + int a = 1; + int b = 2; + (flag ? a : b) = 42; +} + +// CIR-LABEL: cir.func{{.*}} @_Z23test_cond_lvalue_assignb( +// CIR: %[[FLAG:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["flag", init] +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] +// CIR: %[[TERNARY_PTR:.*]] = cir.ternary(%[[FLAG_VAL]], true { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: cir.yield %[[B]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %{{.*}}, %[[TERNARY_PTR]] : !s32i, !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} void @_Z23test_cond_lvalue_assignb( +// LLVM: %[[FLAG:.*]] = alloca i8 +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM: %[[FLAG_VAL:.*]] = load i8, ptr %[[FLAG]] +// LLVM: %[[COND:.*]] = trunc i8 %[[FLAG_VAL]] to i1 +// LLVM: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PHI_PTR:.*]] = phi ptr [ %[[B]], %[[FALSE_BB]] ], [ %[[A]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT_BB:.*]] +// LLVM: [[CONT_BB]]: +// LLVM: store i32 42, ptr %[[PHI_PTR]] + +// OGCG-LABEL: define{{.*}} void @_Z23test_cond_lvalue_assignb( +// OGCG: %[[FLAG:.*]] = alloca i8 +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG: %[[FLAG_VAL:.*]] = load i8, ptr %[[FLAG]] +// OGCG: %[[COND:.*]] = trunc i8 %[[FLAG_VAL]] to i1 +// OGCG: br i1 %[[COND]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PHI_PTR:.*]] = phi ptr [ %[[A]], %[[TRUE_BB]] ], [ %[[B]], %[[FALSE_BB]] ] +// OGCG: store i32 42, ptr %[[PHI_PTR]] + +int& test_cond_lvalue_ref(bool cond, int x, int y) { + return cond ? x : y; +} + +// CIR-LABEL: cir.func{{.*}} @_Z20test_cond_lvalue_refbii( +// CIR: %[[COND:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cond", init] +// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// CIR: %[[Y:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] +// CIR: %[[COND_VAL:.*]] = cir.load{{.*}} %[[COND]] +// CIR: %[[REF_PTR:.*]] = cir.ternary(%[[COND_VAL]], true { +// CIR: cir.yield %[[X]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: cir.yield %[[Y]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: cir.store %[[REF_PTR]] +// CIR: %[[RET_VAL:.*]] = cir.load +// CIR: cir.return %[[RET_VAL]] : !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z20test_cond_lvalue_refbii( +// LLVM: %[[COND:.*]] = alloca i8 +// LLVM: %[[X:.*]] = alloca i32 +// LLVM: %[[Y:.*]] = alloca i32 +// LLVM: %[[COND_VAL:.*]] = load i8, ptr %[[COND]] +// LLVM: %[[BOOL:.*]] = trunc i8 %[[COND_VAL]] to i1 +// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PHI:.*]] = phi ptr [ %[[Y]], %[[FALSE_BB]] ], [ %[[X]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT:.*]] +// LLVM: [[CONT]]: +// LLVM: store ptr %[[PHI]] +// LLVM: %[[RET:.*]] = load ptr +// LLVM: ret ptr %[[RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z20test_cond_lvalue_refbii( +// OGCG: %[[COND:.*]] = alloca i8 +// OGCG: %[[X:.*]] = alloca i32 +// OGCG: %[[Y:.*]] = alloca i32 +// OGCG: %[[COND_VAL:.*]] = load i8, ptr %[[COND]] +// OGCG: %[[BOOL:.*]] = trunc i8 %[[COND_VAL]] to i1 +// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PHI:.*]] = phi ptr [ %[[X]], %[[TRUE_BB]] ], [ %[[Y]], %[[FALSE_BB]] ] +// OGCG: ret ptr %[[PHI]] + +// Test ConditionalOperator as lvalue - compound assignment +void test_cond_lvalue_compound(bool flag) { + int a = 5; + int b = 10; + (flag ? a : b) += 3; +} + +// CIR-LABEL: cir.func{{.*}} @_Z25test_cond_lvalue_compoundb( +// CIR: %[[FLAG:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["flag", init] +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] +// CIR: %[[LVAL_PTR:.*]] = cir.ternary(%[[FLAG_VAL]], true { +// CIR: cir.yield %[[A]] : !cir.ptr<!s32i> +// CIR: }, false { +// CIR: cir.yield %[[B]] : !cir.ptr<!s32i> +// CIR: }) : (!cir.bool) -> !cir.ptr<!s32i> +// CIR: %[[OLD_VAL:.*]] = cir.load{{.*}} %[[LVAL_PTR]] +// CIR: %[[NEW_VAL:.*]] = cir.binop(add, %[[OLD_VAL]], %{{.*}}) +// CIR: cir.store{{.*}} %[[NEW_VAL]], %[[LVAL_PTR]] + +// LLVM-LABEL: define{{.*}} void @_Z25test_cond_lvalue_compoundb( +// LLVM: %[[FLAG:.*]] = alloca i8 +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM: %[[FLAG_VAL:.*]] = load i8, ptr %[[FLAG]] +// LLVM: %[[BOOL:.*]] = trunc i8 %[[FLAG_VAL]] to i1 +// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// LLVM: [[TRUE_BB]]: +// LLVM: br label %[[MERGE_BB:.*]] +// LLVM: [[FALSE_BB]]: +// LLVM: br label %[[MERGE_BB]] +// LLVM: [[MERGE_BB]]: +// LLVM: %[[PTR:.*]] = phi ptr [ %[[B]], %[[FALSE_BB]] ], [ %[[A]], %[[TRUE_BB]] ] +// LLVM: br label %[[CONT:.*]] +// LLVM: [[CONT]]: +// LLVM: %[[OLD:.*]] = load i32, ptr %[[PTR]] +// LLVM: %[[NEW:.*]] = add{{.*}} i32 %[[OLD]], 3 +// LLVM: store i32 %[[NEW]], ptr %[[PTR]] + +// OGCG-LABEL: define{{.*}} void @_Z25test_cond_lvalue_compoundb( +// OGCG: %[[FLAG:.*]] = alloca i8 +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG: %[[FLAG_VAL:.*]] = load i8, ptr %[[FLAG]] +// OGCG: %[[BOOL:.*]] = trunc i8 %[[FLAG_VAL]] to i1 +// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]] +// OGCG: [[TRUE_BB]]: +// OGCG: br label %[[MERGE_BB:.*]] +// OGCG: [[FALSE_BB]]: +// OGCG: br label %[[MERGE_BB]] +// OGCG: [[MERGE_BB]]: +// OGCG: %[[PTR:.*]] = phi ptr [ %[[A]], %[[TRUE_BB]] ], [ %[[B]], %[[FALSE_BB]] ] +// OGCG: %[[OLD:.*]] = load i32, ptr %[[PTR]] +// OGCG: %[[NEW:.*]] = add{{.*}} i32 %[[OLD]], 3 +// OGCG: store i32 %[[NEW]], ptr %[[PTR]] + +// Test constant folding - compile-time true condition with lvalue assignment +void test_cond_const_true_lvalue() { + int a = 1; + int b = 2; + (true ? a : b) = 99; +} + +// CIR-LABEL: cir.func{{.*}} @_Z27test_cond_const_true_lvaluev( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR-NOT: cir.ternary +// CIR: %[[NINETYNINE:.*]] = cir.const #cir.int<99> : !s32i +// CIR: cir.store{{.*}} %[[NINETYNINE]], %[[A]] : !s32i, !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} void @_Z27test_cond_const_true_lvaluev( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM-NOT: br i1 +// LLVM: store i32 99, ptr %[[A]] + +// OGCG-LABEL: define{{.*}} void @_Z27test_cond_const_true_lvaluev( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG-NOT: br i1 +// OGCG: store i32 99, ptr %[[A]] + +// Test constant folding - compile-time false condition with lvalue assignment +void test_cond_const_false_lvalue() { + int a = 1; + int b = 2; + (false ? a : b) = 88; +} + +// CIR-LABEL: cir.func{{.*}} @_Z28test_cond_const_false_lvaluev( +// CIR: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR-NOT: cir.ternary +// CIR: %[[EIGHTYEIGHT:.*]] = cir.const #cir.int<88> : !s32i +// CIR: cir.store{{.*}} %[[EIGHTYEIGHT]], %[[B]] : !s32i, !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} void @_Z28test_cond_const_false_lvaluev( +// LLVM: %[[A:.*]] = alloca i32 +// LLVM: %[[B:.*]] = alloca i32 +// LLVM-NOT: br i1 +// LLVM: store i32 88, ptr %[[B]] + +// OGCG-LABEL: define{{.*}} void @_Z28test_cond_const_false_lvaluev( +// OGCG: %[[A:.*]] = alloca i32 +// OGCG: %[[B:.*]] = alloca i32 +// OGCG-NOT: br i1 +// OGCG: store i32 88, ptr %[[B]] diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp index 8f0b3c4..5a50310 100644 --- a/clang/test/CIR/CodeGen/try-catch.cpp +++ b/clang/test/CIR/CodeGen/try-catch.cpp @@ -30,3 +30,90 @@ void empty_try_block_with_catch_with_int_exception() { // OGCG: define{{.*}} void @_Z45empty_try_block_with_catch_with_int_exceptionv() // OGCG: ret void + +void try_catch_with_empty_catch_all() { + int a = 1; + try { + return; + ++a; + } catch (...) { + } +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[CONST_1]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i +// CIR: cir.scope { +// CIR: cir.try { +// CIR: cir.return +// CIR: ^bb1: // no predecessors +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[RESULT:.*]] = cir.unary(inc, %[[TMP_A]]) nsw : !s32i, !s32i +// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.yield +// CIR: } +// CIR: } + +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 1, ptr %[[A_ADDR]], align 4 +// LLVM: br label %[[BB_2:.*]] +// LLVM: [[BB_2]]: +// LLVM: br label %[[BB_3:.*]] +// LLVM: [[BB_3]]: +// LLVM: ret void +// LLVM: [[BB_4:.*]]: +// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// LLVM: %[[RESULT:.*]] = add nsw i32 %[[TMP_A]], 1 +// LLVM: store i32 %[[RESULT]], ptr %[[A_ADDR]], align 4 +// LLVM: br label %[[BB_7:.*]] +// LLVM: [[BB_7]]: +// LLVM: br label %[[BB_8:.*]] +// LLVM: [[BB_8]]: +// LLVM: ret void + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 1, ptr %[[A_ADDR]], align 4 +// OGCG: ret void + +void try_catch_with_empty_catch_all_2() { + int a = 1; + try { + ++a; + return; + } catch (...) { + } +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[CONST_1]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.scope { +// CIR: cir.try { +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[RESULT:.*]] = cir.unary(inc, %[[TMP_A]]) nsw : !s32i, !s32i +// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.return +// CIR: } +// CIR: } + +// LLVM: %[[A_ADDR]] = alloca i32, i64 1, align 4 +// LLVM: store i32 1, ptr %[[A_ADDR]], align 4 +// LLVM: br label %[[BB_2:.*]] +// LLVM: [[BB_2]]: +// LLVM: br label %[[BB_3:.*]] +// LLVM: [[BB_3]]: +// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// LLVM: %[[RESULT:.*]] = add nsw i32 %[[TMP_A:.*]], 1 +// LLVM: store i32 %[[RESULT]], ptr %[[A_ADDR]], align 4 +// LLVM: ret void +// LLVM: [[BB_6:.*]]: +// LLVM: br label %[[BB_7:.*]] +// LLVM: [[BB_7]]: +// LLVM: ret void + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 1, ptr %[[A_ADDR]], align 4 +// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// OGCG: %[[RESULT:.*]] = add nsw i32 %[[TMP_A]], 1 +// OGCG: store i32 %[[RESULT]], ptr %[[A_ADDR]], align 4 +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/vla.c b/clang/test/CIR/CodeGen/vla.c index b22c704..0af4f83 100644 --- a/clang/test/CIR/CodeGen/vla.c +++ b/clang/test/CIR/CodeGen/vla.c @@ -282,4 +282,61 @@ void f3(unsigned len) { // break; // } // } -
\ No newline at end of file + +int f5(unsigned long len) { + int arr[len]; + return arr[2]; +} + +// CIR: cir.func{{.*}} @f5(%[[LEN_ARG:.*]]: !u64i {{.*}}) -> !s32i +// CIR: %[[LEN_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["len", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[SAVED_STACK:.*]] = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>, ["saved_stack"] +// CIR: cir.store{{.*}} %[[LEN_ARG]], %[[LEN_ADDR]] +// CIR: %[[LEN:.*]] = cir.load{{.*}} %[[LEN_ADDR]] +// CIR: %[[STACK_PTR:.*]] = cir.stacksave +// CIR: cir.store{{.*}} %[[STACK_PTR]], %[[SAVED_STACK]] +// CIR: %[[ARR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, %[[LEN]] : !u64i, ["arr"] +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[ARR_2:.*]] = cir.ptr_stride %[[ARR]], %[[TWO]] +// CIR: %[[ARR_VAL:.*]] = cir.load{{.*}} %[[ARR_2]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store{{.*}} %[[ARR_VAL]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[STACK_RESTORE_PTR:.*]] = cir.load{{.*}} %[[SAVED_STACK]] +// CIR: cir.stackrestore %[[STACK_RESTORE_PTR]] +// CIR: %[[RET_VAL:.*]] = cir.load{{.*}} %[[RET_ADDR]] +// CIR: cir.return %[[RET_VAL]] : !s32i + +// LLVM: define{{.*}} i32 @f5(i64 %[[LEN_ARG:.*]]) +// LLVM: %[[LEN_ADDR:.*]] = alloca i64 +// LLVM: %[[RET_ADDR:.*]] = alloca i32 +// LLVM: %[[SAVED_STACK:.*]] = alloca ptr +// LLVM: store i64 %[[LEN_ARG]], ptr %[[LEN_ADDR]] +// LLVM: %[[LEN:.*]] = load i64, ptr %[[LEN_ADDR]] +// LLVM: %[[STACK_PTR:.*]] = call ptr @llvm.stacksave.p0() +// LLVM: store ptr %[[STACK_PTR]], ptr %[[SAVED_STACK]] +// LLVM: %[[ARR:.*]] = alloca i32, i64 %[[LEN]] +// LLVM: %[[ARR_2:.*]] = getelementptr i32, ptr %[[ARR]], i64 2 +// LLVM: %[[ARR_VAL:.*]] = load i32, ptr %[[ARR_2]] +// LLVM: store i32 %[[ARR_VAL]], ptr %[[RET_ADDR]] +// LLVM: %[[STACK_RESTORE_PTR:.*]] = load ptr, ptr %[[SAVED_STACK]] +// LLVM: call void @llvm.stackrestore.p0(ptr %[[STACK_RESTORE_PTR]]) +// LLVM: %[[RET_VAL:.*]] = load i32, ptr %[[RET_ADDR]] +// LLVM: ret i32 %[[RET_VAL]] + +// Note: VLA_EXPR0 below is emitted to capture debug info. + +// OGCG: define{{.*}} i32 @f5(i64 {{.*}} %[[LEN_ARG:.*]]) +// OGCG: %[[LEN_ADDR:.*]] = alloca i64 +// OGCG: %[[SAVED_STACK:.*]] = alloca ptr +// OGCG: %[[VLA_EXPR0:.*]] = alloca i64 +// OGCG: store i64 %[[LEN_ARG]], ptr %[[LEN_ADDR]] +// OGCG: %[[LEN:.*]] = load i64, ptr %[[LEN_ADDR]] +// OGCG: %[[STACK_PTR:.*]] = call ptr @llvm.stacksave.p0() +// OGCG: store ptr %[[STACK_PTR]], ptr %[[SAVED_STACK]] +// OGCG: %[[ARR:.*]] = alloca i32, i64 %[[LEN]] +// OGCG: store i64 %[[LEN]], ptr %[[VLA_EXPR0]] +// OGCG: %[[ARR_2:.*]] = getelementptr inbounds i32, ptr %[[ARR]], i64 2 +// OGCG: %[[ARR_VAL:.*]] = load i32, ptr %[[ARR_2]] +// OGCG: %[[STACK_RESTORE_PTR:.*]] = load ptr, ptr %[[SAVED_STACK]] +// OGCG: call void @llvm.stackrestore.p0(ptr %[[STACK_RESTORE_PTR]]) +// OGCG: ret i32 %[[ARR_VAL]] |