summaryrefslogtreecommitdiff
path: root/clang/test/CIR/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/CIR/CodeGen')
-rw-r--r--clang/test/CIR/CodeGen/atomic.c264
-rw-r--r--clang/test/CIR/CodeGen/builtin_call.cpp48
-rw-r--r--clang/test/CIR/CodeGen/builtins-elementwise.c64
-rw-r--r--clang/test/CIR/CodeGen/complex-compound-assignment.cpp290
-rw-r--r--clang/test/CIR/CodeGen/complex-mul-div.cpp490
-rw-r--r--clang/test/CIR/CodeGen/complex-plus-minus.cpp (renamed from clang/test/CIR/CodeGen/complex-arithmetic.cpp)0
-rw-r--r--clang/test/CIR/CodeGen/complex-unary.cpp135
-rw-r--r--clang/test/CIR/CodeGen/complex.cpp74
-rw-r--r--clang/test/CIR/CodeGen/constant-inits.cpp115
-rw-r--r--clang/test/CIR/CodeGen/cxx-default-init.cpp245
-rw-r--r--clang/test/CIR/CodeGen/delegating-ctor.cpp333
-rw-r--r--clang/test/CIR/CodeGen/local-vars.cpp230
-rw-r--r--clang/test/CIR/CodeGen/mms-bitfields.c75
-rw-r--r--clang/test/CIR/CodeGen/multi-vtable.cpp183
-rw-r--r--clang/test/CIR/CodeGen/new.cpp4
-rw-r--r--clang/test/CIR/CodeGen/nrvo.cpp51
-rw-r--r--clang/test/CIR/CodeGen/statement-exprs.c2
-rw-r--r--clang/test/CIR/CodeGen/throws.cpp85
-rw-r--r--clang/test/CIR/CodeGen/variable-decomposition.cpp12
-rw-r--r--clang/test/CIR/CodeGen/vbase.cpp75
-rw-r--r--clang/test/CIR/CodeGen/volatile.cpp184
-rw-r--r--clang/test/CIR/CodeGen/vtt.cpp487
22 files changed, 3392 insertions, 54 deletions
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 6c37fb7cd432..0eba2959c0eb 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -75,6 +75,35 @@ void load(int *ptr) {
// OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
// OGCG: }
+void load_n(int *ptr) {
+ int a;
+ a = __atomic_load_n(ptr, __ATOMIC_RELAXED);
+ a = __atomic_load_n(ptr, __ATOMIC_CONSUME);
+ a = __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+ a = __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+}
+
+// CIR-LABEL: @load_n
+// CIR: %{{.+}} = cir.load align(4) atomic(relaxed) %{{.+}} : !cir.ptr<!s32i>, !s32i
+// CIR: %{{.+}} = cir.load align(4) atomic(consume) %{{.+}} : !cir.ptr<!s32i>, !s32i
+// CIR: %{{.+}} = cir.load align(4) atomic(acquire) %{{.+}} : !cir.ptr<!s32i>, !s32i
+// CIR: %{{.+}} = cir.load align(4) atomic(seq_cst) %{{.+}} : !cir.ptr<!s32i>, !s32i
+// CIR: }
+
+// LLVM-LABEL: @load_n
+// LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} monotonic, align 4
+// LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} acquire, align 4
+// LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} acquire, align 4
+// LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+// LLVM: }
+
+// OGCG-LABEL: @load_n
+// OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} monotonic, align 4
+// OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} acquire, align 4
+// OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} acquire, align 4
+// OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+// OGCG: }
+
void c11_load(_Atomic(int) *ptr) {
__c11_atomic_load(ptr, __ATOMIC_RELAXED);
__c11_atomic_load(ptr, __ATOMIC_CONSUME);
@@ -127,6 +156,30 @@ void store(int *ptr, int x) {
// OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} seq_cst, align 4
// OGCG: }
+void store_n(int *ptr, int x) {
+ __atomic_store_n(ptr, x, __ATOMIC_RELAXED);
+ __atomic_store_n(ptr, x, __ATOMIC_RELEASE);
+ __atomic_store_n(ptr, x, __ATOMIC_SEQ_CST);
+}
+
+// CIR-LABEL: @store_n
+// CIR: cir.store align(4) atomic(relaxed) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store align(4) atomic(release) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>
+// CIR: }
+
+// LLVM-LABEL: @store_n
+// LLVM: store atomic i32 %{{.+}}, ptr %{{.+}} monotonic, align 4
+// LLVM: store atomic i32 %{{.+}}, ptr %{{.+}} release, align 4
+// LLVM: store atomic i32 %{{.+}}, ptr %{{.+}} seq_cst, align 4
+// LLVM: }
+
+// OGCG-LABEL: @store_n
+// OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} monotonic, align 4
+// OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} release, align 4
+// OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} seq_cst, align 4
+// OGCG: }
+
void c11_store(_Atomic(int) *ptr, int x) {
__c11_atomic_store(ptr, x, __ATOMIC_RELAXED);
__c11_atomic_store(ptr, x, __ATOMIC_RELEASE);
@@ -151,3 +204,214 @@ void c11_store(_Atomic(int) *ptr, int x) {
// OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} seq_cst, align 4
// OGCG: }
+void c11_atomic_cmpxchg_strong(_Atomic(int) *ptr, int *expected, int desired) {
+ // CIR-LABEL: @c11_atomic_cmpxchg_strong
+ // LLVM-LABEL: @c11_atomic_cmpxchg_strong
+ // OGCG-LABEL: @c11_atomic_cmpxchg_strong
+
+ __c11_atomic_compare_exchange_strong(ptr, expected, desired,
+ __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+}
+
+void c11_atomic_cmpxchg_weak(_Atomic(int) *ptr, int *expected, int desired) {
+ // CIR-LABEL: @c11_atomic_cmpxchg_weak
+ // LLVM-LABEL: @c11_atomic_cmpxchg_weak
+ // OGCG-LABEL: @c11_atomic_cmpxchg_weak
+
+ __c11_atomic_compare_exchange_weak(ptr, expected, desired,
+ __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) weak : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+}
+
+void atomic_cmpxchg(int *ptr, int *expected, int *desired) {
+ // CIR-LABEL: @atomic_cmpxchg
+ // LLVM-LABEL: @atomic_cmpxchg
+ // OGCG-LABEL: @atomic_cmpxchg
+
+ __atomic_compare_exchange(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ __atomic_compare_exchange(ptr, expected, desired, /*weak=*/1, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) weak : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+}
+
+void atomic_cmpxchg_n(int *ptr, int *expected, int desired) {
+ // CIR-LABEL: @atomic_cmpxchg_n
+ // LLVM-LABEL: @atomic_cmpxchg_n
+ // OGCG-LABEL: @atomic_cmpxchg_n
+
+ __atomic_compare_exchange_n(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ __atomic_compare_exchange_n(ptr, expected, desired, /*weak=*/1, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+ // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg(%{{.+}} : !cir.ptr<!s32i>, %{{.+}} : !s32i, %{{.+}} : !s32i, success = seq_cst, failure = acquire) align(4) weak : (!s32i, !cir.bool)
+ // CIR-NEXT: %[[FAILED:.+]] = cir.unary(not, %[[SUCCESS]]) : !cir.bool, !cir.bool
+ // CIR-NEXT: cir.if %[[FAILED]] {
+ // CIR-NEXT: cir.store align(4) %[[OLD]], %{{.+}} : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.store align(1) %[[SUCCESS]], %{{.+}} : !cir.bool, !cir.ptr<!cir.bool>
+
+ // LLVM: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // LLVM-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // LLVM-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // LLVM-NEXT: %[[FAILED:.+]] = xor i1 %[[SUCCESS]], true
+ // LLVM-NEXT: br i1 %[[FAILED]], label %[[LABEL_FAILED:.+]], label %[[LABEL_CONT:.+]]
+ // LLVM: [[LABEL_FAILED]]:
+ // LLVM-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[LABEL_CONT]]
+ // LLVM: [[LABEL_CONT]]:
+ // LLVM-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // LLVM-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+
+ // OGCG: %[[RESULT:.+]] = cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire, align 4
+ // OGCG-NEXT: %[[OLD:.+]] = extractvalue { i32, i1 } %[[RESULT]], 0
+ // OGCG-NEXT: %[[SUCCESS:.+]] = extractvalue { i32, i1 } %[[RESULT]], 1
+ // OGCG-NEXT: br i1 %[[SUCCESS]], label %[[LABEL_CONT:.+]], label %[[LABEL_FAILED:.+]]
+ // OGCG: [[LABEL_FAILED]]:
+ // OGCG-NEXT: store i32 %[[OLD]], ptr %{{.+}}, align 4
+ // OGCG-NEXT: br label %[[LABEL_CONT]]
+ // OGCG: [[LABEL_CONT]]:
+ // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8
+ // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1
+}
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp
index 09be7937a433..853d894a3311 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -211,6 +211,10 @@ void unreachable() {
// LLVM: unreachable
// LLVM: }
+// OGCG-LABEL: @_Z11unreachablev
+// OGCG: unreachable
+// OGCG: }
+
void f1();
void unreachable2() {
__builtin_unreachable();
@@ -229,6 +233,9 @@ void unreachable2() {
// LLVM-NEXT: call void @_Z2f1v()
// LLVM: }
+// OGCG-LABEL: @_Z12unreachable2v
+// OGCG: unreachable
+
void trap() {
__builtin_trap();
}
@@ -241,6 +248,10 @@ void trap() {
// LLVM: call void @llvm.trap()
// LLVM: }
+// OGCG-LABEL: @_Z4trapv
+// OGCG: call void @llvm.trap()
+// OGCG: }
+
void trap2() {
__builtin_trap();
f1();
@@ -258,3 +269,40 @@ void trap2() {
// LLVM: {{.+}}:
// LLVM-NEXT: call void @_Z2f1v()
// LLVM: }
+
+// OGCG-LABEL: define{{.*}} void @_Z5trap2v
+// OGCG: call void @llvm.trap()
+// OGCG-NEXT: call void @_Z2f1v()
+// OGCG: ret void
+// OGCG: }
+
+void *test_alloca(unsigned long n) {
+ return __builtin_alloca(n);
+}
+
+// CIR-LABEL: @_Z11test_allocam(
+// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"]
+
+// LLVM-LABEL: @_Z11test_allocam(
+// LLVM: alloca i8, i64 %{{.+}}
+
+// OGCG-LABEL: @_Z11test_allocam(
+// OGCG: alloca i8, i64 %{{.+}}
+
+bool test_multiple_allocas(unsigned long n) {
+ void *a = __builtin_alloca(n);
+ void *b = __builtin_alloca(n);
+ return a != b;
+}
+
+// CIR-LABEL: @_Z21test_multiple_allocasm(
+// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"]
+// CIR: %{{.+}} = cir.alloca !u8i, !cir.ptr<!u8i>, %{{.+}} : !u64i, ["bi_alloca"]
+
+// LLVM-LABEL: @_Z21test_multiple_allocasm(
+// LLVM: alloca i8, i64 %{{.+}}
+// LLVM: alloca i8, i64 %{{.+}}
+
+// OGCG-LABEL: @_Z21test_multiple_allocasm(
+// OGCG: alloca i8, i64 %{{.+}}
+// OGCG: alloca i8, i64 %{{.+}}
diff --git a/clang/test/CIR/CodeGen/builtins-elementwise.c b/clang/test/CIR/CodeGen/builtins-elementwise.c
new file mode 100644
index 000000000000..431558d7e969
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtins-elementwise.c
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+typedef int vint4 __attribute__((ext_vector_type(4)));
+typedef float vfloat4 __attribute__((ext_vector_type(4)));
+typedef double vdouble4 __attribute__((ext_vector_type(4)));
+
+void test_builtin_elementwise_acos(float f, double d, vfloat4 vf4,
+ vdouble4 vd4) {
+ // CIR-LABEL: test_builtin_elementwise_acos
+ // LLVM-LABEL: test_builtin_elementwise_acos
+ // OGCG-LABEL: test_builtin_elementwise_acos
+
+ // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.float
+ // LLVM: %{{.*}} = call float @llvm.acos.f32(float %{{.*}})
+ // OGCG: %{{.*}} = call float @llvm.acos.f32(float %{{.*}})
+ f = __builtin_elementwise_acos(f);
+
+ // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.double
+ // LLVM: %{{.*}} = call double @llvm.acos.f64(double %{{.*}})
+ // OGCG: %{{.*}} = call double @llvm.acos.f64(double %{{.*}})
+ d = __builtin_elementwise_acos(d);
+
+ // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.vector<4 x !cir.float>
+ // LLVM: %{{.*}} = call <4 x float> @llvm.acos.v4f32(<4 x float> %{{.*}})
+ // OGCG: %{{.*}} = call <4 x float> @llvm.acos.v4f32(<4 x float> %{{.*}})
+ vf4 = __builtin_elementwise_acos(vf4);
+
+ // CIR: %{{.*}} = cir.acos %{{.*}} : !cir.vector<4 x !cir.double>
+ // LLVM: %{{.*}} = call <4 x double> @llvm.acos.v4f64(<4 x double> %{{.*}})
+ // OGCG: %{{.*}} = call <4 x double> @llvm.acos.v4f64(<4 x double> %{{.*}})
+ vd4 = __builtin_elementwise_acos(vd4);
+}
+
+void test_builtin_elementwise_asin(float f, double d, vfloat4 vf4,
+ vdouble4 vd4) {
+ // CIR-LABEL: test_builtin_elementwise_asin
+ // LLVM-LABEL: test_builtin_elementwise_asin
+ // OGCG-LABEL: test_builtin_elementwise_asin
+
+ // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.float
+ // LLVM: %{{.*}} = call float @llvm.asin.f32(float %{{.*}})
+ // OGCG: %{{.*}} = call float @llvm.asin.f32(float %{{.*}})
+ f = __builtin_elementwise_asin(f);
+
+ // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.double
+ // LLVM: %{{.*}} = call double @llvm.asin.f64(double %{{.*}})
+ // OGCG: %{{.*}} = call double @llvm.asin.f64(double %{{.*}})
+ d = __builtin_elementwise_asin(d);
+
+ // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.vector<4 x !cir.float>
+ // LLVM: %{{.*}} = call <4 x float> @llvm.asin.v4f32(<4 x float> %{{.*}})
+ // OGCG: %{{.*}} = call <4 x float> @llvm.asin.v4f32(<4 x float> %{{.*}})
+ vf4 = __builtin_elementwise_asin(vf4);
+
+ // CIR: %{{.*}} = cir.asin %{{.*}} : !cir.vector<4 x !cir.double>
+ // LLVM: %{{.*}} = call <4 x double> @llvm.asin.v4f64(<4 x double> %{{.*}})
+ // OGCG: %{{.*}} = call <4 x double> @llvm.asin.v4f64(<4 x double> %{{.*}})
+ vd4 = __builtin_elementwise_asin(vd4);
+}
diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
index 9a6659bd5d93..9909985e7819 100644
--- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
+++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
@@ -198,9 +198,9 @@ void foo3() {
// LLVM: %[[RESULT_REAL:.*]] = extractvalue { float, float } %[[RESULT]], 0
// LLVM: %[[RESULT_IMAG:.*]] = extractvalue { float, float } %[[RESULT]], 1
// LLVM: %[[RESULT_REAL_F16:.*]] = fptrunc float %[[RESULT_REAL]] to half
-// LLVM: %[[RESULT_IMAG_F26:.*]] = fptrunc float %[[RESULT_IMAG]] to half
+// LLVM: %[[RESULT_IMAG_F16:.*]] = fptrunc float %[[RESULT_IMAG]] to half
// LLVM: %[[TMP_RESULT_F16:.*]] = insertvalue { half, half } undef, half %[[RESULT_REAL_F16]], 0
-// LLVM: %[[RESULT_F16:.*]] = insertvalue { half, half } %29, half %[[RESULT_IMAG_F26]], 1
+// LLVM: %[[RESULT_F16:.*]] = insertvalue { half, half } %29, half %[[RESULT_IMAG_F16]], 1
// LLVM: store { half, half } %[[RESULT_F16]], ptr %[[B_ADDR]], align 2
// OGCG: %[[A_ADDR:.*]] = alloca { half, half }, align 2
@@ -534,6 +534,292 @@ void foo8() {
// OGCG: store float %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
+void foo10() {
+ float _Complex a;
+ float _Complex b;
+ a /= b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT:.*]] = cir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
+// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
+// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
+// LLVM: %[[RESULT:.*]] = call { float, float } @__divsc3(float %[[A_REAL]], float %[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]])
+// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[RESULT_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[RESULT:.*]] = call{{.*}} <2 x float> @__divsc3(float noundef %[[A_REAL]], float noundef %[[A_IMAG]], float noundef %[[B_REAL]], float noundef %[[B_IMAG]])
+// OGCG: store <2 x float> %[[RESULT]], ptr %[[RESULT_ADDR]], align 4
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 0
+// OGCG: %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 1
+// OGCG: %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], 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 %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
+// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
+
+void foo11() {
+ float _Complex a;
+ float b;
+ a /= b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b"]
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT_REAL:.*]] = cir.binop(div, %[[A_REAL]], %[[TMP_B]]) : !cir.float
+// CIR: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[A_IMAG]], %[[TMP_B]]) : !cir.float
+// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
+// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
+// LLVM: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
+// LLVM: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
+// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1
+// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca float, align 4
+// OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
+// OGCG: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
+// 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 %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
+// OGCG: store float %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
+
+void foo12() {
+ int _Complex a;
+ int b;
+ a /= b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b"]
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[B_COMPLEX:.*]] = cir.complex.create %[[TMP_B]], %[[CONST_0]] : !s32i -> !cir.complex<!s32i>
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
+// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
+// CIR: %[[B_REAL:.*]] = cir.complex.real %[[B_COMPLEX]] : !cir.complex<!s32i> -> !s32i
+// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[B_COMPLEX]] : !cir.complex<!s32i> -> !s32i
+// CIR: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !s32i
+// CIR: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !s32i
+// CIR: %[[MUL_BR_BR:.*]] = cir.binop(mul, %[[B_REAL]], %[[B_REAL]]) : !s32i
+// CIR: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[B_IMAG]]) : !s32i
+// CIR: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !s32i
+// CIR: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !s32i
+// CIR: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !s32i
+// CIR: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !s32i
+// CIR: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !s32i
+// CIR: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !s32i
+// CIR: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !s32i
+// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !s32i -> !cir.complex<!s32i>
+// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM: %[[TMP_B_COMPLEX:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[TMP_B]], 0
+// LLVM: %[[B_COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_B_COMPLEX]], i32 0, 1
+// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4
+// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1
+// LLVM: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
+// LLVM: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
+// LLVM: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
+// LLVM: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// LLVM: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
+// LLVM: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// LLVM: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
+// LLVM: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
+// LLVM: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// LLVM: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// LLVM: %[[TMP_RESULT:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[RESULT_REAL]], 0
+// LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } %[[TMP_RESULT]], i32 %[[RESULT_IMAG]], 1
+// LLVM: store { i32, i32 } %[[RESULT]], ptr %[[A_ADDR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
+// OGCG: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
+// OGCG: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// OGCG: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
+// OGCG: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
+// OGCG: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
+// OGCG: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
+// OGCG: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// OGCG: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// OGCG: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: store i32 %[[RESULT_REAL]], ptr %[[A_REAL_PTR]], align 4
+// OGCG: store i32 %[[RESULT_IMAG]], ptr %[[A_IMAG_PTR]], align 4
+
+void foo13() {
+ _Float16 _Complex a;
+ _Float16 _Complex b;
+ b /= (a / b);
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["b"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[A_REAL_F32:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.f16), !cir.float
+// CIR: %[[A_IMAG_F32:.*]] = cir.cast(floating, %[[A_IMAG]] : !cir.f16), !cir.float
+// CIR: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[B_REAL_F32:.*]] = cir.cast(floating, %[[B_REAL]] : !cir.f16), !cir.float
+// CIR: %[[B_IMAG_F32:.*]] = cir.cast(floating, %[[B_IMAG]] : !cir.f16), !cir.float
+// CIR: %[[B_COMPLEX_F32:.*]] = cir.complex.create %[[B_REAL_F32]], %[[B_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[A_IMAG_F32:.*]] = cir.complex.imag %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[B_REAL_F32:.*]] = cir.complex.real %[[B_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[B_IMAG_F32:.*]] = cir.complex.imag %[[B_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[DIV_A_B:.*]] = cir.call @__divsc3(%[[A_REAL_F32]], %[[A_IMAG_F32]], %[[B_REAL_F32]], %[[B_IMAG_F32]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR: %[[B_REAL_F32:.*]] = cir.cast(floating, %[[B_REAL]] : !cir.f16), !cir.float
+// CIR: %[[B_IMAG_F32:.*]] = cir.cast(floating, %[[B_IMAG]] : !cir.f16), !cir.float
+// CIR: %[[B_COMPLEX_F32:.*]] = cir.complex.create %[[B_REAL_F32]], %[[B_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: %[[B_REAL_F32:.*]] = cir.complex.real %[[B_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[B_IMAG_F32:.*]] = cir.complex.imag %[[B_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[DIV_AB_REAL:.*]] = cir.complex.real %[[DIV_A_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[DIV_AB_IMAG:.*]] = cir.complex.imag %[[DIV_A_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT:.*]] = cir.call @__divsc3(%[[B_REAL_F32]], %[[B_IMAG_F32]], %[[DIV_AB_REAL]], %[[DIV_AB_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float>
+// CIR: %[[RESULT_REAL_F32:.*]] = cir.complex.real %[[RESULT]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT_IMAG_F32:.*]] = cir.complex.imag %[[RESULT]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT_REAL_F16:.*]] = cir.cast(floating, %[[RESULT_REAL_F32]] : !cir.float), !cir.f16
+// CIR: %[[RESULT_IMAG_F16:.*]] = cir.cast(floating, %[[RESULT_IMAG_F32]] : !cir.float), !cir.f16
+// CIR: %[[RESULT_COMPLEX_F16:.*]] = cir.complex.create %[[RESULT_REAL_F16]], %[[RESULT_IMAG_F16]] : !cir.f16 -> !cir.complex<!cir.f16>
+// CIR: cir.store{{.*}} %[[RESULT_COMPLEX_F16]], %[[B_ADDR]] : !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[B_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[TMP_A:.*]] = load { half, half }, ptr %[[A_ADDR]], align 2
+// LLVM: %[[A_REAL:.*]] = extractvalue { half, half } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { half, half } %[[TMP_A]], 1
+// LLVM: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// LLVM: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// LLVM: %[[TMP_A_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[A_REAL_F32]], 0
+// LLVM: %[[A_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_A_COMPLEX_F32]], float %[[A_IMAG_F32]], 1
+// LLVM: %[[TMP_B:.*]] = load { half, half }, ptr %[[B_ADDR]], align 2
+// LLVM: %[[B_REAL:.*]] = extractvalue { half, half } %[[TMP_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { half, half } %[[TMP_B]], 1
+// LLVM: %[[B_REAL_F32:.*]] = fpext half %[[B_REAL]] to float
+// LLVM: %[[B_IMAG_F32:.*]] = fpext half %[[B_IMAG]] to float
+// LLVM: %[[TMP_B_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[B_REAL_F32]], 0
+// LLVM: %[[B_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_B_COMPLEX_F32]], float %[[B_IMAG_F32]], 1
+// LLVM: %[[DIV_A_B:.*]] = call { float, float } @__divsc3(float %[[A_REAL_F32]], float %[[A_IMAG_F32]], float %[[B_REAL_F32]], float %[[B_IMAG_F32]])
+// LLVM: %[[TMP_B:.*]] = load { half, half }, ptr %[[B_ADDR]], align 2
+// LLVM: %[[B_REAL:.*]] = extractvalue { half, half } %[[TMP_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { half, half } %[[TMP_B]], 1
+// LLVM: %[[B_REAL_F32:.*]] = fpext half %[[B_REAL]] to float
+// LLVM: %[[B_IMAG_F32:.*]] = fpext half %[[B_IMAG]] to float
+// LLVM: %[[TMP_B_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[B_REAL_F32]], 0
+// LLVM: %[[B_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_B_COMPLEX_F32]], float %[[B_IMAG_F32]], 1
+// LLVM: %[[DIV_AB_REAL:.*]] = extractvalue { float, float } %[[DIV_A_B]], 0
+// LLVM: %[[DIV_AB_IMAG:.*]] = extractvalue { float, float } %[[DIV_A_B]], 1
+// LLVM: %[[RESULT:.*]] = call { float, float } @__divsc3(float %[[B_REAL_F32]], float %[[B_IMAG_F32]], float %[[DIV_AB_REAL]], float %[[DIV_AB_IMAG]])
+// LLVM: %[[RESULT_REAL_F32:.*]] = extractvalue { float, float } %[[RESULT]], 0
+// LLVM: %[[RESULT_IMAG_F32:.*]] = extractvalue { float, float } %[[RESULT]], 1
+// LLVM: %[[RESULT_REAL_F16:.*]] = fptrunc float %[[RESULT_REAL_F32]] to half
+// LLVM: %[[RESULT_IMAG_F16:.*]] = fptrunc float %[[RESULT_IMAG_F32]] to half
+// LLVM: %[[TMP_RESULT_F16:.*]] = insertvalue { half, half } {{.*}}, half %[[RESULT_REAL_F16]], 0
+// LLVM: %[[RESULT_COMPLEX_F16:.*]] = insertvalue { half, half } %[[TMP_RESULT_F16]], half %[[RESULT_IMAG_F16]], 1
+// LLVM: store { half, half } %[[RESULT_COMPLEX_F16]], ptr %[[B_ADDR]], align 2
+
+// OGCG: %[[A_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[B_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[DIV_AB_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[DIV_B_AB_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load half, ptr %[[A_REAL_PTR]], align 2
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load half, ptr %[[A_IMAG_PTR]], align 2
+// OGCG: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// OGCG: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_REAL:.*]] = load half, ptr %[[B_REAL_PTR]], align 2
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load half, ptr %[[B_IMAG_PTR]], align 2
+// OGCG: %[[B_REAL_F32:.*]] = fpext half %[[B_REAL]] to float
+// OGCG: %[[B_IMAG_F32:.*]] = fpext half %[[B_IMAG]] to float
+// OGCG: %[[DIV_A_B:.*]] = call{{.*}} <2 x float> @__divsc3(float noundef %[[A_REAL_F32]], float noundef %[[A_IMAG_F32]], float noundef %[[B_REAL_F32]], float noundef %[[B_IMAG_F32]])
+// OGCG: store <2 x float> %[[DIV_A_B]], ptr %[[DIV_AB_ADDR]], align 4
+// OGCG: %[[DIV_AB_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DIV_AB_ADDR]], i32 0, i32 0
+// OGCG: %[[DIV_AB_REAL:.*]] = load float, ptr %[[DIV_AB_REAL_PTR]], align 4
+// OGCG: %[[DIV_AB_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DIV_AB_ADDR]], i32 0, i32 1
+// OGCG: %[[DIV_AB_IMAG:.*]] = load float, ptr %[[DIV_AB_IMAG_PTR]], align 4
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_REAL:.*]] = load half, ptr %[[B_REAL_PTR]], align 2
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load half, ptr %[[B_IMAG_PTR]], align 2
+// OGCG: %[[B_REAL_F32:.*]] = fpext half %[[B_REAL]] to float
+// OGCG: %[[B_IMAG_F32:.*]] = fpext half %[[B_IMAG]] to float
+// OGCG: %[[RESULT:.*]] = call{{.*}} <2 x float> @__divsc3(float noundef %[[B_REAL_F32]], float noundef %[[B_IMAG_F32]], float noundef %[[DIV_AB_REAL]], float noundef %[[DIV_AB_IMAG]])
+// OGCG: store <2 x float> %[[RESULT]], ptr %[[DIV_B_AB_ADDR]], align 4
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DIV_B_AB_ADDR]], i32 0, i32 0
+// OGCG: %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[DIV_B_AB_ADDR]], i32 0, i32 1
+// OGCG: %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
+// OGCG: %[[RESULT_REAL_F16:.*]] = fptrunc float %[[RESULT_REAL]] to half
+// OGCG: %[[RESULT_IMAG_F16:.*]] = fptrunc float %[[RESULT_IMAG]] to half
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store half %[[RESULT_REAL_F16]], ptr %[[B_REAL_PTR]], align 2
+// OGCG: store half %[[RESULT_IMAG_F16]], ptr %[[B_IMAG_PTR]], align 2
+
#ifndef __cplusplus
void foo9() {
float _Complex a;
diff --git a/clang/test/CIR/CodeGen/complex-mul-div.cpp b/clang/test/CIR/CodeGen/complex-mul-div.cpp
index 0fb82b24f664..d49304660b4d 100644
--- a/clang/test/CIR/CodeGen/complex-mul-div.cpp
+++ b/clang/test/CIR/CodeGen/complex-mul-div.cpp
@@ -352,7 +352,7 @@ void foo3() {
// CIR-AFTER-BASIC: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float
// CIR-AFTER-BASIC: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float
// CIR-AFTER-BASIC: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !cir.float
-// CIR-AFTER-BASIC: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %14) : !cir.float
+// CIR-AFTER-BASIC: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !cir.float
// CIR-AFTER-BASIC: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
// CIR-AFTER-BASIC: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
@@ -559,7 +559,7 @@ void foo3() {
// CIR-AFTER-PROMOTED: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG_F64]], %[[B_IMAG_F64]]) : !cir.double
// CIR-AFTER-PROMOTED: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.double
// CIR-AFTER-PROMOTED: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !cir.double
-// CIR-AFTER-PROMOTED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %18) : !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !cir.double
// CIR-AFTER-PROMOTED: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG_F64]], %[[B_REAL_F64]]) : !cir.double
// CIR-AFTER-PROMOTED: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL_F64]], %[[B_IMAG_F64]]) : !cir.double
// CIR-AFTER-PROMOTED: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !cir.double
@@ -773,3 +773,489 @@ void foo4() {
// OGCG-COMBINED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1
// OGCG-COMBINED: store i32 %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
// OGCG-COMBINED: store i32 %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+void foo5() {
+ float _Complex a;
+ float b;
+ float _Complex c = a / b;
+}
+
+// CIR-COMBINED: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR-COMBINED: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b"]
+// CIR-COMBINED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init]
+// CIR-COMBINED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR-COMBINED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR-COMBINED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-COMBINED: %[[A_IMGA:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-COMBINED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[A_REAL]], %[[TMP_B]]) : !cir.float
+// CIR-COMBINED: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[A_IMAG]], %[[TMP_B]]) : !cir.float
+// CIR-COMBINED: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-COMBINED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM-COMBINED: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-COMBINED: %[[B_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM-COMBINED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-COMBINED: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM-COMBINED: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
+// LLVM-COMBINED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0
+// LLVM-COMBINED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
+// LLVM-COMBINED: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
+// LLVM-COMBINED: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
+// LLVM-COMBINED: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM-COMBINED: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1
+// LLVM-COMBINED: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4
+
+// OGCG-COMBINED: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-COMBINED: %[[B_ADDR:.*]] = alloca float, align 4
+// OGCG-COMBINED: %[[C_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-COMBINED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG-COMBINED: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
+// OGCG-COMBINED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG-COMBINED: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
+// OGCG-COMBINED: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
+// OGCG-COMBINED: %[[RESULT_REAL:.*]] = fdiv float %[[A_REAL]], %[[TMP_B]]
+// OGCG-COMBINED: %[[RESULT_IMAG:.*]] = fdiv float %[[A_IMAG]], %[[TMP_B]]
+// OGCG-COMBINED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-COMBINED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-COMBINED: store float %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-COMBINED: store float %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+void foo6() {
+ float a;
+ float _Complex b;
+ float _Complex c = a / b;
+}
+
+// CIR-BEFORE-BASIC: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(basic) : !cir.complex<!cir.float>
+
+// CIR-AFTER-BASIC: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"]
+// CIR-AFTER-BASIC: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR-AFTER-BASIC: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init]
+// CIR-AFTER-BASIC: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR-AFTER-BASIC: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR-AFTER-BASIC: %[[CONST_0:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR-AFTER-BASIC: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-BASIC: %[[A_REAL:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-BASIC: %[[A_IMAG:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-BASIC: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-BASIC: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-BASIC: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !cir.float
+// CIR-AFTER-BASIC: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !cir.float
+// CIR-AFTER-BASIC: %[[MUL_BR_BR:.*]] = cir.binop(mul, %[[B_REAL]], %[[B_REAL]]) : !cir.float
+// CIR-AFTER-BASIC: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[B_IMAG]]) : !cir.float
+// CIR-AFTER-BASIC: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.float
+// CIR-AFTER-BASIC: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !cir.float
+// CIR-AFTER-BASIC: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !cir.float
+// CIR-AFTER-BASIC: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float
+// CIR-AFTER-BASIC: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float
+// CIR-AFTER-BASIC: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !cir.float
+// CIR-AFTER-BASIC: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !cir.float
+// CIR-AFTER-BASIC: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-BASIC: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM-BASIC: %[[A_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM-BASIC: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-BASIC: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-BASIC: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// LLVM-BASIC: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
+// LLVM-BASIC: %[[TMP_COMPELX_A:.*]] = insertvalue { float, float } undef, float %[[TMP_A]], 0
+// LLVM-BASIC: %[[COMPLEX_A:.*]] = insertvalue { float, float } %[[TMP_COMPELX_A]], float 0.000000e+00, 1
+// LLVM-BASIC: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
+// LLVM-BASIC: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
+// LLVM-BASIC: %[[MUL_AR_BR:.*]] = fmul float %[[TMP_A]], %[[B_REAL]]
+// LLVM-BASIC: %[[MUL_AI_BI:.*]] = fmul float 0.000000e+00, %[[B_IMAG]]
+// LLVM-BASIC: %[[MUL_BR_BR:.*]] = fmul float %[[B_REAL]], %[[B_REAL]]
+// LLVM-BASIC: %[[MUL_BI_BI:.*]] = fmul float %[[B_IMAG]], %[[B_IMAG]]
+// LLVM-BASIC: %[[ADD_ARBR_AIBI:.*]] = fadd float %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// LLVM-BASIC: %[[ADD_BRBR_BIBI:.*]] = fadd float %[[MUL_BR_BR]], %[[MUL_BI_BI]]
+// LLVM-BASIC: %[[RESULT_REAL:.*]] = fdiv float %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-BASIC: %[[MUL_AI_BR:.*]] = fmul float 0.000000e+00, %[[B_REAL]]
+// LLVM-BASIC: %[[MUL_BR_BI:.*]] = fmul float %[[TMP_A]], %[[B_IMAG]]
+// LLVM-BASIC: %[[SUB_AIBR_BRBI:.*]] = fsub float %[[MUL_AI_BR]], %[[MUL_BR_BI]]
+// LLVM-BASIC: %[[RESULT_IMAG:.*]] = fdiv float %[[SUB_AIBR_BRBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-BASIC: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM-BASIC: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[RESULT_IMAG]], 1
+// LLVM-BASIC: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4
+
+// OGCG-BASIC: %[[A_ADDR:.*]] = alloca float, align 4
+// OGCG-BASIC: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-BASIC: %[[C_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-BASIC: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// OGCG-BASIC: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG-BASIC: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
+// OGCG-BASIC: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG-BASIC: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
+// OGCG-BASIC: %[[MUL_AR_BR:.*]] = fmul float %[[TMP_A]], %[[B_REAL]]
+// OGCG-BASIC: %[[MUL_AI_BI:.*]] = fmul float 0.000000e+00, %[[B_IMAG]]
+// OGCG-BASIC: %[[ADD_ARBR_AIBI:.*]] = fadd float %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// OGCG-BASIC: %[[MUL_BR_BR:.*]] = fmul float %[[B_REAL]], %[[B_REAL]]
+// OGCG-BASIC: %[[MUL_BI_BI:.*]] = fmul float %[[B_IMAG]], %[[B_IMAG]]
+// OGCG-BASIC: %[[ADD_BRBR_BIBI:.*]] = fadd float %[[MUL_BR_BR]], %[[MUL_BI_BI]]
+// OGCG-BASIC: %[[MUL_AI_BR:.*]] = fmul float 0.000000e+00, %[[B_REAL]]
+// OGCG-BASIC: %[[MUL_AR_BI:.*]] = fmul float %[[TMP_A]], %[[B_IMAG]]
+// OGCG-BASIC: %[[SUB_AIBR_BRBI:.*]] = fsub float %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// OGCG-BASIC: %[[RESULT_REAL:.*]] = fdiv float %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-BASIC: %[[RESULT_IMAG:.*]] = fdiv float %[[SUB_AIBR_BRBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-BASIC: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-BASIC: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-BASIC: store float %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-BASIC: store float %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+// CIR-BEFORE-IMPROVED: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(improved) : !cir.complex<!cir.float>
+
+// CIR-AFTER-IMPROVED: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"]
+// CIR-AFTER-IMPROVED: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR-AFTER-IMPROVED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init]
+// CIR-AFTER-IMPROVED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR-AFTER-IMPROVED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: %[[CONST_0:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR-AFTER-IMPROVED: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: %[[A_REAL:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-IMPROVED: %[[A_IMAG:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-IMPROVED: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-IMPROVED: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-IMPROVED: %[[ABS_B_REAL:.*]] = cir.fabs %[[B_REAL]] : !cir.float
+// CIR-AFTER-IMPROVED: %[[ABS_B_IMAG:.*]] = cir.fabs %[[B_IMAG]] : !cir.float
+// CIR-AFTER-IMPROVED: %[[ABS_B_CMP:.*]] = cir.cmp(ge, %[[ABS_B_REAL]], %[[ABS_B_IMAG]]) : !cir.float, !cir.bool
+// CIR-AFTER-IMPROVED: %[[RESULT:.*]] = cir.ternary(%[[ABS_B_CMP]], true {
+// CIR-AFTER-IMPROVED: %[[DIV_BI_BR:.*]] = cir.binop(div, %[[B_IMAG]], %[[B_REAL]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_DIV_BIBR_BI:.*]] = cir.binop(mul, %[[DIV_BI_BR]], %[[B_IMAG]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[ADD_BR_MUL_DIV_BIBR_BI:.*]] = cir.binop(add, %[[B_REAL]], %[[MUL_DIV_BIBR_BI]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_AI_DIV_BIBR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[DIV_BI_BR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[ADD_AR_MUL_AI_DIV_BIBR:.*]] = cir.binop(add, %[[A_REAL]], %[[MUL_AI_DIV_BIBR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_AR_MUL_AI_DIV_BIBR]], %[[ADD_BR_MUL_DIV_BIBR_BI]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_AR_DIV_BIBR:.*]] = cir.binop(mul, %[[A_REAL]], %[[DIV_BI_BR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[SUB_AI_MUL_AR_DIV_BIBR:.*]] = cir.binop(sub, %[[A_IMAG]], %[[MUL_AR_DIV_BIBR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AI_MUL_AR_DIV_BIBR]], %[[ADD_BR_MUL_DIV_BIBR_BI]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_COMPLEX:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: cir.yield %[[RESULT_COMPLEX]] : !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: }, false {
+// CIR-AFTER-IMPROVED: %[[DIV_BR_BI:.*]] = cir.binop(div, %[[B_REAL]], %[[B_IMAG]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_DIV_BRBI_BR:.*]] = cir.binop(mul, %[[DIV_BR_BI]], %[[B_REAL]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[ADD_BI_MUL_DIV_BRBI_BR:.*]] = cir.binop(add, %[[B_IMAG]], %[[MUL_DIV_BRBI_BR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_AR_DIV_BIBR:.*]] = cir.binop(mul, %[[A_REAL]], %[[DIV_BR_BI]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[ADD_MUL_AR_DIV_BRBI_AI:.*]] = cir.binop(add, %[[MUL_AR_DIV_BIBR]], %[[A_IMAG]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_MUL_AR_DIV_BRBI_AI]], %[[ADD_BI_MUL_DIV_BRBI_BR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[MUL_AI_DIV_BRBI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[DIV_BR_BI]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[SUB_MUL_AI_DIV_BRBI_AR:.*]] = cir.binop(sub, %[[MUL_AI_DIV_BRBI]], %[[A_REAL]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_MUL_AI_DIV_BRBI_AR]], %[[ADD_BI_MUL_DIV_BRBI_BR]]) : !cir.float
+// CIR-AFTER-IMPROVED: %[[RESULT_COMPLEX:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: cir.yield %[[RESULT_COMPLEX]] : !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: }) : (!cir.bool) -> !cir.complex<!cir.float>
+// CIR-AFTER-IMPROVED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM-IMPROVED: %[[A_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM-IMPROVED: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-IMPROVED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-IMPROVED: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// LLVM-IMPROVED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
+// LLVM-IMPROVED: %[[TMP_COMPLEX_A:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_A]], 0
+// LLVM-IMPROVED: %[[COMPLEX_A:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_A]], float 0.000000e+00, 1
+// LLVM-IMPROVED: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
+// LLVM-IMPROVED: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
+// LLVM-IMPROVED: %[[ABS_B_REAL:.*]] = call float @llvm.fabs.f32(float %[[B_REAL]])
+// LLVM-IMPROVED: %[[ABS_B_IMAG:.*]] = call float @llvm.fabs.f32(float %[[B_IMAG]])
+// LLVM-IMPROVED: %[[ABS_B_CMP:.*]] = fcmp oge float %[[ABS_B_REAL]], %[[ABS_B_IMAG]]
+// LLVM-IMPROVED: br i1 %[[ABS_B_CMP]], label %[[ABS_BR_GT_ABS_BI:.*]], label %[[ABS_BR_LT_ABS_BI:.*]]
+// LLVM-IMPROVED: [[ABS_BR_GT_ABS_BI]]:
+// LLVM-IMPROVED: %[[DIV_BI_BR:.*]] = fdiv float %[[B_IMAG]], %[[B_REAL]]
+// LLVM-IMPROVED: %[[MUL_DIV_BIBR_BI:.*]] = fmul float %[[DIV_BI_BR]], %[[B_IMAG]]
+// LLVM-IMPROVED: %[[ADD_BR_MUL_DIV_BIBR_BI:.*]] = fadd float %[[B_REAL]], %[[MUL_DIV_BIBR_BI]]
+// LLVM-IMPROVED: %[[MUL_AI_DIV_BIBR:.*]] = fmul float 0.000000e+00, %[[DIV_BI_BR]]
+// LLVM-IMPROVED: %[[ADD_AR_MUL_AI_DIV_BIBR:.*]] = fadd float %[[TMP_A]], %[[MUL_AI_DIV_BIBR]]
+// LLVM-IMPROVED: %[[RESULT_REAL:.*]] = fdiv float %[[ADD_AR_MUL_AI_DIV_BIBR]], %16
+// LLVM-IMPROVED: %[[MUL_AR_DIV_BIBR:.*]] = fmul float %[[TMP_A]], %[[DIV_BI_BR]]
+// LLVM-IMPROVED: %[[SUB_AI_MUL_AR_DIV_BIBR:.*]] = fsub float 0.000000e+00, %[[MUL_AR_DIV_BIBR]]
+// LLVM-IMPROVED: %[[RESULT_IMAG:.*]] = fdiv float %[[SUB_AI_MUL_AR_DIV_BIBR]], %[[ADD_BR_MUL_DIV_BIBR_BI]]
+// LLVM-IMPROVED: %[[TMP_THEN_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM-IMPROVED: %[[THEN_RESULT:.*]] = insertvalue { float, float } %[[TMP_THEN_RESULT]], float %[[RESULT_IMAG]], 1
+// LLVM-IMPROVED: br label %[[PHI_RESULT:.*]]
+// LLVM-IMPROVED: [[ABS_BR_LT_ABS_BI]]:
+// LLVM-IMPROVED: %[[DIV_BR_BI:.*]] = fdiv float %[[B_REAL]], %[[B_IMAG]]
+// LLVM-IMPROVED: %[[MUL_DIV_BRBI_BR:.*]] = fmul float %[[DIV_BR_BI]], %[[B_REAL]]
+// LLVM-IMPROVED: %[[ADD_BI_MUL_DIV_BRBI_BR:.*]] = fadd float %[[B_IMAG]], %[[MUL_DIV_BRBI_BR]]
+// LLVM-IMPROVED: %[[MUL_AR_DIV_BRBI:.*]] = fmul float %[[TMP_A]], %[[DIV_BR_BI]]
+// LLVM-IMPROVED: %[[ADD_MUL_AR_DIV_BRBI_AI:.*]] = fadd float %[[MUL_AR_DIV_BRBI]], 0.000000e+00
+// LLVM-IMPROVED: %[[RESULT_REAL:.*]] = fdiv float %[[ADD_MUL_AR_DIV_BRBI_AI]], %[[ADD_BI_MUL_DIV_BRBI_BR]]
+// LLVM-IMPROVED: %[[MUL_AI_DIV_BRBI:.*]] = fmul float 0.000000e+00, %[[DIV_BR_BI]]
+// LLVM-IMPROVED: %[[SUB_MUL_AI_DIV_BRBI_AR:.*]] = fsub float %[[MUL_AI_DIV_BRBI]], %[[TMP_A]]
+// LLVM-IMPROVED: %[[RESULT_IMAG:.*]] = fdiv float %[[SUB_MUL_AI_DIV_BRBI_AR]], %[[ADD_BI_MUL_DIV_BRBI_BR]]
+// LLVM-IMPROVED: %[[TMP_ELSE_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM-IMPROVED: %[[ELSE_RESULT:.*]] = insertvalue { float, float } %[[TMP_ELSE_RESULT]], float %[[RESULT_IMAG]], 1
+// LLVM-IMPROVED: br label %[[PHI_RESULT]]
+// LLVM-IMPROVED: [[PHI_RESULT]]:
+// LLVM-IMPROVED: %[[RESULT:.*]] = phi { float, float } [ %[[ELSE_RESULT]], %[[ABS_BR_LT_ABS_BI]] ], [ %[[THEN_RESULT]], %[[ABS_BR_GT_ABS_BI]] ]
+// LLVM-IMPROVED: br label %[[STORE_RESULT:.*]]
+// LLVM-IMPROVED: [[STORE_RESULT]]:
+// LLVM-IMPROVED: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4
+
+// OGCG-IMPROVED: %[[A_ADDR:.*]] = alloca float, align 4
+// OGCG-IMPROVED: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-IMPROVED: %[[C_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-IMPROVED: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// OGCG-IMPROVED: %b.realp = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG-IMPROVED: %b.real = load float, ptr %b.realp, align 4
+// OGCG-IMPROVED: %b.imagp = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG-IMPROVED: %b.imag = load float, ptr %b.imagp, align 4
+// OGCG-IMPROVED: %[[ABS_B_REAL:.*]] = call float @llvm.fabs.f32(float %[[B_REAL]])
+// OGCG-IMPROVED: %[[ABS_B_IMAG:.*]] = call float @llvm.fabs.f32(float %[[B_IMAG]])
+// OGCG-IMPROVED: %[[ABS_B_CMP:.*]] = fcmp ugt float %[[ABS_B_REAL]], %[[ABS_B_IMAG]]
+// OGCG-IMPROVED: br i1 %[[ABS_B_CMP]], label %[[ABS_BR_GT_ABS_BI:.*]], label %[[ABS_BR_LT_ABS_BI:.*]]
+// OGCG-IMPROVED: [[ABS_BR_GT_ABS_BI]]:
+// OGCG-IMPROVED: %[[DIV_BI_BR:.*]] = fdiv float %[[B_IMAG]], %[[B_REAL]]
+// OGCG-IMPROVED: %[[MUL_DIV_BIBR_BI:.*]] = fmul float %[[DIV_BI_BR]], %[[B_IMAG]]
+// OGCG-IMPROVED: %[[ADD_BR_MUL_DIV_BIBR_BI:.*]] = fadd float %[[B_REAL]], %[[MUL_DIV_BIBR_BI]]
+// OGCG-IMPROVED: %[[MUL_AI_DIV_BIBR:.*]] = fmul float 0.000000e+00, %[[DIV_BI_BR]]
+// OGCG-IMPROVED: %[[ADD_AR_MUL_AI_DIV_BIBR:.*]] = fadd float %[[TMP_A]], %[[MUL_AI_DIV_BIBR]]
+// OGCG-IMPROVED: %[[THEN_RESULT_REAL:.*]] = fdiv float %[[ADD_AR_MUL_AI_DIV_BIBR]], %[[ADD_BR_MUL_DIV_BIBR_BI]]
+// OGCG-IMPROVED: %[[MUL_AR_DIV_BI_BR:.*]] = fmul float %[[TMP_A]], %[[DIV_BI_BR]]
+// OGCG-IMPROVED: %[[SUB_AI_MUL_AR_DIV_BIBR:.*]] = fsub float 0.000000e+00, %[[MUL_AR_DIV_BI_BR]]
+// OGCG-IMPROVED: %[[THEN_RESULT_IMAG:.*]] = fdiv float %[[SUB_AI_MUL_AR_DIV_BIBR]], %[[ADD_BR_MUL_DIV_BIBR_BI]]
+// OGCG-IMPROVED: br label %[[STORE_RESULT:.*]]
+// OGCG-IMPROVED: [[ABS_BR_LT_ABS_BI]]:
+// OGCG-IMPROVED: %[[DIV_BR_BI:.*]] = fdiv float %[[B_REAL]], %[[B_IMAG]]
+// OGCG-IMPROVED: %[[MUL_DIV_BRBI_BR:.*]] = fmul float %[[DIV_BR_BI]], %[[B_REAL]]
+// OGCG-IMPROVED: %[[ADD_BI_MUL_DIV_BRBI_BR:.*]] = fadd float %[[B_IMAG]], %[[MUL_DIV_BRBI_BR]]
+// OGCG-IMPROVED: %[[MUL_AR_DIV_BRBI:.*]] = fmul float %[[TMP_A]], %[[DIV_BR_BI]]
+// OGCG-IMPROVED: %[[ADD_MUL_AR_DIV_BRBI_AI:.*]] = fadd float %[[MUL_AR_DIV_BRBI]], 0.000000e+00
+// OGCG-IMPROVED: %[[ELSE_RESULT_REAL:.*]] = fdiv float %[[ADD_MUL_AR_DIV_BRBI_AI]], %[[ADD_BI_MUL_DIV_BRBI_BR]]
+// OGCG-IMPROVED: %[[MUL_AI_DIV_BRBI:.*]] = fmul float 0.000000e+00, %[[DIV_BR_BI]]
+// OGCG-IMPROVED: %[[SUB_MUL_AI_DIV_BRBI_AR:.*]] = fsub float %[[MUL_AI_DIV_BRBI]], %[[TMP_A]]
+// OGCG-IMPROVED: %[[ELSE_RESULT_IMAG:.*]] = fdiv float %[[SUB_MUL_AI_DIV_BRBI_AR]], %[[ADD_BI_MUL_DIV_BRBI_BR]]
+// OGCG-IMPROVED: br label %[[STORE_RESULT]]
+// OGCG-IMPROVED: [[STORE_RESULT]]:
+// OGCG-IMPROVED: %[[RESULT_REAL:.*]] = phi float [ %[[THEN_RESULT_REAL]], %[[ABS_BR_GT_ABS_BI]] ], [ %[[ELSE_RESULT_REAL]], %[[ABS_BR_LT_ABS_BI]] ]
+// OGCG-IMPROVED: %[[RESULT_IMAG:.*]] = phi float [ %[[THEN_RESULT_IMAG]], %[[ABS_BR_GT_ABS_BI]] ], [ %[[ELSE_RESULT_IMAG]], %[[ABS_BR_LT_ABS_BI]] ]
+// OGCG-IMPROVED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-IMPROVED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-IMPROVED: store float %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-IMPROVED: store float %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+// CIR-BEFORE-PROMOTED: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(promoted) : !cir.complex<!cir.float>
+
+// CIR-AFTER-PROMOTED: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"]
+// CIR-AFTER-PROMOTED: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR-AFTER-PROMOTED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init]
+// CIR-AFTER-PROMOTED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR-AFTER-PROMOTED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR-AFTER-PROMOTED: %[[CONST_0:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR-AFTER-PROMOTED: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-PROMOTED: %[[A_REAL:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-PROMOTED: %[[A_IMAG:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-PROMOTED: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-PROMOTED: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-PROMOTED: %[[A_REAL_F64:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.float), !cir.double
+// CIR-AFTER-PROMOTED: %[[A_IMAG_F64:.*]] = cir.cast(floating, %[[A_IMAG]] : !cir.float), !cir.double
+// CIR-AFTER-PROMOTED: %[[B_REAL_F64:.*]] = cir.cast(floating, %[[B_REAL]] : !cir.float), !cir.double
+// CIR-AFTER-PROMOTED: %[[B_IMAG_F64:.*]] = cir.cast(floating, %[[B_IMAG]] : !cir.float), !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL_F64]], %[[B_REAL_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG_F64]], %[[B_IMAG_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_BR_BR:.*]] = cir.binop(mul, %[[B_REAL_F64]], %[[B_REAL_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG_F64]], %[[B_IMAG_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG_F64]], %[[B_REAL_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL_F64]], %[[B_IMAG_F64]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_F64:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !cir.double -> !cir.complex<!cir.double>
+// CIR-AFTER-PROMOTED: %[[RESULT_REAL_F64:.*]] = cir.complex.real %[[RESULT_F64]] : !cir.complex<!cir.double> -> !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_IMAG_F64:.*]] = cir.complex.imag %[[RESULT_F64]] : !cir.complex<!cir.double> -> !cir.double
+// CIR-AFTER-PROMOTED: %[[RESULT_REAL_F32:.*]] = cir.cast(floating, %[[RESULT_REAL_F64]] : !cir.double), !cir.float
+// CIR-AFTER-PROMOTED: %[[RESULT_IMAG_F32:.*]] = cir.cast(floating, %[[RESULT_IMAG_F64]] : !cir.double), !cir.float
+// CIR-AFTER-PROMOTED: %[[RESULT_F32:.*]] = cir.complex.create %[[RESULT_REAL_F32]], %[[RESULT_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-PROMOTED: cir.store{{.*}} %[[RESULT_F32]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM-PROMOTED: %[[A_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM-PROMOTED: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-PROMOTED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-PROMOTED: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// LLVM-PROMOTED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
+// LLVM-PROMOTED: %[[TMP_COMPLEX_A:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_A]], 0
+// LLVM-PROMOTED: %[[COMPLEX_A:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_A]], float 0.000000e+00, 1
+// LLVM-PROMOTED: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
+// LLVM-PROMOTED: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
+// LLVM-PROMOTED: %[[A_REAL_F64:.*]] = fpext float %[[TMP_A]] to double
+// LLVM-PROMOTED: %[[B_REAL_F64:.*]] = fpext float %[[B_REAL]] to double
+// LLVM-PROMOTED: %[[B_IMAG_F64:.*]] = fpext float %[[B_IMAG]] to double
+// LLVM-PROMOTED: %[[MUL_AR_BR:.*]] = fmul double %[[A_REAL_F64]], %[[B_REAL_F64]]
+// LLVM-PROMOTED: %[[MUL_AI_BI:.*]] = fmul double 0.000000e+00, %[[B_IMAG_F64]]
+// LLVM-PROMOTED: %[[MUL_BR_BR:.*]] = fmul double %[[B_REAL_F64]], %[[B_REAL_F64]]
+// LLVM-PROMOTED: %[[MUL_BI_BI:.*]] = fmul double %[[B_IMAG_F64]], %[[B_IMAG_F64]]
+// LLVM-PROMOTED: %[[ADD_ARBR_AIBI:.*]] = fadd double %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// LLVM-PROMOTED: %[[ADD_BRBR_BIBI:.*]] = fadd double %[[MUL_BR_BR]], %[[MUL_BI_BI]]
+// LLVM-PROMOTED: %[[RESULT_REAL:.*]] = fdiv double %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-PROMOTED: %[[MUL_AI_BR:.*]] = fmul double 0.000000e+00, %[[B_REAL_F64]]
+// LLVM-PROMOTED: %[[MUL_AR_BR:.*]] = fmul double %[[A_REAL_F64]], %[[B_IMAG_F64]]
+// LLVM-PROMOTED: %[[SUB_AIBR_ARBI:.*]] = fsub double %[[MUL_AI_BR]], %[[MUL_AR_BR]]
+// LLVM-PROMOTED: %[[RESULT_IMAG:.*]] = fdiv double %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-PROMOTED: %[[TMP_RESULT_F64:.*]] = insertvalue { double, double } {{.*}}, double %[[RESULT_REAL]], 0
+// LLVM-PROMOTED: %[[RESULT_F64:.*]] = insertvalue { double, double } %[[TMP_RESULT_F64]], double %[[RESULT_IMAG]], 1
+// LLVM-PROMOTED: %[[RESULT_REAL_F32:.*]] = fptrunc double %[[RESULT_REAL]] to float
+// LLVM-PROMOTED: %[[RESULT_IMAG_F32:.*]] = fptrunc double %[[RESULT_IMAG]] to float
+// LLVM-PROMOTED: %[[TMP_RESULT_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL_F32]], 0
+// LLVM-PROMOTED: %[[RESULT_F32:.*]] = insertvalue { float, float } %[[TMP_RESULT_F32]], float %[[RESULT_IMAG_F32]], 1
+// LLVM-PROMOTED: store { float, float } %[[RESULT_F32]], ptr %[[C_ADDR]], align 4
+
+// OGCG-PROMOTED: %[[A_ADDR:.*]] = alloca float, align 4
+// OGCG-PROMOTED: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-PROMOTED: %[[C_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-PROMOTED: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// OGCG-PROMOTED: %[[A_REAL_F64:.*]] = fpext float %[[TMP_A]] to double
+// OGCG-PROMOTED: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG-PROMOTED: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
+// OGCG-PROMOTED: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG-PROMOTED: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
+// OGCG-PROMOTED: %[[B_REAL_F64:.*]] = fpext float %[[B_REAL]] to double
+// OGCG-PROMOTED: %[[B_IMAG_F64:.*]] = fpext float %[[B_IMAG]] to double
+// OGCG-PROMOTED: %[[MUL_AR_BR:.*]] = fmul double %[[A_REAL_F64]], %[[B_REAL_F64]]
+// OGCG-PROMOTED: %[[MUL_AI_BI:.*]] = fmul double 0.000000e+00, %[[B_IMAG_F64]]
+// OGCG-PROMOTED: %[[ADD_ARBR_AIBI:.*]] = fadd double %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// OGCG-PROMOTED: %[[MUL_BR_BR:.*]] = fmul double %[[B_REAL_F64]], %[[B_REAL_F64]]
+// OGCG-PROMOTED: %[[MUL_BI_BI:.*]] = fmul double %[[B_IMAG_F64]], %[[B_IMAG_F64]]
+// OGCG-PROMOTED: %[[ADD_BRBR_BIBI:.*]] = fadd double %[[MUL_BR_BR]], %[[MUL_BI_BI]]
+// OGCG-PROMOTED: %[[MUL_AI_BR:.*]] = fmul double 0.000000e+00, %[[B_REAL_F64]]
+// OGCG-PROMOTED: %[[MUL_AR_BI:.*]] = fmul double %[[A_REAL_F64]], %[[B_IMAG_F64]]
+// OGCG-PROMOTED: %[[SUB_AIBR_ARBI:.*]] = fsub double %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// OGCG-PROMOTED: %[[RESULT_REAL:.*]] = fdiv double %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-PROMOTED: %[[RESULT_IMAG:.*]] = fdiv double %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-PROMOTED: %[[UNPROMOTION_RESULT_REAL:.*]] = fptrunc double %[[RESULT_REAL]] to float
+// OGCG-PROMOTED: %[[UNPROMOTION_RESULT_IMAG:.*]] = fptrunc double %[[RESULT_IMAG]] to float
+// OGCG-PROMOTED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-PROMOTED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-PROMOTED: store float %[[UNPROMOTION_RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-PROMOTED: store float %[[UNPROMOTION_RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+// CIR-BEFORE-FULL: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(full) : !cir.complex<!cir.float>
+
+// CIR-AFTER-FULL: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"]
+// CIR-AFTER-FULL: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"]
+// CIR-AFTER-FULL: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init]
+// CIR-AFTER-FULL: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float
+// CIR-AFTER-FULL: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR-AFTER-FULL: %[[CONST_0:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR-AFTER-FULL: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER-FULL: %[[A_REAL:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-FULL: %[[A_IMAG:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-FULL: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-FULL: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER-FULL: %[[RESULT:.*]] = cir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float>
+// CIR-AFTER-FULL: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM-FULL: %[[A_ADDR:.*]] = alloca float, i64 1, align 4
+// LLVM-FULL: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-FULL: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM-FULL: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// LLVM-FULL: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
+// LLVM-FULL: %[[TMP_COMPLEX_A:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_A]], 0
+// LLVM-FULL: %[[COMPLEX_A:.*]] = insertvalue { float, float } %6, float 0.000000e+00, 1
+// LLVM-FULL: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
+// LLVM-FULL: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
+// LLVM-FULL: %[[RESULT:.*]] = call { float, float } @__divsc3(float %[[TMP_A]], float 0.000000e+00, float %[[B_REAL]], float %[[B_IMAG]])
+// LLVM-FULL: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4
+
+// OGCG-FULL: %[[A_ADDR:.*]] = alloca float, align 4
+// OGCG-FULL: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-FULL: %[[C_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-FULL: %[[RESULT_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG-FULL: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4
+// OGCG-FULL: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG-FULL: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4
+// OGCG-FULL: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG-FULL: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4
+// OGCG-FULL: %[[RESULT:.*]] = call noundef <2 x float> @__divsc3(float noundef %[[TMP_A]], float noundef 0.000000e+00, float noundef %[[B_REAL]], float noundef %[[B_IMAG]])
+// OGCG-FULL: store <2 x float> %[[RESULT]], ptr %[[RESULT_ADDR]], align 4
+// OGCG-FULL: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 0
+// OGCG-FULL: %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG-FULL: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT_ADDR]], i32 0, i32 1
+// OGCG-FULL: %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
+// OGCG-FULL: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-FULL: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-FULL: store float %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-FULL: store float %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
+
+void foo7() {
+ int _Complex a;
+ int b;
+ int _Complex c = a / b;
+}
+
+// CIR-BEFORE-BASIC: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(basic) : !cir.complex<!s32i>
+
+// CIR-BEFORE-IMPROVED: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(improved) : !cir.complex<!s32i>
+
+// CIR-BEFORE-PROMOTED: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(promoted) : !cir.complex<!s32i>
+
+// CIR-BEFORE-FULL: %{{.*}} = cir.complex.div {{.*}}, {{.*}} range(full) : !cir.complex<!s32i>
+
+// CIR-COMBINED: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-COMBINED: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b"]
+// CIR-COMBINED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init]
+// CIR-COMBINED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-COMBINED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-COMBINED: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-COMBINED: %[[COMPLEX_B:.*]] = cir.complex.create %4, %5 : !s32i -> !cir.complex<!s32i>
+// CIR-COMBINED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
+// CIR-COMBINED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!s32i> -> !s32i
+// CIR-COMBINED: %[[B_REAL:.*]] = cir.complex.real %[[COMPLEX_B]] : !cir.complex<!s32i> -> !s32i
+// CIR-COMBINED: %[[B_IMAG:.*]] = cir.complex.imag %[[COMPLEX_B]] : !cir.complex<!s32i> -> !s32i
+// CIR-COMBINED: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !s32i
+// CIR-COMBINED: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !s32i
+// CIR-COMBINED: %[[MUL_BR_BR:.*]] = cir.binop(mul, %[[B_REAL]], %[[B_REAL]]) : !s32i
+// CIR-COMBINED: %[[MUL_BI_BI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[B_IMAG]]) : !s32i
+// CIR-COMBINED: %[[ADD_ARBR_AIBI:.*]] = cir.binop(add, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !s32i
+// CIR-COMBINED: %[[ADD_BRBR_BIBI:.*]] = cir.binop(add, %[[MUL_BR_BR]], %[[MUL_BI_BI]]) : !s32i
+// CIR-COMBINED: %[[RESULT_REAL:.*]] = cir.binop(div, %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]) : !s32i
+// CIR-COMBINED: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !s32i
+// CIR-COMBINED: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !s32i
+// CIR-COMBINED: %[[SUB_AIBR_ARBI:.*]] = cir.binop(sub, %[[MUL_AI_BR]], %[[MUL_AR_BI]]) : !s32i
+// CIR-COMBINED: %[[RESULT_IMAG:.*]] = cir.binop(div, %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]) : !s32i
+// CIR-COMBINED: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !s32i -> !cir.complex<!s32i>
+// CIR-COMBINED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM-COMBINED: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM-COMBINED: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM-COMBINED: %[[C_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM-COMBINED: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4
+// LLVM-COMBINED: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM-COMBINED: %[[TMP_COMPLEX_B:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[TMP_B]], 0
+// LLVM-COMBINED: %[[COMPLEX_B:.*]] = insertvalue { i32, i32 } %[[TMP_COMPLEX_B]], i32 0, 1
+// LLVM-COMBINED: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0
+// LLVM-COMBINED: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1
+// LLVM-COMBINED: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
+// LLVM-COMBINED: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
+// LLVM-COMBINED: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
+// LLVM-COMBINED: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// LLVM-COMBINED: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
+// LLVM-COMBINED: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-COMBINED: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
+// LLVM-COMBINED: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
+// LLVM-COMBINED: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// LLVM-COMBINED: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// LLVM-COMBINED: %[[TMP_RESULT:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[RESULT_REAL]], 0
+// LLVM-COMBINED: %[[RESULT:.*]] = insertvalue { i32, i32 } %[[TMP_RESULT]], i32 %[[RESULT_IMAG]], 1
+// LLVM-COMBINED: store { i32, i32 } %[[RESULT]], ptr %[[C_ADDR]], align 4
+
+// OGCG-COMBINED: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG-COMBINED: %[[B_ADDR:.*]] = alloca i32, align 4
+// OGCG-COMBINED: %[[C_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG-COMBINED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG-COMBINED: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
+// OGCG-COMBINED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG-COMBINED: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
+// OGCG-COMBINED: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG-COMBINED: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[TMP_B]]
+// OGCG-COMBINED: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], 0
+// OGCG-COMBINED: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]]
+// OGCG-COMBINED: %[[MUL_BR_BR:.*]] = mul i32 %[[TMP_B]], %[[TMP_B]]
+// OGCG-COMBINED: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], 0
+// OGCG-COMBINED: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[TMP_B]]
+// OGCG-COMBINED: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], 0
+// OGCG-COMBINED: %[[SUB_AIBR_ARBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_AR_BI]]
+// OGCG-COMBINED: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-COMBINED: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_ARBI]], %[[ADD_BRBR_BIBI]]
+// OGCG-COMBINED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 0
+// OGCG-COMBINED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1
+// OGCG-COMBINED: store i32 %[[RESULT_REAL]], ptr %[[C_REAL_PTR]], align 4
+// OGCG-COMBINED: store i32 %[[RESULT_IMAG]], ptr %[[C_IMAG_PTR]], align 4
diff --git a/clang/test/CIR/CodeGen/complex-arithmetic.cpp b/clang/test/CIR/CodeGen/complex-plus-minus.cpp
index fbb0335106f8..fbb0335106f8 100644
--- a/clang/test/CIR/CodeGen/complex-arithmetic.cpp
+++ b/clang/test/CIR/CodeGen/complex-plus-minus.cpp
diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cpp
index 4cd81eb40597..e945d9b09f61 100644
--- a/clang/test/CIR/CodeGen/complex-unary.cpp
+++ b/clang/test/CIR/CodeGen/complex-unary.cpp
@@ -370,3 +370,138 @@ void foo8() {
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: store float %[[A_REAL_MINUS]], ptr %[[B_REAL_PTR]], align 4
// OGCG: store float %[[A_IMAG_MINUS]], ptr %[[B_IMAG_PTR]], align 4
+
+void foo9() {
+ _Float16 _Complex a;
+ _Float16 _Complex b = +a;
+}
+
+
+// CIR-BEFORE: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["a"]
+// CIR-BEFORE: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["b", init]
+// CIR-BEFORE: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR-BEFORE: %[[A_COMPLEX_F32:.*]] = cir.cast(float_complex, %[[TMP_A]] : !cir.complex<!cir.f16>), !cir.complex<!cir.float>
+// CIR-BEFORE: %[[RESULT:.*]] = cir.unary(plus, %[[A_COMPLEX_F32]]) : !cir.complex<!cir.float>, !cir.complex<!cir.float>
+// CIR-BEFORE: %[[A_COMPLEX_F16:.*]] = cir.cast(float_complex, %[[RESULT]] : !cir.complex<!cir.float>), !cir.complex<!cir.f16>
+// CIR-BEFORE: cir.store{{.*}} %[[A_COMPLEX_F16]], %[[B_ADDR]] : !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>
+
+// CIR-AFTER: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["a"]
+// CIR-AFTER: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["b", init]
+// CIR-AFTER: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR-AFTER: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR-AFTER: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR-AFTER: %[[A_REAL_F32:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.f16), !cir.float
+// CIR-AFTER: %[[A_IMAG_F32:.*]] = cir.cast(floating, %[[A_IMAG]] : !cir.f16), !cir.float
+// CIR-AFTER: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[A_IMAG_F32:.*]] = cir.complex.imag %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_REAL_F32:.*]] = cir.unary(plus, %[[A_REAL_F32]]) : !cir.float, !cir.float
+// CIR-AFTER: %[[RESULT_IMAG_F32:.*]] = cir.unary(plus, %[[A_IMAG_F32]]) : !cir.float, !cir.float
+// CIR-AFTER: %[[RESULT_COMPLEX_F32:.*]] = cir.complex.create %[[RESULT_REAL_F32]], %[[RESULT_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER: %[[RESULT_REAL_F32:.*]] = cir.complex.real %[[RESULT_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_IMAG_F32:.*]] = cir.complex.imag %[[RESULT_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_REAL_F16:.*]] = cir.cast(floating, %[[RESULT_REAL_F32]] : !cir.float), !cir.f16
+// CIR-AFTER: %[[RESULT_IMAG_F16:.*]] = cir.cast(floating, %[[RESULT_IMAG_F32]] : !cir.float), !cir.f16
+// CIR-AFTER: %[[RESULT_COMPLEX_F16:.*]] = cir.complex.create %[[RESULT_REAL_F16]], %[[RESULT_IMAG_F16]] : !cir.f16 -> !cir.complex<!cir.f16>
+// CIR-AFTER: cir.store{{.*}} %[[RESULT_COMPLEX_F16]], %[[B_ADDR]] : !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[B_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[TMP_A:.*]] = load { half, half }, ptr %[[A_ADDR]], align 2
+// LLVM: %[[A_REAL:.*]] = extractvalue { half, half } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { half, half } %[[TMP_A]], 1
+// LLVM: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// LLVM: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// LLVM: %[[TMP_A_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[A_REAL_F32]], 0
+// LLVM: %[[A_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_A_COMPLEX_F32]], float %[[A_IMAG_F32]], 1
+// LLVM: %[[TMP_A_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[A_REAL_F32]], 0
+// LLVM: %[[A_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_A_COMPLEX_F32]], float %[[A_IMAG_F32]], 1
+// LLVM: %[[A_REAL_F16:.*]] = fptrunc float %[[A_REAL_F32]] to half
+// LLVM: %[[A_IMAG_F16:.*]] = fptrunc float %[[A_IMAG_F32]] to half
+// LLVM: %[[TMP_RESULT_COMPLEX_F16:.*]] = insertvalue { half, half } {{.*}}, half %[[A_REAL_F16]], 0
+// LLVM: %[[RESULT_COMPLEX_F16:.*]] = insertvalue { half, half } %[[TMP_RESULT_COMPLEX_F16]], half %[[A_IMAG_F16]], 1
+// LLVM: store { half, half } %[[RESULT_COMPLEX_F16]], ptr %[[B_ADDR]], align 2
+
+// OGCG: %[[A_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[B_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load half, ptr %a.realp, align 2
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load half, ptr %a.imagp, align 2
+// OGCG: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// OGCG: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// OGCG: %[[RESULT_REAL:.*]] = fptrunc float %[[A_REAL_F32]] to half
+// OGCG: %[[RESULT_IMAG:.*]] = fptrunc float %[[A_IMAG_F32]] to half
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store half %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 2
+// OGCG: store half %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 2
+
+void foo10() {
+ _Float16 _Complex a;
+ _Float16 _Complex b = -a;
+}
+
+// CIR-BEFORE: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["a"]
+// CIR-BEFORE: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["b", init]
+// CIR-BEFORE: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR-BEFORE: %[[A_COMPLEX_F32:.*]] = cir.cast(float_complex, %[[TMP_A]] : !cir.complex<!cir.f16>), !cir.complex<!cir.float>
+// CIR-BEFORE: %[[RESULT:.*]] = cir.unary(minus, %[[A_COMPLEX_F32]]) : !cir.complex<!cir.float>, !cir.complex<!cir.float>
+// CIR-BEFORE: %[[A_COMPLEX_F16:.*]] = cir.cast(float_complex, %[[RESULT]] : !cir.complex<!cir.float>), !cir.complex<!cir.f16>
+// CIR-BEFORE: cir.store{{.*}} %[[A_COMPLEX_F16]], %[[B_ADDR]] : !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>
+
+// CIR-AFTER: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["a"]
+// CIR-AFTER: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>, ["b", init]
+// CIR-AFTER: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
+// CIR-AFTER: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR-AFTER: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.f16> -> !cir.f16
+// CIR-AFTER: %[[A_REAL_F32:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.f16), !cir.float
+// CIR-AFTER: %[[A_IMAG_F32:.*]] = cir.cast(floating, %[[A_IMAG]] : !cir.f16), !cir.float
+// CIR-AFTER: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[A_IMAG_F32:.*]] = cir.complex.imag %[[A_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_REAL_F32:.*]] = cir.unary(minus, %[[A_REAL_F32]]) : !cir.float, !cir.float
+// CIR-AFTER: %[[RESULT_IMAG_F32:.*]] = cir.unary(minus, %[[A_IMAG_F32]]) : !cir.float, !cir.float
+// CIR-AFTER: %[[RESULT_COMPLEX_F32:.*]] = cir.complex.create %[[RESULT_REAL_F32]], %[[RESULT_IMAG_F32]] : !cir.float -> !cir.complex<!cir.float>
+// CIR-AFTER: %[[RESULT_REAL_F32:.*]] = cir.complex.real %[[RESULT_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_IMAG_F32:.*]] = cir.complex.imag %[[RESULT_COMPLEX_F32]] : !cir.complex<!cir.float> -> !cir.float
+// CIR-AFTER: %[[RESULT_REAL_F16:.*]] = cir.cast(floating, %[[RESULT_REAL_F32]] : !cir.float), !cir.f16
+// CIR-AFTER: %[[RESULT_IMAG_F16:.*]] = cir.cast(floating, %[[RESULT_IMAG_F32]] : !cir.float), !cir.f16
+// CIR-AFTER: %[[RESULT_COMPLEX_F16:.*]] = cir.complex.create %[[RESULT_REAL_F16]], %[[RESULT_IMAG_F16]] : !cir.f16 -> !cir.complex<!cir.f16>
+// CIR-AFTER: cir.store{{.*}} %[[RESULT_COMPLEX_F16]], %[[B_ADDR]] : !cir.complex<!cir.f16>, !cir.ptr<!cir.complex<!cir.f16>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[B_ADDR:.*]] = alloca { half, half }, i64 1, align 2
+// LLVM: %[[TMP_A:.*]] = load { half, half }, ptr %[[A_ADDR]], align 2
+// LLVM: %[[A_REAL:.*]] = extractvalue { half, half } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { half, half } %[[TMP_A]], 1
+// LLVM: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// LLVM: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// LLVM: %[[TMP_A_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[A_REAL_F32]], 0
+// LLVM: %[[A_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_A_COMPLEX_F32]], float %[[A_IMAG_F32]], 1
+// LLVM: %[[RESULT_REAL_F32:.*]] = fneg float %[[A_REAL_F32]]
+// LLVM: %[[RESULT_IMAG_F32:.*]] = fneg float %[[A_IMAG_F32]]
+// LLVM: %[[TMP_A_COMPLEX_F32:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL_F32]], 0
+// LLVM: %[[A_COMPLEX_F32:.*]] = insertvalue { float, float } %[[TMP_A_COMPLEX_F32]], float %[[RESULT_IMAG_F32]], 1
+// LLVM: %[[A_REAL_F16:.*]] = fptrunc float %[[RESULT_REAL_F32]] to half
+// LLVM: %[[A_IMAG_F16:.*]] = fptrunc float %[[RESULT_IMAG_F32]] to half
+// LLVM: %[[TMP_RESULT_COMPLEX_F16:.*]] = insertvalue { half, half } {{.*}}, half %[[A_REAL_F16]], 0
+// LLVM: %[[RESULT_COMPLEX_F16:.*]] = insertvalue { half, half } %[[TMP_RESULT_COMPLEX_F16]], half %[[A_IMAG_F16]], 1
+// LLVM: store { half, half } %[[RESULT_COMPLEX_F16]], ptr %[[B_ADDR]], align 2
+
+// OGCG: %[[A_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[B_ADDR:.*]] = alloca { half, half }, align 2
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load half, ptr %a.realp, align 2
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load half, ptr %a.imagp, align 2
+// OGCG: %[[A_REAL_F32:.*]] = fpext half %[[A_REAL]] to float
+// OGCG: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float
+// OGCG: %[[RESULT_REAL_F32:.*]] = fneg float %[[A_REAL_F32]]
+// OGCG: %[[RESULT_IMAG_F32:.*]] = fneg float %[[A_IMAG_F32]]
+// OGCG: %[[RESULT_REAL:.*]] = fptrunc float %[[RESULT_REAL_F32]] to half
+// OGCG: %[[RESULT_IMAG:.*]] = fptrunc float %[[RESULT_IMAG_F32]] to half
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { half, half }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store half %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 2
+// OGCG: store half %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 2
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index e435a5e6ed01..2e1198b09f01 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -853,3 +853,77 @@ void foo32() {
// OGCG: %[[REAL_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[REAL:.*]] = load i32, ptr @_ZN9Container1cE, align 4
// OGCG: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4
+
+void foo33(__builtin_va_list a) {
+ float _Complex b = __builtin_va_arg(a, float _Complex);
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!rec___va_list_tag>, !cir.ptr<!cir.ptr<!rec___va_list_tag>>, ["a", init]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
+// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!cir.ptr<!rec___va_list_tag>>
+// CIR: %[[VA_TAG:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.ptr<!rec___va_list_tag>>, !cir.ptr<!rec___va_list_tag>
+// CIR: %[[COMPLEX:.*]] = cir.va_arg %[[VA_TAG]] : (!cir.ptr<!rec___va_list_tag>) -> !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: store ptr %[[ARG_0:.*]], ptr %[[A_ADDR]], align 8
+// LLVM: %[[TMP_A:.*]] = load ptr, ptr %[[A_ADDR]], align 8
+// LLVM: %[[COMPLEX:.*]] = va_arg ptr %[[TMP_A]], { float, float }
+// LLVM: store { float, float } %[[COMPLEX]], ptr %[[B_ADDR]], align 4
+
+// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering,
+// Test will be updated when that is implemented
+
+// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: store ptr %[[ARG_0:.*]], ptr %[[A_ADDR]], align 8
+// OGCG: %[[TMP_A:.*]] = load ptr, ptr %[[A_ADDR]], align 8
+// OGCG: %[[GP_OFFSET_PTR:.*]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 1
+// OGCG: %[[GP_OFFSET:.*]] = load i32, ptr %[[GP_OFFSET_PTR]], align 4
+// OGCG: %[[COND:.*]] = icmp ule i32 %[[GP_OFFSET]], 160
+// OGCG: br i1 %[[COND]], label %[[VA_ARG_IN_REG:.*]], label %[[VA_ARG_IN_MEM:.*]]
+//
+// OGCG: [[VA_ARG_IN_REG]]:
+// OGCG: %[[REG_SAVE_PTR:.*]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 3
+// OGCG: %[[REG_SAVE:.*]] = load ptr, ptr %[[REG_SAVE_PTR]], align 8
+// OGCG: %[[VA_ADDR:..*]] = getelementptr i8, ptr %[[REG_SAVE]], i32 %[[GP_OFFSET]]
+// OGCG: %[[GP_OFFSET_NEXT:.*]] = add i32 %[[GP_OFFSET]], 16
+// OGCG: store i32 %[[GP_OFFSET_NEXT]], ptr %[[GP_OFFSET_PTR]], align 4
+// OGCG: br label %[[VA_ARG_END:.*]]
+//
+// OGCG: [[VA_ARG_IN_MEM]]:
+// OGCG: %[[OVERFLOW_PTR:.*]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 2
+// OGCG: %[[OVERFLOW:.*]] = load ptr, ptr %[[OVERFLOW_PTR]], align 8
+// OGCG: %[[OVERFLOW_NEXT:.*]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
+// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]], align 8
+// OGCG: br label %[[VA_ARG_END]]
+//
+// OGCG: [[VA_ARG_END]]:
+// OGCG: %[[RESULT:.*]] = phi ptr [ %[[VA_ADDR]], %[[VA_ARG_IN_REG]] ], [ %[[OVERFLOW]], %[[VA_ARG_IN_MEM]] ]
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 0
+// OGCG: %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 1
+// OGCG: %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store float %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 4
+// OGCG: store float %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 4
+
+void foo34() {
+ _Atomic(float _Complex) a;
+ __c11_atomic_init(&a, {1.0f, 2.0f});
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[CONST_COMPLEX:.*]] = cir.const #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float> : !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[CONST_COMPLEX]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 8
+// LLVM: store { float, float } { float 1.000000e+00, float 2.000000e+00 }, ptr %[[A_ADDR]], align 8
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 8
+// 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 8
+// OGCG: store float 2.000000e+00, ptr %[[A_IMAG_PTR]], align 4
diff --git a/clang/test/CIR/CodeGen/constant-inits.cpp b/clang/test/CIR/CodeGen/constant-inits.cpp
new file mode 100644
index 000000000000..c9153c91ebc2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/constant-inits.cpp
@@ -0,0 +1,115 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+struct empty{};
+
+struct Point {
+ int x;
+ int y;
+ char c[3];
+ int z;
+ [[no_unique_address]] empty e;
+};
+
+struct [[gnu::packed]] packed {
+ char c;
+ int i;
+};
+
+struct [[gnu::packed]] alignas(8) packed_and_aligned {
+ short s;
+ char c;
+ float f;
+};
+
+struct simple {
+ int a, b;
+};
+
+void function() {
+ constexpr static empty e;
+
+ constexpr static Point p1{10, 20, {99, 88, 77}, 40, e};
+
+ constexpr static Point array[] {
+ {123, 456, {11, 22, 33}, 789, {}},
+ {10, 20, {0, 0 ,0}, 40}
+ };
+
+ constexpr static packed p2 {123, 456};
+ constexpr static packed packed_array[] {
+ p2, p2
+ };
+
+ constexpr static packed_and_aligned paa {1, 2, 3.f};
+ constexpr static packed_and_aligned paa_array[2] {
+ {1, 2, 3.f}
+ };
+
+ constexpr static simple s{0, -1};
+ constexpr static simple simple_array[] {
+ s, {1111, 2222}, s
+ };
+}
+
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1e = #cir.zero : !rec_empty
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1s = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p1 = #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.const_array<[#cir.int<99> : !s8i, #cir.int<88> : !s8i, #cir.int<77> : !s8i]> : !cir.array<!s8i x 3>, #cir.int<40> : !s32i}> : !rec_Point
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p2 = #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE3paa = #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned
+
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5array = #cir.const_array<[
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s32i, #cir.int<456> : !s32i, #cir.const_array<[#cir.int<11> : !s8i, #cir.int<22> : !s8i, #cir.int<33> : !s8i]> : !cir.array<!s8i x 3>, #cir.int<789> : !s32i}> : !rec_Point
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.zero : !cir.array<!s8i x 3>, #cir.int<40> : !s32i}> : !rec_Point
+// CIR-DAG-SAME: ]> : !cir.array<!rec_Point x 2>
+
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12simple_array = #cir.const_array<[
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple,
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<1111> : !s32i, #cir.int<2222> : !s32i}> : !rec_simple,
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple
+// CIR-DAG-SAME: ]> : !cir.array<!rec_simple x 3>
+
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12packed_array = #cir.const_array<[
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed,
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed
+// CIR-DAG-SAME: ]> : !cir.array<!rec_packed x 2>
+
+// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE9paa_array = #cir.const_array<[
+// CIR-DAG-SAME: #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned,
+// CIR-DAG-SAME: #cir.zero : !rec_packed_and_aligned
+// CIR-DAG-SAME: ]> : !cir.array<!rec_packed_and_aligned x 2>
+
+// CIR-LABEL: cir.func dso_local @_Z8functionv()
+// CIR: cir.return
+
+
+// LLVM-DAG: @_ZZ8functionvE12packed_array = internal global [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>]
+// LLVM-DAG: @_ZZ8functionvE12simple_array = internal global [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }]
+// LLVM-DAG: @_ZZ8functionvE1e = internal global %struct.empty zeroinitializer
+// LLVM-DAG: @_ZZ8functionvE1s = internal global %struct.simple { i32 0, i32 -1 }
+// LLVM-DAG: @_ZZ8functionvE2p1 = internal global %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 }
+// LLVM-DAG: @_ZZ8functionvE2p2 = internal global %struct.packed <{ i8 123, i32 456 }>
+// LLVM-DAG: @_ZZ8functionvE3paa = internal global %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>
+// LLVM-DAG: @_ZZ8functionvE5array = internal global [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }]
+// LLVM-DAG: @_ZZ8functionvE9paa_array = internal global [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>, %struct.packed_and_aligned zeroinitializer]
+
+// LLVM-LABEL: define{{.*}} void @_Z8functionv
+// LLVM: ret void
+
+
+// OGCG-DAG: @_ZZ8functionvE12packed_array = internal constant [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>]
+// OGCG-DAG: @_ZZ8functionvE12simple_array = internal constant [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }]
+// OGCG-DAG: @_ZZ8functionvE1e = internal constant %struct.empty zeroinitializer
+// OGCG-DAG: @_ZZ8functionvE1s = internal constant %struct.simple { i32 0, i32 -1 }
+// OGCG-DAG: @_ZZ8functionvE2p1 = internal constant %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 }
+// OGCG-DAG: @_ZZ8functionvE2p2 = internal constant %struct.packed <{ i8 123, i32 456 }>
+// OGCG-DAG: @_ZZ8functionvE3paa = internal constant %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 undef }>
+// OGCG-DAG: @_ZZ8functionvE5array = internal constant [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }]
+// OGCG-DAG: @_ZZ8functionvE9paa_array = internal constant [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 undef }>, %struct.packed_and_aligned <{ i16 0, i8 0, float 0.000000e+00, i8 undef }>]
+
+// OGCG-LABEL: define{{.*}} void @_Z8functionv
+// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/cxx-default-init.cpp b/clang/test/CIR/CodeGen/cxx-default-init.cpp
new file mode 100644
index 000000000000..06d3a27f61cc
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx-default-init.cpp
@@ -0,0 +1,245 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct Pair {
+ int a;
+ int b;
+};
+
+struct ZeroInit {
+ int i{};
+ Pair p{};
+ int arr[4]{};
+ float _Complex c{};
+ unsigned bf : 8 {};
+ ZeroInit() = default;
+};
+
+// CIR: cir.func{{.*}} @_ZN8ZeroInitC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_ZeroInit> {{.*}})
+// CIR: %[[ITER:.*]] = cir.alloca {{.*}} ["arrayinit.temp"]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA:.*]]
+// CIR: %[[I:.*]] = cir.get_member %[[THIS]][0] {name = "i"}
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[I]]
+// CIR: %[[P:.*]] = cir.get_member %[[THIS]][1] {name = "p"}
+// CIR: %[[P_A:.*]] = cir.get_member %[[P]][0] {name = "a"}
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[P_A]]
+// CIR: %[[P_B:.*]] = cir.get_member %[[P]][1] {name = "b"}
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[P_B]]
+// CIR: %[[ARR:.*]] = cir.get_member %[[THIS]][2] {name = "arr"}
+// CIR: %[[ARR_BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!s32i x 4>>), !cir.ptr<!s32i>
+// CIR: cir.store{{.*}} %[[ARR_BEGIN]], %[[ITER]]
+// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s64i
+// CIR: %[[END:.*]] = cir.ptr_stride(%[[ARR_BEGIN]] : !cir.ptr<!s32i>, %[[FOUR]] : !s64i)
+// CIR: cir.do {
+// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[ITER]]
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[CUR]]
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CUR]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i)
+// CIR: cir.store{{.*}} %[[NEXT]], %[[ITER]]
+// CIR: cir.yield
+// CIR: } while {
+// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[ITER]]
+// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[END]])
+// CIR: cir.condition(%[[CMP]])
+// CIR: }
+// CIR: %[[C:.*]] = cir.get_member %[[THIS]][3] {name = "c"}
+// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[ZERO]], %[[C]]
+// CIR: %[[BF:.*]] = cir.get_member %[[THIS]][4] {name = "bf"}
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u32i
+// CIR: %[[BF_VAL:.*]] = cir.set_bitfield{{.*}} (#bfi_bf, %[[BF]] : !cir.ptr<!u8i>, %[[ZERO]] : !u32i)
+
+// LLVM: define{{.*}} void @_ZN8ZeroInitC2Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr
+// LLVM: %[[ITER:.*]] = alloca ptr
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// LLVM: %[[I:.*]] = getelementptr %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 0
+// LLVM: store i32 0, ptr %[[I]]
+// LLVM: %[[P:.*]] = getelementptr %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 1
+// LLVM: %[[P_A:.*]] = getelementptr %struct.Pair, ptr %[[P]], i32 0, i32 0
+// LLVM: store i32 0, ptr %[[P_A]]
+// LLVM: %[[P_B:.*]] = getelementptr %struct.Pair, ptr %[[P]], i32 0, i32 1
+// LLVM: store i32 0, ptr %[[P_B]]
+// LLVM: %[[ARR:.*]] = getelementptr %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 2
+// LLVM: %[[ARR_BEGIN:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
+// LLVM: store ptr %[[ARR_BEGIN]], ptr %[[ITER]]
+// LLVM: %[[ARR_END:.*]] = getelementptr i32, ptr %[[ARR_BEGIN]], i64 4
+// LLVM: br label %[[LOOP_BODY:.*]]
+// LLVM: [[LOOP_COND:.*]]:
+// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[ARR_END]]
+// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]]
+// LLVM: [[LOOP_BODY]]:
+// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM: store i32 0, ptr %[[CUR]]
+// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1
+// LLVM: store ptr %[[NEXT]], ptr %[[ITER]]
+// LLVM: br label %[[LOOP_COND]]
+// LLVM: [[LOOP_END]]:
+// LLVM: %[[C:.*]] = getelementptr %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 3
+// LLVM: store { float, float } zeroinitializer, ptr %[[C]]
+// LLVM: %[[BF:.*]] = getelementptr %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 4
+// LLVM: store i8 0, ptr %[[BF]]
+
+// OGCG: define{{.*}} void @_ZN8ZeroInitC2Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA:.*]]
+// OGCG: %[[I:.*]] = getelementptr inbounds nuw %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 0
+// OGCG: store i32 0, ptr %[[I]]
+// OGCG: %[[P:.*]] = getelementptr inbounds nuw %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 1
+// OGCG: %[[P_A:.*]] = getelementptr inbounds nuw %struct.Pair, ptr %[[P]], i32 0, i32 0
+// OGCG: store i32 0, ptr %[[P_A]]
+// OGCG: %[[P_B:.*]] = getelementptr inbounds nuw %struct.Pair, ptr %[[P]], i32 0, i32 1
+// OGCG: store i32 0, ptr %[[P_B]]
+// OGCG: %[[ARR:.*]] = getelementptr inbounds nuw %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 2
+// OGCG: %[[ARR_END:.*]] = getelementptr inbounds i32, ptr %[[ARR]], i64 4
+// OGCG: br label %[[LOOP_BODY:.*]]
+// OGCG: [[LOOP_BODY]]:
+// OGCG: %[[CUR:.*]] = phi ptr [ %[[ARR]], %entry ], [ %[[NEXT:.*]], %[[LOOP_BODY]] ]
+// OGCG: store i32 0, ptr %[[CUR]]
+// OGCG: %[[NEXT]] = getelementptr inbounds i32, ptr %[[CUR]], i64 1
+// OGCG: %[[CMP:.*]] = icmp eq ptr %[[NEXT]], %[[ARR_END]]
+// OGCG: br i1 %[[CMP]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]]
+// OGCG: [[LOOP_END]]:
+// OGCG: %[[C:.*]] = getelementptr inbounds nuw %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 3
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C]], i32 0, i32 1
+// OGCG: store float 0.000000e+00, ptr %[[C_REAL_PTR]]
+// OGCG: store float 0.000000e+00, ptr %[[C_IMAG_PTR]]
+// OGCG: %[[BF:.*]] = getelementptr inbounds nuw %struct.ZeroInit, ptr %[[THIS]], i32 0, i32 4
+// OGCG: store i8 0, ptr %[[BF]]
+
+struct ValueInit {
+ int i{1};
+ Pair p{2, 3};
+ int arr[4]{4, 5};
+ float _Complex c{6.0f, 7.0f};
+ unsigned bf : 8 {0xFF};
+ ValueInit() = default;
+};
+
+// CIR: cir.func{{.*}} @_ZN9ValueInitC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_ValueInit> {{.*}})
+// CIR: %[[ITER:.*]] = cir.alloca {{.*}} ["arrayinit.temp"]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA:.*]]
+// CIR: %[[I:.*]] = cir.get_member %[[THIS]][0] {name = "i"}
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store{{.*}} %[[ONE]], %[[I]]
+// CIR: %[[P:.*]] = cir.get_member %[[THIS]][1] {name = "p"}
+// CIR: %[[P_A:.*]] = cir.get_member %[[P]][0] {name = "a"}
+// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+// CIR: cir.store{{.*}} %[[TWO]], %[[P_A]]
+// CIR: %[[P_B:.*]] = cir.get_member %[[P]][1] {name = "b"}
+// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
+// CIR: cir.store{{.*}} %[[THREE]], %[[P_B]]
+// CIR: %[[ARR:.*]] = cir.get_member %[[THIS]][2] {name = "arr"}
+// CIR: %[[ARR_BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!s32i x 4>>), !cir.ptr<!s32i>
+// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i
+// CIR: cir.store{{.*}} %[[FOUR]], %[[ARR_BEGIN]]
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[SECOND:.*]] = cir.ptr_stride(%[[ARR_BEGIN]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i)
+// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: cir.store{{.*}} %[[FIVE]], %[[SECOND]]
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[SECOND]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i)
+// CIR: cir.store{{.*}} %[[NEXT]], %[[ITER]]
+// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s64i
+// CIR: %[[END:.*]] = cir.ptr_stride(%[[ARR_BEGIN]] : !cir.ptr<!s32i>, %[[FOUR]] : !s64i)
+// CIR: cir.do {
+// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[ITER]]
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[CUR]]
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CUR]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i)
+// CIR: cir.store{{.*}} %[[NEXT]], %[[ITER]]
+// CIR: cir.yield
+// CIR: } while {
+// CIR: %[[CUR:.*]] = cir.load{{.*}} %[[ITER]]
+// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[END]])
+// CIR: cir.condition(%[[CMP]])
+// CIR: }
+// CIR: %[[C:.*]] = cir.get_member %[[THIS]][3] {name = "c"}
+// CIR: %[[FOUR_FIVEI:.*]] = cir.const #cir.const_complex<#cir.fp<6.000000e+00> : !cir.float, #cir.fp<7.000000e+00>
+// CIR: cir.store{{.*}} %[[FOUR_FIVEI]], %[[C]]
+// CIR: %[[BF:.*]] = cir.get_member %[[THIS]][4] {name = "bf"}
+// CIR: %[[FF:.*]] = cir.const #cir.int<255> : !s32i
+// CIR: %[[FF_CAST:.*]] = cir.cast(integral, %[[FF]] : !s32i), !u32i
+// CIR: %[[BF_VAL:.*]] = cir.set_bitfield{{.*}} (#bfi_bf, %[[BF]] : !cir.ptr<!u8i>, %[[FF_CAST]] : !u32i)
+
+// LLVM: define{{.*}} void @_ZN9ValueInitC2Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr
+// LLVM: %[[ITER:.*]] = alloca ptr
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// LLVM: %[[I:.*]] = getelementptr %struct.ValueInit, ptr %[[THIS]], i32 0, i32 0
+// LLVM: store i32 1, ptr %[[I]]
+// LLVM: %[[P:.*]] = getelementptr %struct.ValueInit, ptr %[[THIS]], i32 0, i32 1
+// LLVM: %[[P_A:.*]] = getelementptr %struct.Pair, ptr %[[P]], i32 0, i32 0
+// LLVM: store i32 2, ptr %[[P_A]]
+// LLVM: %[[P_B:.*]] = getelementptr %struct.Pair, ptr %[[P]], i32 0, i32 1
+// LLVM: store i32 3, ptr %[[P_B]]
+// LLVM: %[[ARR:.*]] = getelementptr %struct.ValueInit, ptr %[[THIS]], i32 0, i32 2
+// LLVM: %[[ARR_BEGIN:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
+// LLVM: store i32 4, ptr %[[ARR_BEGIN]]
+// LLVM: %[[ARR_1:.*]] = getelementptr i32, ptr %[[ARR_BEGIN]], i64 1
+// LLVM: store i32 5, ptr %[[ARR_1]]
+// LLVM: %[[ARR_2:.*]] = getelementptr i32, ptr %[[ARR_1]], i64 1
+// LLVM: store ptr %[[ARR_2]], ptr %[[ITER]]
+// LLVM: %[[ARR_END:.*]] = getelementptr i32, ptr %[[ARR_BEGIN]], i64 4
+// LLVM: br label %[[LOOP_BODY:.*]]
+// LLVM: [[LOOP_COND:.*]]:
+// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[ARR_END]]
+// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]]
+// LLVM: [[LOOP_BODY]]:
+// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM: store i32 0, ptr %[[CUR]]
+// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1
+// LLVM: store ptr %[[NEXT]], ptr %[[ITER]]
+// LLVM: br label %[[LOOP_COND]]
+// LLVM: [[LOOP_END]]:
+// LLVM: %[[C:.*]] = getelementptr %struct.ValueInit, ptr %[[THIS]], i32 0, i32 3
+// LLVM: store { float, float } { float 6.000000e+00, float 7.000000e+00 }, ptr %[[C]]
+// LLVM: %[[BF:.*]] = getelementptr %struct.ValueInit, ptr %[[THIS]], i32 0, i32 4
+// LLVM: store i8 -1, ptr %[[BF]]
+
+// OGCG: define{{.*}} void @_ZN9ValueInitC2Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA:.*]]
+// OGCG: %[[I:.*]] = getelementptr inbounds nuw %struct.ValueInit, ptr %[[THIS]], i32 0, i32 0
+// OGCG: store i32 1, ptr %[[I]]
+// OGCG: %[[P:.*]] = getelementptr inbounds nuw %struct.ValueInit, ptr %[[THIS]], i32 0, i32 1
+// OGCG: %[[P_A:.*]] = getelementptr inbounds nuw %struct.Pair, ptr %[[P]], i32 0, i32 0
+// OGCG: store i32 2, ptr %[[P_A]]
+// OGCG: %[[P_B:.*]] = getelementptr inbounds nuw %struct.Pair, ptr %[[P]], i32 0, i32 1
+// OGCG: store i32 3, ptr %[[P_B]]
+// OGCG: %[[ARR:.*]] = getelementptr inbounds nuw %struct.ValueInit, ptr %[[THIS]], i32 0, i32 2
+// OGCG: store i32 4, ptr %[[ARR]]
+// OGCG: %[[ARR_1:.*]] = getelementptr inbounds i32, ptr %[[ARR]], i64 1
+// OGCG: store i32 5, ptr %[[ARR_1]]
+// OGCG: %[[ARR_BEGIN:.*]] = getelementptr inbounds i32, ptr %[[ARR]], i64 2
+// OGCG: %[[ARR_END:.*]] = getelementptr inbounds i32, ptr %[[ARR]], i64 4
+// OGCG: br label %[[LOOP_BODY:.*]]
+// OGCG: [[LOOP_BODY]]:
+// OGCG: %[[CUR:.*]] = phi ptr [ %[[ARR_BEGIN]], %entry ], [ %[[NEXT:.*]], %[[LOOP_BODY]] ]
+// OGCG: store i32 0, ptr %[[CUR]]
+// OGCG: %[[NEXT]] = getelementptr inbounds i32, ptr %[[CUR]], i64 1
+// OGCG: %[[CMP:.*]] = icmp eq ptr %[[NEXT]], %[[ARR_END]]
+// OGCG: br i1 %[[CMP]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]]
+// OGCG: [[LOOP_END]]:
+// OGCG: %[[C:.*]] = getelementptr inbounds nuw %struct.ValueInit, ptr %[[THIS]], i32 0, i32 3
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C]], i32 0, i32 1
+// OGCG: store float 6.000000e+00, ptr %[[C_REAL_PTR]]
+// OGCG: store float 7.000000e+00, ptr %[[C_IMAG_PTR]]
+// OGCG: %[[BF:.*]] = getelementptr inbounds nuw %struct.ValueInit, ptr %[[THIS]], i32 0, i32 4
+// OGCG: store i8 -1, ptr %[[BF]]
+
+void use_structs() {
+ ZeroInit zi;
+ ValueInit vi;
+}
diff --git a/clang/test/CIR/CodeGen/delegating-ctor.cpp b/clang/test/CIR/CodeGen/delegating-ctor.cpp
new file mode 100644
index 000000000000..73ee6b719940
--- /dev/null
+++ b/clang/test/CIR/CodeGen/delegating-ctor.cpp
@@ -0,0 +1,333 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct Delegating {
+ Delegating();
+ Delegating(int);
+};
+
+// Check that the constructor being delegated to is called with the correct
+// arguments.
+Delegating::Delegating() : Delegating(0) {}
+
+// CIR: cir.func {{.*}} @_ZN10DelegatingC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Delegating> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Delegating>, !cir.ptr<!cir.ptr<!rec_Delegating>>, ["this", init]
+// CIR: cir.store{{.*}} %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.call @_ZN10DelegatingC2Ei(%[[THIS]], %[[ZERO]]) : (!cir.ptr<!rec_Delegating>, !s32i) -> ()
+
+// LLVM: define {{.*}} @_ZN10DelegatingC2Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: call void @_ZN10DelegatingC2Ei(ptr %[[THIS]], i32 0)
+
+// OGCG: define {{.*}} @_ZN10DelegatingC2Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: call void @_ZN10DelegatingC2Ei(ptr {{.*}} %[[THIS]], i32 {{.*}} 0)
+
+struct DelegatingWithZeroing {
+ int i;
+ DelegatingWithZeroing() = default;
+ DelegatingWithZeroing(int);
+};
+
+// Check that the delegating constructor performs zero-initialization here.
+// FIXME: we should either emit the trivial default constructor or remove the
+// call to it in a lowering pass.
+DelegatingWithZeroing::DelegatingWithZeroing(int) : DelegatingWithZeroing() {}
+
+// CIR: cir.func {{.*}} @_ZN21DelegatingWithZeroingC2Ei(%[[THIS_ARG:.*]]: !cir.ptr<!rec_DelegatingWithZeroing> {{.*}}, %[[I_ARG:.*]]: !s32i {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_DelegatingWithZeroing>, !cir.ptr<!cir.ptr<!rec_DelegatingWithZeroing>>, ["this", init]
+// CIR: %[[I_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["", init]
+// CIR: cir.store{{.*}} %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store{{.*}} %[[I_ARG]], %[[I_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !rec_DelegatingWithZeroing
+// CIR: cir.store{{.*}} %[[ZERO]], %[[THIS]] : !rec_DelegatingWithZeroing, !cir.ptr<!rec_DelegatingWithZeroing>
+
+// LLVM: define {{.*}} void @_ZN21DelegatingWithZeroingC2Ei(ptr %[[THIS_ARG:.*]], i32 %[[I_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[I_ADDR:.*]] = alloca i32
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store i32 %[[I_ARG]], ptr %[[I_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: store %struct.DelegatingWithZeroing zeroinitializer, ptr %[[THIS]]
+
+// Note: OGCG elides the call to the default constructor.
+
+// OGCG: define {{.*}} void @_ZN21DelegatingWithZeroingC2Ei(ptr {{.*}} %[[THIS_ARG:.*]], i32 {{.*}} %[[I_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[I_ADDR:.*]] = alloca i32
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store i32 %[[I_ARG]], ptr %[[I_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[THIS]], i8 0, i64 4, i1 false)
+
+void other();
+
+class Base {
+public:
+ Base() { squawk(); }
+
+ virtual void squawk();
+};
+
+class Derived : public virtual Base {
+public:
+ Derived();
+ Derived(const void *inVoid);
+
+ virtual void squawk();
+};
+
+Derived::Derived() : Derived(nullptr) { other(); }
+Derived::Derived(const void *inVoid) { squawk(); }
+
+// Note: OGCG emits the constructors in a different order.
+// OGCG: define {{.*}} void @_ZN7DerivedC2Ev(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: call void @_ZN7DerivedC2EPKv(ptr {{.*}} %[[THIS]], ptr {{.*}} %[[VTT]], ptr {{.*}} null)
+// OGCG: call void @_Z5otherv()
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC2EPKv(
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived>
+// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>>
+// CIR-SAME: %[[INVOID_ARG:.*]]: !cir.ptr<!void>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: %[[INVOID_ADDR:.*]] = cir.alloca {{.*}} ["inVoid", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: cir.store %[[INVOID_ARG]], %[[INVOID_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load{{.*}} %[[VTT_ADDR]]
+// CIR: %[[VPTR_GLOBAL_ADDR:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_PTR:.*]] = cir.cast(bitcast, %[[VPTR_GLOBAL_ADDR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_BASE_PTR:.*]] = cir.cast(bitcast, %[[VPTR_BASE_ADDR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_DERIVED_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_DERIVED:.*]] = cir.load{{.*}} %[[VPTR_DERIVED_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_DERIVED_AS_I8PTR:.*]] = cir.cast(bitcast, %[[VPTR_DERIVED]] : !cir.vptr), !cir.ptr<!u8i>
+// CIR: %[[BASE_LOC_OFFSET:.*]] = cir.const #cir.int<-32> : !s64i
+// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.ptr_stride(%[[VPTR_DERIVED_AS_I8PTR]] : !cir.ptr<!u8i>, %[[BASE_LOC_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_OFFSET_I64PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
+// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_I64PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[THIS_AS_I8PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_Derived>), !cir.ptr<!u8i>
+// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_AS_I8PTR]] : !cir.ptr<!u8i>, %[[BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_AS_I8PTR:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!rec_Derived>
+// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_AS_I8PTR]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR_BASE]], %[[BASE_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[SQUAWK_FN_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR_BASE]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>
+// CIR: %[[SQUAWK:.*]] = cir.load{{.*}} %[[SQUAWK_FN_ADDR]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>
+// CIR: cir.call %[[SQUAWK]](%[[THIS]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>, !cir.ptr<!rec_Derived>) -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC2EPKv(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]], ptr %[[INVOID_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: %[[INVOID_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// LLVM: store ptr %[[VPTR]], ptr %[[THIS]]
+// LLVM: %[[VTT_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 1
+// LLVM: %[[VPTR_BASE:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -32
+// LLVM: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// LLVM: %[[BASE_PTR:.*]] = getelementptr i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// LLVM: store ptr %[[VPTR_BASE]], ptr %[[BASE_PTR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[SQUAWK_FN_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0
+// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_FN_ADDR]]
+// LLVM: call void %[[SQUAWK]](ptr %[[THIS]])
+// LLVM: ret void
+
+// OGCG: define {{.*}} void @_ZN7DerivedC2EPKv(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]], ptr {{.*}} %[[INVOID_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: %[[INVOID_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// OGCG: store ptr %[[VPTR]], ptr %[[THIS]]
+// OGCG: %[[VTT_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1
+// OGCG: %[[VPTR_BASE:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -32
+// OGCG: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// OGCG: %[[BASE_PTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// OGCG: store ptr %[[VPTR_BASE]], ptr %[[BASE_PTR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[SQUAWK_FN_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0
+// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_FN_ADDR]]
+// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]])
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}, %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load {{.*}} %[[VTT_ADDR]]
+// CIR: %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR: cir.call @_ZN7DerivedC2EPKv(%[[THIS]], %[[VTT]], %[[NULLPTR]]) : (!cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>) -> ()
+// CIR: cir.call @_Z5otherv() : () -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC2Ev(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: call void @_ZN7DerivedC2EPKv(ptr %[[THIS]], ptr %[[VTT]], ptr null)
+// LLVM: call void @_Z5otherv()
+// LLVM: ret void
+
+// See above for the OGCG _ZN7DerivedC2Ev constructor.
+
+// CIR: cir.func {{.*}} @_ZN4BaseC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Base> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT_ADDR_POINT:.*]] = cir.vtable.address_point(@_ZTV4Base, address_point = <index = 0, offset = 2>) : !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Base> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VTT_ADDR_POINT]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Base> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VIRTUAL_FN_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Base>)>>>
+// CIR: %[[VIRTUAL_FN:.*]] = cir.load{{.*}} %[[VIRTUAL_FN_ADDR]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Base>)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_Base>)>>
+// CIR: cir.call %[[VIRTUAL_FN]](%[[THIS]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Base>)>>, !cir.ptr<!rec_Base>) -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN4BaseC2Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV4Base, i64 16), ptr %[[THIS]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0
+// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]]
+// LLVM: call void %[[SQUAWK]](ptr %[[THIS]])
+// LLVM: ret void
+
+// The base constructor is emitted last for OGCG.
+// The _ZN7DerivedC1Ev constructor is emitted earlier for OGCG.
+
+// OGCG: define {{.*}} void @_ZN7DerivedC1Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: call void @_ZN7DerivedC1EPKv(ptr {{.*}} %[[THIS]], ptr {{.*}} null)
+// OGCG: call void @_Z5otherv()
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC1EPKv(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}, %[[INVOID_ARG:.*]]: !cir.ptr<!void> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[INVOID_ADDR:.*]] = cir.alloca {{.*}} ["inVoid", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[INVOID_ARG]], %[[INVOID_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[BASE:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+// CIR: cir.call @_ZN4BaseC2Ev(%[[BASE]])
+// CIR: %[[VPTR_GLOBAL:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 4>) : !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR_GLOBAL]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_GLOBAL:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = <index = 0, offset = 4>) : !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR_GLOBAL]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[SQUAWK_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>
+// CIR: %[[SQUAWK:.*]] = cir.load{{.*}} %[[SQUAWK_ADDR]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>
+// CIR: cir.call %[[SQUAWK]](%[[THIS]])
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC1EPKv(ptr %[[THIS_ARG:.*]], ptr %[[INVOID_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[INVOID_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: call void @_ZN4BaseC2Ev(ptr %[[THIS]])
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 32), ptr %[[THIS]]
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 32), ptr %[[THIS]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0
+// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]]
+// LLVM: call void %[[SQUAWK]](ptr %[[THIS]])
+// LLVM: ret void
+
+// OGCG: define {{.*}} void @_ZN7DerivedC1EPKv(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[INVOID_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[INVOID_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: call void @_ZN4BaseC2Ev(ptr {{.*}} %[[THIS]])
+// OGCG: store ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV7Derived, i32 0, i32 0, i32 4), ptr %[[THIS]]
+// OGCG: store ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV7Derived, i32 0, i32 0, i32 4), ptr %[[THIS]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0
+// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]]
+// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]])
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC1Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR: cir.call @_ZN7DerivedC1EPKv(%[[THIS]], %[[NULLPTR]]) : (!cir.ptr<!rec_Derived>, !cir.ptr<!void>) -> ()
+// CIR: cir.call @_Z5otherv() : () -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC1Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: call void @_ZN7DerivedC1EPKv(ptr %[[THIS]], ptr null)
+// LLVM: call void @_Z5otherv()
+// LLVM: ret void
+
+// The _ZN7DerivedC1Ev constructor was emitted earlier for OGCG.
+
+// OGCG: define {{.*}} void @_ZN4BaseC2Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV4Base, i32 0, i32 0, i32 2), ptr %[[THIS]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0
+// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]]
+// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]])
+// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/local-vars.cpp b/clang/test/CIR/CodeGen/local-vars.cpp
index 9385fdfa6560..0c5c97246975 100644
--- a/clang/test/CIR/CodeGen/local-vars.cpp
+++ b/clang/test/CIR/CodeGen/local-vars.cpp
@@ -1,5 +1,9 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-cir.ll
-// RUN: FileCheck -input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
void test() {
int i = 1;
@@ -21,46 +25,182 @@ void test() {
bool uib;
}
-// CHECK: module
-// CHECK: cir.func{{.*}} @_Z4testv()
-// CHECK: %[[I_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
-// CHECK: %[[L_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["l", init] {alignment = 8 : i64}
-// CHECK: %[[F_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init] {alignment = 4 : i64}
-// CHECK: %[[D_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["d", init] {alignment = 8 : i64}
-// CHECK: %[[B1_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b1", init] {alignment = 1 : i64}
-// CHECK: %[[B2_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b2", init] {alignment = 1 : i64}
-// CHECK: %[[CI_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ci", init, const] {alignment = 4 : i64}
-// CHECK: %[[CL_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["cl", init, const] {alignment = 8 : i64}
-// CHECK: %[[CF_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["cf", init, const] {alignment = 4 : i64}
-// CHECK: %[[CD_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["cd", init, const] {alignment = 8 : i64}
-// CHECK: %[[CB1_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cb1", init, const] {alignment = 1 : i64}
-// CHECK: %[[CB2_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cb2", init, const] {alignment = 1 : i64}
-// CHECK: %[[UII_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["uii"] {alignment = 4 : i64}
-// CHECK: %[[UIL_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["uil"] {alignment = 8 : i64}
-// CHECK: %[[UIF_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["uif"] {alignment = 4 : i64}
-// CHECK: %[[UID_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["uid"] {alignment = 8 : i64}
-// CHECK: %[[UIB_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["uib"] {alignment = 1 : i64}
-// CHECK: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
-// CHECK: cir.store align(4) %[[ONE]], %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
-// CHECK: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i
-// CHECK: cir.store align(8) %[[TWO]], %[[L_PTR]] : !s64i, !cir.ptr<!s64i>
-// CHECK: %[[THREE:.*]] = cir.const #cir.fp<3.0{{.*}}> : !cir.float
-// CHECK: cir.store align(4) %[[THREE]], %[[F_PTR]] : !cir.float, !cir.ptr<!cir.float>
-// CHECK: %[[FOUR:.*]] = cir.const #cir.fp<4.0{{.*}}> : !cir.double
-// CHECK: cir.store align(8) %[[FOUR]], %[[D_PTR]] : !cir.double, !cir.ptr<!cir.double>
-// CHECK: %[[TRUE:.*]] = cir.const #true
-// CHECK: cir.store align(1) %[[TRUE]], %[[B1_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
-// CHECK: %[[FALSE:.*]] = cir.const #false
-// CHECK: cir.store align(1) %[[FALSE]], %[[B2_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
-// CHECK: %[[ONEC:.*]] = cir.const #cir.int<1> : !s32i
-// CHECK: cir.store align(4) %[[ONEC]], %[[CI_PTR]] : !s32i, !cir.ptr<!s32i>
-// CHECK: %[[TWOC:.*]] = cir.const #cir.int<2> : !s64i
-// CHECK: cir.store align(8) %[[TWOC]], %[[CL_PTR]] : !s64i, !cir.ptr<!s64i>
-// CHECK: %[[THREEC:.*]] = cir.const #cir.fp<3.0{{.*}}> : !cir.float
-// CHECK: cir.store align(4) %[[THREEC]], %[[CF_PTR]] : !cir.float, !cir.ptr<!cir.float>
-// CHECK: %[[FOURC:.*]] = cir.const #cir.fp<4.0{{.*}}> : !cir.double
-// CHECK: cir.store align(8) %[[FOURC]], %[[CD_PTR]] : !cir.double, !cir.ptr<!cir.double>
-// CHECK: %[[TRUEC:.*]] = cir.const #true
-// CHECK: cir.store align(1) %[[TRUEC]], %[[CB1_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
-// CHECK: %[[FALSEC:.*]] = cir.const #false
-// CHECK: cir.store align(1) %[[FALSEC]], %[[CB2_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: module
+// CIR: cir.func{{.*}} @_Z4testv()
+// CIR: %[[I_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
+// CIR: %[[L_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["l", init] {alignment = 8 : i64}
+// CIR: %[[F_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init] {alignment = 4 : i64}
+// CIR: %[[D_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["d", init] {alignment = 8 : i64}
+// CIR: %[[B1_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b1", init] {alignment = 1 : i64}
+// CIR: %[[B2_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b2", init] {alignment = 1 : i64}
+// CIR: %[[CI_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ci", init, const] {alignment = 4 : i64}
+// CIR: %[[CL_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["cl", init, const] {alignment = 8 : i64}
+// CIR: %[[CF_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["cf", init, const] {alignment = 4 : i64}
+// CIR: %[[CD_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["cd", init, const] {alignment = 8 : i64}
+// CIR: %[[CB1_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cb1", init, const] {alignment = 1 : i64}
+// CIR: %[[CB2_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["cb2", init, const] {alignment = 1 : i64}
+// CIR: %[[UII_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["uii"] {alignment = 4 : i64}
+// CIR: %[[UIL_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["uil"] {alignment = 8 : i64}
+// CIR: %[[UIF_PTR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["uif"] {alignment = 4 : i64}
+// CIR: %[[UID_PTR:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["uid"] {alignment = 8 : i64}
+// CIR: %[[UIB_PTR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["uib"] {alignment = 1 : i64}
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store align(4) %[[ONE]], %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i
+// CIR: cir.store align(8) %[[TWO]], %[[L_PTR]] : !s64i, !cir.ptr<!s64i>
+// CIR: %[[THREE:.*]] = cir.const #cir.fp<3.0{{.*}}> : !cir.float
+// CIR: cir.store align(4) %[[THREE]], %[[F_PTR]] : !cir.float, !cir.ptr<!cir.float>
+// CIR: %[[FOUR:.*]] = cir.const #cir.fp<4.0{{.*}}> : !cir.double
+// CIR: cir.store align(8) %[[FOUR]], %[[D_PTR]] : !cir.double, !cir.ptr<!cir.double>
+// CIR: %[[TRUE:.*]] = cir.const #true
+// CIR: cir.store align(1) %[[TRUE]], %[[B1_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: %[[FALSE:.*]] = cir.const #false
+// CIR: cir.store align(1) %[[FALSE]], %[[B2_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: %[[ONEC:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store align(4) %[[ONEC]], %[[CI_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TWOC:.*]] = cir.const #cir.int<2> : !s64i
+// CIR: cir.store align(8) %[[TWOC]], %[[CL_PTR]] : !s64i, !cir.ptr<!s64i>
+// CIR: %[[THREEC:.*]] = cir.const #cir.fp<3.0{{.*}}> : !cir.float
+// CIR: cir.store align(4) %[[THREEC]], %[[CF_PTR]] : !cir.float, !cir.ptr<!cir.float>
+// CIR: %[[FOURC:.*]] = cir.const #cir.fp<4.0{{.*}}> : !cir.double
+// CIR: cir.store align(8) %[[FOURC]], %[[CD_PTR]] : !cir.double, !cir.ptr<!cir.double>
+// CIR: %[[TRUEC:.*]] = cir.const #true
+// CIR: cir.store align(1) %[[TRUEC]], %[[CB1_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: %[[FALSEC:.*]] = cir.const #false
+// CIR: cir.store align(1) %[[FALSEC]], %[[CB2_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// LLVM: define dso_local void @_Z4testv()
+// LLVM: %[[I_PTR:.+]] = alloca i32
+// LLVM: %[[L_PTR:.+]] = alloca i64
+// LLVM: %[[F_PTR:.+]] = alloca float
+// LLVM: %[[D_PTR:.+]] = alloca double
+// LLVM: %[[B1_PTR:.+]] = alloca i8
+// LLVM: %[[B2_PTR:.+]] = alloca i8
+// LLVM: %[[CI_PTR:.+]] = alloca i32
+// LLVM: %[[CL_PTR:.+]] = alloca i64
+// LLVM: %[[CF_PTR:.+]] = alloca float
+// LLVM: %[[CD_PTR:.+]] = alloca double
+// LLVM: %[[CB1_PTR:.+]] = alloca i8
+// LLVM: %[[CB2_PTR:.+]] = alloca i8
+// LLVM: %[[UII_PTR:.+]] = alloca i32
+// LLVM: %[[UIL_PTR:.+]] = alloca i64
+// LLVM: %[[UIF_PTR:.+]] = alloca float
+// LLVM: %[[UID_PTR:.+]] = alloca double
+// LLVM: %[[UIB_PTR:.+]] = alloca i8
+// LLVM: store i32 1, ptr %[[I_PTR]]
+// LLVM: store i64 2, ptr %[[L_PTR]]
+// LLVM: store float 3.000000e+00, ptr %[[F_PTR]]
+// LLVM: store double 4.000000e+00, ptr %[[D_PTR]]
+// LLVM: store i8 1, ptr %[[B1_PTR]]
+// LLVM: store i8 0, ptr %[[B2_PTR]]
+// LLVM: store i32 1, ptr %[[CI_PTR]]
+// LLVM: store i64 2, ptr %[[CL_PTR]]
+// LLVM: store float 3.000000e+00, ptr %[[CF_PTR]]
+// LLVM: store double 4.000000e+00, ptr %[[CD_PTR]]
+// LLVM: store i8 1, ptr %[[CB1_PTR]]
+// LLVM: store i8 0, ptr %[[CB2_PTR]]
+// LLVM: ret void
+
+// OGCG: define dso_local void @_Z4testv()
+// OGCG: %[[I_PTR:.+]] = alloca i32
+// OGCG: %[[L_PTR:.+]] = alloca i64
+// OGCG: %[[F_PTR:.+]] = alloca float
+// OGCG: %[[D_PTR:.+]] = alloca double
+// OGCG: %[[B1_PTR:.+]] = alloca i8
+// OGCG: %[[B2_PTR:.+]] = alloca i8
+// OGCG: %[[CI_PTR:.+]] = alloca i32
+// OGCG: %[[CL_PTR:.+]] = alloca i64
+// OGCG: %[[CF_PTR:.+]] = alloca float
+// OGCG: %[[CD_PTR:.+]] = alloca double
+// OGCG: %[[CB1_PTR:.+]] = alloca i8
+// OGCG: %[[CB2_PTR:.+]] = alloca i8
+// OGCG: %[[UII_PTR:.+]] = alloca i32
+// OGCG: %[[UIL_PTR:.+]] = alloca i64
+// OGCG: %[[UIF_PTR:.+]] = alloca float
+// OGCG: %[[UID_PTR:.+]] = alloca double
+// OGCG: %[[UIB_PTR:.+]] = alloca i8
+// OGCG: store i32 1, ptr %[[I_PTR]]
+// OGCG: store i64 2, ptr %[[L_PTR]]
+// OGCG: store float 3.000000e+00, ptr %[[F_PTR]]
+// OGCG: store double 4.000000e+00, ptr %[[D_PTR]]
+// OGCG: store i8 1, ptr %[[B1_PTR]]
+// OGCG: store i8 0, ptr %[[B2_PTR]]
+// OGCG: store i32 1, ptr %[[CI_PTR]]
+// OGCG: store i64 2, ptr %[[CL_PTR]]
+// OGCG: store float 3.000000e+00, ptr %[[CF_PTR]]
+// OGCG: store double 4.000000e+00, ptr %[[CD_PTR]]
+// OGCG: store i8 1, ptr %[[CB1_PTR]]
+// OGCG: store i8 0, ptr %[[CB2_PTR]]
+// OGCG: ret void
+
+void value_init() {
+ float f{};
+ bool b{};
+ int i{};
+
+ float f2 = {};
+ bool b2 = {};
+ int i2 = {};
+
+ bool scalar_value_init_expr = int() == 0;
+}
+
+// CIR: cir.func{{.*}} @_Z10value_initv()
+// CIR: %[[F_PTR:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init]
+// CIR: %[[B_PTR:.+]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b", init]
+// CIR: %[[I_PTR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init]
+// CIR: %[[F2_PTR:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f2", init]
+// CIR: %[[B2_PTR:.+]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b2", init]
+// CIR: %[[I2_PTR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i2", init]
+// CIR: %[[S_PTR:.+]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["scalar_value_init_expr", init]
+// CIR: %[[ZEROF1:.+]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR: cir.store{{.*}} %[[ZEROF1]], %[[F_PTR]] : !cir.float, !cir.ptr<!cir.float>
+// CIR: %[[FALSE1:.+]] = cir.const #false
+// CIR: cir.store{{.*}} %[[FALSE1]], %[[B_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: %[[ZEROI1:.+]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZEROI1]], %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[ZEROF2:.+]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR: cir.store{{.*}} %[[ZEROF2]], %[[F2_PTR]] : !cir.float, !cir.ptr<!cir.float>
+// CIR: %[[FALSE2:.+]] = cir.const #false
+// CIR: cir.store{{.*}} %[[FALSE2]], %[[B2_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: %[[ZEROI2:.+]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZEROI2]], %[[I2_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[ZEROI_LHS:.+]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[ZEROI_RHS:.+]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[CMP:.+]] = cir.cmp(eq, %[[ZEROI_LHS]], %[[ZEROI_RHS]]) : !s32i, !cir.bool
+// CIR: cir.store{{.*}} %[[CMP]], %[[S_PTR]] : !cir.bool, !cir.ptr<!cir.bool>
+// CIR: cir.return
+
+// LLVM: define{{.*}} void @_Z10value_initv()
+// LLVM: %[[F_PTR:.+]] = alloca float
+// LLVM: %[[B_PTR:.+]] = alloca i8
+// LLVM: %[[I_PTR:.+]] = alloca i32
+// LLVM: %[[F2_PTR:.+]] = alloca float
+// LLVM: %[[B2_PTR:.+]] = alloca i8
+// LLVM: %[[I2_PTR:.+]] = alloca i32
+// LLVM: %[[S_PTR:.+]] = alloca i8
+// LLVM: store float 0.000000e+00, ptr %[[F_PTR]]
+// LLVM: store i8 0, ptr %[[B_PTR]]
+// LLVM: store i32 0, ptr %[[I_PTR]]
+// LLVM: store float 0.000000e+00, ptr %[[F2_PTR]]
+// LLVM: store i8 0, ptr %[[B2_PTR]]
+// LLVM: store i32 0, ptr %[[I2_PTR]]
+// LLVM: store i8 1, ptr %[[S_PTR]]
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_Z10value_initv()
+// OGCG: %[[F_PTR:.+]] = alloca float
+// OGCG: %[[B_PTR:.+]] = alloca i8
+// OGCG: %[[I_PTR:.+]] = alloca i32
+// OGCG: %[[F2_PTR:.+]] = alloca float
+// OGCG: %[[B2_PTR:.+]] = alloca i8
+// OGCG: %[[I2_PTR:.+]] = alloca i32
+// OGCG: %[[S_PTR:.+]] = alloca i8
+// OGCG: store float 0.000000e+00, ptr %[[F_PTR]]
+// OGCG: store i8 0, ptr %[[B_PTR]]
+// OGCG: store i32 0, ptr %[[I_PTR]]
+// OGCG: store float 0.000000e+00, ptr %[[F2_PTR]]
+// OGCG: store i8 0, ptr %[[B2_PTR]]
+// OGCG: store i32 0, ptr %[[I2_PTR]]
+// OGCG: store i8 1, ptr %[[S_PTR]]
+// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/mms-bitfields.c b/clang/test/CIR/CodeGen/mms-bitfields.c
new file mode 100644
index 000000000000..698034aadb10
--- /dev/null
+++ b/clang/test/CIR/CodeGen/mms-bitfields.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -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 -mms-bitfields -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 -mms-bitfields -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct s1 {
+ int f32 : 2;
+ long long f64 : 30;
+} s1;
+
+// CIR-DAG: !rec_s1 = !cir.record<struct "s1" {!s32i, !s64i}>
+// LLVM-DAG: %struct.s1 = type { i32, i64 }
+// OGCG-DAG: %struct.s1 = type { i32, i64 }
+
+struct s2 {
+ int a : 24;
+ char b;
+ int c : 30;
+} Clip;
+
+// CIR-DAG: !rec_s2 = !cir.record<struct "s2" {!s32i, !s8i, !s32i}>
+// LLVM-DAG: %struct.s2 = type { i32, i8, i32 }
+// OGCG-DAG: %struct.s2 = type { i32, i8, i32 }
+
+struct s3 {
+ int a : 18;
+ int : 0;
+ int c : 14;
+} zero_bit;
+
+// CIR-DAG: !rec_s3 = !cir.record<struct "s3" {!s32i, !s32i}>
+// LLVM-DAG: %struct.s3 = type { i32, i32 }
+// OGCG-DAG: %struct.s3 = type { i32, i32 }
+
+#pragma pack (push,1)
+
+struct Inner {
+ unsigned int A : 1;
+ unsigned int B : 1;
+ unsigned int C : 1;
+ unsigned int D : 30;
+} Inner;
+
+#pragma pack (pop)
+
+// CIR-DAG: !rec_Inner = !cir.record<struct "Inner" {!u32i, !u32i}>
+// LLVM-DAG: %struct.Inner = type { i32, i32 }
+// OGCG-DAG: %struct.Inner = type { i32, i32 }
+
+#pragma pack(push, 1)
+
+union HEADER {
+ struct A {
+ int : 3; // Bits 2:0
+ int a : 9; // Bits 11:3
+ int : 12; // Bits 23:12
+ int b : 17; // Bits 40:24
+ int : 7; // Bits 47:41
+ int c : 4; // Bits 51:48
+ int : 4; // Bits 55:52
+ int d : 3; // Bits 58:56
+ int : 5; // Bits 63:59
+ } Bits;
+} HEADER;
+
+#pragma pack(pop)
+
+// CIR-DAG: !rec_A = !cir.record<struct "A" {!s32i, !s32i, !s32i}>
+// CIR-DAG: !rec_HEADER = !cir.record<union "HEADER" {!rec_A}>
+// LLVM-DAG: %struct.A = type { i32, i32, i32 }
+// LLVM-DAG: %union.HEADER = type { %struct.A }
+// OGCG-DAG: %struct.A = type { i32, i32, i32 }
+// OGCG-DAG: %union.HEADER = type { %struct.A }
diff --git a/clang/test/CIR/CodeGen/multi-vtable.cpp b/clang/test/CIR/CodeGen/multi-vtable.cpp
new file mode 100644
index 000000000000..b42f8a651809
--- /dev/null
+++ b/clang/test/CIR/CodeGen/multi-vtable.cpp
@@ -0,0 +1,183 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fno-rtti -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fno-rtti -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fno-rtti -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// Note: This test is using -fno-rtti so that we can delay implemntation of that handling.
+// When rtti handling for vtables is implemented, that option should be removed.
+
+class Mother {
+public:
+ virtual void MotherKey();
+ void simple() { }
+ virtual void MotherNonKey() {}
+};
+
+class Father {
+public:
+ virtual void FatherKey();
+};
+
+class Child : public Mother, public Father {
+public:
+ Child();
+ void MotherKey() override;
+};
+
+void Mother::MotherKey() {}
+void Father::FatherKey() {}
+void Child::MotherKey() {}
+
+// CIR-DAG: [[MOTHER_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
+// CIR-DAG: [[FATHER_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 3>}>
+// CIR-DAG: [[CHILD_VTABLE_TYPE:.*]] = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 3>}>
+// CIR-DAG: !rec_Father = !cir.record<class "Father" {!cir.vptr}
+// CIR-DAG: !rec_Mother = !cir.record<class "Mother" {!cir.vptr}
+// CIR-DAG: !rec_Child = !cir.record<class "Child" {!rec_Mother, !rec_Father}
+
+// Child vtable
+
+// CIR: cir.global "private" external @_ZTV5Child = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN5Child9MotherKeyEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother12MotherNonKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Father9FatherKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 3>
+// CIR-SAME: }> : [[CHILD_VTABLE_TYPE]]
+
+// LLVM: @_ZTV5Child = global { [4 x ptr], [3 x ptr] } {
+// LLVM-SAME: [4 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN5Child9MotherKeyEv,
+// LLVM-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// LLVM-SAME: ],
+// LLVM-SAME: [3 x ptr] [
+// LLVM-SAME: ptr inttoptr (i64 -8 to ptr),
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Father9FatherKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV5Child = unnamed_addr constant { [4 x ptr], [3 x ptr] } {
+// OGCG-SAME: [4 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN5Child9MotherKeyEv,
+// OGCG-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// OGCG-SAME: ],
+// OGCG-SAME: [3 x ptr] [
+// OGCG-SAME: ptr inttoptr (i64 -8 to ptr),
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Father9FatherKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
+
+// Mother vtable
+
+// CIR: cir.global "private" external @_ZTV6Mother = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother9MotherKeyEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Mother12MotherNonKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : [[MOTHER_VTABLE_TYPE]]
+
+// LLVM: @_ZTV6Mother = global { [4 x ptr] } {
+// LLVM-SAME: [4 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Mother9MotherKeyEv,
+// LLVM-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV6Mother = unnamed_addr constant { [4 x ptr] } {
+// OGCG-SAME: [4 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Mother9MotherKeyEv,
+// OGCG-SAME: ptr @_ZN6Mother12MotherNonKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
+
+// Father vtable
+
+// CIR: cir.global "private" external @_ZTV6Father = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN6Father9FatherKeyEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 3>
+// CIR-SAME: }> : [[FATHER_VTABLE_TYPE]]
+
+// LLVM: @_ZTV6Father = global { [3 x ptr] } {
+// LLVM-SAME: [3 x ptr] [
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr null,
+// LLVM-SAME: ptr @_ZN6Father9FatherKeyEv
+// LLVM-SAME: ]
+// LLVM-SAME: }
+
+// OGCG: @_ZTV6Father = unnamed_addr constant { [3 x ptr] } {
+// OGCG-SAME: [3 x ptr] [
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr null,
+// OGCG-SAME: ptr @_ZN6Father9FatherKeyEv
+// OGCG-SAME: ]
+// OGCG-SAME: }
+
+
+Child::Child() {}
+
+// CIR: cir.func {{.*}} @_ZN5ChildC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Child>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[MOTHER_BASE:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_Child> nonnull [0] -> !cir.ptr<!rec_Mother>
+// CIR: cir.call @_ZN6MotherC2Ev(%[[MOTHER_BASE]]) nothrow : (!cir.ptr<!rec_Mother>) -> ()
+// CIR: %[[FATHER_BASE:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_Child> nonnull [8] -> !cir.ptr<!rec_Father>
+// CIR: cir.call @_ZN6FatherC2Ev(%[[FATHER_BASE]]) nothrow : (!cir.ptr<!rec_Father>) -> ()
+// CIR: %[[CHILD_VPTR:.*]] = cir.vtable.address_point(@_ZTV5Child, address_point = <index = 0, offset = 2>) : !cir.vptr
+// CIR: %[[CHILD_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Child> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[CHILD_VPTR]], %[[CHILD_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[FATHER_IN_CHILD_VPTR:.*]] = cir.vtable.address_point(@_ZTV5Child, address_point = <index = 1, offset = 2>) : !cir.vptr
+// CIR: %[[FATHER_BASE:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_Child> nonnull [8] -> !cir.ptr<!rec_Father>
+// CIR: %[[FATHER_IN_CHILD_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[FATHER_BASE]] : !cir.ptr<!rec_Father> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[FATHER_IN_CHILD_VPTR]], %[[FATHER_IN_CHILD_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: cir.return
+
+// The GEP instructions are different between LLVM and OGCG, but they calculate the same addresses.
+
+// LLVM: define{{.*}} void @_ZN5ChildC2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: call void @_ZN6MotherC2Ev(ptr{{.*}} %[[THIS]])
+// LLVM: %[[FATHER_BASE:.*]] = getelementptr{{.*}} i8, ptr %[[THIS]], i32 8
+// LLVM: call void @_ZN6FatherC2Ev(ptr{{.*}} %[[FATHER_BASE]])
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV5Child, i64 16), ptr %[[THIS]]
+// LLVM: %[[FATHER_BASE:.*]] = getelementptr{{.*}} i8, ptr %[[THIS]], i32 8
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV5Child, i64 48), ptr %[[FATHER_BASE]]
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_ZN5ChildC2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: call void @_ZN6MotherC2Ev(ptr {{.*}} %[[THIS]])
+// OGCG: %[[FATHER_BASE:.*]] = getelementptr{{.*}} i8, ptr %[[THIS]], i64 8
+// OGCG: call void @_ZN6FatherC2Ev(ptr{{.*}} %[[FATHER_BASE]])
+// OGCG: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr], [3 x ptr] }, ptr @_ZTV5Child, i32 0, i32 0, i32 2), ptr %[[THIS]]
+// OGCG: %[[FATHER_BASE:.*]] = getelementptr{{.*}} i8, ptr %[[THIS]], i64 8
+// OGCG: store ptr getelementptr inbounds inrange(-16, 8) ({ [4 x ptr], [3 x ptr] }, ptr @_ZTV5Child, i32 0, i32 1, i32 2), ptr %[[FATHER_BASE]]
+// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp
index 4f88addc6116..31adb9bf4859 100644
--- a/clang/test/CIR/CodeGen/new.cpp
+++ b/clang/test/CIR/CodeGen/new.cpp
@@ -23,7 +23,6 @@ void test_basic_new() {
// CHECK: %[[EIGHT:.*]] = cir.const #cir.int<8>
// CHECK: %[[NEW_S:.*]] = cir.call @_Znwm(%[[EIGHT]])
// CHECK: %[[NEW_S_PTR:.*]] = cir.cast(bitcast, %[[NEW_S]]
-// CHECK: cir.call @_ZN1SC1Ev(%[[NEW_S_PTR]])
// CHECK: cir.store{{.*}} %[[NEW_S_PTR]], %[[PS_ADDR]]
// CHECK: %[[FOUR:.*]] = cir.const #cir.int<4>
// CHECK: %[[NEW_INT:.*]] = cir.call @_Znwm(%[[FOUR]])
@@ -40,7 +39,6 @@ void test_basic_new() {
// LLVM: %[[PN_ADDR:.*]] = alloca ptr, i64 1, align 8
// LLVM: %[[PD_ADDR:.*]] = alloca ptr, i64 1, align 8
// LLVM: %[[NEW_S:.*]] = call{{.*}} ptr @_Znwm(i64 8)
-// LLVM: call{{.*}} void @_ZN1SC1Ev(ptr %[[NEW_S]])
// LLVM: store ptr %[[NEW_S]], ptr %[[PS_ADDR]], align 8
// LLVM: %[[NEW_INT:.*]] = call{{.*}} ptr @_Znwm(i64 4)
// LLVM: store ptr %[[NEW_INT]], ptr %[[PN_ADDR]], align 8
@@ -48,8 +46,6 @@ void test_basic_new() {
// LLVM: store ptr %[[NEW_DOUBLE]], ptr %[[PD_ADDR]], align 8
// LLVM: ret void
-// NOTE: OGCG elides the constructor call here, but CIR does not.
-
// OGCG: define{{.*}} void @_Z14test_basic_newv
// OGCG: %[[PS_ADDR:.*]] = alloca ptr, align 8
// OGCG: %[[PN_ADDR:.*]] = alloca ptr, align 8
diff --git a/clang/test/CIR/CodeGen/nrvo.cpp b/clang/test/CIR/CodeGen/nrvo.cpp
new file mode 100644
index 000000000000..72c39d7878dc
--- /dev/null
+++ b/clang/test/CIR/CodeGen/nrvo.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-elide-constructors -fclangir -emit-cir %s -o %t-noelide.cir
+// RUN: FileCheck --input-file=%t-noelide.cir %s --check-prefix=CIR-NOELIDE
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+// There are no LLVM and OGCG tests with -fno-elide-constructors because the
+// lowering isn't of interest for this test. We just need to see that the
+// copy constructor is elided without -fno-elide-constructors but not with it.
+
+struct S {
+ S();
+ int a;
+ int b;
+};
+
+struct S f1() {
+ S s;
+ return s;
+}
+
+// CIR: cir.func{{.*}} @_Z2f1v() -> !rec_S {
+// CIR-NEXT: %[[RETVAL:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["__retval", init]
+// CIR-NEXT: cir.call @_ZN1SC1Ev(%[[RETVAL]]) : (!cir.ptr<!rec_S>) -> ()
+// CIR-NEXT: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!rec_S>, !rec_S
+// CIR-NEXT: cir.return %[[RET]]
+
+// CIR-NOELIDE: cir.func{{.*}} @_Z2f1v() -> !rec_S {
+// CIR-NOELIDE-NEXT: %[[RETVAL:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["__retval"]
+// CIR-NOELIDE-NEXT: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init]
+// CIR-NOELIDE-NEXT: cir.call @_ZN1SC1Ev(%[[S]]) : (!cir.ptr<!rec_S>) -> ()
+// CIR-NOELIDE-NEXT: cir.call @_ZN1SC1EOS_(%[[RETVAL]], %[[S]]){{.*}} : (!cir.ptr<!rec_S>, !cir.ptr<!rec_S>) -> ()
+// CIR-NOELIDE-NEXT: %[[RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!rec_S>, !rec_S
+// CIR-NOELIDE-NEXT: cir.return %[[RET]]
+
+// FIXME: Update this when calling convetnion lowering is implemented.
+// LLVM: define{{.*}} %struct.S @_Z2f1v()
+// LLVM-NEXT: %[[RETVAL:.*]] = alloca %struct.S
+// LLVM-NEXT: call void @_ZN1SC1Ev(ptr %[[RETVAL]])
+// LLVM-NEXT: %[[RET:.*]] = load %struct.S, ptr %[[RETVAL]]
+// LLVM-NEXT: ret %struct.S %[[RET]]
+
+// OGCG: define{{.*}} i64 @_Z2f1v()
+// OGCG-NEXT: entry:
+// OGCG-NEXT: %[[RETVAL:.*]] = alloca %struct.S
+// OGCG-NEXT: call void @_ZN1SC1Ev(ptr {{.*}} %[[RETVAL]])
+// OGCG-NEXT: %[[RET:.*]] = load i64, ptr %[[RETVAL]]
+// OGCG-NEXT: ret i64 %[[RET]]
diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c
index 927a868336b5..f6ec9ecd1b67 100644
--- a/clang/test/CIR/CodeGen/statement-exprs.c
+++ b/clang/test/CIR/CodeGen/statement-exprs.c
@@ -226,6 +226,7 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// CIR: %[[GEP_X_S:.+]] = cir.get_member %[[S]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[C1:.+]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store {{.*}} %[[C1]], %[[GEP_X_S]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.copy %[[S]] to %[[REF_TMP0]] : !cir.ptr<!rec_S>
// CIR: }
// CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[XVAL:.+]] = cir.load {{.*}} %[[GEP_X_TMP]] : !cir.ptr<!s32i>, !s32i
@@ -246,6 +247,7 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// LLVM: [[LBL6]]:
// LLVM: %[[GEP_S:.+]] = getelementptr %struct.S, ptr %[[VAR3]], i32 0, i32 0
// LLVM: store i32 1, ptr %[[GEP_S]]
+// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[VAR1]], ptr %[[VAR3]], i32 4, i1 false)
// LLVM: br label %[[LBL8:.+]]
// LLVM: [[LBL8]]:
// LLVM: %[[GEP_VAR1:.+]] = getelementptr %struct.S, ptr %[[VAR1]], i32 0, i32 0
diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp
new file mode 100644
index 000000000000..0122f3088f0b
--- /dev/null
+++ b/clang/test/CIR/CodeGen/throws.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void foo() {
+ throw;
+}
+
+// CIR: cir.throw
+// CIR: cir.unreachable
+
+// LLVM: call void @__cxa_rethrow()
+// LLVM: unreachable
+
+// OGCG: call void @__cxa_rethrow()
+// OGCG: unreachable
+
+int foo1(int a, int b) {
+ if (b == 0)
+ throw;
+ return a / b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+// CIR: %[[RES_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: cir.store %{{.*}}, %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %{{.*}}, %[[B_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.scope {
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[IS_B_ZERO:.*]] = cir.cmp(eq, %[[TMP_B]], %[[CONST_0]]) : !s32i, !cir.bool
+// CIR: cir.if %[[IS_B_ZERO]] {
+// CIR: cir.throw
+// CIR: cir.unreachable
+// CIR: }
+// CIR: }
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[DIV_A_B:.*]] = cir.binop(div, %[[TMP_A:.*]], %[[TMP_B:.*]]) : !s32i
+// CIR: cir.store %[[DIV_A_B]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[RESULT:.*]] = cir.load %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[RESULT]] : !s32i
+
+// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[RES_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4
+// LLVM: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4
+// LLVM: br label %[[CHECK_COND:.*]]
+// LLVM: [[CHECK_COND]]:
+// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0
+// LLVM: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+// LLVM: [[IF_THEN]]:
+// LLVM: call void @__cxa_rethrow()
+// LLVM: unreachable
+// LLVM: [[IF_ELSE]]:
+// LLVM: br label %[[IF_END:.*]]
+// LLVM: [[IF_END]]:
+// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]]
+// LLVM: store i32 %[[DIV_A_B]], ptr %[[RES_ADDR]], align 4
+// LLVM: %[[RESULT:.*]] = load i32, ptr %[[RES_ADDR]], align 4
+// LLVM: ret i32 %[[RESULT]]
+
+// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4
+// OGCG: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4
+// OGCG: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4
+// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0
+// OGCG: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// OGCG: [[IF_THEN]]:
+// OGCG: call void @__cxa_rethrow()
+// OGCG: unreachable
+// OGCG: [[IF_END]]:
+// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]]
+// OGCG: ret i32 %[[DIV_A_B]]
diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp
index 022d06a97e36..40dfe73c411c 100644
--- a/clang/test/CIR/CodeGen/variable-decomposition.cpp
+++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp
@@ -18,7 +18,13 @@ float function() {
// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float
// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"]
-// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, [""]
+// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, ["", init]
+// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
+// CIR: %[[CONST_1:.+]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store{{.*}} %[[CONST_1]], %[[MEMBER_A]]
+// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float>
+// CIR: %[[TWO_FP:.+]] = cir.const #cir.fp<2.000000e+00> : !cir.float
+// CIR: cir.store{{.*}} %[[TWO_FP]], %[[MEMBER_B]]
// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[CAST_A:.+]] = cir.cast(int_to_float, %[[LOAD_A]] : !s32i), !cir.float
@@ -33,6 +39,10 @@ float function() {
// LLVM: %[[RETVAL:.+]] = alloca float, i64 1
// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1
// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
+// LLVM: store i32 1, ptr %[[GEP_A]]
+// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
+// LLVM: store float 2.000000e+00, ptr %[[GEP_B]]
+// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
// LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
// LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
diff --git a/clang/test/CIR/CodeGen/vbase.cpp b/clang/test/CIR/CodeGen/vbase.cpp
new file mode 100644
index 000000000000..91396518a40b
--- /dev/null
+++ b/clang/test/CIR/CodeGen/vbase.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+// Test the record layout for a class with a primary virtual base.
+class Base {
+public:
+ virtual void f();
+};
+
+class Derived : public virtual Base {};
+
+// This is just here to force the record types to be emitted.
+void f() {
+ Derived d;
+}
+
+// CIR: !rec_Base = !cir.record<class "Base" {!cir.vptr}>
+// CIR: !rec_Derived = !cir.record<class "Derived" {!rec_Base}>
+
+// LLVM: %class.Derived = type { %class.Base }
+// LLVM: %class.Base = type { ptr }
+
+// OGCG: %class.Derived = type { %class.Base }
+// OGCG: %class.Base = type { ptr }
+
+// Test the constructor handling for a class with a virtual base.
+struct A {
+ int a;
+};
+
+struct B: virtual A {
+ int b;
+};
+
+void ppp() { B b; }
+
+// Note: OGCG speculatively emits the VTT and VTables. This is not yet implemented in CIR.
+
+// Vtable definition for B
+// CIR: cir.global "private" external @_ZTV1B
+
+// LLVM: @_ZTV1B = external global { [3 x ptr] }
+
+// OGCG: @_ZTV1B = linkonce_odr unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr inttoptr (i64 12 to ptr), ptr null, ptr @_ZTI1B] }, comdat, align 8
+
+// Constructor for B
+// CIR: cir.func comdat linkonce_odr @_ZN1BC1Ev(%arg0: !cir.ptr<!rec_B>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>, ["this", init]
+// CIR: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!rec_B>>
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_B>>, !cir.ptr<!rec_B>
+// CIR: %[[BASE_A_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_B> nonnull [12] -> !cir.ptr<!rec_A>
+// CIR: %[[VTABLE:.*]] = cir.vtable.address_point(@_ZTV1B, address_point = <index = 0, offset = 3>) : !cir.vptr
+// CIR: %[[B_VPTR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_B> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store align(8) %[[VTABLE]], %[[B_VPTR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: cir.return
+
+// LLVM: define{{.*}} void @_ZN1BC1Ev(ptr %[[THIS_ARG:.*]]) {
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[BASE_A_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 12
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1B, i64 24), ptr %[[THIS]]
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_ZN1BC1Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[BASE_A_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 12
+// OGCG: store ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3), ptr %[[THIS]]
+// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/volatile.cpp b/clang/test/CIR/CodeGen/volatile.cpp
new file mode 100644
index 000000000000..df1d3a66733e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/volatile.cpp
@@ -0,0 +1,184 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR %s < %t.cir
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM %s < %t-cir.ll
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG %s < %t.ll
+
+int test_load(volatile int *ptr) {
+ return *ptr;
+}
+
+// CIR: cir.func dso_local @_Z9test_loadPVi
+// CIR: cir.load volatile
+
+// LLVM: define {{.*}} i32 @_Z9test_loadPVi
+// LLVM: load volatile i32, ptr %{{.*}}
+
+// OGCG: define {{.*}} i32 @_Z9test_loadPVi
+// OGCG: load volatile i32, ptr %{{.*}}
+
+void test_store(volatile int *ptr) {
+ *ptr = 42;
+}
+
+// CIR: cir.func dso_local @_Z10test_storePVi
+// CIR: cir.store volatile
+
+// LLVM: define {{.*}} void @_Z10test_storePVi
+// LLVM: store volatile i32 42, ptr %{{.*}}
+
+// OGCG: define {{.*}} void @_Z10test_storePVi
+// OGCG: store volatile i32 42, ptr %{{.*}}
+
+struct Foo {
+ int x;
+ volatile int y;
+ volatile int z: 4;
+};
+
+int test_load_field1(volatile Foo *ptr) {
+ return ptr->x;
+}
+
+// CIR: cir.func dso_local @_Z16test_load_field1PV3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} i32 @_Z16test_load_field1PV3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 0
+// LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} i32 @_Z16test_load_field1PV3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 0
+// OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
+
+int test_load_field2(Foo *ptr) {
+ return ptr->y;
+}
+
+// CIR: cir.func dso_local @_Z16test_load_field2P3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: %{{.+}} = cir.load volatile{{.*}} %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} i32 @_Z16test_load_field2P3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 1
+// LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} i32 @_Z16test_load_field2P3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 1
+// OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
+
+int test_load_field3(Foo *ptr) {
+ return ptr->z;
+}
+
+// CIR: cir.func dso_local @_Z16test_load_field3P3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: %{{.*}} = cir.get_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] {is_volatile} : !cir.ptr<!u8i>) -> !s32i
+
+// LLVM: define {{.*}} i32 @_Z16test_load_field3P3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 2
+// LLVM: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]]
+// LLVM: %[[TMP2:.*]] = shl i8 %[[TMP1]], 4
+// LLVM: %[[TMP3:.*]] = ashr i8 %[[TMP2]], 4
+// LLVM: %{{.*}} = sext i8 %[[TMP3]] to i32
+
+// OGCG: define {{.*}} i32 @_Z16test_load_field3P3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 2
+// OGCG: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]]
+// OGCG: %[[TMP2:.*]] = shl i8 %[[TMP1]], 4
+// OGCG: %[[TMP3:.*]] = ashr i8 %[[TMP2]], 4
+// OGCG: %{{.*}} = sext i8 %[[TMP3]] to i32
+
+void test_store_field1(volatile Foo *ptr) {
+ ptr->x = 42;
+}
+
+// CIR: cir.func dso_local @_Z17test_store_field1PV3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} void @_Z17test_store_field1PV3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 0
+// LLVM: store volatile i32 42, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} void @_Z17test_store_field1PV3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 0
+// OGCG: store volatile i32 42, ptr %[[MEMBER_ADDR]]
+
+void test_store_field2(Foo *ptr) {
+ ptr->y = 42;
+}
+
+// CIR: cir.func dso_local @_Z17test_store_field2P3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: cir.store volatile{{.*}} %{{.+}}, %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} void @_Z17test_store_field2P3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 1
+// LLVM: store volatile i32 42, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} void @_Z17test_store_field2P3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 1
+// OGCG: store volatile i32 42, ptr %[[MEMBER_ADDR]]
+
+void test_store_field3(Foo *ptr) {
+ ptr->z = 4;
+}
+
+// CIR: cir.func dso_local @_Z17test_store_field3P3Foo
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member
+// CIR: cir.set_bitfield align(4) (#bfi_z, %[[MEMBER_ADDR:.+]] : !cir.ptr<!u8i>, %1 : !s32i) {is_volatile}
+
+// LLVM: define {{.*}} void @_Z17test_store_field3P3Foo
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.Foo, ptr %{{.*}}, i32 0, i32 2
+// LLVM: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]]
+// LLVM: %[[TMP2:.*]] = and i8 %[[TMP1]], -16
+// LLVM: %[[TMP3:.*]] = or i8 %[[TMP2]], 4
+// LLVM: store volatile i8 %[[TMP3]], ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} void @_Z17test_store_field3P3Foo
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.Foo, ptr %{{.*}}, i32 0, i32 2
+// OGCG: %[[TMP1:.*]] = load volatile i8, ptr %[[MEMBER_ADDR]]
+// OGCG: %[[TMP2:.*]] = and i8 %[[TMP1]], -16
+// OGCG: %[[TMP3:.*]] = or i8 %[[TMP2]], 4
+// OGCG: store volatile i8 %[[TMP3]], ptr %[[MEMBER_ADDR]]
+
+struct A {
+ int x;
+ void set_x(int val) volatile;
+ int get_x() volatile;
+};
+
+void A::set_x(int val) volatile {
+ x = val;
+}
+
+// CIR: cir.func dso_local @_ZNV1A5set_xEi
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"}
+// CIR: cir.store volatile {{.*}} %{{.*}}, %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} void @_ZNV1A5set_xEi
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.A, ptr %{{.*}}, i32 0, i32 0
+// LLVM: store volatile i32 %{{.*}}, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} void @_ZNV1A5set_xEi
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.A, ptr %{{.*}}, i32 0, i32 0
+// OGCG: store volatile i32 %{{.*}}, ptr %[[MEMBER_ADDR]]
+
+int A::get_x() volatile {
+ return x;
+}
+
+// CIR: cir.func dso_local @_ZNV1A5get_xEv
+// CIR: %[[MEMBER_ADDR:.*]] = cir.get_member %{{.*}}[0] {name = "x"}
+// CIR: cir.load volatile {{.*}} %[[MEMBER_ADDR]]
+
+// LLVM: define {{.*}} i32 @_ZNV1A5get_xEv
+// LLVM: %[[MEMBER_ADDR:.*]] = getelementptr %struct.A, ptr %{{.*}}, i32 0, i32 0
+// LLVM: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
+
+// OGCG: define {{.*}} i32 @_ZNV1A5get_xEv
+// OGCG: %[[MEMBER_ADDR:.*]] = getelementptr inbounds nuw %struct.A, ptr %{{.*}}, i32 0, i32 0
+// OGCG: %{{.*}} = load volatile i32, ptr %[[MEMBER_ADDR]]
diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp
new file mode 100644
index 000000000000..9d88acef91ee
--- /dev/null
+++ b/clang/test/CIR/CodeGen/vtt.cpp
@@ -0,0 +1,487 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -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 -fno-rtti -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 -fno-rtti -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// Note: This test will be expanded to verify VTT emission and VTT implicit
+// argument handling. For now, it's just test the record layout.
+
+class A {
+public:
+ int a;
+ virtual void v();
+};
+
+class B : public virtual A {
+public:
+ int b;
+ virtual void w();
+};
+
+class C : public virtual A {
+public:
+ long c;
+ virtual void x();
+};
+
+class D : public B, public C {
+public:
+ long d;
+ D();
+ virtual void y();
+};
+
+// This is just here to force the record types to be emitted.
+void f(D *d) {}
+
+// Trigger vtable and VTT emission for D.
+void D::y() {}
+
+// CIR: !rec_A2Ebase = !cir.record<struct "A.base" packed {!cir.vptr, !s32i}>
+// CIR: !rec_B2Ebase = !cir.record<struct "B.base" packed {!cir.vptr, !s32i}>
+// CIR: !rec_C2Ebase = !cir.record<struct "C.base" {!cir.vptr, !s64i}>
+// CIR: !rec_A = !cir.record<class "A" packed padded {!cir.vptr, !s32i, !cir.array<!u8i x 4>}>
+// CIR: !rec_B = !cir.record<class "B" packed padded {!cir.vptr, !s32i, !cir.array<!u8i x 4>, !rec_A2Ebase, !cir.array<!u8i x 4>}>
+// CIR: !rec_C = !cir.record<class "C" {!cir.vptr, !s64i, !rec_A2Ebase}>
+// CIR: !rec_D = !cir.record<class "D" {!rec_B2Ebase, !rec_C2Ebase, !s64i, !rec_A2Ebase}>
+
+// CIR: !rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 5>, !cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 4>}>
+// CIR: !rec_anon_struct1 = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 4>}>
+
+// Vtable for D
+// CIR: cir.global{{.*}} @_ZTV1D = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1B1wEv> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1D1yEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 5>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<24 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-16 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1C1xEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1A1vEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : !rec_anon_struct {alignment = 8 : i64}
+
+// LLVM: @_ZTV1D = global { [5 x ptr], [4 x ptr], [4 x ptr] } {
+// LLVM-SAME: [5 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv, ptr @_ZN1D1yEv],
+// LLVM-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN1C1xEv],
+// LLVM-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// LLVM-SAME: }, align 8
+
+// OGCG: @_ZTV1D = unnamed_addr constant { [5 x ptr], [4 x ptr], [4 x ptr] } {
+// OGCG-SAME: [5 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv, ptr @_ZN1D1yEv],
+// OGCG-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN1C1xEv],
+// OGCG-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// OGCG-SAME: }, align 8
+
+// VTT for D
+// CIR: cir.global{{.*}} @_ZTT1D = #cir.const_array<[
+// CIR-SAME: #cir.global_view<@_ZTV1D, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D0_1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D0_1B, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D16_1C, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTC1D16_1C, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTV1D, [2 : i32, 3 : i32]> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZTV1D, [1 : i32, 3 : i32]> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 7> {alignment = 8 : i64}
+
+// LLVM: @_ZTT1D = global [7 x ptr] [
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D0_1B, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D0_1B, i64 56),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D16_1C, i64 24),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTC1D16_1C, i64 56),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 96),
+// LLVM-SAME: ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 64)
+// LLVM-SAME: ], align 8
+
+// OGCG: @_ZTT1D = unnamed_addr constant [7 x ptr] [
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D0_1B, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D0_1B, i32 0, i32 1, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D16_1C, i32 0, i32 0, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTC1D16_1C, i32 0, i32 1, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 2, i32 3),
+// OGCG-SAME: ptr getelementptr inbounds inrange(-24, 8) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 3)
+// OGCG-SAME: ], align 8
+
+// Construction vtable for B-in-D
+// CIR: cir.global{{.*}} @_ZTC1D0_1B = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1B1wEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-40 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1A1vEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : !rec_anon_struct1 {alignment = 8 : i64}
+
+// LLVM: @_ZTC1D0_1B = global { [4 x ptr], [4 x ptr] } {
+// LLVM-SAME: [4 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv],
+// LLVM-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// LLVM-SAME: }, align 8
+
+// OGCG: @_ZTC1D0_1B = unnamed_addr constant { [4 x ptr], [4 x ptr] } {
+// OGCG-SAME: [4 x ptr] [ptr inttoptr (i64 40 to ptr), ptr null, ptr null, ptr @_ZN1B1wEv],
+// OGCG-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -40 to ptr), ptr null, ptr @_ZN1A1vEv]
+// OGCG-SAME: }, align 8
+
+// Construction vtable for C-in-D
+// CIR: cir.global{{.*}} @_ZTC1D16_1C = #cir.vtable<{
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<24 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1C1xEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+// CIR-SAME: #cir.const_array<[
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<-24 : i64> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>,
+// CIR-SAME: #cir.global_view<@_ZN1A1vEv> : !cir.ptr<!u8i>
+// CIR-SAME: ]> : !cir.array<!cir.ptr<!u8i> x 4>
+// CIR-SAME: }> : !rec_anon_struct1 {alignment = 8 : i64}
+
+// LLVM: @_ZTC1D16_1C = global { [4 x ptr], [4 x ptr] } {
+// LLVM-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr null, ptr null, ptr @_ZN1C1xEv],
+// LLVM-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -24 to ptr), ptr null, ptr @_ZN1A1vEv]
+// LLVM-SAME: }, align 8
+
+// OGCG: @_ZTC1D16_1C = unnamed_addr constant { [4 x ptr], [4 x ptr] } {
+// OGCG-SAME: [4 x ptr] [ptr inttoptr (i64 24 to ptr), ptr null, ptr null, ptr @_ZN1C1xEv],
+// OGCG-SAME: [4 x ptr] [ptr null, ptr inttoptr (i64 -24 to ptr), ptr null, ptr @_ZN1A1vEv]
+// OGCG-SAME: }, align 8
+
+D::D() {}
+
+// In CIR, this gets emitted after the B and C constructors. See below.
+// Base (C2) constructor for D
+
+// OGCG: define {{.*}} void @_ZN1DC2Ev(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[B_VTT:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1
+// OGCG: call void @_ZN1BC2Ev(ptr {{.*}} %[[THIS]], ptr {{.*}} %[[B_VTT]])
+// OGCG: %[[C_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 16
+// OGCG: %[[C_VTT:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 3
+// OGCG: call void @_ZN1CC2Ev(ptr {{.*}} %[[C_ADDR]], ptr {{.*}} %[[C_VTT]])
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// OGCG: store ptr %[[VPTR]], ptr %[[THIS]]
+// OGCG: %[[D_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 5
+// OGCG: %[[D_VPTR:.*]] = load ptr, ptr %[[D_VPTR_ADDR]]
+// OGCG: %[[D_VPTR_ADDR2:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[D_VPTR_ADDR2]], i64 -24
+// OGCG: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// OGCG: %[[BASE_PTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// OGCG: store ptr %[[D_VPTR]], ptr %[[BASE_PTR]]
+// OGCG: %[[C_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 6
+// OGCG: %[[C_VPTR:.*]] = load ptr, ptr %[[C_VPTR_ADDR]]
+// OGCG: %[[C_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 16
+// OGCG: store ptr %[[C_VPTR]], ptr %[[C_ADDR]]
+
+
+// Base (C2) constructor for B
+
+// CIR: cir.func {{.*}} @_ZN1BC2Ev
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_B>
+// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load{{.*}} %[[VTT_ADDR]]
+// CIR: %[[VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_ADDR:.*]] = cir.cast(bitcast, %[[VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]]
+// CIR: %[[B_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]]
+// CIR: cir.store{{.*}} %[[VPTR]], %[[B_VPTR_ADDR]]
+// CIR: %[[B_VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[B_VPTR_ADDR:.*]] = cir.cast(bitcast, %[[B_VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[B_VPTR:.*]] = cir.load{{.*}} %[[B_VPTR_ADDR]]
+// CIR: %[[B_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]]
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[B_VPTR_ADDR]]
+// CIR: %[[VPTR_ADDR2:.*]] = cir.cast(bitcast, %[[VPTR]] : !cir.vptr), !cir.ptr<!u8i>
+// CIR: %[[CONST_24:.*]] = cir.const #cir.int<-24>
+// CIR: %[[BASE_OFFSET_ADDR:.*]] = cir.ptr_stride(%[[VPTR_ADDR2]] : !cir.ptr<!u8i>, %[[CONST_24]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_ADDR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
+// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[THIS_PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_B>), !cir.ptr<!u8i>
+// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_PTR]] : !cir.ptr<!u8i>, %[[BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_CAST:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!rec_B>
+// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_CAST]]
+// CIR: cir.store{{.*}} %[[B_VPTR]], %[[BASE_VPTR_ADDR]]
+
+// LLVM: define {{.*}} void @_ZN1BC2Ev(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// LLVM: store ptr %[[VPTR]], ptr %[[THIS]]
+// LLVM: %[[B_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 1
+// LLVM: %[[B_VPTR:.*]] = load ptr, ptr %[[B_VPTR_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -24
+// LLVM: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// LLVM: %[[BASE_PTR:.*]] = getelementptr i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// LLVM: store ptr %[[B_VPTR]], ptr %[[BASE_PTR]]
+
+// OGCG: define {{.*}} void @_ZN1BC2Ev(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// OGCG: store ptr %[[VPTR]], ptr %[[THIS]]
+// OGCG: %[[B_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1
+// OGCG: %[[B_VPTR:.*]] = load ptr, ptr %[[B_VPTR_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -24
+// OGCG: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// OGCG: %[[BASE_PTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// OGCG: store ptr %[[B_VPTR]], ptr %[[BASE_PTR]]
+
+// Base (C2) constructor for C
+
+// CIR: cir.func {{.*}} @_ZN1CC2Ev
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_C>
+// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load{{.*}} %[[VTT_ADDR]]
+// CIR: %[[VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_ADDR:.*]] = cir.cast(bitcast, %[[VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]]
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]]
+// CIR: cir.store{{.*}} %[[VPTR]], %[[C_VPTR_ADDR]]
+// CIR: %[[C_VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.cast(bitcast, %[[C_VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[C_VPTR:.*]] = cir.load{{.*}} %[[C_VPTR_ADDR]]
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]]
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[C_VPTR_ADDR]]
+// CIR: %[[VPTR_ADDR2:.*]] = cir.cast(bitcast, %[[VPTR]] : !cir.vptr), !cir.ptr<!u8i>
+// CIR: %[[CONST_24:.*]] = cir.const #cir.int<-24>
+// CIR: %[[BASE_OFFSET_ADDR:.*]] = cir.ptr_stride(%[[VPTR_ADDR2]] : !cir.ptr<!u8i>, %[[CONST_24]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_ADDR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
+// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[THIS_PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_C>), !cir.ptr<!u8i>
+// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_PTR]] : !cir.ptr<!u8i>, %[[BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_CAST:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!rec_C>
+// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_CAST]]
+// CIR: cir.store{{.*}} %[[C_VPTR]], %[[BASE_VPTR_ADDR]]
+
+// LLVM: define {{.*}} void @_ZN1CC2Ev(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// LLVM: store ptr %[[VPTR]], ptr %[[THIS]]
+// LLVM: %[[B_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 1
+// LLVM: %[[B_VPTR:.*]] = load ptr, ptr %[[B_VPTR_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -24
+// LLVM: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// LLVM: %[[BASE_PTR:.*]] = getelementptr i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// LLVM: store ptr %[[B_VPTR]], ptr %[[BASE_PTR]]
+
+// OGCG: define {{.*}} void @_ZN1CC2Ev(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// OGCG: store ptr %[[VPTR]], ptr %[[THIS]]
+// OGCG: %[[B_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1
+// OGCG: %[[B_VPTR:.*]] = load ptr, ptr %[[B_VPTR_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -24
+// OGCG: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// OGCG: %[[BASE_PTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// OGCG: store ptr %[[B_VPTR]], ptr %[[BASE_PTR]]
+
+// Base (C2) constructor for D
+
+// CIR: cir.func {{.*}} @_ZN1DC2Ev
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_D>
+// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load{{.*}} %[[VTT_ADDR]]
+// CIR: %[[B_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [0] -> !cir.ptr<!rec_B>
+// CIR: %[[B_VTT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: cir.call @_ZN1BC2Ev(%[[B_ADDR]], %[[B_VTT]]) nothrow : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
+// CIR: %[[C_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [16] -> !cir.ptr<!rec_C>
+// CIR: %[[C_VTT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 3 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: cir.call @_ZN1CC2Ev(%[[C_ADDR]], %[[C_VTT]]) nothrow : (!cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!void>>) -> ()
+// CIR: %[[D_VTT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_ADDR:.*]] = cir.cast(bitcast, %[[D_VTT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[D_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]]
+// CIR: cir.store{{.*}} %[[VPTR]], %[[D_VPTR_ADDR]]
+// CIR: %[[D_VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 5 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[D_VPTR_ADDR:.*]] = cir.cast(bitcast, %[[D_VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[D_VPTR:.*]] = cir.load{{.*}} %[[D_VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[D_VPTR_ADDR2:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_D> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR2:.*]] = cir.load{{.*}} %[[D_VPTR_ADDR2]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_ADDR2:.*]] = cir.cast(bitcast, %[[VPTR2]] : !cir.vptr), !cir.ptr<!u8i>
+// CIR: %[[CONST_24:.*]] = cir.const #cir.int<-24> : !s64i
+// CIR: %[[BASE_OFFSET_ADDR:.*]] = cir.ptr_stride(%[[VPTR_ADDR2]] : !cir.ptr<!u8i>, %[[CONST_24]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_ADDR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
+// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[THIS_PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_D>), !cir.ptr<!u8i>
+// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_PTR]] : !cir.ptr<!u8i>, %[[BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_CAST:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!rec_D>
+// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_CAST]]
+// CIR: cir.store{{.*}} %[[D_VPTR]], %[[BASE_VPTR_ADDR]]
+// CIR: %[[C_VTT_ADDR_POINT:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 6 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.cast(bitcast, %[[C_VTT_ADDR_POINT]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[C_VPTR:.*]] = cir.load{{.*}} %[[C_VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[C_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [16] -> !cir.ptr<!rec_C>
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[C_ADDR]] : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[C_VPTR]], %[[C_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+
+// LLVM: define {{.*}} void @_ZN1DC2Ev(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]]) {
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[B_VTT:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 1
+// LLVM: call void @_ZN1BC2Ev(ptr %[[THIS]], ptr %[[B_VTT]])
+// LLVM: %[[C_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 16
+// LLVM: %[[C_VTT:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 3
+// LLVM: call void @_ZN1CC2Ev(ptr %[[C_ADDR]], ptr %[[C_VTT]])
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// LLVM: store ptr %[[VPTR]], ptr %[[THIS]]
+// LLVM: %[[D_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 5
+// LLVM: %[[D_VPTR:.*]] = load ptr, ptr %[[D_VPTR_ADDR]]
+// LLVM: %[[D_VPTR_ADDR2:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[D_VPTR_ADDR2]], i64 -24
+// LLVM: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// LLVM: %[[BASE_PTR:.*]] = getelementptr i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// LLVM: store ptr %[[D_VPTR]], ptr %[[BASE_PTR]]
+// LLVM: %[[C_VPTR_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 6
+// LLVM: %[[C_VPTR:.*]] = load ptr, ptr %[[C_VPTR_ADDR]]
+// LLVM: %[[C_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 16
+// LLVM: store ptr %[[C_VPTR]], ptr %[[C_ADDR]]
+
+// The C2 constructor for D gets emitted earlier in OGCG, see above.
+
+// Base (C2) constructor for A
+
+// CIR: cir.func {{.*}} @_ZN1AC2Ev
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_A>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VPTR:.*]] = cir.vtable.address_point(@_ZTV1A, address_point = <index = 0, offset = 2>) : !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+
+// LLVM: define {{.*}} void @_ZN1AC2Ev(ptr %[[THIS_ARG:.*]]) {
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]], align 8
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1A, i64 16), ptr %[[THIS]]
+
+// The C2 constructor for A gets emitted later in OGCG, see below.
+
+// Complete (C1) constructor for D
+
+// CIR: cir.func {{.*}} @_ZN1DC1Ev
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_D>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[A_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [40] -> !cir.ptr<!rec_A>
+// CIR: cir.call @_ZN1AC2Ev(%[[A_ADDR]]) nothrow : (!cir.ptr<!rec_A>) -> ()
+// CIR: %[[B_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [0] -> !cir.ptr<!rec_B>
+// CIR: %[[B_VTT:.*]] = cir.vtt.address_point @_ZTT1D, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: cir.call @_ZN1BC2Ev(%[[B_ADDR]], %[[B_VTT]]) nothrow : (!cir.ptr<!rec_B>, !cir.ptr<!cir.ptr<!void>>) -> ()
+// CIR: %[[C_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [16] -> !cir.ptr<!rec_C>
+// CIR: %[[C_VTT:.*]] = cir.vtt.address_point @_ZTT1D, offset = 3 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: cir.call @_ZN1CC2Ev(%[[C_ADDR]], %[[C_VTT]]) nothrow : (!cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!void>>) -> ()
+// CIR: %[[D_VPTR:.*]] = cir.vtable.address_point(@_ZTV1D, address_point = <index = 0, offset = 3>) : !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_D> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[D_VPTR]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[A_VPTR:.*]] = cir.vtable.address_point(@_ZTV1D, address_point = <index = 2, offset = 3>) : !cir.vptr
+// CIR: %[[A_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [40] -> !cir.ptr<!rec_A>
+// CIR: %[[A_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[A_ADDR]] : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[A_VPTR]], %[[A_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[C_VPTR:.*]] = cir.vtable.address_point(@_ZTV1D, address_point = <index = 1, offset = 3>) : !cir.vptr
+// CIR: %[[C_ADDR:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr<!rec_D> nonnull [16] -> !cir.ptr<!rec_C>
+// CIR: %[[C_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[C_ADDR]] : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[C_VPTR]], %[[C_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+
+// LLVM: define {{.*}} void @_ZN1DC1Ev(ptr %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[A_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 40
+// LLVM: call void @_ZN1AC2Ev(ptr %[[A_ADDR]])
+// LLVM: call void @_ZN1BC2Ev(ptr %[[THIS]], ptr getelementptr inbounds nuw (i8, ptr @_ZTT1D, i64 8))
+// LLVM: %[[C_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 16
+// LLVM: call void @_ZN1CC2Ev(ptr %[[C_ADDR]], ptr getelementptr inbounds nuw (i8, ptr @_ZTT1D, i64 24))
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 24), ptr %[[THIS]]
+// LLVM: %[[A_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 40
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 96), ptr %[[A_ADDR]]
+// LLVM: %[[C_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i32 16
+// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1D, i64 64), ptr %[[C_ADDR]]
+
+// OGCG: define {{.*}} void @_ZN1DC1Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[A_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 40
+// OGCG: call void @_ZN1AC2Ev(ptr {{.*}} %[[A_ADDR]])
+// OGCG: call void @_ZN1BC2Ev(ptr {{.*}} %[[THIS]], ptr {{.*}} getelementptr inbounds ([7 x ptr], ptr @_ZTT1D, i64 0, i64 1))
+// OGCG: %[[C_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 16
+// OGCG: call void @_ZN1CC2Ev(ptr {{.*}} %[[C_ADDR]], ptr {{.*}} getelementptr inbounds ([7 x ptr], ptr @_ZTT1D, i64 0, i64 3))
+// OGCG: store ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3), ptr %[[THIS]]
+// OGCG: %[[A_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 40
+// OGCG: store ptr getelementptr inbounds inrange(-24, 8) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 2, i32 3), ptr %[[A_ADDR]]
+// OGCG: %[[C_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 16
+// OGCG: store ptr getelementptr inbounds inrange(-24, 8) ({ [5 x ptr], [4 x ptr], [4 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 3), ptr %[[C_ADDR]]
+
+// OGCG: define {{.*}} void @_ZN1AC2Ev(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 2), ptr %[[THIS]]