aboutsummaryrefslogtreecommitdiff
path: root/clang/test/CIR
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/CIR')
-rw-r--r--clang/test/CIR/CodeGen/array-ctor.cpp106
-rw-r--r--clang/test/CIR/CodeGen/bitfields.c48
-rw-r--r--clang/test/CIR/CodeGen/builtin_bit.cpp72
-rw-r--r--clang/test/CIR/CodeGen/cleanup.cpp83
-rw-r--r--clang/test/CIR/CodeGen/complex-cast.cpp375
-rw-r--r--clang/test/CIR/CodeGen/complex.cpp19
-rw-r--r--clang/test/CIR/CodeGen/dtor-alias.cpp75
-rw-r--r--clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp271
-rw-r--r--clang/test/CIR/CodeGen/struct-init.cpp184
-rw-r--r--clang/test/CIR/CodeGenOpenACC/host_data.c20
-rw-r--r--clang/test/CIR/IR/array-ctor.cir29
-rw-r--r--clang/test/CIR/Lowering/poison.cir14
-rw-r--r--clang/test/CIR/Transforms/bit.cir232
-rw-r--r--clang/test/CIR/Transforms/canonicalize.cir20
14 files changed, 1546 insertions, 2 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/builtin_bit.cpp b/clang/test/CIR/CodeGen/builtin_bit.cpp
index 4ac82bd..8b9a187 100644
--- a/clang/test/CIR/CodeGen/builtin_bit.cpp
+++ b/clang/test/CIR/CodeGen/builtin_bit.cpp
@@ -216,6 +216,78 @@ int test_builtin_clzg(unsigned x) {
// 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);
}
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..a8f51cd
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-cast.cpp
@@ -0,0 +1,375 @@
+// 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
+
+void lvalue_bitcast() {
+ CX a;
+ (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: %[[A_ADDR:.*]] = alloca %struct.CX, i64 1, align 8
+// LLVM: store { double, double } zeroinitializer, ptr %[[A_ADDR]], align 8
+
+// OGCG: %[[A_ADDR]] = alloca %struct.CX, 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 double 0.000000e+00, ptr %[[A_REAL_PTR]], align 8
+// OGCG: store double 0.000000e+00, ptr %[[A_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/finegrain-bitfield-access.cpp b/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp
new file mode 100644
index 0000000..930b0a9
--- /dev/null
+++ b/clang/test/CIR/CodeGen/finegrain-bitfield-access.cpp
@@ -0,0 +1,271 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -ffine-grained-bitfield-accesses %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 -ffine-grained-bitfield-accesses %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 -ffine-grained-bitfield-accesses %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct S1 {
+ unsigned f1:2;
+ unsigned f2:6;
+ unsigned f3:8;
+ unsigned f4:4;
+ unsigned f5:8;
+};
+
+// CIR-DAG: !rec_S1 = !cir.record<struct "S1" {!u8i, !u8i, !u16i}>
+// LLVM-DAG: %struct.S1 = type { i8, i8, i16 }
+// OGCG-DAG: %struct.S1 = type { i8, i8, i16 }
+
+struct S2 {
+ unsigned long f1:16;
+ unsigned long f2:16;
+ unsigned long f3:6;
+};
+
+// CIR-DAG: !rec_S2 = !cir.record<struct "S2" padded {!u16i, !u16i, !u8i, !cir.array<!u8i x 3>}>
+// LLVM-DAG: %struct.S2 = type { i16, i16, i8, [3 x i8] }
+// OGCG-DAG: %struct.S2 = type { i16, i16, i8, [3 x i8] }
+
+struct S3 {
+ unsigned long f1:14;
+ unsigned long f2:18;
+ unsigned long f3:32;
+};
+
+// CIR-DAG: !rec_S3 = !cir.record<struct "S3" {!u32i, !u32i}>
+// LLVM-DAG: %struct.S3 = type { i32, i32 }
+// OGCG-DAG: %struct.S3 = type { i32, i32 }
+
+S1 a1;
+S2 a2;
+S3 a3;
+
+unsigned read8_1() {
+ return a1.f3;
+}
+
+// CIR-LABEL: @_Z7read8_1v
+// CIR: [[MEMBER:%.*]] = cir.get_member %1[1] {name = "f3"} : !cir.ptr<!rec_S1> -> !cir.ptr<!u8i>
+// CIR: [[BITFI:%.*]] = cir.get_bitfield align(1) (#bfi_f3, [[MEMBER]] : !cir.ptr<!u8i>) -> !u32i
+// CIR: cir.store [[BITFI]], {{.*}} : !u32i, !cir.ptr<!u32i>
+// CIR: [[RET:%.*]] = cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
+// CIR: cir.return [[RET]] : !u32i
+
+// LLVM-LABEL: @_Z7read8_1v
+// LLVM: [[MEMBER:%.*]] = load i8, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 1), align 1
+// LLVM: [[BFCAST:%.*]] = zext i8 [[MEMBER]] to i32
+// LLVM: store i32 [[BFCAST]], ptr {{.*}}, align 4
+// LLVM: [[RET:%.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: ret i32 [[RET]]
+
+// OGCG-LABEL: @_Z7read8_1v
+// OGCG: [[BFLOAD:%.*]] = load i8, ptr getelementptr inbounds nuw (%struct.S1, ptr {{.*}}, i32 0, i32 1), align 1
+// OGCG-NEXT: [[BFCAST:%.*]] = zext i8 [[BFLOAD]] to i32
+// OGCG-NEXT: ret i32 [[BFCAST]]
+
+void write8_1() {
+ a1.f3 = 3;
+}
+
+// CIR-LABEL: @_Z8write8_1v
+// CIR: [[CONST3:%.*]] = cir.const #cir.int<3> : !s32i
+// CIR: [[INT3:%.*]] = cir.cast(integral, [[CONST3]] : !s32i), !u32i
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[1] {name = "f3"} : !cir.ptr<!rec_S1> -> !cir.ptr<!u8i>
+// CIR: cir.set_bitfield align(1) (#bfi_f3, [[MEMBER]] : !cir.ptr<!u8i>, [[INT3]] : !u32i) -> !u32i
+
+// LLVM-LABEL: @_Z8write8_1v
+// LLVM: store i8 3, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 1), align 1
+// LLVM: ret void
+
+// OGCG-LABEL: @_Z8write8_1v
+// OGCG: store i8 3, ptr getelementptr inbounds nuw (%struct.S1, ptr {{.*}}, i32 0, i32 1), align 1
+// OGCG-NEXT: ret void
+
+unsigned read8_2() {
+
+ return a1.f5;
+}
+
+// CIR-LABEL: @_Z7read8_2v
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[2] {name = "f5"} : !cir.ptr<!rec_S1> -> !cir.ptr<!u16i>
+// CIR: [[BITFI:%.*]] = cir.get_bitfield align(2) (#bfi_f5, [[MEMBER]] : !cir.ptr<!u16i>) -> !u32i
+// CIR: cir.store [[BITFI]], {{.*}} : !u32i, !cir.ptr<!u32i>
+// CIR: [[RET:%.*]] = cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
+// CIR: cir.return [[RET]] : !u32i
+
+// LLVM-LABEL: @_Z7read8_2v
+// LLVM: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 2), align 2
+// LLVM: [[BFLSHR:%.*]] = lshr i16 [[BFLOAD]], 4
+// LLVM: [[BFCLEAR:%.*]] = and i16 [[BFLSHR]], 255
+// LLVM: [[BFCAST:%.*]] = zext i16 [[BFCLEAR]] to i32
+// LLVM: store i32 [[BFCAST]], ptr {{.*}}, align 4
+// LLVM: [[RET:%.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: ret i32 [[RET]]
+
+// OGCG-LABEL: @_Z7read8_2v
+// OGCG: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (%struct.S1, ptr {{.*}}, i32 0, i32 2), align 2
+// OGCG-NEXT: [[BFLSHR:%.*]] = lshr i16 [[BFLOAD]], 4
+// OGCG-NEXT: [[BFCLEAR:%.*]] = and i16 [[BFLSHR]], 255
+// OGCG-NEXT: [[BFCAST:%.*]] = zext i16 [[BFCLEAR]] to i32
+// OGCG-NEXT: ret i32 [[BFCAST]]
+
+void write8_2() {
+ a1.f5 = 3;
+}
+
+// CIR-LABEL: @_Z8write8_2v
+// CIR: [[CONST3:%.*]] = cir.const #cir.int<3> : !s32i
+// CIR: [[INT3:%.*]] = cir.cast(integral, [[CONST3]] : !s32i), !u32i
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[2] {name = "f5"} : !cir.ptr<!rec_S1> -> !cir.ptr<!u16i>
+// CIR: cir.set_bitfield align(2) (#bfi_f5, %3 : !cir.ptr<!u16i>, {{.*}} : !u32i) -> !u32i
+
+// LLVM-LABEL: @_Z8write8_2v
+// LLVM: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 2), align 2
+// LLVM: [[BFCLEAR:%.*]] = and i16 [[BFLOAD]], -4081
+// LLVM: [[BFSET:%.*]] = or i16 [[BFCLEAR]], 48
+// LLVM: store i16 [[BFSET]], ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 2), align 2
+// LLVM: ret void
+
+// OGCG-LABEL: @_Z8write8_2v
+// OGCG: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (%struct.S1, ptr {{.*}}, i32 0, i32 2), align 2
+// OGCG-NEXT: [[BFCLEAR:%.*]] = and i16 [[BFLOAD]], -4081
+// OGCG-NEXT: [[BFSET:%.*]] = or i16 [[BFCLEAR]], 48
+// OGCG-NEXT: store i16 [[BFSET]], ptr getelementptr inbounds nuw (%struct.S1, ptr {{.*}}, i32 0, i32 2), align 2
+// OGCG-NEXT: ret void
+
+unsigned read16_1() {
+ return a2.f1;
+}
+
+// CIR-LABEL: @_Z8read16_1v
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[0] {name = "f1"} : !cir.ptr<!rec_S2> -> !cir.ptr<!u16i>
+// CIR: [[BITFI:%.*]] = cir.get_bitfield align(8) (#bfi_f1, [[MEMBER]] : !cir.ptr<!u16i>) -> !u64i
+// CIR: [[BFCAST:%.*]] = cir.cast(integral, [[BITFI]] : !u64i), !u32i
+// CIR: cir.store [[BFCAST]], {{.*}} : !u32i, !cir.ptr<!u32i>
+// CIR: [[RET:%.*]] = cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
+// CIR: cir.return [[RET]] : !u32i
+
+// LLVM-LABEL: @_Z8read16_1v
+// LLVM: [[BFLOAD:%.*]] = load i16, ptr {{.*}}, align 8
+// LLVM: [[BFCAST:%.*]] = zext i16 [[BFLOAD]] to i64
+// LLVM: [[BF:%.*]] = trunc i64 [[BFCAST]] to i32
+// LLVM: store i32 [[BF]], ptr {{.*}}, align 4
+// LLVM: [[RET:%.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: ret i32 [[RET]]
+
+// OGCG-LABEL: @_Z8read16_1v
+// OGCG: [[BFLOAD:%.*]] = load i16, ptr {{.*}}, align 8
+// OGCG-NEXT: [[BFCAST:%.*]] = zext i16 [[BFLOAD]] to i64
+// OGCG-NEXT: [[RET:%.*]] = trunc i64 [[BFCAST]] to i32
+// OGCG-NEXT: ret i32 [[RET]]
+
+unsigned read16_2() {
+ return a2.f2;
+}
+
+// CIR-LABEL: @_Z8read16_2v
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[1] {name = "f2"} : !cir.ptr<!rec_S2> -> !cir.ptr<!u16i>
+// CIR: [[BITFI:%.*]] = cir.get_bitfield align(2) (#bfi_f2, [[MEMBER]] : !cir.ptr<!u16i>) -> !u64i
+// CIR: [[BFCAST:%.*]] = cir.cast(integral, [[BITFI]] : !u64i), !u32i
+// CIR: cir.store [[BFCAST]], {{.*}} : !u32i, !cir.ptr<!u32i>
+// CIR: [[RET:%.*]] = cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
+// CIR: cir.return [[RET]] : !u32i
+
+// LLVM-LABEL: @_Z8read16_2v
+// LLVM: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 2), align 2
+// LLVM: [[BFCAST:%.*]] = zext i16 [[BFLOAD]] to i64
+// LLVM: [[BF:%.*]] = trunc i64 [[BFCAST]] to i32
+// LLVM: store i32 [[BF]], ptr {{.*}}, align 4
+// LLVM: [[RET:%.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: ret i32 [[RET]]
+
+// OGCG-LABEL: @_Z8read16_2v
+// OGCG: [[BFLOAD:%.*]] = load i16, ptr getelementptr inbounds nuw (%struct.S2, ptr {{.*}}, i32 0, i32 1), align 2
+// OGCG-NEXT: [[BFCAST:%.*]] = zext i16 [[BFLOAD]] to i64
+// OGCG-NEXT: [[RET:%.*]] = trunc i64 [[BFCAST]] to i32
+// OGCG-NEXT: ret i32 [[RET]]
+
+void write16_1() {
+ a2.f1 = 5;
+}
+
+// CIR-LABEL: @_Z9write16_1v
+// CIR: [[CONST5:%.*]] = cir.const #cir.int<5> : !s32i
+// CIR: [[INT5:%.*]] = cir.cast(integral, [[CONST5]] : !s32i), !u64i
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[0] {name = "f1"} : !cir.ptr<!rec_S2> -> !cir.ptr<!u16i>
+// CIR: cir.set_bitfield align(8) (#bfi_f1, [[MEMBER]] : !cir.ptr<!u16i>, [[INT5]] : !u64i) -> !u64i
+// CIR: cir.return
+
+// LLVM-LABEL: @_Z9write16_1v
+// LLVM: store i16 5, ptr {{.*}}, align 8
+// LLVM: ret void
+
+// OGCG-LABEL: @_Z9write16_1v
+// OGCG: store i16 5, ptr {{.*}}, align 8
+// OGCG-NEXT: ret void
+
+void write16_2() {
+
+ a2.f2 = 5;
+}
+
+// CIR-LABEL: @_Z9write16_2v
+// CIR: [[CONST5:%.*]] = cir.const #cir.int<5> : !s32i
+// CIR: [[INT5:%.*]] = cir.cast(integral, [[CONST5]] : !s32i), !u64i
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[1] {name = "f2"} : !cir.ptr<!rec_S2> -> !cir.ptr<!u16i>
+// CIR: cir.set_bitfield align(2) (#bfi_f2, [[MEMBER]] : !cir.ptr<!u16i>, {{.*}} : !u64i) -> !u64i
+// CIR: cir.return
+
+// LLVM-LABEL: @_Z9write16_2v
+// LLVM: store i16 5, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 2), align 2
+// LLVM: ret void
+
+// OGCG-LABEL: @_Z9write16_2v
+// OGCG: store i16 5, ptr getelementptr inbounds nuw (%struct.S2, ptr {{.*}}, i32 0, i32 1), align 2
+// OGCG-NEXT: ret void
+
+unsigned read32_1() {
+
+ return a3.f3;
+}
+// CIR-LABEL: @_Z8read32_1v
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[1] {name = "f3"} : !cir.ptr<!rec_S3> -> !cir.ptr<!u32i>
+// CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_f3_1, [[MEMBER]] : !cir.ptr<!u32i>) -> !u64i
+// CIR: [[BFCAST:%.*]] = cir.cast(integral, [[BITFI]] : !u64i), !u32i
+// CIR: cir.store [[BFCAST]], {{.*}} : !u32i, !cir.ptr<!u32i>
+// CIR: [[RET:%.*]] = cir.load {{.*}} : !cir.ptr<!u32i>, !u32i
+// CIR: cir.return [[RET]] : !u32i
+
+// LLVM-LABEL: @_Z8read32_1v
+// LLVM: [[BFLOAD:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 4), align 4
+// LLVM: [[BFCAST:%.*]] = zext i32 [[BFLOAD]] to i64
+// LLVM: [[BF:%.*]] = trunc i64 [[BFCAST]] to i32
+// LLVM: store i32 [[BF]], ptr {{.*}}, align 4
+// LLVM: [[RET:%.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: ret i32 [[RET]]
+
+// OGCG-LABEL: @_Z8read32_1v
+// OGCG: [[BFLOAD:%.*]] = load i32, ptr getelementptr inbounds nuw (%struct.S3, ptr {{.*}}, i32 0, i32 1), align 4
+// OGCG-NEXT: [[BFCAST:%.*]] = zext i32 %bf.load to i64
+// OGCG-NEXT: [[RET:%.*]] = trunc i64 %bf.cast to i32
+// OGCG-NEXT: ret i32 [[RET]]
+
+void write32_1() {
+ a3.f3 = 5;
+}
+
+// CIR-LABEL: @_Z9write32_1v
+// CIR: [[CONST5:%.*]] = cir.const #cir.int<5> : !s32i
+// CIR: [[INT5:%.*]] = cir.cast(integral, [[CONST5]] : !s32i), !u64i
+// CIR: [[MEMBER:%.*]] = cir.get_member {{.*}}[1] {name = "f3"} : !cir.ptr<!rec_S3> -> !cir.ptr<!u32i>
+// CIR: cir.set_bitfield align(4) (#bfi_f3_1, [[MEMBER]] : !cir.ptr<!u32i>, [[INT5]] : !u64i) -> !u64i
+// CIR: cir.return
+
+// LLVM-LABEL: @_Z9write32_1v
+// LLVM: store i32 5, ptr getelementptr inbounds nuw (i8, ptr {{.*}}, i64 4), align 4
+// LLVM: ret void
+
+// OGCG-LABEL: @_Z9write32_1v
+// OGCG: store i32 5, ptr getelementptr inbounds nuw (%struct.S3, ptr {{.*}}, i32 0, i32 1), align 4
+// OGCG-NEXT: ret void
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
diff --git a/clang/test/CIR/CodeGenOpenACC/host_data.c b/clang/test/CIR/CodeGenOpenACC/host_data.c
index aeaf3d2f..fa06d2a 100644
--- a/clang/test/CIR/CodeGenOpenACC/host_data.c
+++ b/clang/test/CIR/CodeGenOpenACC/host_data.c
@@ -1,13 +1,15 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s
-void acc_host_data(int cond, int var1, int var2) {
- // CHECK: cir.func{{.*}} @acc_host_data(%[[ARG_COND:.*]]: !s32i {{.*}}, %[[ARG_V1:.*]]: !s32i {{.*}}, %[[ARG_V2:.*]]: !s32i {{.*}}) {
+void acc_host_data(int cond, int var1, int var2, int *arr) {
+ // CHECK: cir.func{{.*}} @acc_host_data(%[[ARG_COND:.*]]: !s32i {{.*}}, %[[ARG_V1:.*]]: !s32i {{.*}}, %[[ARG_V2:.*]]: !s32i {{.*}}, %[[ARG_ARR:.*]]: !cir.ptr<!s32i> {{.*}}) {
// CHECK-NEXT: %[[COND:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["cond", init]
// CHECK-NEXT: %[[V1:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["var1", init]
// CHECK-NEXT: %[[V2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["var2", init]
+ // CHECK-NEXT: %[[ARR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arr", init]
// CHECK-NEXT: cir.store %[[ARG_COND]], %[[COND]] : !s32i, !cir.ptr<!s32i>
// CHECK-NEXT: cir.store %[[ARG_V1]], %[[V1]] : !s32i, !cir.ptr<!s32i>
// CHECK-NEXT: cir.store %[[ARG_V2]], %[[V2]] : !s32i, !cir.ptr<!s32i>
+ // CHECK-NEXT: cir.store %[[ARG_ARR]], %[[ARR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
#pragma acc host_data use_device(var1)
{}
@@ -52,4 +54,18 @@ void acc_host_data(int cond, int var1, int var2) {
// CHECK-NEXT: acc.host_data if(%[[COND_CAST]]) dataOperands(%[[USE_DEV1]], %[[USE_DEV2]] : !cir.ptr<!s32i>, !cir.ptr<!s32i>) {
// CHECK-NEXT: acc.terminator
// CHECK-NEXT: } attributes {ifPresent}
+
+#pragma acc host_data use_device(arr[0:var1])
+ {}
+ // CHECK-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0>
+ // CHECK-NEXT: %[[ZERO_CAST:.*]] = builtin.unrealized_conversion_cast %[[ZERO]] : !s32i to si32
+ // CHECK-NEXT: %[[VAR1_LOAD:.*]] = cir.load{{.*}} %[[V1]] : !cir.ptr<!s32i>, !s32i
+ // CHECK-NEXT: %[[VAR1_CAST:.*]] = builtin.unrealized_conversion_cast %[[VAR1_LOAD]] : !s32i to si32
+ // CHECK-NEXT: %[[CONST_ZERO:.*]] = arith.constant 0
+ // CHECK-NEXT: %[[CONST_ONE:.*]] = arith.constant 1
+ // CHECK-NEXT: %[[BOUNDS:.*]] = acc.bounds lowerbound(%[[ZERO_CAST]] : si32) extent(%[[VAR1_CAST]] : si32) stride(%[[CONST_ONE]] : i64) startIdx(%[[CONST_ZERO]] : i64)
+ // CHECK-NEXT: %[[USE_DEV1:.*]] = acc.use_device varPtr(%[[ARR]] : !cir.ptr<!cir.ptr<!s32i>>) bounds(%[[BOUNDS]]) -> !cir.ptr<!cir.ptr<!s32i>> {name = "arr[0:var1]"}
+ // CHECK-NEXT: acc.host_data dataOperands(%[[USE_DEV1]] : !cir.ptr<!cir.ptr<!s32i>>)
+ // CHECK-NEXT: acc.terminator
+ // CHECK-NEXT: } loc
}
diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir
new file mode 100644
index 0000000..2378992
--- /dev/null
+++ b/clang/test/CIR/IR/array-ctor.cir
@@ -0,0 +1,29 @@
+
+// RUN: cir-opt %s | FileCheck %s
+
+!u8i = !cir.int<u, 8>
+!rec_S = !cir.record<struct "S" padded {!u8i}>
+
+module {
+ cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>)
+ cir.func dso_local @_Z3foov() {
+ %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64}
+ cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
+ ^bb0(%arg0: !cir.ptr<!rec_S>):
+ cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
+ cir.yield
+ }
+ cir.return
+ }
+
+ // CHECK: cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>)
+ // CHECK: cir.func dso_local @_Z3foov() {
+ // CHECK: %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64}
+ // CHECK: cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
+ // CHECK: ^bb0(%arg0: !cir.ptr<!rec_S>):
+ // CHECK: cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
+ // CHECK: cir.yield
+ // CHECK: }
+ // CHECK: cir.return
+ // CHECK: }
+}
diff --git a/clang/test/CIR/Lowering/poison.cir b/clang/test/CIR/Lowering/poison.cir
new file mode 100644
index 0000000..6f8b792
--- /dev/null
+++ b/clang/test/CIR/Lowering/poison.cir
@@ -0,0 +1,14 @@
+// RUN: cir-translate -cir-to-llvmir --disable-cc-lowering -o %t.ll %s
+// RUN: FileCheck -check-prefix=LLVM --input-file=%t.ll %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+ cir.func @lower_poison() -> !s32i {
+ %0 = cir.const #cir.poison : !s32i
+ cir.return %0 : !s32i
+ }
+ // LLVM-LABEL: @lower_poison
+ // LLVM-NEXT: ret i32 poison
+ // LLVM-NEXT: }
+}
diff --git a/clang/test/CIR/Transforms/bit.cir b/clang/test/CIR/Transforms/bit.cir
new file mode 100644
index 0000000..11f47aa
--- /dev/null
+++ b/clang/test/CIR/Transforms/bit.cir
@@ -0,0 +1,232 @@
+// RUN: cir-opt -cir-canonicalize -cir-simplify -o %t.cir %s
+// RUN: FileCheck --input-file=%t.cir %s
+
+!s32i = !cir.int<s, 32>
+!u32i = !cir.int<u, 32>
+
+module {
+ cir.func @fold_clrsb() -> !s32i {
+ %0 = cir.const #cir.int<1> : !s32i
+ %1 = cir.clrsb %0 : !s32i
+ cir.return %1 : !s32i
+ }
+ // CHECK-LABEL: @fold_clrsb
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<30> : !s32i
+ // CHECK-NEXT: cir.return %[[R]] : !s32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_clz() -> !u32i {
+ %0 = cir.const #cir.int<1> : !u32i
+ %1 = cir.clz %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_clz
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<31> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_clz_zero_poison() -> !u32i {
+ %0 = cir.const #cir.int<0> : !u32i
+ %1 = cir.clz %0 poison_zero : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_clz_zero_poison
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_clz_zero_no_poison() -> !u32i {
+ %0 = cir.const #cir.int<0> : !u32i
+ %1 = cir.clz %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_clz_zero_no_poison
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_ctz() -> !u32i {
+ %0 = cir.const #cir.int<2> : !u32i
+ %1 = cir.ctz %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_ctz
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<1> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_ctz_zero_poison() -> !u32i {
+ %0 = cir.const #cir.int<0> : !u32i
+ %1 = cir.ctz %0 poison_zero : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_ctz_zero_poison
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_ctz_zero_no_poison() -> !u32i {
+ %0 = cir.const #cir.int<0> : !u32i
+ %1 = cir.ctz %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_ctz_zero_no_poison
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_ffs() -> !s32i {
+ // 40 is 0b0010_1000
+ %0 = cir.const #cir.int<40> : !s32i
+ %1 = cir.ffs %0 : !s32i
+ cir.return %1 : !s32i
+ }
+ // CHECK-LABEL: @fold_ffs
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4> : !s32i
+ // CHECK-NEXT: cir.return %[[R]] : !s32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_ffs_zero() -> !s32i {
+ %0 = cir.const #cir.int<0> : !s32i
+ %1 = cir.ffs %0 : !s32i
+ cir.return %1 : !s32i
+ }
+ // CHECK-LABEL: @fold_ffs_zero
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<0> : !s32i
+ // CHECK-NEXT: cir.return %[[R]] : !s32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_parity() -> !u32i {
+ // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
+ // 0xdeadbeef contains 24 ones
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.parity %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_parity
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<0> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_popcount() -> !u32i {
+ // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
+ // 0xdeadbeef contains 24 ones
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.popcount %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_popcount
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<24> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_bitreverse() -> !u32i {
+ // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.bitreverse %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_bitreverse
+ // 4152210811 is 0b1111_0111_0111_1101_1011_0101_0111_1011
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4152210811> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_byte_swap() -> !u32i {
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.byte_swap %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_byte_swap
+ // 4022250974 is 0xefbeadde
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4022250974> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_input_poison() -> !s32i {
+ %0 = cir.const #cir.poison : !s32i
+ %1 = cir.clrsb %0 : !s32i
+ cir.return %1 : !s32i
+ }
+ // CHECK-LABEL: @fold_input_poison
+ // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i
+ // CHECK-NEXT: cir.return %[[P]] : !s32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_input_all_zeros(%arg0 : !u32i) -> !u32i {
+ %0 = cir.const #cir.int<0> : !u32i
+ %1 = cir.rotate left %0, %arg0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_input_all_zeros
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<0> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_input_all_ones(%arg0 : !u32i) -> !u32i {
+ // 4294967295 is 0b1111_1111_1111_1111_1111_1111_1111_1111
+ %0 = cir.const #cir.int<4294967295> : !u32i
+ %1 = cir.rotate left %0, %arg0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_input_all_ones
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4294967295> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_zero_amount(%arg0 : !u32i) -> !u32i {
+ %0 = cir.const #cir.int<32> : !u32i
+ %1 = cir.rotate left %arg0, %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_zero_amount
+ // CHECK-SAME: (%[[R:.+]]: !u32i)
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_left() -> !u32i {
+ // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.const #cir.int<8> : !u32i
+ %2 = cir.rotate left %0, %1 : !u32i
+ cir.return %2 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_left
+ // 2914971614 is 0b1010_1101_1011_1110_1110_1111_1101_1110
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<2914971614> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_right() -> !u32i {
+ // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
+ %0 = cir.const #cir.int<0xdeadbeef> : !u32i
+ %1 = cir.const #cir.int<8> : !u32i
+ %2 = cir.rotate right %0, %1 : !u32i
+ cir.return %2 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_right
+ // 4260027374 is 0b1110_1111_1101_1110_1010_1101_1011_1110
+ // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4024348094> : !u32i
+ // CHECK-NEXT: cir.return %[[R]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_input_poison(%arg0 : !u32i) -> !u32i {
+ %0 = cir.const #cir.poison : !u32i
+ %1 = cir.rotate left %0, %arg0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_input_poison
+ // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i
+ // CHECK-NEXT: cir.return %[[P]] : !u32i
+ // CHECK-NEXT: }
+
+ cir.func @fold_rotate_amount_poison(%arg0 : !u32i) -> !u32i {
+ %0 = cir.const #cir.poison : !u32i
+ %1 = cir.rotate left %arg0, %0 : !u32i
+ cir.return %1 : !u32i
+ }
+ // CHECK-LABEL: @fold_rotate_amount_poison
+ // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i
+ // CHECK-NEXT: cir.return %[[P]] : !u32i
+ // CHECK-NEXT: }
+}
diff --git a/clang/test/CIR/Transforms/canonicalize.cir b/clang/test/CIR/Transforms/canonicalize.cir
index 7ba163e..5daff11 100644
--- a/clang/test/CIR/Transforms/canonicalize.cir
+++ b/clang/test/CIR/Transforms/canonicalize.cir
@@ -39,6 +39,16 @@ module {
// CHECK: cir.func{{.*}} @unary_not(%arg0: !cir.bool) -> !cir.bool
// CHECK-NEXT: cir.return %arg0 : !cir.bool
+ cir.func @unary_poison() -> !s32i {
+ %0 = cir.const #cir.poison : !s32i
+ %1 = cir.unary(inc, %0) : !s32i, !s32i
+ cir.return %1 : !s32i
+ }
+ // CHECK: @unary_poison
+ // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i
+ // CHECK-NEXT: cir.return %[[P]] : !s32i
+ // CHECK-NEXT: }
+
cir.func @cast1(%arg0: !cir.bool) -> !cir.bool {
%0 = cir.cast(bool_to_int, %arg0 : !cir.bool), !s32i
%1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool
@@ -70,4 +80,14 @@ module {
// CHECK-NEXT: %[[CAST3:.*]] = cir.cast(integral, %[[CAST2]] : !s32i), !s64i
// CHECK-NEXT: cir.return %[[CAST3]] : !s64i
+ cir.func @cast_poison() -> !s64i {
+ %0 = cir.const #cir.poison : !s32i
+ %1 = cir.cast(integral, %0 : !s32i), !s64i
+ cir.return %1 : !s64i
+ }
+ // CHECK: @cast_poison
+ // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s64i
+ // CHECK-NEXT: cir.return %[[P]] : !s64i
+ // CHECK-NEXT: }
+
}