[clang] [CIR] Implement NotEqualOp for ComplexType (PR #146129)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 2 09:26:30 PDT 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/146129
>From f7c4d39602e7dda28f09a43fecc5b84c94c4c1bb Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 27 Jun 2025 20:10:48 +0200
Subject: [PATCH 1/6] [CIR] Implement NotEqualOp for ComplexType
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 25 +++++++
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 5 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 38 ++++++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++
clang/test/CIR/CodeGen/complex.cpp | 73 +++++++++++++++++++
5 files changed, 148 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4d3ebfb93615d..780da23b08cad 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2481,6 +2481,31 @@ def ComplexEqualOp : CIR_Op<"complex.eq", [Pure, SameTypeOperands]> {
}];
}
+//===----------------------------------------------------------------------===//
+// ComplexNotEqualOp
+//===----------------------------------------------------------------------===//
+
+def ComplexNotEqualOp : CIR_Op<"complex.neq", [Pure, SameTypeOperands]> {
+
+ let summary = "Computes whether two complex values are not equal";
+ let description = [{
+ The `complex.equal` op takes two complex numbers and returns whether
+ they are not equal.
+
+ ```mlir
+ %r = cir.complex.neq %a, %b : !cir.complex<!cir.float>
+ ```
+ }];
+
+ let results = (outs CIR_BoolType:$result);
+ let arguments = (ins CIR_ComplexType:$lhs, CIR_ComplexType:$rhs);
+
+ let assemblyFormat = [{
+ $lhs `,` $rhs
+ `:` qualified(type($lhs)) attr-dict
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Assume Operations
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 6eeecca7e7c8f..b0e8921d72954 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -911,9 +911,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
result =
builder.create<cir::ComplexEqualOp>(loc, boInfo.lhs, boInfo.rhs);
} else {
- assert(!cir::MissingFeatures::complexType());
- cgf.cgm.errorNYI(loc, "complex not equal");
- result = builder.getBool(false, loc);
+ result =
+ builder.create<cir::ComplexNotEqualOp>(loc, boInfo.lhs, boInfo.rhs);
}
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1034b8780c03c..598283eeaf518 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1903,6 +1903,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMComplexCreateOpLowering,
CIRToLLVMComplexEqualOpLowering,
CIRToLLVMComplexImagOpLowering,
+ CIRToLLVMComplexNotEqualOpLowering,
CIRToLLVMComplexRealOpLowering,
CIRToLLVMConstantOpLowering,
CIRToLLVMExpectOpLowering,
@@ -2282,6 +2283,43 @@ mlir::LogicalResult CIRToLLVMComplexEqualOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMComplexNotEqualOpLowering::matchAndRewrite(
+ cir::ComplexNotEqualOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Value lhs = adaptor.getLhs();
+ mlir::Value rhs = adaptor.getRhs();
+
+ auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());
+ mlir::Type complexElemTy =
+ getTypeConverter()->convertType(complexType.getElementType());
+
+ mlir::Location loc = op.getLoc();
+ auto lhsReal =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
+ auto lhsImag =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
+ auto rhsReal =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
+ auto rhsImag =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
+
+ if (complexElemTy.isInteger()) {
+ auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp);
+ return mlir::success();
+ }
+
+ auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp);
+ return mlir::success();
+}
+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 25cf218cf8b6c..5cd1d09b88c00 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -473,6 +473,16 @@ class CIRToLLVMComplexEqualOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMComplexNotEqualOpLowering
+ : public mlir::OpConversionPattern<cir::ComplexNotEqualOp> {
+public:
+ using mlir::OpConversionPattern<cir::ComplexNotEqualOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ComplexNotEqualOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
} // namespace direct
} // namespace cir
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index e75ba5e92f99b..cc2a2b131a4ee 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -442,6 +442,79 @@ bool foo19(double _Complex a, double _Complex b) {
// OGCG: %[[CMP_IMAG:.*]] = fcmp oeq double %[[A_IMAG]], %[[B_IMAG]]
// OGCG: %[[RESULT:.*]] = and i1 %[[CMP_REAL]], %[[CMP_IMAG]]
+
+bool foo20(int _Complex a, int _Complex b) {
+ return a != b;
+}
+
+// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!s32i>
+
+// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
+// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
+// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 1
+// LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 1
+// LLVM: %[[CMP_REAL:.*]] = icmp ne i32 %[[A_REAL]], %[[B_REAL]]
+// LLVM: %[[CMP_IMAG:.*]] = icmp ne i32 %[[A_IMAG]], %[[B_IMAG]]
+// LLVM: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]]
+
+// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], 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 %[[COMPLEX_A]], 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 %[[COMPLEX_B]], 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 %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4
+// OGCG: %[[CMP_REAL:.*]] = icmp ne i32 %[[A_REAL]], %[[B_REAL]]
+// OGCG: %[[CMP_IMAG:.*]] = icmp ne i32 %[[A_IMAG]], %[[B_IMAG]]
+// OGCG: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]]
+
+bool foo21(double _Complex a, double _Complex b) {
+ return a != b;
+}
+
+// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
+// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!cir.double>
+
+// LLVM: %[[COMPLEX_A:.*]] = load { double, double }, ptr {{.*}}, align 8
+// LLVM: %[[COMPLEX_B:.*]] = load { double, double }, ptr {{.*}}, align 8
+// LLVM: %[[A_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_A]], 0
+// LLVM: %[[A_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_A]], 1
+// LLVM: %[[B_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_B]], 0
+// LLVM: %[[B_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_B]], 1
+// LLVM: %[[CMP_REAL:.*]] = fcmp une double %[[A_REAL]], %[[B_REAL]]
+// LLVM: %[[CMP_IMAG:.*]] = fcmp une double %[[A_IMAG]], %[[B_IMAG]]
+// LLVM: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]]
+
+// OGCG: %[[COMPLEX_A:.*]] = alloca { double, double }, align 8
+// OGCG: %[[COMPLEX_B:.*]] = alloca { double, double }, align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 0
+// OGCG: store double {{.*}}, ptr %[[A_REAL_PTR]], align 8
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 1
+// OGCG: store double {{.*}}, ptr %[[A_IMAG_PTR]], align 8
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 0
+// OGCG: store double {{.*}}, ptr %[[B_REAL_PTR]], align 8
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: store double {{.*}}, ptr %[[B_IMAG_PTR]], align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], 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 %[[COMPLEX_A]], 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 %[[COMPLEX_B]], 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 %[[COMPLEX_B]], i32 0, i32 1
+// OGCG: %[[B_IMAG:.*]] = load double, ptr %[[B_IMAG_PTR]], align 8
+// OGCG: %[[CMP_REAL:.*]] = fcmp une double %[[A_REAL]], %[[B_REAL]]
+// OGCG: %[[CMP_IMAG:.*]] = fcmp une double %[[A_IMAG]], %[[B_IMAG]]
+// OGCG: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]]
+
void foo22(int _Complex a, int _Complex b) {
int _Complex c = (a, b);
}
>From 0e3c592646a71b3316072feb62228c557bc72cd1 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 27 Jun 2025 20:51:02 +0200
Subject: [PATCH 2/6] Fix op description
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 780da23b08cad..026b947b33369 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2464,7 +2464,7 @@ def ComplexEqualOp : CIR_Op<"complex.eq", [Pure, SameTypeOperands]> {
let summary = "Computes whether two complex values are equal";
let description = [{
- The `complex.equal` op takes two complex numbers and returns whether
+ The `cir.complex.eq` op takes two complex numbers and returns whether
they are equal.
```mlir
@@ -2489,7 +2489,7 @@ def ComplexNotEqualOp : CIR_Op<"complex.neq", [Pure, SameTypeOperands]> {
let summary = "Computes whether two complex values are not equal";
let description = [{
- The `complex.equal` op takes two complex numbers and returns whether
+ The `cir.complex.neq` op takes two complex numbers and returns whether
they are not equal.
```mlir
>From e0d5478991342e10378b52f794dcd196e4035a9b Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Sat, 28 Jun 2025 09:22:59 +0200
Subject: [PATCH 3/6] Replace ComplexEqual and ComplexNotEqual by CmpOp
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 50 ------
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 10 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 147 ++++++++----------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 20 ---
clang/test/CIR/CodeGen/complex.cpp | 9 +-
5 files changed, 73 insertions(+), 163 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 026b947b33369..4afacab80957a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2456,56 +2456,6 @@ def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> {
let hasFolder = 1;
}
-//===----------------------------------------------------------------------===//
-// ComplexEqualOp
-//===----------------------------------------------------------------------===//
-
-def ComplexEqualOp : CIR_Op<"complex.eq", [Pure, SameTypeOperands]> {
-
- let summary = "Computes whether two complex values are equal";
- let description = [{
- The `cir.complex.eq` op takes two complex numbers and returns whether
- they are equal.
-
- ```mlir
- %r = cir.complex.eq %a, %b : !cir.complex<!cir.float>
- ```
- }];
-
- let results = (outs CIR_BoolType:$result);
- let arguments = (ins CIR_ComplexType:$lhs, CIR_ComplexType:$rhs);
-
- let assemblyFormat = [{
- $lhs `,` $rhs
- `:` qualified(type($lhs)) attr-dict
- }];
-}
-
-//===----------------------------------------------------------------------===//
-// ComplexNotEqualOp
-//===----------------------------------------------------------------------===//
-
-def ComplexNotEqualOp : CIR_Op<"complex.neq", [Pure, SameTypeOperands]> {
-
- let summary = "Computes whether two complex values are not equal";
- let description = [{
- The `cir.complex.neq` op takes two complex numbers and returns whether
- they are not equal.
-
- ```mlir
- %r = cir.complex.neq %a, %b : !cir.complex<!cir.float>
- ```
- }];
-
- let results = (outs CIR_BoolType:$result);
- let arguments = (ins CIR_ComplexType:$lhs, CIR_ComplexType:$rhs);
-
- let assemblyFormat = [{
- $lhs `,` $rhs
- `:` qualified(type($lhs)) attr-dict
- }];
-}
-
//===----------------------------------------------------------------------===//
// Assume Operations
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index b0e8921d72954..a03b136e98732 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -907,13 +907,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
BinOpInfo boInfo = emitBinOps(e);
- if (e->getOpcode() == BO_EQ) {
- result =
- builder.create<cir::ComplexEqualOp>(loc, boInfo.lhs, boInfo.rhs);
- } else {
- result =
- builder.create<cir::ComplexNotEqualOp>(loc, boInfo.lhs, boInfo.rhs);
- }
+ cir::CmpOpKind opKind =
+ e->getOpcode() == BO_EQ ? cir::CmpOpKind::eq : cir::CmpOpKind::ne;
+ result = builder.create<cir::CmpOp>(loc, opKind, boInfo.lhs, boInfo.rhs);
}
return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 598283eeaf518..bdc7492d48211 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1586,7 +1586,6 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::dataMemberType());
assert(!cir::MissingFeatures::methodType());
- // Lower to LLVM comparison op.
if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) {
bool isSigned = mlir::isa<cir::IntType>(type)
? mlir::cast<cir::IntType>(type).isSigned()
@@ -1595,22 +1594,82 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
convertCmpKindToICmpPredicate(cmpOp.getKind(), isSigned);
rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
- } else if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {
+ return mlir::success();
+ }
+
+ if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {
mlir::LLVM::ICmpPredicate kind =
convertCmpKindToICmpPredicate(cmpOp.getKind(),
/* isSigned=*/false);
rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
- } else if (mlir::isa<cir::FPTypeInterface>(type)) {
+ return mlir::success();
+ }
+
+ if (mlir::isa<cir::FPTypeInterface>(type)) {
mlir::LLVM::FCmpPredicate kind =
convertCmpKindToFCmpPredicate(cmpOp.getKind());
rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(
cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
- } else {
- return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
+ return mlir::success();
}
- return mlir::success();
+ if (mlir::isa<cir::ComplexType>(type)) {
+ mlir::Value lhs = adaptor.getLhs();
+ mlir::Value rhs = adaptor.getRhs();
+ mlir::Location loc = cmpOp.getLoc();
+
+ auto complexType = mlir::cast<cir::ComplexType>(cmpOp.getLhs().getType());
+ mlir::Type complexElemTy =
+ getTypeConverter()->convertType(complexType.getElementType());
+
+ auto lhsReal =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
+ auto lhsImag =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
+ auto rhsReal =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
+ auto rhsImag =
+ rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
+
+ if (cmpOp.getKind() == cir::CmpOpKind::eq) {
+ if (complexElemTy.isInteger()) {
+ auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::eq, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::eq, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);
+ return mlir::success();
+ }
+
+ auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::oeq, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::oeq, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);
+ return mlir::success();
+ }
+
+ if (cmpOp.getKind() == cir::CmpOpKind::ne) {
+ if (complexElemTy.isInteger()) {
+ auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
+ loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);
+ return mlir::success();
+ }
+
+ auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);
+ auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
+ loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);
+ return mlir::success();
+ }
+ }
+
+ return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
}
mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(
@@ -1901,9 +1960,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMCallOpLowering,
CIRToLLVMCmpOpLowering,
CIRToLLVMComplexCreateOpLowering,
- CIRToLLVMComplexEqualOpLowering,
CIRToLLVMComplexImagOpLowering,
- CIRToLLVMComplexNotEqualOpLowering,
CIRToLLVMComplexRealOpLowering,
CIRToLLVMConstantOpLowering,
CIRToLLVMExpectOpLowering,
@@ -2246,80 +2303,6 @@ mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(
return mlir::success();
}
-mlir::LogicalResult CIRToLLVMComplexEqualOpLowering::matchAndRewrite(
- cir::ComplexEqualOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- mlir::Value lhs = adaptor.getLhs();
- mlir::Value rhs = adaptor.getRhs();
-
- auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());
- mlir::Type complexElemTy =
- getTypeConverter()->convertType(complexType.getElementType());
-
- mlir::Location loc = op.getLoc();
- auto lhsReal =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
- auto lhsImag =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
- auto rhsReal =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
- auto rhsImag =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
-
- if (complexElemTy.isInteger()) {
- auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
- loc, mlir::LLVM::ICmpPredicate::eq, lhsReal, rhsReal);
- auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
- loc, mlir::LLVM::ICmpPredicate::eq, lhsImag, rhsImag);
- rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, realCmp, imagCmp);
- return mlir::success();
- }
-
- auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
- loc, mlir::LLVM::FCmpPredicate::oeq, lhsReal, rhsReal);
- auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
- loc, mlir::LLVM::FCmpPredicate::oeq, lhsImag, rhsImag);
- rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, realCmp, imagCmp);
- return mlir::success();
-}
-
-mlir::LogicalResult CIRToLLVMComplexNotEqualOpLowering::matchAndRewrite(
- cir::ComplexNotEqualOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- mlir::Value lhs = adaptor.getLhs();
- mlir::Value rhs = adaptor.getRhs();
-
- auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());
- mlir::Type complexElemTy =
- getTypeConverter()->convertType(complexType.getElementType());
-
- mlir::Location loc = op.getLoc();
- auto lhsReal =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
- auto lhsImag =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
- auto rhsReal =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
- auto rhsImag =
- rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
-
- if (complexElemTy.isInteger()) {
- auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
- loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);
- auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
- loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);
- rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp);
- return mlir::success();
- }
-
- auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
- loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);
- auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
- loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);
- rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp);
- return mlir::success();
-}
-
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 5cd1d09b88c00..8502cb1ae5d9f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -463,26 +463,6 @@ class CIRToLLVMComplexImagOpLowering
mlir::ConversionPatternRewriter &) const override;
};
-class CIRToLLVMComplexEqualOpLowering
- : public mlir::OpConversionPattern<cir::ComplexEqualOp> {
-public:
- using mlir::OpConversionPattern<cir::ComplexEqualOp>::OpConversionPattern;
-
- mlir::LogicalResult
- matchAndRewrite(cir::ComplexEqualOp op, OpAdaptor,
- mlir::ConversionPatternRewriter &) const override;
-};
-
-class CIRToLLVMComplexNotEqualOpLowering
- : public mlir::OpConversionPattern<cir::ComplexNotEqualOp> {
-public:
- using mlir::OpConversionPattern<cir::ComplexNotEqualOp>::OpConversionPattern;
-
- mlir::LogicalResult
- matchAndRewrite(cir::ComplexNotEqualOp op, OpAdaptor,
- mlir::ConversionPatternRewriter &) const override;
-};
-
} // namespace direct
} // namespace cir
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index cc2a2b131a4ee..78d7a2024490b 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -376,7 +376,7 @@ bool foo18(int _Complex a, int _Complex b) {
// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR: %[[RESULT:.*]] = cir.complex.eq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!s32i>
+// CIR: %[[RESULT:.*]] = cir.cmp(eq, %[[COMPLEX_A]], %[[COMPLEX_B]]) : !cir.complex<!s32i>, !cir.bool
// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
@@ -408,7 +408,8 @@ bool foo19(double _Complex a, double _Complex b) {
// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
-// CIR: %[[RESULT:.*]] = cir.complex.eq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!cir.double>
+// CIR: %[[RESULT:.*]] = cir.cmp(eq, %[[COMPLEX_A]], %[[COMPLEX_B]]) : !cir.complex<!cir.double>, !cir.bool
+
// LLVM: %[[COMPLEX_A:.*]] = load { double, double }, ptr {{.*}}, align 8
// LLVM: %[[COMPLEX_B:.*]] = load { double, double }, ptr {{.*}}, align 8
@@ -449,7 +450,7 @@ bool foo20(int _Complex a, int _Complex b) {
// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!s32i>
+// CIR: %[[RESULT:.*]] = cir.cmp(ne, %[[COMPLEX_A]], %[[COMPLEX_B]]) : !cir.complex<!s32i>, !cir.bool
// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
@@ -481,7 +482,7 @@ bool foo21(double _Complex a, double _Complex b) {
// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
-// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!cir.double>
+// CIR: %[[RESULT:.*]] = cir.cmp(ne, %[[COMPLEX_A]], %[[COMPLEX_B]]) : !cir.complex<!cir.double>, !cir.bool
// LLVM: %[[COMPLEX_A:.*]] = load { double, double }, ptr {{.*}}, align 8
// LLVM: %[[COMPLEX_B:.*]] = load { double, double }, ptr {{.*}}, align 8
>From 93f8f02f199a75f92d7c3bd08b91487348b6c6ff Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Sat, 28 Jun 2025 10:55:15 +0200
Subject: [PATCH 4/6] Remove unneeded check
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index a03b136e98732..b76b703a79fe8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -907,9 +907,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
assert(e->getOpcode() == BO_EQ || e->getOpcode() == BO_NE);
BinOpInfo boInfo = emitBinOps(e);
- cir::CmpOpKind opKind =
- e->getOpcode() == BO_EQ ? cir::CmpOpKind::eq : cir::CmpOpKind::ne;
- result = builder.create<cir::CmpOp>(loc, opKind, boInfo.lhs, boInfo.rhs);
+ result = builder.create<cir::CmpOp>(loc, kind, boInfo.lhs, boInfo.rhs);
}
return emitScalarConversion(result, cgf.getContext().BoolTy, e->getType(),
>From cd92e969bf52111f57d4f25273022b0f24f44204 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Mon, 30 Jun 2025 22:09:23 +0200
Subject: [PATCH 5/6] Add note in Cmp op about complex dialect
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4afacab80957a..ee4c378043ed7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1319,6 +1319,9 @@ def CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
`cir.bool` result. The kinds of comparison available are:
[lt,gt,ge,eq,ne]
+ Note: The 'complex' dialect has separate complex.eq and complex.neq
+ operations
+
```mlir
%7 = cir.cmp(gt, %1, %2) : i32, !cir.bool
```
>From 871b0d08c948131779ecbc657575f5d52b20056a Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Wed, 2 Jul 2025 18:03:34 +0200
Subject: [PATCH 6/6] Remove extra note in CmpOp
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index ee4c378043ed7..4afacab80957a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1319,9 +1319,6 @@ def CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
`cir.bool` result. The kinds of comparison available are:
[lt,gt,ge,eq,ne]
- Note: The 'complex' dialect has separate complex.eq and complex.neq
- operations
-
```mlir
%7 = cir.cmp(gt, %1, %2) : i32, !cir.bool
```
More information about the cfe-commits
mailing list