diff options
Diffstat (limited to 'clang/test/CIR/CodeGen')
33 files changed, 4184 insertions, 136 deletions
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index 141b67e..a643de2d 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -45,9 +45,9 @@ int dd[3][2] = {{1, 2}, {3, 4}, {5, 6}}; // OGCG: [i32 3, i32 4], [2 x i32] [i32 5, i32 6]] int e[10] = {1, 2}; -// CIR: cir.global external @e = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i], trailing_zeros> : !cir.array<!s32i x 10> +// CIR: cir.global external @e = #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.zero : !cir.array<!s32i x 8>}> : !rec_anon_struct -// LLVM: @e = global [10 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0] +// LLVM: @e = global <{ i32, i32, [8 x i32] }> <{ i32 1, i32 2, [8 x i32] zeroinitializer }> // OGCG: @e = global <{ i32, i32, [8 x i32] }> <{ i32 1, i32 2, [8 x i32] zeroinitializer }> @@ -58,6 +58,28 @@ int f[5] = {1, 2}; // OGCG: @f = global [5 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0] +int g[16] = {1, 2, 3, 4, 5, 6, 7, 8}; +// CIR: cir.global external @g = #cir.const_record<{ +// CIR-SAME: #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, +// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i, +// CIR-SAME: #cir.int<5> : !s32i, #cir.int<6> : !s32i, +// CIR-SAME: #cir.int<7> : !s32i, #cir.int<8> : !s32i]> +// CIR-SAME: : !cir.array<!s32i x 8>, +// CIR-SAME: #cir.zero : !cir.array<!s32i x 8>}> : !rec_anon_struct1 + +// LLVM: @g = global <{ [8 x i32], [8 x i32] }> +// LLVM-SAME: <{ [8 x i32] +// LLVM-SAME: [i32 1, i32 2, i32 3, i32 4, +// LLVM-SAME: i32 5, i32 6, i32 7, i32 8], +// LLVM-SAME: [8 x i32] zeroinitializer }> + +// OGCG: @g = global <{ [8 x i32], [8 x i32] }> +// OGCG-SAME: <{ [8 x i32] +// OGCG-SAME: [i32 1, i32 2, i32 3, i32 4, +// OGCG-SAME: i32 5, i32 6, i32 7, i32 8], +// OGCG-SAME: [8 x i32] zeroinitializer }> + + extern int b[10]; // CIR: cir.global "private" external @b : !cir.array<!s32i x 10> // LLVM: @b = external global [10 x i32] @@ -129,31 +151,50 @@ void func2() { } // CIR: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init] -// CIR: %[[ELE_ALLOCA:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init] -// CIR: %[[ARR_2_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i> -// CIR: %[[V1:.*]] = cir.const #cir.int<5> : !s32i -// CIR: cir.store{{.*}} %[[V1]], %[[ARR_2_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["arrayinit.temp", init] +// CIR: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>>), !cir.ptr<!s32i> +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store{{.*}} %[[FIVE]], %[[ARR_0]] : !s32i, !cir.ptr<!s32i> // CIR: %[[OFFSET_0:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_2_PTR]] : !cir.ptr<!s32i>, %[[OFFSET_0]] : !s64i), !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[LOAD_1:.*]] = cir.load{{.*}} %[[ELE_ALLOCA]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> -// CIR: %[[V2:.*]] = cir.const #cir.int<0> : !s32i -// CIR: cir.store{{.*}} %[[V2]], %[[LOAD_1]] : !s32i, !cir.ptr<!s32i> -// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_1_PTR:.*]] = cir.ptr_stride(%[[LOAD_1]] : !cir.ptr<!s32i>, %[[OFFSET_1]] : !s64i), !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[ELE_1_PTR]], %[[ELE_ALLOCA]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!s32i>, %[[OFFSET_0]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!s32i>, %[[TWO]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!s32i>, %[[ONE]] : !s64i), !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!s32i>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func2v() -// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 -// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 -// LLVM: %[[TMP2:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store i32 0, ptr %[[TMP2]], align 4 -// LLVM: %[[ELE_1:.*]] = getelementptr i32, ptr %[[TMP2]], i64 1 -// LLVM: store ptr %[[ELE_1]], ptr %[[TMP]], align 8 +// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0 +// LLVM: store i32 5, ptr %[[ARR_PTR]], align 4 +// LLVM: %[[ELE_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1 +// LLVM: store ptr %[[ELE_1_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 2 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store i32 0, ptr %[[CUR]], align 4 +// LLVM: %[[NEXT:.*]] = getelementptr i32, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // OGCG: %[[ARR:.*]] = alloca [2 x i32], align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN2_ARR]], i64 8, i1 false) @@ -270,27 +311,46 @@ void func5() { // CIR: %[[V_0_0:.*]] = cir.const #cir.int<5> : !s32i // CIR: cir.store{{.*}} %[[V_0_0]], %[[ARR_0_PTR]] : !s32i, !cir.ptr<!s32i> // CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %6 = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %6, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> -// CIR: %7 = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %8 = cir.const #cir.zero : !cir.array<!s32i x 1> -// CIR: cir.store{{.*}} %8, %7 : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 1>> -// CIR: %[[OFFSET_1:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %10 = cir.ptr_stride(%7 : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET_1]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> -// CIR: cir.store{{.*}} %10, %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: %[[ARR_1:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.store{{.*}} %[[ARR_1]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[TWO]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !cir.array<!s32i x 1> +// CIR: cir.store{{.*}} %[[ZERO]], %[[ARR_CUR]] : !cir.array<!s32i x 1>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!cir.array<!s32i x 1>>, %[[ONE]] : !s64i), !cir.ptr<!cir.array<!s32i x 1>> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.array<!s32i x 1>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 1>>>, !cir.ptr<!cir.array<!s32i x 1>> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.array<!s32i x 1>>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func5v() -// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 -// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 -// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 -// LLVM: store i32 5, ptr %[[ARR_0]], align 4 -// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 -// LLVM: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 -// LLVM: %[[ARR_1_VAL:.*]] = load ptr, ptr %[[TMP]], align 8 -// LLVM: store [1 x i32] zeroinitializer, ptr %[[ARR_1_VAL]], align 4 -// LLVM: %[[ARR_1_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1_VAL]], i64 1 -// LLVM: store ptr %[[ARR_1_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0 +// LLVM: %[[ARR_0:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0 +// LLVM: store i32 5, ptr %[[ARR_0]], align 4 +// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1 +// LLVM: store ptr %[[ARR_1]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 2 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store [1 x i32] zeroinitializer, ptr %[[CUR]], align 4 +// LLVM: %[[NEXT:.*]] = getelementptr [1 x i32], ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // ORGC: %[[ARR:.*]] = alloca [2 x [1 x i32]], align 4 // ORGC: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN5_ARR]], i64 8, i1 false) @@ -335,25 +395,44 @@ void func7() { } // CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init] -// CIR: %[[ARR_TMP:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init] -// CIR: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ARR_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> -// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> -// CIR: cir.store{{.*}} %[[NULL_PTR]], %[[TMP]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> -// CIR: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s64i -// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride(%[[TMP]] : !cir.ptr<!cir.ptr<!s32i>>, %[[OFFSET]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> -// CIR: cir.store{{.*}} %[[ELE_PTR]], %[[ARR_TMP]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["arrayinit.temp", init] +// CIR: %[[ARR_0:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.store{{.*}} %[[ARR_0]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[ARR_0]] : !cir.ptr<!cir.ptr<!s32i>>, %[[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i> +// CIR: cir.store{{.*}} %[[NULL_PTR]], %[[ARR_CUR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!cir.ptr<!s32i>>, %[[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s32i>> +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>> +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) : !cir.ptr<!cir.ptr<!s32i>>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } // LLVM: define{{.*}} void @_Z5func7v() -// LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 -// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[ELE_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 -// LLVM: store ptr %[[ELE_PTR]], ptr %[[ALLOCA]], align 8 -// LLVM: %[[TMP:.*]] = load ptr, ptr %[[ALLOCA]], align 8 -// LLVM: store ptr null, ptr %[[TMP]], align 8 -// LLVM: %[[ELE:.*]] = getelementptr ptr, ptr %[[TMP]], i64 1 -// LLVM: store ptr %[[ELE]], ptr %[[ALLOCA]], align 8 +// LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8 +// LLVM: %[[TMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ARR_PTR:.*]] = getelementptr ptr, ptr %[[ARR]], i32 0 +// LLVM: store ptr %[[ARR_PTR]], ptr %[[TMP]], align 8 +// LLVM: %[[END_PTR:.*]] = getelementptr ptr, ptr %[[ARR_PTR]], i64 1 +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]], align 8 +// LLVM: store ptr null, ptr %[[CUR]], align 8 +// LLVM: %[[NEXT:.*]] = getelementptr ptr, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]], align 8 +// LLVM: br label %[[LOOP_NEXT:.*]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void // OGCG: %[[ARR:.*]] = alloca [1 x ptr], align 8 // OGCG: call void @llvm.memset.p0.i64(ptr align 8 %[[ARR]], i8 0, i64 8, i1 false) diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c new file mode 100644 index 0000000..8b947f7 --- /dev/null +++ b/clang/test/CIR/CodeGen/atomic.c @@ -0,0 +1,206 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void f1(void) { + _Atomic(int) x = 42; +} + +// CIR-LABEL: @f1 +// CIR: %[[SLOT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64} +// CIR-NEXT: %[[INIT:.+]] = cir.const #cir.int<42> : !s32i +// CIR-NEXT: cir.store align(4) %[[INIT]], %[[SLOT]] : !s32i, !cir.ptr<!s32i> +// CIR: } + +// LLVM-LABEL: @f1 +// LLVM: %[[SLOT:.+]] = alloca i32, i64 1, align 4 +// LLVM-NEXT: store i32 42, ptr %[[SLOT]], align 4 +// LLVM: } + +// OGCG-LABEL: @f1 +// OGCG: %[[SLOT:.+]] = alloca i32, align 4 +// OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4 +// OGCG: } + +void f2(void) { + _Atomic(int) x; + __c11_atomic_init(&x, 42); +} + +// CIR-LABEL: @f2 +// CIR: %[[SLOT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64} +// CIR-NEXT: %[[INIT:.+]] = cir.const #cir.int<42> : !s32i +// CIR-NEXT: cir.store align(4) %[[INIT]], %[[SLOT]] : !s32i, !cir.ptr<!s32i> +// CIR: } + +// LLVM-LABEL: @f2 +// LLVM: %[[SLOT:.+]] = alloca i32, i64 1, align 4 +// LLVM-NEXT: store i32 42, ptr %[[SLOT]], align 4 +// LLVM: } + +// OGCG-LABEL: @f2 +// OGCG: %[[SLOT:.+]] = alloca i32, align 4 +// OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4 +// OGCG: } + +void load(int *ptr) { + int x; + __atomic_load(ptr, &x, __ATOMIC_RELAXED); + __atomic_load(ptr, &x, __ATOMIC_CONSUME); + __atomic_load(ptr, &x, __ATOMIC_ACQUIRE); + __atomic_load(ptr, &x, __ATOMIC_SEQ_CST); +} + +// CIR-LABEL: @load +// 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 +// 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 +// 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 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); + __c11_atomic_load(ptr, __ATOMIC_ACQUIRE); + __c11_atomic_load(ptr, __ATOMIC_SEQ_CST); +} + +// CIR-LABEL: @c11_load +// 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: @c11_load +// 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: @c11_load +// 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 store(int *ptr, int x) { + __atomic_store(ptr, &x, __ATOMIC_RELAXED); + __atomic_store(ptr, &x, __ATOMIC_RELEASE); + __atomic_store(ptr, &x, __ATOMIC_SEQ_CST); +} + +// CIR-LABEL: @store +// 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 +// 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 +// 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 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); + __c11_atomic_store(ptr, x, __ATOMIC_SEQ_CST); +} + +// CIR-LABEL: @c11_store +// 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: @c11_store +// 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: @c11_store +// 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: } + diff --git a/clang/test/CIR/CodeGen/bitfield-union.c b/clang/test/CIR/CodeGen/bitfield-union.c index b5d1454..14a2aaf 100644 --- a/clang/test/CIR/CodeGen/bitfield-union.c +++ b/clang/test/CIR/CodeGen/bitfield-union.c @@ -28,3 +28,44 @@ typedef union { demo d; zero_bit z; + +void f() { + demo d; + d.x = 1; + d.y = 2; + d.z = 0; +} + +// CIR: #bfi_y = #cir.bitfield_info<name = "y", storage_type = !u8i, size = 4, offset = 0, is_signed = true> +// CIR: #bfi_z = #cir.bitfield_info<name = "z", storage_type = !u8i, size = 8, offset = 0, is_signed = true> + +// CIR: cir.func no_proto dso_local @f +// CIR: [[ALLOC:%.*]] = cir.alloca !rec_demo, !cir.ptr<!rec_demo>, ["d"] {alignment = 4 : i64} +// CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i +// CIR: [[X:%.*]] = cir.get_member [[ALLOC]][0] {name = "x"} : !cir.ptr<!rec_demo> -> !cir.ptr<!s32i> +// CIR: cir.store align(4) [[ONE]], [[X]] : !s32i, !cir.ptr<!s32i> +// CIR: [[TWO:%.*]] = cir.const #cir.int<2> : !s32i +// CIR: [[Y:%.*]] = cir.get_member [[ALLOC]][1] {name = "y"} : !cir.ptr<!rec_demo> -> !cir.ptr<!u8i> +// CIR: [[SET:%.*]] = cir.set_bitfield align(4) (#bfi_y, [[Y]] : !cir.ptr<!u8i>, [[TWO]] : !s32i) -> !s32i +// CIR: [[ZERO:%.*]] = cir.const #cir.int<0> : !s32i +// CIR: [[Z:%.*]] = cir.get_member [[ALLOC]][2] {name = "z"} : !cir.ptr<!rec_demo> -> !cir.ptr<!u8i> +// CIR: [[SET2:%.*]] = cir.set_bitfield align(4) (#bfi_z, [[Z]] : !cir.ptr<!u8i>, [[ZERO]] : !s32i) -> !s32i +// CIR: cir.return + +// LLVM: define dso_local void @f +// LLVM: [[ALLOC:%.*]] = alloca %union.demo, i64 1, align 4 +// LLVM: store i32 1, ptr [[ALLOC]], align 4 +// LLVM: [[BFLOAD:%.*]] = load i8, ptr [[ALLOC]], align 4 +// LLVM: [[CLEAR:%.*]] = and i8 [[BFLOAD]], -16 +// LLVM: [[SET:%.*]] = or i8 [[CLEAR]], 2 +// LLVM: store i8 [[SET]], ptr [[ALLOC]], align 4 +// LLVM: store i8 0, ptr [[ALLOC]], align 4 + +// OGCG: define dso_local void @f +// OGCG: [[ALLOC:%.*]] = alloca %union.demo, align 4 +// OGCG: store i32 1, ptr [[ALLOC]], align 4 +// OGCG: [[BFLOAD:%.*]] = load i8, ptr [[ALLOC]], align 4 +// OGCG: [[CLEAR:%.*]] = and i8 [[BFLOAD]], -16 +// OGCG: [[SET:%.*]] = or i8 [[CLEAR]], 2 +// OGCG: store i8 [[SET]], ptr [[ALLOC]], align 4 +// OGCG: store i8 0, ptr [[ALLOC]], align 4 diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp index c266f1a..09be793 100644 --- a/clang/test/CIR/CodeGen/builtin_call.cpp +++ b/clang/test/CIR/CodeGen/builtin_call.cpp @@ -111,6 +111,38 @@ void assume(bool arg) { // OGCG: call void @llvm.assume(i1 %{{.+}}) // OGCG: } +void *assume_aligned(void *ptr) { + return __builtin_assume_aligned(ptr, 16); +} + +// CIR: @_Z14assume_alignedPv +// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16 : !cir.ptr<!void> +// CIR: } + +// LLVM: @_Z14assume_alignedPv +// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] +// LLVM: } + +// OGCG: @_Z14assume_alignedPv +// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] +// OGCG: } + +void *assume_aligned_misalignment(void *ptr, unsigned misalignment) { + return __builtin_assume_aligned(ptr, 16, misalignment); +} + +// CIR: @_Z27assume_aligned_misalignmentPvj +// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16[offset %{{.+}} : !u64i] : !cir.ptr<!void> +// CIR: } + +// LLVM: @_Z27assume_aligned_misalignmentPvj +// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] +// LLVM: } + +// OGCG: @_Z27assume_aligned_misalignmentPvj +// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] +// OGCG: } + void assume_separate_storage(void *p1, void *p2) { __builtin_assume_separate_storage(p1, p2); } diff --git a/clang/test/CIR/CodeGen/builtin_printf.cpp b/clang/test/CIR/CodeGen/builtin_printf.cpp index 43128e4..80875c3 100644 --- a/clang/test/CIR/CodeGen/builtin_printf.cpp +++ b/clang/test/CIR/CodeGen/builtin_printf.cpp @@ -5,10 +5,10 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG -// CIR: cir.global "private" cir_private dso_local @".str" = #cir.const_array<"%s\00" : !cir.array<!s8i x 3>> : !cir.array<!s8i x 3> -// CIR: cir.global "private" cir_private dso_local @".str.1" = #cir.const_array<"%s %d\0A\00" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7> -// LLVM: @.str = private global [3 x i8] c"%s\00" -// LLVM: @.str.1 = private global [7 x i8] c"%s %d\0A\00" +// CIR: cir.global "private" constant cir_private dso_local @".str" = #cir.const_array<"%s\00" : !cir.array<!s8i x 3>> : !cir.array<!s8i x 3> +// CIR: cir.global "private" constant cir_private dso_local @".str.1" = #cir.const_array<"%s %d\0A\00" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7> +// LLVM: @.str = private constant [3 x i8] c"%s\00" +// LLVM: @.str.1 = private constant [7 x i8] c"%s %d\0A\00" // OGCG: @.str = private unnamed_addr constant [3 x i8] c"%s\00" // OGCG: @.str.1 = private unnamed_addr constant [7 x i8] c"%s %d\0A\00" diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp new file mode 100644 index 0000000..0e43480 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtins.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +double fabs(double x) { + return __builtin_fabs(x); +} + +// CIR: {{.*}} = cir.fabs {{.*}} : !cir.double +// LLVM: {{.*}} = call double @llvm.fabs.f64(double {{.*}}) +// OGCG: {{.*}} = call double @llvm.fabs.f64(double {{.*}}) + +extern "C" void *test_return_address(void) { + return __builtin_return_address(1); + + // CIR-LABEL: test_return_address + // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i + // CIR: {{%.*}} = cir.return_address([[ARG]]) + + // LLVM-LABEL: @test_return_address + // LLVM: {{%.*}} = call ptr @llvm.returnaddress(i32 1) + + // OGCG-LABEL: @test_return_address + // OGCG: {{%.*}} = call ptr @llvm.returnaddress(i32 1) +} + +extern "C" void *test_frame_address(void) { + return __builtin_frame_address(1); + + // CIR-LABEL: test_frame_address + // CIR: [[ARG:%.*]] = cir.const #cir.int<1> : !u32i + // CIR: {{%.*}} = cir.frame_address([[ARG]]) + + // LLVM-LABEL: @test_frame_address + // LLVM: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1) + + // OGCG-LABEL: @test_frame_address + // OGCG: {{%.*}} = call ptr @llvm.frameaddress.p0(i32 1) +} diff --git a/clang/test/CIR/CodeGen/call.cpp b/clang/test/CIR/CodeGen/call.cpp index 43e5d15..3e8cfc1 100644 --- a/clang/test/CIR/CodeGen/call.cpp +++ b/clang/test/CIR/CodeGen/call.cpp @@ -116,4 +116,18 @@ void f14() { // LLVM: call void @_Z3f13v() #[[LLVM_ATTR_0:.+]] // LLVM: } -// LLLVM: attributes #[[LLVM_ATTR_0]] = { nounwind } +int f15(); +void f16() { + using T = int; + f15().~T(); +} + +// CIR-LABEL: @_Z3f16v +// CIR-NEXT: %{{.+}} = cir.call @_Z3f15v() : () -> !s32i +// CIR: } + +// LLVM-LABEL: define{{.+}} void @_Z3f16v() { +// LLVM-NEXT: %{{.+}} = call i32 @_Z3f15v() +// LLVM: } + +// LLVM: attributes #[[LLVM_ATTR_0]] = { nounwind } diff --git a/clang/test/CIR/CodeGen/class.cpp b/clang/test/CIR/CodeGen/class.cpp index 43dde12..eb9d5d7 100644 --- a/clang/test/CIR/CodeGen/class.cpp +++ b/clang/test/CIR/CodeGen/class.cpp @@ -100,3 +100,22 @@ int use_base_via_pointer(Derived *d) { // OGCG: define{{.*}} i32 @_Z20use_base_via_pointerP7Derived // OGCG: %[[D_A_ADDR:.*]] = getelementptr inbounds nuw %class.Base, ptr %{{.*}}, i32 0, i32 0 + +struct EmptyDerived : Base {}; +struct EmptyDerived2 : EmptyDerived {}; + +void use_empty_derived2() { + EmptyDerived2 d2; +} + +// CIR: cir.func{{.*}} @_Z18use_empty_derived2v() +// CIR: %0 = cir.alloca !rec_EmptyDerived2, !cir.ptr<!rec_EmptyDerived2>, ["d2"] +// CIR: cir.return + +// LLVM: define{{.*}} void @_Z18use_empty_derived2v +// LLVM: alloca %struct.EmptyDerived2 +// LLVM: ret void + +// OGCG: define{{.*}} void @_Z18use_empty_derived2v +// OGCG: alloca %struct.EmptyDerived2 +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp index 35a8aa6..82c0086 100644 --- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp +++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp @@ -286,3 +286,456 @@ void foo4() { // CXX_OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 // CXX_OGCG: store i32 %[[B_REAL]], ptr %[[C_REAL_PTR]], align 4 // CXX_OGCG: store i32 %[[B_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +void foo5() { + 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(add, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[A_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:.*]] = fadd float %[[A_REAL]], %[[TMP_B]] +// LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0 +// LLVM: %[[RESULT:.*]] = insertvalue { float, float } %[[TMP_RESULT]], float %[[A_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: %[[ADD_REAL:.*]] = fadd float %[[A_REAL]], %[[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 %[[ADD_REAL]], ptr %[[A_REAL_PTR]], align 4 +// OGCG: store float %[[A_IMAG]], ptr %[[A_IMAG_PTR]], align 4 + +void foo6() { + int _Complex a; + int _Complex b; + b *= a; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b"] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!s32i> -> !s32i +// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!s32i> -> !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: %[[MUL_BR_AR:.*]] = cir.binop(mul, %[[B_REAL]], %[[A_REAL]]) : !s32i +// CIR: %[[MUL_BI_AI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[A_IMAG]]) : !s32i +// CIR: %[[MUL_BR_AI:.*]] = cir.binop(mul, %[[B_REAL]], %[[A_IMAG]]) : !s32i +// CIR: %[[MUL_BI_AR:.*]] = cir.binop(mul, %[[B_IMAG]], %[[A_REAL]]) : !s32i +// CIR: %[[RESULT_REAL:.*]] = cir.binop(sub, %[[MUL_BR_AR]], %[[MUL_BI_AI]]) : !s32i +// CIR: %[[RESULT_IMAG:.*]] = cir.binop(add, %[[MUL_BR_AI]], %[[MUL_BI_AR]]) : !s32i +// CIR: %[[RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : !s32i -> !cir.complex<!s32i> +// CIR: cir.store{{.*}} %[[RESULT]], %[[B_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>> + +// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load { i32, i32 }, ptr %[[B_ADDR]], align 4 +// LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1 +// LLVM: %[[MUL_BR_AR:.*]] = mul i32 %[[B_REAL]], %[[A_REAL]] +// LLVM: %[[MUL_BI_AI:.*]] = mul i32 %[[B_IMAG]], %[[A_IMAG]] +// LLVM: %[[MUL_BR_AI:.*]] = mul i32 %[[B_REAL]], %[[A_IMAG]] +// LLVM: %[[MUL_BI_AR:.*]] = mul i32 %[[B_IMAG]], %[[A_REAL]] +// LLVM: %[[RESULT_REAL:.*]] = sub i32 %[[MUL_BR_AR]], %[[MUL_BI_AI]] +// LLVM: %[[RESULT_IMAG:.*]] = add i32 %[[MUL_BR_AI]], %[[MUL_BI_AR]] +// LLVM: %[[MUL_A_B:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[RESULT_REAL]], 0 +// LLVM: %[[RESULT:.*]] = insertvalue { i32, i32 } %[[MUL_A_B]], i32 %[[RESULT_IMAG]], 1 +// LLVM: store { i32, i32 } %[[RESULT]], ptr %[[B_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca { i32, i32 }, 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: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_REAL:.*]] = load i32, ptr %[[B_REAL_PTR]], align 4 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4 +// OGCG: %[[MUL_BR_AR:.*]] = mul i32 %[[B_REAL]], %[[A_REAL]] +// OGCG: %[[MUL_BI_AI:.*]] = mul i32 %[[B_IMAG]], %[[A_IMAG]] +// OGCG: %[[RESULT_REAL:.*]] = sub i32 %[[MUL_BR_AR]], %[[MUL_BI_AI]] +// OGCG: %[[MUL_BI_AR:.*]] = mul i32 %[[B_IMAG]], %[[A_REAL]] +// OGCG: %[[MUL_BR_AI:.*]] = mul i32 %[[B_REAL]], %[[A_IMAG]] +// OGCG: %[[RESULT_IMAG:.*]] = add i32 %[[MUL_BI_AR]], %[[MUL_BR_AI]] +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: store i32 %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 4 +// OGCG: store i32 %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 4 + +void foo7() { + float _Complex a; + float _Complex b; + b *= a; +} + +// 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_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!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: %[[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: %[[MUL_BR_AR:.*]] = cir.binop(mul, %[[B_REAL]], %[[A_REAL]]) : !cir.float +// CIR: %[[MUL_BI_AI:.*]] = cir.binop(mul, %[[B_IMAG]], %[[A_IMAG]]) : !cir.float +// CIR: %[[MUL_BR_AI:.*]] = cir.binop(mul, %[[B_REAL]], %[[A_IMAG]]) : !cir.float +// CIR: %[[MUL_BI_AR:.*]] = cir.binop(mul, %[[B_IMAG]], %[[A_REAL]]) : !cir.float +// CIR: %[[C_REAL:.*]] = cir.binop(sub, %[[MUL_BR_AR]], %[[MUL_BI_AI]]) : !cir.float +// CIR: %[[C_IMAG:.*]] = cir.binop(add, %[[MUL_BR_AI]], %[[MUL_BI_AR]]) : !cir.float +// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[C_REAL]], %[[C_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// CIR: %[[IS_C_REAL_NAN:.*]] = cir.cmp(ne, %[[C_REAL]], %[[C_REAL]]) : !cir.float, !cir.bool +// CIR: %[[IS_C_IMAG_NAN:.*]] = cir.cmp(ne, %[[C_IMAG]], %[[C_IMAG]]) : !cir.float, !cir.bool +// CIR: %[[CONST_FALSE:.*]] = cir.const #false +// CIR: %[[SELECT_CONDITION:.*]] = cir.select if %[[IS_C_REAL_NAN]] then %[[IS_C_IMAG_NAN]] else %[[CONST_FALSE]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool +// CIR: %[[RESULT:.*]] = cir.ternary(%[[SELECT_CONDITION]], true { +// CIR: %[[LIBC_COMPLEX:.*]] = cir.call @__mulsc3(%[[B_REAL]], %[[B_IMAG]], %[[A_REAL]], %[[A_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float> +// CIR: cir.yield %[[LIBC_COMPLEX]] : !cir.complex<!cir.float> +// CIR: }, false { +// CIR: cir.yield %[[COMPLEX]] : !cir.complex<!cir.float> +// CIR: }) : (!cir.bool) -> !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[RESULT]], %[[B_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_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM: %[[MUL_BR_AR:.*]] = fmul float %[[B_REAL]], %[[A_REAL]] +// LLVM: %[[MUL_BI_AI:.*]] = fmul float %[[B_IMAG]], %[[A_IMAG]] +// LLVM: %[[MUL_BR_AI:.*]] = fmul float %[[B_REAL]], %[[A_IMAG]] +// LLVM: %[[MUL_BI_AR:.*]] = fmul float %[[B_IMAG]], %[[A_REAL]] +// LLVM: %[[C_REAL:.*]] = fsub float %[[MUL_BR_AR]], %[[MUL_BI_AI]] +// LLVM: %[[C_IMAG:.*]] = fadd float %[[MUL_BR_AI]], %[[MUL_BI_AR]] +// LLVM: %[[MUL_A_B:.*]] = insertvalue { float, float } {{.*}}, float %[[C_REAL]], 0 +// LLVM: %[[COMPLEX:.*]] = insertvalue { float, float } %[[MUL_A_B]], float %[[C_IMAG]], 1 +// LLVM: %[[IS_C_REAL_NAN:.*]] = fcmp une float %[[C_REAL]], %[[C_REAL]] +// LLVM: %[[IS_C_IMAG_NAN:.*]] = fcmp une float %[[C_IMAG]], %[[C_IMAG]] +// LLVM: %[[SELECT_CONDITION:.*]] = and i1 %[[IS_C_REAL_NAN]], %[[IS_C_IMAG_NAN]] +// LLVM: br i1 %[[SELECT_CONDITION]], label %[[THEN_LABEL:.*]], label %[[ELSE_LABEL:.*]] +// LLVM: [[THEN_LABEL]]: +// LLVM: %[[LIBC_COMPLEX:.*]] = call { float, float } @__mulsc3(float %[[B_REAL]], float %[[B_IMAG]], float %[[A_REAL]], float %[[A_IMAG]]) +// LLVM: br label %[[PHI_BRANCH:.*]] +// LLVM: [[ELSE_LABEL]]: +// LLVM: br label %[[PHI_BRANCH:]] +// LLVM: [[PHI_BRANCH:]]: +// LLVM: %[[RESULT:.*]] = phi { float, float } [ %[[COMPLEX]], %[[ELSE_LABEL]] ], [ %[[LIBC_COMPLEX]], %[[THEN_LABEL]] ] +// LLVM: br label %[[END_LABEL:.*]] +// LLVM: [[END_LABEL]]: +// LLVM: store { float, float } %[[RESULT]], ptr %[[B_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[COMPLEX_CALL_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[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: %[[MUL_BR_AR:.*]] = fmul float %[[B_REAL]], %[[A_REAL]] +// OGCG: %[[MUL_BI_AI:.*]] = fmul float %[[B_IMAG]], %[[A_IMAG]] +// OGCG: %[[MUL_BR_AI:.*]] = fmul float %[[B_REAL]], %[[A_IMAG]] +// OGCG: %[[MUL_BI_AR:.*]] = fmul float %[[B_IMAG]], %[[A_REAL]] +// OGCG: %[[C_REAL:.*]] = fsub float %[[MUL_BR_AR]], %[[MUL_BI_AI]] +// OGCG: %[[C_IMAG:.*]] = fadd float %[[MUL_BR_AI]], %[[MUL_BI_AR]] +// OGCG: %[[IS_C_REAL_NAN:.*]] = fcmp uno float %[[C_REAL]], %[[C_REAL]] +// OGCG: br i1 %[[IS_C_REAL_NAN]], label %[[COMPLEX_IS_IMAG_NAN:.*]], label %[[END_LABEL:.*]], !prof !2 +// OGCG: [[COMPLEX_IS_IMAG_NAN]]: +// OGCG: %[[IS_C_IMAG_NAN:.*]] = fcmp uno float %[[C_IMAG]], %[[C_IMAG]] +// OGCG: br i1 %[[IS_C_IMAG_NAN]], label %[[COMPLEX_LIB_CALL:.*]], label %[[END_LABEL]], !prof !2 +// OGCG: [[COMPLEX_LIB_CALL]]: +// OGCG: %[[CALL_RESULT:.*]] = call{{.*}} <2 x float> @__mulsc3(float noundef %[[B_REAL]], float noundef %[[B_IMAG]], float noundef %[[A_REAL]], float noundef %[[A_IMAG]]) +// OGCG: store <2 x float> %[[CALL_RESULT]], ptr %[[COMPLEX_CALL_ADDR]], align 4 +// OGCG: %[[COMPLEX_CALL_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_CALL_ADDR]], i32 0, i32 0 +// OGCG: %[[COMPLEX_CALL_REAL:.*]] = load float, ptr %[[COMPLEX_CALL_REAL_PTR]], align 4 +// OGCG: %[[COMPLEX_CALL_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_CALL_ADDR]], i32 0, i32 1 +// OGCG: %[[COMPLEX_CALL_IMAG:.*]] = load float, ptr %[[COMPLEX_CALL_IMAG_PTR]], align 4 +// OGCG: br label %[[END_LABEL]] +// OGCG: [[END_LABEL]]: +// OGCG: %[[FINAL_REAL:.*]] = phi float [ %[[C_REAL]], %[[ENTRY:.*]] ], [ %[[C_REAL]], %[[COMPLEX_IS_IMAG_NAN]] ], [ %[[COMPLEX_CALL_REAL]], %[[COMPLEX_LIB_CALL]] ] +// OGCG: %[[FINAL_IMAG:.*]] = phi float [ %[[C_IMAG]], %[[ENTRY]] ], [ %[[C_IMAG]], %[[COMPLEX_IS_IMAG_NAN]] ], [ %[[COMPLEX_CALL_IMAG]], %[[COMPLEX_LIB_CALL]] ] +// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG: store float %[[FINAL_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG: store float %[[FINAL_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +void foo8() { + 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(mul, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR: %[[RESULT_IMAG:.*]] = cir.binop(mul, %[[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:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// LLVM: %[[RESULT_IMAG:.*]] = fmul 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:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// OGCG: %[[RESULT_IMAG:.*]] = fmul 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 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 + +#ifndef __cplusplus +void foo9() { + float _Complex a; + float b; + b += a; +} +#endif + +// C_CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// C_CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b"] +// C_CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// C_CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.float>, !cir.float +// C_CIR: %[[A_REAL:.*]] = cir.complex.real %[[A_ADDR]] : !cir.complex<!cir.float> -> !cir.float +// C_CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[A_ADDR]] : !cir.complex<!cir.float> -> !cir.float +// C_CIR: %[[NEW_REAL:.*]] = cir.binop(add, %[[TMP_B]], %[[A_REAL]]) : !cir.float +// C_CIR: %[[RESULT:.*]] = cir.complex.create %[[NEW_REAL]], %[[A_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// C_CIR: %[[RESULT_REAL:.*]] = cir.complex.real %[[RESULT]] : !cir.complex<!cir.float> -> !cir.float +// C_CIR: cir.store{{.*}} %[[RESULT_REAL]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> + +// C_LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// C_LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// C_LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// C_LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// C_LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// C_LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// C_LLVM: %[[NEW_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]] +// C_LLVM: %[[TMP_RESULT:.*]] = insertvalue { float, float } {{.*}}, float %[[NEW_REAL]], 0 +// C_LLVM: store float %[[NEW_REAL]], ptr %[[B_ADDR]], align 4 + +// C_OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// C_OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// C_OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// C_OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// C_OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// C_OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// C_OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// C_OGCG: %[[ADD_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]] +// C_OGCG: store float %[[ADD_REAL]], ptr %[[B_ADDR]], align 4
\ No newline at end of file diff --git a/clang/test/CIR/CodeGen/complex-mul-div.cpp b/clang/test/CIR/CodeGen/complex-mul-div.cpp index 9d71ef7..d493046 100644 --- a/clang/test/CIR/CodeGen/complex-mul-div.cpp +++ b/clang/test/CIR/CodeGen/complex-mul-div.cpp @@ -1,38 +1,38 @@ // complex-range basic // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=basic -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-BASIC %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED,CIR-AFTER-BASIC // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED,LLVM-BASIC // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED,OGCG-BASIC // complex-range improved // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=improved -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-IMPROVED %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED,CIR-AFTER-IMPROVED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED,LLVM-IMPROVED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED,OGCG-IMPROVED // complex-range promoted // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=promoted -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-PROMOTED %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-INT,CIR-AFTER-MUL-COMBINED,CIR-COMBINED,CIR-AFTER-PROMOTED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-INT,LLVM-MUL-COMBINED,LLVM-COMBINED,LLVM-PROMOTED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-INT,OGCG-MUL-COMBINED,OGCG-COMBINED,OGCG-PROMOTED // complex-range full // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=full -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-FULL %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-FULL,CIR-AFTER-INT +// RUN: FileCheck --input-file=%t.cir %s --check-prefixes=CIR-AFTER-FULL,CIR-AFTER-INT,CIR-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-FULL,LLVM-INT +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM-FULL,LLVM-INT,LLVM-COMBINED // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -emit-llvm %s -o %t.ll -// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-FULL,OGCG-INT +// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=OGCG-FULL,OGCG-INT,OGCG-COMBINED void foo() { float _Complex a; @@ -278,3 +278,984 @@ void foo1() { // OGCG-INT: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[C_ADDR]], i32 0, i32 1 // OGCG-INT: store i32 %[[C_REAL]], ptr %[[C_REAL_PTR]], align 4 // OGCG-INT: store i32 %[[C_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +void foo2() { + 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{{.*}} %0 : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-COMBINED: %[[TMP_B:.*]] = cir.load{{.*}} %1 : !cir.ptr<!cir.float>, !cir.float +// CIR-COMBINED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-COMBINED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-COMBINED: %[[RESULT_REAL:.*]] = cir.binop(mul, %[[A_REAL]], %[[TMP_B]]) : !cir.float +// CIR-COMBINED: %[[RESULT_IMAG:.*]] = cir.binop(mul, %[[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:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// LLVM-COMBINED: %[[RESULT_IMAG:.*]] = fmul 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:.*]] = fmul float %[[A_REAL]], %[[TMP_B]] +// OGCG-COMBINED: %[[RESULT_IMAG:.*]] = fmul 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 foo3() { + float _Complex 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.complex<!cir.float>, !cir.ptr<!cir.complex<!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.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-BASIC: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-BASIC: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-BASIC: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_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, 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, float }, ptr %[[A_ADDR]], align 4 +// LLVM-BASIC: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-BASIC: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-BASIC: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 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 %[[A_REAL]], %[[B_REAL]] +// LLVM-BASIC: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[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 %[[A_IMAG]], %[[B_REAL]] +// LLVM-BASIC: %[[MUL_BR_BI:.*]] = fmul float %[[A_REAL]], %[[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, float }, align 4 +// OGCG-BASIC: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-BASIC: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-BASIC: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-BASIC: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-BASIC: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-BASIC: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], 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 %[[A_REAL]], %[[B_REAL]] +// OGCG-BASIC: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[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 %[[A_IMAG]], %[[B_REAL]] +// OGCG-BASIC: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[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.complex<!cir.float>, !cir.ptr<!cir.complex<!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.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-IMPROVED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-IMPROVED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-IMPROVED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_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, 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, float }, ptr %[[A_ADDR]], align 4 +// LLVM-IMPROVED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-IMPROVED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-IMPROVED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 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 %[[A_IMAG]], %[[DIV_BI_BR]] +// LLVM-IMPROVED: %[[ADD_AR_MUL_AI_DIV_BIBR:.*]] = fadd float %[[A_REAL]], %[[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 %[[A_REAL]], %[[DIV_BI_BR]] +// LLVM-IMPROVED: %[[SUB_AI_MUL_AR_DIV_BIBR:.*]] = fsub float %[[A_IMAG]], %[[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 %[[A_REAL]], %[[DIV_BR_BI]] +// LLVM-IMPROVED: %[[ADD_MUL_AR_DIV_BRBI_AI:.*]] = fadd float %[[MUL_AR_DIV_BRBI]], %[[A_IMAG]] +// 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 %[[A_IMAG]], %[[DIV_BR_BI]] +// LLVM-IMPROVED: %[[SUB_MUL_AI_DIV_BRBI_AR:.*]] = fsub float %[[MUL_AI_DIV_BRBI]], %[[A_REAL]] +// 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, float }, align 4 +// OGCG-IMPROVED: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-IMPROVED: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-IMPROVED: %a.realp = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-IMPROVED: %a.real = load float, ptr %a.realp, align 4 +// OGCG-IMPROVED: %a.imagp = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-IMPROVED: %a.imag = load float, ptr %a.imagp, 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 %[[A_IMAG]], %[[DIV_BI_BR]] +// OGCG-IMPROVED: %[[ADD_AR_MUL_AI_DIV_BIBR:.*]] = fadd float %[[A_REAL]], %[[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 %[[A_REAL]], %[[DIV_BI_BR]] +// OGCG-IMPROVED: %[[SUB_AI_MUL_AR_DIV_BIBR:.*]] = fsub float %[[A_IMAG]], %[[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 %[[A_REAL]], %[[DIV_BR_BI]] +// OGCG-IMPROVED: %[[ADD_MUL_AR_DIV_BRBI_AI:.*]] = fadd float %[[MUL_AR_DIV_BRBI]], %[[A_IMAG]] +// 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 %[[A_IMAG]], %[[DIV_BR_BI]] +// OGCG-IMPROVED: %[[SUB_MUL_AI_DIV_BRBI_AR:.*]] = fsub float %[[MUL_AI_DIV_BRBI]], %[[A_REAL]] +// 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.complex<!cir.float>, !cir.ptr<!cir.complex<!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.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-PROMOTED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-PROMOTED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-PROMOTED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_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, 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, float }, ptr %[[A_ADDR]], align 4 +// LLVM-PROMOTED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-PROMOTED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-PROMOTED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 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 %[[A_REAL]] to double +// LLVM-PROMOTED: %[[A_IMAG_F64:.*]] = fpext float %[[A_IMAG]] 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 %[[A_IMAG_F64]], %[[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 %[[A_IMAG_F64]], %[[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, float }, align 4 +// OGCG-PROMOTED: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-PROMOTED: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-PROMOTED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-PROMOTED: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-PROMOTED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-PROMOTED: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-PROMOTED: %[[A_REAL_F64:.*]] = fpext float %[[A_REAL]] to double +// OGCG-PROMOTED: %[[A_IMAG_F64:.*]] = fpext float %[[A_IMAG]] 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 %[[A_IMAG_F64]], %[[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 %[[A_IMAG_F64]], %[[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.complex<!cir.float>, !cir.ptr<!cir.complex<!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.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-FULL: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-FULL: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-FULL: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_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, 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, float }, ptr %[[A_ADDR]], align 4 +// LLVM-FULL: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-FULL: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-FULL: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 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 %[[A_REAL]], float %[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]]) +// LLVM-FULL: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-FULL: %[[A_ADDR:.*]] = alloca { float, 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: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-FULL: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-FULL: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-FULL: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], 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 %[[A_REAL]], float noundef %[[A_IMAG]], float noundef %[[B_REAL]], float noundef %[[B_IMAG]]) #2 +// 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 foo4() { + int _Complex a; + int _Complex 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 !cir.complex<!s32i>, !cir.ptr<!cir.complex<!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<!cir.complex<!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 %[[TMP_B]] : !cir.complex<!s32i> -> !s32i +// CIR-COMBINED: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_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]], %14) : !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, 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, i32 }, ptr %[[B_ADDR]], align 4 +// LLVM-COMBINED: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 0 +// LLVM-COMBINED: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_A]], 1 +// LLVM-COMBINED: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 0 +// LLVM-COMBINED: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[TMP_B]], 1 +// LLVM-COMBINED: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[B_REAL]] +// LLVM-COMBINED: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], %[[B_IMAG]] +// LLVM-COMBINED: %[[MUL_BR_BR:.*]] = mul i32 %[[B_REAL]], %[[B_REAL]] +// LLVM-COMBINED: %[[MUL_BI_BI:.*]] = mul i32 %[[B_IMAG]], %[[B_IMAG]] +// LLVM-COMBINED: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// LLVM-COMBINED: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], %[[MUL_BI_BI]] +// LLVM-COMBINED: %[[RESULT_REAL:.*]] = sdiv i32 %[[ADD_ARBR_AIBI]], %[[ADD_BRBR_BIBI]] +// LLVM-COMBINED: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[B_REAL]] +// LLVM-COMBINED: %[[MUL_BR_BI:.*]] = mul i32 %[[A_REAL]], %[[B_IMAG]] +// LLVM-COMBINED: %[[SUB_AIBR_BRBI:.*]] = sub i32 %[[MUL_AI_BR]], %[[MUL_BR_BI]] +// LLVM-COMBINED: %[[RESULT_IMAG:.*]] = sdiv i32 %[[SUB_AIBR_BRBI]], %[[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, 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: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG-COMBINED: %[[B_REAL:.*]] = load i32, ptr %[[B_REAL_PTR]], align 4 +// OGCG-COMBINED: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG-COMBINED: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4 +// OGCG-COMBINED: %[[MUL_AR_BR:.*]] = mul i32 %[[A_REAL]], %[[B_REAL]] +// OGCG-COMBINED: %[[MUL_AI_BI:.*]] = mul i32 %[[A_IMAG]], %[[B_IMAG]] +// OGCG-COMBINED: %[[ADD_ARBR_AIBI:.*]] = add i32 %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// OGCG-COMBINED: %[[MUL_BR_BR:.*]] = mul i32 %[[B_REAL]], %[[B_REAL]] +// OGCG-COMBINED: %[[MUL_BI_BI:.*]] = mul i32 %[[B_IMAG]], %[[B_IMAG]] +// OGCG-COMBINED: %[[ADD_BRBR_BIBI:.*]] = add i32 %[[MUL_BR_BR]], %[[MUL_BI_BI]] +// OGCG-COMBINED: %[[MUL_AI_BR:.*]] = mul i32 %[[A_IMAG]], %[[B_REAL]] +// OGCG-COMBINED: %[[MUL_AR_BI:.*]] = mul i32 %[[A_REAL]], %[[B_IMAG]] +// OGCG-COMBINED: %[[SUB_AIBR_BRBI:.*]] = 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_BRBI]], %[[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 + +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-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cpp index 4cd81eb..e945d9b 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 bd7de9a..db837e5 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -799,3 +799,113 @@ void foo30() { // OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 // OGCG: store float 1.000000e+00, ptr %[[A_REAL_PTR]], align 4 // OGCG: store float 0.000000e+00, ptr %[[A_IMAG_PTR]], align 4 + +void foo31() { + struct Wrapper { + int _Complex c; + }; + + Wrapper w; + int r = __real__ w.c; +} + +// CIR: %[[W_ADDR:.*]] = cir.alloca !rec_Wrapper, !cir.ptr<!rec_Wrapper>, ["w"] +// CIR: %[[REAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["r", init] +// CIR: %[[ELEM_PTR:.*]] = cir.get_member %[[W_ADDR]][0] {name = "c"} : !cir.ptr<!rec_Wrapper> -> !cir.ptr<!cir.complex<!s32i>> +// CIR: %[[TMP_ELEM_PTR:.*]] = cir.load{{.*}} %[[ELEM_PTR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[REAL:.*]] = cir.complex.real %[[TMP_ELEM_PTR]] : !cir.complex<!s32i> -> !s32i +// CIR: cir.store{{.*}} %[[REAL]], %[[REAL_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[W_ADDR:.*]] = alloca %struct.Wrapper, i64 1, align 4 +// LLVM: %[[REAL_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[ELEM_PTR:.*]] = getelementptr %struct.Wrapper, ptr %[[W_ADDR]], i32 0, i32 0 +// LLVM: %[[TMP_ELEM_PTR:.*]] = load { i32, i32 }, ptr %[[ELEM_PTR]], align 4 +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP_ELEM_PTR]], 0 +// LLVM: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4 + +// OGCG: %[[W_ADDR:.*]] = alloca %struct.Wrapper, align 4 +// OGCG: %[[REAL_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[ELEM_PTR:.*]] = getelementptr inbounds nuw %struct.Wrapper, ptr %[[W_ADDR]], i32 0, i32 0 +// OGCG: %[[REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[ELEM_PTR]], i32 0, i32 0 +// OGCG: %[[REAL:.*]] = load i32, ptr %[[REAL_PTR]], align 4 +// OGCG: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4 + +struct Container { + static int _Complex c; +}; + +void foo32() { + Container con; + int r = __real__ con.c; +} + +// CIR: %[[REAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["r", init] +// CIR: %[[ELEM_PTR:.*]] = cir.get_global @_ZN9Container1cE : !cir.ptr<!cir.complex<!s32i>> +// CIR: %[[ELEM:.*]] = cir.load{{.*}} %[[ELEM_PTR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[REAL:.*]] = cir.complex.real %[[ELEM]] : !cir.complex<!s32i> -> !s32i +// CIR: cir.store{{.*}} %[[REAL]], %[[REAL_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[REAL_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[ELEM:.*]] = load { i32, i32 }, ptr @_ZN9Container1cE, align 4 +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[ELEM]], 0 +// LLVM: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4 + +// 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 diff --git a/clang/test/CIR/CodeGen/destructors.cpp b/clang/test/CIR/CodeGen/destructors.cpp index de7718f..fde0732 100644 --- a/clang/test/CIR/CodeGen/destructors.cpp +++ b/clang/test/CIR/CodeGen/destructors.cpp @@ -55,3 +55,102 @@ struct inline_destructor { // CIR-NOT: cir.func {{.*}}inline_destructor{{.*}} // LLVM-NOT: define {{.*}}inline_destructor{{.*}} // OGCG-NOT: define {{.*}}inline_destructor{{.*}} + +struct array_element {~array_element();}; +void test_array_destructor() { + array_element arr[5]{}; +} + +// CIR: cir.func dso_local @_Z21test_array_destructorv() +// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_array_element x 5>, !cir.ptr<!cir.array<!rec_array_element x 5>>, ["arr", init] +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>>, ["arrayinit.temp", init] +// CIR: %[[BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!rec_array_element x 5>>) +// CIR: cir.store{{.*}} %[[BEGIN]], %[[ARR_PTR]] +// CIR: %[[FIVE:.*]] = cir.const #cir.int<5> : !s64i +// CIR: %[[ARR_END:.*]] = cir.ptr_stride(%[[BEGIN]] : !cir.ptr<!rec_array_element>, %[[FIVE]] : !s64i) +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!rec_array_element>, %[[ONE]] : !s64i) +// CIR: cir.store{{.*}} %[[ARR_NEXT]], %[[ARR_PTR]] : !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[ARR_END]]) +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr<!cir.array<!rec_array_element x 5>>) +// CIR: %[[END:.*]] = cir.ptr_stride(%[[BEGIN]] : !cir.ptr<!rec_array_element>, %[[FOUR]] : !u64i) +// CIR: %[[ARR_PTR:.*]] = cir.alloca !cir.ptr<!rec_array_element>, !cir.ptr<!cir.ptr<!rec_array_element>>, ["__array_idx"] +// CIR: cir.store %[[END]], %[[ARR_PTR]] +// CIR: cir.do { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: cir.call @_ZN13array_elementD1Ev(%[[ARR_CUR]]) nothrow : (!cir.ptr<!rec_array_element>) -> () +// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[ARR_NEXT:.*]] = cir.ptr_stride(%[[ARR_CUR]] : !cir.ptr<!rec_array_element>, %[[NEG_ONE]] : !s64i) +// CIR: cir.store %[[ARR_NEXT]], %[[ARR_PTR]] +// CIR: cir.yield +// CIR: } while { +// CIR: %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_PTR]] +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[ARR_CUR]], %[[BEGIN]]) +// CIR: cir.condition(%[[CMP]]) +// CIR: } + +// LLVM: define{{.*}} void @_Z21test_array_destructorv() +// LLVM: %[[ARR:.*]] = alloca [5 x %struct.array_element] +// LLVM: %[[TMP:.*]] = alloca ptr +// LLVM: %[[ARR_PTR:.*]] = getelementptr %struct.array_element, ptr %[[ARR]], i32 0 +// LLVM: store ptr %[[ARR_PTR]], ptr %[[TMP]] +// LLVM: %[[END_PTR:.*]] = getelementptr %struct.array_element, ptr %[[ARR_PTR]], i64 5 +// LLVM: br label %[[INIT_LOOP_BODY:.*]] +// LLVM: [[INIT_LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[END_PTR]] +// LLVM: br i1 %[[CMP]], label %[[INIT_LOOP_BODY]], label %[[INIT_LOOP_END:.*]] +// LLVM: [[INIT_LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[TMP]] +// LLVM: %[[NEXT:.*]] = getelementptr %struct.array_element, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[TMP]] +// LLVM: br label %[[INIT_LOOP_NEXT:.*]] +// LLVM: [[INIT_LOOP_END]]: +// LLVM: %[[ARR_BEGIN:.*]] = getelementptr %struct.array_element, ptr %[[ARR]], i32 0 +// LLVM: %[[ARR_END:.*]] = getelementptr %struct.array_element, ptr %[[ARR_BEGIN]], i64 4 +// LLVM: %[[ARR_CUR:.*]] = alloca ptr +// LLVM: store ptr %[[ARR_END]], ptr %[[ARR_CUR]] +// LLVM: br label %[[DESTROY_LOOP_BODY:.*]] +// LLVM: [[DESTROY_LOOP_NEXT:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ARR_CUR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[ARR_BEGIN]] +// LLVM: br i1 %[[CMP]], label %[[DESTROY_LOOP_BODY]], label %[[DESTROY_LOOP_END:.*]] +// LLVM: [[DESTROY_LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ARR_CUR]] +// LLVM: call void @_ZN13array_elementD1Ev(ptr %[[CUR]]) +// LLVM: %[[PREV:.*]] = getelementptr %struct.array_element, ptr %[[CUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[ARR_CUR]] +// LLVM: br label %[[DESTROY_LOOP_NEXT]] +// LLVM: [[DESTROY_LOOP_END]]: +// LLVM: ret void + +// OGCG: define{{.*}} void @_Z21test_array_destructorv() +// OGCG: entry: +// OGCG: %[[ARR:.*]] = alloca [5 x %struct.array_element] +// OGCG: %[[ARRAYINIT_END:.*]] = getelementptr inbounds %struct.array_element, ptr %[[ARR]], i64 5 +// OGCG: br label %[[INIT_LOOP_BODY:.*]] +// OGCG: [[INIT_LOOP_BODY]]: +// OGCG: %[[CUR:.*]] = phi ptr [ %[[ARR]], %entry ], [ %[[NEXT:.*]], %[[INIT_LOOP_BODY]] ] +// OGCG: %[[NEXT]] = getelementptr inbounds %struct.array_element, ptr %[[CUR]], i64 1 +// OGCG: %[[CMP:.*]] = icmp eq ptr %[[NEXT]], %[[ARRAYINIT_END]] +// OGCG: br i1 %[[CMP]], label %[[INIT_LOOP_END:.*]], label %[[INIT_LOOP_BODY]] +// OGCG: [[INIT_LOOP_END:.*]]: +// OGCG: %[[BEGIN:.*]] = getelementptr inbounds [5 x %struct.array_element], ptr %[[ARR]], i32 0, i32 0 +// OGCG: %[[END:.*]] = getelementptr inbounds %struct.array_element, ptr %[[BEGIN]], i64 5 +// OGCG: br label %[[DESTROY_LOOP_BODY:.*]] +// OGCG: [[DESTROY_LOOP_BODY:.*]]: +// OGCG: %[[CUR:.*]] = phi ptr [ %[[END]], %[[INIT_LOOP_END]] ], [ %[[PREV:.*]], %[[DESTROY_LOOP_BODY]] ] +// OGCG: %[[PREV]] = getelementptr inbounds %struct.array_element, ptr %[[CUR]], i64 -1 +// OGCG: call void @_ZN13array_elementD1Ev(ptr {{.*}} %[[PREV]]) +// OGCG: %[[CMP:.*]] = icmp eq ptr %[[PREV]], %[[BEGIN]] +// OGCG: br i1 %[[CMP]], label %[[DESTROY_LOOP_END:.*]], label %[[DESTROY_LOOP_BODY]] +// OGCG: [[DESTROY_LOOP_END:.*]]: +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/function-to-pointer-decay.c b/clang/test/CIR/CodeGen/function-to-pointer-decay.c new file mode 100644 index 0000000..507957a --- /dev/null +++ b/clang/test/CIR/CodeGen/function-to-pointer-decay.c @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void f(void); + +void f1() { + (void (*)())f; +} + +void f2() { + (*(void (*)(void))f)(); +} + +void test_lvalue_cast() { + (*(void (*)(int))f)(42); +} + +// CIR-LABEL: cir.func{{.*}} @f() +// CIR: cir.func{{.*}} @f1() +// CIR: cir.return{{.*}} + +// CIR-LABEL: cir.func{{.*}} @f2() +// CIR: cir.call @f() : () -> () + +// CIR-LABEL: cir.func{{.*}} @test_lvalue_cast() +// CIR: %[[S0:.+]] = {{.*}}@f : !cir.ptr<!cir.func<()>>{{.*}} +// CIR: %[[S1:.+]] = cir.cast{{.*}}%[[S0]] : !cir.ptr<!cir.func<()>>{{.*}} +// CIR: %[[S2:.+]] = cir.const #cir.int<42> : !s32i +// CIR: cir.call %[[S1]](%[[S2]]) : (!cir.ptr<!cir.func<(!s32i)>>, !s32i) -> () + +// LLVM-LABEL: define{{.*}} void @f1() +// LLVM: ret void +// LLVM: define{{.*}} void @f2() +// LLVM: call void @f() +// LLVM: define{{.*}} void @test_lvalue_cast() +// LLVM: call void @f(i32 42) + +// OGCG-LABEL: define{{.*}} void @f1() +// OGCG: ret void +// OGCG: define{{.*}} void @f2() +// OGCG: call void @f() +// OGCG: define{{.*}} void @test_lvalue_cast() +// OGCG: call void @f(i32 noundef 42) diff --git a/clang/test/CIR/CodeGen/globals.cpp b/clang/test/CIR/CodeGen/globals.cpp new file mode 100644 index 0000000..a3e1613 --- /dev/null +++ b/clang/test/CIR/CodeGen/globals.cpp @@ -0,0 +1,37 @@ +// 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 + +// Should constant initialize global with constant address. +int var = 1; +int *constAddr = &var; + +// CIR: cir.global external @constAddr = #cir.global_view<@var> : !cir.ptr<!s32i> + +// LLVM: @constAddr = global ptr @var, align 8 + +// OGCG: @constAddr = global ptr @var, align 8 + +// Should constant initialize global with constant address. +int f(); +int (*constFnAddr)() = f; + +// CIR: cir.global external @constFnAddr = #cir.global_view<@_Z1fv> : !cir.ptr<!cir.func<() -> !s32i>> + +// LLVM: @constFnAddr = global ptr @_Z1fv, align 8 + +// OGCG: @constFnAddr = global ptr @_Z1fv, align 8 + +int arr[4][16]; +int *constArrAddr = &arr[2][1]; + +// CIR: cir.global external @constArrAddr = #cir.global_view<@arr, [2 : i32, 1 : i32]> : !cir.ptr<!s32i> + +// The 'inbounds' and 'nuw' flags are inferred by LLVM's constant folder. The +// same flags show up at -O1 in OGCG. +// LLVM: @constArrAddr = global ptr getelementptr inbounds nuw (i8, ptr @arr, i64 132), align 8 + +// OGCG: @constArrAddr = global ptr getelementptr (i8, ptr @arr, i64 132), align 8 diff --git a/clang/test/CIR/CodeGen/goto.cpp b/clang/test/CIR/CodeGen/goto.cpp new file mode 100644 index 0000000..48cb44e --- /dev/null +++ b/clang/test/CIR/CodeGen/goto.cpp @@ -0,0 +1,305 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +int shouldNotGenBranchRet(int x) { + if (x > 5) + goto err; + return 0; +err: + return -1; +} +// CIR: cir.func dso_local @_Z21shouldNotGenBranchReti +// CIR: cir.if {{.*}} { +// CIR: cir.goto "err" +// CIR: } +// CIR: [[ZERO:%.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store [[ZERO]], [[RETVAL:%.*]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.br ^bb1 +// CIR: ^bb1: +// CIR: [[RET:%.*]] = cir.load [[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return [[RET]] : !s32i +// CIR: ^bb2: +// CIR: cir.label "err" +// CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i +// CIR: [[MINUS:%.*]] = cir.unary(minus, [[ONE]]) nsw : !s32i, !s32i +// CIR: cir.store [[MINUS]], [[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.br ^bb1 + +// LLVM: define dso_local i32 @_Z21shouldNotGenBranchReti +// LLVM: [[COND:%.*]] = load i32, ptr {{.*}}, align 4 +// LLVM: [[CMP:%.*]] = icmp sgt i32 [[COND]], 5 +// LLVM: br i1 [[CMP]], label %[[IFTHEN:.*]], label %[[IFEND:.*]] +// LLVM: [[IFTHEN]]: +// LLVM: br label %[[ERR:.*]] +// LLVM: [[IFEND]]: +// LLVM: br label %[[BB9:.*]] +// LLVM: [[BB9]]: +// LLVM: store i32 0, ptr %[[RETVAL:.*]], align 4 +// LLVM: br label %[[BBRET:.*]] +// LLVM: [[BBRET]]: +// LLVM: [[RET:%.*]] = load i32, ptr %[[RETVAL]], align 4 +// LLVM: ret i32 [[RET]] +// LLVM: [[ERR]]: +// LLVM: store i32 -1, ptr %[[RETVAL]], align 4 +// LLVM: br label %10 + +// OGCG: define dso_local noundef i32 @_Z21shouldNotGenBranchReti +// OGCG: if.then: +// OGCG: br label %err +// OGCG: if.end: +// OGCG: br label %return +// OGCG: err: +// OGCG: br label %return +// OGCG: return: + +int shouldGenBranch(int x) { + if (x > 5) + goto err; + x++; +err: + return -1; +} +// CIR: cir.func dso_local @_Z15shouldGenBranchi +// CIR: cir.if {{.*}} { +// CIR: cir.goto "err" +// CIR: } +// CIR: cir.br ^bb1 +// CIR: ^bb1: +// CIR: cir.label "err" + +// LLVM: define dso_local i32 @_Z15shouldGenBranchi +// LLVM: br i1 [[CMP:%.*]], label %[[IFTHEN:.*]], label %[[IFEND:.*]] +// LLVM: [[IFTHEN]]: +// LLVM: br label %[[ERR:.*]] +// LLVM: [[IFEND]]: +// LLVM: br label %[[BB9:.*]] +// LLVM: [[BB9]]: +// LLVM: br label %[[ERR]] +// LLVM: [[ERR]]: +// LLVM: ret i32 [[RET:%.*]] + +// OGCG: define dso_local noundef i32 @_Z15shouldGenBranchi +// OGCG: if.then: +// OGCG: br label %err +// OGCG: if.end: +// OGCG: br label %err +// OGCG: err: +// OGCG: ret + +void severalLabelsInARow(int a) { + int b = a; + goto end1; + b = b + 1; + goto end2; +end1: +end2: + b = b + 2; +} +// CIR: cir.func dso_local @_Z19severalLabelsInARowi +// CIR: cir.goto "end1" +// CIR: ^bb[[#BLK1:]] +// CIR: cir.goto "end2" +// CIR: ^bb[[#BLK2:]]: +// CIR: cir.label "end1" +// CIR: cir.br ^bb[[#BLK3:]] +// CIR: ^bb[[#BLK3]]: +// CIR: cir.label "end2" + +// LLVM: define dso_local void @_Z19severalLabelsInARowi +// LLVM: br label %[[END1:.*]] +// LLVM: [[UNRE:.*]]: ; No predecessors! +// LLVM: br label %[[END2:.*]] +// LLVM: [[END1]]: +// LLVM: br label %[[END2]] +// LLVM: [[END2]]: +// LLVM: ret + +// OGCG: define dso_local void @_Z19severalLabelsInARowi +// OGCG: br label %end1 +// OGCG: end1: +// OGCG: br label %end2 +// OGCG: end2: +// OGCG: ret + +void severalGotosInARow(int a) { + int b = a; + goto end; + goto end; +end: + b = b + 2; +} +// CIR: cir.func dso_local @_Z18severalGotosInARowi +// CIR: cir.goto "end" +// CIR: ^bb[[#BLK1:]]: +// CIR: cir.goto "end" +// CIR: ^bb[[#BLK2:]]: +// CIR: cir.label "end" + +// LLVM: define dso_local void @_Z18severalGotosInARowi +// LLVM: br label %[[END:.*]] +// LLVM: [[UNRE:.*]]: ; No predecessors! +// LLVM: br label %[[END]] +// LLVM: [[END]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z18severalGotosInARowi(i32 noundef %a) #0 { +// OGCG: br label %end +// OGCG: end: +// OGCG: ret void + +extern "C" void action1(); +extern "C" void action2(); +extern "C" void multiple_non_case(int v) { + switch (v) { + default: + action1(); + l2: + action2(); + break; + } +} + +// CIR: cir.func dso_local @multiple_non_case +// CIR: cir.switch +// CIR: cir.case(default, []) { +// CIR: cir.call @action1() +// CIR: cir.br ^[[BB1:[a-zA-Z0-9]+]] +// CIR: ^[[BB1]]: +// CIR: cir.label +// CIR: cir.call @action2() +// CIR: cir.break + +// LLVM: define dso_local void @multiple_non_case +// LLVM: [[SWDEFAULT:.*]]: +// LLVM: call void @action1() +// LLVM: br label %[[L2:.*]] +// LLVM: [[L2]]: +// LLVM: call void @action2() +// LLVM: br label %[[BREAK:.*]] + +// OGCG: define dso_local void @multiple_non_case +// OGCG: sw.default: +// OGCG: call void @action1() +// OGCG: br label %l2 +// OGCG: l2: +// OGCG: call void @action2() +// OGCG: br label [[BREAK:%.*]] + +extern "C" void case_follow_label(int v) { + switch (v) { + case 1: + label: + case 2: + action1(); + break; + default: + action2(); + goto label; + } +} + +// CIR: cir.func dso_local @case_follow_label +// CIR: cir.switch +// CIR: cir.case(equal, [#cir.int<1> : !s32i]) { +// CIR: cir.label "label" +// CIR: cir.case(equal, [#cir.int<2> : !s32i]) { +// CIR: cir.call @action1() +// CIR: cir.break +// CIR: cir.case(default, []) { +// CIR: cir.call @action2() +// CIR: cir.goto "label" + +// LLVM: define dso_local void @case_follow_label +// LLVM: switch i32 {{.*}}, label %[[SWDEFAULT:.*]] [ +// LLVM: i32 1, label %[[LABEL:.*]] +// LLVM: i32 2, label %[[CASE2:.*]] +// LLVM: ] +// LLVM: [[LABEL]]: +// LLVM: br label %[[CASE2]] +// LLVM: [[CASE2]]: +// LLVM: call void @action1() +// LLVM: br label %[[BREAK:.*]] +// LLVM: [[BREAK]]: +// LLVM: br label %[[END:.*]] +// LLVM: [[SWDEFAULT]]: +// LLVM: call void @action2() +// LLVM: br label %[[LABEL]] +// LLVM: [[END]]: +// LLVM: br label %[[RET:.*]] +// LLVM: [[RET]]: +// LLVM: ret void + +// OGCG: define dso_local void @case_follow_label +// OGCG: sw.bb: +// OGCG: br label %label +// OGCG: label: +// OGCG: br label %sw.bb1 +// OGCG: sw.bb1: +// OGCG: call void @action1() +// OGCG: br label %sw.epilog +// OGCG: sw.default: +// OGCG: call void @action2() +// OGCG: br label %label +// OGCG: sw.epilog: +// OGCG: ret void + +extern "C" void default_follow_label(int v) { + switch (v) { + case 1: + case 2: + action1(); + break; + label: + default: + action2(); + goto label; + } +} + +// CIR: cir.func dso_local @default_follow_label +// CIR: cir.switch +// CIR: cir.case(equal, [#cir.int<1> : !s32i]) { +// CIR: cir.yield +// CIR: cir.case(equal, [#cir.int<2> : !s32i]) { +// CIR: cir.call @action1() +// CIR: cir.break +// CIR: cir.label "label" +// CIR: cir.case(default, []) { +// CIR: cir.call @action2() +// CIR: cir.goto "label" + +// LLVM: define dso_local void @default_follow_label +// LLVM: [[CASE1:.*]]: +// LLVM: br label %[[BB8:.*]] +// LLVM: [[BB8]]: +// LLVM: br label %[[CASE2:.*]] +// LLVM: [[CASE2]]: +// LLVM: call void @action1() +// LLVM: br label %[[BREAK:.*]] +// LLVM: [[LABEL:.*]]: +// LLVM: br label %[[SWDEFAULT:.*]] +// LLVM: [[SWDEFAULT]]: +// LLVM: call void @action2() +// LLVM: br label %[[BB9:.*]] +// LLVM: [[BB9]]: +// LLVM: br label %[[LABEL]] +// LLVM: [[BREAK]]: +// LLVM: br label %[[RET:.*]] +// LLVM: [[RET]]: +// LLVM: ret void + +// OGCG: define dso_local void @default_follow_label +// OGCG: sw.bb: +// OGCG: call void @action1() +// OGCG: br label %sw.epilog +// OGCG: label: +// OGCG: br label %sw.default +// OGCG: sw.default: +// OGCG: call void @action2() +// OGCG: br label %label +// OGCG: sw.epilog: +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/inline-asm.c b/clang/test/CIR/CodeGen/inline-asm.c new file mode 100644 index 0000000..fc959f9 --- /dev/null +++ b/clang/test/CIR/CodeGen/inline-asm.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM + +void f1() { + // CIR: cir.asm(x86_att, + // CIR: out = [], + // CIR: in = [], + // CIR: in_out = [], + // CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects + // LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() + __asm__ volatile("" : : : ); +} + +void f2() { + // CIR: cir.asm(x86_att, + // CIR: out = [], + // CIR: in = [], + // CIR: in_out = [], + // CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects + // LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() + __asm__ volatile("nop" : : : ); +} diff --git a/clang/test/CIR/CodeGen/label.c b/clang/test/CIR/CodeGen/label.c new file mode 100644 index 0000000..a050094 --- /dev/null +++ b/clang/test/CIR/CodeGen/label.c @@ -0,0 +1,186 @@ +// 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 + +void label() { +labelA: + return; +} + +// CIR: cir.func no_proto dso_local @label +// CIR: cir.label "labelA" +// CIR: cir.return + +// LLVM:define dso_local void @label +// LLVM: ret void + +// OGCG: define dso_local void @label +// OGCG: br label %labelA +// OGCG: labelA: +// OGCG: ret void + +void multiple_labels() { +labelB: +labelC: + return; +} + +// CIR: cir.func no_proto dso_local @multiple_labels +// CIR: cir.label "labelB" +// CIR: cir.br ^bb1 +// CIR: ^bb1: // pred: ^bb0 +// CIR: cir.label "labelC" +// CIR: cir.return + +// LLVM: define dso_local void @multiple_labels() +// LLVM: br label %1 +// LLVM: 1: +// LLVM: ret void + +// OGCG: define dso_local void @multiple_labels +// OGCG: br label %labelB +// OGCG: labelB: +// OGCG: br label %labelC +// OGCG: labelC: +// OGCG: ret void + +void label_in_if(int cond) { + if (cond) { +labelD: + cond++; + } +} + +// CIR: cir.func dso_local @label_in_if +// CIR: cir.if {{.*}} { +// CIR: cir.label "labelD" +// CIR: [[LOAD:%.*]] = cir.load align(4) [[COND:%.*]] : !cir.ptr<!s32i>, !s32i +// CIR: [[INC:%.*]] = cir.unary(inc, %3) nsw : !s32i, !s32i +// CIR: cir.store align(4) [[INC]], [[COND]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: cir.return + +// LLVM: define dso_local void @label_in_if +// LLVM: br label %3 +// LLVM: 3: +// LLVM: [[LOAD:%.*]] = load i32, ptr [[COND:%.*]], align 4 +// LLVM: [[CMP:%.*]] = icmp ne i32 [[LOAD]], 0 +// LLVM: br i1 [[CMP]], label %6, label %9 +// LLVM: 6: +// LLVM: [[LOAD2:%.*]] = load i32, ptr [[COND]], align 4 +// LLVM: [[ADD1:%.*]] = add nsw i32 [[LOAD2]], 1 +// LLVM: store i32 [[ADD1]], ptr [[COND]], align 4 +// LLVM: br label %9 +// LLVM: 9: +// LLVM: br label %10 +// LLVM: 10: +// LLVM: ret void + +// OGCG: define dso_local void @label_in_if +// OGCG: if.then: +// OGCG: br label %labelD +// OGCG: labelD: +// OGCG: [[LOAD:%.*]] = load i32, ptr [[COND:%.*]], align 4 +// OGCG: [[INC:%.*]] = add nsw i32 %1, 1 +// OGCG: store i32 [[INC]], ptr [[COND]], align 4 +// OGCG: br label %if.end +// OGCG: if.end: +// OGCG: ret void + +void after_return() { + return; + label: +} + +// CIR: cir.func no_proto dso_local @after_return +// CIR: cir.br ^bb1 +// CIR: ^bb1: // 2 preds: ^bb0, ^bb2 +// CIR: cir.return +// CIR: ^bb2: // no predecessors +// CIR: cir.label "label" +// CIR: cir.br ^bb1 + +// LLVM: define dso_local void @after_return +// LLVM: br label %1 +// LLVM: 1: +// LLVM: ret void +// LLVM: 2: +// LLVM: br label %1 + +// OGCG: define dso_local void @after_return +// OGCG: br label %label +// OGCG: label: +// OGCG: ret void + + +void after_unreachable() { + __builtin_unreachable(); + label: +} + +// CIR: cir.func no_proto dso_local @after_unreachable +// CIR: cir.unreachable +// CIR: ^bb1: +// CIR: cir.label "label" +// CIR: cir.return + +// LLVM: define dso_local void @after_unreachable +// LLVM: unreachable +// LLVM: 1: +// LLVM: ret void + +// OGCG: define dso_local void @after_unreachable +// OGCG: unreachable +// OGCG: label: +// OGCG: ret void + +void labelWithoutMatch() { +end: + return; +} +// CIR: cir.func no_proto dso_local @labelWithoutMatch +// CIR: cir.label "end" +// CIR: cir.return +// CIR: } + +// LLVM: define dso_local void @labelWithoutMatch +// LLVM: ret void + +// OGCG: define dso_local void @labelWithoutMatch +// OGCG: br label %end +// OGCG: end: +// OGCG: ret void + +struct S {}; +struct S get(); +void bar(struct S); + +void foo() { + { + label: + bar(get()); + } +} + +// CIR: cir.func no_proto dso_local @foo +// CIR: cir.scope { +// CIR: cir.label "label" +// CIR: %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["agg.tmp0"] + +// LLVM:define dso_local void @foo() { +// LLVM: [[ALLOC:%.*]] = alloca %struct.S, i64 1, align 1 +// LLVM: br label %2 +// LLVM:2: +// LLVM: [[CALL:%.*]] = call %struct.S @get() +// LLVM: store %struct.S [[CALL]], ptr [[ALLOC]], align 1 +// LLVM: [[LOAD:%.*]] = load %struct.S, ptr [[ALLOC]], align 1 +// LLVM: call void @bar(%struct.S [[LOAD]]) + +// OGCG: define dso_local void @foo() +// OGCG: %agg.tmp = alloca %struct.S, align 1 +// OGCG: %undef.agg.tmp = alloca %struct.S, align 1 +// OGCG: br label %label +// OGCG: label: diff --git a/clang/test/CIR/CodeGen/lang-c-cpp.cpp b/clang/test/CIR/CodeGen/lang-c-cpp.cpp new file mode 100644 index 0000000..e126932 --- /dev/null +++ b/clang/test/CIR/CodeGen/lang-c-cpp.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cpp.cir +// RUN: FileCheck --check-prefix=CIR-CPP --input-file=%t.cpp.cir %s +// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.c.cir +// RUN: FileCheck --check-prefix=CIR-C --input-file=%t.c.cir %s + +// CIR-CPP: module attributes {{{.*}}cir.lang = #cir.lang<cxx>{{.*}}} +// CIR-C: module attributes {{{.*}}cir.lang = #cir.lang<c>{{.*}}} + +int main() { + return 0; +} diff --git a/clang/test/CIR/CodeGen/local-vars.cpp b/clang/test/CIR/CodeGen/local-vars.cpp index 9385fdf..0c5c972 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/module-asm.c b/clang/test/CIR/CodeGen/module-asm.c new file mode 100644 index 0000000..e6cec5e --- /dev/null +++ b/clang/test/CIR/CodeGen/module-asm.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +// CHECK: cir.module_asm = [".globl bar", ".globl foo"] +__asm (".globl bar"); +__asm (".globl foo"); diff --git a/clang/test/CIR/CodeGen/multi-vtable.cpp b/clang/test/CIR/CodeGen/multi-vtable.cpp new file mode 100644 index 0000000..b42f8a6 --- /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/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c new file mode 100644 index 0000000..1b54edf --- /dev/null +++ b/clang/test/CIR/CodeGen/statement-exprs.c @@ -0,0 +1,277 @@ +// 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 + +// This fails because of a non-ignored copy of an aggregate in test3. +// XFAIL: * + +int f19(void) { + return ({ 3;;4;; }); +} + +// CIR: cir.func dso_local @f19() -> !s32i +// CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[TMP:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[C3:.+]] = cir.const #cir.int<3> : !s32i +// CIR: %[[C4:.+]] = cir.const #cir.int<4> : !s32i +// CIR: cir.store {{.*}} %[[C4]], %[[TMP]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[TMP_VAL:.+]] = cir.load {{.*}} %[[TMP]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[TMP_VAL]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RES:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RES]] : !s32i + +// LLVM: define dso_local i32 @f19() +// LLVM: %[[VAR1:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR2:.+]] = alloca i32, i64 1 +// LLVM: br label %[[LBL3:.+]] +// LLVM: [[LBL3]]: +// LLVM: store i32 4, ptr %[[VAR2]] +// LLVM: br label %[[LBL4:.+]] +// LLVM: [[LBL4]]: +// LLVM: %[[V1:.+]] = load i32, ptr %[[VAR2]] +// LLVM: store i32 %[[V1]], ptr %[[VAR1]] +// LLVM: %[[RES:.+]] = load i32, ptr %[[VAR1]] +// LLVM: ret i32 %[[RES]] + +// OGCG: define dso_local i32 @f19() +// OGCG: entry: +// OGCG: %[[TMP:.+]] = alloca i32 +// OGCG: store i32 4, ptr %[[TMP]] +// OGCG: %[[TMP_VAL:.+]] = load i32, ptr %[[TMP]] +// OGCG: ret i32 %[[TMP_VAL]] + + +int nested(void) { + ({123;}); + { + int bar = 987; + return ({ ({ int asdf = 123; asdf; }); ({9999;}); }); + } +} + +// CIR: cir.func dso_local @nested() -> !s32i +// CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[TMP_OUTER:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[C123_OUTER:.+]] = cir.const #cir.int<123> : !s32i +// CIR: cir.store {{.*}} %[[C123_OUTER]], %[[TMP_OUTER]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[LOAD_TMP_OUTER:.+]] = cir.load {{.*}} %[[TMP_OUTER]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.scope { +// CIR: %[[BAR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["bar", init] +// CIR: %[[TMP_BARRET:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] +// CIR: %[[C987:.+]] = cir.const #cir.int<987> : !s32i +// CIR: cir.store {{.*}} %[[C987]], %[[BAR]] : !s32i, !cir.ptr<!s32i> +// CIR: cir.scope { +// CIR: %[[TMP1:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] +// CIR: %[[TMP2:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[ASDF:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["asdf", init] +// CIR: %[[C123_INNER:.+]] = cir.const #cir.int<123> : !s32i +// CIR: cir.store {{.*}} %[[C123_INNER]], %[[ASDF]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[LOAD_ASDF:.+]] = cir.load {{.*}} %[[ASDF]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store {{.*}} %[[LOAD_ASDF]], %[[TMP1]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[V1:.+]] = cir.load {{.*}} %[[TMP1]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.scope { +// CIR: %[[C9999:.+]] = cir.const #cir.int<9999> : !s32i +// CIR: cir.store {{.*}} %[[C9999]], %[[TMP2]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[V2:.+]] = cir.load {{.*}} %[[TMP2]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store {{.*}} %[[V2]], %[[TMP_BARRET]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[BARRET_VAL:.+]] = cir.load {{.*}} %[[TMP_BARRET]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[BARRET_VAL]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RES:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RES]] : !s32i +// CIR: } +// CIR: %[[FINAL_RES:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[FINAL_RES]] : !s32i + +// LLVM: define dso_local i32 @nested() +// LLVM: %[[VAR1:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR2:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR3:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR4:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR5:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR6:.+]] = alloca i32, i64 1 +// LLVM: %[[VAR7:.+]] = alloca i32, i64 1 +// LLVM: br label %[[LBL8:.+]] +// LLVM: [[LBL8]]: +// LLVM: store i32 123, ptr %[[VAR7]] +// LLVM: br label %[[LBL9:.+]] +// LLVM: [[LBL9]]: +// LLVM: br label %[[LBL10:.+]] +// LLVM: [[LBL10]]: +// LLVM: store i32 987, ptr %[[VAR1]] +// LLVM: br label %[[LBL11:.+]] +// LLVM: [[LBL11]]: +// LLVM: br label %[[LBL12:.+]] +// LLVM: [[LBL12]]: +// LLVM: store i32 123, ptr %[[VAR5]] +// LLVM: %[[V1:.+]] = load i32, ptr %[[VAR5]] +// LLVM: store i32 %[[V1]], ptr %[[VAR3]] +// LLVM: br label %[[LBL14:.+]] +// LLVM: [[LBL14]]: +// LLVM: br label %[[LBL15:.+]] +// LLVM: [[LBL15]]: +// LLVM: store i32 9999, ptr %[[VAR4]] +// LLVM: br label %[[LBL16:.+]] +// LLVM: [[LBL16]]: +// LLVM: %[[V2:.+]] = load i32, ptr %[[VAR4]] +// LLVM: store i32 %[[V2]], ptr %[[VAR2]] +// LLVM: br label %[[LBL18:.+]] +// LLVM: [[LBL18]]: +// LLVM: %[[V3:.+]] = load i32, ptr %[[VAR2]] +// LLVM: store i32 %[[V3]], ptr %[[VAR6]] +// LLVM: %[[RES:.+]] = load i32, ptr %[[VAR6]] +// LLVM: ret i32 %[[RES]] + +// OGCG: define dso_local i32 @nested() +// OGCG: entry: +// OGCG: %[[TMP_OUTER:.+]] = alloca i32 +// OGCG: %[[BAR:.+]] = alloca i32 +// OGCG: %[[ASDF:.+]] = alloca i32 +// OGCG: %[[TMP1:.+]] = alloca i32 +// OGCG: %[[TMP2:.+]] = alloca i32 +// OGCG: %[[TMP3:.+]] = alloca i32 +// OGCG: store i32 123, ptr %[[TMP_OUTER]] +// OGCG: %[[OUTER_VAL:.+]] = load i32, ptr %[[TMP_OUTER]] +// OGCG: store i32 987, ptr %[[BAR]] +// OGCG: store i32 123, ptr %[[ASDF]] +// OGCG: %[[ASDF_VAL:.+]] = load i32, ptr %[[ASDF]] +// OGCG: store i32 %[[ASDF_VAL]], ptr %[[TMP1]] +// OGCG: %[[TMP1_VAL:.+]] = load i32, ptr %[[TMP1]] +// OGCG: store i32 9999, ptr %[[TMP3]] +// OGCG: %[[TMP3_VAL:.+]] = load i32, ptr %[[TMP3]] +// OGCG: store i32 %[[TMP3_VAL]], ptr %[[TMP2]] +// OGCG: %[[RES:.+]] = load i32, ptr %[[TMP2]] +// OGCG: ret i32 %[[RES]] + +void empty() { + return ({;;;;}); +} + +// CIR: cir.func no_proto dso_local @empty() +// CIR-NEXT: cir.return + +// LLVM: define dso_local void @empty() +// LLVM: ret void +// LLVM: } + +// OGCG: define dso_local void @empty() +// OGCG: ret void +// OGCG: } + +void empty2() { ({ }); } + +// CIR: @empty2 +// CIR-NEXT: cir.return + +// LLVM: @empty2() +// LLVM: ret void +// LLVM: } + +// OGCG: @empty2() +// OGCG: ret void +// OGCG: } + + +// Yields an out-of-scope scalar. +void test2() { ({int x = 3; x; }); } +// CIR: @test2 +// CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i> +// CIR: cir.scope { +// CIR: %[[VAR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] +// [...] +// CIR: %[[TMP:.+]] = cir.load{{.*}} %[[VAR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store{{.*}} %[[TMP]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %{{.+}} = cir.load{{.*}} %[[RETVAL]] : !cir.ptr<!s32i>, !s32i + +// LLVM: define dso_local void @test2() +// LLVM: %[[X:.+]] = alloca i32, i64 1 +// LLVM: %[[TMP:.+]] = alloca i32, i64 1 +// LLVM: br label %[[LBL3:.+]] +// LLVM: [[LBL3]]: +// LLVM: store i32 3, ptr %[[X]] +// LLVM: %[[X_VAL:.+]] = load i32, ptr %[[X]] +// LLVM: store i32 %[[X_VAL]], ptr %[[TMP]] +// LLVM: br label %[[LBL5:.+]] +// LLVM: [[LBL5]]: +// LLVM: ret void + +// OGCG: define dso_local void @test2() +// OGCG: entry: +// OGCG: %[[X:.+]] = alloca i32 +// OGCG: %[[TMP:.+]] = alloca i32 +// OGCG: store i32 3, ptr %[[X]] +// OGCG: %[[X_VAL:.+]] = load i32, ptr %[[X]] +// OGCG: store i32 %[[X_VAL]], ptr %[[TMP]] +// OGCG: %[[TMP_VAL:.+]] = load i32, ptr %[[TMP]] +// OGCG: ret void + +// Yields an aggregate. +struct S { int x; }; +int test3() { return ({ struct S s = {1}; s; }).x; } +// CIR: cir.func no_proto dso_local @test3() -> !s32i +// CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[YIELDVAL:.+]] = cir.scope { +// CIR: %[[REF_TMP0:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["ref.tmp0"] +// CIR: %[[TMP:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[S:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] +// CIR: %[[GEP_X_S:.+]] = cir.get_member %[[S]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i> +// CIR: %[[C1:.+]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store {{.*}} %[[C1]], %[[GEP_X_S]] : !s32i, !cir.ptr<!s32i> +// CIR: } +// CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i> +// CIR: %[[XVAL:.+]] = cir.load {{.*}} %[[GEP_X_TMP]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.yield %[[XVAL]] : !s32i +// CIR: } : !s32i +// CIR: cir.store %[[YIELDVAL]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RES:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RES]] : !s32i + +// LLVM: define dso_local i32 @test3() +// LLVM: %[[VAR1:.+]] = alloca %struct.S, i64 1 +// LLVM: %[[VAR2:.+]] = alloca %struct.S, i64 1 +// LLVM: %[[VAR3:.+]] = alloca %struct.S, i64 1 +// LLVM: %[[VAR4:.+]] = alloca i32, i64 1 +// LLVM: br label %[[LBL5:.+]] +// LLVM: [[LBL5]]: +// LLVM: br label %[[LBL6:.+]] +// LLVM: [[LBL6]]: +// LLVM: %[[GEP_S:.+]] = getelementptr %struct.S, ptr %[[VAR3]], i32 0, i32 0 +// LLVM: store i32 1, ptr %[[GEP_S]] +// LLVM: br label %[[LBL8:.+]] +// LLVM: [[LBL8]]: +// LLVM: %[[GEP_VAR1:.+]] = getelementptr %struct.S, ptr %[[VAR1]], i32 0, i32 0 +// LLVM: %[[LOAD_X:.+]] = load i32, ptr %[[GEP_VAR1]] +// LLVM: br label %[[LBL11:.+]] +// LLVM: [[LBL11]]: +// LLVM: %[[PHI:.+]] = phi i32 [ %[[LOAD_X]], %[[LBL8]] ] +// LLVM: store i32 %[[PHI]], ptr %[[VAR4]] +// LLVM: %[[RES:.+]] = load i32, ptr %[[VAR4]] +// LLVM: ret i32 %[[RES]] + +// OGCG: define dso_local i32 @test3() +// OGCG: entry: +// OGCG: %[[REF_TMP:.+]] = alloca %struct.S +// OGCG: %[[S:.+]] = alloca %struct.S +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[S]], ptr align 4 @__const.test3.s, i64 4, i1 false) +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[REF_TMP]], ptr align 4 %[[S]], i64 4, i1 false) +// OGCG: %[[GEP:.+]] = getelementptr inbounds nuw %struct.S, ptr %[[REF_TMP]], i32 0, i32 0 +// OGCG: %[[XVAL:.+]] = load i32, ptr %[[GEP]] +// OGCG: ret i32 %[[XVAL]] + +// Expression is wrapped in an expression attribute (just ensure it does not crash). +void test4(int x) { ({[[gsl::suppress("foo")]] x;}); } +// CIR: @test4 +// LLVM: @test4 +// OGCG: @test4 diff --git a/clang/test/CIR/CodeGen/static-vars.cpp b/clang/test/CIR/CodeGen/static-vars.cpp index d949936..4f22fc7ab 100644 --- a/clang/test/CIR/CodeGen/static-vars.cpp +++ b/clang/test/CIR/CodeGen/static-vars.cpp @@ -2,6 +2,37 @@ // RUN: FileCheck --input-file=%t.cir %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t1.ll // RUN: FileCheck --check-prefix=LLVM --input-file=%t1.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t1.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t1.ll %s + +template<typename T> +struct implicitly_instantiated { + static T member; +}; + +template<typename T> +T implicitly_instantiated<T>::member = 12345; + +int use_implicitly_instantiated() { + return implicitly_instantiated<int>::member; +} + +// CHECK-DAG: cir.global linkonce_odr comdat @_ZN23implicitly_instantiatedIiE6memberE = #cir.int<12345> : !s32i +// LLVM-DAG: @_ZN23implicitly_instantiatedIiE6memberE = linkonce_odr global i32 12345, comdat +// OGCG-DAG: @_ZN23implicitly_instantiatedIiE6memberE = linkonce_odr global i32 12345, comdat + +template<typename T> +struct explicitly_instantiated { + static T member; +}; + +template<typename T> +T explicitly_instantiated<T>::member = 54321; + +template int explicitly_instantiated<int>::member; +// CHECK-DAG: cir.global weak_odr comdat @_ZN23explicitly_instantiatedIiE6memberE = #cir.int<54321> : !s32i +// LLVM-DAG: @_ZN23explicitly_instantiatedIiE6memberE = weak_odr global i32 54321, comdat +// OGCG-DAG: @_ZN23explicitly_instantiatedIiE6memberE = weak_odr global i32 54321, comdat void func1(void) { // Should lower default-initialized static vars. @@ -42,6 +73,8 @@ void func2(void) { // LLVM-DAG: $_ZZ4testvE1c = comdat any // LLVM-DAG: @_ZZ4testvE1c = linkonce_odr global i32 0, comdat, align 4 +// OGCG-DAG: $_ZZ4testvE1c = comdat any +// OGCG-DAG: @_ZZ4testvE1c = linkonce_odr global i32 0, comdat, align 4 inline void test() { static int c; } // CHECK-LABEL: @_Z4testv diff --git a/clang/test/CIR/CodeGen/stmt-expr.cpp b/clang/test/CIR/CodeGen/stmt-expr.cpp new file mode 100644 index 0000000..9e3911f --- /dev/null +++ b/clang/test/CIR/CodeGen/stmt-expr.cpp @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -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 -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 -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +class A { +public: + A(): x(0) {} + A(A &a) : x(a.x) {} + int x; + void Foo() {} +}; + +void test1() { + ({ + A a; + a; + }).Foo(); +} + +// CIR: cir.func dso_local @_Z5test1v() +// CIR: cir.scope { +// CIR: %[[REF_TMP0:.+]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["ref.tmp0"] +// CIR: %[[TMP:.+]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["tmp"] +// CIR: cir.scope { +// CIR: %[[A:.+]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["a", init] +// CIR: cir.call @_ZN1AC2Ev(%[[A]]) : (!cir.ptr<!rec_A>) -> () +// CIR: cir.call @_ZN1AC2ERS_(%[[REF_TMP0]], %[[A]]) : (!cir.ptr<!rec_A>, !cir.ptr<!rec_A>) -> () +// CIR: } +// CIR: cir.call @_ZN1A3FooEv(%[[REF_TMP0]]) : (!cir.ptr<!rec_A>) -> () +// CIR: } +// CIR: cir.return + +// LLVM: define dso_local void @_Z5test1v() +// LLVM: %[[VAR1:.+]] = alloca %class.A, i64 1 +// LLVM: %[[VAR2:.+]] = alloca %class.A, i64 1 +// LLVM: %[[VAR3:.+]] = alloca %class.A, i64 1 +// LLVM: br label %[[LBL4:.+]] +// LLVM: [[LBL4]]: +// LLVM: br label %[[LBL5:.+]] +// LLVM: [[LBL5]]: +// LLVM: call void @_ZN1AC2Ev(ptr %[[VAR3]]) +// LLVM: call void @_ZN1AC2ERS_(ptr %[[VAR1]], ptr %[[VAR3]]) +// LLVM: br label %[[LBL6:.+]] +// LLVM: [[LBL6]]: +// LLVM: call void @_ZN1A3FooEv(ptr %[[VAR1]]) +// LLVM: br label %[[LBL7:.+]] +// LLVM: [[LBL7]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z5test1v() +// OGCG: entry: +// OGCG: %[[REF_TMP:.+]] = alloca %class.A +// OGCG: %[[A:.+]] = alloca %class.A +// OGCG: call void @_ZN1AC2Ev(ptr {{.*}} %[[A]]) +// OGCG: call void @_ZN1AC2ERS_(ptr {{.*}} %[[REF_TMP]], ptr {{.*}} %[[A]]) +// OGCG: call void @_ZN1A3FooEv(ptr {{.*}} %[[REF_TMP]]) +// OGCG: ret void + +struct with_dtor { + ~with_dtor(); +}; + +void cleanup() { + ({ with_dtor wd; }); +} + +// CIR: cir.func dso_local @_Z7cleanupv() +// CIR: cir.scope { +// CIR: %[[WD:.+]] = cir.alloca !rec_with_dtor, !cir.ptr<!rec_with_dtor>, ["wd"] +// CIR: cir.call @_ZN9with_dtorD1Ev(%[[WD]]) nothrow : (!cir.ptr<!rec_with_dtor>) -> () +// CIR: } +// CIR: cir.return + +// LLVM: define dso_local void @_Z7cleanupv() +// LLVM: %[[WD:.+]] = alloca %struct.with_dtor, i64 1 +// LLVM: br label %[[LBL2:.+]] +// LLVM: [[LBL2]]: +// LLVM: call void @_ZN9with_dtorD1Ev(ptr %[[WD]]) +// LLVM: br label %[[LBL3:.+]] +// LLVM: [[LBL3]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z7cleanupv() +// OGCG: entry: +// OGCG: %[[WD:.+]] = alloca %struct.with_dtor +// OGCG: call void @_ZN9with_dtorD1Ev(ptr {{.*}} %[[WD]]) +// OGCG: ret void diff --git a/clang/test/CIR/CodeGen/string-literals.c b/clang/test/CIR/CodeGen/string-literals.c index 44fd191..38657b2 100644 --- a/clang/test/CIR/CodeGen/string-literals.c +++ b/clang/test/CIR/CodeGen/string-literals.c @@ -17,13 +17,13 @@ char g_exact[4] = "123"; // CIR: cir.global external @g_exact = #cir.const_array<"123\00" : !cir.array<!s8i x 4>> : !cir.array<!s8i x 4> -// CIR: cir.global "private" cir_private dso_local @[[STR1_GLOBAL:.*]] = #cir.const_array<"1\00" : !cir.array<!s8i x 2>> : !cir.array<!s8i x 2> -// CIR: cir.global "private" cir_private dso_local @[[STR2_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 1> -// CIR: cir.global "private" cir_private dso_local @[[STR3_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 2> +// CIR: cir.global "private" constant cir_private dso_local @[[STR1_GLOBAL:.*]] = #cir.const_array<"1\00" : !cir.array<!s8i x 2>> : !cir.array<!s8i x 2> +// CIR: cir.global "private" constant cir_private dso_local @[[STR2_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 1> +// CIR: cir.global "private" constant cir_private dso_local @[[STR3_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 2> -// LLVM: @[[STR1_GLOBAL:.*]] = private global [2 x i8] c"1\00" -// LLVM: @[[STR2_GLOBAL:.*]] = private global [1 x i8] zeroinitializer -// LLVM: @[[STR3_GLOBAL:.*]] = private global [2 x i8] zeroinitializer +// LLVM: @[[STR1_GLOBAL:.*]] = private constant [2 x i8] c"1\00" +// LLVM: @[[STR2_GLOBAL:.*]] = private constant [1 x i8] zeroinitializer +// LLVM: @[[STR3_GLOBAL:.*]] = private constant [2 x i8] zeroinitializer // OGCG: @[[STR1_GLOBAL:.*]] = private unnamed_addr constant [2 x i8] c"1\00" // OGCG: @[[STR2_GLOBAL:.*]] = private unnamed_addr constant [1 x i8] zeroinitializer diff --git a/clang/test/CIR/CodeGen/string-literals.cpp b/clang/test/CIR/CodeGen/string-literals.cpp index 081c4c2..1411567 100644 --- a/clang/test/CIR/CodeGen/string-literals.cpp +++ b/clang/test/CIR/CodeGen/string-literals.cpp @@ -5,11 +5,37 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s -// CIR: cir.global "private" cir_private dso_local @[[STR1_GLOBAL:.*]] = #cir.const_array<"abcd\00" : !cir.array<!s8i x 5>> : !cir.array<!s8i x 5> -// LLVM: @[[STR1_GLOBAL:.*]] = private global [5 x i8] c"abcd\00" +char const *array[] { + "my", "hands", "are", "typing", "words" +}; -// OGCG: @[[STR1_GLOBAL:.*]] = private unnamed_addr constant [5 x i8] c"abcd\00" +// CIR: cir.global "private" constant cir_private dso_local @"[[STR:.+]]" = #cir.const_array<"my\00" : !cir.array<!s8i x 3>> : !cir.array<!s8i x 3> +// CIR: cir.global "private" constant cir_private dso_local @"[[STR1:.+]]" = #cir.const_array<"hands\00" : !cir.array<!s8i x 6>> : !cir.array<!s8i x 6> +// CIR: cir.global "private" constant cir_private dso_local @"[[STR2:.+]]" = #cir.const_array<"are\00" : !cir.array<!s8i x 4>> : !cir.array<!s8i x 4> +// CIR: cir.global "private" constant cir_private dso_local @"[[STR3:.+]]" = #cir.const_array<"typing\00" : !cir.array<!s8i x 7>> : !cir.array<!s8i x 7> +// CIR: cir.global "private" constant cir_private dso_local @"[[STR4:.+]]" = #cir.const_array<"words\00" : !cir.array<!s8i x 6>> : !cir.array<!s8i x 6> +// CIR: cir.global external @array = #cir.const_array<[#cir.global_view<@"[[STR]]"> : !cir.ptr<!s8i>, #cir.global_view<@"[[STR1]]"> : !cir.ptr<!s8i>, #cir.global_view<@"[[STR2]]"> : !cir.ptr<!s8i>, #cir.global_view<@"[[STR3]]"> : !cir.ptr<!s8i>, #cir.global_view<@"[[STR4]]"> : !cir.ptr<!s8i>]> : !cir.array<!cir.ptr<!s8i> x 5> + +// LLVM: @[[STR:.+]] = private constant [3 x i8] c"my\00" +// LLVM: @[[STR1:.+]] = private constant [6 x i8] c"hands\00" +// LLVM: @[[STR2:.+]] = private constant [4 x i8] c"are\00" +// LLVM: @[[STR3:.+]] = private constant [7 x i8] c"typing\00" +// LLVM: @[[STR4:.+]] = private constant [6 x i8] c"words\00" +// LLVM: @array = global [5 x ptr] [ptr @[[STR]], ptr @[[STR1]], ptr @[[STR2]], ptr @[[STR3]], ptr @[[STR4]]] + +// OGCG: @[[STR:.+]] = private unnamed_addr constant [3 x i8] c"my\00" +// OGCG: @[[STR1:.+]] = private unnamed_addr constant [6 x i8] c"hands\00" +// OGCG: @[[STR2:.+]] = private unnamed_addr constant [4 x i8] c"are\00" +// OGCG: @[[STR3:.+]] = private unnamed_addr constant [7 x i8] c"typing\00" +// OGCG: @[[STR4:.+]] = private unnamed_addr constant [6 x i8] c"words\00" +// OGCG: @array = global [5 x ptr] [ptr @[[STR]], ptr @[[STR1]], ptr @[[STR2]], ptr @[[STR3]], ptr @[[STR4]]] + +// CIR: cir.global "private" constant cir_private dso_local @[[STR5_GLOBAL:.*]] = #cir.const_array<"abcd\00" : !cir.array<!s8i x 5>> : !cir.array<!s8i x 5> + +// LLVM: @[[STR5_GLOBAL:.*]] = private constant [5 x i8] c"abcd\00" + +// OGCG: @[[STR5_GLOBAL:.*]] = private unnamed_addr constant [5 x i8] c"abcd\00" decltype(auto) returns_literal() { return "abcd"; @@ -17,7 +43,7 @@ decltype(auto) returns_literal() { // CIR: cir.func{{.*}} @_Z15returns_literalv() -> !cir.ptr<!cir.array<!s8i x 5>> // CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.ptr<!cir.array<!s8i x 5>>, !cir.ptr<!cir.ptr<!cir.array<!s8i x 5>>>, ["__retval"] -// CIR: %[[STR_ADDR:.*]] = cir.get_global @[[STR1_GLOBAL]] : !cir.ptr<!cir.array<!s8i x 5>> +// CIR: %[[STR_ADDR:.*]] = cir.get_global @[[STR5_GLOBAL]] : !cir.ptr<!cir.array<!s8i x 5>> // CIR: cir.store{{.*}} %[[STR_ADDR]], %[[RET_ADDR]] // CIR: %[[RET:.*]] = cir.load %[[RET_ADDR]] // CIR: cir.return %[[RET]] diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp new file mode 100644 index 0000000..0122f30 --- /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/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c new file mode 100644 index 0000000..e9c4acb --- /dev/null +++ b/clang/test/CIR/CodeGen/var_arg.c @@ -0,0 +1,166 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// CIR: !rec___va_list_tag = !cir.record<struct "__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>} +// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr } +// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr } + +int varargs(int count, ...) { + __builtin_va_list args; + __builtin_va_start(args, count); + int res = __builtin_va_arg(args, int); + __builtin_va_end(args); + return res; +} + +// CIR-LABEL: cir.func dso_local @varargs( +// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init] +// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[VA_PTR0:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[COUNT_VAL:.+]] = cir.load{{.*}} %[[COUNT_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.va_start %[[VA_PTR0]] %[[COUNT_VAL]] : !cir.ptr<!rec___va_list_tag>, !s32i +// CIR: %[[VA_PTR1:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i +// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[VA_PTR2:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag> +// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RETVAL]] : !s32i + +// LLVM-LABEL: define dso_local i32 @varargs( +// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}} +// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]]) +// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32 +// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}} +// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]]) +// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}} +// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}} +// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}} +// LLVM: ret i32 %[[RETVAL]] + +// OGCG-LABEL: define dso_local i32 @varargs +// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 +// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag] +// OGCG: %[[RES_ADDR:.+]] = alloca i32 +// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]]) +// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0 +// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]] +// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40 +// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem +// +// OGCG: vaarg.in_reg: +// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3 +// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]] +// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.in_mem: +// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2 +// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.end: +// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ] +// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]] +// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]] +// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]] +// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]]) +// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]] +// OGCG: ret i32 %[[VAL]] + +int stdarg_start(int count, ...) { + __builtin_va_list args; + __builtin_stdarg_start(args, 12345); + int res = __builtin_va_arg(args, int); + __builtin_va_end(args); + return res; +} + +// CIR-LABEL: cir.func dso_local @stdarg_start( +// CIR: %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", init] +// CIR: %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] +// CIR: %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, !cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"] +// CIR: %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init] +// CIR: cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[VA_PTR0:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i +// CIR: cir.va_start %[[VA_PTR0]] %[[C12345]] : !cir.ptr<!rec___va_list_tag>, !s32i +// CIR: %[[VA_PTR1:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR1]] : (!cir.ptr<!rec___va_list_tag>) -> !s32i +// CIR: cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[VA_PTR2:.+]] = cir.cast(array_to_ptrdecay, %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>), !cir.ptr<!rec___va_list_tag> +// CIR: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag> +// CIR: %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.return %[[RETVAL]] : !s32i + +// LLVM-LABEL: define dso_local i32 @stdarg_start( +// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}} +// LLVM: %[[RES_ADDR:.+]] = alloca i32{{.*}} +// LLVM: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]]) +// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32 +// LLVM: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}} +// LLVM: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0 +// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR2]]) +// LLVM: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}} +// LLVM: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}} +// LLVM: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}} +// LLVM: ret i32 %[[RETVAL]] + +// OGCG-LABEL: define dso_local i32 @stdarg_start +// OGCG: %[[COUNT_ADDR:.+]] = alloca i32 +// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag] +// OGCG: %[[RES_ADDR:.+]] = alloca i32 +// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]]) +// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 0 +// OGCG: %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]] +// OGCG: %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40 +// OGCG: br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem +// +// OGCG: vaarg.in_reg: +// OGCG: %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3 +// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]] +// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]] +// OGCG: %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8 +// OGCG: store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.in_mem: +// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2 +// OGCG: %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]] +// OGCG: %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8 +// OGCG: store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]] +// OGCG: br label %vaarg.end +// +// OGCG: vaarg.end: +// OGCG: %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ %[[OVERFLOW]], %vaarg.in_mem ] +// OGCG: %[[LOADED:.+]] = load i32, ptr %[[PHI]] +// OGCG: store i32 %[[LOADED]], ptr %[[RES_ADDR]] +// OGCG: %[[DECAY2:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0 +// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]]) +// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]] +// OGCG: ret i32 %[[VAL]] diff --git a/clang/test/CIR/CodeGen/vbase.cpp b/clang/test/CIR/CodeGen/vbase.cpp new file mode 100644 index 0000000..1d1b5e0 --- /dev/null +++ b/clang/test/CIR/CodeGen/vbase.cpp @@ -0,0 +1,70 @@ +// 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 + +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 A +// CIR: cir.func comdat linkonce_odr @_ZN1AC2Ev(%arg0: !cir.ptr<!rec_A> +// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["this", init] +// CIR: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>> +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> +// CIR: cir.return + +// LLVM: define{{.*}} void @_ZN1AC2Ev(ptr %[[THIS_ARG:.*]]) { +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: ret void + +// Note: OGCG elides the constructor for A. This is not yet implemented in CIR. + +// 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: cir.call @_ZN1AC2Ev(%[[BASE_A_ADDR]]) nothrow : (!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: call void @_ZN1AC2Ev(ptr %[[BASE_A_ADDR]]) +// 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/virtual-function-calls.cpp b/clang/test/CIR/CodeGen/virtual-function-calls.cpp index 3e03b32..e68b38f 100644 --- a/clang/test/CIR/CodeGen/virtual-function-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-function-calls.cpp @@ -1,13 +1,81 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG struct A { + A(); virtual void f(char); }; -// This is just here to force the class definition to be emitted without -// requiring any other support. It will be removed when more complete -// vtable support is implemented. -A *a; +// This should initialize the vtable pointer. +A::A() {} // CIR: !rec_A = !cir.record<struct "A" {!cir.vptr}> +// CIR: !rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 3>}> + +// CIR: cir.global "private" external @_ZTV1A : !rec_anon_struct + +// LLVM: @_ZTV1A = external global { [3 x ptr] } + +// OGCG: @_ZTV1A = external unnamed_addr constant { [3 x ptr] } + +// CIR: cir.func{{.*}} @_ZN1AC2Ev(%arg0: !cir.ptr<!rec_A> {{.*}}) +// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["this", init] +// CIR: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>> +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> +// CIR: %[[VPTR:.*]] = cir.vtable.address_point(@_ZTV1A, address_point = <index = 0, offset = 2>) : !cir.vptr +// CIR: %[[THIS_VPTR_PTR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr> +// CIR: cir.store{{.*}} align(8) %[[VPTR]], %[[THIS_VPTR_PTR]] : !cir.vptr, !cir.ptr<!cir.vptr> +// CIR: cir.return + +// LLVM: define{{.*}} void @_ZN1AC2Ev(ptr %[[ARG0:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1A, i64 16), ptr %[[THIS]] + +// OGCG: define{{.*}} void @_ZN1AC2Ev(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], 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]] + +// NOTE: The GEP in OGCG looks very different from the one generated with CIR, +// but it is equivalent. The OGCG GEP indexes by base pointer, then +// structure, then array, whereas the CIR GEP indexes by byte offset. + +void f1(A *a) { + a->f('c'); +} + +// CIR: cir.func{{.*}} @_Z2f1P1A(%arg0: !cir.ptr<!rec_A> {{.*}}) +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A> +// CIR: cir.store %arg0, %[[A_ADDR]] +// CIR: %[[A:.*]] = cir.load{{.*}} %[[A_ADDR]] +// CIR: %[[C_LITERAL:.*]] = cir.const #cir.int<99> : !s8i +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[A]] : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr> +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr +// CIR: %[[FN_PTR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_A>, !s8i)>>> +// CIR: %[[FN_PTR:.*]] = cir.load{{.*}} %[[FN_PTR_PTR:.*]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_A>, !s8i)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_A>, !s8i)>> +// CIR: cir.call %[[FN_PTR]](%[[A]], %[[C_LITERAL]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_A>, !s8i)>>, !cir.ptr<!rec_A>, !s8i) -> () + +// LLVM: define{{.*}} void @_Z2f1P1A(ptr %[[ARG0:.*]]) +// LLVM: %[[A_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[A_ADDR]] +// LLVM: %[[A:.*]] = load ptr, ptr %[[A_ADDR]] +// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[A]] +// LLVM: %[[FN_PTR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0 +// LLVM: %[[FN_PTR:.*]] = load ptr, ptr %[[FN_PTR_PTR]] +// LLVM: call void %[[FN_PTR]](ptr %[[A]], i8 99) + +// OGCG: define{{.*}} void @_Z2f1P1A(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: %[[A_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], ptr %[[A_ADDR]] +// OGCG: %[[A:.*]] = load ptr, ptr %[[A_ADDR]] +// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[A]] +// OGCG: %[[FN_PTR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0 +// OGCG: %[[FN_PTR:.*]] = load ptr, ptr %[[FN_PTR_PTR]] +// OGCG: call void %[[FN_PTR]](ptr {{.*}} %[[A]], i8 {{.*}} 99) diff --git a/clang/test/CIR/CodeGen/vtable-emission.cpp b/clang/test/CIR/CodeGen/vtable-emission.cpp new file mode 100644 index 0000000..9a34573 --- /dev/null +++ b/clang/test/CIR/CodeGen/vtable-emission.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -fclangir -emit-llvm -o %t-cir.ll %s +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -emit-llvm -o %t.ll %s +// 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. + +struct S { + virtual void key(); + virtual void nonKey() {} +}; + +void S::key() {} + +// CHECK-DAG: !rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}> + +// The definition of the key function should result in the vtable being emitted. +// CHECK: cir.global "private" external @_ZTV1S = #cir.vtable<{ +// CHECK-SAME: #cir.const_array<[ +// CHECK-SAME: #cir.ptr<null> : !cir.ptr<!u8i>, +// CHECK-SAME: #cir.ptr<null> : !cir.ptr<!u8i>, +// CHECK-SAME: #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, +// CHECK-SAME: #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> +// CHECK-SAME: : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct + +// LLVM: @_ZTV1S = global { [4 x ptr] } { [4 x ptr] +// LLVM-SAME: [ptr null, ptr null, ptr @_ZN1S3keyEv, ptr @_ZN1S6nonKeyEv] } + +// OGCG: @_ZTV1S = unnamed_addr constant { [4 x ptr] } { [4 x ptr] +// OGCG-SAME: [ptr null, ptr null, ptr @_ZN1S3keyEv, ptr @_ZN1S6nonKeyEv] } + +// CHECK: cir.func dso_local @_ZN1S3keyEv + +// The reference from the vtable should result in nonKey being emitted. +// CHECK: cir.func comdat linkonce_odr @_ZN1S6nonKeyEv diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp new file mode 100644 index 0000000..631aab4 --- /dev/null +++ b/clang/test/CIR/CodeGen/vtt.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// 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; + virtual void y() {} +}; + +// This is just here to force the record types to be emitted. +void f(D *d) {} + +// 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_D = !cir.record<class "D" {!rec_B2Ebase, !rec_C2Ebase, !s64i, !rec_A2Ebase}> + +// Nothing interesting to see here yet. +// LLVM: define{{.*}} void @_Z1fP1D +// OGCG: define{{.*}} void @_Z1fP1D |