From 569c9fea82815b985c77f478ed6f9074a7490ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmr?= Date: Sun, 28 Sep 2025 14:47:13 +0200 Subject: [PATCH 1/4] [CIR] Update ComplexRealOp to work on scalar type --- .../clang/CIR/Dialect/Builder/CIRBaseBuilder.h | 7 ++++--- clang/include/clang/CIR/Dialect/IR/CIROps.td | 9 +++++---- .../clang/CIR/Dialect/IR/CIRTypeConstraints.td | 6 ++++++ clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 6 ++++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 11 ++++++++++- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 9 +++++++-- clang/test/CIR/CodeGen/complex.cpp | 9 ++++++--- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 3f83c302176c0..ef8f7cf79562f 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -148,9 +148,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { } mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) { - auto operandTy = mlir::cast(operand.getType()); - return cir::ComplexRealOp::create(*this, loc, operandTy.getElementType(), - operand); + auto resultType = operand.getType(); + if (mlir::isa(resultType)) + resultType = mlir::cast(resultType).getElementType(); + return cir::ComplexRealOp::create(*this, loc, resultType, operand); } mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e1be08c1bbbbd..85ad79a983a93 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3260,18 +3260,19 @@ def CIR_ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { def CIR_ComplexRealOp : CIR_Op<"complex.real", [Pure]> { let summary = "Extract the real part of a complex value"; let description = [{ - `cir.complex.real` operation takes an operand of `!cir.complex` type and - yields the real part of it. + `cir.complex.real` operation takes an operand of `!cir.complex` or scalar + type and yields the real part of it. Example: ```mlir - %1 = cir.complex.real %0 : !cir.complex -> !cir.float + %real = cir.complex.real %complex : !cir.complex -> !cir.float + %real = cir.complex.real %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/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 82f6e1d33043e..da03a291a7690 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -165,6 +165,12 @@ def CIR_AnyIntOrFloatType : AnyTypeOf<[CIR_AnyFloatType, CIR_AnyIntType], def CIR_AnyComplexType : CIR_TypeBase<"::cir::ComplexType", "complex type">; +def CIR_AnyComplexOrIntOrFloatType : AnyTypeOf<[ + CIR_AnyComplexType, CIR_AnyFloatType, CIR_AnyIntType +], "complex, integer or floating point type"> { + let cppFunctionName = "isComplexOrIntegerOrFloatingPointType"; +} + //===----------------------------------------------------------------------===// // Array Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index f4bbced781942..500007f6f241b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2151,8 +2151,10 @@ mlir::Value ScalarExprEmitter::VisitRealImag(const UnaryOperator *e, } if (e->getOpcode() == UO_Real) { - return promotionTy.isNull() ? Visit(op) - : cgf.emitPromotedScalarExpr(op, promotionTy); + mlir::Value operand = promotionTy.isNull() + ? Visit(op) + : cgf.emitPromotedScalarExpr(op, promotionTy); + return builder.createComplexReal(loc, operand); } // __imag on a scalar returns zero. Emit the subexpr to ensure side diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index fb87036fdfe21..1fedc62dc0522 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2388,14 +2388,23 @@ OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) { //===----------------------------------------------------------------------===// LogicalResult cir::ComplexRealOp::verify() { - if (getType() != getOperand().getType().getElementType()) { + mlir::Type operandTy = getOperand().getType(); + if (mlir::isa(operandTy)) { + operandTy = mlir::cast(operandTy).getElementType(); + } + + if (getType() != operandTy) { emitOpError() << ": result type does not match operand type"; return failure(); } + return success(); } OpFoldResult cir::ComplexRealOp::fold(FoldAdaptor adaptor) { + if (!mlir::isa(getOperand().getType())) + return nullptr; + if (auto complexCreateOp = getOperand().getDefiningOp()) return complexCreateOp.getOperand(0); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 876948d53010b..664bf55d2b7f5 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2992,8 +2992,13 @@ mlir::LogicalResult CIRToLLVMComplexRealOpLowering::matchAndRewrite( cir::ComplexRealOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType()); - rewriter.replaceOpWithNewOp( - op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef{0}); + mlir::Value operand = adaptor.getOperand(); + if (mlir::isa(op.getOperand().getType())) { + operand = mlir::LLVM::ExtractValueOp::create( + rewriter, op.getLoc(), resultLLVMTy, operand, + llvm::ArrayRef{0}); + } + rewriter.replaceOp(op, operand); return mlir::success(); } diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 4c396d312d148..f686b804a6f95 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1140,7 +1140,8 @@ void real_on_scalar_glvalue() { // 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: cir.store{{.*}} %[[TMP_A]], %[[B_ADDR]] : !cir.float, !cir.ptr +// CIR: %[[A_REAL:.*]] = cir.complex.real %2 : !cir.float -> !cir.float +// CIR: cir.store{{.*}} %[[A_REAL]], %[[B_ADDR]] : !cir.float, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca float, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 @@ -1179,7 +1180,8 @@ void real_on_scalar_with_type_promotion() { // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.f16, !cir.ptr, ["b", init] // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr, !cir.f16 // CIR: %[[TMP_A_F32:.*]] = cir.cast(floating, %[[TMP_A]] : !cir.f16), !cir.float -// CIR: %[[TMP_A_F16:.*]] = cir.cast(floating, %[[TMP_A_F32]] : !cir.float), !cir.f16 +// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A_F32]] : !cir.float -> !cir.float +// CIR: %[[TMP_A_F16:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.float), !cir.f16 // CIR: cir.store{{.*}} %[[TMP_A_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca half, i64 1, align 2 @@ -1248,7 +1250,8 @@ void real_on_scalar_from_real_with_type_promotion() { // CIR: %[[A_IMAG_F32:.*]] = cir.cast(floating, %[[A_IMAG]] : !cir.f16), !cir.float // CIR: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex // CIR: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_COMPLEX_F32]] : !cir.complex -> !cir.float -// CIR: %[[A_REAL_F16:.*]] = cir.cast(floating, %[[A_REAL_F32]] : !cir.float), !cir.f16 +// CIR: %[[A_REAL:.*]] = cir.complex.real %[[A_REAL_F32]] : !cir.float -> !cir.float +// CIR: %[[A_REAL_F16:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.float), !cir.f16 // CIR: cir.store{{.*}} %[[A_REAL_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2 From ea00ca23788920bc6ceaa1e58142d3cc31ee38f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmr?= Date: Mon, 29 Sep 2025 17:45:25 +0200 Subject: [PATCH 2/4] Address code review comments --- clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h | 4 ++-- clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index ef8f7cf79562f..8a5bf0376ec98 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -149,8 +149,8 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) { auto resultType = operand.getType(); - if (mlir::isa(resultType)) - resultType = mlir::cast(resultType).getElementType(); + if (auto complexResultType = mlir::dyn_cast(resultType)) + resultType = complexResultType.getElementType(); return cir::ComplexRealOp::create(*this, loc, resultType, operand); } diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 85ad79a983a93..c71fb566a041a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3260,8 +3260,8 @@ def CIR_ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { def CIR_ComplexRealOp : CIR_Op<"complex.real", [Pure]> { let summary = "Extract the real part of a complex value"; let description = [{ - `cir.complex.real` operation takes an operand of `!cir.complex` or scalar - type and yields the real part of it. + `cir.complex.real` operation takes an operand of `!cir.complex`, `!cir.int` + or `!cir.float` type and yields the real part of it. Example: diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 1fedc62dc0522..6b5cc808e9a29 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2389,8 +2389,8 @@ OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) { LogicalResult cir::ComplexRealOp::verify() { mlir::Type operandTy = getOperand().getType(); - if (mlir::isa(operandTy)) { - operandTy = mlir::cast(operandTy).getElementType(); + if (auto complexOperandTy = mlir::dyn_cast(operandTy)) { + operandTy = complexOperandTy.getElementType(); } if (getType() != operandTy) { From 10522fd83c20b42286dc50363eb338b731bf7226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmr?= Date: Tue, 30 Sep 2025 18:02:43 +0200 Subject: [PATCH 3/4] Address code review comments --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 ++- clang/test/CIR/CodeGen/complex.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c71fb566a041a..569581da273ea 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3261,7 +3261,8 @@ def CIR_ComplexRealOp : CIR_Op<"complex.real", [Pure]> { let summary = "Extract the real part of a complex value"; let description = [{ `cir.complex.real` operation takes an operand of `!cir.complex`, `!cir.int` - or `!cir.float` type and yields the real part of it. + or `!cir.float`. If the operand is `!cir.complex`, the real part of it will + be returned, otherwise the value returned unmodified. Example: diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index f686b804a6f95..145a0c32fcaa3 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1140,7 +1140,7 @@ void real_on_scalar_glvalue() { // 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_REAL:.*]] = cir.complex.real %2 : !cir.float -> !cir.float +// CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.float -> !cir.float // CIR: cir.store{{.*}} %[[A_REAL]], %[[B_ADDR]] : !cir.float, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca float, i64 1, align 4 From 8cc56ab07b74a7edd9bd98a242d97480f0904ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmr?= Date: Wed, 1 Oct 2025 18:07:46 +0200 Subject: [PATCH 4/4] Update lit test with the new cast syntax --- clang/test/CIR/CodeGen/complex.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 48da47b3abaac..ae69b2486efd0 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1179,9 +1179,9 @@ void real_on_scalar_with_type_promotion() { // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.f16, !cir.ptr, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.f16, !cir.ptr, ["b", init] // CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr, !cir.f16 -// CIR: %[[TMP_A_F32:.*]] = cir.cast(floating, %[[TMP_A]] : !cir.f16), !cir.float +// CIR: %[[TMP_A_F32:.*]] = cir.cast floating %[[TMP_A]] : !cir.f16 -> !cir.float // CIR: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A_F32]] : !cir.float -> !cir.float -// CIR: %[[TMP_A_F16:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.float), !cir.f16 +// CIR: %[[TMP_A_F16:.*]] = cir.cast floating %[[A_REAL]] : !cir.float -> !cir.f16 // CIR: cir.store{{.*}} %[[TMP_A_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca half, i64 1, align 2 @@ -1251,7 +1251,7 @@ void real_on_scalar_from_real_with_type_promotion() { // CIR: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex // CIR: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_COMPLEX_F32]] : !cir.complex -> !cir.float // CIR: %[[A_REAL:.*]] = cir.complex.real %[[A_REAL_F32]] : !cir.float -> !cir.float -// CIR: %[[A_REAL_F16:.*]] = cir.cast(floating, %[[A_REAL]] : !cir.float), !cir.f16 +// CIR: %[[A_REAL_F16:.*]] = cir.cast floating %[[A_REAL]] : !cir.float -> !cir.f16 // CIR: cir.store{{.*}} %[[A_REAL_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2 @@ -1288,8 +1288,9 @@ void real_on_scalar_from_imag_with_type_promotion() { // CIR: %[[A_IMAG_F32:.*]] = cir.cast floating %[[A_IMAG]] : !cir.f16 -> !cir.float // CIR: %[[A_COMPLEX_F32:.*]] = cir.complex.create %[[A_REAL_F32]], %[[A_IMAG_F32]] : !cir.float -> !cir.complex // CIR: %[[A_IMAG_F32:.*]] = cir.complex.imag %[[A_COMPLEX_F32]] : !cir.complex -> !cir.float -// CIR: %[[A_IMAG_F16:.*]] = cir.cast floating %[[A_IMAG_F32]] : !cir.float -> !cir.f16 -// CIR: cir.store{{.*}} %[[A_IMAG_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr +// CIR: %[[A_REAL_F32:.*]] = cir.complex.real %[[A_IMAG_F32]] : !cir.float -> !cir.float +// CIR: %[[A_REAL_F16:.*]] = cir.cast floating %[[A_REAL_F32]] : !cir.float -> !cir.f16 +// CIR: cir.store{{.*}} %[[A_REAL_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr // LLVM: %[[A_ADDR:.*]] = alloca { half, half }, i64 1, align 2 // LLVM: %[[B_ADDR]] = alloca half, i64 1, align 2