[clang] [CIR] Fix Codegen for Comparison of Complex bin ops (PR #185316)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 8 13:19:00 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Amr Hesham (AmrDeveloper)
<details>
<summary>Changes</summary>
Fix Codegen for Comparison between two Complex bin ops
---
Full diff: https://github.com/llvm/llvm-project/pull/185316.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+17-11)
- (modified) clang/test/CIR/CodeGen/complex.cpp (+84-4)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 1b5ba5ee6783f..4a2973d3824ee 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1196,19 +1196,25 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
result = builder.createCompare(loc, kind, lhs, rhs);
}
} else {
- // Complex Comparison: can only be an equality comparison.
- assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
- BinOpInfo boInfo = emitBinOps(e);
- mlir::Value lhs = boInfo.lhs;
- if (!lhsTy->isAnyComplexType()) {
- lhs = builder.createComplexCreate(
- loc, lhs, builder.getNullValue(lhs.getType(), loc));
+ assert((e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE) &&
+ "Complex Comparison: can only be an equality comparison");
+
+ mlir::Value lhs;
+ if (lhsTy->isAnyComplexType()) {
+ lhs = cgf.emitComplexExpr(e->getLHS());
+ } else {
+ mlir::Value lhsReal = Visit(e->getLHS());
+ mlir::Value lhsImag = builder.getNullValue(convertType(lhsTy), loc);
+ lhs = builder.createComplexCreate(loc, lhsReal, lhsImag);
}
- mlir::Value rhs = boInfo.rhs;
- if (!rhsTy->isAnyComplexType()) {
- rhs = builder.createComplexCreate(
- loc, rhs, builder.getNullValue(rhs.getType(), loc));
+ mlir::Value rhs;
+ if (rhsTy->isAnyComplexType()) {
+ rhs = cgf.emitComplexExpr(e->getRHS());
+ } else {
+ mlir::Value rhsReal = Visit(e->getRHS());
+ mlir::Value rhsImag = builder.getNullValue(convertType(rhsTy), loc);
+ rhs = builder.createComplexCreate(loc, rhsReal, rhsImag);
}
result = builder.createCompare(loc, kind, lhs, rhs);
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index 48b7dd72ae661..421ef6735db7d 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -1734,9 +1734,9 @@ bool eq_float_and_float_complex(float a, float _Complex b) {
// 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: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!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>
@@ -1746,9 +1746,9 @@ bool eq_float_and_float_complex(float a, float _Complex b) {
// 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: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
// 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
@@ -1830,9 +1830,9 @@ bool ne_float_and_float_complex(float a, float _Complex b) {
// 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: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!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>
@@ -1842,9 +1842,9 @@ bool ne_float_and_float_complex(float a, float _Complex b) {
// 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: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4
// 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
@@ -1867,3 +1867,83 @@ bool ne_float_and_float_complex(float a, float _Complex b) {
// 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]]
+
+void compare_two_complex_bin_ops() {
+ double _Complex a;
+ double _Complex b;
+ bool c = a + b != b + a;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["b"]
+// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["c", init]
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[COMPLEX_AB:.*]] = cir.complex.add %[[TMP_A]], %[[TMP_B]] : !cir.complex<!cir.double>
+// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[COMPLEX_BA:.*]] = cir.complex.add %[[TMP_B]], %[[TMP_A]] : !cir.complex<!cir.double>
+// CIR: %[[RESULT:.*]] = cir.cmp(ne, %[[COMPLEX_AB]], %[[COMPLEX_BA]]) : !cir.complex<!cir.double>, !cir.bool
+// CIR: cir.store {{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: %[[B_ADDR:.*]] = alloca { double, double }, i64 1, align 8
+// LLVM: %[[C_ADDR:.*]] = alloca i8, i64 1, align 1
+// LLVM: %[[TMP_A:.*]] = load { double, double }, ptr %[[A_ADDR]], align 8
+// LLVM: %[[TMP_B:.*]] = load { double, double }, ptr %[[B_ADDR]], align 8
+// LLVM: %[[A_REAL:.*]] = extractvalue { double, double } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { double, double } %[[TMP_A]], 1
+// LLVM: %[[B_REAL:.*]] = extractvalue { double, double } %[[TMP_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { double, double } %[[TMP_B]], 1
+// LLVM: %[[ADD_AB_REAL:.*]] = fadd double %[[A_REAL]], %[[B_REAL]]
+// LLVM: %[[ADD_AB_IMAG:.*]] = fadd double %[[A_IMAG]], %[[B_IMAG]]
+// LLVM: %[[TMP_COMPLEX_AB:.*]] = insertvalue { double, double } poison, double %[[ADD_AB_REAL]], 0
+// LLVM: %[[COMPLEX_AB:.*]] = insertvalue { double, double } %[[TMP_COMPLEX_AB]], double %[[ADD_AB_IMAG]], 1
+// LLVM: %[[TMP_B:.*]] = load { double, double }, ptr %[[B_ADDR]], align 8
+// LLVM: %[[TMP_A:.*]] = load { double, double }, ptr %[[A_ADDR]], align 8
+// LLVM: %[[B_REAL:.*]] = extractvalue { double, double } %[[TMP_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { double, double } %[[TMP_B]], 1
+// LLVM: %[[A_REAL:.*]] = extractvalue { double, double } %[[TMP_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { double, double } %[[TMP_A]], 1
+// LLVM: %[[ADD_BA_REAL:.*]] = fadd double %[[B_REAL]], %[[A_REAL]]
+// LLVM: %[[ADD_BA_IMAG:.*]] = fadd double %[[B_IMAG]], %[[A_IMAG]]
+// LLVM: %[[TMP_COMPLEX_BA:.*]] = insertvalue { double, double } poison, double %[[ADD_BA_REAL]], 0
+// LLVM: %[[COMPLEX_BA:.*]] = insertvalue { double, double } %[[TMP_COMPLEX_BA]], double %[[ADD_BA_IMAG]], 1
+// LLVM: %[[AB_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_AB]], 0
+// LLVM: %[[AB_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_AB]], 1
+// LLVM: %[[BA_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_BA]], 0
+// LLVM: %[[BA_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_BA]], 1
+// LLVM: %[[CMP_NE_REAL:.*]] = fcmp une double %[[AB_REAL]], %[[BA_REAL]]
+// LLVM: %[[CMP_NE_IMAG:.*]] = fcmp une double %[[AB_IMAG]], %[[BA_IMAG]]
+// LLVM: %[[RESULT:.*]] = or i1 %[[CMP_NE_REAL]], %[[CMP_NE_IMAG]]
+// LLVM: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8
+// LLVM: store i8 %[[RESULT_I8]], ptr %[[C_ADDR]], align 1
+
+// OGCG: %[[A_ADDR:.*]] = alloca { double, double }, align 8
+// OGCG: %[[B_ADDR:.*]] = alloca { double, double }, align 8
+// OGCG: %[[C_ADDR:.*]] = alloca i8, align 1
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_REAL:.*]] = load double, ptr %[[B_REAL_PTR]], align 8
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load double, ptr %[[B_IMAG_PTR]], align 8
+// OGCG: %[[ADD_AB_REAL:.*]] = fadd double %[[A_REAL]], %[[B_REAL]]
+// OGCG: %[[ADD_AB_IMAG:.*]] = fadd double %[[A_IMAG]], %[[B_IMAG]]
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_REAL:.*]] = load double, ptr %[[B_REAL_PTR]], align 8
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load double, ptr %[[B_IMAG_PTR]], align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8
+// OGCG: %[[ADD_BA_REAL:.*]] = fadd double %[[B_REAL]], %[[A_REAL]]
+// OGCG: %[[ADD_BA_IMAG:.*]] = fadd double %[[B_IMAG]], %[[A_IMAG]]
+// OGCG: %[[CMP_NE_REAL:.*]] = fcmp une double %[[ADD_AB_REAL]], %[[ADD_BA_REAL]]
+// OGCG: %[[CMP_NE_IMAG:.*]] = fcmp une double %[[ADD_AB_IMAG]], %[[ADD_BA_IMAG]]
+// OGCG: %[[RESULT:.*]] = or i1 %[[CMP_NE_REAL]], %[[CMP_NE_IMAG]]
+// OGCG: %[[RESULT_I8:.*]] = zext i1 %[[RESULT]] to i8
+// OGCG: store i8 %[[RESULT_I8]], ptr %[[C_ADDR]], align 1
``````````
</details>
https://github.com/llvm/llvm-project/pull/185316
More information about the cfe-commits
mailing list