From 3f103e657d1d8c5fa1b4db0fc1a19ded479de7b6 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Mon, 24 Nov 2025 21:41:04 +0100 Subject: [PATCH] [CIR] Backport ComplexImagOp on scalar type --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 7 ++++--- clang/include/clang/CIR/Dialect/IR/CIROps.td | 10 ++++++---- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 4 ++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 10 +++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 ++++++++++++-- clang/test/CIR/CodeGen/complex.cpp | 20 +++++++++++++++++++ 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 638791894480..44142a7d4435 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -337,9 +337,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { } mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { - auto operandTy = mlir::cast(operand.getType()); - return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(), - operand); + auto resultType = operand.getType(); + if (auto complexResultType = mlir::dyn_cast(resultType)) + resultType = complexResultType.getElementType(); + return cir::ComplexImagOp::create(*this, loc, resultType, operand); } mlir::Value createComplexBinOp(mlir::Location loc, mlir::Value lhs, diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index f6d4ed5707d9..0c117bd6d636 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1539,18 +1539,20 @@ def CIR_ComplexRealOp : CIR_Op<"complex.real", [Pure]> { def CIR_ComplexImagOp : CIR_Op<"complex.imag", [Pure]> { let summary = "Extract the imaginary part of a complex value"; let description = [{ - `cir.complex.imag` operation takes an operand of `!cir.complex` type and - yields the imaginary part of it. + `cir.complex.imag` operation takes an operand of `!cir.complex`, `!cir.int` + or `!cir.float`. If the operand is `!cir.complex`, the imag part of it will + be returned, otherwise a zero value will be returned. Example: ```mlir - %1 = cir.complex.imag %0 : !cir.complex -> !cir.float + %imag = cir.complex.imag %complex : !cir.complex -> !cir.float + %imag = cir.complex.imag %scalar : !cir.float -> !cir.float ``` }]; let results = (outs CIR_AnyIntOrFloatType:$result); - let arguments = (ins CIR_ComplexType:$operand); + let arguments = (ins CIR_AnyComplexOrIntOrFloatType:$operand); let assemblyFormat = [{ $operand `:` qualified(type($operand)) `->` qualified(type($result)) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 081ac4f0adbe..8b85d07efd22 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2127,8 +2127,8 @@ mlir::Value ScalarExprEmitter::VisitImag(const UnaryOperator *E) { // TODO(cir): handle scalar promotion. Expr *Op = E->getSubExpr(); + mlir::Location Loc = CGF.getLoc(E->getExprLoc()); if (Op->getType()->isAnyComplexType()) { - mlir::Location Loc = CGF.getLoc(E->getExprLoc()); // If it's an l-value, load through the appropriate subobject l-value. // Note that we have to ask E because Op might be an l-value that @@ -2142,7 +2142,7 @@ mlir::Value ScalarExprEmitter::VisitImag(const UnaryOperator *E) { return Builder.createComplexImag(Loc, CGF.emitComplexExpr(Op)); } - return Visit(Op); + return Builder.createComplexImag(Loc, Visit(Op)); } // Conversion from bool, integral, or floating-point to integral or diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 7c637662955f..627691077da6 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -969,14 +969,22 @@ OpFoldResult cir::ComplexRealOp::fold(FoldAdaptor adaptor) { } LogicalResult cir::ComplexImagOp::verify() { - if (getType() != getOperand().getType().getElementType()) { + mlir::Type operandTy = getOperand().getType(); + if (auto complexOperandTy = mlir::dyn_cast(operandTy)) + operandTy = complexOperandTy.getElementType(); + + if (getType() != operandTy) { emitOpError() << ": result type does not match operand type"; return failure(); } + return success(); } OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) { + if (!mlir::isa(getOperand().getType())) + return nullptr; + if (auto complexCreateOp = getOperand().getDefiningOp()) return complexCreateOp.getOperand(1); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index d4b7e8ce1592..d2efc8075119 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2597,8 +2597,19 @@ mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite( cir::ComplexImagOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { auto resultLLVMTy = getTypeConverter()->convertType(op.getType()); - rewriter.replaceOpWithNewOp( - op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef{1}); + mlir::Value operand = adaptor.getOperand(); + mlir::Location loc = op.getLoc(); + + if (mlir::isa(op.getOperand().getType())) { + operand = mlir::LLVM::ExtractValueOp::create( + rewriter, loc, resultLLVMTy, operand, llvm::ArrayRef{1}); + } else { + mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(resultLLVMTy); + operand = + mlir::LLVM::ConstantOp::create(rewriter, loc, resultLLVMTy, zeroAttr); + } + + rewriter.replaceOp(op, operand); return mlir::success(); } diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 1147777126db..948f9013387d 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -390,3 +390,23 @@ void real_on_scalar_glvalue() { // OGCG: %[[B_ADDR:.*]] = alloca float, align 4 // OGCG: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4 // OGCG: store float %[[TMP_A]], ptr %[[B_ADDR]], align 4 + +void imag_on_scalar_glvalue() { + float a; + float b = __imag__ a; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr, ["b", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr, !cir.float +// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.float -> !cir.float +// CIR: cir.store{{.*}} %[[A_IMAG]], %[[B_ADDR]] : !cir.float, !cir.ptr + +// LLVM: %[[A_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load float, ptr %[[A_ADDR]], align 4 +// LLVM: store float 0.000000e+00, ptr %[[B_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca float, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: store float 0.000000e+00, ptr %[[B_ADDR]], align 4