[clang] [CIR] Upstream unary not for ComplexType (PR #148857)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 15 07:22:58 PDT 2025
https://github.com/AmrDeveloper created https://github.com/llvm/llvm-project/pull/148857
Upstream unary not for ComplexType
https://github.com/llvm/llvm-project/issues/141365
>From 8d328786bdfc80f348fd6c4159ac54c343a28ae9 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Tue, 15 Jul 2025 16:16:34 +0200
Subject: [PATCH] [CIR] Upstream unary not for ComplexType
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 21 +++++++
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 16 ------
clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 6 ++
.../Dialect/Transforms/LoweringPrepare.cpp | 57 ++++++++++++++++++-
clang/test/CIR/CodeGen/complex-unary.cpp | 48 ++++++++++++++++
5 files changed, 131 insertions(+), 17 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/complex-unary.cpp
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 277c278fd38b7..25baf278bba38 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
+ mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
+ mlir::Value imag) {
+ auto resultComplexTy = cir::ComplexType::get(real.getType());
+ return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
+ }
+
+ mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
+ }
+
+ mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
+ }
+
mlir::Value createNot(mlir::Value value) {
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
cir::UnaryOpKind::Not, value);
@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::ContinueOp>(loc);
}
+ mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
+ mlir::Value operand) {
+ return create<cir::UnaryOp>(loc, kind, operand);
+ }
+
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5bd53ebc52ab5..f855bdad2d7c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);
}
- mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
- mlir::Value imag) {
- auto resultComplexTy = cir::ComplexType::get(real.getType());
- return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
- }
-
- mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
- }
-
- mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
- }
-
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
/// part of the complex value pointed to by the specified pointer value.
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 3273d9000771a..6663f5ea1e758 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
mlir::Value
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
mlir::Value VisitUnaryDeref(const Expr *e);
+ mlir::Value VisitUnaryNot(const UnaryOperator *e);
struct BinOpInfo {
mlir::Location loc;
@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {
return emitLoadOfLValue(e);
}
+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
+ mlir::Value op = Visit(e->getSubExpr());
+ return builder.createNot(op);
+}
+
mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
QualType promotionTy) {
e = e->IgnoreParens();
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5493b86a0a321..788817006baa5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,7 +8,9 @@
#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
#include <memory>
@@ -22,15 +24,68 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void runOnOperation() override;
void runOnOp(Operation *op);
+ void lowerUnaryOp(UnaryOp op);
};
} // namespace
-void LoweringPreparePass::runOnOp(Operation *op) {}
+void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {
+ mlir::Type ty = op.getType();
+ if (!mlir::isa<cir::ComplexType>(ty))
+ return;
+
+ mlir::Location loc = op.getLoc();
+ cir::UnaryOpKind opKind = op.getKind();
+
+ CIRBaseBuilderTy builder(getContext());
+ builder.setInsertionPointAfter(op);
+
+ mlir::Value operand = op.getInput();
+ mlir::Value operandReal = builder.createComplexReal(loc, operand);
+ mlir::Value operandImag = builder.createComplexImag(loc, operand);
+
+ mlir::Value resultReal;
+ mlir::Value resultImag;
+
+ switch (opKind) {
+ case cir::UnaryOpKind::Inc:
+ case cir::UnaryOpKind::Dec:
+ llvm_unreachable("Complex unary Inc/Dec NYI");
+ break;
+
+ case cir::UnaryOpKind::Plus:
+ case cir::UnaryOpKind::Minus:
+ llvm_unreachable("Complex unary Plus/Minus NYI");
+ break;
+
+ case cir::UnaryOpKind::Not:
+ resultReal = operandReal;
+ resultImag =
+ builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
+ break;
+ }
+
+ auto result = builder.createComplexCreate(loc, resultReal, resultImag);
+ op.replaceAllUsesWith(result);
+ op.erase();
+}
+
+void LoweringPreparePass::runOnOp(Operation *op) {
+ if (auto unary = dyn_cast<UnaryOp>(op)) {
+ lowerUnaryOp(unary);
+ }
+}
void LoweringPreparePass::runOnOperation() {
+ mlir::Operation *op = getOperation();
+
llvm::SmallVector<Operation *> opsToTransform;
+ op->walk([&](Operation *op) {
+ if (isa<UnaryOp>(op))
+ opsToTransform.push_back(op);
+ });
+
for (auto *o : opsToTransform)
runOnOp(o);
}
diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cpp
new file mode 100644
index 0000000000000..463c4dde47ed6
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-unary.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s
+// 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 foo() {
+ int _Complex a;
+ int _Complex b = ~a;
+}
+
+// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>
+// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i
+// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>
+// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4
+// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0
+// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1
+// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]
+// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0
+// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1
+// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4
+
+// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], 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]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1
+// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4
More information about the cfe-commits
mailing list