https://github.com/AmrDeveloper created https://github.com/llvm/llvm-project/pull/184006
Fix Codegen for emitting comparisons between Complex & Scalar >From cd917013ae95b39df49612b2778c0c4fda2994fc Mon Sep 17 00:00:00 2001 From: Amr Hesham <[email protected]> Date: Sun, 1 Mar 2026 14:02:07 +0100 Subject: [PATCH] [CIR] Fix Codegen for Complex & Scalar comparisons --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 15 +- clang/test/CIR/CodeGen/complex.cpp | 192 +++++++++++++++++++++ 2 files changed, 205 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 03c8369753f35..1276ef2611e51 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1204,9 +1204,20 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { } else { // Complex Comparison: can only be an equality comparison. assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE); - BinOpInfo boInfo = emitBinOps(e); - result = cir::CmpOp::create(builder, loc, kind, boInfo.lhs, boInfo.rhs); + mlir::Value lhs = boInfo.lhs; + if (!mlir::isa<cir::ComplexType>(lhs.getType())) { + lhs = builder.createComplexCreate( + loc, lhs, builder.getNullValue(lhs.getType(), loc)); + } + + mlir::Value rhs = boInfo.rhs; + if (!mlir::isa<cir::ComplexType>(rhs.getType())) { + rhs = builder.createComplexCreate( + loc, rhs, builder.getNullValue(rhs.getType(), loc)); + } + + result = builder.createCompare(loc, kind, lhs, rhs); } return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(), diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 734dddc4848b9..9881b15f93621 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1675,3 +1675,195 @@ void load_store_volatile_2() { // OGCG: %[[DV_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[DV_ADDR]], i32 0, i32 1 // OGCG: store volatile i32 %[[D_REAL]], ptr %[[DV_REAL_PTR]], align 4 // OGCG: store volatile i32 %[[D_IMAG]], ptr %[[DV_IMAG_PTR]], align 4 + +bool eq_float_complex_and_float(float _Complex a, float b) { + return a == b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["__retval"] +// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: cir.store %[[ARG_1:.*]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// 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.float>, !cir.float +// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float +// CIR: %[[COMPLEX_B:.*]] = cir.complex.create %[[TMP_B]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float> +// CIR: %[[RESULT:.*]] = cir.cmp(eq, %[[TMP_A]], %[[COMPLEX_B]]) : !cir.complex<!cir.float>, !cir.bool +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !cir.bool, !cir.ptr<!cir.bool> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float } +// LLVM: %[[B_ADDR:.*]] = alloca float +// LLVM: %[[RET_ADDR:.*]] = alloca i8 +// LLVM: store { float, float } %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// LLVM: store float %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_COMPLEX_B:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_B]], 0 +// LLVM: %[[COMPLEX_B:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_B]], float 0.000000e+00, 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[COMPLEX_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[COMPLEX_B]], 1 +// LLVM: %[[REAL_CMP:.*]] = fcmp oeq float %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[IMAG_CMP:.*]] = fcmp oeq float %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = and i1 %[[REAL_CMP]], %[[IMAG_CMP]] +// LLVM: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8 +// LLVM: store i8 %[[RESULT_I8]], ptr %[[RET_ADDR]], align 1 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: store <2 x float> %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// OGCG: store float %[[ARG_1:.*]], 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: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// OGCG: %[[REAL_CMP:.*]] = fcmp oeq float %[[A_REAL]], %[[TMP_B]] +// OGCG: %[[IMAG_CMP:.*]] = fcmp oeq float %[[A_IMAG]], 0.000000e+00 +// OGCG: %[[RESULT:.*]] = and i1 %[[REAL_CMP]], %[[IMAG_CMP]] + +bool eq_float_and_float_complex(float a, float _Complex b) { + return a == b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["__retval"] +// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// CIR: cir.store %[[ARG_1:.*]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float +// CIR: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float> +// CIR: %[[RESULT:.*]] = cir.cmp(eq, %[[COMPLEX_A]], %[[TMP_B]]) : !cir.complex<!cir.float>, !cir.bool +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !cir.bool, !cir.ptr<!cir.bool> + +// LLVM: %[[A_ADDR:.*]] = alloca float +// LLVM: %[[B_ADDR:.*]] = alloca { float, float } +// LLVM: %[[RET_ADDR:.*]] = alloca i8 +// LLVM: store float %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// LLVM: store { float, float } %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_COMPLEX_A:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_A]], 0 +// LLVM: %[[COMPLEX_A:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_A]], float 0.000000e+00, 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[COMPLEX_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[COMPLEX_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM: %[[REAL_CMP:.*]] = fcmp oeq float %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[IMAG_CMP:.*]] = fcmp oeq float %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = and i1 %[[REAL_CMP]], %[[IMAG_CMP]] +// LLVM: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8 +// LLVM: store i8 %[[RESULT_I8]], ptr %[[RET_ADDR]], align 1 + +// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[A_ADDR:.*]] = alloca float, align 4 +// OGCG: store <2 x float> %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// OGCG: store float %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// OGCG: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], 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: %[[REAL_CMP:.*]] = fcmp oeq float %[[TMP_A]], %[[B_REAL]] +// OGCG: %[[IMAG_CMP:.*]] = fcmp oeq float 0.000000e+00, %[[B_IMAG]] +// OGCG: %[[RESULT:.*]] = and i1 %[[REAL_CMP]], %[[IMAG_CMP]] + +bool ne_float_complex_and_float(float _Complex a, float b) { + return a != b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["__retval"] +// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: cir.store %[[ARG_1:.*]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// 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.float>, !cir.float +// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float +// CIR: %[[COMPLEX_B:.*]] = cir.complex.create %[[TMP_B]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float> +// CIR: %[[RESULT:.*]] = cir.cmp(ne, %[[TMP_A]], %[[COMPLEX_B]]) : !cir.complex<!cir.float>, !cir.bool +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !cir.bool, !cir.ptr<!cir.bool> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float } +// LLVM: %[[B_ADDR:.*]] = alloca float +// LLVM: %[[RET_ADDR:.*]] = alloca i8 +// LLVM: store { float, float } %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// LLVM: store float %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_COMPLEX_B:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_B]], 0 +// LLVM: %[[COMPLEX_B:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_B]], float 0.000000e+00, 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[COMPLEX_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[COMPLEX_B]], 1 +// LLVM: %[[REAL_CMP:.*]] = fcmp une float %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[IMAG_CMP:.*]] = fcmp une float %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = or i1 %[[REAL_CMP]], %[[IMAG_CMP]] +// LLVM: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8 +// LLVM: store i8 %[[RESULT_I8]], ptr %[[RET_ADDR]], align 1 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: store <2 x float> %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// OGCG: store float %[[ARG_1:.*]], 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: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4 +// OGCG: %[[REAL_CMP:.*]] = fcmp une float %[[A_REAL]], %[[TMP_B]] +// OGCG: %[[IMAG_CMP:.*]] = fcmp une float %[[A_IMAG]], 0.000000e+00 +// OGCG: %[[RESULT:.*]] = or i1 %[[REAL_CMP]], %[[IMAG_CMP]] + +bool ne_float_and_float_complex(float a, float _Complex b) { + return a != b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init] +// CIR: %[[RET_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["__retval"] +// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// CIR: cir.store %[[ARG_1:.*]], %[[B_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float +// CIR: %[[COMPLEX_A:.*]] = cir.complex.create %[[TMP_A]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float> +// CIR: %[[RESULT:.*]] = cir.cmp(ne, %[[COMPLEX_A]], %[[TMP_B]]) : !cir.complex<!cir.float>, !cir.bool +// CIR: cir.store %[[RESULT]], %[[RET_ADDR]] : !cir.bool, !cir.ptr<!cir.bool> + +// LLVM: %[[A_ADDR:.*]] = alloca float +// LLVM: %[[B_ADDR:.*]] = alloca { float, float } +// LLVM: %[[RET_ADDR:.*]] = alloca i8 +// LLVM: store float %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// LLVM: store { float, float } %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4 +// LLVM: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM: %[[TMP_COMPLEX_A:.*]] = insertvalue { float, float } {{.*}}, float %[[TMP_A]], 0 +// LLVM: %[[COMPLEX_A:.*]] = insertvalue { float, float } %[[TMP_COMPLEX_A]], float 0.000000e+00, 1 +// LLVM: %[[A_REAL:.*]] = extractvalue { float, float } %[[COMPLEX_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[COMPLEX_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM: %[[REAL_CMP:.*]] = fcmp une float %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[IMAG_CMP:.*]] = fcmp une float %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = or i1 %[[REAL_CMP]], %[[IMAG_CMP]] +// LLVM: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8 +// LLVM: store i8 %[[RESULT_I8]], ptr %[[RET_ADDR]], align 1 + +// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[A_ADDR:.*]] = alloca float, align 4 +// OGCG: store <2 x float> %[[ARG_1:.*]], ptr %[[B_ADDR]], align 4 +// OGCG: store float %[[ARG_0:.*]], ptr %[[A_ADDR]], align 4 +// OGCG: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], 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: %[[REAL_CMP:.*]] = fcmp une float %[[TMP_A]], %[[B_REAL]] +// OGCG: %[[IMAG_CMP:.*]] = fcmp une float 0.000000e+00, %[[B_IMAG]] +// OGCG: %[[RESULT:.*]] = or i1 %[[REAL_CMP]], %[[IMAG_CMP]] _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
