https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/148857
>From 8d328786bdfc80f348fd6c4159ac54c343a28ae9 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Tue, 15 Jul 2025 16:16:34 +0200 Subject: [PATCH 1/2] [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 >From 9edd9e0e7494b92ab8cf0fcd16cf5bc14156f055 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Tue, 15 Jul 2025 17:02:37 +0200 Subject: [PATCH 2/2] Address code review comments --- .../Dialect/Transforms/LoweringPrepare.cpp | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 788817006baa5..c708cf9d9fa61 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -23,13 +23,13 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { LoweringPreparePass() = default; void runOnOperation() override; - void runOnOp(Operation *op); - void lowerUnaryOp(UnaryOp op); + void runOnOp(mlir::Operation *op); + void lowerUnaryOp(cir::UnaryOp op); }; } // namespace -void LoweringPreparePass::lowerUnaryOp(UnaryOp op) { +void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { mlir::Type ty = op.getType(); if (!mlir::isa<cir::ComplexType>(ty)) return; @@ -65,28 +65,27 @@ void LoweringPreparePass::lowerUnaryOp(UnaryOp op) { break; } - auto result = builder.createComplexCreate(loc, resultReal, resultImag); + mlir::Value result = builder.createComplexCreate(loc, resultReal, resultImag); op.replaceAllUsesWith(result); op.erase(); } -void LoweringPreparePass::runOnOp(Operation *op) { - if (auto unary = dyn_cast<UnaryOp>(op)) { +void LoweringPreparePass::runOnOp(mlir::Operation *op) { + if (auto unary = dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); - } } void LoweringPreparePass::runOnOperation() { mlir::Operation *op = getOperation(); - llvm::SmallVector<Operation *> opsToTransform; + llvm::SmallVector<mlir::Operation *> opsToTransform; - op->walk([&](Operation *op) { - if (isa<UnaryOp>(op)) + op->walk([&](mlir::Operation *op) { + if (mlir::isa<cir::UnaryOp>(op)) opsToTransform.push_back(op); }); - for (auto *o : opsToTransform) + for (mlir::Operation *o : opsToTransform) runOnOp(o); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits