diff options
Diffstat (limited to 'clang/test/CIR/CodeGen')
-rw-r--r-- | clang/test/CIR/CodeGen/array-ctor.cpp | 106 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/bitfields.c | 48 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/cleanup.cpp | 83 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/complex-cast.cpp | 358 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/complex.cpp | 19 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/dtor-alias.cpp | 75 | ||||
-rw-r--r-- | clang/test/CIR/CodeGen/struct-init.cpp | 184 |
7 files changed, 873 insertions, 0 deletions
diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp new file mode 100644 index 0000000..b3d81a8 --- /dev/null +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o - 2>&1 | FileCheck --check-prefixes=CIR-BEFORE-LPP %s +// 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 + +struct S { + S(); +}; + +void foo() { + S s[42]; +} + +// CIR-BEFORE-LPP: cir.func dso_local @_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>): +// CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: cir.return +// CIR-BEFORE-LPP: } + +// CIR: cir.func dso_local @_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> +// CIR: %[[END_PTR:.*]] = cir.ptr_stride(%[[DECAY]] : !cir.ptr<!rec_S>, %[[CONST42]] : !u64i), !cir.ptr<!rec_S> +// CIR: %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"] +// CIR: cir.store %[[DECAY]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.do { +// CIR: %[[CURRENT:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i +// CIR: cir.call @_ZN1SC1Ev(%[[CURRENT]]) : (!cir.ptr<!rec_S>) -> () +// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CURRENT]] : !cir.ptr<!rec_S>, %[[CONST1]] : !u64i), !cir.ptr<!rec_S> +// CIR: cir.store %[[NEXT]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CURRENT2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CURRENT2]], %[[END_PTR]]) : !cir.ptr<!rec_S>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define dso_local void @_Z3foov() +// LLVM: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// LLVM: %[[START:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.S, ptr %[[START]], i64 42 +// LLVM: %[[ITER:.*]] = alloca ptr +// LLVM: store ptr %[[START]], ptr %[[ITER]] +// LLVM: br label %[[LOOP:.*]] +// LLVM: [[COND:.*]]: +// LLVM: %[[CURRENT_CHECK:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[DONE:.*]] = icmp ne ptr %[[CURRENT_CHECK]], %[[END]] +// LLVM: br i1 %[[DONE]], label %[[LOOP]], label %[[EXIT:.*]] +// LLVM: [[LOOP]]: +// LLVM: %[[CURRENT:.*]] = load ptr, ptr %[[ITER]] +// LLVM: call void @_ZN1SC1Ev(ptr %[[CURRENT]]) +// LLVM: %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CURRENT]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[ITER]] +// LLVM: br label %[[COND]] +// LLVM: [[EXIT]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z3foov() +// OGCG: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// OGCG: %[[START:.*]] = getelementptr{{.*}} %struct.S{{.*}} +// OGCG: %[[END:.*]] = getelementptr{{.*}} %struct.S{{.*}} i64 42 +// OGCG: br label %[[LOOP:.*]] +// OGCG: [[LOOP]]: +// OGCG: %[[CURRENT:.*]] = phi ptr [ %[[START]], %{{.*}} ], [ %[[NEXT:.*]], %[[LOOP]] ] +// OGCG: call void @_ZN1SC1Ev(ptr{{.*}}) +// OGCG: %[[NEXT]] = getelementptr{{.*}} %struct.S{{.*}} i64 1 +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]] +// OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] +// OGCG: [[EXIT]]: +// OGCG: ret void + +void zero_sized() { + S s[0]; +} + +// CIR-BEFORE-LPP: cir.func dso_local @_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.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 +// CIR: cir.return + +// LLVM: define dso_local void @_Z10zero_sizedv() +// LLVM: alloca [0 x %struct.S] +// LLVM-NOT: call void @_ZN1SC1Ev +// LLVM: ret void + +// OGCG: define dso_local void @_Z10zero_sizedv() +// OGCG: alloca [0 x %struct.S] +// OGCG-NOT: call void @_ZN1SC1Ev +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index a73c076..869a7c9 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -315,3 +315,51 @@ void unOp(S* s) { // OGCG: [[TMP12:%.*]] = shl i64 [[TMP8]], 62 // OGCG: [[TMP13:%.*]] = ashr i64 [[TMP12]], 62 // OGCG: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 + +void binOp(S* s) { + s->d |= 42; +} + +// CIR: cir.func {{.*@binOp}} +// CIR: [[TMP0:%.*]] = cir.const #cir.int<42> : !s32i +// CIR: [[TMP1:%.*]] = cir.get_member {{.*}}[0] {name = "d"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i> +// CIR: [[TMP2:%.*]] = cir.get_bitfield align(4) (#bfi_d, [[TMP1]] : !cir.ptr<!u64i>) -> !s32i +// CIR: [[TMP3:%.*]] = cir.binop(or, [[TMP2]], [[TMP0]]) : !s32i +// CIR: cir.set_bitfield align(4) (#bfi_d, [[TMP1]] : !cir.ptr<!u64i>, [[TMP3]] : !s32i) + +// LLVM: define {{.*@binOp}} +// LLVM: [[TMP0:%.*]] = load ptr, ptr {{.*}}, align 8 +// LLVM: [[TMP1:%.*]] = getelementptr %struct.S, ptr [[TMP0]], i32 0, i32 0 +// LLVM: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4 +// LLVM: [[TMP3:%.*]] = shl i64 [[TMP2]], 13 +// LLVM: [[TMP4:%.*]] = ashr i64 [[TMP3]], 62 +// LLVM: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// LLVM: [[TMP6:%.*]] = or i32 [[TMP5]], 42 +// LLVM: [[TMP7:%.*]] = zext i32 [[TMP6]] to i64 +// LLVM: [[TMP8:%.*]] = load i64, ptr [[TMP1]], align 4 +// LLVM: [[TMP9:%.*]] = and i64 [[TMP7]], 3 +// LLVM: [[TMP10:%.*]] = shl i64 [[TMP9]], 49 +// LLVM: [[TMP11:%.*]] = and i64 [[TMP8]], -1688849860263937 +// LLVM: [[TMP12:%.*]] = or i64 [[TMP11]], [[TMP10]] +// LLVM: store i64 [[TMP12]], ptr [[TMP1]], align 4 +// LLVM: [[TMP13:%.*]] = shl i64 [[TMP9]], 62 +// LLVM: [[TMP14:%.*]] = ashr i64 [[TMP13]], 62 +// LLVM: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 + +// OGCG: define {{.*@binOp}} +// OGCG: [[TMP0:%.*]] = load ptr, ptr %s.addr, align 8 +// OGCG: [[TMP1:%.*]] = load i64, ptr [[TMP0]], align 4 +// OGCG: [[TMP2:%.*]] = shl i64 [[TMP1]], 13 +// OGCG: [[TMP3:%.*]] = ashr i64 [[TMP2]], 62 +// OGCG: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32 +// OGCG: [[TMP5:%.*]] = or i32 [[TMP4]], 42 +// OGCG: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// OGCG: [[TMP7:%.*]] = load i64, ptr [[TMP0]], align 4 +// OGCG: [[TMP8:%.*]] = and i64 [[TMP6]], 3 +// OGCG: [[TMP9:%.*]] = shl i64 [[TMP8]], 49 +// OGCG: [[TMP10:%.*]] = and i64 [[TMP7]], -1688849860263937 +// OGCG: [[TMP11:%.*]] = or i64 [[TMP10]], [[TMP9]] +// OGCG: store i64 [[TMP11]], ptr [[TMP0]], align 4 +// OGCG: [[TMP12:%.*]] = shl i64 [[TMP8]], 62 +// OGCG: [[TMP13:%.*]] = ashr i64 [[TMP12]], 62 +// OGCG: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 diff --git a/clang/test/CIR/CodeGen/cleanup.cpp b/clang/test/CIR/CodeGen/cleanup.cpp new file mode 100644 index 0000000..41961513 --- /dev/null +++ b/clang/test/CIR/CodeGen/cleanup.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +struct Struk { + ~Struk(); +}; + +// CHECK: !rec_Struk = !cir.record<struct "Struk" padded {!u8i}> + +// CHECK: cir.func{{.*}} @_ZN5StrukD1Ev(!cir.ptr<!rec_Struk>) + +void test_cleanup() { + Struk s; +} + +// CHECK: cir.func{{.*}} @_Z12test_cleanupv() +// CHECK: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S_ADDR]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: cir.return + +void test_cleanup_ifelse(bool b) { + if (b) { + Struk s; + } else { + Struk s; + } +} + +// CHECK: cir.func{{.*}} @_Z19test_cleanup_ifelseb(%arg0: !cir.bool +// CHECK: cir.scope { +// CHECK: %[[B:.*]] = cir.load{{.*}} %0 : !cir.ptr<!cir.bool> +// CHECK: cir.if %[[B]] { +// CHECK: %[[S:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } else { +// CHECK: %[[S_TOO:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S_TOO]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: } +// CHECK: cir.return + +void test_cleanup_for() { + for (int i = 0; i < 10; i++) { + Struk s; + } +} + +// CHECK: cir.func{{.*}} @_Z16test_cleanup_forv() +// CHECK: cir.scope { +// CHECK: cir.for : cond { +// CHECK: } body { +// CHECK: cir.scope { +// CHECK: %[[S:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[S]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.yield +// CHECK: } step { +// CHECK: } +// CHECK: } +// CHECK: cir.return + +void test_cleanup_nested() { + Struk outer; + { + Struk middle; + { + Struk inner; + } + } +} + +// CHECK: cir.func{{.*}} @_Z19test_cleanup_nestedv() +// CHECK: %[[OUTER:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["outer"] +// CHECK: cir.scope { +// CHECK: %[[MIDDLE:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["middle"] +// CHECK: cir.scope { +// CHECK: %[[INNER:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["inner"] +// CHECK: cir.call @_ZN5StrukD1Ev(%[[INNER]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.call @_ZN5StrukD1Ev(%[[MIDDLE]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: } +// CHECK: cir.call @_ZN5StrukD1Ev(%[[OUTER]]) nothrow : (!cir.ptr<!rec_Struk>) -> () +// CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/complex-cast.cpp b/clang/test/CIR/CodeGen/complex-cast.cpp new file mode 100644 index 0000000..0881057 --- /dev/null +++ b/clang/test/CIR/CodeGen/complex-cast.cpp @@ -0,0 +1,358 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s +// 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 _Complex cd; +float _Complex cf; +int _Complex ci; +short _Complex cs; +double sd; +int si; +bool b; + +void scalar_to_complex() { + cd = sd; + ci = si; + cd = si; + ci = sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void scalar_to_complex_explicit() { + cd = (double _Complex)sd; + ci = (int _Complex)si; + cd = (double _Complex)si; + ci = (int _Complex)sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 +// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 +// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void complex_to_scalar() { + sd = (double)cd; + si = (int)ci; + sd = (double)ci; + si = (int)cd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 +// LLVM: store double %[[REAL]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0 +// LLVM: store i32 %[[REAL]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %[[INT_COMPLEX_TO_REAL]] : !s32i), !cir.double + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(int_to_float, %[[REAL]] : !s32i), !cir.double + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.+}}, 0 +// LLVM-NEXT: %[[REAL_TO_DOUBLE:.*]] = sitofp i32 %[[REAL]] to double +// LLVM-NEXT: store double %[[REAL_TO_DOUBLE]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[INT_TO_FP:.*]] = sitofp i32 %[[REAL]] to double +// OGCG: store double %[[INT_TO_FP]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %[[FP_TO_COMPLEX_REAL]] : !cir.double), !s32i + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(float_to_int, %[[REAL]] : !cir.double), !s32i + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.+}}, 0 +// LLVM-NEXT: %[[REAL_TO_INT:.*]] = fptosi double %[[REAL]] to i32 +// LLVM-NEXT: store i32 %[[REAL_TO_INT]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[FP_TO_INT:.*]] = fptosi double %[[REAL]] to i32 +// OGCG: store i32 %[[FP_TO_INT]], ptr {{.*}}, align 4 + +void complex_to_bool() { + b = (bool)cd; + b = (bool)ci; +} + +// CIR-BEFORE: %[[FP_COMPLEX_TO_BOOL:.*]] = cir.cast(float_complex_to_bool, %{{.*}} : !cir.complex<!cir.double>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[REAL]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[IMAG]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.*}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { double, double } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// LLVM-NEXT: %[[OR:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8 +// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[IMAG:.*]] = load double, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 +// OGCG: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// OGCG: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_BOOL:.*]] = cir.cast(int_complex_to_bool, %{{.*}} : !cir.complex<!s32i>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[REAL]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[IMAG]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.+}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { i32, i32 } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// LLVM-NEXT: %[[OR:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8 +// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load i32, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// OGCG: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +void complex_to_complex_cast() { + cd = cf; + ci = cs; +} + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-BEFORE: %[[FP_COMPLEX:.*]] = cir.cast(float_complex, %[[TMP]] : !cir.complex<!cir.float>), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[REAL_FP_CAST:.*]] = cir.cast(floating, %[[REAL]] : !cir.float), !cir.double +// CIR-AFTER: %[[IMAG_FP_CAST:.*]] = cir.cast(floating, %[[IMAG]] : !cir.float), !cir.double +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_FP_CAST]], %[[IMAG_FP_CAST]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = extractvalue { float, float } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %{{.*}}, 1 +// LLVM: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// LLVM: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL_FP_CAST]], 0 +// LLVM: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double %[[IMAG_FP_CAST]], 1 +// LLVM: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8 + +// OGCG: %[[REAL:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// OGCG: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// OGCG: store double %[[REAL_FP_CAST]], ptr {{.*}}, align 8 +// OGCG: store double %[[IMAG_FP_CAST]], ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!s16i>>, !cir.complex<!s16i> +// CIR-BEFORE: %[[INT_COMPLEX:.*]] = cir.cast(int_complex, %[[TMP]] : !cir.complex<!s16i>), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[REAL_INT_CAST:.*]] = cir.cast(integral, %[[REAL]] : !s16i), !s32i +// CIR-AFTER: %[[IMAG_INT_CAST:.*]] = cir.cast(integral, %[[IMAG]] : !s16i), !s32i +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_INT_CAST]], %[[IMAG_INT_CAST]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = extractvalue { i16, i16 } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { i16, i16 } %{{.*}}, 1 +// LLVM: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// LLVM: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// LLVM: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL_INT_CAST]], 0 +// LLVM: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 %[[IMAG_INT_CAST]], 1 +// LLVM: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4 + +// OGCG: %[[REAL:.*]] = load i16, ptr {{.*}}, align 2 +// OGCG: %[[IMAG:.*]] = load i16, ptr getelementptr inbounds nuw ({ i16, i16 }, ptr {{.*}}, i32 0, i32 1), align 2 +// OGCG: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// OGCG: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// OGCG: store i32 %[[REAL_INT_CAST]], ptr {{.*}}, align 4 +// OGCG: store i32 %[[IMAG_INT_CAST]], ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +struct CX { + double real; + double imag; +}; + +void lvalue_to_rvalue_bitcast() { + CX a; + double _Complex b = __builtin_bit_cast(double _Complex, a); +} + + +// CIR-BEFORE: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// CIR-AFTER: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// LLVM: %[[PTR_ADDR:.*]] = alloca %struct.CX, i64 1, align 8 +// LLVM: %[[COMPLEX_ADDR:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[PTR_TO_COMPLEX:.*]] = load { double, double }, ptr %[[PTR_ADDR]], align 8 +// LLVM: store { double, double } %[[PTR_TO_COMPLEX]], ptr %[[COMPLEX_ADDR]], align 8 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CX, align 8 +// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8 +// 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: %[[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 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 8 +// OGCG: store double %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 8 diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 0a7765f..bd7de9a 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -780,3 +780,22 @@ void foo29() { // OGCG: %[[INIT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[INIT]], i32 0, i32 1 // OGCG: store i32 0, ptr %[[INIT_REAL_PTR]], align 4 // OGCG: store i32 0, ptr %[[INIT_IMAG_PTR]], align 4 + +void foo30() { + float _Complex a = { 1.0f }; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: %[[CONST_1F:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float +// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[CONST_1F]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[COMPLEX]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } { float 1.000000e+00, float 0.000000e+00 }, ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, 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 1.000000e+00, ptr %[[A_REAL_PTR]], align 4 +// OGCG: store float 0.000000e+00, ptr %[[A_IMAG_PTR]], align 4 diff --git a/clang/test/CIR/CodeGen/dtor-alias.cpp b/clang/test/CIR/CodeGen/dtor-alias.cpp new file mode 100644 index 0000000..e37ddab --- /dev/null +++ b/clang/test/CIR/CodeGen/dtor-alias.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++17 -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 -std=c++17 -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 B { + ~B(); +}; +B::~B() { +} + +// OGCG: @_ZN1BD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BD2Ev + +// CHECK: cir.func{{.*}} @_ZN1BD2Ev(%arg0: !cir.ptr<!rec_B> +// CHECK: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["this", init] +// CHECK: cir.store %arg0, %[[THIS_ADDR]] +// CHECK: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B> + +// CHECK: cir.func{{.*}} private dso_local @_ZN1BD1Ev(!cir.ptr<!rec_B>) alias(@_ZN1BD2Ev) + +// LLVM: define{{.*}} @_ZN1BD2Ev(ptr %[[THIS_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + +// This should be an alias, like the similar OGCG alias above, but that's not +// implemented yet. +// LLVM: declare dso_local void @_ZN1BD1Ev(ptr) + +// OGCG: define{{.*}} @_ZN1BD2Ev(ptr{{.*}} %[[THIS_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] + +// The destructor in this case is handled by RAUW rather than aliasing. +struct Struk { + ~Struk() {} +}; + +void baz() { + Struk s; +} + +// CHECK: cir.func{{.*}} @_ZN5StrukD2Ev(%arg0: !cir.ptr<!rec_Struk> +// CHECK: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Struk>, !cir.ptr<!cir.ptr<!rec_Struk>>, ["this", init] +// CHECK: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_Struk>, !cir.ptr<!cir.ptr<!rec_Struk>> +// CHECK: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_Struk>>, !cir.ptr<!rec_Struk> +// CHECK: cir.return + +// CHECK-NOT: cir.func{{.*}} @_ZN5StrukD1Ev + +// CHECK: cir.func{{.*}} @_Z3bazv() +// CHECK: %[[S_ADDR:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["s"] +// CHECK: cir.call @_ZN5StrukD2Ev(%[[S_ADDR]]) nothrow : (!cir.ptr<!rec_Struk>) -> () + +// LLVM: define linkonce_odr void @_ZN5StrukD2Ev(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{{.*}} void @_Z3bazv() +// LLVM: %[[S_ADDR:.*]] = alloca %struct.Struk +// LLVM: call void @_ZN5StrukD2Ev(ptr{{.*}} %[[S_ADDR]]) + +// This function gets emitted before the destructor in OGCG. +// OGCG: define{{.*}} void @_Z3bazv() +// OGCG: %[[S_ADDR:.*]] = alloca %struct.Struk +// OGCG: call void @_ZN5StrukD2Ev(ptr{{.*}} %[[S_ADDR]]) + +// OGCG: define linkonce_odr void @_ZN5StrukD2Ev(ptr{{.*}} %[[THIS_ARG]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp new file mode 100644 index 0000000..a47ef53 --- /dev/null +++ b/clang/test/CIR/CodeGen/struct-init.cpp @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct S { + int a, b, c; +}; + +void init() { + S s1 = {1, 2, 3}; + S s2 = {4, 5}; +} + +// 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 + +// 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]] + +// 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 } + +// OGCG: define{{.*}} void @_Z4initv() +// OGCG: %[[S1:.*]] = alloca %struct.S +// OGCG: %[[S2:.*]] = alloca %struct.S +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %[[S1]], ptr{{.*}} @__const._Z4initv.s1, i64 12, i1 false) +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr{{.*}} %[[S2]], ptr{{.*}} @__const._Z4initv.s2, i64 12, i1 false) + +void init_var(int a, int b) { + S s = {a, b}; +} + +// CIR: cir.func{{.*}} @_Z8init_varii(%[[A_ARG:.*]]: !s32i {{.*}}, %[[B_ARG:.*]]: !s32i {{.*}}) +// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] +// CIR: cir.store{{.*}} %[[A_ARG]], %[[A_PTR]] +// CIR: cir.store{{.*}} %[[B_ARG]], %[[B_PTR]] +// CIR: %[[S_A:.*]] = cir.get_member %[[S]][0] {name = "a"} +// CIR: %[[A:.*]] = cir.load{{.*}} %[[A_PTR]] +// CIR: cir.store{{.*}} %[[A]], %[[S_A]] +// CIR: %[[S_B:.*]] = cir.get_member %[[S]][1] {name = "b"} +// CIR: %[[B:.*]] = cir.load{{.*}} %[[B_PTR]] +// CIR: cir.store{{.*}} %[[B]], %[[S_B]] +// CIR: cir.return + +// LLVM: define{{.*}} void @_Z8init_varii(i32 %[[A_ARG:.*]], i32 %[[B_ARG:.*]]) +// LLVM: %[[A_PTR:.*]] = alloca i32 +// LLVM: %[[B_PTR:.*]] = alloca i32 +// LLVM: %[[S:.*]] = alloca %struct.S +// LLVM: store i32 %[[A_ARG]], ptr %[[A_PTR]] +// LLVM: store i32 %[[B_ARG]], ptr %[[B_PTR]] +// LLVM: %[[S_A:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0, i32 0 +// LLVM: %[[A:.*]] = load i32, ptr %[[A_PTR]] +// LLVM: store i32 %[[A]], ptr %[[S_A]] +// LLVM: %[[S_B:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0, i32 1 +// LLVM: %[[B:.*]] = load i32, ptr %[[B_PTR]] +// LLVM: store i32 %[[B]], ptr %[[S_B]] +// LLVM: ret void + +// OGCG: define{{.*}} void @_Z8init_varii(i32 {{.*}} %[[A_ARG:.*]], i32 {{.*}} %[[B_ARG:.*]]) +// OGCG: %[[A_PTR:.*]] = alloca i32 +// OGCG: %[[B_PTR:.*]] = alloca i32 +// OGCG: %[[S:.*]] = alloca %struct.S +// OGCG: store i32 %[[A_ARG]], ptr %[[A_PTR]] +// OGCG: store i32 %[[B_ARG]], ptr %[[B_PTR]] +// OGCG: %[[S_A:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 0 +// OGCG: %[[A:.*]] = load i32, ptr %[[A_PTR]] +// OGCG: store i32 %[[A]], ptr %[[S_A]] +// OGCG: %[[S_B:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 1 +// OGCG: %[[B:.*]] = load i32, ptr %[[B_PTR]] +// OGCG: store i32 %[[B]], ptr %[[S_B]] +// OGCG: %[[S_C:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 2 +// OGCG: store i32 0, ptr %[[S_C]] +// OGCG: ret void + +void init_expr(int a, int b, int c) { + S s = {a + 1, b + 2, c + 3}; +} + +// CIR: cir.func{{.*}} @_Z9init_expriii(%[[A_ARG:.*]]: !s32i {{.*}}, %[[B_ARG:.*]]: !s32i {{.*}}, %[[C_ARG:.*]]: !s32i {{.*}}) +// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] +// CIR: %[[B_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[C_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["c", init] +// CIR: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] +// CIR: cir.store{{.*}} %[[A_ARG]], %[[A_PTR]] +// CIR: cir.store{{.*}} %[[B_ARG]], %[[B_PTR]] +// CIR: cir.store{{.*}} %[[C_ARG]], %[[C_PTR]] +// CIR: %[[S_A:.*]] = cir.get_member %[[S]][0] {name = "a"} +// CIR: %[[A:.*]] = cir.load{{.*}} %[[A_PTR]] +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> +// CIR: %[[A_PLUS_ONE:.*]] = cir.binop(add, %[[A]], %[[ONE]]) +// CIR: cir.store{{.*}} %[[A_PLUS_ONE]], %[[S_A]] +// CIR: %[[S_B:.*]] = cir.get_member %[[S]][1] {name = "b"} +// CIR: %[[B:.*]] = cir.load{{.*}} %[[B_PTR]] +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> +// CIR: %[[B_PLUS_TWO:.*]] = cir.binop(add, %[[B]], %[[TWO]]) nsw : !s32i +// CIR: cir.store{{.*}} %[[B_PLUS_TWO]], %[[S_B]] +// CIR: %[[S_C:.*]] = cir.get_member %[[S]][2] {name = "c"} +// CIR: %[[C:.*]] = cir.load{{.*}} %[[C_PTR]] +// CIR: %[[THREE:.*]] = cir.const #cir.int<3> +// CIR: %[[C_PLUS_THREE:.*]] = cir.binop(add, %[[C]], %[[THREE]]) nsw : !s32i +// CIR: cir.store{{.*}} %[[C_PLUS_THREE]], %[[S_C]] +// CIR: cir.return + +// LLVM: define{{.*}} void @_Z9init_expriii(i32 %[[A_ARG:.*]], i32 %[[B_ARG:.*]], i32 %[[C_ARG:.*]]) +// LLVM: %[[A_PTR:.*]] = alloca i32 +// LLVM: %[[B_PTR:.*]] = alloca i32 +// LLVM: %[[C_PTR:.*]] = alloca i32 +// LLVM: %[[S:.*]] = alloca %struct.S +// LLVM: store i32 %[[A_ARG]], ptr %[[A_PTR]] +// LLVM: store i32 %[[B_ARG]], ptr %[[B_PTR]] +// LLVM: store i32 %[[C_ARG]], ptr %[[C_PTR]] +// LLVM: %[[S_A:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0, i32 0 +// LLVM: %[[A:.*]] = load i32, ptr %[[A_PTR]] +// LLVM: %[[A_PLUS_ONE:.*]] = add nsw i32 %[[A]], 1 +// LLVM: store i32 %[[A_PLUS_ONE]], ptr %[[S_A]] +// LLVM: %[[S_B:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0, i32 1 +// LLVM: %[[B:.*]] = load i32, ptr %[[B_PTR]] +// LLVM: %[[B_PLUS_TWO:.*]] = add nsw i32 %[[B]], 2 +// LLVM: store i32 %[[B_PLUS_TWO]], ptr %[[S_B]] +// LLVM: %[[S_C:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0, i32 2 +// LLVM: %[[C:.*]] = load i32, ptr %[[C_PTR]] +// LLVM: %[[C_PLUS_THREE:.*]] = add nsw i32 %[[C]], 3 +// LLVM: store i32 %[[C_PLUS_THREE]], ptr %[[S_C]] +// LLVM: ret void + +// OGCG: define{{.*}} void @_Z9init_expriii(i32 {{.*}} %[[A_ARG:.*]], i32 {{.*}} %[[B_ARG:.*]], i32 {{.*}} %[[C_ARG:.*]]) +// OGCG: %[[A_PTR:.*]] = alloca i32 +// OGCG: %[[B_PTR:.*]] = alloca i32 +// OGCG: %[[C_PTR:.*]] = alloca i32 +// OGCG: %[[S:.*]] = alloca %struct.S +// OGCG: store i32 %[[A_ARG]], ptr %[[A_PTR]] +// OGCG: store i32 %[[B_ARG]], ptr %[[B_PTR]] +// OGCG: store i32 %[[C_ARG]], ptr %[[C_PTR]] +// OGCG: %[[S_A:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 0 +// OGCG: %[[A:.*]] = load i32, ptr %[[A_PTR]] +// OGCG: %[[A_PLUS_ONE:.*]] = add nsw i32 %[[A]], 1 +// OGCG: store i32 %[[A_PLUS_ONE]], ptr %[[S_A]] +// OGCG: %[[S_B:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 1 +// OGCG: %[[B:.*]] = load i32, ptr %[[B_PTR]] +// OGCG: %[[B_PLUS_TWO:.*]] = add nsw i32 %[[B]], 2 +// OGCG: store i32 %[[B_PLUS_TWO]], ptr %[[S_B]] +// OGCG: %[[S_C:.*]] = getelementptr {{.*}} %struct.S, ptr %[[S]], i32 0, i32 2 +// OGCG: %[[C:.*]] = load i32, ptr %[[C_PTR]] +// OGCG: %[[C_PLUS_THREE:.*]] = add nsw i32 %[[C]], 3 +// OGCG: store i32 %[[C_PLUS_THREE]], ptr %[[S_C]] +// OGCG: ret void |