diff options
Diffstat (limited to 'clang/test/CIR/CodeGen')
88 files changed, 5117 insertions, 1812 deletions
diff --git a/clang/test/CIR/CodeGen/X86/cir-sqrt-builtins.c b/clang/test/CIR/CodeGen/X86/cir-sqrt-builtins.c new file mode 100644 index 0000000..d540e9c --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/cir-sqrt-builtins.c @@ -0,0 +1,45 @@ +// Test X86-specific sqrt builtins
+
+// 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 -target-feature +avx512f -target-feature +avx512fp16 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+typedef float __m512 __attribute__((__vector_size__(64), __aligned__(64)));
+typedef double __m512d __attribute__((__vector_size__(64), __aligned__(64)));
+typedef _Float16 __m512h __attribute__((__vector_size__(64), __aligned__(64)));
+
+// Test __builtin_ia32_sqrtph512
+__m512h test_sqrtph512(__m512h a) {
+ return __builtin_ia32_sqrtph512(a, 4);
+}
+// CIR-LABEL: cir.func {{.*}}@test_sqrtph512
+// CIR: cir.sqrt {{%.*}} : !cir.vector<32 x !cir.f16>
+// LLVM-LABEL: define {{.*}} @test_sqrtph512
+// LLVM: call <32 x half> @llvm.sqrt.v32f16
+// OGCG-LABEL: define {{.*}} @test_sqrtph512
+// OGCG: call <32 x half> @llvm.sqrt.v32f16
+
+// Test __builtin_ia32_sqrtps512
+__m512 test_sqrtps512(__m512 a) {
+ return __builtin_ia32_sqrtps512(a, 4);
+}
+// CIR-LABEL: cir.func {{.*}}@test_sqrtps512
+// CIR: cir.sqrt {{%.*}} : !cir.vector<16 x !cir.float>
+// LLVM-LABEL: define {{.*}} @test_sqrtps512
+// LLVM: call <16 x float> @llvm.sqrt.v16f32
+// OGCG-LABEL: define {{.*}} @test_sqrtps512
+// OGCG: call <16 x float> @llvm.sqrt.v16f32
+
+// Test __builtin_ia32_sqrtpd512
+__m512d test_sqrtpd512(__m512d a) {
+ return __builtin_ia32_sqrtpd512(a, 4);
+}
+// CIR-LABEL: cir.func {{.*}}@test_sqrtpd512
+// CIR: cir.sqrt {{%.*}} : !cir.vector<8 x !cir.double>
+// LLVM-LABEL: define {{.*}} @test_sqrtpd512
+// LLVM: call <8 x double> @llvm.sqrt.v8f64
+// OGCG-LABEL: define {{.*}} @test_sqrtpd512
+// OGCG: call <8 x double> @llvm.sqrt.v8f64
\ No newline at end of file diff --git a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c index 19362cf..66891f9 100644 --- a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c +++ b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c @@ -82,7 +82,7 @@ int check_load(st1 *s1) { return s1->b; } -// CIR: cir.func dso_local @check_load +// CIR: cir.func {{.*}} @check_load // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st1>>, !cir.ptr<!rec_st1> // CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "b"} : !cir.ptr<!rec_st1> -> !cir.ptr<!u16i> // CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b, [[MEMBER]] {is_volatile} : !cir.ptr<!u16i>) -> !u32i @@ -114,7 +114,7 @@ int check_load_exception(st3 *s3) { return s3->b; } -// CIR: cir.func dso_local @check_load_exception +// CIR: cir.func {{.*}} @check_load_exception // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3> // CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][2] {name = "b"} : !cir.ptr<!rec_st3> -> !cir.ptr<!u8i> // CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b1, [[MEMBER]] {is_volatile} : !cir.ptr<!u8i>) -> !u32i @@ -151,7 +151,7 @@ int clip_load_exception2(clip *c) { return c->a; } -// CIR: cir.func dso_local @clip_load_exception2 +// CIR: cir.func {{.*}} @clip_load_exception2 // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip> // CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>> // CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_a1, [[MEMBER]] {is_volatile} : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i @@ -178,7 +178,7 @@ void check_store(st2 *s2) { s2->a = 1; } -// CIR: cir.func dso_local @check_store +// CIR: cir.func {{.*}} @check_store // CIR: [[CONST:%.*]] = cir.const #cir.int<1> : !s32i // CIR: [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !s16i // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st2>>, !cir.ptr<!rec_st2> @@ -209,7 +209,7 @@ void check_store_exception(st3 *s3) { s3->b = 2; } -// CIR: cir.func dso_local @check_store_exception +// CIR: cir.func {{.*}} @check_store_exception // CIR: [[CONST:%.*]] = cir.const #cir.int<2> : !s32i // CIR: [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !u32i // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3> @@ -239,7 +239,7 @@ void clip_store_exception2(clip *c) { c->a = 3; } -// CIR: cir.func dso_local @clip_store_exception2 +// CIR: cir.func {{.*}} @clip_store_exception2 // CIR: [[CONST:%.*]] = cir.const #cir.int<3> : !s32i // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip> // CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>> @@ -261,7 +261,7 @@ void check_store_second_member (st4 *s4) { s4->b = 1; } -// CIR: cir.func dso_local @check_store_second_member +// CIR: cir.func {{.*}} @check_store_second_member // CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i // CIR: [[CAST:%.*]] = cir.cast integral [[ONE]] : !s32i -> !u64i // CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st4>>, !cir.ptr<!rec_st4> diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp new file mode 100644 index 0000000..9ce1f5e --- /dev/null +++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -std=c++17 -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 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +using pi1_t = int __attribute__((address_space(1))) *; +using pi2_t = int __attribute__((address_space(2))) *; + +using ri1_t = int __attribute__((address_space(1))) &; +using ri2_t = int __attribute__((address_space(2))) &; + +// CIR: cir.func {{.*}} @{{.*test_ptr.*}} +// LLVM: define dso_local void @{{.*test_ptr.*}} +// OGCG: define dso_local void @{{.*test_ptr.*}} +void test_ptr() { + pi1_t ptr1; + pi2_t ptr2 = (pi2_t)ptr1; + // CIR: %[[#PTR1:]] = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>, !cir.ptr<!s32i, target_address_space(1)> + // CIR-NEXT: %[[#CAST:]] = cir.cast address_space %[[#PTR1]] : !cir.ptr<!s32i, target_address_space(1)> -> !cir.ptr<!s32i, target_address_space(2)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(2)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(2)>> + + // LLVM: %[[#PTR1:]] = load ptr addrspace(1), ptr %{{.*}} + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#PTR1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{.*}} + + // OGCG: %{{.*}} = load ptr addrspace(1), ptr %{{.*}} + // OGCG-NEXT: %{{.*}} = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(2) + // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}} +} + +// CIR: cir.func {{.*}} @{{.*test_ref.*}} +// LLVM: define dso_local void @{{.*test_ref.*}} +// OGCG: define dso_local void @{{.*test_ref.*}} +void test_ref() { + pi1_t ptr; + ri1_t ref1 = *ptr; + ri2_t ref2 = (ri2_t)ref1; + // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>, !cir.ptr<!s32i, target_address_space(1)> + // CIR-NEXT: cir.store{{.*}} %[[#DEREF]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(1)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>> + // CIR-NEXT: %[[#REF1:]] = cir.load %{{[0-9]+}} : !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>, !cir.ptr<!s32i, target_address_space(1)> + // CIR-NEXT: %[[#CAST:]] = cir.cast address_space %[[#REF1]] : !cir.ptr<!s32i, target_address_space(1)> -> !cir.ptr<!s32i, target_address_space(2)> + // CIR-NEXT: cir.store{{.*}} %[[#CAST]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(2)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(2)>> + + // LLVM: %[[#DEREF:]] = load ptr addrspace(1), ptr %{{.*}} + // LLVM-NEXT: store ptr addrspace(1) %[[#DEREF]], ptr %{{.*}} + // LLVM-NEXT: %[[#REF1:]] = load ptr addrspace(1), ptr %{{.*}} + // LLVM-NEXT: %[[#CAST:]] = addrspacecast ptr addrspace(1) %[[#REF1]] to ptr addrspace(2) + // LLVM-NEXT: store ptr addrspace(2) %[[#CAST]], ptr %{{.*}} + + // OGCG: %{{.*}} = load ptr addrspace(1), ptr %{{.*}} + // OGCG-NEXT: store ptr addrspace(1) %{{.*}}, ptr %{{.*}} + // OGCG-NEXT: %{{.*}} = load ptr addrspace(1), ptr %{{.*}} + // OGCG-NEXT: %{{.*}} = addrspacecast ptr addrspace(1) %{{.*}} to ptr addrspace(2) + // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}} +} + +// CIR: cir.func {{.*}} @{{.*test_nullptr.*}} +// LLVM: define dso_local void @{{.*test_nullptr.*}} +// OGCG: define dso_local void @{{.*test_nullptr.*}} +void test_nullptr() { + constexpr pi1_t null1 = nullptr; + pi2_t ptr = (pi2_t)null1; + // CIR: %[[#NULL1:]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i, target_address_space(1)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL1]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(1)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>> + // CIR-NEXT: %[[#NULL2:]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i, target_address_space(2)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL2]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(2)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(2)>> + + // LLVM: store ptr addrspace(1) null, ptr %{{.*}} + // LLVM-NEXT: store ptr addrspace(2) null, ptr %{{.*}} + + // OGCG: store ptr addrspace(1) null, ptr %{{.*}} + // OGCG-NEXT: store ptr addrspace(2) null, ptr %{{.*}} +} + +// CIR: cir.func {{.*}} @{{.*test_side_effect.*}} +// LLVM: define dso_local void @{{.*test_side_effect.*}} +// OGCG: define dso_local void @{{.*test_side_effect.*}} +void test_side_effect(pi1_t b) { + pi2_t p = (pi2_t)(*b++, (int*)0); + // CIR: %[[#DEREF:]] = cir.load deref{{.*}} %{{[0-9]+}} : !cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>, !cir.ptr<!s32i, target_address_space(1)> + // CIR: %[[#STRIDE:]] = cir.ptr_stride %[[#DEREF]], %{{[0-9]+}} : (!cir.ptr<!s32i, target_address_space(1)>, !s32i) -> !cir.ptr<!s32i, target_address_space(1)> + // CIR: %[[#NULL:]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i, target_address_space(2)> + // CIR-NEXT: cir.store{{.*}} %[[#NULL]], %{{[0-9]+}} : !cir.ptr<!s32i, target_address_space(2)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(2)>> + + // LLVM: %{{[0-9]+}} = getelementptr {{.*}}i32, ptr addrspace(1) %{{[0-9]+}}, i{{32|64}} 1 + // LLVM: store ptr addrspace(2) null, ptr %{{.*}} + + // OGCG: %{{.*}} = getelementptr{{.*}} i32, ptr addrspace(1) %{{.*}}, i32 1 + // OGCG: store ptr addrspace(2) null, ptr %{{.*}} +} diff --git a/clang/test/CIR/CodeGen/address-space.c b/clang/test/CIR/CodeGen/address-space.c index a334b8a..2a5c0e1 100644 --- a/clang/test/CIR/CodeGen/address-space.c +++ b/clang/test/CIR/CodeGen/address-space.c @@ -6,7 +6,7 @@ // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG // Test address space 1 -// CIR: cir.func dso_local @foo(%arg0: !cir.ptr<!s32i, target_address_space(1)> +// CIR: cir.func {{.*}} @foo(%arg0: !cir.ptr<!s32i, target_address_space(1)> // LLVM: define dso_local void @foo(ptr addrspace(1) %0) // OGCG: define dso_local void @foo(ptr addrspace(1) noundef %arg) void foo(int __attribute__((address_space(1))) *arg) { @@ -14,7 +14,7 @@ void foo(int __attribute__((address_space(1))) *arg) { } // Test explicit address space 0 (should be same as default) -// CIR: cir.func dso_local @bar(%arg0: !cir.ptr<!s32i, target_address_space(0)> +// CIR: cir.func {{.*}} @bar(%arg0: !cir.ptr<!s32i, target_address_space(0)> // LLVM: define dso_local void @bar(ptr %0) // OGCG: define dso_local void @bar(ptr noundef %arg) void bar(int __attribute__((address_space(0))) *arg) { @@ -22,7 +22,7 @@ void bar(int __attribute__((address_space(0))) *arg) { } // Test default address space (no attribute) -// CIR: cir.func dso_local @baz(%arg0: !cir.ptr<!s32i> +// CIR: cir.func {{.*}} @baz(%arg0: !cir.ptr<!s32i> // LLVM: define dso_local void @baz(ptr %0) // OGCG: define dso_local void @baz(ptr noundef %arg) void baz(int *arg) { diff --git a/clang/test/CIR/CodeGen/agg-expr-lvalue.c b/clang/test/CIR/CodeGen/agg-expr-lvalue.c index c826f8f..509f021 100644 --- a/clang/test/CIR/CodeGen/agg-expr-lvalue.c +++ b/clang/test/CIR/CodeGen/agg-expr-lvalue.c @@ -95,16 +95,13 @@ void test_string_array_in_array(void) { } // 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 +// CIR: %[[MATRIX:.*]] = cir.alloca !cir.array<!cir.array<!s8i x 6> x 2>, {{.*}}, ["matrix", init] +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<104> : !s8i, #cir.int<101> : !s8i, #cir.int<108> : !s8i, #cir.int<108> : !s8i, #cir.int<111> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>, #cir.const_array<[#cir.int<119> : !s8i, #cir.int<111> : !s8i, #cir.int<114> : !s8i, #cir.int<108> : !s8i, #cir.int<100> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>]> +// CIR: cir.store{{.*}} %[[CONST]], %[[MATRIX]] // 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 +// LLVM: %[[MATRIX:.*]] = alloca [2 x [6 x i8]] +// LLVM: store [2 x [6 x i8]] {{\[}}[6 x i8] c"hello\00", [6 x i8] c"world\00"], ptr %[[MATRIX]] // OGCG-LABEL: define{{.*}} @test_string_array_in_array // OGCG: alloca [2 x [6 x i8]] diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index 1fb14ec..8643c8c 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -14,7 +14,7 @@ void foo() { S s[42]; } -// CIR-BEFORE-LPP: cir.func dso_local @_Z3foov() +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z3foov() // CIR-BEFORE-LPP: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] // CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>> { // CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>): @@ -24,7 +24,7 @@ void foo() { // CIR-BEFORE-LPP: cir.return // CIR-BEFORE-LPP: } -// CIR: cir.func dso_local @_Z3foov() +// CIR: cir.func {{.*}} @_Z3foov() // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] // CIR: %[[CONST42:.*]] = cir.const #cir.int<42> : !u64i // CIR: %[[DECAY:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>> -> !cir.ptr<!rec_S> @@ -84,12 +84,12 @@ void zero_sized() { S s[0]; } -// CIR-BEFORE-LPP: cir.func dso_local @_Z10zero_sizedv() +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z10zero_sizedv() // CIR-BEFORE-LPP: cir.alloca !cir.array<!rec_S x 0>, !cir.ptr<!cir.array<!rec_S x 0>>, ["s"] // CIR-BEFORE-LPP-NOT: cir.array.ctor // CIR-BEFORE-LPP: cir.return -// CIR: cir.func dso_local @_Z10zero_sizedv() +// CIR: cir.func {{.*}} @_Z10zero_sizedv() // CIR: cir.alloca !cir.array<!rec_S x 0>, !cir.ptr<!cir.array<!rec_S x 0>>, ["s"] // CIR-NOT: cir.do // CIR-NOT: cir.call @_ZN1SC1Ev diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index 82add4b..5e87381 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -151,50 +151,12 @@ void func2() { } // CIR: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init] -// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init] -// CIR: %[[ARR_0:.*]] = cir.cast array_to_ptrdecay %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i> -// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[FIVE]], %[[ARR_0]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride %[[ARR_0]], %[[OFFSET_0]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i -// CIR: %[[ARR_END:.*]] = cir.ptr_stride %[[ARR_0]], %[[TWO]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i> -// CIR: cir.do { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> -// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i -// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride %[[ARR_CUR]], %[[ONE]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.yield -// CIR: } while { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> -// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!s32i>, !cir.bool -// CIR: cir.condition(%[[CMP]]) -// CIR: } +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.int<5> : !s32i, #cir.int<0> : !s32i]> : !cir.array<!s32i x 2> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR2]] : !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>> // LLVM: define{{.*}} void @_Z5func2v(){{.*}} // LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 -// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 -// LLVM: %[[END_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 2 -// LLVM: br label %[[LOOP_BODY:.*]] -// LLVM: [[LOOP_NEXT:.*]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] -// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] -// LLVM: [[LOOP_BODY]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store i32 0, ptr %[[CUR]], align 4 -// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1 -// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 -// LLVM: br label %[[LOOP_NEXT:.*]] -// LLVM: [[LOOP_END]]: -// LLVM: ret void +// LLVM: store [2 x i32] [i32 5, i32 0], ptr %[[ARR]], align 4 // OGCG: %[[ARR:.*]] = alloca [2 x i32], align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN2_ARR]], i64 8, i1 false) @@ -209,13 +171,8 @@ void func3() { // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init] // CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["idx", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init] -// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i> -// CIR: %[[V0:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[V0]], %[[ARR_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[OFFSET_0]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i> -// CIR: %[[V1:.*]] = cir.const #cir.int<6> : !s32i -// CIR: cir.store{{.*}} %[[V1]], %[[ELE_1_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 2> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>> // CIR: %[[IDX_V:.*]] = cir.const #cir.int<1> : !s32i // CIR: cir.store{{.*}} %[[IDX_V]], %[[IDX]] : !s32i, !cir.ptr<!s32i> // CIR: %[[TMP_IDX:.*]] = cir.load{{.*}} %[[IDX]] : !cir.ptr<!s32i>, !s32i @@ -228,10 +185,7 @@ void func3() { // LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 // LLVM: %[[IDX:.*]] = alloca i32, i64 1, align 4 // LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4 -// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 -// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 -// LLVM: store i32 6, ptr %[[ELE_1_PTR]], align 4 +// LLVM: store [2 x i32] [i32 5, i32 6], ptr %[[ARR]], align 4 // LLVM: store i32 1, ptr %[[IDX]], align 4 // LLVM: %[[TMP1:.*]] = load i32, ptr %[[IDX]], align 4 // LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 @@ -258,15 +212,8 @@ void func4() { // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init] // CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init] -// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[ARR_0_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>> -> !cir.ptr<!s32i> -// CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_1:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[OFFSET]] : (!cir.ptr<!cir.array<!s32i x 1>>, !s64i) -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[ARR_1_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR_1]] : !cir.ptr<!cir.array<!s32i x 1>> -> !cir.ptr<!s32i> -// CIR: %[[V_1_0:.*]] = cir.const #cir.int<6> : !s32i -// CIR: cir.store{{.*}} %[[V_1_0]], %[[ARR_1_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.const_array<[#cir.int<6> : !s32i]> : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> // CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i // CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i // CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>> @@ -279,12 +226,7 @@ void func4() { // LLVM: define{{.*}} void @_Z5func4v(){{.*}} // LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 // LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4 -// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 -// LLVM: %[[ARR_0_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_0_0]], align 4 -// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 -// LLVM: %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0 -// LLVM: store i32 6, ptr %[[ARR_1_0]], align 4 +// LLVM: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] [i32 6]], ptr %[[ARR]], align 4 // LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 // LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 // LLVM: %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0 @@ -305,52 +247,12 @@ void func5() { } // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init] -// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, ["arrayinit.temp", init] -// CIR: %[[ARR_0:.*]] = cir.cast array_to_ptrdecay %0 : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[ARR_0_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>> -> !cir.ptr<!s32i> -// CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_1:.*]] = cir.ptr_stride %[[ARR_0]], %[[OFFSET]] : (!cir.ptr<!cir.array<!s32i x 1>>, !s64i) -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %[[ARR_1]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i -// CIR: %[[ARR_END:.*]] = cir.ptr_stride %[[ARR_0]], %[[TWO]] : (!cir.ptr<!cir.array<!s32i x 1>>, !s64i) -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.do { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !cir.array<!s32i x 1> -// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride %[[ARR_CUR]], %[[ONE]] : (!cir.ptr<!cir.array<!s32i x 1>>, !s64i) -> !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> -// CIR: cir.yield -// CIR: } while { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.array<!s32i x 1>>, !cir.bool -// CIR: cir.condition(%[[CMP]]) -// CIR: } +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.zero : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> // LLVM: define{{.*}} void @_Z5func5v(){{.*}} // LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 -// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_0]], align 4 -// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 -// LLVM: %[[END_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 2 -// LLVM: br label %[[LOOP_BODY:.*]] -// LLVM: [[LOOP_NEXT:.*]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] -// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] -// LLVM: [[LOOP_BODY]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store [1 x i32] zeroinitializer, ptr %[[CUR]], align 4 -// LLVM: %[[NEXT:.*]] = getelementptr [1 x i32], ptr %[[CUR]], i64 1 -// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 -// LLVM: br label %[[LOOP_NEXT:.*]] -// LLVM: [[LOOP_END]]: -// LLVM: ret void +// LLVM: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] zeroinitializer], ptr %[[ARR]], align 4 // ORGC: %[[ARR:.*]] = alloca [2 x [1 x i32]], align 4 // ORGC: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN5_ARR]], i64 8, i1 false) @@ -395,44 +297,12 @@ void func7() { } // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init] -// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init] -// CIR: %[[ARR_0:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>> -> !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ARR_0]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_END:.*]] = cir.ptr_stride %[[ARR_0]], %[[ONE]] : (!cir.ptr<!cir.ptr<!s32i>>, !s64i) -> !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.do { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[NULL_PTR]], %[[ARR_CUR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride %[[ARR_CUR]], %[[ONE]] : (!cir.ptr<!cir.ptr<!s32i>>, !s64i) -> !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> -// CIR: cir.yield -// CIR: } while { -// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.ptr<!s32i>>, !cir.bool -// CIR: cir.condition(%[[CMP]]) -// CIR: } +// CIR: %[[CONST:.*]] = cir.const #cir.zero : !cir.array<!cir.ptr<!s32i> x 1> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>> // LLVM: define{{.*}} void @_Z5func7v(){{.*}} // LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 -// LLVM: store ptr %[[ARR_PTR]], ptr %[[TMP]], align 8 -// LLVM: %[[END_PTR:.*]] = getelementptr ptr, ptr %[[ARR_PTR]], i64 1 -// LLVM: br label %[[LOOP_BODY:.*]] -// LLVM: [[LOOP_NEXT:.*]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] -// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] -// LLVM: [[LOOP_BODY]]: -// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store ptr null, ptr %[[CUR]], align 8 -// LLVM: %[[NEXT:.*]] = getelementptr ptr, ptr %[[CUR]], i64 1 -// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 -// LLVM: br label %[[LOOP_NEXT:.*]] -// LLVM: [[LOOP_END]]: -// LLVM: ret void +// LLVM: store [1 x ptr] zeroinitializer, ptr %[[ARR]], align 8 // OGCG: %[[ARR:.*]] = alloca [1 x ptr], align 8 // OGCG: call void @llvm.memset.p0.i64(ptr align 8 %[[ARR]], i8 0, i64 8, i1 false) @@ -581,19 +451,11 @@ void array_with_complex_elements() { } // CIR: %[[ARR_ADDR:.*]] = cir.alloca !cir.array<!cir.complex<!cir.float> x 2>, !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>, ["arr", init] -// CIR: %[[ARR_0:.*]] = cir.cast array_to_ptrdecay %[[ARR_ADDR]] : !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>> -> !cir.ptr<!cir.complex<!cir.float>> -// CIR: %[[CONST_COMPLEX_0:.*]] = cir.const #cir.const_complex<#cir.fp<1.100000e+00> : !cir.float, #cir.fp<2.200000e+00> : !cir.float> : !cir.complex<!cir.float> -// CIR: cir.store{{.*}} %[[CONST_COMPLEX_0]], %[[ARR_0]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> -// CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ARR_1:.*]] = cir.ptr_stride %1, %[[IDX_1]] : (!cir.ptr<!cir.complex<!cir.float>>, !s64i) -> !cir.ptr<!cir.complex<!cir.float>> -// CIR: %[[CONST_COMPLEX_1:.*]] = cir.const #cir.const_complex<#cir.fp<3.300000e+00> : !cir.float, #cir.fp<4.400000e+00> : !cir.float> : !cir.complex<!cir.float> -// CIR: cir.store{{.*}} %[[CONST_COMPLEX_1]], %[[ARR_1]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_complex<#cir.fp<1.100000e+00> : !cir.float, #cir.fp<2.200000e+00> : !cir.float> : !cir.complex<!cir.float>, #cir.const_complex<#cir.fp<3.300000e+00> : !cir.float, #cir.fp<4.400000e+00> : !cir.float> : !cir.complex<!cir.float>]> : !cir.array<!cir.complex<!cir.float> x 2> +// CIR: cir.store{{.*}} %[[CONST]], %[[ARR_ADDR]] : !cir.array<!cir.complex<!cir.float> x 2>, !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>> // LLVM: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], i64 1, align 16 -// LLVM: %[[ARR_0:.*]] = getelementptr { float, float }, ptr %[[ARR_ADDR]], i32 0 -// LLVM: store { float, float } { float 0x3FF19999A0000000, float 0x40019999A0000000 }, ptr %[[ARR_0]], align 8 -// LLVM: %[[ARR_1:.*]] = getelementptr { float, float }, ptr %[[ARR_0]], i64 1 -// LLVM: store { float, float } { float 0x400A666660000000, float 0x40119999A0000000 }, ptr %[[ARR_1]], align 8 +// LLVM: store [2 x { float, float }] [{ float, float } { float 0x3FF19999A0000000, float 0x40019999A0000000 }, { float, float } { float 0x400A666660000000, float 0x40119999A0000000 }], ptr %[[ARR_ADDR]], align 16 // OGCG: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], align 16 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[ARR_ADDR]], ptr align 16 @__const._Z27array_with_complex_elementsv.arr, i64 16, i1 false) diff --git a/clang/test/CIR/CodeGen/asm-label-inline-builtins.c b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c new file mode 100644 index 0000000..bad521a --- /dev/null +++ b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -triple x86_64 -fclangir -emit-cir -disable-llvm-passes -o %t-cir.cir %s +// RUN: FileCheck --input-file=%t-cir.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64 -fclangir -emit-llvm -disable-llvm-passes -o %t-cir.ll %s +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64 -emit-llvm -disable-llvm-passes -o %t.ll %s +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + + +// Verifies that clang-generated *.inline carry the same name at call and callee +// site, in spite of asm labels. + +typedef struct _IO_FILE FILE; +extern FILE *stdout; +extern int vprintf (const char *__restrict __format, __builtin_va_list __arg); +extern int __vfprintf_chk (FILE *__restrict __stream, int __flag, + const char *__restrict __format, __builtin_va_list __ap); +extern int __vprintf_chk (int __flag, const char *__restrict __format, + __builtin_va_list __ap); + +extern __typeof (vprintf) vprintf __asm ("__vprintfieee128"); +extern __typeof (__vfprintf_chk) __vfprintf_chk __asm ("__vfprintf_chkieee128"); +extern __typeof (__vprintf_chk) __vprintf_chk __asm ("__vprintf_chkieee128"); + +extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) __attribute__ ((__artificial__)) int +vprintf (const char *__restrict __fmt, __builtin_va_list __ap) +{ + return __vfprintf_chk (stdout, 2 - 1, __fmt, __ap); +} + +void test(const char *fmt, __builtin_va_list ap) { + vprintf(fmt, ap); +} + +// CIR: cir.func always_inline internal private @__vprintfieee128.inline({{.*}}) -> !s32i +// CIR: cir.call @__vfprintf_chkieee128(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) +// +// CIR: cir.func {{.*}} @test({{.*}}) +// CIR: cir.call @__vprintfieee128.inline(%{{.*}}, %{{.*}}) + + +// LLVM: define internal i32 @__vprintfieee128.inline({{.*}}) #[[ALWAYS_INLINE_ATTR:.*]] { +// LLVM: call i32 @__vfprintf_chkieee128(ptr %{{.*}}, i32 1, ptr %{{.*}}, ptr %{{.*}}) +// +// LLVM: define {{.*}} void @test{{.*}} +// LLVM: call i32 @__vprintfieee128.inline(ptr %{{.*}}, ptr %{{.*}}) +// +// LLVM: attributes #[[ALWAYS_INLINE_ATTR]] = { alwaysinline } + +// Note: OGCG emits these in the opposite order, but the content is the same. + + +// OGCG: define {{.*}} void @test{{.*}} +// OGCG: call i32 @__vprintfieee128.inline(ptr noundef %{{.*}}, ptr noundef %{{.*}}) +// +// OGCG: define internal i32 @__vprintfieee128.inline({{.*}}) #[[ALWAYS_INLINE_ATTR:.*]] { +// OGCG: call i32 @__vfprintf_chkieee128(ptr noundef %{{.*}}, i32 noundef 1, ptr noundef %{{.*}}, ptr noundef %{{.*}}) +// +// OGCG: attributes #[[ALWAYS_INLINE_ATTR]] = { alwaysinline {{.*}} } diff --git a/clang/test/CIR/CodeGen/assign-operator.cpp b/clang/test/CIR/CodeGen/assign-operator.cpp index 66d4b48..ad3e5c0 100644 --- a/clang/test/CIR/CodeGen/assign-operator.cpp +++ b/clang/test/CIR/CodeGen/assign-operator.cpp @@ -13,7 +13,7 @@ void a() { a = 1u; } -// CIR: cir.func private @_ZN1xaSEi(!cir.ptr<!rec_x>, !s32i) +// CIR: cir.func {{.*}} @_ZN1xaSEi(!cir.ptr<!rec_x>, !s32i) // CIR: cir.func{{.*}} @_Z1av() // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_x, !cir.ptr<!rec_x>, ["a"] // CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !u32i @@ -63,7 +63,7 @@ void copy_c(C &c1, C &c2) { // Implicit assignment operator for C. -// CIR: cir.func comdat linkonce_odr @_ZN1CaSERKS_(%arg0: !cir.ptr<!rec_C> {{.*}}, %arg1: !cir.ptr<!rec_C> {{.*}}) -> !cir.ptr<!rec_C> +// CIR: cir.func {{.*}} @_ZN1CaSERKS_(%arg0: !cir.ptr<!rec_C> {{.*}}, %arg1: !cir.ptr<!rec_C> {{.*}}) -> !cir.ptr<!rec_C> // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init] // CIR: %[[ARG1_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["", init, const] // CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["__retval"] diff --git a/clang/test/CIR/CodeGen/atomic-thread-fence.c b/clang/test/CIR/CodeGen/atomic-thread-fence.c new file mode 100644 index 0000000..f28bc68 --- /dev/null +++ b/clang/test/CIR/CodeGen/atomic-thread-fence.c @@ -0,0 +1,181 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -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.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct Data { + int value; + void *ptr; +}; + +typedef struct Data *DataPtr; + +void applyThreadFence() { + __atomic_thread_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: @applyThreadFence + // CIR: cir.atomic.fence syncscope(system) seq_cst + // CIR: cir.return + + // LLVM-LABEL: @applyThreadFence + // LLVM: fence seq_cst + // LLVM: ret void + + // OGCG-LABEL: @applyThreadFence + // OGCG: fence seq_cst + // OGCG: ret void +} + +void applySignalFence() { + __atomic_signal_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: @applySignalFence + // CIR: cir.atomic.fence syncscope(single_thread) seq_cst + // CIR: cir.return + + // LLVM-LABEL: @applySignalFence + // LLVM: fence syncscope("singlethread") seq_cst + // LLVM: ret void + + // OGCG-LABEL: @applySignalFence + // OGCG: fence syncscope("singlethread") seq_cst + // OGCG: ret void +} + +void modifyWithThreadFence(DataPtr d) { + __atomic_thread_fence(__ATOMIC_SEQ_CST); + d->value = 42; + // CIR-LABEL: @modifyWithThreadFence + // CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!rec_Data>, !cir.ptr<!cir.ptr<!rec_Data>>, ["d", init] {alignment = 8 : i64} + // CIR: cir.atomic.fence syncscope(system) seq_cst + // CIR: %[[VAL_42:.*]] = cir.const #cir.int<42> : !s32i + // CIR: %[[LOAD_DATA:.*]] = cir.load{{.*}} %[[DATA]] : !cir.ptr<!cir.ptr<!rec_Data>>, !cir.ptr<!rec_Data> + // CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!rec_Data> -> !cir.ptr<!s32i> + // CIR: cir.store{{.*}} %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i> + // CIR: cir.return + + // LLVM-LABEL: @modifyWithThreadFence + // LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 + // LLVM: fence seq_cst + // LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 + // LLVM: store i32 42, ptr %[[DATA_VALUE]], align 8 + // LLVM: ret void + + // OGCG-LABEL: @modifyWithThreadFence + // OGCG: %[[DATA:.*]] = alloca ptr, align 8 + // OGCG: fence seq_cst + // OGCG: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // OGCG: %[[DATA_VALUE:.*]] = getelementptr inbounds nuw %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 + // OGCG: store i32 42, ptr %[[DATA_VALUE]], align 8 + // OGCG: ret void +} + +void modifyWithSignalFence(DataPtr d) { + __atomic_signal_fence(__ATOMIC_SEQ_CST); + d->value = 24; + // CIR-LABEL: @modifyWithSignalFence + // CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!rec_Data>, !cir.ptr<!cir.ptr<!rec_Data>>, ["d", init] {alignment = 8 : i64} + // CIR: cir.atomic.fence syncscope(single_thread) seq_cst + // CIR: %[[VAL_42:.*]] = cir.const #cir.int<24> : !s32i + // CIR: %[[LOAD_DATA:.*]] = cir.load{{.*}} %[[DATA]] : !cir.ptr<!cir.ptr<!rec_Data>>, !cir.ptr<!rec_Data> + // CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!rec_Data> -> !cir.ptr<!s32i> + // CIR: cir.store{{.*}} %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i> + // CIR: cir.return + + // LLVM-LABEL: @modifyWithSignalFence + // LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 + // LLVM: fence syncscope("singlethread") seq_cst + // LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 + // LLVM: store i32 24, ptr %[[DATA_VALUE]], align 8 + // LLVM: ret void + + // OGCG-LABEL: @modifyWithSignalFence + // OGCG: %[[DATA:.*]] = alloca ptr, align 8 + // OGCG: fence syncscope("singlethread") seq_cst + // OGCG: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // OGCG: %[[DATA_VALUE:.*]] = getelementptr inbounds nuw %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 + // OGCG: store i32 24, ptr %[[DATA_VALUE]], align 8 + // OGCG: ret void +} + +void loadWithThreadFence(DataPtr d) { + __atomic_thread_fence(__ATOMIC_SEQ_CST); + __atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST); + // CIR-LABEL: @loadWithThreadFence + // CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!rec_Data>, !cir.ptr<!cir.ptr<!rec_Data>>, ["d", init] {alignment = 8 : i64} + // CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64} + // CIR: cir.atomic.fence syncscope(system) seq_cst + // CIR: %[[LOAD_DATA:.*]] = cir.load{{.*}} %[[DATA]] : !cir.ptr<!cir.ptr<!rec_Data>>, !cir.ptr<!rec_Data> + // CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!rec_Data> -> !cir.ptr<!cir.ptr<!void>> + // CIR: %[[CASTED_DATA_VALUE:.*]] = cir.cast bitcast %[[DATA_VALUE]] : !cir.ptr<!cir.ptr<!void>> -> !cir.ptr<!u64i> + // CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast bitcast %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>> -> !cir.ptr<!u64i> + // CIR: %[[ATOMIC_LOAD:.*]] = cir.load{{.*}} atomic(seq_cst) %[[CASTED_DATA_VALUE]] : !cir.ptr<!u64i>, !u64i + // CIR: cir.store{{.*}} %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i> + // CIR: %[[DOUBLE_CASTED_ATOMIC_TEMP:.*]] = cir.cast bitcast %[[CASTED_ATOMIC_TEMP]] : !cir.ptr<!u64i> -> !cir.ptr<!cir.ptr<!void>> + // CIR: %[[ATOMIC_LOAD_PTR:.*]] = cir.load{{.*}} %[[DOUBLE_CASTED_ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR: cir.return + + // LLVM-LABEL: @loadWithThreadFence + // LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 + // LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8 + // LLVM: fence seq_cst + // LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 + // LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 + // LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 + // LLVM: %[[DATA_TEMP_LOAD:.*]] = load ptr, ptr %[[DATA_TEMP]], align 8 + // LLVM: ret void + + // OGCG-LABEL: @loadWithThreadFence + // OGCG: %[[DATA:.*]] = alloca ptr, align 8 + // OGCG: %[[DATA_TEMP:.*]] = alloca ptr, align 8 + // OGCG: fence seq_cst + // OGCG: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // OGCG: %[[DATA_VALUE:.*]] = getelementptr inbounds nuw %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 + // OGCG: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 + // OGCG: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 + // OGCG: %[[DATA_TEMP_LOAD:.*]] = load ptr, ptr %[[DATA_TEMP]], align 8 + // OGCG: ret void +} + +void loadWithSignalFence(DataPtr d) { + __atomic_signal_fence(__ATOMIC_SEQ_CST); + __atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST); + // CIR-LABEL: @loadWithSignalFence + // CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!rec_Data>, !cir.ptr<!cir.ptr<!rec_Data>>, ["d", init] {alignment = 8 : i64} + // CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64} + // CIR: cir.atomic.fence syncscope(single_thread) seq_cst + // CIR: %[[LOAD_DATA:.*]] = cir.load{{.*}} %[[DATA]] : !cir.ptr<!cir.ptr<!rec_Data>>, !cir.ptr<!rec_Data> + // CIR: %[[DATA_PTR:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!rec_Data> -> !cir.ptr<!cir.ptr<!void>> + // CIR: %[[CASTED_DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR]] : !cir.ptr<!cir.ptr<!void>> -> !cir.ptr<!u64i> + // CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast bitcast %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>> -> !cir.ptr<!u64i> + // CIR: %[[ATOMIC_LOAD:.*]] = cir.load{{.*}} atomic(seq_cst) %[[CASTED_DATA_PTR]] : !cir.ptr<!u64i>, !u64i + // CIR: cir.store{{.*}} %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i> + // CIR: %[[DOUBLE_CASTED_ATOMIC_TEMP:.*]] = cir.cast bitcast %[[CASTED_ATOMIC_TEMP]] : !cir.ptr<!u64i> -> !cir.ptr<!cir.ptr<!void>> + // CIR: %[[LOAD_ATOMIC_TEMP:.*]] = cir.load{{.*}} %[[DOUBLE_CASTED_ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR: cir.return + + // LLVM-LABEL: @loadWithSignalFence + // LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 + // LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8 + // LLVM: fence syncscope("singlethread") seq_cst + // LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 + // LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 + // LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 + // LLVM: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8 + // LLVM: ret void + + // OGCG-LABEL: @loadWithSignalFence + // OGCG: %[[DATA:.*]] = alloca ptr, align 8 + // OGCG: %[[DATA_TEMP:.*]] = alloca ptr, align 8 + // OGCG: fence syncscope("singlethread") seq_cst + // OGCG: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 + // OGCG: %[[DATA_VALUE:.*]] = getelementptr inbounds nuw %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 + // OGCG: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 + // OGCG: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 + // OGCG: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8 + // OGCG: ret void +} diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 6579988..71cb1f1 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -46,6 +46,32 @@ void f2(void) { // OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4 // OGCG: } +void f3(_Atomic(int) *p) { + *p = 42; +} + +// CIR-LABEL: @f3 +// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i> + +// LLVM-LABEL: @f3 +// LLVM: store atomic i32 42, ptr %{{.+}} seq_cst, align 4 + +// OGCG-LABEL: @f3 +// OGCG: store atomic i32 42, ptr %{{.+}} seq_cst, align 4 + +void f4(_Atomic(float) *p) { + *p = 3.14; +} + +// CIR-LABEL: @f4 +// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !cir.float, !cir.ptr<!cir.float> + +// LLVM-LABEL: @f4 +// LLVM: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4 + +// OGCG-LABEL: @f4 +// OGCG: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4 + void load(int *ptr) { int x; __atomic_load(ptr, &x, __ATOMIC_RELAXED); @@ -1107,3 +1133,269 @@ int c11_atomic_fetch_nand(_Atomic(int) *ptr, int value) { // OGCG: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4 } + +int atomic_load_dynamic_order(int *ptr, int order) { + // CIR-LABEL: atomic_load_dynamic_order + // LLVM-LABEL: atomic_load_dynamic_order + // OGCG-LABEL: atomic_load_dynamic_order + + return __atomic_load_n(ptr, order); + + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> + // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.switch (%[[ORDER]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(relaxed) %[[PTR]] : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(acquire) %[[PTR]] : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(seq_cst) %[[PTR]] : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + // CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i + + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM-NEXT: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK:.+]] + // LLVM: [[ACQUIRE_BLK]]: + // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[SEQ_CST_BLK]]: + // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[CONTINUE_BLK]]: + // LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4 + + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG-NEXT: ] + // OGCG: [[DEFAULT_BLK]]: + // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK:.+]] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[CONTINUE_BLK]]: + // OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4 +} + +void atomic_store_dynamic_order(int *ptr, int order) { + // CIR-LABEL: atomic_store_dynamic_order + // LLVM-LABEL: atomic_store_dynamic_order + // OGCG-LABEL: atomic_store_dynamic_order + + __atomic_store_n(ptr, 10, order); + + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> + // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR: cir.switch (%[[ORDER]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) atomic(relaxed) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) atomic(release) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: cir.store align(4) atomic(seq_cst) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM-NEXT: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4 + // LLVM-NEXT: br label %{{.+}} + // LLVM: [[RELEASE_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4 + // LLVM-NEXT: br label %{{.+}} + // LLVM: [[SEQ_CST_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4 + // LLVM-NEXT: br label %{{.+}} + + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG-NEXT: ] + // OGCG: [[DEFAULT_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4 + // OGCG-NEXT: br label %{{.+}} + // OGCG: [[RELEASE_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4 + // OGCG-NEXT: br label %{{.+}} + // OGCG: [[SEQ_CST_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4 + // OGCG-NEXT: br label %{{.+}} +} + +int atomic_load_and_store_dynamic_order(int *ptr, int order) { + // CIR-LABEL: atomic_load_and_store_dynamic_order + // LLVM-LABEL: atomic_load_and_store_dynamic_order + // OGCG-LABEL: atomic_load_and_store_dynamic_order + + return __atomic_exchange_n(ptr, 20, order); + + // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> + // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR: cir.switch (%[[ORDER]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg relaxed %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acquire %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg release %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<4> : !s32i]) { + // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acq_rel %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i + // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg seq_cst %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i + // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i> + // CIR-NEXT: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + // CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i + + // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]] + // LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM-NEXT: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK:.+]] + // LLVM: [[ACQUIRE_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[RELEASE_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[ACQ_REL_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[SEQ_CST_BLK]]: + // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4 + // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // LLVM-NEXT: br label %[[CONTINUE_BLK]] + // LLVM: [[CONTINUE_BLK]]: + // LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4 + + // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8 + // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]] + // OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG-NEXT: ] + // OGCG: [[DEFAULT_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK:.+]] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[RELEASE_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[ACQ_REL_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4 + // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4 + // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4 + // OGCG-NEXT: br label %[[CONTINUE_BLK]] + // OGCG: [[CONTINUE_BLK]]: + // OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4 +} diff --git a/clang/test/CIR/CodeGen/base-to-derived.cpp b/clang/test/CIR/CodeGen/base-to-derived.cpp new file mode 100644 index 0000000..af9aa0f --- /dev/null +++ b/clang/test/CIR/CodeGen/base-to-derived.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +class A { + int a; +}; + +class B { + int b; +public: + A *getAsA(); +}; + +class X : public A, public B { + int x; +}; + +X *castAtoX(A *a) { + return static_cast<X*>(a); +} + +// CIR: cir.func {{.*}} @_Z8castAtoXP1A(%[[ARG0:.*]]: !cir.ptr<!rec_A> {{.*}}) +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["a", init] +// CIR: cir.store %[[ARG0]], %[[A_ADDR]] : !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>> +// CIR: %[[A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> +// CIR: %[[X:.*]] = cir.derived_class_addr %[[A]] : !cir.ptr<!rec_A> [0] -> !cir.ptr<!rec_X> + +// Note: Because the offset is 0, a null check is not needed. + +// LLVM: define {{.*}} ptr @_Z8castAtoXP1A(ptr %[[ARG0:.*]]) +// LLVM: %[[A_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[A_ADDR]] +// LLVM: %[[X:.*]] = load ptr, ptr %[[A_ADDR]] + +// OGCG: define {{.*}} ptr @_Z8castAtoXP1A(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: %[[A_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], ptr %[[A_ADDR]] +// OGCG: %[[X:.*]] = load ptr, ptr %[[A_ADDR]] + +X *castBtoX(B *b) { + return static_cast<X*>(b); +} + +// CIR: cir.func {{.*}} @_Z8castBtoXP1B(%[[ARG0:.*]]: !cir.ptr<!rec_B> {{.*}}) +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["b", init] +// CIR: cir.store %[[ARG0]], %[[B_ADDR]] : !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>> +// CIR: %[[B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B> +// CIR: %[[X:.*]] = cir.derived_class_addr %[[B]] : !cir.ptr<!rec_B> [4] -> !cir.ptr<!rec_X> + +// LLVM: define {{.*}} ptr @_Z8castBtoXP1B(ptr %[[ARG0:.*]]) +// LLVM: %[[B_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: store ptr %[[ARG0]], ptr %[[B_ADDR]], align 8 +// LLVM: %[[B:.*]] = load ptr, ptr %[[B_ADDR]], align 8 +// LLVM: %[[IS_NULL:.*]] = icmp eq ptr %[[B]], null +// LLVM: %[[B_NON_NULL:.*]] = getelementptr inbounds i8, ptr %[[B]], i32 -4 +// LLVM: %[[X:.*]] = select i1 %[[IS_NULL]], ptr %[[B]], ptr %[[B_NON_NULL]] + +// OGCG: define {{.*}} ptr @_Z8castBtoXP1B(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: entry: +// OGCG: %[[B_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], ptr %[[B_ADDR]] +// OGCG: %[[B:.*]] = load ptr, ptr %[[B_ADDR]] +// OGCG: %[[IS_NULL:.*]] = icmp eq ptr %[[B]], null +// OGCG: br i1 %[[IS_NULL]], label %[[LABEL_NULL:.*]], label %[[LABEL_NOTNULL:.*]] +// OGCG: [[LABEL_NOTNULL]]: +// OGCG: %[[B_NON_NULL:.*]] = getelementptr inbounds i8, ptr %[[B]], i64 -4 +// OGCG: br label %[[LABEL_END:.*]] +// OGCG: [[LABEL_NULL]]: +// OGCG: br label %[[LABEL_END:.*]] +// OGCG: [[LABEL_END]]: +// OGCG: %[[X:.*]] = phi ptr [ %[[B_NON_NULL]], %[[LABEL_NOTNULL]] ], [ null, %[[LABEL_NULL]] ] + +X &castBReftoXRef(B &b) { + return static_cast<X&>(b); +} + +// CIR: cir.func {{.*}} @_Z14castBReftoXRefR1B(%[[ARG0:.*]]: !cir.ptr<!rec_B> {{.*}}) +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["b", init, const] +// CIR: cir.store %[[ARG0]], %[[B_ADDR]] : !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>> +// CIR: %[[B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B> +// CIR: %[[X:.*]] = cir.derived_class_addr %[[B]] : !cir.ptr<!rec_B> nonnull [4] -> !cir.ptr<!rec_X> + +// LLVM: define {{.*}} ptr @_Z14castBReftoXRefR1B(ptr %[[ARG0:.*]]) +// LLVM: %[[B_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[B_ADDR]] +// LLVM: %[[B:.*]] = load ptr, ptr %[[B_ADDR]] +// LLVM: %[[X:.*]] = getelementptr inbounds i8, ptr %[[B]], i32 -4 + +// OGCG: define {{.*}} ptr @_Z14castBReftoXRefR1B(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: %[[B_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], ptr %[[B_ADDR]] +// OGCG: %[[B:.*]] = load ptr, ptr %[[B_ADDR]] +// OGCG: %[[X:.*]] = getelementptr inbounds i8, ptr %[[B]], i64 -4 diff --git a/clang/test/CIR/CodeGen/binassign.c b/clang/test/CIR/CodeGen/binassign.c index 44c54b4..4520063 100644 --- a/clang/test/CIR/CodeGen/binassign.c +++ b/clang/test/CIR/CodeGen/binassign.c @@ -100,3 +100,107 @@ void binary_assign_struct() { // 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 + +int ignore_result_assign() { + int arr[10]; + int i, j; + j = i = 123, 0; + j = arr[i = 5]; + int *p, *q = 0; + if(p = q) + return 1; + return 0; +} + +// CIR-LABEL: cir.func{{.*}} @ignore_result_assign() -> !s32i +// CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, !cir.ptr<!cir.array<!s32i x 10>>, ["arr"] +// CIR: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i"] +// CIR: %[[J:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["j"] +// CIR: %[[P:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p"] +// CIR: %[[Q:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["q", init] +// CIR: %[[VAL_123:.*]] = cir.const #cir.int<123> : !s32i +// CIR: cir.store{{.*}} %[[VAL_123]], %[[I]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[VAL_123]], %[[J]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[VAL_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: %[[VAL_5:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store{{.*}} %[[VAL_5]], %[[I]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ARR_DECAY:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i> +// CIR: %[[ARR_ELEM:.*]] = cir.ptr_stride %[[ARR_DECAY]], %[[VAL_5]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CIR: %[[ARR_LOAD:.*]] = cir.load{{.*}} %[[ARR_ELEM]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store{{.*}} %[[ARR_LOAD]], %[[J]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[NULL]], %[[Q]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.scope { +// CIR: %[[Q_VAL:.*]] = cir.load{{.*}} %[[Q]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[Q_VAL]], %[[P]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[COND:.*]] = cir.cast ptr_to_bool %[[Q_VAL]] : !cir.ptr<!s32i> -> !cir.bool +// CIR: cir.if %[[COND]] { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store %[[ONE]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %{{.*}} = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return +// CIR: } +// CIR: } +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store %[[ZERO]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %{{.*}} = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return + +// LLVM-LABEL: define {{.*}}i32 @ignore_result_assign() +// LLVM: %[[RETVAL_PTR:.*]] = alloca i32 +// LLVM: %[[ARR_PTR:.*]] = alloca [10 x i32] +// LLVM: %[[I_PTR:.*]] = alloca i32 +// LLVM: %[[J_PTR:.*]] = alloca i32 +// LLVM: %[[P_PTR:.*]] = alloca ptr +// LLVM: %[[Q_PTR:.*]] = alloca ptr +// LLVM: store i32 123, ptr %[[I_PTR]] +// LLVM: store i32 123, ptr %[[J_PTR]] +// LLVM: store i32 5, ptr %[[I_PTR]] +// LLVM: %[[GEP1:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 +// LLVM: %[[GEP2:.*]] = getelementptr i32, ptr %[[GEP1]], i64 5 +// LLVM: %[[ARR_VAL:.*]] = load i32, ptr %[[GEP2]] +// LLVM: store i32 %[[ARR_VAL]], ptr %[[J_PTR]] +// LLVM: store ptr null, ptr %[[Q_PTR]] +// LLVM: br label +// LLVM: %[[Q_VAL:.*]] = load ptr, ptr %[[Q_PTR]] +// LLVM: store ptr %[[Q_VAL]], ptr %[[P_PTR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[Q_VAL]], null +// LLVM: br i1 %[[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]] +// LLVM: [[THEN]]: +// LLVM: store i32 1, ptr %[[RETVAL_PTR]] +// LLVM: %{{.*}} = load i32, ptr %[[RETVAL_PTR]] +// LLVM: ret i32 +// LLVM: [[ELSE]]: +// LLVM: br label +// LLVM: store i32 0, ptr %[[RETVAL_PTR]] +// LLVM: %{{.*}} = load i32, ptr %[[RETVAL_PTR]] +// LLVM: ret i32 + +// OGCG-LABEL: define {{.*}}i32 @ignore_result_assign() +// OGCG: %[[RETVAL:.*]] = alloca i32 +// OGCG: %[[ARR:.*]] = alloca [10 x i32] +// OGCG: %[[I:.*]] = alloca i32 +// OGCG: %[[J:.*]] = alloca i32 +// OGCG: %[[P:.*]] = alloca ptr +// OGCG: %[[Q:.*]] = alloca ptr +// OGCG: store i32 123, ptr %[[I]] +// OGCG: store i32 123, ptr %[[J]] +// OGCG: store i32 5, ptr %[[I]] +// OGCG: %[[ARRAYIDX:.*]] = getelementptr inbounds [10 x i32], ptr %[[ARR]], i64 0, i64 5 +// OGCG: %[[ARR_VAL:.*]] = load i32, ptr %[[ARRAYIDX]] +// OGCG: store i32 %[[ARR_VAL]], ptr %[[J]] +// OGCG: store ptr null, ptr %[[Q]] +// OGCG: %[[Q_VAL:.*]] = load ptr, ptr %[[Q]] +// OGCG: store ptr %[[Q_VAL]], ptr %[[P]] +// OGCG: %[[TOBOOL:.*]] = icmp ne ptr %[[Q_VAL]], null +// OGCG: br i1 %[[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] +// OGCG: [[IF_THEN]]: +// OGCG: store i32 1, ptr %[[RETVAL]] +// OGCG: br label %[[RETURN:.*]] +// OGCG: [[IF_END]]: +// OGCG: store i32 0, ptr %[[RETVAL]] +// OGCG: br label %[[RETURN]] +// OGCG: [[RETURN]]: +// OGCG: %{{.*}} = load i32, ptr %[[RETVAL]] +// OGCG: ret i32 diff --git a/clang/test/CIR/CodeGen/bitfield-union.c b/clang/test/CIR/CodeGen/bitfield-union.c index 14a2aaf..9c235c5 100644 --- a/clang/test/CIR/CodeGen/bitfield-union.c +++ b/clang/test/CIR/CodeGen/bitfield-union.c @@ -39,7 +39,7 @@ void f() { // CIR: #bfi_y = #cir.bitfield_info<name = "y", storage_type = !u8i, size = 4, offset = 0, is_signed = true> // CIR: #bfi_z = #cir.bitfield_info<name = "z", storage_type = !u8i, size = 8, offset = 0, is_signed = true> -// CIR: cir.func no_proto dso_local @f +// CIR: cir.func {{.*}} @f // CIR: [[ALLOC:%.*]] = cir.alloca !rec_demo, !cir.ptr<!rec_demo>, ["d"] {alignment = 4 : i64} // CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i // CIR: [[X:%.*]] = cir.get_member [[ALLOC]][0] {name = "x"} : !cir.ptr<!rec_demo> -> !cir.ptr<!s32i> diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index b2c7d1c..d116039 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -122,7 +122,7 @@ unsigned int load_field_unsigned(A* s) { return s->more_bits; } -//CIR: cir.func dso_local @load_field_unsigned +//CIR: cir.func {{.*}} @load_field_unsigned //CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["s", init] {alignment = 8 : i64} //CIR: [[TMP1:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> //CIR: [[TMP2:%.*]] = cir.get_member [[TMP1]][3] {name = "more_bits"} : !cir.ptr<!rec_A> -> !cir.ptr<!u16i> @@ -228,7 +228,7 @@ void get_volatile(V* v) { v->b = 3; } -// CIR: cir.func dso_local @get_volatile +// CIR: cir.func {{.*}} @get_volatile // CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_V>, !cir.ptr<!cir.ptr<!rec_V>>, ["v", init] {alignment = 8 : i64} // CIR: [[TMP1:%.*]] = cir.const #cir.int<3> : !s32i // CIR: [[TMP2:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_V>>, !cir.ptr<!rec_V> @@ -255,7 +255,7 @@ void get_volatile(V* v) { void set_volatile(V* v) { v->b = 3; } -//CIR: cir.func dso_local @set_volatile +//CIR: cir.func {{.*}} @set_volatile //CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_V>, !cir.ptr<!cir.ptr<!rec_V>>, ["v", init] {alignment = 8 : i64} //CIR: [[TMP1:%.*]] = cir.const #cir.int<3> : !s32i //CIR: [[TMP2:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_V>>, !cir.ptr<!rec_V> diff --git a/clang/test/CIR/CodeGen/bitfields.cpp b/clang/test/CIR/CodeGen/bitfields.cpp index 7650e0b..8eeb71c 100644 --- a/clang/test/CIR/CodeGen/bitfields.cpp +++ b/clang/test/CIR/CodeGen/bitfields.cpp @@ -35,7 +35,7 @@ void def() { int load_field(S* s) { return s->c; } -// CIR: cir.func dso_local @_Z10load_field +// CIR: cir.func {{.*}} @_Z10load_field // CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["s", init] // CIR: [[TMP1:%.*]] = cir.load{{.*}} [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> // CIR: [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "c"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i> @@ -63,7 +63,7 @@ void store_field() { S s; s.a = 3; } -// CIR: cir.func dso_local @_Z11store_field +// CIR: cir.func {{.*}} @_Z11store_field // CIR: [[TMP0:%.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S> // CIR: [[TMP1:%.*]] = cir.const #cir.int<3> : !s32i // CIR: [[TMP2:%.*]] = cir.get_member [[TMP0]][0] {name = "a"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i> @@ -88,7 +88,7 @@ void store_bitfield_to_bitfield(S* s) { s->a = s->b = 3; } -// CIR: cir.func dso_local @_Z26store_bitfield_to_bitfieldP1S +// CIR: cir.func {{.*}} @_Z26store_bitfield_to_bitfieldP1S // CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["s", init] {alignment = 8 : i64} // CIR: [[TMP1:%.*]] = cir.const #cir.int<3> : !s32i // CIR: [[TMP2:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> diff --git a/clang/test/CIR/CodeGen/bitfields_be.c b/clang/test/CIR/CodeGen/bitfields_be.c index 3e1f054..f4f3476 100644 --- a/clang/test/CIR/CodeGen/bitfields_be.c +++ b/clang/test/CIR/CodeGen/bitfields_be.c @@ -21,7 +21,7 @@ int init(S* s) { return s->c; } -//CIR: cir.func dso_local @init +//CIR: cir.func {{.*}} @init //CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["s", init] {alignment = 8 : i64} //CIR: [[TMP1:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> //CIR: [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "c"} : !cir.ptr<!rec_S> -> !cir.ptr<!u32i> @@ -51,7 +51,7 @@ void load(S* s) { } // field 'a' -// CIR: cir.func dso_local @load +// CIR: cir.func {{.*}} @load // CIR: %[[PTR0:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["s", init] {alignment = 8 : i64} loc(#loc35) // CIR: %[[CONST1:.*]] = cir.const #cir.int<4> : !s32i // CIR: %[[MIN1:.*]] = cir.unary(minus, %[[CONST1]]) nsw : !s32i, !s32i diff --git a/clang/test/CIR/CodeGen/builtin_bit.cpp b/clang/test/CIR/CodeGen/builtin_bit.cpp deleted file mode 100644 index 32a53d8..0000000 --- a/clang/test/CIR/CodeGen/builtin_bit.cpp +++ /dev/null @@ -1,628 +0,0 @@ -// 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 %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 %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -int test_builtin_clrsb(int x) { - return __builtin_clrsb(x); -} - -// CIR-LABEL: _Z18test_builtin_clrsbi -// CIR: [[TMP:%.+]] = cir.clrsb %{{.+}} : !s32i - -// LLVM-LABEL: _Z18test_builtin_clrsbi -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i32 %[[X]], 0 -// LLVM-NEXT: %[[X_NOT:.+]] = xor i32 %[[X]], -1 -// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i32 %[[X_NOT]], i32 %[[X]] -// LLVM-NEXT: %[[LZ:.+]] = call i32 @llvm.ctlz.i32(i32 %[[P]], i1 false) -// LLVM-NEXT: %{{.+}} = sub i32 %[[LZ]], 1 - -// OGCG-LABEL: _Z18test_builtin_clrsbi -// OGCG: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i32 %[[X]], 0 -// OGCG-NEXT: %[[X_NOT:.+]] = xor i32 %[[X]], -1 -// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i32 %[[X_NOT]], i32 %[[X]] -// OGCG-NEXT: %[[LZ:.+]] = call i32 @llvm.ctlz.i32(i32 %[[P]], i1 false) -// OGCG-NEXT: %{{.+}} = sub i32 %[[LZ]], 1 - -int test_builtin_clrsbl(long x) { - return __builtin_clrsbl(x); -} - -// CIR-LABEL: _Z19test_builtin_clrsbll -// CIR: [[TMP:%.+]] = cir.clrsb %{{.+}} : !s64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !s64i -> !s32i - -// LLVM-LABEL: _Z19test_builtin_clrsbll -// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0 -// LLVM-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1 -// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]] -// LLVM-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false) -// LLVM-NEXT: %{{.+}} = sub i64 %[[LZ]], 1 - -// OGCG-LABEL: _Z19test_builtin_clrsbll -// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0 -// OGCG-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1 -// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]] -// OGCG-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false) -// OGCG-NEXT: %{{.+}} = sub i64 %[[LZ]], 1 - -int test_builtin_clrsbll(long long x) { - return __builtin_clrsbll(x); -} - -// CIR-LABEL: _Z20test_builtin_clrsbllx -// CIR: [[TMP:%.+]] = cir.clrsb %{{.+}} : !s64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !s64i -> !s32i - -// LLVM-LABEL: _Z20test_builtin_clrsbllx -// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0 -// LLVM-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1 -// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]] -// LLVM-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false) -// LLVM-NEXT: %{{.+}} = sub i64 %[[LZ]], 1 - -// OGCG-LABEL: _Z20test_builtin_clrsbllx -// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0 -// OGCG-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1 -// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]] -// OGCG-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false) -// OGCG-NEXT: %{{.+}} = sub i64 %[[LZ]], 1 - -int test_builtin_ctzs(unsigned short x) { - return __builtin_ctzs(x); -} - -// CIR-LABEL: _Z17test_builtin_ctzst -// CIR: [[TMP:%.+]] = cir.ctz %{{.+}} poison_zero : !u16i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u16i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_ctzst -// LLVM: %{{.+}} = call i16 @llvm.cttz.i16(i16 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_ctzst -// OGCG: %{{.+}} = call i16 @llvm.cttz.i16(i16 %{{.+}}, i1 true) - -int test_builtin_ctz(unsigned x) { - return __builtin_ctz(x); -} - -// CIR-LABEL: _Z16test_builtin_ctzj -// CIR: [[TMP:%.+]] = cir.ctz %{{.+}} poison_zero : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z16test_builtin_ctzj -// LLVM: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z16test_builtin_ctzj -// OGCG: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true) - -int test_builtin_ctzl(unsigned long x) { - return __builtin_ctzl(x); -} - -// CIR-LABEL: _Z17test_builtin_ctzlm -// CIR: [[TMP:%.+]] = cir.ctz %{{.+}} poison_zero : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_ctzlm -// LLVM: %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_ctzlm -// OGCG: %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true) - -int test_builtin_ctzll(unsigned long long x) { - return __builtin_ctzll(x); -} - -// CIR-LABEL: _Z18test_builtin_ctzlly -// CIR: [[TMP:%.+]] = cir.ctz %{{.+}} poison_zero : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z18test_builtin_ctzlly -// LLVM: %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z18test_builtin_ctzlly -// OGCG: %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true) - -int test_builtin_ctzg(unsigned x) { - return __builtin_ctzg(x); -} - -// CIR-LABEL: _Z17test_builtin_ctzgj -// CIR: [[TMP:%.+]] = cir.ctz %{{.+}} poison_zero : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_ctzgj -// LLVM: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_ctzgj -// OGCG: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true) - -int test_builtin_clzs(unsigned short x) { - return __builtin_clzs(x); -} - -// CIR-LABEL: _Z17test_builtin_clzst -// CIR: [[TMP:%.+]] = cir.clz %{{.+}} poison_zero : !u16i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u16i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_clzst -// LLVM: %{{.+}} = call i16 @llvm.ctlz.i16(i16 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_clzst -// OGCG: %{{.+}} = call i16 @llvm.ctlz.i16(i16 %{{.+}}, i1 true) - -int test_builtin_clz(unsigned x) { - return __builtin_clz(x); -} - -// CIR-LABEL: _Z16test_builtin_clzj -// CIR: [[TMP:%.+]] = cir.clz %{{.+}} poison_zero : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z16test_builtin_clzj -// LLVM: %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z16test_builtin_clzj -// OGCG: %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true) - -int test_builtin_clzl(unsigned long x) { - return __builtin_clzl(x); -} - -// CIR-LABEL: _Z17test_builtin_clzlm -// CIR: [[TMP:%.+]] = cir.clz %{{.+}} poison_zero : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_clzlm -// LLVM: %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_clzlm -// OGCG: %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true) - -int test_builtin_clzll(unsigned long long x) { - return __builtin_clzll(x); -} - -// CIR-LABEL: _Z18test_builtin_clzlly -// CIR: [[TMP:%.+]] = cir.clz %{{.+}} poison_zero : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z18test_builtin_clzlly -// LLVM: %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z18test_builtin_clzlly -// OGCG: %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true) - -int test_builtin_clzg(unsigned x) { - return __builtin_clzg(x); -} - -// CIR-LABEL: _Z17test_builtin_clzgj -// CIR: [[TMP:%.+]] = cir.clz %{{.+}} poison_zero : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z17test_builtin_clzgj -// LLVM: %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true) - -// OGCG-LABEL: _Z17test_builtin_clzgj -// OGCG: %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true) - -int test_builtin_ffs(int x) { - return __builtin_ffs(x); -} - -// CIR-LABEL: _Z16test_builtin_ffsi -// CIR: %{{.+}} = cir.ffs %{{.+}} : !s32i -// CIR: } - -// LLVM-LABEL: _Z16test_builtin_ffsi -// LLVM: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[CTZ:.+]] = call i32 @llvm.cttz.i32(i32 %[[INPUT]], i1 true) -// LLVM-NEXT: %[[R1:.+]] = add i32 %[[CTZ]], 1 -// LLVM-NEXT: %[[IS_ZERO:.+]] = icmp eq i32 %[[INPUT]], 0 -// LLVM-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i32 0, i32 %[[R1]] -// LLVM: } - -// OGCG-LABEL: _Z16test_builtin_ffsi -// OGCG: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %[[CTZ:.+]] = call i32 @llvm.cttz.i32(i32 %[[INPUT]], i1 true) -// OGCG-NEXT: %[[R1:.+]] = add i32 %[[CTZ]], 1 -// OGCG-NEXT: %[[IS_ZERO:.+]] = icmp eq i32 %[[INPUT]], 0 -// OGCG-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i32 0, i32 %[[R1]] -// OGCG: } - -int test_builtin_ffsl(long x) { - return __builtin_ffsl(x); -} - -// CIR-LABEL: _Z17test_builtin_ffsll -// CIR: %{{.+}} = cir.ffs %{{.+}} : !s64i -// CIR: } - -// LLVM-LABEL: _Z17test_builtin_ffsll -// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[CTZ:.+]] = call i64 @llvm.cttz.i64(i64 %[[INPUT]], i1 true) -// LLVM-NEXT: %[[R1:.+]] = add i64 %[[CTZ]], 1 -// LLVM-NEXT: %[[IS_ZERO:.+]] = icmp eq i64 %[[INPUT]], 0 -// LLVM-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i64 0, i64 %[[R1]] -// LLVM: } - -// OGCG-LABEL: _Z17test_builtin_ffsll -// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[CTZ:.+]] = call i64 @llvm.cttz.i64(i64 %[[INPUT]], i1 true) -// OGCG-NEXT: %[[R1:.+]] = add i64 %[[CTZ]], 1 -// OGCG-NEXT: %[[IS_ZERO:.+]] = icmp eq i64 %[[INPUT]], 0 -// OGCG-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i64 0, i64 %[[R1]] -// OGCG: } - -int test_builtin_ffsll(long long x) { - return __builtin_ffsll(x); -} - -// CIR-LABEL: _Z18test_builtin_ffsllx -// CIR: %{{.+}} = cir.ffs %{{.+}} : !s64i -// CIR: } - -// LLVM-LABEL: _Z18test_builtin_ffsllx -// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[CTZ:.+]] = call i64 @llvm.cttz.i64(i64 %[[INPUT]], i1 true) -// LLVM-NEXT: %[[R1:.+]] = add i64 %[[CTZ]], 1 -// LLVM-NEXT: %[[IS_ZERO:.+]] = icmp eq i64 %[[INPUT]], 0 -// LLVM-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i64 0, i64 %[[R1]] -// LLVM: } - -// OGCG-LABEL: _Z18test_builtin_ffsllx -// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[CTZ:.+]] = call i64 @llvm.cttz.i64(i64 %[[INPUT]], i1 true) -// OGCG-NEXT: %[[R1:.+]] = add i64 %[[CTZ]], 1 -// OGCG-NEXT: %[[IS_ZERO:.+]] = icmp eq i64 %[[INPUT]], 0 -// OGCG-NEXT: %{{.+}} = select i1 %[[IS_ZERO]], i64 0, i64 %[[R1]] -// OGCG: } - -int test_builtin_parity(unsigned x) { - return __builtin_parity(x); -} - -// CIR-LABEL: _Z19test_builtin_parityj -// CIR: [[TMP:%.+]] = cir.parity %{{.+}} : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z19test_builtin_parityj -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[POPCNT:.+]] = call i32 @llvm.ctpop.i32(i32 %[[X]]) -// LLVM-NEXT: %{{.+}} = and i32 %[[POPCNT]], 1 - -// OGCG-LABEL: _Z19test_builtin_parityj -// OGCG: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %[[POPCNT:.+]] = call i32 @llvm.ctpop.i32(i32 %[[X]]) -// OGCG-NEXT: %{{.+}} = and i32 %[[POPCNT]], 1 - -int test_builtin_parityl(unsigned long x) { - return __builtin_parityl(x); -} - -// CIR-LABEL: _Z20test_builtin_paritylm -// CIR: [[TMP:%.+]] = cir.parity %{{.+}} : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z20test_builtin_paritylm -// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]]) -// LLVM-NEXT: %{{.+}} = and i64 %[[POPCNT]], 1 - -// OGCG-LABEL: _Z20test_builtin_paritylm -// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]]) -// OGCG-NEXT: %{{.+}} = and i64 %[[POPCNT]], 1 - -int test_builtin_parityll(unsigned long long x) { - return __builtin_parityll(x); -} - -// CIR-LABEL: _Z21test_builtin_paritylly -// CIR: [[TMP:%.+]] = cir.parity %{{.+}} : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z21test_builtin_paritylly -// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]]) -// LLVM-NEXT: %{{.+}} = and i64 %[[POPCNT]], 1 - -// OGCG-LABEL: _Z21test_builtin_paritylly -// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]]) -// OGCG-NEXT: %{{.+}} = and i64 %[[POPCNT]], 1 - -int test_builtin_popcount(unsigned x) { - return __builtin_popcount(x); -} - -// CIR-LABEL: _Z21test_builtin_popcountj -// CIR: [[TMP:%.+]] = cir.popcount %{{.+}} : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z21test_builtin_popcountj -// LLVM: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}}) - -// OGCG-LABEL: _Z21test_builtin_popcountj -// OGCG: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}}) - -int test_builtin_popcountl(unsigned long x) { - return __builtin_popcountl(x); -} - -// CIR-LABEL: _Z22test_builtin_popcountlm -// CIR: [[TMP:%.+]] = cir.popcount %{{.+}} : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z22test_builtin_popcountlm -// LLVM: %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}}) - -// OGCG-LABEL: _Z22test_builtin_popcountlm -// OGCG: %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}}) - -int test_builtin_popcountll(unsigned long long x) { - return __builtin_popcountll(x); -} - -// CIR-LABEL: _Z23test_builtin_popcountlly -// CIR: [[TMP:%.+]] = cir.popcount %{{.+}} : !u64i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u64i -> !s32i - -// LLVM-LABEL: _Z23test_builtin_popcountlly -// LLVM: %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}}) - -// OGCG-LABEL: _Z23test_builtin_popcountlly -// OGCG: %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}}) - -int test_builtin_popcountg(unsigned x) { - return __builtin_popcountg(x); -} - -// CIR-LABEL: _Z22test_builtin_popcountgj -// CIR: [[TMP:%.+]] = cir.popcount %{{.+}} : !u32i -// CIR: {{%.+}} = cir.cast integral [[TMP]] : !u32i -> !s32i - -// LLVM-LABEL: _Z22test_builtin_popcountgj -// LLVM: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}}) - -// OGCG-LABEL: _Z22test_builtin_popcountgj -// OGCG: %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}}) - -unsigned char test_builtin_bitreverse8(unsigned char x) { - return __builtin_bitreverse8(x); -} - -// CIR-LABEL: @_Z24test_builtin_bitreverse8h -// CIR: %{{.+}} = cir.bitreverse %{{.+}} : !u8i - -// LLVM-LABEL: @_Z24test_builtin_bitreverse8h -// LLVM: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}}) - -// OGCG-LABEL: @_Z24test_builtin_bitreverse8h -// OGCG: %{{.+}} = call i8 @llvm.bitreverse.i8(i8 %{{.+}}) - -unsigned short test_builtin_bitreverse16(unsigned short x) { - return __builtin_bitreverse16(x); -} - -// CIR-LABEL: @_Z25test_builtin_bitreverse16t -// CIR: %{{.+}} = cir.bitreverse %{{.+}} : !u16i - -// LLVM-LABEL: @_Z25test_builtin_bitreverse16t -// LLVM: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}}) - -// OGCG-LABEL: @_Z25test_builtin_bitreverse16t -// OGCG: %{{.+}} = call i16 @llvm.bitreverse.i16(i16 %{{.+}}) - -unsigned test_builtin_bitreverse32(unsigned x) { - return __builtin_bitreverse32(x); -} - -// CIR-LABEL: @_Z25test_builtin_bitreverse32j -// CIR: %{{.+}} = cir.bitreverse %{{.+}} : !u32i - -// LLVM-LABEL: @_Z25test_builtin_bitreverse32j -// LLVM: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}}) - -// OGCG-LABEL: @_Z25test_builtin_bitreverse32j -// OGCG: %{{.+}} = call i32 @llvm.bitreverse.i32(i32 %{{.+}}) - -unsigned long long test_builtin_bitreverse64(unsigned long long x) { - return __builtin_bitreverse64(x); -} - -// CIR-LABEL: @_Z25test_builtin_bitreverse64y -// CIR: %{{.+}} = cir.bitreverse %{{.+}} : !u64i - -// LLVM-LABEL: @_Z25test_builtin_bitreverse64y -// LLVM: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}}) - -// OGCG-LABEL: @_Z25test_builtin_bitreverse64y -// OGCG: %{{.+}} = call i64 @llvm.bitreverse.i64(i64 %{{.+}}) - -unsigned short test_builtin_bswap16(unsigned short x) { - return __builtin_bswap16(x); -} - -// CIR-LABEL: @_Z20test_builtin_bswap16t -// CIR: %{{.+}} = cir.byte_swap %{{.+}} : !u16i - -// LLVM-LABEL: @_Z20test_builtin_bswap16t -// LLVM: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}}) - -// OGCG-LABEL: @_Z20test_builtin_bswap16t -// OGCG: %{{.+}} = call i16 @llvm.bswap.i16(i16 %{{.+}}) - -unsigned test_builtin_bswap32(unsigned x) { - return __builtin_bswap32(x); -} - -// CIR-LABEL: @_Z20test_builtin_bswap32j -// CIR: %{{.+}} = cir.byte_swap %{{.+}} : !u32i - -// LLVM-LABEL: @_Z20test_builtin_bswap32j -// LLVM: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}}) - -// OGCG-LABEL: @_Z20test_builtin_bswap32j -// OGCG: %{{.+}} = call i32 @llvm.bswap.i32(i32 %{{.+}}) - -unsigned long long test_builtin_bswap64(unsigned long long x) { - return __builtin_bswap64(x); -} - -// CIR-LABEL: @_Z20test_builtin_bswap64y -// CIR: %{{.+}} = cir.byte_swap %{{.+}} : !u64i - -// LLVM-LABEL: @_Z20test_builtin_bswap64y -// LLVM: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}}) - -// OGCG-LABEL: @_Z20test_builtin_bswap64y -// OGCG: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}}) - -unsigned char test_builtin_rotateleft8(unsigned char x, unsigned char y) { - return __builtin_rotateleft8(x, y); -} - -// CIR-LABEL: @_Z24test_builtin_rotateleft8hh -// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u8i - -// LLVM-LABEL: @_Z24test_builtin_rotateleft8hh -// LLVM: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1 -// LLVM-NEXT: %{{.+}} = call i8 @llvm.fshl.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z24test_builtin_rotateleft8hh -// OGCG: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1 -// OGCG-NEXT: %{{.+}} = call i8 @llvm.fshl.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]]) - -unsigned short test_builtin_rotateleft16(unsigned short x, unsigned short y) { - return __builtin_rotateleft16(x, y); -} - -// CIR-LABEL: @_Z25test_builtin_rotateleft16tt -// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u16i - -// LLVM-LABEL: @_Z25test_builtin_rotateleft16tt -// LLVM: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2 -// LLVM-NEXT: %{{.+}} = call i16 @llvm.fshl.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z25test_builtin_rotateleft16tt -// OGCG: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2 -// OGCG-NEXT: %{{.+}} = call i16 @llvm.fshl.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]]) - -unsigned test_builtin_rotateleft32(unsigned x, unsigned y) { - return __builtin_rotateleft32(x, y); -} - -// CIR-LABEL: @_Z25test_builtin_rotateleft32jj -// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u32i - -// LLVM-LABEL: @_Z25test_builtin_rotateleft32jj -// LLVM: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %{{.+}} = call i32 @llvm.fshl.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z25test_builtin_rotateleft32jj -// OGCG: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %{{.+}} = call i32 @llvm.fshl.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]]) - -unsigned long long test_builtin_rotateleft64(unsigned long long x, - unsigned long long y) { - return __builtin_rotateleft64(x, y); -} - -// CIR-LABEL: @_Z25test_builtin_rotateleft64yy -// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u64i - -// LLVM-LABEL: @_Z25test_builtin_rotateleft64yy -// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.fshl.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z25test_builtin_rotateleft64yy -// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %{{.+}} = call i64 @llvm.fshl.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]]) - -unsigned char test_builtin_rotateright8(unsigned char x, unsigned char y) { - return __builtin_rotateright8(x, y); -} - -// CIR-LABEL: @_Z25test_builtin_rotateright8hh -// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u8i - -// LLVM-LABEL: @_Z25test_builtin_rotateright8hh -// LLVM: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1 -// LLVM-NEXT: %{{.+}} = call i8 @llvm.fshr.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z25test_builtin_rotateright8hh -// OGCG: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1 -// OGCG-NEXT: %{{.+}} = call i8 @llvm.fshr.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]]) - -unsigned short test_builtin_rotateright16(unsigned short x, unsigned short y) { - return __builtin_rotateright16(x, y); -} - -// CIR-LABEL: @_Z26test_builtin_rotateright16tt -// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u16i - -// LLVM-LABEL: @_Z26test_builtin_rotateright16tt -// LLVM: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2 -// LLVM-NEXT: %{{.+}} = call i16 @llvm.fshr.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z26test_builtin_rotateright16tt -// OGCG: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2 -// OGCG-NEXT: %{{.+}} = call i16 @llvm.fshr.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]]) - -unsigned test_builtin_rotateright32(unsigned x, unsigned y) { - return __builtin_rotateright32(x, y); -} - -// CIR-LABEL: @_Z26test_builtin_rotateright32jj -// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u32i - -// LLVM-LABEL: @_Z26test_builtin_rotateright32jj -// LLVM: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %{{.+}} = call i32 @llvm.fshr.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z26test_builtin_rotateright32jj -// OGCG: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4 -// OGCG-NEXT: %{{.+}} = call i32 @llvm.fshr.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]]) - -unsigned long long test_builtin_rotateright64(unsigned long long x, - unsigned long long y) { - return __builtin_rotateright64(x, y); -} - -// CIR-LABEL: @_Z26test_builtin_rotateright64yy -// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u64i - -// LLVM-LABEL: @_Z26test_builtin_rotateright64yy -// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.fshr.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]]) - -// OGCG-LABEL: @_Z26test_builtin_rotateright64yy -// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8 -// OGCG-NEXT: %{{.+}} = call i64 @llvm.fshr.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]]) diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp deleted file mode 100644 index a08a784..0000000 --- a/clang/test/CIR/CodeGen/builtin_call.cpp +++ /dev/null @@ -1,308 +0,0 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR -// RUN: %clang_cc1 -std=c++11 -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 -// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -constexpr extern int cx_var = __builtin_is_constant_evaluated(); - -// CIR: cir.global {{.*}} @cx_var = #cir.int<1> : !s32i -// LLVM: @cx_var = {{.*}} i32 1 -// OGCG: @cx_var = {{.*}} i32 1 - -constexpr extern float cx_var_single = __builtin_huge_valf(); - -// CIR: cir.global {{.*}} @cx_var_single = #cir.fp<0x7F800000> : !cir.float -// LLVM: @cx_var_single = {{.*}} float 0x7FF0000000000000 -// OGCG: @cx_var_single = {{.*}} float 0x7FF0000000000000 - -constexpr extern long double cx_var_ld = __builtin_huge_vall(); - -// CIR: cir.global {{.*}} @cx_var_ld = #cir.fp<0x7FFF8000000000000000> : !cir.long_double<!cir.f80> -// LLVM: @cx_var_ld = {{.*}} x86_fp80 0xK7FFF8000000000000000 -// OGCG: @cx_var_ld = {{.*}} x86_fp80 0xK7FFF8000000000000000 - -int is_constant_evaluated() { - return __builtin_is_constant_evaluated(); -} - -// CIR: cir.func{{.*}} @_Z21is_constant_evaluatedv() -> !s32i -// CIR: %[[ZERO:.+]] = cir.const #cir.int<0> - -// LLVM: define {{.*}}i32 @_Z21is_constant_evaluatedv() -// LLVM: %[[MEM:.+]] = alloca i32 -// LLVM: store i32 0, ptr %[[MEM]] -// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[MEM]] -// LLVM: ret i32 %[[RETVAL]] -// LLVM: } - -// OGCG: define {{.*}}i32 @_Z21is_constant_evaluatedv() -// OGCG: ret i32 0 -// OGCG: } - -long double constant_fp_builtin_ld() { - return __builtin_fabsl(-0.1L); -} - -// CIR: cir.func{{.*}} @_Z22constant_fp_builtin_ldv() -> !cir.long_double<!cir.f80> -// CIR: %[[PONE:.+]] = cir.const #cir.fp<1.000000e-01> : !cir.long_double<!cir.f80> - -// LLVM: define {{.*}}x86_fp80 @_Z22constant_fp_builtin_ldv() -// LLVM: %[[MEM:.+]] = alloca x86_fp80 -// LLVM: store x86_fp80 0xK3FFBCCCCCCCCCCCCCCCD, ptr %[[MEM]] -// LLVM: %[[RETVAL:.+]] = load x86_fp80, ptr %[[MEM]] -// LLVM: ret x86_fp80 %[[RETVAL]] -// LLVM: } - -// OGCG: define {{.*}}x86_fp80 @_Z22constant_fp_builtin_ldv() -// OGCG: ret x86_fp80 0xK3FFBCCCCCCCCCCCCCCCD -// OGCG: } - -float constant_fp_builtin_single() { - return __builtin_fabsf(-0.1f); -} - -// CIR: cir.func{{.*}} @_Z26constant_fp_builtin_singlev() -> !cir.float -// CIR: %[[PONE:.+]] = cir.const #cir.fp<1.000000e-01> : !cir.float - -// LLVM: define {{.*}}float @_Z26constant_fp_builtin_singlev() -// LLVM: %[[MEM:.+]] = alloca float -// LLVM: store float 0x3FB99999A0000000, ptr %[[MEM]] -// LLVM: %[[RETVAL:.+]] = load float, ptr %[[MEM]] -// LLVM: ret float %[[RETVAL]] -// LLVM: } - -// OGCG: define {{.*}}float @_Z26constant_fp_builtin_singlev() -// OGCG: ret float 0x3FB99999A0000000 -// OGCG: } - -void library_builtins() { - __builtin_printf(nullptr); - __builtin_abort(); -} - -// CIR: cir.func{{.*}} @_Z16library_builtinsv() -// CIR: %[[NULL:.+]] = cir.const #cir.ptr<null> : !cir.ptr<!s8i> -// CIR: cir.call @printf(%[[NULL]]) nothrow : (!cir.ptr<!s8i>) -> !s32i -// CIR: cir.call @abort() nothrow : () -> () - -// LLVM: define{{.*}} void @_Z16library_builtinsv() -// LLVM: call i32 (ptr, ...) @printf(ptr null) -// LLVM: call void @abort() - -// OGCG: define{{.*}} void @_Z16library_builtinsv() -// OGCG: call i32 (ptr, ...) @printf(ptr noundef null) -// OGCG: call void @abort() - -void assume(bool arg) { - __builtin_assume(arg); -} - -// CIR: cir.func{{.*}} @_Z6assumeb -// CIR: cir.assume %{{.+}} : !cir.bool -// CIR: } - -// LLVM: define {{.*}}void @_Z6assumeb -// LLVM: call void @llvm.assume(i1 %{{.+}}) -// LLVM: } - -// OGCG: define {{.*}}void @_Z6assumeb -// OGCG: call void @llvm.assume(i1 %{{.+}}) -// OGCG: } - -void *assume_aligned(void *ptr) { - return __builtin_assume_aligned(ptr, 16); -} - -// CIR: @_Z14assume_alignedPv -// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16 : !cir.ptr<!void> -// CIR: } - -// LLVM: @_Z14assume_alignedPv -// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] -// LLVM: } - -// OGCG: @_Z14assume_alignedPv -// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] -// OGCG: } - -void *assume_aligned_misalignment(void *ptr, unsigned misalignment) { - return __builtin_assume_aligned(ptr, 16, misalignment); -} - -// CIR: @_Z27assume_aligned_misalignmentPvj -// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16[offset %{{.+}} : !u64i] : !cir.ptr<!void> -// CIR: } - -// LLVM: @_Z27assume_aligned_misalignmentPvj -// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] -// LLVM: } - -// OGCG: @_Z27assume_aligned_misalignmentPvj -// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] -// OGCG: } - -void assume_separate_storage(void *p1, void *p2) { - __builtin_assume_separate_storage(p1, p2); -} - -// CIR: cir.func{{.*}} @_Z23assume_separate_storagePvS_ -// CIR: cir.assume_separate_storage %{{.+}}, %{{.+}} : !cir.ptr<!void> -// CIR: } - -// LLVM: define {{.*}}void @_Z23assume_separate_storagePvS_ -// LLVM: call void @llvm.assume(i1 true) [ "separate_storage"(ptr %{{.+}}, ptr %{{.+}}) ] -// LLVM: } - -// OGCG: define {{.*}}void @_Z23assume_separate_storagePvS_ -// OGCG: call void @llvm.assume(i1 true) [ "separate_storage"(ptr %{{.+}}, ptr %{{.+}}) ] -// OGCG: } - -void expect(int x, int y) { - __builtin_expect(x, y); -} - -// CIR-LABEL: cir.func{{.*}} @_Z6expectii -// CIR: %[[X:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i -// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i -// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i -// CIR-NEXT: %[[Y_LONG:.+]] = cir.cast integral %[[Y]] : !s32i -> !s64i -// CIR-NEXT: %{{.+}} = cir.expect(%[[X_LONG]], %[[Y_LONG]]) : !s64i -// CIR: } - -// LLVM-LABEL: define{{.*}} void @_Z6expectii -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[X_LONG:.+]] = sext i32 %[[X]] to i64 -// LLVM-NEXT: %[[Y:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[Y_LONG:.+]] = sext i32 %[[Y]] to i64 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.expect.i64(i64 %[[X_LONG]], i64 %[[Y_LONG]]) -// LLVM: } - -void expect_prob(int x, int y) { - __builtin_expect_with_probability(x, y, 0.25); -} - -// CIR-LABEL: cir.func{{.*}} @_Z11expect_probii -// CIR: %[[X:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i -// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i -// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i -// CIR-NEXT: %[[Y_LONG:.+]] = cir.cast integral %[[Y]] : !s32i -> !s64i -// CIR-NEXT: %{{.+}} = cir.expect(%[[X_LONG]], %[[Y_LONG]], 2.500000e-01) : !s64i -// CIR: } - -// LLVM: define{{.*}} void @_Z11expect_probii -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[X_LONG:.+]] = sext i32 %[[X]] to i64 -// LLVM-NEXT: %[[Y:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[Y_LONG:.+]] = sext i32 %[[Y]] to i64 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.expect.with.probability.i64(i64 %[[X_LONG]], i64 %[[Y_LONG]], double 2.500000e-01) -// LLVM: } - -void unreachable() { - __builtin_unreachable(); -} - -// CIR-LABEL: @_Z11unreachablev -// CIR: cir.unreachable -// CIR: } - -// LLVM-LABEL: @_Z11unreachablev -// LLVM: unreachable -// LLVM: } - -// OGCG-LABEL: @_Z11unreachablev -// OGCG: unreachable -// OGCG: } - -void f1(); -void unreachable2() { - __builtin_unreachable(); - f1(); -} - -// CIR-LABEL: @_Z12unreachable2v -// CIR: cir.unreachable -// CIR-NEXT: ^{{.+}}: -// CIR-NEXT: cir.call @_Z2f1v() : () -> () -// CIR: } - -// LLVM-LABEL: @_Z12unreachable2v -// LLVM: unreachable -// LLVM: {{.+}}: -// LLVM-NEXT: call void @_Z2f1v() -// LLVM: } - -// OGCG-LABEL: @_Z12unreachable2v -// OGCG: unreachable - -void trap() { - __builtin_trap(); -} - -// CIR-LABEL: @_Z4trapv -// CIR: cir.trap -// CIR: } - -// LLVM-LABEL: @_Z4trapv -// LLVM: call void @llvm.trap() -// LLVM: } - -// OGCG-LABEL: @_Z4trapv -// OGCG: call void @llvm.trap() -// OGCG: } - -void trap2() { - __builtin_trap(); - f1(); -} - -// CIR-LABEL: @_Z5trap2v -// CIR: cir.trap -// CIR-NEXT: ^{{.+}}: -// CIR-NEXT: cir.call @_Z2f1v() : () -> () -// CIR: } - -// LLVM-LABEL: @_Z5trap2v -// LLVM: call void @llvm.trap() -// LLVM-NEXT: unreachable -// LLVM: {{.+}}: -// LLVM-NEXT: call void @_Z2f1v() -// LLVM: } - -// OGCG-LABEL: define{{.*}} void @_Z5trap2v -// OGCG: call void @llvm.trap() -// OGCG-NEXT: call void @_Z2f1v() -// OGCG: ret void -// OGCG: } - -void *test_alloca(unsigned long n) { - return __builtin_alloca(n); -} - -// CIR-LABEL: @_Z11test_allocam( -// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"] - -// LLVM-LABEL: @_Z11test_allocam( -// LLVM: alloca i8, i64 %{{.+}} - -// OGCG-LABEL: @_Z11test_allocam( -// OGCG: alloca i8, i64 %{{.+}} - -bool test_multiple_allocas(unsigned long n) { - void *a = __builtin_alloca(n); - void *b = __builtin_alloca(n); - return a != b; -} - -// CIR-LABEL: @_Z21test_multiple_allocasm( -// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"] -// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"] - -// LLVM-LABEL: @_Z21test_multiple_allocasm( -// LLVM: alloca i8, i64 %{{.+}} -// LLVM: alloca i8, i64 %{{.+}} - -// OGCG-LABEL: @_Z21test_multiple_allocasm( -// OGCG: alloca i8, i64 %{{.+}} -// OGCG: alloca i8, i64 %{{.+}} diff --git a/clang/test/CIR/CodeGen/builtin_inline.c b/clang/test/CIR/CodeGen/builtin_inline.c deleted file mode 100644 index 83a3ba6..0000000 --- a/clang/test/CIR/CodeGen/builtin_inline.c +++ /dev/null @@ -1,91 +0,0 @@ -// 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/builtin_prefetch.c b/clang/test/CIR/CodeGen/builtin_prefetch.c deleted file mode 100644 index cfe85b9..0000000 --- a/clang/test/CIR/CodeGen/builtin_prefetch.c +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s -check-prefix=CIR -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=LLVM -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=OGCG - -void foo(void *a) { - __builtin_prefetch(a); // rw=0, locality=3 - __builtin_prefetch(a, 0); // rw=0, locality=3 - __builtin_prefetch(a, 1); // rw=1, locality=3 - __builtin_prefetch(a, 1, 1); // rw=1, locality=1 -} - -// CIR-LABEL: cir.func dso_local @foo( -// CIR: %[[ALLOCA:.*]] = cir.alloca !cir.ptr<!void> -// CIR: cir.store %arg0, %[[ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> -// CIR: %[[P1:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> -// CIR: cir.prefetch read locality(3) %[[P1]] : !cir.ptr<!void> -// CIR: %[[P2:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> -// CIR: cir.prefetch read locality(3) %[[P2]] : !cir.ptr<!void> -// CIR: %[[P3:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> -// CIR: cir.prefetch write locality(3) %[[P3]] : !cir.ptr<!void> -// CIR: %[[P4:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> -// CIR: cir.prefetch write locality(1) %[[P4]] : !cir.ptr<!void> -// CIR: cir.return - -// LLVM-LABEL: define dso_local void @foo( -// LLVM: [[ALLOCA:%.*]] = alloca ptr, i64 1 -// LLVM: store ptr {{.*}}, ptr [[ALLOCA]] -// LLVM: [[LP1:%.*]] = load ptr, ptr [[ALLOCA]] -// LLVM: call void @llvm.prefetch.p0(ptr [[LP1]], i32 0, i32 3, i32 1) -// LLVM: [[LP2:%.*]] = load ptr, ptr [[ALLOCA]] -// LLVM: call void @llvm.prefetch.p0(ptr [[LP2]], i32 0, i32 3, i32 1) -// LLVM: [[LP3:%.*]] = load ptr, ptr [[ALLOCA]] -// LLVM: call void @llvm.prefetch.p0(ptr [[LP3]], i32 1, i32 3, i32 1) -// LLVM: [[LP4:%.*]] = load ptr, ptr [[ALLOCA]] -// LLVM: call void @llvm.prefetch.p0(ptr [[LP4]], i32 1, i32 1, i32 1) -// LLVM: ret void - -// OGCG-LABEL: define dso_local void @foo(ptr -// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1) -// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1) -// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1) -// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 1, i32 1) -// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/builtin_printf.cpp b/clang/test/CIR/CodeGen/builtin_printf.cpp deleted file mode 100644 index 7200df1..0000000 --- a/clang/test/CIR/CodeGen/builtin_printf.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR -// RUN: %clang_cc1 -std=c++11 -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 -// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -// CIR: cir.global "private" constant cir_private dso_local @".str" = #cir.const_array<"%s\00" : !cir.array<!s8i x 3>> : !cir.array<!s8i x 3> -// CIR: cir.global "private" constant cir_private dso_local @".str.1" = #cir.const_array<"%s %d\0A\00" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7> -// LLVM: @.str = private constant [3 x i8] c"%s\00" -// LLVM: @.str.1 = private constant [7 x i8] c"%s %d\0A\00" -// OGCG: @.str = private unnamed_addr constant [3 x i8] c"%s\00" -// OGCG: @.str.1 = private unnamed_addr constant [7 x i8] c"%s %d\0A\00" - -void func(char const * const str, int i) { - __builtin_printf(nullptr); - __builtin_printf("%s", str); - __builtin_printf("%s %d\n", str, i); -} - -// CIR: cir.func{{.*}} @printf(!cir.ptr<!s8i>, ...) -> !s32i - -// CIR: cir.func{{.*}} @_Z4funcPKci(%[[arg0:.+]]: !cir.ptr<!s8i>{{.*}}, %[[arg1:.+]]: !s32i -// CIR: %[[str_ptr:.+]] = cir.alloca !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>, ["str", init, const] -// CIR: %[[i_ptr:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] -// CIR: cir.store %[[arg0]], %[[str_ptr]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>> -// CIR: cir.store %[[arg1]], %[[i_ptr]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[null_ptr:.+]] = cir.const #cir.ptr<null> : !cir.ptr<!s8i> -// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) nothrow : (!cir.ptr<!s8i>) -> !s32i -// CIR: %[[str_fmt_global:.+]] = cir.get_global @".str" : !cir.ptr<!cir.array<!s8i x 3>> -// CIR: %[[str_fmt_ptr:.+]] = cir.cast array_to_ptrdecay %[[str_fmt_global]] : !cir.ptr<!cir.array<!s8i x 3>> -> !cir.ptr<!s8i> -// CIR: %[[str_val:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!s8i> -// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) nothrow : (!cir.ptr<!s8i>, !cir.ptr<!s8i>) -> !s32i -// CIR: %[[full_fmt_global:.+]] = cir.get_global @".str.1" : !cir.ptr<!cir.array<!s8i x 7>> -// CIR: %[[full_fmt_ptr:.+]] = cir.cast array_to_ptrdecay %[[full_fmt_global]] : !cir.ptr<!cir.array<!s8i x 7>> -> !cir.ptr<!s8i> -// CIR: %[[str_val2:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!s8i> -// CIR: %[[i_val:.+]] = cir.load{{.*}} %[[i_ptr]] : !cir.ptr<!s32i>, !s32i -// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) nothrow : (!cir.ptr<!s8i>, !cir.ptr<!s8i>, !s32i) -> !s32i -// CIR: cir.return - -// LLVM: define{{.*}} void @_Z4funcPKci(ptr %[[arg0:.+]], i32 %[[arg1:.+]]) -// LLVM: %[[str_ptr:.+]] = alloca ptr -// LLVM: %[[i_ptr:.+]] = alloca i32 -// LLVM: store ptr %[[arg0]], ptr %[[str_ptr]]{{.*}} -// LLVM: store i32 %[[arg1]], ptr %[[i_ptr]]{{.*}} -// LLVM: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr null) -// LLVM: %[[str_val:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} -// LLVM: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr @.str, ptr %[[str_val]]) -// LLVM: %[[str_val2:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} -// LLVM: %[[i_val:.+]] = load i32, ptr %[[i_ptr]]{{.*}} -// LLVM: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr @.str.1, ptr %[[str_val2]], i32 %[[i_val]]) -// LLVM: ret void - -// OGCG: define{{.*}} void @_Z4funcPKci(ptr noundef %[[arg0:.+]], i32 noundef %[[arg1:.+]]) -// OGCG: %[[str_ptr:.+]] = alloca ptr -// OGCG: %[[i_ptr:.+]] = alloca i32 -// OGCG: store ptr %[[arg0]], ptr %[[str_ptr]]{{.*}} -// OGCG: store i32 %[[arg1]], ptr %[[i_ptr]]{{.*}} -// OGCG: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr noundef null) -// OGCG: %[[str_val:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} -// OGCG: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %[[str_val]]) -// OGCG: %[[str_val2:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} -// OGCG: %[[i_val:.+]] = load i32, ptr %[[i_ptr]]{{.*}} -// OGCG: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str.1, ptr noundef %[[str_val2]], i32 noundef %[[i_val]]) -// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/builtins-elementwise.c b/clang/test/CIR/CodeGen/builtins-elementwise.c deleted file mode 100644 index f64080b..0000000 --- a/clang/test/CIR/CodeGen/builtins-elementwise.c +++ /dev/null @@ -1,118 +0,0 @@ -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -typedef int vint4 __attribute__((ext_vector_type(4))); -typedef float vfloat4 __attribute__((ext_vector_type(4))); -typedef double vdouble4 __attribute__((ext_vector_type(4))); - -void test_builtin_elementwise_acos(float f, double d, vfloat4 vf4, - vdouble4 vd4) { - // CIR-LABEL: test_builtin_elementwise_acos - // LLVM-LABEL: test_builtin_elementwise_acos - // OGCG-LABEL: test_builtin_elementwise_acos - - // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.float - // LLVM: %{{.*}} = call float @llvm.acos.f32(float %{{.*}}) - // OGCG: %{{.*}} = call float @llvm.acos.f32(float %{{.*}}) - f = __builtin_elementwise_acos(f); - - // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.double - // LLVM: %{{.*}} = call double @llvm.acos.f64(double %{{.*}}) - // OGCG: %{{.*}} = call double @llvm.acos.f64(double %{{.*}}) - d = __builtin_elementwise_acos(d); - - // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.vector<4 x !cir.float> - // LLVM: %{{.*}} = call <4 x float> @llvm.acos.v4f32(<4 x float> %{{.*}}) - // OGCG: %{{.*}} = call <4 x float> @llvm.acos.v4f32(<4 x float> %{{.*}}) - vf4 = __builtin_elementwise_acos(vf4); - - // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.vector<4 x !cir.double> - // LLVM: %{{.*}} = call <4 x double> @llvm.acos.v4f64(<4 x double> %{{.*}}) - // OGCG: %{{.*}} = call <4 x double> @llvm.acos.v4f64(<4 x double> %{{.*}}) - vd4 = __builtin_elementwise_acos(vd4); -} - -void test_builtin_elementwise_asin(float f, double d, vfloat4 vf4, - vdouble4 vd4) { - // CIR-LABEL: test_builtin_elementwise_asin - // LLVM-LABEL: test_builtin_elementwise_asin - // OGCG-LABEL: test_builtin_elementwise_asin - - // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.float - // LLVM: %{{.*}} = call float @llvm.asin.f32(float %{{.*}}) - // OGCG: %{{.*}} = call float @llvm.asin.f32(float %{{.*}}) - f = __builtin_elementwise_asin(f); - - // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.double - // LLVM: %{{.*}} = call double @llvm.asin.f64(double %{{.*}}) - // OGCG: %{{.*}} = call double @llvm.asin.f64(double %{{.*}}) - d = __builtin_elementwise_asin(d); - - // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.vector<4 x !cir.float> - // LLVM: %{{.*}} = call <4 x float> @llvm.asin.v4f32(<4 x float> %{{.*}}) - // OGCG: %{{.*}} = call <4 x float> @llvm.asin.v4f32(<4 x float> %{{.*}}) - vf4 = __builtin_elementwise_asin(vf4); - - // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.vector<4 x !cir.double> - // LLVM: %{{.*}} = call <4 x double> @llvm.asin.v4f64(<4 x double> %{{.*}}) - // OGCG: %{{.*}} = call <4 x double> @llvm.asin.v4f64(<4 x double> %{{.*}}) - vd4 = __builtin_elementwise_asin(vd4); -} - -void test_builtin_elementwise_atan(float f, double d, vfloat4 vf4, - vdouble4 vd4) { - // CIR-LABEL: test_builtin_elementwise_atan - // LLVM-LABEL: test_builtin_elementwise_atan - // OGCG-LABEL: test_builtin_elementwise_atan - - // CIR: %{{.*}} = cir.atan %{{.*}} : !cir.float - // LLVM: %{{.*}} = call float @llvm.atan.f32(float %{{.*}}) - // OGCG: %{{.*}} = call float @llvm.atan.f32(float %{{.*}}) - f = __builtin_elementwise_atan(f); - - // CIR: %{{.*}} = cir.atan %{{.*}} : !cir.double - // LLVM: %{{.*}} = call double @llvm.atan.f64(double %{{.*}}) - // OGCG: %{{.*}} = call double @llvm.atan.f64(double %{{.*}}) - d = __builtin_elementwise_atan(d); - - // CIR: %{{.*}} = cir.atan %{{.*}} : !cir.vector<4 x !cir.float> - // LLVM: %{{.*}} = call <4 x float> @llvm.atan.v4f32(<4 x float> %{{.*}}) - // OGCG: %{{.*}} = call <4 x float> @llvm.atan.v4f32(<4 x float> %{{.*}}) - vf4 = __builtin_elementwise_atan(vf4); - - // CIR: %{{.*}} = cir.atan %{{.*}} : !cir.vector<4 x !cir.double> - // LLVM: %{{.*}} = call <4 x double> @llvm.atan.v4f64(<4 x double> %{{.*}}) - // OGCG: %{{.*}} = call <4 x double> @llvm.atan.v4f64(<4 x double> %{{.*}}) - vd4 = __builtin_elementwise_atan(vd4); -} - -void test_builtin_elementwise_cos(float f, double d, vfloat4 vf4, - vdouble4 vd4) { - // CIR-LABEL: test_builtin_elementwise_cos - // LLVM-LABEL: test_builtin_elementwise_cos - // OGCG-LABEL: test_builtin_elementwise_cos - - // CIR: {{%.*}} = cir.cos {{%.*}} : !cir.float - // LLVM: {{%.*}} = call float @llvm.cos.f32(float {{%.*}}) - // OGCG: {{%.*}} = call float @llvm.cos.f32(float {{%.*}}) - f = __builtin_elementwise_cos(f); - - // CIR: {{%.*}} = cir.cos {{%.*}} : !cir.double - // LLVM: {{%.*}} = call double @llvm.cos.f64(double {{%.*}}) - // OGCG: {{%.*}} = call double @llvm.cos.f64(double {{%.*}}) - d = __builtin_elementwise_cos(d); - - // CIR: {{%.*}} = cir.cos {{%.*}} : !cir.vector<4 x !cir.float> - // LLVM: {{%.*}} = call <4 x float> @llvm.cos.v4f32(<4 x float> {{%.*}}) - // OGCG: {{%.*}} = call <4 x float> @llvm.cos.v4f32(<4 x float> {{%.*}}) - vf4 = __builtin_elementwise_cos(vf4); - - // CIR: {{%.*}} = cir.cos {{%.*}} : !cir.vector<4 x !cir.double> - // LLVM: {{%.*}} = call <4 x double> @llvm.cos.v4f64(<4 x double> {{%.*}}) - // OGCG: {{%.*}} = call <4 x double> @llvm.cos.v4f64(<4 x double> {{%.*}}) - vd4 = __builtin_elementwise_cos(vd4); -} diff --git a/clang/test/CIR/CodeGen/builtins-floating-point.c b/clang/test/CIR/CodeGen/builtins-floating-point.c deleted file mode 100644 index 193cc172d..0000000 --- a/clang/test/CIR/CodeGen/builtins-floating-point.c +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM -// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -float cosf(float f) { - return __builtin_cosf(f); - // CHECK: %{{.*}} = cir.cos {{.*}} : !cir.float - // LLVM: %{{.*}} = call float @llvm.cos.f32(float %{{.*}}) - // OGCG: %{{.*}} = call float @llvm.cos.f32(float %{{.*}}) -} - -double cos(double f) { - return __builtin_cos(f); - // CIR: {{.+}} = cir.cos {{.+}} : !cir.double - // LLVM: %{{.*}} = call double @llvm.cos.f64(double %{{.*}}) - // OGCG: %{{.*}} = call double @llvm.cos.f64(double %{{.*}}) -} diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp deleted file mode 100644 index 0e43480..0000000 --- a/clang/test/CIR/CodeGen/builtins.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -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 -Wno-unused-value -fclangir -emit-llvm %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 -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG - -double fabs(double x) { - return __builtin_fabs(x); -} - -// CIR: {{.*}} = cir.fabs {{.*}} : !cir.double -// LLVM: {{.*}} = call double @llvm.fabs.f64(double {{.*}}) -// OGCG: {{.*}} = call double @llvm.fabs.f64(double {{.*}}) - -extern "C" void *test_return_address(void) { - return __builtin_return_address(1); - - // CIR-LABEL: test_return_address - // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i - // CIR: {{%.*}} = cir.return_address([[ARG]]) - - // LLVM-LABEL: @test_return_address - // LLVM: {{%.*}} = call ptr @llvm.returnaddress(i32 1) - - // OGCG-LABEL: @test_return_address - // OGCG: {{%.*}} = call ptr @llvm.returnaddress(i32 1) -} - -extern "C" void *test_frame_address(void) { - return __builtin_frame_address(1); - - // CIR-LABEL: test_frame_address - // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i - // CIR: {{%.*}} = cir.frame_address([[ARG]]) - - // LLVM-LABEL: @test_frame_address - // LLVM: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1) - - // OGCG-LABEL: @test_frame_address - // OGCG: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1) -} diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c index d780e37..35d977f 100644 --- a/clang/test/CIR/CodeGen/call.c +++ b/clang/test/CIR/CodeGen/call.c @@ -130,7 +130,7 @@ int f12(void) { // OGCG: %{{.+}} = call i32 @f10(i32 noundef 1) #[[ATTR0:.+]] // OGCG-NEXT: %{{.+}} = call i32 @f11(i32 noundef 2) #[[ATTR1:.+]] -// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read, errnomem: none) } +// LLVM: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } // LLVM: attributes #[[ATTR1]] = { nounwind willreturn memory(none) } // OGCG: attributes #[[ATTR0]] = { nounwind willreturn memory(read) } diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp index a5070f5..f2dbb3cc 100644 --- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp +++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp @@ -237,18 +237,18 @@ void foo4() { // CXX_CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"] // CXX_CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"] // CXX_CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init] -// CXX_CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> -// CXX_CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CXX_CIR: %[[TMP_A:.*]] = cir.load volatile {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CXX_CIR: %[[TMP_B:.*]] = cir.load volatile {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> // CXX_CIR: %[[RESULT:.*]] = cir.complex.add %[[TMP_B]], %[[TMP_A]] : !cir.complex<!s32i> -// CXX_CIR: cir.store{{.*}} %[[RESULT]], %[[B_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> -// CXX_CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CXX_CIR: cir.store volatile {{.*}} %[[RESULT]], %[[B_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> +// CXX_CIR: %[[TMP_B:.*]] = cir.load volatile {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> // CXX_CIR: cir.store{{.*}} %[[TMP_B]], %[[C_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i> // CXX_LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 // CXX_LLVM: %[[B_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 // CXX_LLVM: %[[C_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 -// CXX_LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4 -// CXX_LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[B_ADDR]], align 4 +// CXX_LLVM: %[[TMP_A:.*]] = load volatile { i32, i32 }, ptr %[[A_ADDR]], align 4 +// CXX_LLVM: %[[TMP_B:.*]] = load volatile { i32, i32 }, ptr %[[B_ADDR]], align 4 // CXX_LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 0 // CXX_LLVM: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 1 // CXX_LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0 @@ -257,8 +257,8 @@ void foo4() { // CXX_LLVM: %[[ADD_IMAG:.*]] = add i32 %[[B_IMAG]], %[[A_IMAG]] // CXX_LLVM: %[[TMP_RESULT:.*]] = insertvalue { i32, i32 } poison, i32 %[[ADD_REAL]], 0 // CXX_LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } %[[TMP_RESULT]], i32 %[[ADD_IMAG]], 1 -// CXX_LLVM: store { i32, i32 } %[[RESULT]], ptr %[[B_ADDR]], align 4 -// CXX_LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[B_ADDR]], align 4 +// CXX_LLVM: store volatile { i32, i32 } %[[RESULT]], ptr %[[B_ADDR]], align 4 +// CXX_LLVM: %[[TMP_B:.*]] = load volatile { i32, i32 }, ptr %[[B_ADDR]], align 4 // CXX_LLVM: store { i32, i32 } %[[TMP_B]], ptr %[[C_ADDR]], align 4 // CXX_OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4 diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 3fb78dc..82c9f2d 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1495,3 +1495,185 @@ void calling_function_that_return_complex() { // OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 // OGCG: store float %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4 // OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4 + +void imag_literal_gnu_extension() { + float _Complex a = 3.0fi; + double _Complex b = 3.0i; + int _Complex c = 3i; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["b", init] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init] +// CIR: %[[COMPLEX_A:.*]] = cir.const #cir.const_complex<#cir.fp<0.000000e+00> : !cir.float, #cir.fp<3.000000e+00> : !cir.float> : !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[COMPLEX_A]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[COMPLEX_B:.*]] = cir.const #cir.const_complex<#cir.fp<0.000000e+00> : !cir.double, #cir.fp<3.000000e+00> : !cir.double> : !cir.complex<!cir.double> +// CIR: cir.store{{.*}} %[[COMPLEX_B]], %[[B_ADDR]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>> +// CIR: %[[COMPLEX_C:.*]] = cir.const #cir.const_complex<#cir.int<0> : !s32i, #cir.int<3> : !s32i> : !cir.complex<!s32i> +// CIR: cir.store{{.*}} %[[COMPLEX_C]], %[[C_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: store { float, float } { float 0.000000e+00, float 3.000000e+00 }, ptr %[[A_ADDR]], align 4 +// LLVM: store { double, double } { double 0.000000e+00, double 3.000000e+00 }, ptr %[[B_ADDR]], align 8 +// LLVM: store { i32, i32 } { i32 0, i32 3 }, ptr %[[C_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store float 0.000000e+00, ptr %[[A_REAL_PTR]], align 4 +// OGCG: store float 3.000000e+00, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: store double 0.000000e+00, ptr %[[B_REAL_PTR]], align 8 +// OGCG: store double 3.000000e+00, ptr %[[B_IMAG_PTR]], align 8 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 3, ptr %[[C_IMAG_PTR]], align 4 + +void load_store_volatile() { + volatile double _Complex a; + volatile double _Complex b; + a = b; + + volatile int _Complex c; + volatile int _Complex d; + c = d; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["b"] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c"] +// CIR: %[[D_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["d"] +// CIR: %[[TMP_B:.*]] = cir.load volatile {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double> +// CIR: cir.store volatile {{.*}} %[[TMP_B]], %[[A_ADDR]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>> +// CIR: %[[TMP_D:.*]] = cir.load volatile {{.*}} %[[D_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: cir.store volatile {{.*}} %[[TMP_D]], %[[C_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[D_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_B:.*]] = load volatile { double, double }, ptr %[[B_ADDR]], align 8 +// LLVM: store volatile { double, double } %[[TMP_B]], ptr %[[A_ADDR]], align 8 +// LLVM: %[[TMP_D:.*]] = load volatile { i32, i32 }, ptr %[[D_ADDR]], align 4 +// LLVM: store volatile { i32, i32 } %[[TMP_D]], ptr %[[C_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[D_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_REAL:.*]] = load volatile double, ptr %[[B_REAL_PTR]], align 8 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: %[[B_IMAG:.*]] = load volatile double, ptr %[[B_IMAG_PTR]], align 8 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store volatile double %[[B_REAL]], ptr %[[A_REAL_PTR]], align 8 +// OGCG: store volatile double %[[B_IMAG]], ptr %[[A_IMAG_PTR]], align 8 +// OGCG: %[[D_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[D_ADDR]], i32 0, i32 0 +// OGCG: %[[D_REAL:.*]] = load volatile i32, ptr %[[D_REAL_PTR]], align 4 +// OGCG: %[[D_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[D_ADDR]], i32 0, i32 1 +// OGCG: %[[D_IMAG:.*]] = load volatile i32, ptr %[[D_IMAG_PTR]], align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG: store volatile i32 %[[D_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store volatile i32 %[[D_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + + +void load_store_volatile_2() { + volatile double _Complex av; + double _Complex a; + av = a; + + double _Complex b; + volatile double _Complex bv; + b = bv; + + int _Complex c; + volatile int _Complex cv; + c = cv; + + volatile int _Complex dv; + int _Complex d; + dv = d; +} + +// CIR: %[[AV_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["av"] +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["b"] +// CIR: %[[BV_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["bv"] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c"] +// CIR: %[[CV_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["cv"] +// CIR: %[[DV_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["dv"] +// CIR: %[[D_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["d"] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double> +// CIR: cir.store volatile {{.*}} %[[TMP_A]], %[[AV_ADDR]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>> +// CIR: %[[TMP_BV:.*]] = cir.load volatile {{.*}} %[[BV_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double> +// CIR: cir.store {{.*}} %[[TMP_BV]], %[[B_ADDR]] : !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>> +// CIR: %[[TMP_CV:.*]] = cir.load volatile {{.*}} %[[CV_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: cir.store {{.*}} %[[TMP_CV]], %[[C_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> +// CIR: %[[TMP_D:.*]] = cir.load {{.*}} %[[D_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: cir.store volatile {{.*}} %[[TMP_D]], %[[DV_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[AV_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[A_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[BV_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[CV_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[DV_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[D_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { double, double }, ptr %[[A_ADDR]], align 8 +// LLVM: store volatile { double, double } %[[TMP_A]], ptr %[[AV_ADDR]], align 8 +// LLVM: %[[TMP_BV:.*]] = load volatile { double, double }, ptr %[[BV_ADDR]], align 8 +// LLVM: store { double, double } %[[TMP_BV]], ptr %[[B_ADDR]], align 8 +// LLVM: %[[TMP_CV:.*]] = load volatile { i32, i32 }, ptr %[[CV_ADDR]], align 4 +// LLVM: store { i32, i32 } %[[TMP_CV]], ptr %[[C_ADDR]], align 4 +// LLVM: %[[TMP_D:.*]] = load { i32, i32 }, ptr %[[D_ADDR]], align 4 +// LLVM: store volatile { i32, i32 } %[[TMP_D]], ptr %[[DV_ADDR]], align 4 + +// OGCG: %[[AV_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[A_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[BV_ADDR:.*]] = alloca { double, double }, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[CV_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[DV_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[D_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8 +// OGCG: %[[AV_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[AV_ADDR]], i32 0, i32 0 +// OGCG: %[[AV_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[AV_ADDR]], i32 0, i32 1 +// OGCG: store volatile double %[[A_REAL]], ptr %[[AV_REAL_PTR]], align 8 +// OGCG: store volatile double %[[A_IMAG]], ptr %[[AV_IMAG_PTR]], align 8 +// OGCG: %[[BV_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[BV_ADDR]], i32 0, i32 0 +// OGCG: %[[BV_REAL:.*]] = load volatile double, ptr %[[BV_REAL_PTR]], align 8 +// OGCG: %[[BV_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[BV_ADDR]], i32 0, i32 1 +// OGCG: %[[BV_IMAG:.*]] = load volatile double, ptr %[[BV_IMAG_PTR]], align 8 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: store double %[[BV_REAL]], ptr %[[B_REAL_PTR]], align 8 +// OGCG: store double %[[BV_IMAG]], ptr %[[B_IMAG_PTR]], align 8 +// OGCG: %[[CV_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CV_ADDR]], i32 0, i32 0 +// OGCG: %[[CV_REAL:.*]] = load volatile i32, ptr %[[CV_REAL_PTR]], align 4 +// OGCG: %[[CV_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[CV_ADDR]], i32 0, i32 1 +// OGCG: %[[CV_IMAG:.*]] = load volatile i32, ptr %[[CV_IMAG_PTR]], align 4 +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG: store i32 %[[CV_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store i32 %[[CV_IMAG]], ptr %[[C_IMAG_PTR]], align 4 +// OGCG: %[[D_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[D_ADDR]], i32 0, i32 0 +// OGCG: %[[D_REAL:.*]] = load i32, ptr %[[D_REAL_PTR]], align 4 +// OGCG: %[[D_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[D_ADDR]], i32 0, i32 1 +// OGCG: %[[D_IMAG:.*]] = load i32, ptr %[[D_IMAG_PTR]], align 4 +// OGCG: %[[DV_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[DV_ADDR]], i32 0, i32 0 +// OGCG: %[[DV_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[DV_ADDR]], i32 0, i32 1 +// OGCG: store volatile i32 %[[D_REAL]], ptr %[[DV_REAL_PTR]], align 4 +// OGCG: store volatile i32 %[[D_IMAG]], ptr %[[DV_IMAG_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp index 30a1dc0..5219710 100644 --- a/clang/test/CIR/CodeGen/compound_literal.cpp +++ b/clang/test/CIR/CodeGen/compound_literal.cpp @@ -79,17 +79,17 @@ void foo3() { } // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] -// CIR: %[[CL_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, [".compoundliteral", init] // CIR: %[[VEC:.*]] = cir.const #cir.const_vector<[#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.int<30> : !s32i, #cir.int<40> : !s32i]> : !cir.vector<4 x !s32i> -// CIR: cir.store{{.*}} %[[VEC]], %[[CL_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> -// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[CL_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> -// CIR: cir.store{{.*}} %[[TMP]], %[[A_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: cir.store{{.*}} %[[VEC]], %[[A_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> // LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 -// LLVM: %[[CL_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 -// LLVM: store <4 x i32> <i32 10, i32 20, i32 30, i32 40>, ptr %[[CL_ADDR]], align 16 -// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[CL_ADDR]], align 16 -// LLVM: store <4 x i32> %[[TMP]], ptr %[[A_ADDR]], align 16 +// LLVM: store <4 x i32> <i32 10, i32 20, i32 30, i32 40>, ptr %[[A_ADDR]], align 16 + +// FIXME: OGCG emits a temporary compound literal in this case because it omits +// vector types from the check for aggregate constants in +// EmitAutoVarAlloca. This looks like an oversight in OGCG because the +// code to emit a constant in EmitStoresForConstant specifically looks +// for vector types in OGCG. // OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 // OGCG: %[[CL_ADDR:.*]] = alloca <4 x i32>, align 16 @@ -107,19 +107,12 @@ void foo4() { // 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]] +// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<5> : !s32i, #cir.int<10> : !s32i}> : !rec_Point +// CIR: cir.store{{.*}} %[[CONST]], %[[P]] : !rec_Point, !cir.ptr<!rec_Point> // 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]] +// LLVM: store %struct.Point { i32 5, i32 10 }, ptr %[[P]], align 4 // OGCG-LABEL: @_Z4foo4v // OGCG: %[[P:.*]] = alloca %struct.Point diff --git a/clang/test/CIR/CodeGen/constant-inits.cpp b/clang/test/CIR/CodeGen/constant-inits.cpp index d5a7bb9..ff0c0da 100644 --- a/clang/test/CIR/CodeGen/constant-inits.cpp +++ b/clang/test/CIR/CodeGen/constant-inits.cpp @@ -105,79 +105,79 @@ void function() { // CIR-DAG: !rec_anon_struct = !cir.record<struct {!u8i, !u8i, !u8i, !u8i}> // CIR-DAG: !rec_anon_struct1 = !cir.record<struct {!u8i, !u8i, !cir.array<!u8i x 2>}> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1e = #cir.zero : !rec_empty -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1s = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p1 = #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.const_array<[#cir.int<99> : !s8i, #cir.int<88> : !s8i, #cir.int<77> : !s8i]> : !cir.array<!s8i x 3>, #cir.int<40> : !s32i}> : !rec_Point -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p2 = #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE3paa = #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE1e = #cir.zero : !rec_empty +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE1s = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE2p1 = #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.const_array<[#cir.int<99> : !s8i, #cir.int<88> : !s8i, #cir.int<77> : !s8i]> : !cir.array<!s8i x 3>, #cir.int<40> : !s32i}> : !rec_Point +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE2p2 = #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE3paa = #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s32i, #cir.int<456> : !s32i, #cir.const_array<[#cir.int<11> : !s8i, #cir.int<22> : !s8i, #cir.int<33> : !s8i]> : !cir.array<!s8i x 3>, #cir.int<789> : !s32i}> : !rec_Point // CIR-DAG-SAME: #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.zero : !cir.array<!s8i x 3>, #cir.int<40> : !s32i}> : !rec_Point // CIR-DAG-SAME: ]> : !cir.array<!rec_Point x 2> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12simple_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE12simple_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple, // CIR-DAG-SAME: #cir.const_record<{#cir.int<1111> : !s32i, #cir.int<2222> : !s32i}> : !rec_simple, // CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple // CIR-DAG-SAME: ]> : !cir.array<!rec_simple x 3> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12packed_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE12packed_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed, // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed // CIR-DAG-SAME: ]> : !cir.array<!rec_packed x 2> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE9paa_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE9paa_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned, // CIR-DAG-SAME: #cir.zero : !rec_packed_and_aligned // CIR-DAG-SAME: ]> : !cir.array<!rec_packed_and_aligned x 2> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf1 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf1 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<255> : !u8i, // CIR-DAG-SAME: #cir.int<170> : !u8i, // CIR-DAG-SAME: #cir.int<52> : !u8i, // CIR-DAG-SAME: #cir.int<18> : !u8i // CIR-DAG-SAME: }> : !rec_anon_struct -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf2 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf2 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<255> : !u8i, // CIR-DAG-SAME: #cir.int<127> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 2> // CIR-DAG-SAME: }> : !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf3 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf3 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<42> : !u8i // CIR-DAG-SAME: }> : !rec_single_byte_bitfield -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf1 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf1 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<17> : !u8i, // CIR-DAG-SAME: #cir.int<3> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 2> // CIR-DAG-SAME: }> : !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf2 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf2 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<127> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3> // CIR-DAG-SAME: }> : !rec_signed_partial_bitfields -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf3 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf3 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<125> : !u8i // CIR-DAG-SAME: }> : !rec_mixed_partial_bitfields -// CIR-LABEL: cir.func dso_local @_Z8functionv() +// CIR-LABEL: cir.func {{.*}} @_Z8functionv() // CIR: cir.return -// LLVM-DAG: @_ZZ8functionvE12packed_array = internal global [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>] -// LLVM-DAG: @_ZZ8functionvE12simple_array = internal global [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }] -// LLVM-DAG: @_ZZ8functionvE1e = internal global %struct.empty zeroinitializer -// LLVM-DAG: @_ZZ8functionvE1s = internal global %struct.simple { i32 0, i32 -1 } -// LLVM-DAG: @_ZZ8functionvE2p1 = internal global %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 } -// LLVM-DAG: @_ZZ8functionvE2p2 = internal global %struct.packed <{ i8 123, i32 456 }> -// LLVM-DAG: @_ZZ8functionvE3paa = internal global %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }> -// LLVM-DAG: @_ZZ8functionvE5array = internal global [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }] -// LLVM-DAG: @_ZZ8functionvE9paa_array = internal global [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>, %struct.packed_and_aligned zeroinitializer] -// LLVM-DAG: @_ZZ8functionvE6ba_bf1 = internal global { i8, i8, i8, i8 } { i8 -1, i8 -86, i8 52, i8 18 } -// LLVM-DAG: @_ZZ8functionvE6ba_bf2 = internal global { i8, i8, [2 x i8] } { i8 -1, i8 127, [2 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE6ba_bf3 = internal global %struct.single_byte_bitfield { i8 42 } -// LLVM-DAG: @_ZZ8functionvE5p_bf1 = internal global { i8, i8, [2 x i8] } { i8 17, i8 3, [2 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE5p_bf2 = internal global %struct.signed_partial_bitfields { i8 127, [3 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE5p_bf3 = internal global %struct.mixed_partial_bitfields { i8 125 } +// LLVM-DAG: @_ZZ8functionvE12packed_array = internal constant [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>] +// LLVM-DAG: @_ZZ8functionvE12simple_array = internal constant [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }] +// LLVM-DAG: @_ZZ8functionvE1e = internal constant %struct.empty zeroinitializer +// LLVM-DAG: @_ZZ8functionvE1s = internal constant %struct.simple { i32 0, i32 -1 } +// LLVM-DAG: @_ZZ8functionvE2p1 = internal constant %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 } +// LLVM-DAG: @_ZZ8functionvE2p2 = internal constant %struct.packed <{ i8 123, i32 456 }> +// LLVM-DAG: @_ZZ8functionvE3paa = internal constant %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }> +// LLVM-DAG: @_ZZ8functionvE5array = internal constant [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }] +// LLVM-DAG: @_ZZ8functionvE9paa_array = internal constant [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>, %struct.packed_and_aligned zeroinitializer] +// LLVM-DAG: @_ZZ8functionvE6ba_bf1 = internal constant { i8, i8, i8, i8 } { i8 -1, i8 -86, i8 52, i8 18 } +// LLVM-DAG: @_ZZ8functionvE6ba_bf2 = internal constant { i8, i8, [2 x i8] } { i8 -1, i8 127, [2 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE6ba_bf3 = internal constant %struct.single_byte_bitfield { i8 42 } +// LLVM-DAG: @_ZZ8functionvE5p_bf1 = internal constant { i8, i8, [2 x i8] } { i8 17, i8 3, [2 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE5p_bf2 = internal constant %struct.signed_partial_bitfields { i8 127, [3 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE5p_bf3 = internal constant %struct.mixed_partial_bitfields { i8 125 } // LLVM-LABEL: define{{.*}} void @_Z8functionv // LLVM: ret void diff --git a/clang/test/CIR/CodeGen/copy-constructor.cpp b/clang/test/CIR/CodeGen/copy-constructor.cpp new file mode 100644 index 0000000..97c514a --- /dev/null +++ b/clang/test/CIR/CodeGen/copy-constructor.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -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 -mconstructor-aliases -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 -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct HasScalarArrayMember { + int arr[2][2]; + HasScalarArrayMember(const HasScalarArrayMember &); +}; + +HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = default; + +// CIR-LABEL: cir.func {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_( +// CIR-NEXT: %[[THIS:.*]] = cir.alloca !cir.ptr<!rec_HasScalarArrayMember> +// CIR-NEXT: %[[OTHER:.*]] = cir.alloca !cir.ptr<!rec_HasScalarArrayMember> +// CIR-NEXT: cir.store %arg0, %[[THIS]] +// CIR-NEXT: cir.store %arg1, %[[OTHER]] +// CIR-NEXT: %[[THIS_LOAD:.*]] = cir.load{{.*}} %[[THIS]] +// CIR-NEXT: %[[THIS_ARR:.*]] = cir.get_member %[[THIS_LOAD]][0] {name = "arr"} +// CIR-NEXT: %[[OTHER_LOAD:.*]] = cir.load{{.*}} %[[OTHER]] +// CIR-NEXT: %[[OTHER_ARR:.*]] = cir.get_member %[[OTHER_LOAD]][0] {name = "arr"} +// CIR-NEXT: cir.copy %[[OTHER_ARR]] to %[[THIS_ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 2> x 2>> +// CIR-NEXT: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_( +// LLVM-SAME: ptr %[[ARG0:.*]], ptr %[[ARG1:.*]]) +// LLVM-NEXT: %[[THIS:.*]] = alloca ptr +// LLVM-NEXT: %[[OTHER:.*]] = alloca ptr +// LLVM-NEXT: store ptr %[[ARG0]], ptr %[[THIS]] +// LLVM-NEXT: store ptr %[[ARG1]], ptr %[[OTHER]] +// LLVM-NEXT: %[[THIS_LOAD:.*]] = load ptr, ptr %[[THIS]] +// LLVM-NEXT: %[[THIS_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[THIS_LOAD]], i32 0, i32 0 +// LLVM-NEXT: %[[OTHER_LOAD:.*]] = load ptr, ptr %[[OTHER]] +// LLVM-NEXT: %[[OTHER_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[OTHER_LOAD]], i32 0, i32 0 +// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %[[THIS_ARR]], ptr %[[OTHER_ARR]], i32 16, i1 false) +// LLVM-NEXT: ret void + +// OGCG-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_( +// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]], ptr {{.*}} %[[ARG1:.*]]) +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[THIS:.*]] = alloca ptr +// OGCG-NEXT: %[[OTHER:.*]] = alloca ptr +// OGCG-NEXT: store ptr %[[ARG0]], ptr %[[THIS]] +// OGCG-NEXT: store ptr %[[ARG1]], ptr %[[OTHER]] +// OGCG-NEXT: %[[THIS_LOAD:.*]] = load ptr, ptr %[[THIS]] +// OGCG-NEXT: %[[THIS_ARR:.*]] = getelementptr inbounds nuw %struct.HasScalarArrayMember, ptr %[[THIS_LOAD]], i32 0, i32 0 +// OGCG-NEXT: %[[OTHER_LOAD:.*]] = load ptr, ptr %[[OTHER]] +// OGCG-NEXT: %[[OTHER_ARR:.*]] = getelementptr inbounds nuw %struct.HasScalarArrayMember, ptr %[[OTHER_LOAD]], i32 0, i32 0 +// OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[THIS_ARR]], ptr {{.*}} %[[OTHER_ARR]], i64 16, i1 false) +// OGCG-NEXT: ret void diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp index 265325f..c6e21c9 100644 --- a/clang/test/CIR/CodeGen/coro-task.cpp +++ b/clang/test/CIR/CodeGen/coro-task.cpp @@ -36,6 +36,12 @@ struct suspend_never { void await_resume() noexcept {} }; +struct string { + int size() const; + string(); + string(char const *s); +}; + } // namespace std namespace folly { @@ -101,6 +107,14 @@ co_invoke_fn co_invoke; }} // namespace folly::coro // CIR-DAG: ![[VoidTask:.*]] = !cir.record<struct "folly::coro::Task<void>" padded {!u8i}> +// CIR-DAG: ![[IntTask:.*]] = !cir.record<struct "folly::coro::Task<int>" padded {!u8i}> +// CIR-DAG: ![[VoidPromisse:.*]] = !cir.record<struct "folly::coro::Task<void>::promise_type" padded {!u8i}> +// CIR-DAG: ![[IntPromisse:.*]] = !cir.record<struct "folly::coro::Task<int>::promise_type" padded {!u8i}> +// CIR-DAG: ![[StdString:.*]] = !cir.record<struct "std::string" padded {!u8i}> +// CIR-DAG: ![[CoroHandleVoid:.*]] = !cir.record<struct "std::coroutine_handle<void>" padded {!u8i}> +// CIR-DAG: ![[CoroHandlePromiseVoid:rec_.*]] = !cir.record<struct "std::coroutine_handle<folly::coro::Task<void>::promise_type>" padded {!u8i}> +// CIR-DAG: ![[CoroHandlePromiseInt:rec_.*]] = !cir.record<struct "std::coroutine_handle<folly::coro::Task<int>::promise_type>" padded {!u8i}> +// CIR-DAG: ![[SuspendAlways:.*]] = !cir.record<struct "std::suspend_always" padded {!u8i}> // CIR: module {{.*}} { // CIR-NEXT: cir.global external @_ZN5folly4coro9co_invokeE = #cir.zero : !rec_folly3A3Acoro3A3Aco_invoke_fn @@ -116,9 +130,10 @@ VoidTask silly_task() { co_await std::suspend_always(); } -// CIR: cir.func coroutine dso_local @_Z10silly_taskv() -> ![[VoidTask]] +// CIR: cir.func coroutine {{.*}} @_Z10silly_taskv() -> ![[VoidTask]] // CIR: %[[VoidTaskAddr:.*]] = cir.alloca ![[VoidTask]], {{.*}}, ["__retval"] // CIR: %[[SavedFrameAddr:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["__coro_frame_addr"] +// CIR: %[[VoidPromisseAddr:.*]] = cir.alloca ![[VoidPromisse]], {{.*}}, ["__promise"] // Get coroutine id with __builtin_coro_id. @@ -138,3 +153,110 @@ VoidTask silly_task() { // CIR: } // CIR: %[[Load0:.*]] = cir.load{{.*}} %[[SavedFrameAddr]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> // CIR: %[[CoroFrameAddr:.*]] = cir.call @__builtin_coro_begin(%[[CoroId]], %[[Load0]]) + +// Call promise.get_return_object() to retrieve the task object. + +// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type17get_return_objectEv(%[[VoidPromisseAddr]]) nothrow : {{.*}} -> ![[VoidTask]] +// CIR: cir.store{{.*}} %[[RetObj]], %[[VoidTaskAddr]] : ![[VoidTask]] +// Start a new scope for the actual codegen for co_await, create temporary allocas for +// holding coroutine handle and the suspend_always struct. + +// CIR: cir.scope { +// CIR: %[[SuspendAlwaysAddr:.*]] = cir.alloca ![[SuspendAlways]], {{.*}} ["ref.tmp0"] {alignment = 1 : i64} +// CIR: %[[CoroHandleVoidAddr:.*]] = cir.alloca ![[CoroHandleVoid]], {{.*}} ["agg.tmp0"] {alignment = 1 : i64} +// CIR: %[[CoroHandlePromiseAddr:.*]] = cir.alloca ![[CoroHandlePromiseVoid]], {{.*}} ["agg.tmp1"] {alignment = 1 : i64} + +// Effectively execute `coawait promise_type::initial_suspend()` by calling initial_suspend() and getting +// the suspend_always struct to use for cir.await. Note that we return by-value since we defer ABI lowering +// to later passes, same is done elsewhere. + +// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIvE12promise_type15initial_suspendEv(%[[VoidPromisseAddr]]) +// CIR: cir.store{{.*}} %[[Tmp0:.*]], %[[SuspendAlwaysAddr]] + +// +// Here we start mapping co_await to cir.await. +// + +// First regions `ready` has a special cir.yield code to veto suspension. + +// CIR: cir.await(init, ready : { +// CIR: %[[ReadyVeto:.*]] = cir.scope { +// CIR: %[[TmpCallRes:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield %[[TmpCallRes:.*]] : !cir.bool +// CIR: } +// CIR: cir.condition(%[[ReadyVeto]]) + +// Second region `suspend` contains the actual suspend logic. +// +// - Start by getting the coroutine handle using from_address(). +// - Implicit convert coroutine handle from task specific promisse +// specialization to a void one. +// - Call suspend_always::await_suspend() passing the handle. +// +// FIXME: add veto support for non-void await_suspends. + +// CIR: }, suspend : { +// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIvE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr]]) +// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseVoid]] +// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIvE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) +// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) +// CIR: cir.yield + +// Third region `resume` handles coroutine resuming logic. + +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield +// CIR: },) +// CIR: } + +// Since we already tested cir.await guts above, the remaining checks for: +// - The actual user written co_await +// - The promise call +// - The final suspend co_await +// - Return + +folly::coro::Task<int> byRef(const std::string& s) { + co_return s.size(); +} + +// CIR: cir.func coroutine {{.*}} @_Z5byRefRKSt6string(%[[ARG:.*]]: !cir.ptr<![[StdString]]> {{.*}}) -> ![[IntTask]] +// CIR: %[[AllocaParam:.*]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}}, ["s", init, const] +// CIR: %[[IntTaskAddr:.*]] = cir.alloca ![[IntTask]], {{.*}}, ["__retval"] +// CIR: %[[SavedFrameAddr:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["__coro_frame_addr"] +// CIR: %[[AllocaFnUse:.*]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}}, ["s", init, const] +// CIR: %[[IntPromisseAddr:.*]] = cir.alloca ![[IntPromisse]], {{.*}}, ["__promise"] +// CIR: cir.store %[[ARG]], %[[AllocaParam]] : !cir.ptr<![[StdString]]>, {{.*}} + +// Call promise.get_return_object() to retrieve the task object. + +// CIR: %[[LOAD:.*]] = cir.load %[[AllocaParam]] : !cir.ptr<!cir.ptr<![[StdString]]>>, !cir.ptr<![[StdString]]> +// CIR: cir.store {{.*}} %[[LOAD]], %[[AllocaFnUse]] : !cir.ptr<![[StdString]]>, !cir.ptr<!cir.ptr<![[StdString]]>> +// CIR: %[[RetObj:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type17get_return_objectEv(%4) nothrow : {{.*}} -> ![[IntTask]] +// CIR: cir.store {{.*}} %[[RetObj]], %[[IntTaskAddr]] : ![[IntTask]] +// CIR: cir.scope { +// CIR: %[[SuspendAlwaysAddr:.*]] = cir.alloca ![[SuspendAlways]], {{.*}} ["ref.tmp0"] {alignment = 1 : i64} +// CIR: %[[CoroHandleVoidAddr:.*]] = cir.alloca ![[CoroHandleVoid]], {{.*}} ["agg.tmp0"] {alignment = 1 : i64} +// CIR: %[[CoroHandlePromiseAddr:.*]] = cir.alloca ![[CoroHandlePromiseInt]], {{.*}} ["agg.tmp1"] {alignment = 1 : i64} +// CIR: %[[Tmp0:.*]] = cir.call @_ZN5folly4coro4TaskIiE12promise_type15initial_suspendEv(%[[IntPromisseAddr]]) +// CIR: cir.await(init, ready : { +// CIR: %[[ReadyVeto:.*]] = cir.scope { +// CIR: %[[TmpCallRes:.*]] = cir.call @_ZNSt14suspend_always11await_readyEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield %[[TmpCallRes:.*]] : !cir.bool +// CIR: } +// CIR: cir.condition(%[[ReadyVeto]]) +// CIR: }, suspend : { +// CIR: %[[FromAddrRes:.*]] = cir.call @_ZNSt16coroutine_handleIN5folly4coro4TaskIiE12promise_typeEE12from_addressEPv(%[[CoroFrameAddr:.*]]) +// CIR: cir.store{{.*}} %[[FromAddrRes]], %[[CoroHandlePromiseAddr]] : ![[CoroHandlePromiseInt]] +// CIR: %[[CoroHandlePromiseReload:.*]] = cir.load{{.*}} %[[CoroHandlePromiseAddr]] +// CIR: cir.call @_ZNSt16coroutine_handleIvEC1IN5folly4coro4TaskIiE12promise_typeEEES_IT_E(%[[CoroHandleVoidAddr]], %[[CoroHandlePromiseReload]]) +// CIR: %[[CoroHandleVoidReload:.*]] = cir.load{{.*}} %[[CoroHandleVoidAddr]] : !cir.ptr<![[CoroHandleVoid]]>, ![[CoroHandleVoid]] +// CIR: cir.call @_ZNSt14suspend_always13await_suspendESt16coroutine_handleIvE(%[[SuspendAlwaysAddr]], %[[CoroHandleVoidReload]]) +// CIR: cir.yield +// CIR: }, resume : { +// CIR: cir.call @_ZNSt14suspend_always12await_resumeEv(%[[SuspendAlwaysAddr]]) +// CIR: cir.yield +// CIR: },) +// CIR: } diff --git a/clang/test/CIR/CodeGen/count-of.c b/clang/test/CIR/CodeGen/count-of.c new file mode 100644 index 0000000..1fd1290 --- /dev/null +++ b/clang/test/CIR/CodeGen/count-of.c @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c2y -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 +// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +unsigned long vla_with_array_element_type_with_const_size() { + long size; + return _Countof(int[5][size]); +} + +// CIR: %[[RET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["__retval"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["size"] +// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !u64i +// CIR: cir.store %[[CONST_5]], %[[RET_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[RET_VAL:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: cir.return %[[RET_VAL]] : !u64i + +// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 5, ptr %[[RET_ADDR]], align 8 +// LLVM: %[[RET_VAL:.*]] = load i64, ptr %[[RET_ADDR]], align 8 +// LLVM: ret i64 %[[RET_VAL]] + +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: ret i64 5 + +unsigned long vla_with_array_element_type_non_const_size() { + long size; + return _Countof(int[size][size]); +} + +// CIR: %[[REET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["__retval"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["size"] +// CIR: %[[TMP_SIZE:.*]] = cir.load {{.*}} %[[SIZE_ADDR]] : !cir.ptr<!s64i>, !s64i +// CIR: %[[TMP_SIZE_U64:.*]] = cir.cast integral %[[TMP_SIZE]] : !s64i -> !u64i +// CIR: cir.store %[[TMP_SIZE_U64]], %[[RET_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: cir.return %[[TMP_RET]] : !u64i + +// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// LLVM: store i64 %[[TMP_SIZE]], ptr %[[RET_ADDR]], align 8 +// LLVM: %[[TMP_RET:.*]] = load i64, ptr %[[RET_ADDR]], align 8 +// LLVM: ret i64 %[[TMP_RET]] + +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// OGCG: %[[TMP_SIZE_2:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// OGCG: ret i64 %[[TMP_SIZE]] diff --git a/clang/test/CIR/CodeGen/ctor-null-init.cpp b/clang/test/CIR/CodeGen/ctor-null-init.cpp new file mode 100644 index 0000000..6f31a46 --- /dev/null +++ b/clang/test/CIR/CodeGen/ctor-null-init.cpp @@ -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 --check-prefix=CIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s + +struct A { + A() = default; + A(int); // This constructor triggers the null base class initialization. +}; + +struct B : A { +}; + +void test_empty_base_null_init() { + B{}; +} + +// CIR: cir.func {{.*}} @_Z25test_empty_base_null_initv() +// CIR-NEXT: %[[B_ADDR:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["agg.tmp.ensured"] +// CIR-NEXT: %[[A_ADDR:.*]] = cir.base_class_addr %[[B_ADDR]] : !cir.ptr<!rec_B> nonnull [0] -> !cir.ptr<!rec_A> + +// LLVM: define{{.*}} @_Z25test_empty_base_null_initv() +// LLVM-NEXT: %[[B:.*]] = alloca %struct.B +// LLVM-NEXT: ret void + +// OGCG: define{{.*}} @_Z25test_empty_base_null_initv() +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[B:.*]] = alloca %struct.B +// OGCG-NEXT: ret void + + +struct C { + int c; + C() = default; + C(int); // This constructor triggers the null base class initialization. +}; + +struct D : C { +}; + +void test_non_empty_base_null_init() { + D{}; +} + +// CIR: cir.func {{.*}} @_Z29test_non_empty_base_null_initv() +// CIR: %[[TMP:.*]] = cir.alloca !rec_D, !cir.ptr<!rec_D>, ["agg.tmp.ensured"] +// CIR: %[[BASE:.*]] = cir.base_class_addr %[[TMP]] : !cir.ptr<!rec_D> nonnull [0] -> !cir.ptr<!rec_C> +// CIR: %[[ZERO:.*]] = cir.const #cir.const_record<{#cir.int<0> : !s32i}> : !rec_C +// CIR: cir.store{{.*}} %[[ZERO]], %[[BASE]] + +// LLVM: define{{.*}} void @_Z29test_non_empty_base_null_initv() +// LLVM: %[[TMP:.*]] = alloca %struct.D +// LLVM: store %struct.C zeroinitializer, ptr %[[TMP]] + +// OGCG: define {{.*}} void @_Z29test_non_empty_base_null_initv() +// OGCG: %[[TMP:.*]] = alloca %struct.D +// OGCG: %[[BASE:.*]] = getelementptr inbounds i8, ptr %[[TMP]], i64 0 +// OGCG: call void @llvm.memset.p0.i64(ptr{{.*}} %[[BASE]], i8 0, i64 4, i1 false) + +struct E { + int e; +}; + +struct F : E { + F() = default; + F(int); +}; + +struct G : F { +}; + +void test_base_chain_null_init() { + G{}; +} + +// CIR: cir.func {{.*}} @_Z25test_base_chain_null_initv() +// CIR: %[[TMP:.*]] = cir.alloca !rec_G, !cir.ptr<!rec_G>, ["agg.tmp.ensured"] +// CIR: %[[BASE:.*]] = cir.base_class_addr %[[TMP]] : !cir.ptr<!rec_G> nonnull [0] -> !cir.ptr<!rec_F> +// CIR: %[[ZERO:.*]] = cir.const #cir.const_record<{#cir.zero : !rec_E}> : !rec_F +// CIR: cir.store{{.*}} %[[ZERO]], %[[BASE]] + +// LLVM: define{{.*}} void @_Z25test_base_chain_null_initv() +// LLVM: %[[TMP:.*]] = alloca %struct.G +// LLVM: store %struct.F zeroinitializer, ptr %[[TMP]] + +// OGCG: define {{.*}} void @_Z25test_base_chain_null_initv() +// OGCG: %[[TMP:.*]] = alloca %struct.G +// OGCG: %[[BASE:.*]] = getelementptr inbounds i8, ptr %[[TMP]], i64 0 +// OGCG: call void @llvm.memset.p0.i64(ptr{{.*}} %[[BASE]], i8 0, i64 4, i1 false) diff --git a/clang/test/CIR/CodeGen/cxx-conversion-operators.cpp b/clang/test/CIR/CodeGen/cxx-conversion-operators.cpp index a386a41..30e6298 100644 --- a/clang/test/CIR/CodeGen/cxx-conversion-operators.cpp +++ b/clang/test/CIR/CodeGen/cxx-conversion-operators.cpp @@ -27,7 +27,7 @@ void test() { x = o; } -// CIR: cir.func dso_local @_ZN20out_of_line_operatorcviEv(%[[THIS_ARG:.+]]: !cir.ptr<!rec_out_of_line_operator>{{.*}}) -> !s32i +// CIR: cir.func {{.*}} @_ZN20out_of_line_operatorcviEv(%[[THIS_ARG:.+]]: !cir.ptr<!rec_out_of_line_operator>{{.*}}) -> !s32i // CIR: %[[THIS_ALLOCA:.+]] = cir.alloca !cir.ptr<!rec_out_of_line_operator>, !cir.ptr<!cir.ptr<!rec_out_of_line_operator>>, ["this", init] // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]] : !cir.ptr<!rec_out_of_line_operator>, !cir.ptr<!cir.ptr<!rec_out_of_line_operator>> @@ -38,7 +38,7 @@ void test() { // CIR: cir.return %[[RET_LOAD]] : !s32i // CIR: } -// CIR: cir.func comdat linkonce_odr @_ZNK15inline_operatorcviEv(%[[INLINE_THIS_ARG:.+]]: !cir.ptr<!rec_inline_operator>{{.*}}) -> !s32i +// CIR: cir.func no_inline comdat linkonce_odr @_ZNK15inline_operatorcviEv(%[[INLINE_THIS_ARG:.+]]: !cir.ptr<!rec_inline_operator>{{.*}}) -> !s32i // CIR: %[[INLINE_THIS_ALLOCA:.+]] = cir.alloca !cir.ptr<!rec_inline_operator>, !cir.ptr<!cir.ptr<!rec_inline_operator>>, ["this", init] // CIR: %[[INLINE_RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[INLINE_THIS_ARG]], %[[INLINE_THIS_ALLOCA]] : !cir.ptr<!rec_inline_operator>, !cir.ptr<!cir.ptr<!rec_inline_operator>> @@ -49,7 +49,7 @@ void test() { // CIR: cir.return %[[INLINE_RET_LOAD]] : !s32i // CIR: } -// CIR: cir.func dso_local @_Z4testv() +// CIR: cir.func {{.*}} @_Z4testv() // CIR: %[[X_ALLOCA:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] // CIR: %[[I_ALLOCA:.+]] = cir.alloca {{.*}}, {{.*}}, ["i"] // CIR: %[[O_ALLOCA:.+]] = cir.alloca {{.*}}, {{.*}}, ["o"] @@ -82,7 +82,7 @@ void test() { // LLVM: ret i32 %[[INLINE_RET_LOAD]] // LLVM: } -// LLVM: define dso_local void @_Z4testv() +// LLVM: define {{.*}} void @_Z4testv() // LLVM: %[[X_ALLOCA:.+]] = alloca i32, i64 1 // LLVM: %[[I_ALLOCA:.+]] = alloca {{.*}}, i64 1 // LLVM: %[[O_ALLOCA:.+]] = alloca {{.*}}, i64 1 @@ -102,7 +102,7 @@ void test() { // OGCG: ret i32 123 // OGCG: } -// OGCG: define dso_local void @_Z4testv() +// OGCG: define {{.*}} void @_Z4testv() // OGCG: entry: // OGCG: %[[X_VAR:.+]] = alloca i32 // OGCG: %[[I_VAR:.+]] = alloca {{.*}} diff --git a/clang/test/CIR/CodeGen/cxx-rewritten-binary-operator.cpp b/clang/test/CIR/CodeGen/cxx-rewritten-binary-operator.cpp new file mode 100644 index 0000000..ac4cac4 --- /dev/null +++ b/clang/test/CIR/CodeGen/cxx-rewritten-binary-operator.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -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 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct HasOpEq { + bool operator==(const HasOpEq &) const; +}; + +void cxx_rewritten_binary_operator_scalar_expr() { + HasOpEq a; + HasOpEq b; + bool neq = a != b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_HasOpEq, !cir.ptr<!rec_HasOpEq>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !rec_HasOpEq, !cir.ptr<!rec_HasOpEq>, ["b"] +// CIR: %[[NEQ_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["neq", init] +// CIR: %[[EQ:.*]] = cir.call @_ZNK7HasOpEqeqERKS_(%[[A_ADDR]], %[[B_ADDR]]) : (!cir.ptr<!rec_HasOpEq>, !cir.ptr<!rec_HasOpEq>) -> !cir.bool +// CIR: %[[NEQ:.*]] = cir.unary(not, %[[EQ]]) : !cir.bool, !cir.bool +// CIR: cir.store{{.*}} %[[NEQ]], %[[NEQ_ADDR]] : !cir.bool, !cir.ptr<!cir.bool> + +// LLVM: %[[A_ADDR:.*]] = alloca %struct.HasOpEq, i64 1, align 1 +// LLVM: %[[B_ADDR:.*]] = alloca %struct.HasOpEq, i64 1, align 1 +// LLVM: %[[NEQ_ADDR:.*]] = alloca i8, i64 1, align 1 +// LLVM: %[[EQ:.*]] = call i1 @_ZNK7HasOpEqeqERKS_(ptr %[[A_ADDR]], ptr %[[B_ADDR]]) +// LLVM: %[[NEQ_I1:.*]] = xor i1 %[[EQ]], true +// LLVM: %[[NEQ:.*]] = zext i1 %[[NEQ_I1]] to i8 +// LLVM: store i8 %[[NEQ]], ptr %[[NEQ_ADDR]], align 1 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.HasOpEq, align 1 +// OGCG: %[[B_ADDR:.*]] = alloca %struct.HasOpEq, align 1 +// OGCG: %[[NEQ_ADDR:.*]] = alloca i8, align 1 +// OGCG: %[[EQ:.*]] = call {{.*}} zeroext i1 @_ZNK7HasOpEqeqERKS_(ptr {{.*}} %[[A_ADDR]], ptr {{.*}} %[[B_ADDR]]) +// OGCG: %[[NEQ_I1:.*]] = xor i1 %[[EQ]], true +// OGCG: %[[NEQ:.*]] = zext i1 %[[NEQ_I1]] to i8 +// OGCG: store i8 %[[NEQ]], ptr %[[NEQ_ADDR]], align 1 diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp new file mode 100644 index 0000000..f2c2c1f --- /dev/null +++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -std=c++11 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +struct Flub { + int a = 123; +}; + +struct Foo { + int a; + + Foo() : a(123) {} + Foo(const Foo &other) : a(other.a) {} + Foo(Foo &&other) noexcept : a(other.a) { other.a = 0; } + + Foo &operator=(const Foo &other) { + if (this != &other) { + a = other.a; + } + return *this; + } + + Foo &operator=(Foo &&other) noexcept { + if (this != &other) { + a = other.a; + other.a = 0; + } + return *this; + } + + ~Foo(); +}; + +void trivial_func() { + Flub f1{}; + + Flub f2 = f1; + // Trivial copy constructors/assignments are replaced with cir.copy + // CIR: cir.copy {{.*}} : !cir.ptr<!rec_Flub> + + Flub f3 = static_cast<Flub&&>(f1); + // CIR: @_ZN4FlubC1EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, trivial true> + + f2 = f1; + // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, copy, trivial true>> + + f1 = static_cast<Flub&&>(f3); + // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: !cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> special_member<#cir.cxx_assign<!rec_Flub, move, trivial true>> +} + +void non_trivial_func() { + Foo f1{}; + // CIR: @_ZN3FooC2Ev(%arg0: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, default>> + + Foo f2 = f1; + // CIR: @_ZN3FooC2ERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, copy>> + + Foo f3 = static_cast<Foo&&>(f1); + // CIR: @_ZN3FooC2EOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, move>> + + f2 = f1; + // CIR: @_ZN3FooaSERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, copy>> + + f1 = static_cast<Foo&&>(f3); + // CIR: @_ZN3FooaSEOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: !cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> special_member<#cir.cxx_assign<!rec_Foo, move>> + // CIR: @_ZN3FooD1Ev(!cir.ptr<!rec_Foo>) special_member<#cir.cxx_dtor<!rec_Foo>> +} diff --git a/clang/test/CIR/CodeGen/defaultarg.cpp b/clang/test/CIR/CodeGen/defaultarg.cpp new file mode 100644 index 0000000..29c929c --- /dev/null +++ b/clang/test/CIR/CodeGen/defaultarg.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -std=c++17 %s -o %t.cir +// RUN: FileCheck %s --input-file=%t.cir --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -std=c++17 %s -o %t-cir.ll +// RUN: FileCheck %s --input-file=%t-cir.ll --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -std=c++17 %s -o %t.ll +// RUN: FileCheck %s --input-file=%t.ll --check-prefix=OGCG + +void bar(const int &i = 42); + +void foo() { + bar(); +} + +// CIR: cir.func {{.*}} @_Z3foov() +// CIR: cir.scope { +// CIR: %[[TMP0:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp0"] +// CIR: %[[TMP1:.*]] = cir.const #cir.int<42> +// CIR: cir.store{{.*}} %[[TMP1]], %[[TMP0]] +// CIR: cir.call @_Z3barRKi(%[[TMP0]]) +// CIR: } + +// LLVM: define{{.*}} @_Z3foov() +// LLVM: %[[TMP0:.*]] = alloca i32 +// LLVM: br label %[[SCOPE_LABEL:.*]] +// LLVM: [[SCOPE_LABEL]]: +// LLVM: store i32 42, ptr %[[TMP0]] +// LLVM: call void @_Z3barRKi(ptr %[[TMP0]]) + +// OGCG: define{{.*}} @_Z3foov() +// OGCG: %[[TMP0:.*]] = alloca i32 +// OGCG: store i32 42, ptr %[[TMP0]] +// OGCG: call void @_Z3barRKi(ptr {{.*}} %[[TMP0]]) + +struct S +{ + S(int n = 2); +}; + +void test_ctor_defaultarg() { + S s; +} + +// CIR: cir.func {{.*}} @_Z20test_ctor_defaultargv() +// CIR: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i +// CIR: cir.call @_ZN1SC1Ei(%[[S]], %[[TWO]]) : (!cir.ptr<!rec_S>, !s32i) -> () + +// LLVM: define{{.*}} @_Z20test_ctor_defaultargv() +// LLVM: %[[S:.*]] = alloca %struct.S +// LLVM: call void @_ZN1SC1Ei(ptr %[[S]], i32 2) + +// OGCG: define{{.*}} @_Z20test_ctor_defaultargv() +// OGCG: %[[S:.*]] = alloca %struct.S +// OGCG: call void @_ZN1SC1Ei(ptr{{.*}} %[[S]], i32 {{.*}} 2) diff --git a/clang/test/CIR/CodeGen/delete.cpp b/clang/test/CIR/CodeGen/delete.cpp index d8ac436..c8d6f05 100644 --- a/clang/test/CIR/CodeGen/delete.cpp +++ b/clang/test/CIR/CodeGen/delete.cpp @@ -19,7 +19,7 @@ void test_sized_delete(SizedDelete *x) { // CIR: cir.func private @_ZN11SizedDeletedlEPvm(!cir.ptr<!void>, !u64i) // LLVM: declare void @_ZN11SizedDeletedlEPvm(ptr, i64) -// CIR: cir.func dso_local @_Z17test_sized_deleteP11SizedDelete +// CIR: cir.func {{.*}} @_Z17test_sized_deleteP11SizedDelete // CIR: %[[X:.*]] = cir.load{{.*}} %{{.*}} // CIR: %[[X_CAST:.*]] = cir.cast bitcast %[[X]] : !cir.ptr<!rec_SizedDelete> -> !cir.ptr<!void> // CIR: %[[OBJ_SIZE:.*]] = cir.const #cir.int<4> : !u64i @@ -49,15 +49,15 @@ struct Container { Container::~Container() { delete contents; } // Contents::~Contents() -// CIR: cir.func comdat linkonce_odr @_ZN8ContentsD2Ev +// CIR: cir.func {{.*}} @_ZN8ContentsD2Ev // LLVM: define linkonce_odr void @_ZN8ContentsD2Ev // operator delete(void*, unsigned long) -// CIR: cir.func private @_ZdlPvm(!cir.ptr<!void>, !u64i) +// CIR: cir.func {{.*}} @_ZdlPvm(!cir.ptr<!void>, !u64i) // LLVM: declare void @_ZdlPvm(ptr, i64) // Container::~Container() -// CIR: cir.func dso_local @_ZN9ContainerD2Ev +// CIR: cir.func {{.*}} @_ZN9ContainerD2Ev // CIR: %[[THIS:.*]] = cir.load %{{.*}} // CIR: %[[CONTENTS_PTR_ADDR:.*]] = cir.get_member %[[THIS]][0] {name = "contents"} : !cir.ptr<!rec_Container> -> !cir.ptr<!cir.ptr<!rec_Contents>> // CIR: %[[CONTENTS_PTR:.*]] = cir.load{{.*}} %[[CONTENTS_PTR_ADDR]] diff --git a/clang/test/CIR/CodeGen/derived-to-base.cpp b/clang/test/CIR/CodeGen/derived-to-base.cpp new file mode 100644 index 0000000..13acb47 --- /dev/null +++ b/clang/test/CIR/CodeGen/derived-to-base.cpp @@ -0,0 +1,129 @@ +// 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 %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 %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +// TODO(cir): The constructors in this test case are only here because we don't +// have support for zero-initialization of base classes yet. We should +// fix that soon. + +struct Base { + Base(); + void f(); + int a; +}; + +struct Derived : Base { + Derived(); + double b; +}; + +void f() { + Derived d; + d.f(); +} + +// CIR: cir.func {{.*}} @_Z1fv() +// CIR: %[[D:.*]] = cir.alloca !rec_Derived, !cir.ptr<!rec_Derived>, ["d", init] +// CIR: cir.call @_ZN7DerivedC1Ev(%[[D]]) : (!cir.ptr<!rec_Derived>) -> () +// CIR: %[[D_BASE:.*]] = cir.base_class_addr %[[D]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base> +// CIR: cir.call @_ZN4Base1fEv(%[[D_BASE]]) : (!cir.ptr<!rec_Base>) -> () + +// LLVM: define {{.*}}void @_Z1fv() +// LLVM: %[[D:.*]] = alloca %struct.Derived +// LLVM: call void @_ZN7DerivedC1Ev(ptr %[[D]]) +// LLVM: call void @_ZN4Base1fEv(ptr %[[D]]) + +// OGCG: define {{.*}}void @_Z1fv() +// OGCG: %[[D:.*]] = alloca %struct.Derived +// OGCG: call void @_ZN7DerivedC1Ev(ptr {{.*}} %[[D]]) +// OGCG: call void @_ZN4Base1fEv(ptr {{.*}} %[[D]]) + +void useBase(Base *base); +void callBaseUsingDerived(Derived *derived) { + useBase(derived); +} + + +// CIR: cir.func {{.*}} @_Z20callBaseUsingDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}) +// CIR: %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init] +// CIR: cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]] +// CIR: %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]] +// CIR: %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base> +// CIR: cir.call @_Z7useBaseP4Base(%[[DERIVED_BASE]]) : (!cir.ptr<!rec_Base>) -> () + +// LLVM: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr %[[DERIVED_ARG:.*]]) +// LLVM: %[[DERIVED_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]] +// LLVM: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]] +// LLVM: call void @_Z7useBaseP4Base(ptr %[[DERIVED]]) + +// OGCG: define {{.*}} void @_Z20callBaseUsingDerivedP7Derived(ptr {{.*}} %[[DERIVED_ARG:.*]]) +// OGCG: %[[DERIVED_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]] +// OGCG: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]] +// OGCG: call void @_Z7useBaseP4Base(ptr {{.*}} %[[DERIVED]]) + +Base *returnBaseFromDerived(Derived* derived) { + return derived; +} + +// CIR: cir.func {{.*}} @_Z21returnBaseFromDerivedP7Derived(%[[DERIVED_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}) -> !cir.ptr<!rec_Base> +// CIR: %[[DERIVED_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!rec_Derived>>, ["derived", init] +// CIR: %[[BASE_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Base>, !cir.ptr<!cir.ptr<!rec_Base>>, ["__retval"] +// CIR: cir.store %[[DERIVED_ARG]], %[[DERIVED_ADDR]] +// CIR: %[[DERIVED:.*]] = cir.load{{.*}} %[[DERIVED_ADDR]] +// CIR: %[[DERIVED_BASE:.*]] = cir.base_class_addr %[[DERIVED]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base> +// CIR: cir.store %[[DERIVED_BASE]], %[[BASE_ADDR]] +// CIR: %[[BASE:.*]] = cir.load{{.*}} %[[BASE_ADDR]] +// CIR: cir.return %[[BASE]] : !cir.ptr<!rec_Base> + +// LLVM: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr %[[DERIVED_ARG:.*]]) +// LLVM: %[[DERIVED_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]] +// LLVM: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]] + +// OGCG: define {{.*}} ptr @_Z21returnBaseFromDerivedP7Derived(ptr {{.*}} %[[DERIVED_ARG:.*]]) +// OGCG: %[[DERIVED_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[DERIVED_ARG]], ptr %[[DERIVED_ADDR]] +// OGCG: %[[DERIVED:.*]] = load ptr, ptr %[[DERIVED_ADDR]] + +volatile Derived derivedObj; + +void test_volatile_store() { + derivedObj.a = 0; +} + +// CIR: cir.func {{.*}} @_Z19test_volatile_storev() +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : !cir.ptr<!rec_Derived> +// CIR: %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base> +// CIR: %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] {name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i> +// CIR: cir.store volatile {{.*}} %[[ZERO]], %[[DERIVED_OBJ_A]] : !s32i, !cir.ptr<!s32i> + +// LLVM: define {{.*}} void @_Z19test_volatile_storev() +// LLVM: store volatile i32 0, ptr @derivedObj + +// OGCG: define {{.*}} void @_Z19test_volatile_storev() +// OGCG: store volatile i32 0, ptr @derivedObj + +void test_volatile_load() { + [[maybe_unused]] int val = derivedObj.a; +} + +// CIR: cir.func {{.*}} @_Z18test_volatile_loadv() +// CIR: %[[DERIVED_OBJ:.*]] = cir.get_global @derivedObj : !cir.ptr<!rec_Derived> +// CIR: %[[DERIVED_OBJ_BASE:.*]] = cir.base_class_addr %[[DERIVED_OBJ]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base> +// CIR: %[[DERIVED_OBJ_A:.*]] = cir.get_member %[[DERIVED_OBJ_BASE]][0] {name = "a"} : !cir.ptr<!rec_Base> -> !cir.ptr<!s32i> +// CIR: %[[VAL:.*]] = cir.load volatile {{.*}} %[[DERIVED_OBJ_A]] : !cir.ptr<!s32i>, !s32i + +// LLVM: define {{.*}} void @_Z18test_volatile_loadv() +// LLVM: %[[VAL_ADDR:.*]] = alloca i32 +// LLVM: %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj + +// OGCG: define {{.*}} void @_Z18test_volatile_loadv() +// OGCG: %[[VAL_ADDR:.*]] = alloca i32 +// OGCG: %[[DERIVED_OBJ:.*]] = load volatile i32, ptr @derivedObj +// OGCG: store i32 %[[DERIVED_OBJ]], ptr %[[VAL_ADDR]] diff --git a/clang/test/CIR/CodeGen/destructors.cpp b/clang/test/CIR/CodeGen/destructors.cpp index 4363db5a..ec190f5 100644 --- a/clang/test/CIR/CodeGen/destructors.cpp +++ b/clang/test/CIR/CodeGen/destructors.cpp @@ -18,7 +18,7 @@ out_of_line_destructor::~out_of_line_destructor() { // CIR: !rec_out_of_line_destructor = !cir.record<struct "out_of_line_destructor" {!s32i}> -// CIR: cir.func dso_local @_ZN22out_of_line_destructorD2Ev(%{{.+}}: !cir.ptr<!rec_out_of_line_destructor> +// CIR: cir.func {{.*}} @_ZN22out_of_line_destructorD2Ev(%{{.+}}: !cir.ptr<!rec_out_of_line_destructor> // CIR: cir.call @_Z13some_functionv() nothrow : () -> () // CIR: cir.return @@ -30,7 +30,7 @@ out_of_line_destructor::~out_of_line_destructor() { // OGCG: call void @_Z13some_functionv() // OGCG: ret void -// CIR: cir.func dso_local @_ZN22out_of_line_destructorD1Ev(%{{.+}}: !cir.ptr<!rec_out_of_line_destructor> +// CIR: cir.func {{.*}} @_ZN22out_of_line_destructorD1Ev(%{{.+}}: !cir.ptr<!rec_out_of_line_destructor> // CIR: cir.call @_ZN22out_of_line_destructorD2Ev(%{{.*}}) nothrow : (!cir.ptr<!rec_out_of_line_destructor>) // CIR: cir.return @@ -61,7 +61,7 @@ void test_array_destructor() { array_element arr[5]{}; } -// CIR: cir.func dso_local @_Z21test_array_destructorv() +// CIR: cir.func {{.*}} @_Z21test_array_destructorv() // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_array_element x 5>, !cir.ptr<!cir.array<!rec_array_element x 5>>, ["arr", init] // CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>>, ["arrayinit.temp", init] // CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!rec_array_element x 5>> diff --git a/clang/test/CIR/CodeGen/dtors.cpp b/clang/test/CIR/CodeGen/dtors.cpp index 1fe048b7..aeee085 100644 --- a/clang/test/CIR/CodeGen/dtors.cpp +++ b/clang/test/CIR/CodeGen/dtors.cpp @@ -13,7 +13,7 @@ void test_temporary_dtor() { A(); } -// CIR: cir.func dso_local @_Z19test_temporary_dtorv() +// CIR: cir.func {{.*}} @_Z19test_temporary_dtorv() // CIR: %[[ALLOCA:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["agg.tmp.ensured"] // CIR: cir.call @_ZN1AD1Ev(%[[ALLOCA]]) nothrow : (!cir.ptr<!rec_A>) -> () diff --git a/clang/test/CIR/CodeGen/dynamic-cast.cpp b/clang/test/CIR/CodeGen/dynamic-cast.cpp index 5d010d2..e963be0 100644 --- a/clang/test/CIR/CodeGen/dynamic-cast.cpp +++ b/clang/test/CIR/CodeGen/dynamic-cast.cpp @@ -21,11 +21,11 @@ Derived *ptr_cast(Base *b) { return dynamic_cast<Derived *>(b); } -// CIR-BEFORE: cir.func dso_local @_Z8ptr_castP4Base +// CIR-BEFORE: cir.func {{.*}} @_Z8ptr_castP4Base // CIR-BEFORE: %{{.+}} = cir.dyn_cast ptr %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived // CIR-BEFORE: } -// CIR-AFTER: cir.func dso_local @_Z8ptr_castP4Base +// CIR-AFTER: cir.func {{.*}} @_Z8ptr_castP4Base // CIR-AFTER: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base>>, !cir.ptr<!rec_Base> // CIR-AFTER-NEXT: %[[SRC_IS_NOT_NULL:.*]] = cir.cast ptr_to_bool %[[SRC]] : !cir.ptr<!rec_Base> -> !cir.bool // CIR-AFTER-NEXT: %{{.+}} = cir.ternary(%[[SRC_IS_NOT_NULL]], true { @@ -69,11 +69,11 @@ Derived &ref_cast(Base &b) { return dynamic_cast<Derived &>(b); } -// CIR-BEFORE: cir.func dso_local @_Z8ref_castR4Base +// CIR-BEFORE: cir.func {{.*}} @_Z8ref_castR4Base // CIR-BEFORE: %{{.+}} = cir.dyn_cast ref %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> #dyn_cast_info__ZTI4Base__ZTI7Derived // CIR-BEFORE: } -// CIR-AFTER: cir.func dso_local @_Z8ref_castR4Base +// CIR-AFTER: cir.func {{.*}} @_Z8ref_castR4Base // CIR-AFTER: %[[SRC_VOID_PTR:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!void> // CIR-AFTER-NEXT: %[[SRC_RTTI:.*]] = cir.const #cir.global_view<@_ZTI4Base> : !cir.ptr<!u8i> // CIR-AFTER-NEXT: %[[DEST_RTTI:.*]] = cir.const #cir.global_view<@_ZTI7Derived> : !cir.ptr<!u8i> @@ -106,11 +106,11 @@ void *ptr_cast_to_complete(Base *ptr) { return dynamic_cast<void *>(ptr); } -// CIR-BEFORE: cir.func dso_local @_Z20ptr_cast_to_completeP4Base +// CIR-BEFORE: cir.func {{.*}} @_Z20ptr_cast_to_completeP4Base // CIR-BEFORE: %{{.+}} = cir.dyn_cast ptr %{{.+}} : !cir.ptr<!rec_Base> -> !cir.ptr<!void> // CIR-BEFORE: } -// CIR-AFTER: cir.func dso_local @_Z20ptr_cast_to_completeP4Base +// CIR-AFTER: cir.func {{.*}} @_Z20ptr_cast_to_completeP4Base // CIR-AFTER: %[[SRC:.*]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!rec_Base>>, !cir.ptr<!rec_Base> // CIR-AFTER-NEXT: %[[SRC_IS_NOT_NULL:.*]] = cir.cast ptr_to_bool %[[SRC]] : !cir.ptr<!rec_Base> -> !cir.bool // CIR-AFTER-NEXT: %{{.+}} = cir.ternary(%[[SRC_IS_NOT_NULL]], true { diff --git a/clang/test/CIR/CodeGen/global-array-dtor.cpp b/clang/test/CIR/CodeGen/global-array-dtor.cpp new file mode 100644 index 0000000..01277a3 --- /dev/null +++ b/clang/test/CIR/CodeGen/global-array-dtor.cpp @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir +// RUN: FileCheck --input-file=%t-before.cir %s --check-prefix=CIR-BEFORE-LPP +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +// This duplicates a test case in global-init.cpp, but having it by itself +// forces the __cxa_atexit function to be emitted for this case, which was +// broken in the original implementation. + +struct ArrayDtor { + ~ArrayDtor(); +}; + +ArrayDtor arrDtor[16]; + +// CIR-BEFORE-LPP: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> +// CIR-BEFORE-LPP-SAME: dtor { +// CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> +// CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> { +// CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>): +// CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: } + +// CIR: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> {alignment = 16 : i64} +// CIR: cir.func internal private @__cxx_global_array_dtor(%[[ARR_ARG:.*]]: !cir.ptr<!void> {{.*}}) { +// CIR: %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR_ARG]] : !cir.ptr<!void> -> !cir.ptr<!rec_ArrayDtor> +// CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST15]] : (!cir.ptr<!rec_ArrayDtor>, !u64i) -> !cir.ptr<!rec_ArrayDtor> +// CIR: %[[CUR_ADDR:.*]] = cir.alloca !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, ["__array_idx"] +// CIR: cir.store %[[END]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>> +// CIR: cir.do { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor> +// CIR: cir.call @_ZN9ArrayDtorD1Ev(%[[CUR]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> () +// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[NEG_ONE]] : (!cir.ptr<!rec_ArrayDtor>, !s64i) -> !cir.ptr<!rec_ArrayDtor> +// CIR: cir.store %[[NEXT]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[BEGIN]]) : !cir.ptr<!rec_ArrayDtor>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } +// +// CIR: cir.func internal private @__cxx_global_var_init() { +// CIR: %[[ARR:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> +// CIR: %[[DTOR:.*]] = cir.get_global @__cxx_global_array_dtor : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[ARR_CAST:.*]] = cir.cast bitcast %[[ARR]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> -> !cir.ptr<!void> +// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[ARR_CAST]], %[[HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>) -> () + +// LLVM: define internal void @__cxx_global_array_dtor(ptr %[[ARR_ARG:.*]]) { +// LLVM: %[[BEGIN:.*]] = getelementptr %struct.ArrayDtor, ptr %[[ARR_ARG]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.ArrayDtor, ptr %[[BEGIN]], i64 15 +// LLVM: %[[CUR_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[END]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_COND:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[BEGIN]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: call void @_ZN9ArrayDtorD1Ev(ptr %[[CUR]]) #0 +// LLVM: %[[PREV:.*]] = getelementptr %struct.ArrayDtor, ptr %[[CUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_COND]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void +// LLVM: } +// +// LLVM: define internal void @__cxx_global_var_init() { +// LLVM: call void @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr @arrDtor, ptr @__dso_handle) + +// Note: OGCG defines these functions in reverse order of CIR->LLVM. +// Note also: OGCG doesn't pass the address of the array to the destructor function. +// Instead, it uses the global directly in the helper function. + +// OGCG: define internal void @__cxx_global_var_init() {{.*}} section ".text.startup" { +// OGCG: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle) + +// OGCG: define internal void @__cxx_global_array_dtor(ptr noundef %[[ARG:.*]]) {{.*}} section ".text.startup" { +// OGCG: entry: +// OGCG: %[[UNUSED_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG]], ptr %[[UNUSED_ADDR]] +// OGCG: br label %[[LOOP_BODY:.*]] +// OGCG: [[LOOP_BODY]]: +// OGCG: %[[PREV:.*]] = phi ptr [ getelementptr inbounds (%struct.ArrayDtor, ptr @arrDtor, i64 16), %entry ], [ %[[CUR:.*]], %[[LOOP_BODY]] ] +// OGCG: %[[CUR]] = getelementptr inbounds %struct.ArrayDtor, ptr %[[PREV]], i64 -1 +// OGCG: call void @_ZN9ArrayDtorD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]]) +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[CUR]], @arrDtor +// OGCG: br i1 %[[DONE]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]] +// OGCG: [[LOOP_END]]: +// OGCG: ret void +// OGCG: } + +// Common init function for all globals with default priority + +// CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() { +// CIR: cir.call @__cxx_global_var_init() : () -> () + +// LLVM: define void @_GLOBAL__sub_I_[[FILENAME:.*]]() +// LLVM: call void @__cxx_global_var_init() + +// OGCG: define internal void @_GLOBAL__sub_I_[[FILENAME:.*]]() {{.*}} section ".text.startup" { +// OGCG: call void @__cxx_global_var_init() diff --git a/clang/test/CIR/CodeGen/global-constant.c b/clang/test/CIR/CodeGen/global-constant.c new file mode 100644 index 0000000..588642c --- /dev/null +++ b/clang/test/CIR/CodeGen/global-constant.c @@ -0,0 +1,20 @@ +// 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 + +const int global_no_use = 12; +// CIR: cir.global constant {{.*}}@global_no_use +// LLVM: @global_no_use = constant +// OGCG: @global_no_use = constant + +const float global_used = 1.2f; +// CIR: cir.global constant {{.*}}@global_used +// LLVM: @global_used = constant +// OGCG: @global_used = constant + +float const * get_float_ptr() { + return &global_used; +} diff --git a/clang/test/CIR/CodeGen/global-ctor-dtor.cpp b/clang/test/CIR/CodeGen/global-ctor-dtor.cpp index 2e03ff3..63f1752 100644 --- a/clang/test/CIR/CodeGen/global-ctor-dtor.cpp +++ b/clang/test/CIR/CodeGen/global-ctor-dtor.cpp @@ -13,28 +13,28 @@ void foo(void) { bar(); } -// CIR-BEFORE-LPP: cir.func dso_local @_Z3foov() global_ctor +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z3foov() global_ctor void foo2(void) __attribute__((constructor(777))); void foo2(void) { bar(); } -// CIR-BEFORE-LPP: cir.func dso_local @_Z4foo2v() global_ctor(777) +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z4foo2v() global_ctor(777) void foo3(void) __attribute__((destructor)); void foo3(void) { bar(); } -// CIR-BEFORE-LPP: cir.func dso_local @_Z4foo3v() global_dtor +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z4foo3v() global_dtor void foo4(void) __attribute__((destructor(789))); void foo4(void) { bar(); } -// CIR-BEFORE-LPP: cir.func dso_local @_Z4foo4v() global_dtor(789) +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z4foo4v() global_dtor(789) // CIR-AFTER: module @{{.*}} attributes {cir.global_ctors = [#cir.global_ctor<"_Z3foov", 65535>, #cir.global_ctor<"_Z4foo2v", 777>], cir.global_dtors = [#cir.global_dtor<"_Z4foo3v", 65535>, #cir.global_dtor<"_Z4foo4v", 789>] diff --git a/clang/test/CIR/CodeGen/global-init.cpp b/clang/test/CIR/CodeGen/global-init.cpp index 01e2868..3510e3e 100644 --- a/clang/test/CIR/CodeGen/global-init.cpp +++ b/clang/test/CIR/CodeGen/global-init.cpp @@ -15,12 +15,14 @@ // LLVM: @needsCtor = global %struct.NeedsCtor zeroinitializer, align 1 // LLVM: @needsDtor = global %struct.NeedsDtor zeroinitializer, align 1 // LLVM: @needsCtorDtor = global %struct.NeedsCtorDtor zeroinitializer, align 1 +// LLVM: @arrDtor = global [16 x %struct.ArrayDtor] zeroinitializer, align 16 // LLVM: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_[[FILENAME:.*]], ptr null }] // OGCG: @needsCtor = global %struct.NeedsCtor zeroinitializer, align 1 // OGCG: @needsDtor = global %struct.NeedsDtor zeroinitializer, align 1 // OGCG: @__dso_handle = external hidden global i8 // OGCG: @needsCtorDtor = global %struct.NeedsCtorDtor zeroinitializer, align 1 +// OGCG: @arrDtor = global [16 x %struct.ArrayDtor] zeroinitializer, align 16 // OGCG: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_[[FILENAME:.*]], ptr null }] struct NeedsCtor { @@ -145,11 +147,11 @@ float fp; int i = (int)fp; // CIR-BEFORE-LPP: cir.global external @i = ctor : !s32i { -// CIR-BEFORE-LPP: %0 = cir.get_global @i : !cir.ptr<!s32i> -// CIR-BEFORE-LPP: %1 = cir.get_global @fp : !cir.ptr<!cir.float> -// CIR-BEFORE-LPP: %2 = cir.load{{.*}} %1 : !cir.ptr<!cir.float>, !cir.float -// CIR-BEFORE-LPP: %3 = cir.cast float_to_int %2 : !cir.float -> !s32i -// CIR-BEFORE-LPP: cir.store{{.*}} %3, %0 : !s32i, !cir.ptr<!s32i> +// CIR-BEFORE-LPP: %[[I:.*]] = cir.get_global @i : !cir.ptr<!s32i> +// CIR-BEFORE-LPP: %[[FP:.*]] = cir.get_global @fp : !cir.ptr<!cir.float> +// CIR-BEFORE-LPP: %[[FP_VAL:.*]] = cir.load{{.*}} %[[FP]] : !cir.ptr<!cir.float>, !cir.float +// CIR-BEFORE-LPP: %[[FP_I32:.*]] = cir.cast float_to_int %[[FP_VAL]] : !cir.float -> !s32i +// CIR-BEFORE-LPP: cir.store{{.*}} %[[FP_I32]], %[[I]] : !s32i, !cir.ptr<!s32i> // CIR-BEFORE-LPP: } // CIR: cir.func internal private @__cxx_global_var_init.4() @@ -169,6 +171,97 @@ int i = (int)fp; // OGCG: %[[FP_I32:.*]] = fptosi float %[[TMP_FP]] to i32 // OGCG: store i32 %[[FP_I32]], ptr @i, align 4 +struct ArrayDtor { + ~ArrayDtor(); +}; + +ArrayDtor arrDtor[16]; + +// CIR-BEFORE-LPP: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> +// CIR-BEFORE-LPP-SAME: dtor { +// CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> +// CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> { +// CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>): +// CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: } + +// CIR: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> {alignment = 16 : i64} +// CIR: cir.func internal private @__cxx_global_array_dtor(%[[ARR_ARG:.*]]: !cir.ptr<!void> {{.*}}) { +// CIR: %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR_ARG]] : !cir.ptr<!void> -> !cir.ptr<!rec_ArrayDtor> +// CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST15]] : (!cir.ptr<!rec_ArrayDtor>, !u64i) -> !cir.ptr<!rec_ArrayDtor> +// CIR: %[[CUR_ADDR:.*]] = cir.alloca !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, ["__array_idx"] +// CIR: cir.store %[[END]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>> +// CIR: cir.do { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor> +// CIR: cir.call @_ZN9ArrayDtorD1Ev(%[[CUR]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> () +// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[NEG_ONE]] : (!cir.ptr<!rec_ArrayDtor>, !s64i) -> !cir.ptr<!rec_ArrayDtor> +// CIR: cir.store %[[NEXT]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[BEGIN]]) : !cir.ptr<!rec_ArrayDtor>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } +// +// CIR: cir.func internal private @__cxx_global_var_init.5() { +// CIR: %[[ARR:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> +// CIR: %[[DTOR:.*]] = cir.get_global @__cxx_global_array_dtor : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[ARR_CAST:.*]] = cir.cast bitcast %[[ARR]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> -> !cir.ptr<!void> +// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[ARR_CAST]], %[[HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>) -> () + +// LLVM: define internal void @__cxx_global_array_dtor(ptr %[[ARR_ARG:.*]]) { +// LLVM: %[[BEGIN:.*]] = getelementptr %struct.ArrayDtor, ptr %[[ARR_ARG]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.ArrayDtor, ptr %[[BEGIN]], i64 15 +// LLVM: %[[CUR_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[END]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_COND:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[BEGIN]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: call void @_ZN9ArrayDtorD1Ev(ptr %[[CUR]]) #0 +// LLVM: %[[PREV:.*]] = getelementptr %struct.ArrayDtor, ptr %[[CUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_COND]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void +// LLVM: } +// +// LLVM: define internal void @__cxx_global_var_init.5() { +// LLVM: call void @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr @arrDtor, ptr @__dso_handle) + +// Note: OGCG defines these functions in reverse order of CIR->LLVM. +// Note also: OGCG doesn't pass the address of the array to the destructor function. +// Instead, it uses the global directly in the helper function. + +// OGCG: define internal void @__cxx_global_var_init.5() {{.*}} section ".text.startup" { +// OGCG: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle) + +// OGCG: define internal void @__cxx_global_array_dtor(ptr noundef %[[ARG:.*]]) {{.*}} section ".text.startup" { +// OGCG: entry: +// OGCG: %[[UNUSED_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG]], ptr %[[UNUSED_ADDR]] +// OGCG: br label %[[LOOP_BODY:.*]] +// OGCG: [[LOOP_BODY]]: +// OGCG: %[[PREV:.*]] = phi ptr [ getelementptr inbounds (%struct.ArrayDtor, ptr @arrDtor, i64 16), %entry ], [ %[[CUR:.*]], %[[LOOP_BODY]] ] +// OGCG: %[[CUR]] = getelementptr inbounds %struct.ArrayDtor, ptr %[[PREV]], i64 -1 +// OGCG: call void @_ZN9ArrayDtorD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]]) +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[CUR]], @arrDtor +// OGCG: br i1 %[[DONE]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]] +// OGCG: [[LOOP_END]]: +// OGCG: ret void +// OGCG: } + // Common init function for all globals with default priority // CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() { @@ -177,6 +270,7 @@ int i = (int)fp; // CIR: cir.call @__cxx_global_var_init.2() : () -> () // CIR: cir.call @__cxx_global_var_init.3() : () -> () // CIR: cir.call @__cxx_global_var_init.4() : () -> () +// CIR: cir.call @__cxx_global_var_init.5() : () -> () // LLVM: define void @_GLOBAL__sub_I_[[FILENAME]]() // LLVM: call void @__cxx_global_var_init() @@ -184,6 +278,7 @@ int i = (int)fp; // LLVM: call void @__cxx_global_var_init.2() // LLVM: call void @__cxx_global_var_init.3() // LLVM: call void @__cxx_global_var_init.4() +// LLVM: call void @__cxx_global_var_init.5() // OGCG: define internal void @_GLOBAL__sub_I_[[FILENAME]]() {{.*}} section ".text.startup" { // OGCG: call void @__cxx_global_var_init() @@ -191,3 +286,4 @@ int i = (int)fp; // OGCG: call void @__cxx_global_var_init.2() // OGCG: call void @__cxx_global_var_init.3() // OGCG: call void @__cxx_global_var_init.4() +// OGCG: call void @__cxx_global_var_init.5() diff --git a/clang/test/CIR/CodeGen/globals.cpp b/clang/test/CIR/CodeGen/globals.cpp index a3e1613..848cac8 100644 --- a/clang/test/CIR/CodeGen/globals.cpp +++ b/clang/test/CIR/CodeGen/globals.cpp @@ -35,3 +35,9 @@ int *constArrAddr = &arr[2][1]; // LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8 // OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8 + +bool bool_global = true; + +// CIR: cir.global external @bool_global = #true {alignment = 1 : i64} +// LLVM: @bool_global = global i8 1, align 1 +// OGCG: @bool_global = global i8 1, align 1 diff --git a/clang/test/CIR/CodeGen/gnu-null.cpp b/clang/test/CIR/CodeGen/gnu-null.cpp new file mode 100644 index 0000000..d1d15f2 --- /dev/null +++ b/clang/test/CIR/CodeGen/gnu-null.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -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 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void gnu_null_expr() { + long a = __null; + int *b = __null; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["b", init] +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i +// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !s64i, !cir.ptr<!s64i> +// CIR: %[[CONST_NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> +// CIR: cir.store {{.*}} %[[CONST_NULL]], %[[B_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: store i64 0, ptr %[[A_ADDR]], align 8 +// LLVM: store ptr null, ptr %[[B_ADDR]], align 8 + +// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca ptr, align 8 +// OGCG: store i64 0, ptr %[[A_ADDR]], align 8 +// OGCG: store ptr null, ptr %[[B_ADDR]], align 8 diff --git a/clang/test/CIR/CodeGen/goto.cpp b/clang/test/CIR/CodeGen/goto.cpp index 257c255..4b825d6 100644 --- a/clang/test/CIR/CodeGen/goto.cpp +++ b/clang/test/CIR/CodeGen/goto.cpp @@ -12,7 +12,7 @@ int shouldNotGenBranchRet(int x) { err: return -1; } -// CIR: cir.func dso_local @_Z21shouldNotGenBranchReti +// CIR: cir.func {{.*}} @_Z21shouldNotGenBranchReti // CIR: cir.if {{.*}} { // CIR: cir.goto "err" // CIR: } @@ -63,7 +63,7 @@ int shouldGenBranch(int x) { err: return -1; } -// CIR: cir.func dso_local @_Z15shouldGenBranchi +// CIR: cir.func {{.*}} @_Z15shouldGenBranchi // CIR: cir.if {{.*}} { // CIR: cir.goto "err" // CIR: } @@ -99,7 +99,7 @@ end1: end2: b = b + 2; } -// CIR: cir.func dso_local @_Z19severalLabelsInARowi +// CIR: cir.func {{.*}} @_Z19severalLabelsInARowi // CIR: cir.goto "end1" // CIR: ^bb[[#BLK1:]] // CIR: cir.goto "end2" @@ -132,7 +132,7 @@ void severalGotosInARow(int a) { end: b = b + 2; } -// CIR: cir.func dso_local @_Z18severalGotosInARowi +// CIR: cir.func {{.*}} @_Z18severalGotosInARowi // CIR: cir.goto "end" // CIR: ^bb[[#BLK1:]]: // CIR: cir.goto "end" @@ -163,7 +163,7 @@ extern "C" void multiple_non_case(int v) { } } -// CIR: cir.func dso_local @multiple_non_case +// CIR: cir.func {{.*}} @multiple_non_case // CIR: cir.switch // CIR: cir.case(default, []) { // CIR: cir.call @action1() @@ -202,7 +202,7 @@ extern "C" void case_follow_label(int v) { } } -// CIR: cir.func dso_local @case_follow_label +// CIR: cir.func {{.*}} @case_follow_label // CIR: cir.switch // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { // CIR: cir.br ^bb1 @@ -264,7 +264,7 @@ extern "C" void default_follow_label(int v) { } } -// CIR: cir.func dso_local @default_follow_label +// CIR: cir.func {{.*}} @default_follow_label // CIR: cir.switch // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { // CIR: cir.yield @@ -313,7 +313,7 @@ label: goto label; } -// CIR: cir.func dso_local @_Z2g3v +// CIR: cir.func {{.*}} @_Z2g3v // CIR: cir.br ^bb1 // CIR: ^bb1: // CIR: cir.label "label" diff --git a/clang/test/CIR/CodeGen/inline-attributes.cpp b/clang/test/CIR/CodeGen/inline-attributes.cpp index fab4010..5477797 100644 --- a/clang/test/CIR/CodeGen/inline-attributes.cpp +++ b/clang/test/CIR/CodeGen/inline-attributes.cpp @@ -29,17 +29,17 @@ int (*inline_hint_ptr)(int) = &inline_hint_function; int (*noinline_ptr)(int) = &noinline_function; int (*regular_ptr)(int) = ®ular_function; -// CIR-LABEL: cir.func dso_local @_Z17noinline_functioni(%arg0: !s32i {{.*}}) -> !s32i inline(never) +// CIR-LABEL: cir.func no_inline dso_local @_Z17noinline_functioni(%arg0: !s32i {{.*}}) -> !s32i // CIR-LABEL: cir.func dso_local @_Z16regular_functioni(%arg0: !s32i {{.*}}) -> !s32i -// CIR-NOT: inline(never) -// CIR-NOT: inline(always) -// CIR-NOT: inline(hint) +// CIR-NOT: no_inline +// CIR-NOT: always_inline +// CIR-NOT: inline_hint // CIR-SAME: { -// CIR-LABEL: cir.func {{.*}}@_Z22always_inline_functioni(%arg0: !s32i {{.*}}) -> !s32i inline(always) +// CIR-LABEL: cir.func{{.*}} always_inline {{.*}}@_Z22always_inline_functioni(%arg0: !s32i {{.*}}) -> !s32i -// CIR-LABEL: cir.func {{.*}}@_Z20inline_hint_functioni(%arg0: !s32i {{.*}}) -> !s32i inline(hint) +// CIR-LABEL: cir.func{{.*}} inline_hint {{.*}}@_Z20inline_hint_functioni(%arg0: !s32i {{.*}}) -> !s32i // LLVM: ; Function Attrs:{{.*}} noinline // LLVM: define{{.*}} i32 @_Z17noinline_functioni diff --git a/clang/test/CIR/CodeGen/kr-func-promote.c b/clang/test/CIR/CodeGen/kr-func-promote.c new file mode 100644 index 0000000..5fed068 --- /dev/null +++ b/clang/test/CIR/CodeGen/kr-func-promote.c @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c89 -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 -std=c89 -fclangir -emit-llvm %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 -std=c89 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// CIR: cir.func {{.*}}@foo(%arg0: !s32i +// CIR: %0 = cir.alloca !s16i, !cir.ptr<!s16i>, ["x", init] +// CIR: %1 = cir.cast integral %arg0 : !s32i -> !s16i +// CIR: cir.store %1, %0 : !s16i, !cir.ptr<!s16i> +// expected-warning@+1 {{a function definition without a prototype is deprecated}} +void foo(x) short x; {} + +// LLVM: define{{.*}} void @foo(i32 %0) +// LLVM: %[[X_PTR:.*]] = alloca i16, i64 1, align 2 +// LLVM: %[[X:.*]] = trunc i32 %0 to i16 +// LLVM: store i16 %[[X]], ptr %[[X_PTR]], align 2 + +// OGCG: define{{.*}} void @foo(i32 noundef %0) +// OGCG: entry: +// OGCG: %[[X_PTR:.*]] = alloca i16, align 2 +// OGCG: %[[X:.*]] = trunc i32 %0 to i16 +// OGCG: store i16 %[[X]], ptr %[[X_PTR]], align 2 + +// CIR: cir.func{{.*}}no_proto dso_local @bar(%arg0: !cir.double +// CIR: %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init] +// CIR: %1 = cir.cast floating %arg0 : !cir.double -> !cir.float +// CIR: cir.store %1, %0 : !cir.float, !cir.ptr<!cir.float> +// expected-warning@+1 {{a function definition without a prototype is deprecated}} +void bar(f) float f; {} + +// LLVM: define{{.*}} void @bar(double %0) +// LLVM: %[[F_PTR:.*]] = alloca float, i64 1, align 4 +// LLVM: %[[F:.*]] = fptrunc double %0 to float +// LLVM: store float %[[F]], ptr %[[F_PTR]], align 4 + +// OGCG: define{{.*}} void @bar(double noundef %0) +// OGCG: entry: +// OGCG: %[[F_PTR:.*]] = alloca float, align 4 +// OGCG: %[[F:.*]] = fptrunc double %0 to float +// OGCG: store float %[[F]], ptr %[[F_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/label-values.c b/clang/test/CIR/CodeGen/label-values.c new file mode 100644 index 0000000..750ef1f6 --- /dev/null +++ b/clang/test/CIR/CodeGen/label-values.c @@ -0,0 +1,204 @@ +// 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 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +void A(void) { + void *ptr = &&LABEL_A; + goto *ptr; +LABEL_A: + return; +} +// CIR: cir.func {{.*}} @A +// CIR: [[PTR:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64} +// CIR: [[BLOCK:%.*]] = cir.block_address <@A, "LABEL_A"> : !cir.ptr<!void> +// CIR: cir.store align(8) [[BLOCK]], [[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> +// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>) +// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0 +// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [ +// CIR: ^bb2 +// CIR: ] +// CIR: ^bb2: // pred: ^bb1 +// CIR: cir.label "LABEL_A" +// CIR: cir.return + +// OGCG: define dso_local void @A() +// OGCG: [[PTR:%.*]] = alloca ptr, align 8 +// OGCG: store ptr blockaddress(@A, %LABEL_A), ptr [[PTR]], align 8 +// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8 +// OGCG: br label %indirectgoto +// OGCG: LABEL_A: ; preds = %indirectgoto +// OGCG: ret void +// OGCG: indirectgoto: ; preds = %entry +// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %entry ] +// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A] + +void B(void) { +LABEL_B: + void *ptr = &&LABEL_B; + goto *ptr; +} + +// CIR: cir.func {{.*}} @B() +// CIR: [[PTR:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64} +// CIR: cir.br ^bb1 +// CIR: ^bb1: // 2 preds: ^bb0, ^bb2 +// CIR: cir.label "LABEL_B" +// CIR: [[BLOCK:%.*]] = cir.block_address <@B, "LABEL_B"> : !cir.ptr<!void> +// CIR: cir.store align(8) [[BLOCK]], [[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> +// CIR: cir.br ^bb2([[BLOCKADD]] : !cir.ptr<!void>) +// CIR: ^bb2([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb1 +// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [ +// CIR-NEXT: ^bb1 +// CIR: ] + +// OGCG: define dso_local void @B +// OGCG: [[PTR:%.*]] = alloca ptr, align 8 +// OGCG: br label %LABEL_B +// OGCG: LABEL_B: ; preds = %indirectgoto, %entry +// OGCG: store ptr blockaddress(@B, %LABEL_B), ptr [[PTR]], align 8 +// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8 +// OGCG: br label %indirectgoto +// OGCG: indirectgoto: ; preds = %LABEL_B +// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %LABEL_B ] +// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_B] + +void C(int x) { + void *ptr = (x == 0) ? &&LABEL_A : &&LABEL_B; + goto *ptr; +LABEL_A: + return; +LABEL_B: + return; +} + +// CIR: cir.func {{.*}} @C +// CIR: [[BLOCK1:%.*]] = cir.block_address <@C, "LABEL_A"> : !cir.ptr<!void> +// CIR: [[BLOCK2:%.*]] = cir.block_address <@C, "LABEL_B"> : !cir.ptr<!void> +// CIR: [[COND:%.*]] = cir.select if [[CMP:%.*]] then [[BLOCK1]] else [[BLOCK2]] : (!cir.bool, !cir.ptr<!void>, !cir.ptr<!void>) -> !cir.ptr<!void> +// CIR: cir.store align(8) [[COND]], [[PTR:%.*]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> +// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>) +// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0 +// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [ +// CIR-NEXT: ^bb2, +// CIR-NEXT: ^bb4 +// CIR: ] +// CIR: ^bb2: // pred: ^bb1 +// CIR: cir.label "LABEL_A" +// CIR: cir.br ^bb3 +// CIR: ^bb3: // 2 preds: ^bb2, ^bb4 +// CIR: cir.return +// CIR: ^bb4: // pred: ^bb1 +// CIR: cir.label "LABEL_B" +// CIR: cir.br ^bb3 + +// OGCG: define dso_local void @C +// OGCG: [[COND:%.*]] = select i1 [[CMP:%.*]], ptr blockaddress(@C, %LABEL_A), ptr blockaddress(@C, %LABEL_B) +// OGCG: store ptr [[COND]], ptr [[PTR:%.*]], align 8 +// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8 +// OGCG: br label %indirectgoto +// OGCG: LABEL_A: ; preds = %indirectgoto +// OGCG: br label %return +// OGCG: LABEL_B: ; preds = %indirectgoto +// OGCG: br label %return +// OGCG: return: ; preds = %LABEL_B, %LABEL_A +// OGCG: ret void +// OGCG: indirectgoto: ; preds = %entry +// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %entry ] +// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A, label %LABEL_B] + +void D(void) { + void *ptr = &&LABEL_A; + void *ptr2 = &&LABEL_A; + goto *ptr2; +LABEL_A: + void *ptr3 = &&LABEL_A; + return; +} + +// CIR: cir.func {{.*}} @D +// CIR: %[[PTR:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] +// CIR: %[[PTR2:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr2", init] +// CIR: %[[PTR3:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr3", init] +// CIR: %[[BLK1:.*]] = cir.block_address <@D, "LABEL_A"> : !cir.ptr<!void> +// CIR: cir.store align(8) %[[BLK1]], %[[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: %[[BLK2:.*]] = cir.block_address <@D, "LABEL_A"> : !cir.ptr<!void> +// CIR: cir.store align(8) %[[BLK2]], %[[PTR2]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: cir.br ^bb1 +// CIR: ^bb1([[PHI:%*.]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0 +// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [ +// CIR-DAG: ^bb2, +// CIR-DAG: ^bb2, +// CIR-DAG: ^bb2 +// CIR: ] +// CIR: ^bb2: // 3 preds: ^bb1, ^bb1, ^bb1 +// CIR: cir.label "LABEL_A" +// CIR: %[[BLK3:.*]] = cir.block_address <@D, "LABEL_A"> : !cir.ptr<!void> +// CIR: cir.store align(8) %[[BLK3]], %[[PTR3]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: cir.return + +// OGCG: define dso_local void @D +// OGCG: %[[PTR:.*]] = alloca ptr, align 8 +// OGCG: %[[PTR2:.*]] = alloca ptr, align 8 +// OGCG: %[[PTR3:.*]] = alloca ptr, align 8 +// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR]], align 8 +// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR2]], align 8 +// OGCG: %[[BLOCKADD:.*]] = load ptr, ptr %[[PTR2]], align 8 +// OGCG: br label %indirectgoto +// OGCG: LABEL_A: ; preds = %indirectgoto, %indirectgoto, %indirectgoto +// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR3]], align 8 +// OGCG: ret void +// OGCG: indirectgoto: ; preds = %entry +// OGCG: %indirect.goto.dest = phi ptr [ %[[BLOCKADD]], %entry ] +// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A, label %LABEL_A, label %LABEL_A] + +// This test checks that CIR preserves insertion order of blockaddresses +// for indirectbr, even if some were resolved immediately and others later. +void E(void) { + void *ptr = &&LABEL_D; + void *ptr2 = &&LABEL_C; +LABEL_A: +LABEL_B: + void *ptr3 = &&LABEL_B; + void *ptr4 = &&LABEL_A; +LABEL_C: +LABEL_D: + return; +} + +//CIR: cir.func {{.*}} @E() +//CIR: ^bb1({{.*}}: !cir.ptr<!void> {{.*}}): // no predecessors +//CIR: cir.indirect_br {{.*}} poison : !cir.ptr<!void>, [ +//CIR-NEXT: ^bb5, +//CIR-NEXT: ^bb4, +//CIR-NEXT: ^bb3, +//CIR-NEXT: ^bb2 +//CIR: ] +//CIR: ^bb2: // 2 preds: ^bb0, ^bb1 +//CIR: cir.label "LABEL_A" +//CIR: ^bb3: // 2 preds: ^bb1, ^bb2 +//CIR: cir.label "LABEL_B" +//CIR: ^bb4: // 2 preds: ^bb1, ^bb3 +//CIR: cir.label "LABEL_C" +//CIR: ^bb5: // 2 preds: ^bb1, ^bb4 +//CIR: cir.label "LABEL_D" + +// OGCG: define dso_local void @E() #0 { +// OGCG: store ptr blockaddress(@E, %LABEL_D), ptr %ptr, align 8 +// OGCG: store ptr blockaddress(@E, %LABEL_C), ptr %ptr2, align 8 +// OGCG: br label %LABEL_A +// OGCG: A: ; preds = %indirectgoto, %entry +// OGCG: br label %LABEL_B +// OGCG: B: ; preds = %indirectgoto, %LABEL_A +// OGCG: store ptr blockaddress(@E, %LABEL_B), ptr %ptr3, align 8 +// OGCG: store ptr blockaddress(@E, %LABEL_A), ptr %ptr4, align 8 +// OGCG: br label %LABEL_C +// OGCG: C: ; preds = %LABEL_B, %indirectgoto +// OGCG: br label %LABEL_D +// OGCG: D: ; preds = %LABEL_C, %indirectgoto +// OGCG: ret void +// OGCG: indirectgoto: ; No predecessors! +// OGCG: indirectbr ptr poison, [label %LABEL_D, label %LABEL_C, label %LABEL_B, label %LABEL_A] diff --git a/clang/test/CIR/CodeGen/label.c b/clang/test/CIR/CodeGen/label.c index fd3c7f2..d3fdf5f 100644 --- a/clang/test/CIR/CodeGen/label.c +++ b/clang/test/CIR/CodeGen/label.c @@ -10,7 +10,7 @@ labelA: return; } -// CIR: cir.func no_proto dso_local @label +// CIR: cir.func {{.*}} @label // CIR: cir.br ^bb1 // CIR: ^bb1: // CIR: cir.label "labelA" @@ -32,7 +32,7 @@ labelC: return; } -// CIR: cir.func no_proto dso_local @multiple_labels +// CIR: cir.func {{.*}} @multiple_labels // CIR: cir.br ^bb1 // CIR: ^bb1: // CIR: cir.label "labelB" @@ -62,7 +62,7 @@ labelD: } } -// CIR: cir.func dso_local @label_in_if +// CIR: cir.func {{.*}} @label_in_if // CIR: cir.if {{.*}} { // CIR: cir.br ^bb1 // CIR: ^bb1: @@ -107,7 +107,7 @@ void after_return() { label: } -// CIR: cir.func no_proto dso_local @after_return +// CIR: cir.func {{.*}} @after_return // CIR: cir.br ^bb1 // CIR: ^bb1: // 2 preds: ^bb0, ^bb2 // CIR: cir.return @@ -133,7 +133,7 @@ void after_unreachable() { label: } -// CIR: cir.func no_proto dso_local @after_unreachable +// CIR: cir.func {{.*}} @after_unreachable // CIR: cir.unreachable // CIR: ^bb1: // CIR: cir.label "label" @@ -153,7 +153,7 @@ void labelWithoutMatch() { end: return; } -// CIR: cir.func no_proto dso_local @labelWithoutMatch +// CIR: cir.func {{.*}} @labelWithoutMatch // CIR: cir.br ^bb1 // CIR: ^bb1: // CIR: cir.label "end" @@ -181,7 +181,7 @@ void foo() { } } -// CIR: cir.func no_proto dso_local @foo +// CIR: cir.func {{.*}} @foo // CIR: cir.scope { // CIR: %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["agg.tmp0"] // CIR: cir.br ^bb1 diff --git a/clang/test/CIR/CodeGen/lambda-static-invoker.cpp b/clang/test/CIR/CodeGen/lambda-static-invoker.cpp index e7d199b..fc68447f 100644 --- a/clang/test/CIR/CodeGen/lambda-static-invoker.cpp +++ b/clang/test/CIR/CodeGen/lambda-static-invoker.cpp @@ -37,7 +37,7 @@ int g3() { // OGCG: ret ptr @"_ZZ2g3vEN3$_08__invokeERKi" // lambda operator() -// CIR: cir.func lambda internal private dso_local @_ZZ2g3vENK3$_0clERKi(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3:.*]]> {{.*}}, %[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) +// CIR: cir.func no_inline lambda internal private dso_local @_ZZ2g3vENK3$_0clERKi(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3:.*]]> {{.*}}, %[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) // CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_G3]]>, !cir.ptr<!cir.ptr<![[REC_LAM_G3]]>>, ["this", init] // CIR: %[[REF_I_ALLOCA:.*]] = cir.alloca {{.*}} ["i", init, const] // CIR: %[[RETVAL:.*]] = cir.alloca {{.*}} ["__retval"] @@ -66,7 +66,7 @@ int g3() { // In OGCG, the _ZZ2g3vENK3$_0clERKi function is emitted after _ZZ2g3vEN3$_08__invokeERKi, see below. // lambda invoker -// CIR: cir.func internal private dso_local @_ZZ2g3vEN3$_08__invokeERKi(%[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) -> !s32i{{.*}} { +// CIR: cir.func no_inline internal private dso_local @_ZZ2g3vEN3$_08__invokeERKi(%[[REF_I_ARG:.*]]: !cir.ptr<!s32i> {{.*}}) -> !s32i{{.*}} { // CIR: %[[REF_I_ALLOCA:.*]] = cir.alloca {{.*}} ["i", init, const] // CIR: %[[RETVAL:.*]] = cir.alloca {{.*}} ["__retval"] // CIR: %[[LAM_ALLOCA:.*]] = cir.alloca ![[REC_LAM_G3]], !cir.ptr<![[REC_LAM_G3]]>, ["unused.capture"] @@ -91,7 +91,7 @@ int g3() { // In OGCG, the _ZZ2g3vEN3$_08__invokeERKi function is emitted after _ZN1A3barEv, see below. // lambda operator int (*)(int const&)() -// CIR: cir.func internal private dso_local @_ZZ2g3vENK3$_0cvPFiRKiEEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3]]> {{.*}}) -> !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>{{.*}} { +// CIR: cir.func no_inline internal private dso_local @_ZZ2g3vENK3$_0cvPFiRKiEEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G3]]> {{.*}}) -> !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>{{.*}} { // CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_G3]]>, !cir.ptr<!cir.ptr<![[REC_LAM_G3]]>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> !s32i>>>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]] diff --git a/clang/test/CIR/CodeGen/lambda.cpp b/clang/test/CIR/CodeGen/lambda.cpp index 91380b9..3c2b096 100644 --- a/clang/test/CIR/CodeGen/lambda.cpp +++ b/clang/test/CIR/CodeGen/lambda.cpp @@ -8,18 +8,51 @@ // We declare anonymous record types to represent lambdas. Rather than trying to // to match the declarations, we establish variables for these when they are used. +auto global_lambda = [](){}; +void use_global_lambda() { + global_lambda(); +} + +// CIR: cir.global "private" internal dso_local @global_lambda = #cir.undef : ![[REC_LAM_GLOBAL_LAMBDA:.*]] {alignment = 1 : i64} +// CIR: cir.func {{.*}} lambda internal private dso_local @_ZNK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]> {{.*}}) +// CIR: %[[THIS:.*]] = cir.alloca !cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>, !cir.ptr<!cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>>, ["this", init] +// CIR: cir.store %[[THIS_ARG]], %[[THIS]] +// CIR: cir.load %[[THIS]] +// +// CIR: cir.func {{.*}} @_Z17use_global_lambdav() +// CIR: %[[LAMBDA:.*]] = cir.get_global @global_lambda : !cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]> +// CIR: cir.call @_ZNK3$_0clEv(%[[LAMBDA]]) : (!cir.ptr<![[REC_LAM_GLOBAL_LAMBDA]]>) -> () + +// LLVM: @global_lambda = internal global %[[REC_LAM_GLOBAL_LAMBDA:.*]] undef, align 1 +// LLVM: define internal void @"_ZNK3$_0clEv"(ptr %[[THIS_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// +// LLVM: define dso_local void @_Z17use_global_lambdav() +// LLVM: call void @"_ZNK3$_0clEv"(ptr @global_lambda) + +// OGCG: @global_lambda = internal global %[[REC_LAM_GLOBAL_LAMBDA:.*]] undef, align 1 +// OGCG: define dso_local void @_Z17use_global_lambdav() +// OGCG: call void @"_ZNK3$_0clEv"(ptr noundef nonnull align 1 dereferenceable(1) @global_lambda) +// +// OGCG: define internal void @"_ZNK3$_0clEv"(ptr {{.*}} %[[THIS_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + void fn() { auto a = [](){}; a(); } -// CIR: cir.func lambda internal private dso_local @_ZZ2fnvENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_FN_A:.*]]> {{.*}}) {{.*}} { +// CIR: cir.func {{.*}} lambda internal private dso_local @_ZZ2fnvENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_FN_A:.*]]> {{.*}}) // CIR: %[[THIS:.*]] = cir.alloca !cir.ptr<![[REC_LAM_FN_A]]>, !cir.ptr<!cir.ptr<![[REC_LAM_FN_A]]>>, ["this", init] // CIR: cir.store %[[THIS_ARG]], %[[THIS]] // CIR: cir.load %[[THIS]] // CIR: cir.return -// CIR: cir.func dso_local @_Z2fnv() {{.*}} { +// CIR: cir.func {{.*}} @_Z2fnv() // CIR: %[[A:.*]] = cir.alloca ![[REC_LAM_FN_A]], !cir.ptr<![[REC_LAM_FN_A]]>, ["a"] // CIR: cir.call @_ZZ2fnvENK3$_0clEv(%[[A]]) @@ -52,7 +85,7 @@ void l0() { a(); } -// CIR: cir.func lambda internal private dso_local @_ZZ2l0vENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_L0_A:.*]]> {{.*}}) {{.*}} { +// CIR: cir.func {{.*}} lambda internal private dso_local @_ZZ2l0vENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_L0_A:.*]]> {{.*}}) // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<![[REC_LAM_L0_A]]>, !cir.ptr<!cir.ptr<![[REC_LAM_L0_A]]>>, ["this", init] {alignment = 8 : i64} // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] // CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] @@ -66,7 +99,7 @@ void l0() { // CIR: cir.store{{.*}} %[[I_PLUS_ONE]], %[[I_ADDR]] // CIR: cir.return -// CIR: cir.func {{.*}} @_Z2l0v() {{.*}} { +// CIR: cir.func {{.*}} @_Z2l0v() // CIR: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i"] // CIR: %[[A:.*]] = cir.alloca ![[REC_LAM_L0_A]], !cir.ptr<![[REC_LAM_L0_A]]>, ["a", init] // CIR: %[[I_ADDR:.*]] = cir.get_member %[[A]][0] {name = "i"} @@ -124,7 +157,7 @@ auto g() { }; } -// CIR: cir.func dso_local @_Z1gv() -> ![[REC_LAM_G:.*]] {{.*}} { +// CIR: cir.func {{.*}} @_Z1gv() -> ![[REC_LAM_G:.*]] { // CIR: %[[RETVAL:.*]] = cir.alloca ![[REC_LAM_G]], !cir.ptr<![[REC_LAM_G]]>, ["__retval"] // CIR: %[[I_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] // CIR: %[[TWELVE:.*]] = cir.const #cir.int<12> : !s32i @@ -166,7 +199,7 @@ auto g2() { } // Should be same as above because of NRVO -// CIR: cir.func dso_local @_Z2g2v() -> ![[REC_LAM_G2:.*]] {{.*}} { +// CIR: cir.func {{.*}} @_Z2g2v() -> ![[REC_LAM_G2:.*]] { // CIR: %[[RETVAL:.*]] = cir.alloca ![[REC_LAM_G2]], !cir.ptr<![[REC_LAM_G2]]>, ["__retval", init] // CIR: %[[I_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] // CIR: %[[TWELVE:.*]] = cir.const #cir.int<12> : !s32i @@ -199,7 +232,7 @@ int f() { return g2()(); } -// CIR:cir.func lambda internal private dso_local @_ZZ2g2vENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G2]]> {{.*}}) -> !s32i {{.*}} { +// CIR:cir.func {{.*}} lambda internal private dso_local @_ZZ2g2vENK3$_0clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_G2]]> {{.*}}) -> !s32i // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<![[REC_LAM_G2]]>, !cir.ptr<!cir.ptr<![[REC_LAM_G2]]>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] @@ -217,7 +250,7 @@ int f() { // CIR: %[[RET:.*]] = cir.load %[[RETVAL]] // CIR: cir.return %[[RET]] -// CIR: cir.func dso_local @_Z1fv() -> !s32i {{.*}} { +// CIR: cir.func {{.*}} @_Z1fv() -> !s32i // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.scope { // CIR: %[[TMP:.*]] = cir.alloca ![[REC_LAM_G2]], !cir.ptr<![[REC_LAM_G2]]>, ["ref.tmp0"] @@ -299,7 +332,7 @@ struct A { // OGCG: call noundef i32 @_ZN1A3barEv(ptr {{.*}} %[[A_THIS]]) // lambda operator() in foo() -// CIR: cir.func lambda comdat linkonce_odr @_ZZN1A3fooEvENKUlvE_clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_A:.*]]> {{.*}}) {{.*}} { +// CIR: cir.func {{.*}} lambda comdat linkonce_odr @_ZZN1A3fooEvENKUlvE_clEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_A:.*]]> {{.*}}) // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<![[REC_LAM_A]]>, !cir.ptr<!cir.ptr<![[REC_LAM_A]]>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store{{.*}} %[[THIS_ARG]], %[[THIS_ADDR]] @@ -326,7 +359,7 @@ struct A { // The function above is defined after _ZN1A3barEv in OGCG, see below. // A::foo() -// CIR: cir.func {{.*}} @_ZN1A3fooEv(%[[THIS_ARG:.*]]: !cir.ptr<!rec_A> {{.*}}) -> !s32i {{.*}} { +// CIR: cir.func {{.*}} @_ZN1A3fooEv(%[[THIS_ARG:.*]]: !cir.ptr<!rec_A> {{.*}}) -> !s32i // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] @@ -334,7 +367,7 @@ struct A { // 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: cir.copy %[[THIS]] to %[[STRUCT_A]] : !cir.ptr<!rec_A> // CIR: %[[LAM_RET:.*]] = cir.call @_ZZN1A3fooEvENKUlvE_clEv(%[[LAM_ADDR]]) // CIR: cir.store{{.*}} %[[LAM_RET]], %[[RETVAL]] // CIR: } @@ -350,7 +383,7 @@ struct A { // LLVM: br label %[[SCOPE_BB:.*]] // LLVM: [[SCOPE_BB]]: // LLVM: %[[STRUCT_A:.*]] = getelementptr %[[REC_LAM_A]], ptr %[[LAM_ALLOCA]], i32 0, i32 0 -// LLVM: call void @_ZN1AC1ERKS_(ptr %[[STRUCT_A]], ptr %[[THIS]]) +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[STRUCT_A]], ptr %[[THIS]], i32 4, i1 false) // LLVM: %[[LAM_RET:.*]] = call i32 @_ZZN1A3fooEvENKUlvE_clEv(ptr %[[LAM_ALLOCA]]) // LLVM: store i32 %[[LAM_RET]], ptr %[[RETVAL]] // LLVM: br label %[[RET_BB:.*]] @@ -369,7 +402,7 @@ struct A { // OGCG: ret i32 %[[LAM_RET]] // lambda operator() in bar() -// CIR: cir.func {{.*}} @_ZZN1A3barEvENKUlvE_clEv(%[[THIS_ARG2:.*]]: !cir.ptr<![[REC_LAM_PTR_A:.*]]> {{.*}}) -> !s32i {{.*}} { +// CIR: cir.func {{.*}} @_ZZN1A3barEvENKUlvE_clEv(%[[THIS_ARG2:.*]]: !cir.ptr<![[REC_LAM_PTR_A:.*]]> {{.*}}) -> !s32i // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<![[REC_LAM_PTR_A]]>, !cir.ptr<!cir.ptr<![[REC_LAM_PTR_A]]>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store{{.*}} %[[THIS_ARG]], %[[THIS_ADDR]] @@ -398,7 +431,7 @@ struct A { // The function above is defined after _ZZN1A3fooEvENKUlvE_clEv in OGCG, see below. // A::bar() -// CIR: cir.func {{.*}} @_ZN1A3barEv(%[[THIS_ARG:.*]]: !cir.ptr<!rec_A> {{.*}}) -> !s32i {{.*}} { +// CIR: cir.func {{.*}} @_ZN1A3barEv(%[[THIS_ARG:.*]]: !cir.ptr<!rec_A> {{.*}}) -> !s32i // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["this", init] // CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] @@ -466,7 +499,7 @@ int test_lambda_this1(){ return x+y; } -// CIR: cir.func {{.*}} @_Z17test_lambda_this1v{{.*}} { +// CIR: cir.func {{.*}} @_Z17test_lambda_this1v // CIR: cir.call @_ZN1AC1Ev(%[[A_THIS:.*]]){{.*}} : (!cir.ptr<!rec_A>) -> () // CIR: cir.call @_ZN1A3fooEv(%[[A_THIS]]){{.*}} : (!cir.ptr<!rec_A>) -> !s32i // CIR: cir.call @_ZN1A3barEv(%[[A_THIS]]){{.*}} : (!cir.ptr<!rec_A>) -> !s32i diff --git a/clang/test/CIR/CodeGen/linkage-spec.cpp b/clang/test/CIR/CodeGen/linkage-spec.cpp index 1affecd..bfb21f8 100644 --- a/clang/test/CIR/CodeGen/linkage-spec.cpp +++ b/clang/test/CIR/CodeGen/linkage-spec.cpp @@ -1,42 +1,42 @@ // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s extern "C" void TopLevelC(){} -// CHECK: cir.func dso_local @TopLevelC() inline(never) { +// CHECK: cir.func no_inline dso_local @TopLevelC() extern "C++" void TopLevelCpp(){} -// CHECK: cir.func dso_local @_Z11TopLevelCppv() inline(never) { +// CHECK: cir.func no_inline dso_local @_Z11TopLevelCppv() extern "C++" { void ExternCppEmpty(){} - // CHECK: cir.func dso_local @_Z14ExternCppEmptyv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z14ExternCppEmptyv() extern "C" void ExternCpp_C(){} - // CHECK: cir.func dso_local @ExternCpp_C() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternCpp_C() extern "C++" void ExternCpp_Cpp(){} - // CHECK: cir.func dso_local @_Z13ExternCpp_Cppv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z13ExternCpp_Cppv() extern "C" { void ExternCpp_CEmpty(){} - // CHECK: cir.func dso_local @ExternCpp_CEmpty() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternCpp_CEmpty() extern "C" void ExternCpp_C_C(){} - // CHECK: cir.func dso_local @ExternCpp_C_C() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternCpp_C_C() extern "C++" void ExternCpp_C_Cpp(){} - // CHECK: cir.func dso_local @_Z15ExternCpp_C_Cppv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z15ExternCpp_C_Cppv() } } extern "C" { void ExternCEmpty(){} - // CHECK: cir.func dso_local @ExternCEmpty() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternCEmpty() extern "C" void ExternC_C(){} - // CHECK: cir.func dso_local @ExternC_C() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternC_C() extern "C++" void ExternC_Cpp(){} - // CHECK: cir.func dso_local @_Z11ExternC_Cppv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z11ExternC_Cppv() extern "C++" { void ExternC_CppEmpty(){} - // CHECK: cir.func dso_local @_Z16ExternC_CppEmptyv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z16ExternC_CppEmptyv() extern "C" void ExternC_Cpp_C(){} - // CHECK: cir.func dso_local @ExternC_Cpp_C() inline(never) { + // CHECK: cir.func no_inline dso_local @ExternC_Cpp_C() extern "C++" void ExternC_Cpp_Cpp(){} - // CHECK: cir.func dso_local @_Z15ExternC_Cpp_Cppv() inline(never) { + // CHECK: cir.func no_inline dso_local @_Z15ExternC_Cpp_Cppv() } } diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp index 3d28666..463434c 100644 --- a/clang/test/CIR/CodeGen/loop.cpp +++ b/clang/test/CIR/CodeGen/loop.cpp @@ -312,23 +312,10 @@ void l5() { // CIR: %[[BEGIN_ADDR:.*]] = cir.alloca {{.*}} ["__begin1", init] // CIR: %[[END_ADDR:.*]] = cir.alloca {{.*}} ["__end1", init] // CIR: %[[X_ADDR:.*]] = cir.alloca {{.*}} ["x", init] -// CIR: %[[ARR_CAST:.*]] = cir.cast array_to_ptrdecay %[[ARR_ADDR]] : {{.*}} -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i -// CIR: cir.store{{.*}} %[[ONE]], %[[ARR_CAST]] -// CIR: %[[OFFSET1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[STRIDE:.*]] = cir.ptr_stride %[[ARR_CAST]], %[[OFFSET1]] : ({{.*}}, {{.*}}) -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i -// CIR: cir.store{{.*}} %[[TWO]], %[[STRIDE]] -// CIR: %[[OFFSET2:.*]] = cir.const #cir.int<2> : !s64i -// CIR: %[[STRIDE2:.*]] = cir.ptr_stride %[[ARR_CAST]], %[[OFFSET2]] : ({{.*}}, {{.*}}) -// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i -// CIR: cir.store{{.*}} %[[THREE]], %[[STRIDE2]] -// CIR: %[[OFFSET3:.*]] = cir.const #cir.int<3> : !s64i -// CIR: %[[STRIDE3:.*]] = cir.ptr_stride %[[ARR_CAST]], %[[OFFSET3]] : ({{.*}}, {{.*}}) -// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i -// CIR: cir.store{{.*}} %[[FOUR]], %[[STRIDE3]] +// CIR: %[[ARR_INIT:.*]] = cir.const #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]> +// CIR: cir.store{{.*}} %[[ARR_INIT]], %[[ARR_ADDR]] // CIR: cir.store{{.*}} %[[ARR_ADDR]], %[[RANGE_ADDR]] -// CIR: %[[RANGE_LOAD:.*]] = cir.load{{.*}} %[[RANGE_ADDR]] +// CIR: %[[RANGE_LOAD:.*]] = cir.load %[[RANGE_ADDR]] // CIR: %[[RANGE_CAST:.*]] = cir.cast array_to_ptrdecay %[[RANGE_LOAD]] : {{.*}} // CIR: cir.store{{.*}} %[[RANGE_CAST]], %[[BEGIN_ADDR]] // CIR: %[[BEGIN:.*]] = cir.load{{.*}} %[[RANGE_ADDR]] @@ -363,14 +350,7 @@ void l5() { // LLVM: %[[X_ADDR:.*]] = alloca i32 // LLVM: br label %[[SETUP:.*]] // LLVM: [[SETUP]]: -// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_ADDR]], i32 0 -// LLVM: store i32 1, ptr %[[ARR_0]] -// LLVM: %[[ARR_1:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 1 -// LLVM: store i32 2, ptr %[[ARR_1]] -// LLVM: %[[ARR_2:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 2 -// LLVM: store i32 3, ptr %[[ARR_2]] -// LLVM: %[[ARR_3:.*]] = getelementptr i32, ptr %[[ARR_0]], i64 3 -// LLVM: store i32 4, ptr %[[ARR_3]] +// LLVM: store [4 x i32] [i32 1, i32 2, i32 3, i32 4], ptr %[[ARR_ADDR]] // LLVM: store ptr %[[ARR_ADDR]], ptr %[[RANGE_ADDR]] // LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]] // LLVM: %[[BEGIN_CAST:.*]] = getelementptr i32, ptr %[[BEGIN]], i32 0 diff --git a/clang/test/CIR/CodeGen/no-common.c b/clang/test/CIR/CodeGen/no-common.c new file mode 100644 index 0000000..ce4c5fc --- /dev/null +++ b/clang/test/CIR/CodeGen/no-common.c @@ -0,0 +1,103 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -emit-cir -o %t-default.cir +// RUN: FileCheck --input-file=%t-default.cir %s -check-prefix=CIR-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fno-common -emit-cir -o %t-no-common.cir +// RUN: FileCheck --input-file=%t-no-common.cir %s -check-prefix=CIR-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fcommon -emit-cir -o %t-common.cir +// RUN: FileCheck --input-file=%t-common.cir %s -check-prefix=CIR-COMMON + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -emit-llvm -o %t-default-cir.ll +// RUN: FileCheck --input-file=%t-default-cir.ll %s -check-prefix=LLVM-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fno-common -emit-llvm -o %t-no-common-cir.ll +// RUN: FileCheck --input-file=%t-no-common-cir.ll %s -check-prefix=LLVM-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fcommon -emit-llvm -o %t-common-cir.ll +// RUN: FileCheck --input-file=%t-common-cir.ll %s -check-prefix=LLVM-COMMON + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o %t-default.ll +// RUN: FileCheck --input-file=%t-default.ll %s -check-prefix=OGCG-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fno-common -emit-llvm -o %t-no-common.ll +// RUN: FileCheck --input-file=%t-no-common.ll %s -check-prefix=OGCG-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fcommon -emit-llvm -o %t-common.ll +// RUN: FileCheck --input-file=%t-common.ll %s -check-prefix=OGCG-COMMON + +const int a = 42; +// CIR-DEFAULT: cir.global constant external @a = #cir.int<42> +// LLVM-DEFAULT: @a = constant i32 42 +// OGCG-DEFAULT: @a = constant i32 42 + +// CIR-COMMON: cir.global constant external @a +// LLVM-COMMON: @a = constant i32 42 +// OGCG-COMMON: @a = constant i32 42 + +const int b __attribute__((common)) = 42; +// CIR-DEFAULT: cir.global constant external @b = #cir.int<42> +// LLVM-DEFAULT: @b = constant i32 42 +// OGCG-DEFAULT: @b = constant i32 42 + +// CIR-COMMON: cir.global constant external @b = #cir.int<42> +// LLVM-COMMON: @b = constant i32 42 +// OGCG-COMMON: @b = constant i32 42 + +const int c __attribute__((nocommon)) = 42; +// CIR-DEFAULT: cir.global constant external @c = #cir.int<42> +// LLVM-DEFAULT: @c = constant i32 42 +// OGCG-DEFAULT: @c = constant i32 42 + +// CIR-COMMON: cir.global constant external @c = #cir.int<42> +// LLVM-COMMON: @c = constant i32 42 +// OGCG-COMMON: @c = constant i32 42 + +int d = 11; +// CIR-DEFAULT: cir.global external @d = #cir.int<11> +// LLVM-DEFAULT: @d = global i32 11 +// OGCG-DEFAULT: @d = global i32 11 + +// CIR-COMMON: cir.global external @d = #cir.int<11> +// LLVM-COMMON: @d = global i32 11 +// OGCG-COMMON: @d = global i32 11 + +int e; +// CIR-DEFAULT: cir.global external @e = #cir.int<0> +// LLVM-DEFAULT: @e = global i32 0 +// OGCG-DEFAULT: @e = global i32 0 + +// CIR-COMMON: cir.global common @e = #cir.int<0> +// LLVM-COMMON: @e = common global i32 0 +// OGCG-COMMON: @e = common global i32 0 + + +int f __attribute__((common)); +// CIR-DEFAULT: cir.global common @f = #cir.int<0> +// LLVM-DEFAULT: @f = common global i32 0 +// OGCG-DEFAULT: @f = common global i32 0 + +// CIR-COMMON: cir.global common @f +// LLVM-COMMON: @f = common global i32 0 +// OGCG-COMMON: @f = common global i32 0 + +int g __attribute__((nocommon)); +// CIR-DEFAULT: cir.global external @g = #cir.int<0> +// LLVM-DEFAULT: @g = global i32 +// OGCG-DEFAULT: @g = global i32 0 + +// CIR-COMMON: cir.global external @g = #cir.int<0> +// LLVM-COMMON: @g = global i32 0 +// OGCG-COMMON: @g = global i32 0 + +const int h; +// CIR-DEFAULT: cir.global constant external @h = #cir.int<0> +// LLVM-DEFAULT: @h = constant i32 +// OGCG-DEFAULT: @h = constant i32 0 + +// CIR-COMMON: cir.global common @h = #cir.int<0> +// LLVM-COMMON: @h = common global i32 0 +// OGCG-COMMON: @h = common global i32 0 + +typedef void* (*fn_t)(long a, long b, char *f, int c); +fn_t ABC __attribute__ ((nocommon)); +// CIR-DEFAULT: cir.global external @ABC = #cir.ptr<null> +// LLVM-DEFAULT: @ABC = global ptr null +// OGCG-DEFAULT: @ABC = global ptr null + +// CIR-COMMON: cir.global external @ABC = #cir.ptr<null> +// LLVM-COMMON: @ABC = global ptr null +// OGCG-COMMON: @ABC = global ptr null diff --git a/clang/test/CIR/CodeGen/no-prototype.c b/clang/test/CIR/CodeGen/no-prototype.c index 728c4b8..d266ccb 100644 --- a/clang/test/CIR/CodeGen/no-prototype.c +++ b/clang/test/CIR/CodeGen/no-prototype.c @@ -7,9 +7,9 @@ // No-proto definition followed by a correct call. int noProto0(x) int x; { return x; } -// CHECK: cir.func no_proto dso_local @noProto0(%arg0: !s32i {{.+}}) -> !s32i +// CHECK: cir.func {{.*}} no_proto {{.*}} @noProto0(%arg0: !s32i {{.+}}) -> !s32i int test0(int x) { - // CHECK: cir.func dso_local @test0 + // CHECK: cir.func {{.*}} @test0 return noProto0(x); // We know the definition. Should be a direct call. // CHECK: %{{.+}} = cir.call @noProto0(%{{.+}}) } @@ -21,9 +21,9 @@ int test0(int x) { // definition is not marked as no-proto. int noProto1(); int noProto1(int x) { return x; } -// CHECK: cir.func dso_local @noProto1(%arg0: !s32i {{.+}}) -> !s32i +// CHECK: cir.func {{.*}} @noProto1(%arg0: !s32i {{.+}}) -> !s32i int test1(int x) { - // CHECK: cir.func dso_local @test1 + // CHECK: cir.func {{.*}} @test1 return noProto1(x); // CHECK: %{{.+}} = cir.call @noProto1(%{{[0-9]+}}) : (!s32i) -> !s32i } @@ -39,7 +39,7 @@ int test2(int x) { // CHECK: {{.*}} = cir.call [[GGO]](%{{[0-9]+}}) : (!cir.ptr<!cir.func<(!s32i) -> !s32i>>, !s32i) -> !s32i } int noProto2(int x) { return x; } -// CHECK: cir.func no_proto dso_local @noProto2(%arg0: !s32i {{.+}}) -> !s32i +// CHECK: cir.func {{.*}} no_proto {{.*}} @noProto2(%arg0: !s32i {{.+}}) -> !s32i // No-proto declaration without definition (any call here is "correct"). // @@ -48,7 +48,7 @@ int noProto2(int x) { return x; } int noProto3(); // cir.func private no_proto @noProto3(...) -> !s32i int test3(int x) { -// CHECK: cir.func dso_local @test3 +// CHECK: cir.func {{.*}} @test3 return noProto3(x); // CHECK: [[GGO:%.*]] = cir.get_global @noProto3 : !cir.ptr<!cir.func<(...) -> !s32i>> // CHECK: [[CAST:%.*]] = cir.cast bitcast [[GGO]] : !cir.ptr<!cir.func<(...) -> !s32i>> -> !cir.ptr<!cir.func<(!s32i) -> !s32i>> @@ -64,7 +64,7 @@ int test3(int x) { // No-proto definition followed by an incorrect call due to extra args. int noProto4() { return 0; } -// cir.func private no_proto @noProto4() -> !s32i +// cir.func {{.*}} no_proto {{.*}} @noProto4() -> !s32i int test4(int x) { return noProto4(x); // Even if we know the definition, this should compile. // CHECK: [[GGO:%.*]] = cir.get_global @noProto4 : !cir.ptr<!cir.func<() -> !s32i>> @@ -81,4 +81,4 @@ int test5(int x) { // CHECK: {{%.*}} = cir.call [[CAST]]() : (!cir.ptr<!cir.func<() -> !s32i>>) -> !s32i } int noProto5(int x) { return x; } -// CHECK: cir.func no_proto dso_local @noProto5(%arg0: !s32i {{.+}}) -> !s32i +// CHECK: cir.func {{.*}} no_proto {{.*}} @noProto5(%arg0: !s32i {{.+}}) -> !s32i diff --git a/clang/test/CIR/CodeGen/nrvo.cpp b/clang/test/CIR/CodeGen/nrvo.cpp index ce08c79..0fc9b9b 100644 --- a/clang/test/CIR/CodeGen/nrvo.cpp +++ b/clang/test/CIR/CodeGen/nrvo.cpp @@ -49,3 +49,65 @@ struct S f1() { // OGCG-NEXT: call void @_ZN1SC1Ev(ptr {{.*}} %[[RETVAL]]) // OGCG-NEXT: %[[RET:.*]] = load i64, ptr %[[RETVAL]] // OGCG-NEXT: ret i64 %[[RET]] + +struct NonTrivial { + ~NonTrivial(); +}; + +void maybeThrow(); + +NonTrivial test_nrvo() { + NonTrivial result; + maybeThrow(); + return result; +} + +// TODO(cir): Handle normal cleanup properly. + +// CIR: cir.func {{.*}} @_Z9test_nrvov() +// CIR: %[[RESULT:.*]] = cir.alloca !rec_NonTrivial, !cir.ptr<!rec_NonTrivial>, ["__retval"] +// CIR: %[[NRVO_FLAG:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["nrvo"] +// CIR: %[[FALSE:.*]] = cir.const #false +// CIR: cir.store{{.*}} %[[FALSE]], %[[NRVO_FLAG]] +// CIR: cir.call @_Z10maybeThrowv() : () -> () +// CIR: %[[TRUE:.*]] = cir.const #true +// CIR: cir.store{{.*}} %[[TRUE]], %[[NRVO_FLAG]] +// CIR: %[[NRVO_FLAG_VAL:.*]] = cir.load{{.*}} %[[NRVO_FLAG]] +// CIR: %[[NOT_NRVO_VAL:.*]] = cir.unary(not, %[[NRVO_FLAG_VAL]]) +// CIR: cir.if %[[NOT_NRVO_VAL]] { +// CIR: cir.call @_ZN10NonTrivialD1Ev(%[[RESULT]]) +// CIR: } +// CIR: %[[RET:.*]] = cir.load %[[RESULT]] +// CIR: cir.return %[[RET]] + +// LLVM: define {{.*}} %struct.NonTrivial @_Z9test_nrvov() +// LLVM: %[[RESULT:.*]] = alloca %struct.NonTrivial +// LLVM: %[[NRVO_FLAG:.*]] = alloca i8 +// LLVM: store i8 0, ptr %[[NRVO_FLAG]] +// LLVM: call void @_Z10maybeThrowv() +// LLVM: store i8 1, ptr %[[NRVO_FLAG]] +// LLVM: %[[NRVO_VAL:.*]] = load i8, ptr %[[NRVO_FLAG]] +// LLVM: %[[NRVO_VAL_TRUNC:.*]] = trunc i8 %[[NRVO_VAL]] to i1 +// LLVM: %[[NOT_NRVO_VAL:.*]] = xor i1 %[[NRVO_VAL_TRUNC]], true +// LLVM: br i1 %[[NOT_NRVO_VAL]], label %[[NRVO_UNUSED:.*]], label %[[NRVO_USED:.*]] +// LLVM: [[NRVO_UNUSED]]: +// LLVM: call void @_ZN10NonTrivialD1Ev(ptr %[[RESULT]]) +// LLVM: br label %[[NRVO_USED]] +// LLVM: [[NRVO_USED]]: +// LLVM: %[[RET:.*]] = load %struct.NonTrivial, ptr %[[RESULT]] +// LLVM: ret %struct.NonTrivial %[[RET]] + +// OGCG: define {{.*}} void @_Z9test_nrvov(ptr {{.*}} sret(%struct.NonTrivial) {{.*}} %[[RESULT:.*]]) +// OGCG: %[[RESULT_ADDR:.*]] = alloca ptr +// OGCG: %[[NRVO_FLAG:.*]] = alloca i1, align 1 +// OGCG: store ptr %[[RESULT]], ptr %[[RESULT_ADDR]] +// OGCG: store i1 false, ptr %[[NRVO_FLAG]] +// OGCG: call void @_Z10maybeThrowv() +// OGCG: store i1 true, ptr %[[NRVO_FLAG]] +// OGCG: %[[NRVO_VAL:.*]] = load i1, ptr %[[NRVO_FLAG]] +// OGCG: br i1 %[[NRVO_VAL]], label %[[SKIPDTOR:.*]], label %[[NRVO_UNUSED:.*]] +// OGCG: [[NRVO_UNUSED]]: +// OGCG: call void @_ZN10NonTrivialD1Ev(ptr {{.*}} %[[RESULT]]) +// OGCG: br label %[[SKIPDTOR]] +// OGCG: [[SKIPDTOR]]: +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/object-size-flex-array.c b/clang/test/CIR/CodeGen/object-size-flex-array.c new file mode 100644 index 0000000..74229fd --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size-flex-array.c @@ -0,0 +1,317 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR --check-prefix=CIR-NO-STRICT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-llvm -disable-llvm-passes %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM --check-prefix=LLVM-NO-STRICT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm -disable-llvm-passes %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG --check-prefix=OGCG-NO-STRICT + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=0 -emit-cir %s -o %t-strict-0.cir +// RUN: FileCheck --input-file=%t-strict-0.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-0 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=0 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-0.ll +// RUN: FileCheck --input-file=%t-cir-strict-0.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-0 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=0 -emit-llvm -disable-llvm-passes %s -o %t-strict-0.ll +// RUN: FileCheck --input-file=%t-strict-0.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-0 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=1 -emit-cir %s -o %t-strict-1.cir +// RUN: FileCheck --input-file=%t-strict-1.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-1 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=1 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-1.ll +// RUN: FileCheck --input-file=%t-cir-strict-1.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-1 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=1 -emit-llvm -disable-llvm-passes %s -o %t-strict-1.ll +// RUN: FileCheck --input-file=%t-strict-1.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-1 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=2 -emit-cir %s -o %t-strict-2.cir +// RUN: FileCheck --input-file=%t-strict-2.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-2 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=2 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-2.ll +// RUN: FileCheck --input-file=%t-cir-strict-2.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-2 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=2 -emit-llvm -disable-llvm-passes %s -o %t-strict-2.ll +// RUN: FileCheck --input-file=%t-strict-2.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-2 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=3 -emit-cir %s -o %t-strict-3.cir +// RUN: FileCheck --input-file=%t-strict-3.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-3 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=3 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-3.ll +// RUN: FileCheck --input-file=%t-cir-strict-3.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-3 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=3 -emit-llvm -disable-llvm-passes %s -o %t-strict-3.ll +// RUN: FileCheck --input-file=%t-strict-3.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-3 + +#define OBJECT_SIZE_BUILTIN __builtin_object_size + +typedef struct { + float f; + double c[]; +} foo_t; + +typedef struct { + float f; + double c[0]; +} foo0_t; + +typedef struct { + float f; + double c[1]; +} foo1_t; + +typedef struct { + float f; + double c[2]; +} foo2_t; + +// CIR-LABEL: @bar +// LLVM-LABEL: @bar( +// OGCG-LABEL: @bar( +unsigned bar(foo_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar0 +// LLVM-LABEL: @bar0( +// OGCG-LABEL: @bar0( +unsigned bar0(foo0_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-3: ret i32 0 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar1 +// LLVM-LABEL: @bar1( +// OGCG-LABEL: @bar1( +unsigned bar1(foo1_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar2 +// LLVM-LABEL: @bar2( +// OGCG-LABEL: @bar2( +unsigned bar2(foo2_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +#define DYNAMIC_OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size + +// CIR-LABEL: @dyn_bar +// LLVM-LABEL: @dyn_bar( +// OGCG-LABEL: @dyn_bar( +unsigned dyn_bar(foo_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar0 +// LLVM-LABEL: @dyn_bar0( +// OGCG-LABEL: @dyn_bar0( +unsigned dyn_bar0(foo0_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-3: ret i32 0 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar1 +// LLVM-LABEL: @dyn_bar1( +// OGCG-LABEL: @dyn_bar1( +unsigned dyn_bar1(foo1_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar2 +// LLVM-LABEL: @dyn_bar2( +// OGCG-LABEL: @dyn_bar2( +unsigned dyn_bar2(foo2_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// Also checks for non-trailing flex-array like members + +typedef struct { + double c[0]; + float f; +} foofoo0_t; + +typedef struct { + double c[1]; + float f; +} foofoo1_t; + +typedef struct { + double c[2]; + float f; +} foofoo2_t; + +// CIR-LABEL: @babar0 +// LLVM-LABEL: @babar0( +// OGCG-LABEL: @babar0( +unsigned babar0(foofoo0_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<0> + // CIR-STRICT-0: cir.const #cir.int<0> + // CIR-STRICT-1: cir.const #cir.int<0> + // CIR-STRICT-2: cir.const #cir.int<0> + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: store i32 0 + // LLVM-STRICT-0: store i32 0 + // LLVM-STRICT-1: store i32 0 + // LLVM-STRICT-2: store i32 0 + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: ret i32 0 + // OGCG-STRICT-0: ret i32 0 + // OGCG-STRICT-1: ret i32 0 + // OGCG-STRICT-2: ret i32 0 + // OGCG-STRICT-3: ret i32 0 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @babar1 +// LLVM-LABEL: @babar1( +// OGCG-LABEL: @babar1( +unsigned babar1(foofoo1_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<8> + // CIR-STRICT-0: cir.const #cir.int<8> + // CIR-STRICT-1: cir.const #cir.int<8> + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: store i32 8 + // LLVM-STRICT-0: store i32 8 + // LLVM-STRICT-1: store i32 8 + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: ret i32 8 + // OGCG-STRICT-0: ret i32 8 + // OGCG-STRICT-1: ret i32 8 + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @babar2 +// LLVM-LABEL: @babar2( +// OGCG-LABEL: @babar2( +unsigned babar2(foofoo2_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<16> + // CIR-STRICT-0: cir.const #cir.int<16> + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: store i32 16 + // LLVM-STRICT-0: store i32 16 + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: ret i32 16 + // OGCG-STRICT-0: ret i32 16 + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} diff --git a/clang/test/CIR/CodeGen/object-size.c b/clang/test/CIR/CodeGen/object-size.c new file mode 100644 index 0000000..1b10fb8b --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size.c @@ -0,0 +1,877 @@ +// 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 %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 %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +char gbuf[63]; +char *gp; +int gi, gj; + +// CIR-LABEL: @test1 +// LLVM-LABEL: define {{.*}} void @test1 +// OGCG-LABEL: define {{.*}} void @test1 +void test1(void) { + // CIR: cir.const #cir.int<59> + // LLVM: store i32 59 + // OGCG: store i32 59 + gi = __builtin_object_size(&gbuf[4], 1); +} + +// CIR-LABEL: @test2 +// LLVM-LABEL: define {{.*}} void @test2 +// OGCG-LABEL: define {{.*}} void @test2 +void test2(void) { + // CIR: cir.const #cir.int<63> + // LLVM: store i32 63 + // OGCG: store i32 63 + gi = __builtin_object_size(gbuf, 1); +} + +// CIR-LABEL: @test3 +// LLVM-LABEL: define {{.*}} void @test3 +// OGCG-LABEL: define {{.*}} void @test3 +void test3(void) { + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&gbuf[100], 1); +} + +// CIR-LABEL: @test4 +// LLVM-LABEL: define {{.*}} void @test4 +// OGCG-LABEL: define {{.*}} void @test4 +void test4(void) { + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)(void*)&gbuf[-1], 1); +} + +// CIR-LABEL: @test5 +// LLVM-LABEL: define {{.*}} void @test5 +// OGCG-LABEL: define {{.*}} void @test5 +void test5(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(gp, 0); +} + +// CIR-LABEL: @test6 +// LLVM-LABEL: define {{.*}} void @test6 +// OGCG-LABEL: define {{.*}} void @test6 +void test6(void) { + char buf[57]; + + // CIR: cir.const #cir.int<53> + // LLVM: store i32 53 + // OGCG: store i32 53 + gi = __builtin_object_size(&buf[4], 1); +} + +// CIR-LABEL: @test18 +// LLVM-LABEL: define {{.*}} i32 @test18 +// OGCG-LABEL: define {{.*}} i32 @test18 +unsigned test18(int cond) { + int a[4], b[4]; + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64 + // OGCG: call i64 @llvm.objectsize.i64 + return __builtin_object_size(cond ? a : b, 0); +} + +// CIR-LABEL: @test19 +// LLVM-LABEL: define {{.*}} void @test19 +// OGCG-LABEL: define {{.*}} void @test19 +void test19(void) { + struct { + int a, b; + } foo; + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&foo.a, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.a, 1); + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&foo.a, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.a, 3); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 1); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 3); +} + +// CIR-LABEL: @test20 +// LLVM-LABEL: define {{.*}} void @test20 +// OGCG-LABEL: define {{.*}} void @test20 +void test20(void) { + struct { int t[10]; } t[10]; + + // CIR: cir.const #cir.int<380> + // LLVM: store i32 380 + // OGCG: store i32 380 + gi = __builtin_object_size(&t[0].t[5], 0); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&t[0].t[5], 1); + + // CIR: cir.const #cir.int<380> + // LLVM: store i32 380 + // OGCG: store i32 380 + gi = __builtin_object_size(&t[0].t[5], 2); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&t[0].t[5], 3); +} + +// CIR-LABEL: @test21 +// LLVM-LABEL: define {{.*}} void @test21 +// OGCG-LABEL: define {{.*}} void @test21 +void test21(void) { + struct { int t; } t; + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 3); +} + +// CIR-LABEL: @test22 +// LLVM-LABEL: define {{.*}} void @test22 +// OGCG-LABEL: define {{.*}} void @test22 +void test22(void) { + struct { int t[10]; } t[10]; + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 3); +} + +struct Test23Ty { int a; int t[10]; }; + +// CIR-LABEL: @test23 +// LLVM-LABEL: define {{.*}} void @test23 +// OGCG-LABEL: define {{.*}} void @test23 +void test23(struct Test23Ty *p) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(p, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(p, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(p, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(p, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->a, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&p->a, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&p->a, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&p->a, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 2); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&p->t[5], 3); +} + +// CIR-LABEL: @test24 +// LLVM-LABEL: define {{.*}} void @test24 +// OGCG-LABEL: define {{.*}} void @test24 +void test24(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size((void*)0, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((void*)0, 3); +} + +// CIR-LABEL: @test25 +// LLVM-LABEL: define {{.*}} void @test25 +// OGCG-LABEL: define {{.*}} void @test25 +void test25(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((void*)0x1000, 3); + + // Skipping (void*)0 + 0x1000 tests - void pointer arithmetic NYI in CIR +} + +// CIR-LABEL: @test26 +// LLVM-LABEL: define {{.*}} void @test26 +// OGCG-LABEL: define {{.*}} void @test26 +void test26(void) { + struct { int v[10]; } t[10]; + + // CIR: cir.const #cir.int<316> + // LLVM: store i32 316 + // OGCG: store i32 316 + gi = __builtin_object_size(&t[1].v[11], 0); + + // CIR: cir.const #cir.int<312> + // LLVM: store i32 312 + // OGCG: store i32 312 + gi = __builtin_object_size(&t[1].v[12], 1); + + // CIR: cir.const #cir.int<308> + // LLVM: store i32 308 + // OGCG: store i32 308 + gi = __builtin_object_size(&t[1].v[13], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[1].v[14], 3); +} + +struct Test27IncompleteTy; + +// CIR-LABEL: @test27 +// LLVM-LABEL: define {{.*}} void @test27 +// OGCG-LABEL: define {{.*}} void @test27 +void test27(struct Test27IncompleteTy *t) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(t, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(t, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(t, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(t, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&test27, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&test27, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&test27, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&test27, 3); +} + +// CIR-LABEL: @test28 +// LLVM-LABEL: define {{.*}} void @test28 +// OGCG-LABEL: define {{.*}} void @test28 +void test28(void) { + struct { int v[10]; } t[10]; + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 0); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 1); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 2); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 3); + + // CIR: cir.const #cir.int<356> + // LLVM: store i32 356 + // OGCG: store i32 356 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 0); + + // CIR: cir.const #cir.int<36> + // LLVM: store i32 36 + // OGCG: store i32 36 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 1); + + // CIR: cir.const #cir.int<356> + // LLVM: store i32 356 + // OGCG: store i32 356 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 2); + + // CIR: cir.const #cir.int<36> + // LLVM: store i32 36 + // OGCG: store i32 36 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 3); +} + +struct DynStructVar { + char fst[16]; + char snd[]; +}; + +struct DynStruct0 { + char fst[16]; + char snd[0]; +}; + +struct DynStruct1 { + char fst[16]; + char snd[1]; +}; + +struct StaticStruct { + char fst[16]; + char snd[2]; +}; + +// CIR-LABEL: @test29 +// LLVM-LABEL: define {{.*}} void @test29 +// OGCG-LABEL: define {{.*}} void @test29 +void test29(struct DynStructVar *dv, struct DynStruct0 *d0, + struct DynStruct1 *d1, struct StaticStruct *ss) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(dv->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(dv->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(dv->snd, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(dv->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d0->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d0->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(d0->snd, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(d0->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d1->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d1->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(d1->snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(d1->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(ss->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(ss->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(ss->snd, 2); + + // CIR: cir.const #cir.int<2> + // LLVM: store i32 2 + // OGCG: store i32 2 + gi = __builtin_object_size(ss->snd, 3); +} + +// CIR-LABEL: @test30 +// LLVM-LABEL: define {{.*}} void @test30 +// OGCG-LABEL: define {{.*}} void @test30 +void test30(void) { + struct { struct DynStruct1 fst, snd; } *nested; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->fst.snd, 0); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->fst.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(nested->fst.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->fst.snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->snd.snd, 3); + + union { struct DynStruct1 d1; char c[1]; } *u; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->c, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->c, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(u->c, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(u->c, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(u->d1.snd, 3); +} + +// CIR-LABEL: @test32 +// LLVM-LABEL: define {{.*}} i64 @test32 +// OGCG-LABEL: define {{.*}} i64 @test32 +static struct DynStructVar D32 = { + .fst = {}, + .snd = { 0, 1, 2, }, +}; +unsigned long test32(void) { + // CIR: cir.const #cir.int<19> + // LLVM: store i64 19 + // OGCG: ret i64 19 + return __builtin_object_size(&D32, 1); +} + +// CIR-LABEL: @test33 +// LLVM-LABEL: define {{.*}} i64 @test33 +// OGCG-LABEL: define {{.*}} i64 @test33 +static struct DynStructVar D33 = { + .fst = {}, + .snd = {}, +}; +unsigned long test33(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&D33, 1); +} + +// CIR-LABEL: @test34 +// LLVM-LABEL: define {{.*}} i64 @test34 +// OGCG-LABEL: define {{.*}} i64 @test34 +static struct DynStructVar D34 = { + .fst = {}, +}; +unsigned long test34(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&D34, 1); +} + +// CIR-LABEL: @test35 +// LLVM-LABEL: define {{.*}} i64 @test35 +// OGCG-LABEL: define {{.*}} i64 @test35 +unsigned long test35(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&(struct DynStructVar){}, 1); +} + +// CIR-LABEL: @test37 +// LLVM-LABEL: define {{.*}} i64 @test37 +// OGCG-LABEL: define {{.*}} i64 @test37 +struct Z { struct A { int x, y[]; } z; int a; int b[]; }; +static struct Z my_z = { .b = {1,2,3} }; +unsigned long test37(void) { + // CIR: cir.const #cir.int<4> + // LLVM: store i64 4 + // OGCG: ret i64 4 + return __builtin_object_size(&my_z.z, 1); +} + +// CIR-LABEL: @PR30346 +// LLVM-LABEL: define {{.*}} void @PR30346 +// OGCG-LABEL: define {{.*}} void @PR30346 +void PR30346(void) { + struct sa_family_t {}; + struct sockaddr { + struct sa_family_t sa_family; + char sa_data[14]; + }; + + struct sockaddr *sa; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 2); + + // CIR: cir.const #cir.int<14> + // LLVM: store i32 14 + // OGCG: store i32 14 + gi = __builtin_object_size(sa->sa_data, 3); +} + +extern char incomplete_char_array[]; + +// CIR-LABEL: @incomplete_and_function_types +// LLVM-LABEL: define {{.*}} void @incomplete_and_function_types +// OGCG-LABEL: define {{.*}} void @incomplete_and_function_types +void incomplete_and_function_types(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(incomplete_char_array, 3); +} + +// CIR-LABEL: @deeply_nested +// LLVM-LABEL: define {{.*}} void @deeply_nested +// OGCG-LABEL: define {{.*}} void @deeply_nested +void deeply_nested(void) { + struct { + struct { + struct { + struct { + int e[2]; + char f; + } d[2]; + } c[2]; + } b[2]; + } *a; + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 1); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 3); +} diff --git a/clang/test/CIR/CodeGen/object-size.cpp b/clang/test/CIR/CodeGen/object-size.cpp new file mode 100644 index 0000000..b60e245 --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size.cpp @@ -0,0 +1,108 @@ +// 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 %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 %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +// C++-specific tests for __builtin_object_size + +int gi; + +// CIR-LABEL: @_Z5test1v +// LLVM-LABEL: define{{.*}} void @_Z5test1v() +// OGCG-LABEL: define{{.*}} void @_Z5test1v() +void test1() { + // Guaranteeing that our cast removal logic doesn't break more interesting + // cases. + struct A { int a; }; + struct B { int b; }; + struct C: public A, public B {}; + + C c; + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&c, 0); + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((A*)&c, 0); + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size((B*)&c, 0); + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((char*)&c, 0); + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((char*)(A*)&c, 0); + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size((char*)(B*)&c, 0); +} + +// CIR-LABEL: @_Z5test2v() +// LLVM-LABEL: define{{.*}} void @_Z5test2v() +// OGCG-LABEL: define{{.*}} void @_Z5test2v() +void test2() { + struct A { char buf[16]; }; + struct B : A {}; + struct C { int i; B bs[1]; } *c; + + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 0); + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 1); + // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 2); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0], 3); + + // NYI: DerivedToBase cast + // gi = __builtin_object_size((A*)&c->bs[0], 0); + + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size((A*)&c->bs[0], 1); + + // NYI: DerivedToBase cast + // gi = __builtin_object_size((A*)&c->bs[0], 2); + + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size((A*)&c->bs[0], 3); + + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0].buf[0], 0); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0].buf[0], 1); + // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0].buf[0], 2); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0].buf[0], 3); +} diff --git a/clang/test/CIR/CodeGen/offset-of.cpp b/clang/test/CIR/CodeGen/offset-of.cpp new file mode 100644 index 0000000..f62da9e --- /dev/null +++ b/clang/test/CIR/CodeGen/offset-of.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -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 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct Struct { + int a; + float b; + double c; + bool d; +}; + +void offset_of_builtin() { + unsigned long a = __builtin_offsetof(Struct, a); + unsigned long b = __builtin_offsetof(Struct, b); + unsigned long c = __builtin_offsetof(Struct, c); + unsigned long d = __builtin_offsetof(Struct, d); +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init] +// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init] +// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init] +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i +// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i +// CIR: cir.store {{.*}} %[[CONST_4]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !u64i +// CIR: cir.store {{.*}} %[[CONST_8]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_16:.*]] = cir.const #cir.int<16> : !u64i +// CIR: cir.store {{.*}} %[[CONST_16]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i> + +// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 0, ptr %[[A_ADDR]], align 8 +// LLVM: store i64 4, ptr %[[B_ADDR]], align 8 +// LLVM: store i64 8, ptr %[[C_ADDR]], align 8 +// LLVM: store i64 16, ptr %[[D_ADDR]], align 8 + +// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 0, ptr %[[A_ADDR]], align 8 +// OGCG: store i64 4, ptr %[[B_ADDR]], align 8 +// OGCG: store i64 8, ptr %[[C_ADDR]], align 8 +// OGCG: store i64 16, ptr %[[D_ADDR]], align 8 + +struct StructWithArray { + Struct array[4][4]; +}; + +void offset_of_builtin_from_array_element() { + unsigned long a = __builtin_offsetof(StructWithArray, array[0][0].a); + unsigned long b = __builtin_offsetof(StructWithArray, array[1][1].b); + unsigned long c = __builtin_offsetof(StructWithArray, array[2][2].c); + unsigned long d = __builtin_offsetof(StructWithArray, array[3][3].d); +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init] +// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init] +// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init] +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i +// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_124:.*]] = cir.const #cir.int<124> : !u64i +// CIR: cir.store {{.*}} %[[CONST_124]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_248:.*]] = cir.const #cir.int<248> : !u64i +// CIR: cir.store {{.*}} %[[CONST_248]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[CONST_376:.*]] = cir.const #cir.int<376> : !u64i +// CIR: cir.store {{.*}} %[[CONST_376]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i> + +// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 0, ptr %[[A_ADDR]], align 8 +// LLVM: store i64 124, ptr %[[B_ADDR]], align 8 +// LLVM: store i64 248, ptr %[[C_ADDR]], align 8 +// LLVM: store i64 376, ptr %[[D_ADDR]], align 8 + +// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 0, ptr %[[A_ADDR]], align 8 +// OGCG: store i64 124, ptr %[[B_ADDR]], align 8 +// OGCG: store i64 248, ptr %[[C_ADDR]], align 8 +// OGCG: store i64 376, ptr %[[D_ADDR]], align 8 diff --git a/clang/test/CIR/CodeGen/paren-init-list.cpp b/clang/test/CIR/CodeGen/paren-init-list.cpp index 0efa363..a5676e2 100644 --- a/clang/test/CIR/CodeGen/paren-init-list.cpp +++ b/clang/test/CIR/CodeGen/paren-init-list.cpp @@ -13,18 +13,11 @@ struct CompleteS { void cxx_paren_list_init_expr() { CompleteS a(1, 'a'); } // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] -// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> -// CIR: %[[ELEM_0_VAL:.*]] = cir.const #cir.int<1> : !s32i -// CIR: cir.store{{.*}} %[[ELEM_0_VAL]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[ELEM_1_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i> -// CIR: %[[ELEM_1_VAL:.*]] = cir.const #cir.int<97> : !s8i -// CIR: cir.store{{.*}} %[[ELEM_1_VAL]], %[[ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i> +// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<97> : !s8i}> : !rec_CompleteS +// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] // LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 -// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0 -// LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4 -// LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1 -// LLVM: store i8 97, ptr %[[ELEM_1_PTR]], align 4 +// LLVM: store %struct.CompleteS { i32 1, i8 97 }, ptr %[[A_ADDR]], align 4 // OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[A_ADDR]], ptr align 4 @__const._Z24cxx_paren_list_init_exprv.a, i64 8, i1 false) diff --git a/clang/test/CIR/CodeGen/placement-new.cpp b/clang/test/CIR/CodeGen/placement-new.cpp new file mode 100644 index 0000000..ccc3548 --- /dev/null +++ b/clang/test/CIR/CodeGen/placement-new.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-cir -o %t.cir +// RUN: FileCheck --input-file=%t.cir -check-prefix=CIR %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-llvm -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll -check-prefix=LLVM %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o %t.ll +// RUN: FileCheck --input-file=%t.ll -check-prefix=OGCG %s + +typedef __typeof__(sizeof(0)) size_t; + +// Declare the reserved placement operators. +void *operator new(size_t, void*) throw(); + +struct A { A(); ~A(); }; + +void test_reserved_placement_new(void *p) { + new (p) A(); +} + +// CIR-LABEL: cir.func {{.*}} @_Z27test_reserved_placement_newPv( +// CIR-SAME: %[[ARG0:.*]]: !cir.ptr<!void> +// CIR: %[[P:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["p", init] +// CIR: cir.store %[[ARG0]], %[[P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> +// CIR: %[[SIZE:.*]] = cir.const #cir.int<1> : !u64i +// CIR: %[[PTR:.*]] = cir.load{{.*}} %[[P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> +// CIR: %[[PTR_A:.*]] = cir.cast bitcast %[[PTR]] : !cir.ptr<!void> -> !cir.ptr<!rec_A> +// CIR: cir.call @_ZN1AC1Ev(%[[PTR_A]]) : (!cir.ptr<!rec_A>) -> () + +// LLVM-LABEL: define dso_local void @_Z27test_reserved_placement_newPv( +// LLVM-SAME: ptr %[[ARG0:.*]] +// LLVM: %[[P:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0:.*]], ptr %[[P]] +// LLVM: %[[PTR:.*]] = load ptr, ptr %[[P]] +// LLVM: call void @_ZN1AC1Ev(ptr %[[PTR]]) + +// OGCG-LABEL: define dso_local void @_Z27test_reserved_placement_newPv( +// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]] +// OGCG: %[[P:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0:.*]], ptr %[[P]] +// OGCG: %[[PTR:.*]] = load ptr, ptr %[[P]] +// OGCG: call void @_ZN1AC1Ev(ptr {{.*}} %[[PTR]]) diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp new file mode 100644 index 0000000..b116d21 --- /dev/null +++ b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -Wno-unused-value -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 -std=c++17 -fclangir -Wno-unused-value -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 -std=c++17 -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct Point { + int x; + int y; + int z; +}; + +auto test1() -> int Point::* { + return &Point::y; +} + +// CIR: cir.func {{.*}} @_Z5test1v() -> !cir.data_member<!s32i in !rec_Point> { +// CIR: %[[RETVAL:.*]] = cir.alloca !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, ["__retval"] +// CIR: %[[MEMBER:.*]] = cir.const #cir.data_member<1> : !cir.data_member<!s32i in !rec_Point> +// CIR: cir.store %[[MEMBER]], %[[RETVAL]] : !cir.data_member<!s32i in !rec_Point>, !cir.ptr<!cir.data_member<!s32i in !rec_Point>> +// CIR: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.data_member<!s32i in !rec_Point>>, !cir.data_member<!s32i in !rec_Point> +// CIR: cir.return %[[RET]] : !cir.data_member<!s32i in !rec_Point> + +// LLVM: define {{.*}} i64 @_Z5test1v() +// LLVM: %[[RETVAL:.*]] = alloca i64 +// LLVM: store i64 4, ptr %[[RETVAL]] +// LLVM: %[[RET:.*]] = load i64, ptr %[[RETVAL]] +// LLVM: ret i64 %[[RET]] + +// OGCG: define {{.*}} i64 @_Z5test1v() +// OGCG: ret i64 4 diff --git a/clang/test/CIR/CodeGen/ptrdiff.cpp b/clang/test/CIR/CodeGen/ptrdiff.cpp index 34ba0ff..5805349 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.cpp +++ b/clang/test/CIR/CodeGen/ptrdiff.cpp @@ -8,7 +8,7 @@ typedef unsigned long size_type; size_type size(unsigned long *_start, unsigned long *_finish) { - // CIR-LABEL: cir.func dso_local @_Z4sizePmS_ + // CIR-LABEL: cir.func {{.*}} @_Z4sizePmS_ // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr<!u64i> -> !s64i // CIR: %[[U:.*]] = cir.cast integral %[[D]] : !s64i -> !u64i // CIR: cir.return {{.*}} : !u64i diff --git a/clang/test/CIR/CodeGen/record-zero-init-padding.c b/clang/test/CIR/CodeGen/record-zero-init-padding.c index f131c9b..9c8dacc 100644 --- a/clang/test/CIR/CodeGen/record-zero-init-padding.c +++ b/clang/test/CIR/CodeGen/record-zero-init-padding.c @@ -41,28 +41,28 @@ void test_zero_init_padding(void) { // CIR-DAG: !rec_anon_struct3 = !cir.record<struct {!s8i, !cir.array<!u8i x 3>, !s32i}> // paf: char + 3 bytes padding + int -> uses !rec_anon_struct3 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.paf = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.paf = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<1> : !s8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3>, // CIR-DAG-SAME: #cir.int<42> : !s32i // CIR-DAG-SAME: }> : !rec_anon_struct3 // bfp: unsigned bitfield byte + 3 bytes padding + int -> uses !rec_anon_struct2 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.bfp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.bfp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<17> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3>, // CIR-DAG-SAME: #cir.int<99> : !s32i // CIR-DAG-SAME: }> : !rec_anon_struct2 // tp: int + char + 3 bytes tail padding -> uses !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.tp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.tp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<10> : !s32i, // CIR-DAG-SAME: #cir.int<20> : !s8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array<!u8i x 3> // CIR-DAG-SAME: }> : !rec_anon_struct1 // mp: char + 1 byte padding + short + 4 bytes padding + long long -> uses !rec_anon_struct -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.mp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.mp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<5> : !s8i, // CIR-DAG-SAME: #cir.zero : !u8i, // CIR-DAG-SAME: #cir.int<10> : !s16i, @@ -73,10 +73,10 @@ void test_zero_init_padding(void) { // CIR-LABEL: cir.func {{.*}}@test_zero_init_padding // CIR: cir.return -// LLVM-DAG: @test_zero_init_padding.paf = internal global { i8, [3 x i8], i32 } { i8 1, [3 x i8] zeroinitializer, i32 42 } -// LLVM-DAG: @test_zero_init_padding.bfp = internal global { i8, [3 x i8], i32 } { i8 17, [3 x i8] zeroinitializer, i32 99 } -// LLVM-DAG: @test_zero_init_padding.tp = internal global { i32, i8, [3 x i8] } { i32 10, i8 20, [3 x i8] zeroinitializer } -// LLVM-DAG: @test_zero_init_padding.mp = internal global { i8, i8, i16, [4 x i8], i64 } { i8 5, i8 0, i16 10, [4 x i8] zeroinitializer, i64 100 } +// LLVM-DAG: @test_zero_init_padding.paf = internal constant { i8, [3 x i8], i32 } { i8 1, [3 x i8] zeroinitializer, i32 42 } +// LLVM-DAG: @test_zero_init_padding.bfp = internal constant { i8, [3 x i8], i32 } { i8 17, [3 x i8] zeroinitializer, i32 99 } +// LLVM-DAG: @test_zero_init_padding.tp = internal constant { i32, i8, [3 x i8] } { i32 10, i8 20, [3 x i8] zeroinitializer } +// LLVM-DAG: @test_zero_init_padding.mp = internal constant { i8, i8, i16, [4 x i8], i64 } { i8 5, i8 0, i16 10, [4 x i8] zeroinitializer, i64 100 } // LLVM-LABEL: define{{.*}} void @test_zero_init_padding // LLVM: ret void diff --git a/clang/test/CIR/CodeGen/size-of-vla.cpp b/clang/test/CIR/CodeGen/size-of-vla.cpp new file mode 100644 index 0000000..bcaab27 --- /dev/null +++ b/clang/test/CIR/CodeGen/size-of-vla.cpp @@ -0,0 +1,156 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -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 -Wno-unused-value -fclangir -emit-llvm %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 -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void vla_type_with_element_type_of_size_1() { + unsigned long n = 10ul; + unsigned long size = sizeof(bool[n]); +} + +// CIR: %[[N_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["size", init] +// CIR: %[[CONST_10:.*]] = cir.const #cir.int<10> : !u64i +// CIR: cir.store {{.*}} %[[CONST_10]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_N:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: cir.store {{.*}} %[[TMP_N]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i> + +// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 10, ptr %[[N_ADDR]], align 8 +// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// LLVM: store i64 %[[TMP_N]], ptr %[[SIZE_ADDR]], align 8 + +// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 10, ptr %[[N_ADDR]], align 8 +// OGCG: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// OGCG: store i64 %[[TMP_N]], ptr %[[SIZE_ADDR]], align 8 + +void vla_type_with_element_type_int() { + unsigned long n = 10ul; + unsigned long size = sizeof(int[n]); +} + +// CIR: %[[N_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["size", init] +// CIR: %[[CONST_10:.*]] = cir.const #cir.int<10> : !u64i +// CIR: cir.store {{.*}} %[[CONST_10]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %3 = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i +// CIR: %[[SIZE:.*]] = cir.binop(mul, %[[CONST_4]], %3) nuw : !u64i +// CIR: cir.store {{.*}} %[[SIZE]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i> + +// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 10, ptr %[[N_ADDR]], align 8 +// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// LLVM: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]] +// LLVM: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8 + +// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 10, ptr %[[N_ADDR]], align 8 +// OGCG: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// OGCG: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]] +// OGCG: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8 + +void vla_expr_element_type_of_size_1() { + unsigned long n = 10ul; + bool arr[n]; + unsigned long size = sizeof(arr); +} + +// CIR: %[[N_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] +// CIR: %[[SAVED_STACK_ADDR:.*]] = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>, ["saved_stack"] +// CIR: %[[CONST_10:.*]] = cir.const #cir.int<10> : !u64i +// CIR: cir.store {{.*}} %[[CONST_10]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_N:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: %[[STACK_SAVE:.*]] = cir.stacksave : !cir.ptr<!u8i> +// CIR: cir.store {{.*}} %[[STACK_SAVE]], %[[SAVED_STACK_ADDR]] : !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>> +// CIR: %[[ARR_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, %[[TMP_N]] : !u64i, ["arr"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["size", init] +// CIR: cir.store {{.*}} %[[TMP_N]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_SAVED_STACK:.*]] = cir.load {{.*}} %[[SAVED_STACK_ADDR]] : !cir.ptr<!cir.ptr<!u8i>>, !cir.ptr<!u8i> +// CIR: cir.stackrestore %[[TMP_SAVED_STACK]] : !cir.ptr<!u8i> + +// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SAVED_STACK_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: store i64 10, ptr %[[N_ADDR]], align 8 +// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// LLVM: %[[STACK_SAVE:.*]] = call ptr @llvm.stacksave.p0() +// LLVM: store ptr %[[STACK_SAVE]], ptr %[[SAVED_STACK_ADDR]], align 8 +// LLVM: %[[ARR_ADDR:.*]] = alloca i8, i64 %[[TMP_N]], align 16 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 %[[TMP_N]], ptr %[[SIZE_ADDR]], align 8 +// LLVM: %[[TMP_SAVED_STACK:.*]] = load ptr, ptr %[[SAVED_STACK_ADDR]], align 8 +// LLVM: call void @llvm.stackrestore.p0(ptr %[[TMP_SAVED_STACK]]) + +// Note: VLA_EXPR0 below is emitted to capture debug info. + +// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[SAVED_STACK_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %[[VLA_EXPR0:.*]] = alloca i64, align 8 +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 10, ptr %[[N_ADDR]], align 8 +// OGCG: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// OGCG: %[[STACK_SAVE:.*]] = call ptr @llvm.stacksave.p0() +// OGCG: store ptr %[[STACK_SAVE]], ptr %[[SAVED_STACK_ADDR]], align 8 +// OGCG: %[[ARR_ADDR:.*]] = alloca i8, i64 %[[TMP_N]], align 16 +// OGCG: store i64 %[[TMP_N]], ptr %[[VLA_EXPR0]], align 8 +// OGCG: store i64 %[[TMP_N]], ptr %[[SIZE_ADDR]], align 8 +// OGCG: %[[TMP_SAVED_STACK:.*]] = load ptr, ptr %[[SAVED_STACK_ADDR]], align 8 +// OGCG: call void @llvm.stackrestore.p0(ptr %[[TMP_SAVED_STACK]]) + +void vla_expr_element_type_int() { + unsigned long n = 10ul; + int arr[n]; + unsigned long size = sizeof(arr); +} + +// CIR: %[[N_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init] +// CIR: %[[SAVED_STACK_ADDR:.*]] = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>, ["saved_stack"] +// CIR: %[[CONST_10:.*]] = cir.const #cir.int<10> : !u64i +// CIR: cir.store {{.*}} %[[CONST_10]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_N:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i +// CIR: %[[STACK_SAVE:.*]] = cir.stacksave : !cir.ptr<!u8i> +// CIR: cir.store {{.*}} %[[STACK_SAVE]], %[[SAVED_STACK_ADDR]] : !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>> +// CIR: %[[ARR_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, %[[TMP_N]] : !u64i, ["arr"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["size", init] +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i +// CIR: %[[SIZE:.*]] = cir.binop(mul, %[[CONST_4]], %[[TMP_N]]) nuw : !u64i +// CIR: cir.store {{.*}} %[[SIZE]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i> +// CIR: %[[TMP_SAVED_STACK:.*]] = cir.load {{.*}} %[[SAVED_STACK_ADDR]] : !cir.ptr<!cir.ptr<!u8i>>, !cir.ptr<!u8i> +// CIR: cir.stackrestore %[[TMP_SAVED_STACK]] : !cir.ptr<!u8i> + +// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SAVED_STACK_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: store i64 10, ptr %[[N_ADDR]], align 8 +// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// LLVM: %[[STACK_SAVE:.*]] = call ptr @llvm.stacksave.p0() +// LLVM: store ptr %[[STACK_SAVE]], ptr %[[SAVED_STACK_ADDR]], align 8 +// LLVM: %[[ARR_ADDR:.*]] = alloca i32, i64 %[[TMP_N]], align 16 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]] +// LLVM: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8 +// LLVM: %[[TMP_SAVED_STACK:.*]] = load ptr, ptr %[[SAVED_STACK_ADDR]], align 8 +// LLVM: call void @llvm.stackrestore.p0(ptr %[[TMP_SAVED_STACK]]) + +// Note: VLA_EXPR0 below is emitted to capture debug info. + +// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[SAVED_STACK_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %[[VLA_EXPR0:.*]] = alloca i64, align 8 +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: store i64 10, ptr %[[N_ADDR]], align 8 +// OGCG: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8 +// OGCG: %[[STACK_SAVE:.*]] = call ptr @llvm.stacksave.p0() +// OGCG: store ptr %[[STACK_SAVE]], ptr %[[SAVED_STACK_ADDR]], align 8 +// OGCG: %[[ARR_ADDR:.*]] = alloca i32, i64 %[[TMP_N]], align 16 +// OGCG: store i64 %[[TMP_N]], ptr %[[VLA_EXPR0]], align 8 +// OGCG: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]] +// OGCG: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8 +// OGCG: %[[TMP_SAVED_STACK:.*]] = load ptr, ptr %[[SAVED_STACK_ADDR]], align 8 +// OGCG: call void @llvm.stackrestore.p0(ptr %[[TMP_SAVED_STACK]]) diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c index c784ec9..2ea4672 100644 --- a/clang/test/CIR/CodeGen/statement-exprs.c +++ b/clang/test/CIR/CodeGen/statement-exprs.c @@ -6,10 +6,10 @@ // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG int f19(void) { - return ({ 3;;4;; }); + return ({ 3;;4; }); } -// CIR: cir.func dso_local @f19() -> !s32i +// CIR: cir.func {{.*}} @f19() -> !s32i // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: %[[TMP:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] // CIR: cir.scope { @@ -42,6 +42,16 @@ int f19(void) { // OGCG: %[[TMP_VAL:.+]] = load i32, ptr %[[TMP]] // OGCG: ret i32 %[[TMP_VAL]] +// PR166036: The trailing NullStmt should result in a void. +void f20(void) { + return ({ 3;;4;; }); +} + +// CIR-LABEL: cir.func {{.*}} @f20() {{[^-]*}} +// CIR: cir.return {{[^%]*}} + +// LLVM-LABEL: define{{.*}} void @f20 +// LLVM: ret void int nested(void) { ({123;}); @@ -51,7 +61,7 @@ int nested(void) { } } -// CIR: cir.func dso_local @nested() -> !s32i +// CIR: cir.func {{.*}} @nested() -> !s32i // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: %[[TMP_OUTER:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] // CIR: cir.scope { @@ -154,7 +164,7 @@ void empty() { return ({;;;;}); } -// CIR: cir.func no_proto dso_local @empty() +// CIR: cir.func {{.*}} @empty() // CIR-NEXT: cir.return // LLVM: define dso_local void @empty() @@ -167,7 +177,7 @@ void empty() { void empty2() { ({ }); } -// CIR: @empty2 +// CIR: cir.func {{.*}} @empty2 // CIR-NEXT: cir.return // LLVM: @empty2() @@ -181,7 +191,7 @@ void empty2() { ({ }); } // Yields an out-of-scope scalar. void test2() { ({int x = 3; x; }); } -// CIR: @test2 +// CIR: cir.func {{.*}} @test2 // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i> // CIR: cir.scope { // CIR: %[[VAR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] @@ -216,16 +226,15 @@ void test2() { ({int x = 3; x; }); } // Yields an aggregate. struct S { int x; }; int test3() { return ({ struct S s = {1}; s; }).x; } -// CIR: cir.func no_proto dso_local @test3() -> !s32i +// CIR: cir.func {{.*}} @test3() -> !s32i // CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // 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 { // CIR: %[[S:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] -// CIR: %[[GEP_X_S:.+]] = cir.get_member %[[S]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i> -// CIR: %[[C1:.+]] = cir.const #cir.int<1> : !s32i -// CIR: cir.store {{.*}} %[[C1]], %[[GEP_X_S]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i}> : !rec_S +// CIR: cir.store{{.*}} %[[CONST]], %[[S]] : !rec_S, !cir.ptr<!rec_S> // CIR: cir.copy %[[S]] to %[[REF_TMP0]] : !cir.ptr<!rec_S> // CIR: } // CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i> @@ -244,8 +253,7 @@ int test3() { return ({ struct S s = {1}; s; }).x; } // LLVM: [[LBL5]]: // LLVM: br label %[[LBL6:.+]] // LLVM: [[LBL6]]: -// LLVM: %[[GEP_S:.+]] = getelementptr %struct.S, ptr %[[VAR3]], i32 0, i32 0 -// LLVM: store i32 1, ptr %[[GEP_S]] +// LLVM: store %struct.S { i32 1 }, ptr %[[VAR3]] // LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[VAR1]], ptr %[[VAR3]], i32 4, i1 false) // LLVM: br label %[[LBL8:.+]] // LLVM: [[LBL8]]: @@ -269,6 +277,6 @@ int test3() { return ({ struct S s = {1}; s; }).x; } // Expression is wrapped in an expression attribute (just ensure it does not crash). void test4(int x) { ({[[gsl::suppress("foo")]] x;}); } -// CIR: @test4 +// CIR: cir.func {{.*}} @test4 // LLVM: @test4 // OGCG: @test4 diff --git a/clang/test/CIR/CodeGen/static-members.cpp b/clang/test/CIR/CodeGen/static-members.cpp new file mode 100644 index 0000000..8722dc2 --- /dev/null +++ b/clang/test/CIR/CodeGen/static-members.cpp @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck %s -check-prefix=CIR --input-file=%t.cir +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck %s -check-prefix=LLVM --input-file=%t-cir.ll +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck %s -check-prefix=OGCG --input-file=%t.ll + +struct HasDtor { + ~HasDtor(); +}; +struct S { + static inline HasDtor hd; +}; + +// CIR: cir.global linkonce_odr comdat @_ZN1S2hdE = #cir.zero : !rec_HasDtor + +// CIR: cir.func internal private @__cxx_global_var_init() { +// CIR: %[[HD:.*]] = cir.get_global @_ZN1S2hdE : !cir.ptr<!rec_HasDtor> +// CIR: %[[DTOR:.*]] = cir.get_global @_ZN7HasDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_HasDtor>)>> +// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!rec_HasDtor>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[HD_CAST:.*]] = cir.cast bitcast %[[HD]] : !cir.ptr<!rec_HasDtor> -> !cir.ptr<!void> +// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[HD_CAST]], %[[HANDLE]]) + +// LLVM: @_ZN1S2hdE = linkonce_odr global %struct.HasDtor zeroinitializer, comdat +// LLVM: @_ZN5Outer5Inner2hdE = linkonce_odr global %struct.HasDtor zeroinitializer, comdat + +// LLVM: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_static_members.cpp, ptr null }] +// LLVM: define internal void @__cxx_global_var_init() +// LLVM: call void @__cxa_atexit(ptr @_ZN7HasDtorD1Ev, ptr @_ZN1S2hdE, ptr @__dso_handle) + +// FIXME(cir): OGCG has a guard variable for this case that we don't generate in CIR. +// This is needed because the variable linkonce_odr linkage. + +// OGCG: @_ZN1S2hdE = linkonce_odr global %struct.HasDtor zeroinitializer, comdat +// OGCG: @_ZGVN1S2hdE = linkonce_odr global i64 0, comdat($_ZN1S2hdE) +// OGCG: @_ZN5Outer5Inner2hdE = linkonce_odr global %struct.HasDtor zeroinitializer, comdat +// OGCG: @_ZGVN5Outer5Inner2hdE = linkonce_odr global i64 0, comdat($_ZN5Outer5Inner2hdE) +// OGCG: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [ +// OGCG-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init, ptr @_ZN1S2hdE }, +// OGCG-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.1, ptr @_ZN5Outer5Inner2hdE }] + +// OGCG: define internal void @__cxx_global_var_init() {{.*}} section ".text.startup" comdat($_ZN1S2hdE) { +// OGCG: %[[GUARD:.*]] = load atomic i8, ptr @_ZGVN1S2hdE acquire +// OGCG: %[[UNINIT:.*]] = icmp eq i8 %[[GUARD]], 0 +// OGCG: br i1 %[[UNINIT]], label %[[INIT_CHECK:.*]], label %[[INIT_END:.*]] +// OGCG: [[INIT_CHECK:.*]]: +// OGCG: %[[GUARD_ACQUIRE:.*]] = call i32 @__cxa_guard_acquire(ptr @_ZGVN1S2hdE) +// OGCG: %[[TOBOOL:.*]] = icmp ne i32 %[[GUARD_ACQUIRE]], 0 +// OGCG: br i1 %[[TOBOOL]], label %[[INIT:.*]], label %[[INIT_END]] +// OGCG: [[INIT:.*]]: +// OGCG: %[[ATEXIT:.*]] = call i32 @__cxa_atexit(ptr @_ZN7HasDtorD1Ev, ptr @_ZN1S2hdE, ptr @__dso_handle) +// OGCG: call void @__cxa_guard_release(ptr @_ZGVN1S2hdE) +// OGCG: br label %[[INIT_END]] +// OGCG: [[INIT_END]]: + +struct Outer { + struct Inner { + static inline HasDtor hd; + }; +}; + +// CIR: cir.global linkonce_odr comdat @_ZN5Outer5Inner2hdE = #cir.zero : !rec_HasDtor +// CIR: cir.func internal private @__cxx_global_var_init.1() +// CIR: %[[HD:.*]] = cir.get_global @_ZN5Outer5Inner2hdE : !cir.ptr<!rec_HasDtor> +// CIR: %[[DTOR:.*]] = cir.get_global @_ZN7HasDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_HasDtor>)>> +// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!rec_HasDtor>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR: %[[HD_CAST:.*]] = cir.cast bitcast %[[HD]] : !cir.ptr<!rec_HasDtor> -> !cir.ptr<!void> +// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[HD_CAST]], %[[HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>) -> () + +// LLVM: define internal void @__cxx_global_var_init.1() +// LLVM: call void @__cxa_atexit(ptr @_ZN7HasDtorD1Ev, ptr @_ZN5Outer5Inner2hdE, ptr @__dso_handle) + +// OGCG: define internal void @__cxx_global_var_init.1() {{.*}} section ".text.startup" comdat($_ZN5Outer5Inner2hdE) { +// OGCG: %[[GUARD:.*]] = load atomic i8, ptr @_ZGVN5Outer5Inner2hdE acquire +// OGCG: %[[UNINIT:.*]] = icmp eq i8 %[[GUARD]], 0 +// OGCG: br i1 %[[UNINIT]], label %[[INIT_CHECK:.*]], label %[[INIT_END:.*]] +// OGCG: [[INIT_CHECK:.*]]: +// OGCG: %[[GUARD_ACQUIRE:.*]] = call i32 @__cxa_guard_acquire(ptr @_ZGVN5Outer5Inner2hdE) +// OGCG: %[[TOBOOL:.*]] = icmp ne i32 %[[GUARD_ACQUIRE]], 0 +// OGCG: br i1 %[[TOBOOL]], label %[[INIT:.*]], label %[[INIT_END]] +// OGCG: [[INIT:.*]]: +// OGCG: %[[ATEXIT:.*]] = call i32 @__cxa_atexit(ptr @_ZN7HasDtorD1Ev, ptr @_ZN5Outer5Inner2hdE, ptr @__dso_handle) +// OGCG: call void @__cxa_guard_release(ptr @_ZGVN5Outer5Inner2hdE) +// OGCG: br label %[[INIT_END]] +// OGCG: [[INIT_END]]: + + +// CIR: cir.func private @_GLOBAL__sub_I_static_members.cpp() +// CIR: cir.call @__cxx_global_var_init() + +// LLVM: define void @_GLOBAL__sub_I_static_members.cpp() +// LLVM: call void @__cxx_global_var_init() diff --git a/clang/test/CIR/CodeGen/stmt-expr.cpp b/clang/test/CIR/CodeGen/stmt-expr.cpp index 9e3911f..b645b15 100644 --- a/clang/test/CIR/CodeGen/stmt-expr.cpp +++ b/clang/test/CIR/CodeGen/stmt-expr.cpp @@ -20,7 +20,7 @@ void test1() { }).Foo(); } -// CIR: cir.func dso_local @_Z5test1v() +// CIR: cir.func {{.*}} @_Z5test1v() // CIR: cir.scope { // CIR: %[[REF_TMP0:.+]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["ref.tmp0"] // CIR: %[[TMP:.+]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["tmp"] @@ -67,7 +67,7 @@ void cleanup() { ({ with_dtor wd; }); } -// CIR: cir.func dso_local @_Z7cleanupv() +// CIR: cir.func {{.*}} @_Z7cleanupv() // CIR: cir.scope { // CIR: %[[WD:.+]] = cir.alloca !rec_with_dtor, !cir.ptr<!rec_with_dtor>, ["wd"] // CIR: cir.call @_ZN9with_dtorD1Ev(%[[WD]]) nothrow : (!cir.ptr<!rec_with_dtor>) -> () @@ -88,3 +88,46 @@ void cleanup() { // OGCG: %[[WD:.+]] = alloca %struct.with_dtor // OGCG: call void @_ZN9with_dtorD1Ev(ptr {{.*}} %[[WD]]) // OGCG: ret void + +void gnu_statement_extension() { + float b = __real__ ({float _Complex a; a;}); +} + +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] +// CIR: %[[TMP_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: cir.store {{.*}} %[[TMP_A]], %[[TMP_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: } +// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[TMP_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!cir.float> -> !cir.float +// CIR: cir.store {{.*}} %[[REAL]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM: %[[TMP_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: br label %[[LABEL_1:.*]] +// LLVM: [[LABEL_1]]: +// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: store { float, float } %[[TMP_A]], ptr %[[TMP_ADDR]], align 4 +// LLVM: br label %[[LABEL_2:.*]] +// LLVM: [[LABEL_2]]: +// LLVM: %[[TMP:.*]] = load { float, float }, ptr %[[TMP_ADDR]], align 4 +// LLVM: %[[REAL:.*]] = extractvalue { float, float } %[[TMP]], 0 +// LLVM: store float %[[REAL]], ptr %[[B_ADDR]], align 4 + +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[TMP_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[TMP_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[TMP_ADDR]], i32 0, i32 0 +// OGCG: %[[TMP_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[TMP_ADDR]], i32 0, i32 1 +// OGCG: store float %[[A_REAL]], ptr %[[TMP_REAL_PTR]], align 4 +// OGCG: store float %[[A_IMAG]], ptr %[[TMP_IMAG_PTR]], align 4 +// OGCG: %[[TMP_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[TMP_ADDR]], i32 0, i32 0 +// OGCG: %[[TMP_REAL:.*]] = load float, ptr %[[TMP_REAL_PTR]], align 4 +// OGCG: store float %[[TMP_REAL]], ptr %[[B_ADDR]], align 4 diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp index 7988619..f5c013a 100644 --- a/clang/test/CIR/CodeGen/struct-init.cpp +++ b/clang/test/CIR/CodeGen/struct-init.cpp @@ -65,41 +65,16 @@ void init() { // CIR: cir.func{{.*}} @_Z4initv() // CIR: %[[S1:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s1", init] // CIR: %[[S2:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s2", init] -// CIR: %[[S1_A:.*]] = cir.get_member %[[S1]][0] {name = "a"} -// CIR: %[[ONE:.*]] = cir.const #cir.int<1> -// CIR: cir.store{{.*}} %[[ONE]], %[[S1_A]] -// CIR: %[[S1_B:.*]] = cir.get_member %[[S1]][1] {name = "b"} -// CIR: %[[TWO:.*]] = cir.const #cir.int<2> -// CIR: cir.store{{.*}} %[[TWO]], %[[S1_B]] -// CIR: %[[S1_C:.*]] = cir.get_member %[[S1]][2] {name = "c"} -// CIR: %[[THREE:.*]] = cir.const #cir.int<3> -// CIR: cir.store{{.*}} %[[THREE]], %[[S1_C]] -// CIR: %[[S2_A:.*]] = cir.get_member %[[S2]][0] {name = "a"} -// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> -// CIR: cir.store{{.*}} %[[FOUR]], %[[S2_A]] -// CIR: %[[S2_B:.*]] = cir.get_member %[[S2]][1] {name = "b"} -// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> -// CIR: cir.store{{.*}} %[[FIVE]], %[[S2_B]] -// CIR: %[[S2_C:.*]] = cir.get_member %[[S2]][2] {name = "c"} -// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> -// CIR: cir.store{{.*}} %[[ZERO]], %[[S2_C]] -// CIR: cir.return +// CIR: %[[CONST_1:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i}> : !rec_S +// CIR: cir.store{{.*}} %[[CONST_1]], %[[S1]] +// CIR: %[[CONST_2:.*]] = cir.const #cir.const_record<{#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<0> : !s32i}> : !rec_S +// CIR: cir.store{{.*}} %[[CONST_2]], %[[S2]] // LLVM: define{{.*}} void @_Z4initv() // LLVM: %[[S1:.*]] = alloca %struct.S // LLVM: %[[S2:.*]] = alloca %struct.S -// LLVM: %[[S1_A:.*]] = getelementptr %struct.S, ptr %[[S1]], i32 0, i32 0 -// LLVM: store i32 1, ptr %[[S1_A]] -// LLVM: %[[S1_B:.*]] = getelementptr %struct.S, ptr %[[S1]], i32 0, i32 1 -// LLVM: store i32 2, ptr %[[S1_B]] -// LLVM: %[[S1_C:.*]] = getelementptr %struct.S, ptr %[[S1]], i32 0, i32 2 -// LLVM: store i32 3, ptr %[[S1_C]] -// LLVM: %[[S2_A:.*]] = getelementptr %struct.S, ptr %[[S2]], i32 0, i32 0 -// LLVM: store i32 4, ptr %[[S2_A]] -// LLVM: %[[S2_B:.*]] = getelementptr %struct.S, ptr %[[S2]], i32 0, i32 1 -// LLVM: store i32 5, ptr %[[S2_B]] -// LLVM: %[[S2_C:.*]] = getelementptr %struct.S, ptr %[[S2]], i32 0, i32 2 -// LLVM: store i32 0, ptr %[[S2_C]] +// LLVM: store %struct.S { i32 1, i32 2, i32 3 }, ptr %[[S1]], align 4 +// LLVM: store %struct.S { i32 4, i32 5, i32 0 }, ptr %[[S2]], align 4 // OGCG: @__const._Z4initv.s1 = private unnamed_addr constant %struct.S { i32 1, i32 2, i32 3 } // OGCG: @__const._Z4initv.s2 = private unnamed_addr constant %struct.S { i32 4, i32 5, i32 0 } @@ -230,3 +205,26 @@ void init_expr(int a, int b, int c) { // OGCG: %[[C_PLUS_THREE:.*]] = add nsw i32 %[[C]], 3 // OGCG: store i32 %[[C_PLUS_THREE]], ptr %[[S_C]] // OGCG: ret void + +void cxx_default_init_with_struct_field() { + struct Parent { + int getA(); + int a = getA(); + }; + Parent p = Parent{}; +} + +// CIR: %[[P_ADDR:.*]] = cir.alloca !rec_Parent, !cir.ptr<!rec_Parent>, ["p", init] +// CIR: %[[P_ELEM_0_PTR:.*]] = cir.get_member %[[P_ADDR]][0] {name = "a"} : !cir.ptr<!rec_Parent> -> !cir.ptr<!s32i> +// CIR: %[[METHOD_CALL:.*]] = cir.call @_ZZ34cxx_default_init_with_struct_fieldvEN6Parent4getAEv(%[[P_ADDR]]) : (!cir.ptr<!rec_Parent>) -> !s32i +// CIR: cir.store{{.*}} %[[METHOD_CALL]], %[[P_ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[P_ADDR:.*]] = alloca %struct.Parent, i64 1, align 4 +// LLVM: %[[P_ELEM_0_PTR:.*]] = getelementptr %struct.Parent, ptr %[[P_ADDR]], i32 0, i32 0 +// LLVM: %[[METHOD_CALL:.*]] = call i32 @_ZZ34cxx_default_init_with_struct_fieldvEN6Parent4getAEv(ptr %[[P_ADDR]]) +// LLVM: store i32 %[[METHOD_CALL]], ptr %[[P_ELEM_0_PTR]], align 4 + +// OGCG: %[[P_ADDR:.*]] = alloca %struct.Parent, align 4 +// OGCG: %[[P_ELEM_0_PTR:.*]] = getelementptr inbounds nuw %struct.Parent, ptr %[[P_ADDR]], i32 0, i32 0 +// OGCG: %[[METHOD_CALL:.*]] = call noundef i32 @_ZZ34cxx_default_init_with_struct_fieldvEN6Parent4getAEv(ptr {{.*}} %[[P_ADDR]]) +// OGCG: store i32 %[[METHOD_CALL]], ptr %[[P_ELEM_0_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/struct.cpp b/clang/test/CIR/CodeGen/struct.cpp index c8db714..dc3e241 100644 --- a/clang/test/CIR/CodeGen/struct.cpp +++ b/clang/test/CIR/CodeGen/struct.cpp @@ -107,22 +107,15 @@ void paren_expr() { // CIR: cir.func{{.*}} @_Z10paren_exprv() // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["a", init] // CIR: %[[B_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["b", init] -// CIR: %[[X_ELEM_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "x"} : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i> -// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i -// CIR: cir.store{{.*}} %[[CONST_0]], %[[X_ELEM_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[Y_ELEM_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "y"} : !cir.ptr<!rec_Point> -> !cir.ptr<!s32i> -// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i -// CIR: cir.store{{.*}} %[[CONST_0]], %[[Y_ELEM_PTR]] : !s32i, !cir.ptr<!s32i> -// CIR: cir.call @_ZZ10paren_exprvEN5PointC1ERKS_(%[[B_ADDR]], %[[A_ADDR]]) nothrow : (!cir.ptr<!rec_Point>, !cir.ptr<!rec_Point>) -> () +// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_Point +// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_Point, !cir.ptr<!rec_Point> +// CIR: cir.copy %[[A_ADDR]] to %[[B_ADDR]] : !cir.ptr<!rec_Point> // LLVM: define{{.*}} void @_Z10paren_exprv() // LLVM: %[[A_ADDR:.*]] = alloca %struct.Point, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca %struct.Point, i64 1, align 4 -// LLVM: %[[X_ELEM_PTR:.*]] = getelementptr %struct.Point, ptr %[[A_ADDR]], i32 0, i32 0 -// LLVM: store i32 0, ptr %[[X_ELEM_PTR]], align 4 -// LLVM: %[[Y_ELEM_PTR:.*]] = getelementptr %struct.Point, ptr %[[A_ADDR]], i32 0, i32 1 -// LLVM: store i32 0, ptr %[[Y_ELEM_PTR]], align 4 -// LLVM: call void @_ZZ10paren_exprvEN5PointC1ERKS_(ptr %[[B_ADDR]], ptr %[[A_ADDR]]) +// LLVM: store %struct.Point zeroinitializer, ptr %[[A_ADDR]], align 4 +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[B_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false) // OGCG: define{{.*}} void @_Z10paren_exprv() // OGCG: %[[A_ADDR:.*]] = alloca %struct.Point, align 4 @@ -140,14 +133,13 @@ void choose_expr() { // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["b"] // CIR: %[[C_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["c", init] -// TODO(cir): Call to default copy constructor should be replaced by `cir.copy` op -// CIR: cir.call @_ZN9CompleteSC1ERKS_(%[[C_ADDR]], %[[A_ADDR]]) nothrow : (!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> () +// CIR: cir.copy %[[A_ADDR]] to %[[C_ADDR]] : !cir.ptr<!rec_CompleteS> // LLVM: define{{.*}} void @_Z11choose_exprv() // LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 // LLVM: %[[C_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 -// LLVM: call void @_ZN9CompleteSC1ERKS_(ptr %[[C_ADDR]], ptr %[[A_ADDR]]) +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false) // OGCG: define{{.*}} void @_Z11choose_exprv() // OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 @@ -167,15 +159,14 @@ void generic_selection() { // CIR: %[[B_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["b"] // CIR: %[[C_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["c"] // CIR: %[[D_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["d", init] -// TODO(cir): Call to default copy constructor should be replaced by `cir.copy` op -// CIR: cir.call @_ZN9CompleteSC1ERKS_(%[[D_ADDR]], %[[A_ADDR]]) nothrow : (!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> () +// CIR: cir.copy %[[A_ADDR]] to %[[D_ADDR]] : !cir.ptr<!rec_CompleteS> // LLVM: define{{.*}} void @_Z17generic_selectionv() // LLVM: %1 = alloca %struct.CompleteS, i64 1, align 4 // LLVM: %2 = alloca %struct.CompleteS, i64 1, align 4 // LLVM: %3 = alloca i32, i64 1, align 4 // LLVM: %4 = alloca %struct.CompleteS, i64 1, align 4 -// LLVM: call void @_ZN9CompleteSC1ERKS_(ptr %4, ptr %1) +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %4, ptr %1, i32 8, i1 false) // OGCG: define{{.*}} void @_Z17generic_selectionv() // OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 @@ -195,7 +186,7 @@ void designated_init_update_expr() { // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !rec_Container, !cir.ptr<!rec_Container>, ["b", init] // CIR: %[[C_ADDR:.*]] = cir.get_member %[[B_ADDR]][0] {name = "c"} : !cir.ptr<!rec_Container> -> !cir.ptr<!rec_CompleteS> -// CIR: cir.call @_ZN9CompleteSC1ERKS_(%2, %[[A_ADDR]]) nothrow : (!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> () +// CIR: cir.copy %[[A_ADDR]] to %[[C_ADDR]] : !cir.ptr<!rec_CompleteS> // CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[C_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> // CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i // CIR: cir.store{{.*}} %[[CONST_1]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> @@ -204,7 +195,7 @@ void designated_init_update_expr() { // LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca %struct.Container, i64 1, align 4 // LLVM: %[[C_ADDR:.*]] = getelementptr %struct.Container, ptr %[[B_ADDR]], i32 0, i32 0 -// LLVM: call void @_ZN9CompleteSC1ERKS_(ptr %[[C_ADDR]], ptr %[[A_ADDR]]) +// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false) // LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[C_ADDR]], i32 0, i32 0 // LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4 // LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[C_ADDR]], i32 0, i32 1 @@ -265,16 +256,11 @@ 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.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 -// CIR: cir.store{{.*}} %[[ZERO]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> +// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_CompleteS +// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> // LLVM: define{{.*}} void @_Z9bin_commav() // LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 -// LLVM: %[[TMP_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 -// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[TMP_ADDR]], align 4 // LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4 // OGCG: define{{.*}} void @_Z9bin_commav() @@ -284,20 +270,13 @@ void bin_comma() { 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> +// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_CompleteS +// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> // 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 +// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], 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) @@ -344,3 +323,47 @@ void struct_with_const_member_expr() { // 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 + +void function_arg_with_default_value(CompleteS a = {1, 2}) {} + +// CIR: %[[ARG_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] +// CIR: cir.store %{{.*}}, %[[ARG_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> + +// LLVM: %[[ARG_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: store %struct.CompleteS %{{.*}}, ptr %[[ARG_ADDR]], align 4 + +// OGCG: %[[ARG_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: store i64 %{{.*}}, ptr %[[ARG_ADDR]], align 4 + +void calling_function_with_default_values() { + function_arg_with_default_value(); +} + +// CIR: %[[AGG_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["agg.tmp0"] +// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[AGG_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[CONST_1]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ELEM_1_PTR:.*]] = cir.get_member %[[AGG_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i> +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_2_I8:.*]] = cir.cast integral %[[CONST_2]] : !s32i -> !s8i +// CIR: cir.store{{.*}} %[[CONST_2_I8]], %[[ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i> +// CIR: %[[TMP_AGG:.*]] = cir.load{{.*}} %[[AGG_ADDR]] : !cir.ptr<!rec_CompleteS>, !rec_CompleteS +// CIR: cir.call @_Z31function_arg_with_default_value9CompleteS(%[[TMP_AGG]]) : (!rec_CompleteS) -> () + +// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering, + +// LLVM: %[[AGG_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[AGG_ADDR]], i32 0, i32 0 +// LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4 +// LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[AGG_ADDR]], i32 0, i32 1 +// LLVM: store i8 2, ptr %[[ELEM_1_PTR]], align 4 +// LLVM: %[[TMP_AGG:.*]] = load %struct.CompleteS, ptr %[[AGG_ADDR]], align 4 +// LLVM: call void @_Z31function_arg_with_default_value9CompleteS(%struct.CompleteS %[[TMP_AGG]]) + +// OGCG: %[[AGG_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: %[[ELEM_0_PTR:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[AGG_ADDR]], i32 0, i32 0 +// OGCG: store i32 1, ptr %[[ELEM_0_PTR]], align 4 +// OGCG: %[[ELEM_1_PTR:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[AGG_ADDR]], i32 0, i32 1 +// OGCG: store i8 2, ptr %[[ELEM_1_PTR]], align 4 +// OGCG: %[[TMP_AGG:.*]] = load i64, ptr %[[AGG_ADDR]], align 4 +// OGCG: call void @_Z31function_arg_with_default_value9CompleteS(i64 %[[TMP_AGG]]) diff --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp index e13aa8f..3824be0 100644 --- a/clang/test/CIR/CodeGen/switch.cpp +++ b/clang/test/CIR/CodeGen/switch.cpp @@ -1183,3 +1183,90 @@ int nested_switch(int a) { // OGCG: [[IFEND10]]: // OGCG: br label %[[EPILOG]] // OGCG: [[EPILOG]]: + +int sw_return_multi_cases(int x) { + switch (x) { + case 0: + return 0; + case 1: + return 1; + case 2: + return 2; + default: + return -1; + } +} + +// CIR-LABEL: cir.func{{.*}} @_Z21sw_return_multi_casesi +// CIR: cir.switch (%{{.*}} : !s32i) { +// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[ZERO]], %{{.*}} : !s32i, !cir.ptr<!s32i> +// CIR: %[[RET0:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[RET0]] : !s32i +// CIR-NEXT: } +// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[ONE]], %{{.*}} : !s32i, !cir.ptr<!s32i> +// CIR: %[[RET1:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[RET1]] : !s32i +// CIR-NEXT: } +// CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) { +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i +// CIR: cir.store{{.*}} %[[TWO]], %{{.*}} : !s32i, !cir.ptr<!s32i> +// CIR: %[[RET2:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[RET2]] : !s32i +// CIR-NEXT: } +// CIR-NEXT: cir.case(default, []) { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[NEG:.*]] = cir.unary(minus, %[[ONE]]) {{.*}} : !s32i, !s32i +// CIR: cir.store{{.*}} %[[NEG]], %{{.*}} : !s32i, !cir.ptr<!s32i> +// CIR: %[[RETDEF:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[RETDEF]] : !s32i +// CIR-NEXT: } +// CIR-NEXT: cir.yield + +// LLVM-LABEL: define{{.*}} i32 @_Z21sw_return_multi_casesi +// LLVM: switch i32 %{{.*}}, label %[[DEFAULT:.*]] [ +// LLVM-DAG: i32 0, label %[[CASE0:.*]] +// LLVM-DAG: i32 1, label %[[CASE1:.*]] +// LLVM-DAG: i32 2, label %[[CASE2:.*]] +// LLVM: ] +// LLVM: [[CASE0]]: +// LLVM: store i32 0, ptr %{{.*}}, align 4 +// LLVM: %{{.*}} = load i32, ptr %{{.*}}, align 4 +// LLVM: ret i32 %{{.*}} +// LLVM: [[CASE1]]: +// LLVM: store i32 1, ptr %{{.*}}, align 4 +// LLVM: %{{.*}} = load i32, ptr %{{.*}}, align 4 +// LLVM: ret i32 %{{.*}} +// LLVM: [[CASE2]]: +// LLVM: store i32 2, ptr %{{.*}}, align 4 +// LLVM: %{{.*}} = load i32, ptr %{{.*}}, align 4 +// LLVM: ret i32 %{{.*}} +// LLVM: [[DEFAULT]]: +// LLVM: store i32 -1, ptr %{{.*}}, align 4 +// LLVM: %{{.*}} = load i32, ptr %{{.*}}, align 4 +// LLVM: ret i32 %{{.*}} + +// OGCG-LABEL: define{{.*}} i32 @_Z21sw_return_multi_casesi +// OGCG: entry: +// OGCG: %[[RETVAL:.*]] = alloca i32, align 4 +// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[X_VAL:.*]] = load i32, ptr %[[X_ADDR]], align 4 +// OGCG: switch i32 %[[X_VAL]], label %[[DEFAULT:.*]] [ +// OGCG-DAG: i32 0, label %[[SW0:.*]] +// OGCG-DAG: i32 1, label %[[SW1:.*]] +// OGCG-DAG: i32 2, label %[[SW2:.*]] +// OGCG: ] +// OGCG: [[SW0]]: +// OGCG: br label %[[RETURN:.*]] +// OGCG: [[SW1]]: +// OGCG: br label %[[RETURN]] +// OGCG: [[SW2]]: +// OGCG: br label %[[RETURN]] +// OGCG: [[DEFAULT]]: +// OGCG: br label %[[RETURN]] +// OGCG: [[RETURN]]: +// OGCG: %[[RETVAL_LOAD:.*]] = load i32, ptr %[[RETVAL]], align 4 +// OGCG: ret i32 %[[RETVAL_LOAD]] diff --git a/clang/test/CIR/CodeGen/temporary-materialization.cpp b/clang/test/CIR/CodeGen/temporary-materialization.cpp new file mode 100644 index 0000000..b936ddf --- /dev/null +++ b/clang/test/CIR/CodeGen/temporary-materialization.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -std=c++17 -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 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +int make_int(); + +int test() { + const int &x = make_int(); + return x; +} + +// CIR: cir.func {{.*}} @_Z4testv() +// CIR: %[[TEMP_SLOT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp0", init] +// CIR-NEXT: %[[X:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init, const] +// CIR-NEXT: %[[TEMP_VALUE:.*]] = cir.call @_Z8make_intv() : () -> !s32i +// CIR-NEXT: cir.store{{.*}} %[[TEMP_VALUE]], %[[TEMP_SLOT]] +// CIR-NEXT: cir.store{{.*}} %[[TEMP_SLOT]], %[[X]] + +// LLVM: define {{.*}} i32 @_Z4testv() +// LLVM: %[[RETVAL:.*]] = alloca i32 +// LLVM: %[[TEMP_SLOT:.*]] = alloca i32 +// LLVM: %[[X:.*]] = alloca ptr +// LLVM: %[[TEMP_VALUE:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE]], ptr %[[TEMP_SLOT]] +// LLVM: store ptr %[[TEMP_SLOT]], ptr %[[X]] + +// OGCG: define {{.*}} i32 @_Z4testv() +// OGCG: %[[X:.*]] = alloca ptr +// OGCG: %[[TEMP_SLOT:.*]] = alloca i32 +// OGCG: %[[TEMP_VALUE:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE]], ptr %[[TEMP_SLOT]] +// OGCG: store ptr %[[TEMP_SLOT]], ptr %[[X]] + +int test_scoped() { + int x = make_int(); + { + const int &y = make_int(); + x = y; + } + return x; +} + +// CIR: cir.func {{.*}} @_Z11test_scopedv() +// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// CIR: cir.scope { +// CIR-NEXT: %[[TEMP_SLOT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp0", init] +// CIR-NEXT: %[[Y_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["y", init, const] +// CIR-NEXT: %[[TEMP_VALUE:.*]] = cir.call @_Z8make_intv() : () -> !s32i +// CIR-NEXT: cir.store{{.*}} %[[TEMP_VALUE]], %[[TEMP_SLOT]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: cir.store{{.*}} %[[TEMP_SLOT]], %[[Y_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR-NEXT: %[[Y_REF:.*]] = cir.load %[[Y_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR-NEXT: %[[Y_VALUE:.*]] = cir.load{{.*}} %[[Y_REF]] : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.store{{.*}} %[[Y_VALUE]], %[[X]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: } + +// LLVM: define {{.*}} i32 @_Z11test_scopedv() +// LLVM: %[[TEMP_SLOT:.*]] = alloca i32 +// LLVM: %[[Y_ADDR:.*]] = alloca ptr +// LLVM: %[[RETVAL:.*]] = alloca i32 +// LLVM: %[[X:.*]] = alloca i32 +// LLVM: %[[TEMP_VALUE1:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE1]], ptr %[[X]] +// LLVM: br label %[[SCOPE_LABEL:.*]] +// LLVM: [[SCOPE_LABEL]]: +// LLVM: %[[TEMP_VALUE2:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE2]], ptr %[[TEMP_SLOT]] +// LLVM: store ptr %[[TEMP_SLOT]], ptr %[[Y_ADDR]] +// LLVM: %[[Y_REF:.*]] = load ptr, ptr %[[Y_ADDR]] +// LLVM: %[[Y_VALUE:.*]] = load i32, ptr %[[Y_REF]] +// LLVM: store i32 %[[Y_VALUE]], ptr %[[X]] + +// OGCG: define {{.*}} i32 @_Z11test_scopedv() +// OGCG: %[[X:.*]] = alloca i32 +// OGCG: %[[Y_ADDR:.*]] = alloca ptr +// OGCG: %[[TEMP_SLOT:.*]] = alloca i32 +// OGCG: %[[TEMP_VALUE1:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE1]], ptr %[[X]] +// OGCG: %[[TEMP_VALUE2:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE2]], ptr %[[TEMP_SLOT]] +// OGCG: store ptr %[[TEMP_SLOT]], ptr %[[Y_ADDR]] +// OGCG: %[[Y_REF:.*]] = load ptr, ptr %[[Y_ADDR]] +// OGCG: %[[Y_VALUE:.*]] = load i32, ptr %[[Y_REF]] +// OGCG: store i32 %[[Y_VALUE]], ptr %[[X]] diff --git a/clang/test/CIR/CodeGen/ternary-throw.cpp b/clang/test/CIR/CodeGen/ternary-throw.cpp index fb8897f..74168c1 100644 --- a/clang/test/CIR/CodeGen/ternary-throw.cpp +++ b/clang/test/CIR/CodeGen/ternary-throw.cpp @@ -195,3 +195,46 @@ const int& test_cond_const_false_throw_true() { // OGCG-NOT: __cxa_throw // OGCG: ret ptr %[[A]] +const int &test_cond_const_true_throw_true() { + const int a = 30; + return true ? throw 0 : a; +} + +// CIR-LABEL: cir.func{{.*}} @_Z31test_cond_const_true_throw_truev( +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["__retval"] +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init, const] +// CIR: %[[CONST_30:.*]] = cir.const #cir.int<30> : !s32i +// CIR: cir.store{{.*}} %[[CONST_30]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[EXCEPTION:.*]] = cir.alloc.exception 4 -> !cir.ptr<!s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[EXCEPTION]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.throw %[[EXCEPTION]] : !cir.ptr<!s32i>, @_ZTIi +// CIR: cir.unreachable +// CIR: ^[[NO_PRED_LABEL:.*]]: +// CIR: %[[CONST_NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> +// CIR: cir.store %[[CONST_NULL]], %[[RET_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: cir.return %[[TMP_RET]] : !cir.ptr<!s32i> + +// LLVM-LABEL: define{{.*}} ptr @_Z31test_cond_const_true_throw_truev( +// LLVM: %[[RET_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 30, ptr %[[A_ADDR]], align 4 +// LLVM: %[[EXCEPTION:.*]] = call ptr @__cxa_allocate_exception(i64 4) +// LLVM: store i32 0, ptr %[[EXCEPTION]], align 16 +// LLVM: call void @__cxa_throw(ptr %[[EXCEPTION]], ptr @_ZTIi, ptr null) +// LLVM: unreachable +// LLVM: [[NO_PRED_LABEL:.*]]: +// LLVM: store ptr null, ptr %[[RET_ADDR]], align 8 +// LLVM: %[[TMP_RET:.*]] = load ptr, ptr %[[RET_ADDR]], align 8 +// LLVM: ret ptr %[[TMP_RET]] + +// OGCG-LABEL: define{{.*}} ptr @_Z31test_cond_const_true_throw_truev( +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 30, ptr %[[A_ADDR]], align 4 +// OGCG: %[[EXCEPTION:.*]] = call ptr @__cxa_allocate_exception(i64 4) +// OGCG: store i32 0, ptr %[[EXCEPTION]], align 16 +// OGCG: call void @__cxa_throw(ptr %[[EXCEPTION]], ptr @_ZTIi, ptr null) +// OGCG: unreachable +// OGCG: [[NO_PRED_LABEL:.*]]: +// OGCG: ret ptr [[UNDEF:.*]] diff --git a/clang/test/CIR/CodeGen/tls.c b/clang/test/CIR/CodeGen/tls.c new file mode 100644 index 0000000..582a716 --- /dev/null +++ b/clang/test/CIR/CodeGen/tls.c @@ -0,0 +1,29 @@ +// 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.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ogcg.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ogcg.ll %s + +extern __thread int b; +// CIR: cir.global "private" external tls_dyn @b : !s32i + +__thread int a; +// CIR: cir.global external tls_dyn @a = #cir.int<0> : !s32i + +int c(void) { return *&b; } +// CIR: cir.func no_inline dso_local @c() -> !s32i +// CIR: %[[TLS_ADDR:.*]] = cir.get_global thread_local @b : !cir.ptr<!s32i> + +// LLVM: @b = external thread_local global i32 +// LLVM: @a = thread_local global i32 0 + +// LLVM-LABEL: @c +// LLVM: = call ptr @llvm.threadlocal.address.p0(ptr @b) + +// OGCG: @b = external thread_local{{.*}} global i32 +// OGCG: @a = thread_local{{.*}} global i32 0 + +// OGCG-LABEL: define{{.*}} @c +// OGCG: call{{.*}} ptr @llvm.threadlocal.address.p0(ptr{{.*}} @b) + diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp b/clang/test/CIR/CodeGen/try-catch-tmp.cpp new file mode 100644 index 0000000..078447f --- /dev/null +++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +int division(); + +void calling_division_inside_try_block() { + try { + division(); + } catch (...) { + } +} + +// CIR: cir.scope { +// CIR: cir.try { +// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i +// CIR: cir.yield +// CIR: } catch all { +// CIR: cir.yield +// CIR: } +// CIR: } + +// OGCG: %[[EXN_OBJ_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %[[EH_SELECTOR_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv() +// OGCG: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]] +// OGCG: [[INVOKE_CONT]]: +// OGCG: br label %[[TRY_CONT:.*]] +// OGCG: [[LANDING_PAD]]: +// OGCG: %[[LP:.*]] = landingpad { ptr, i32 } +// OGCG: catch ptr null +// OGCG: %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0 +// OGCG: store ptr %[[EXN_OBJ]], ptr %[[EXN_OBJ_ADDR]], align 8 +// OGCG: %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1 +// OGCG: store i32 %[[EH_SELECTOR_VAL]], ptr %[[EH_SELECTOR_ADDR]], align 4 +// OGCG: br label %[[CATCH:.*]] +// OGCG: [[CATCH]]: +// OGCG: %[[EXN_OBJ:.*]] = load ptr, ptr %[[EXN_OBJ_ADDR]], align 8 +// OGCG: %[[CATCH_BEGIN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ]]) +// OGCG: call void @__cxa_end_catch() +// OGCG: br label %[[TRY_CONT]] +// OGCG: [[TRY_CONT]]: +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c index f5b92c6..aab909e 100644 --- a/clang/test/CIR/CodeGen/var_arg.c +++ b/clang/test/CIR/CodeGen/var_arg.c @@ -17,7 +17,7 @@ int varargs(int count, ...) { return res; } -// CIR-LABEL: cir.func dso_local @varargs( +// CIR-LABEL: cir.func {{.*}} @varargs( // CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] // CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] @@ -93,7 +93,7 @@ int stdarg_start(int count, ...) { return res; } -// CIR-LABEL: cir.func dso_local @stdarg_start( +// CIR-LABEL: cir.func {{.*}} @stdarg_start( // CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] // CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] // CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] @@ -141,7 +141,7 @@ int stdarg_start(int count, ...) { // OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40 // OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem // -// OGCG: vaarg.in_reg: +// OGCG: vaarg.in_reg: // OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3 // OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]] // OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]] @@ -164,3 +164,23 @@ int stdarg_start(int count, ...) { // OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]]) // OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]] // OGCG: ret i32 %[[VAL]] + +void stdarg_copy() { + __builtin_va_list src, dest; + __builtin_va_copy(src, dest); +} + +// CIR-LABEL: @stdarg_copy +// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag> +// CIR: %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag> +// CIR: cir.va_copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag> + +// LLVM-LABEL: @stdarg_copy +// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}} +// LLVM: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}} +// LLVM: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}} + +// OGCG-LABEL: @stdarg_copy +// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}} +// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}} +// OGCG: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}} diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp index ba59109..3ba2fac 100644 --- a/clang/test/CIR/CodeGen/variable-decomposition.cpp +++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp @@ -16,15 +16,11 @@ float function() { return a + b; } -// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float +// CIR-LABEL: cir.func {{.*}} @_Z8functionv() -> !cir.float // CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"] // CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, ["", init] -// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i> -// CIR: %[[CONST_1:.+]] = cir.const #cir.int<1> : !s32i -// CIR: cir.store{{.*}} %[[CONST_1]], %[[MEMBER_A]] -// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float> -// CIR: %[[TWO_FP:.+]] = cir.const #cir.fp<2.000000e+00> : !cir.float -// CIR: cir.store{{.*}} %[[TWO_FP]], %[[MEMBER_B]] +// CIR: %[[CONST:.+]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.fp<2.000000e+00> : !cir.float}> : !rec_some_struct +// CIR: cir.store{{.*}} %[[CONST]], %[[STRUCT]] // CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i> // CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i // CIR: %[[CAST_A:.+]] = cir.cast int_to_float %[[LOAD_A]] : !s32i -> !cir.float @@ -38,10 +34,7 @@ float function() { // LLVM-LABEL: define dso_local float @_Z8functionv() // LLVM: %[[RETVAL:.+]] = alloca float, i64 1 // LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1 -// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0 -// LLVM: store i32 1, ptr %[[GEP_A]] -// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1 -// LLVM: store float 2.000000e+00, ptr %[[GEP_B]] +// LLVM: store %struct.some_struct { i32 1, float 2.000000e+00 }, ptr %[[STRUCT]] // LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0 // LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]] // LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float diff --git a/clang/test/CIR/CodeGen/vbase.cpp b/clang/test/CIR/CodeGen/vbase.cpp index 8fcb2a4..c1f3972 100644 --- a/clang/test/CIR/CodeGen/vbase.cpp +++ b/clang/test/CIR/CodeGen/vbase.cpp @@ -128,7 +128,7 @@ void ppp() { B b; } // OGCG: ret void // Constructor for B -// CIR: cir.func comdat linkonce_odr @_ZN1BC1Ev(%arg0: !cir.ptr<!rec_B> +// CIR: cir.func {{.*}} @_ZN1BC1Ev(%arg0: !cir.ptr<!rec_B> // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["this", init] // CIR: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>> // CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B> diff --git a/clang/test/CIR/CodeGen/vector-ext-element.cpp b/clang/test/CIR/CodeGen/vector-ext-element.cpp new file mode 100644 index 0000000..77ca3b4 --- /dev/null +++ b/clang/test/CIR/CodeGen/vector-ext-element.cpp @@ -0,0 +1,341 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -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 -Wno-unused-value -fclangir -emit-llvm %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 -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +typedef int vi2 __attribute__((ext_vector_type(2))); +typedef int vi4 __attribute__((ext_vector_type(4))); + +void element_expr_from_gl() { + vi4 a; + int x = a.x; + int y = a.y; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"] +// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// CIR: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i +// CIR: %[[ELEM_0:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_0]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_0]], %[[X_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ELEM_1:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_1]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_1]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[Y_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[ELEM_0:.*]] = extractelement <4 x i32> %4, i64 0 +// LLVM: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[ELEM_1:.*]] = extractelement <4 x i32> %6, i64 1 +// LLVM: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[Y_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 0 +// OGCG: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 1 +// OGCG: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +void element_expr_from_gl_with_vec_result() { + vi4 a; + vi2 b = a.xy; + vi4 c = a.wzyx; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>>, ["b", init] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[B_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !s32i> +// CIR: cir.store {{.*}} %[[B_VALUE]], %[[B_ADDR]] : !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[C_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<3> : !s32i, #cir.int<2> : !s32i, #cir.int<1> : !s32i, #cir.int<0> : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[C_VALUE]], %[[C_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[B_ADDR:.*]] = alloca <2 x i32>, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// LLVM: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// LLVM: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[B_ADDR:.*]] = alloca <2 x i32>, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// OGCG: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// OGCG: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16 + +void element_expr_from_pointer() { + vi4 *a; + int X = a->x; + int Y = a->y; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!cir.vector<4 x !s32i>>, !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, ["a"] +// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["X", init] +// CIR: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["Y", init] +// CIR: %[[TMP_A_PTR:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[TMP_A_PTR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i +// CIR: %[[ELEM_0:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_0]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_0]], %[[X_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP_A_PTR:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[TMP_A_PTR:.*]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ELEM_1:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_1]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_1]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[Y_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// LLVM: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 0 +// LLVM: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// LLVM: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 1 +// LLVM: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[Y_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// OGCG: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 0 +// OGCG: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// OGCG: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// OGCG: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 1 +// OGCG: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +void element_expr_from_pointer_with_vec_result() { + vi4 *a; + vi2 b = a->xy; + vi4 c = a->wzyx; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!cir.vector<4 x !s32i>>, !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>>, ["b", init] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["c", init] +// CIR: %[[TMP_A_PTR:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[TMP_A_PTR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[B_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !s32i> +// CIR: cir.store {{.*}} %[[B_VALUE]], %[[B_ADDR]] : !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>> +// CIR: %[[TMP_A_PTR:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!cir.vector<4 x !s32i>>>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[TMP_A_PTR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[C_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<3> : !s32i, #cir.int<2> : !s32i, #cir.int<1> : !s32i, #cir.int<0> : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[C_VALUE]], %[[C_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[B_ADDR:.*]] = alloca <2 x i32>, i64 1, align 8 +// LLVM: %[[C_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// LLVM: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// LLVM: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8 +// LLVM: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// LLVM: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// LLVM: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16 + +// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca <2 x i32>, align 8 +// OGCG: %[[C_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// OGCG: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// OGCG: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8 +// OGCG: %[[TMP_A_PTR:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[TMP_A_PTR]], align 16 +// OGCG: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// OGCG: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16 + +void element_expr_from_rvalue() { + vi4 a; + vi4 b; + int x = (a + b).x; + int y = (a + b).y; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"] +// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// CIR: %[[TMP_1_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["tmp"] +// CIR: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] +// CIR: %[[TMP_2_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["tmp"] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ADD_A_B:.*]] = cir.binop(add, %[[TMP_A]], %[[TMP_B]]) : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ADD_A_B]], %[[TMP_1_ADDR:.*]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_1:.*]] = cir.load {{.*}} %[[TMP_1_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i +// CIR: %[[ELEM_0:.*]] = cir.vec.extract %[[TMP_1]][%[[CONST_0]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_0]], %[[X_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ADD_A_B:.*]] = cir.binop(add, %[[TMP_A]], %[[TMP_B]]) : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ADD_A_B]], %[[TMP_2_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_2:.*]] = cir.load {{.*}} %[[TMP_2_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ELEM_1:.*]] = cir.vec.extract %[[TMP_2]][%[[CONST_1]] : !s64i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ELEM_1]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[B_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[TMP_1_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[Y_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[TMP_2_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// LLVM: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_1_ADDR]], align 16 +// LLVM: %[[TMP_1:.*]] = load <4 x i32>, ptr %[[TMP_1_ADDR]], align 16 +// LLVM: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_1]], i64 0 +// LLVM: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// LLVM: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_2_ADDR]], align 16 +// LLVM: %[[TMP_2:.*]] = load <4 x i32>, ptr %[[TMP_2_ADDR]], align 16 +// LLVM: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_2]], i64 1 +// LLVM: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[B_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[TMP_1_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[Y_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[TMP_2_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// OGCG: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_1_ADDR]], align 16 +// OGCG: %[[TMP_1:.*]] = load <4 x i32>, ptr %[[TMP_1_ADDR]], align 16 +// OGCG: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_1]], i64 0 +// OGCG: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// OGCG: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_2_ADDR]], align 16 +// OGCG: %[[TMP_2:.*]] = load <4 x i32>, ptr %[[TMP_2_ADDR]], align 16 +// OGCG: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_2]], i64 1 +// OGCG: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4 + +void element_expr_from_rvalue_with_vec_result() { + vi4 a; + vi4 b; + vi2 c = (a + b).xy; + vi4 d = (a + b).wzyx; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b"] +// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>>, ["c", init] +// CIR: %[[TMP_1_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["tmp"] +// CIR: %[[D_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["d", init] +// CIR: %[[TMP_2_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["tmp"] +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ADD_A_B:.*]] = cir.binop(add, %[[TMP_A]], %[[TMP_B]]) : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ADD_A_B]], %[[TMP_1_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_1:.*]] = cir.load {{.*}} %[[TMP_1_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[C_VALUE:.*]] = cir.vec.shuffle(%[[TMP_1]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !s32i> +// CIR: cir.store {{.*}} %[[C_VALUE]], %[[C_ADDR]] : !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ADD_A_B:.*]] = cir.binop(add, %[[TMP_A]], %[[TMP_B]]) : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[ADD_A_B]], %[[TMP_2_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_2:.*]] = cir.load {{.*}} %[[TMP_2_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i> +// CIR: %[[D_VALUE:.*]] = cir.vec.shuffle(%[[TMP_2]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<3> : !s32i, #cir.int<2> : !s32i, #cir.int<1> : !s32i, #cir.int<0> : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store {{.*}} %[[D_VALUE]], %[[D_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[B_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[C_ADDR:.*]] = alloca <2 x i32>, i64 1, align 8 +// LLVM: %[[TMP_1_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[D_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[TMP_2_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// LLVM: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_1_ADDR]], align 16 +// LLVM: %[[TMP_1:.*]] = load <4 x i32>, ptr %[[TMP_1_ADDR]], align 16 +// LLVM: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_1]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// LLVM: store <2 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 8 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// LLVM: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_2_ADDR]], align 16 +// LLVM: %[[TMP_2:.*]] = load <4 x i32>, ptr %[[TMP_2_ADDR]], align 16 +// LLVM: %[[D_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_2]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// LLVM: store <4 x i32> %[[D_VALUE]], ptr %[[D_ADDR]], align 16 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[B_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[C_ADDR:.*]] = alloca <2 x i32>, align 8 +// OGCG: %[[TMP_1_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[D_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[TMP_2_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// OGCG: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_1_ADDR]], align 16 +// OGCG: %[[TMP_1:.*]] = load <4 x i32>, ptr %[[TMP_1_ADDR]], align 16 +// OGCG: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_1]], <4 x i32> poison, <2 x i32> <i32 0, i32 1> +// OGCG: store <2 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 8 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[B_ADDR]], align 16 +// OGCG: %[[ADD_A_B:.*]] = add <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[ADD_A_B]], ptr %[[TMP_2_ADDR]], align 16 +// OGCG: %[[TMP_2:.*]] = load <4 x i32>, ptr %[[TMP_2_ADDR]], align 16 +// OGCG: %[[D_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_2]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0> +// OGCG: store <4 x i32> %[[D_VALUE]], ptr %[[D_ADDR]], align 16 + +void array_subscript_expr_with_element_expr_base() { + vi4 a; + a.xyz[1] = 2; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"] +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[A_PTR:.*]] = cir.cast bitcast %0 : !cir.ptr<!cir.vector<4 x !s32i>> -> !cir.ptr<!s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i +// CIR: %[[VEC_MEMBER_EXPR:.*]] = cir.ptr_stride %[[A_PTR]], %[[CONST_0]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i> +// CIR: %[[VEC_ELEM_PTR:.*]] = cir.ptr_stride %[[VEC_MEMBER_EXPR]], %[[CONST_1]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CIR: cir.store {{.*}} %[[CONST_2]], %[[VEC_ELEM_PTR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[VEC_MEMBER_EXPR:.*]] = getelementptr i32, ptr %[[A_ADDR]], i64 0 +// LLVM: %[[VEC_ELEM_PTR:.*]] = getelementptr i32, ptr %[[VEC_MEMBER_EXPR]], i64 1 +// LLVM: store i32 2, ptr %[[VEC_ELEM_PTR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[VEC_MEMBER_EXPR:.*]] = getelementptr inbounds i32, ptr %[[A_ADDR]], i64 0 +// OGCG: %[[VEC_ELEM_PTR:.*]] = getelementptr inbounds i32, ptr %[[VEC_MEMBER_EXPR]], i64 1 +// OGCG: store i32 2, ptr %[[VEC_ELEM_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/volatile.cpp b/clang/test/CIR/CodeGen/volatile.cpp index df1d3a6..17a7154 100644 --- a/clang/test/CIR/CodeGen/volatile.cpp +++ b/clang/test/CIR/CodeGen/volatile.cpp @@ -9,7 +9,7 @@ int test_load(volatile int *ptr) { return *ptr; } -// CIR: cir.func dso_local @_Z9test_loadPVi +// CIR: cir.func {{.*}} @_Z9test_loadPVi // CIR: cir.load volatile // LLVM: define {{.*}} i32 @_Z9test_loadPVi @@ -22,7 +22,7 @@ void test_store(volatile int *ptr) { *ptr = 42; } -// CIR: cir.func dso_local @_Z10test_storePVi +// CIR: cir.func {{.*}} @_Z10test_storePVi // CIR: cir.store volatile // LLVM: define {{.*}} void @_Z10test_storePVi @@ -41,7 +41,7 @@ int test_load_field1(volatile Foo *ptr) { return ptr->x; } -// CIR: cir.func dso_local @_Z16test_load_field1PV3Foo +// CIR: cir.func {{.*}} @_Z16test_load_field1PV3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]] @@ -57,7 +57,7 @@ int test_load_field2(Foo *ptr) { return ptr->y; } -// CIR: cir.func dso_local @_Z16test_load_field2P3Foo +// CIR: cir.func {{.*}} @_Z16test_load_field2P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]] @@ -73,7 +73,7 @@ int test_load_field3(Foo *ptr) { return ptr->z; } -// CIR: cir.func dso_local @_Z16test_load_field3P3Foo +// CIR: cir.func {{.*}} @_Z16test_load_field3P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: %{{.*}} = cir.get_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] {is_volatile} : !cir.ptr<!u8i>) -> !s32i @@ -95,7 +95,7 @@ void test_store_field1(volatile Foo *ptr) { ptr->x = 42; } -// CIR: cir.func dso_local @_Z17test_store_field1PV3Foo +// CIR: cir.func {{.*}} @_Z17test_store_field1PV3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]] @@ -111,7 +111,7 @@ void test_store_field2(Foo *ptr) { ptr->y = 42; } -// CIR: cir.func dso_local @_Z17test_store_field2P3Foo +// CIR: cir.func {{.*}} @_Z17test_store_field2P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]] @@ -127,7 +127,7 @@ void test_store_field3(Foo *ptr) { ptr->z = 4; } -// CIR: cir.func dso_local @_Z17test_store_field3P3Foo +// CIR: cir.func {{.*}} @_Z17test_store_field3P3Foo // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member // CIR: cir.set_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] : !cir.ptr<!u8i>, %1 : !s32i) {is_volatile} @@ -155,7 +155,7 @@ void A::set_x(int val) volatile { x = val; } -// CIR: cir.func dso_local @_ZNV1A5set_xEi +// CIR: cir.func {{.*}} @_ZNV1A5set_xEi // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"} // CIR: cir.store volatile {{.*}} %{{.*}}, %[[MEMBER_ADDR]] @@ -171,7 +171,7 @@ int A::get_x() volatile { return x; } -// CIR: cir.func dso_local @_ZNV1A5get_xEv +// CIR: cir.func {{.*}} @_ZNV1A5get_xEv // CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"} // CIR: cir.load volatile {{.*}} %[[MEMBER_ADDR]] diff --git a/clang/test/CIR/CodeGen/vtable-emission.cpp b/clang/test/CIR/CodeGen/vtable-emission.cpp index 9a34573..ceefb2a 100644 --- a/clang/test/CIR/CodeGen/vtable-emission.cpp +++ b/clang/test/CIR/CodeGen/vtable-emission.cpp @@ -32,7 +32,7 @@ void S::key() {} // OGCG: @_ZTV1S = unnamed_addr constant { [4 x ptr] } { [4 x ptr] // OGCG-SAME: [ptr null, ptr null, ptr @_ZN1S3keyEv, ptr @_ZN1S6nonKeyEv] } -// CHECK: cir.func dso_local @_ZN1S3keyEv +// CHECK: cir.func {{.*}} @_ZN1S3keyEv // The reference from the vtable should result in nonKey being emitted. -// CHECK: cir.func comdat linkonce_odr @_ZN1S6nonKeyEv +// CHECK: cir.func no_inline comdat linkonce_odr @_ZN1S6nonKeyEv diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp index f9a62e3..d0319b7 100644 --- a/clang/test/CIR/CodeGen/vtt.cpp +++ b/clang/test/CIR/CodeGen/vtt.cpp @@ -5,12 +5,12 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefixes=OGCG-NO-RTTI,OGCG-COMMON --input-file=%t.ll %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --check-prefixes=CIR-RTTI,CIR-COMMON --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-prefixes=LLVM-RTTI,LLVM-COMMON --input-file=%t-cir.ll %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll -// RUN: FileCheck --check-prefixes=OGCG-RTTI,OGCG-COMMON --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-rtti.cir +// RUN: FileCheck --check-prefixes=CIR-RTTI,CIR-COMMON --input-file=%t-rtti.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir-rtti.ll +// RUN: FileCheck --check-prefixes=LLVM-RTTI,LLVM-COMMON --input-file=%t-cir-rtti.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-rtti.ll +// RUN: FileCheck --check-prefixes=OGCG-RTTI,OGCG-COMMON --input-file=%t-rtti.ll %s // Note: This test will be expanded to verify VTT emission and VTT implicit // argument handling. For now, it's just test the record layout. @@ -170,7 +170,7 @@ void D::y() {} // CIR-RTTI: cir.global{{.*}} @_ZTI1B : !cir.ptr<!u8i> -// LLVM-RTTI: @_ZTI1B = external global ptr +// LLVM-RTTI: @_ZTI1B = external constant ptr // OGCG-RTTI: @_ZTI1B = external constant ptr |
