https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/149717
>From 8a3e3e87ef31fd347eb70f853a112af5d3c11630 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Sun, 20 Jul 2025 16:58:13 +0200 Subject: [PATCH 1/4] [CIR] Upstream Cast kinds for ComplexType --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 10 +- clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 144 +++++++++- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 38 +++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 98 +++++++ .../Dialect/Transforms/LoweringPrepare.cpp | 115 +++++++- clang/test/CIR/CodeGen/complex-cast.cpp | 258 ++++++++++++++++++ 6 files changed, 652 insertions(+), 11 deletions(-) create mode 100644 clang/test/CIR/CodeGen/complex-cast.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 01c5055484185..e334d508ed2f7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -128,12 +128,12 @@ def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [ // CK_BlockPointerToObjCPointerCast // CK_AnyPointerToBlockPointerCast // CK_ObjCObjectLValueCast - // I32EnumAttrCase<"float_to_complex", 44>, - // I32EnumAttrCase<"float_complex_to_real", 45>, - // I32EnumAttrCase<"float_complex_to_bool", 46>, + I32EnumAttrCase<"float_to_complex", 44>, + I32EnumAttrCase<"float_complex_to_real", 45>, + I32EnumAttrCase<"float_complex_to_bool", 46>, I32EnumAttrCase<"float_complex", 47>, - // I32EnumAttrCase<"float_complex_to_int_complex", 48>, - // I32EnumAttrCase<"int_to_complex", 49>, + I32EnumAttrCase<"float_complex_to_int_complex", 48>, + I32EnumAttrCase<"int_to_complex", 49>, I32EnumAttrCase<"int_complex_to_real", 50>, I32EnumAttrCase<"int_complex_to_bool", 51>, I32EnumAttrCase<"int_complex", 52>, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 6756a7ce067a5..93af2ac536429 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -34,11 +34,19 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { } mlir::Value emitLoadOfLValue(LValue lv, SourceLocation loc); + /// Store the specified real/imag parts into the /// specified value pointer. void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv, bool isInit); + /// Emit a cast from complex value Val to DestType. + mlir::Value emitComplexToComplexCast(mlir::Value Val, QualType SrcType, + QualType DestType, SourceLocation Loc); + /// Emit a cast from scalar value Val to DestType. + mlir::Value emitScalarToComplexCast(mlir::Value Val, QualType SrcType, + QualType DestType, SourceLocation Loc); + mlir::Value VisitAbstractConditionalOperator(const AbstractConditionalOperator *e); mlir::Value VisitArraySubscriptExpr(Expr *e); @@ -164,14 +172,99 @@ LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e, mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, QualType destTy) { switch (ck) { + case CK_Dependent: + llvm_unreachable("dependent cast kind in IR gen!"); + case CK_NoOp: case CK_LValueToRValue: return Visit(op); - default: - break; + + case CK_AtomicToNonAtomic: + case CK_NonAtomicToAtomic: + case CK_UserDefinedConversion: + llvm_unreachable("NYI"); + + case CK_LValueBitCast: + llvm_unreachable("NYI"); + + case CK_LValueToRValueBitCast: + llvm_unreachable("NYI"); + + case CK_BitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_MemberPointerToBoolean: + case CK_ReinterpretMemberPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_BooleanToSignedIntegral: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_ARCProduceObject: + case CK_ARCConsumeObject: + case CK_ARCReclaimReturnedObject: + case CK_ARCExtendBlockObject: + case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: + case CK_ZeroToOCLOpaqueType: + case CK_AddressSpaceConversion: + case CK_IntToOCLSampler: + case CK_FloatingToFixedPoint: + case CK_FixedPointToFloating: + case CK_FixedPointCast: + case CK_FixedPointToBoolean: + case CK_FixedPointToIntegral: + case CK_IntegralToFixedPoint: + case CK_MatrixCast: + case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: + case CK_HLSLElementwiseCast: + case CK_HLSLAggregateSplatCast: + llvm_unreachable("invalid cast kind for complex value"); + + case CK_FloatingRealToComplex: + case CK_IntegralRealToComplex: { + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + return emitScalarToComplexCast(cgf.emitScalarExpr(op), op->getType(), + destTy, op->getExprLoc()); } - cgf.cgm.errorNYI("ComplexType Cast"); - return {}; + + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: { + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + return emitComplexToComplexCast(Visit(op), op->getType(), destTy, + op->getExprLoc()); + } + } + + llvm_unreachable("unknown cast resulting in complex value"); } mlir::Value ComplexExprEmitter::emitConstant( @@ -207,6 +300,49 @@ void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val, builder.createStore(loc, val, destAddr); } +mlir::Value ComplexExprEmitter::emitComplexToComplexCast(mlir::Value val, + QualType srcType, + QualType destType, + SourceLocation loc) { + if (srcType == destType) + return val; + + // Get the src/dest element type. + QualType srcElemTy = srcType->castAs<ComplexType>()->getElementType(); + QualType destElemTy = destType->castAs<ComplexType>()->getElementType(); + + cir::CastKind castOpKind; + if (srcElemTy->isFloatingType() && destElemTy->isFloatingType()) + castOpKind = cir::CastKind::float_complex; + else if (srcElemTy->isFloatingType() && destElemTy->isIntegerType()) + castOpKind = cir::CastKind::float_complex_to_int_complex; + else if (srcElemTy->isIntegerType() && destElemTy->isFloatingType()) + castOpKind = cir::CastKind::int_complex_to_float_complex; + else if (srcElemTy->isIntegerType() && destElemTy->isIntegerType()) + castOpKind = cir::CastKind::int_complex; + else + llvm_unreachable("unexpected src type or dest type"); + + return builder.createCast(cgf.getLoc(loc), castOpKind, val, + cgf.convertType(destType)); +} + +mlir::Value ComplexExprEmitter::emitScalarToComplexCast(mlir::Value val, + QualType srcType, + QualType destType, + SourceLocation loc) { + cir::CastKind castOpKind; + if (srcType->isFloatingType()) + castOpKind = cir::CastKind::float_to_complex; + else if (srcType->isIntegerType()) + castOpKind = cir::CastKind::int_to_complex; + else + llvm_unreachable("unexpected src type"); + + return builder.createCast(cgf.getLoc(loc), castOpKind, val, + cgf.convertType(destType)); +} + mlir::Value ComplexExprEmitter::VisitAbstractConditionalOperator( const AbstractConditionalOperator *e) { mlir::Value condValue = Visit(e->getCond()); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index eba6bffbf2927..e7ef580ebc14a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -88,6 +88,10 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { // Utilities //===--------------------------------------------------------------------===// + mlir::Value emitComplexToScalarConversion(mlir::Location loc, + mlir::Value value, CastKind kind, + QualType destTy); + mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType) { return builder.createFloatingCast(result, cgf.convertType(promotionType)); } @@ -1135,6 +1139,31 @@ LValue ScalarExprEmitter::emitCompoundAssignLValue( return lhsLV; } +mlir::Value ScalarExprEmitter::emitComplexToScalarConversion(mlir::Location lov, + mlir::Value value, + CastKind kind, + QualType destTy) { + cir::CastKind castOpKind; + switch (kind) { + case CK_FloatingComplexToReal: + castOpKind = cir::CastKind::float_complex_to_real; + break; + case CK_IntegralComplexToReal: + castOpKind = cir::CastKind::int_complex_to_real; + break; + case CK_FloatingComplexToBoolean: + castOpKind = cir::CastKind::float_complex_to_bool; + break; + case CK_IntegralComplexToBoolean: + castOpKind = cir::CastKind::int_complex_to_bool; + break; + default: + llvm_unreachable("invalid complex-to-scalar cast kind"); + } + + return builder.createCast(lov, castOpKind, value, cgf.convertType(destTy)); +} + mlir::Value ScalarExprEmitter::emitPromoted(const Expr *e, QualType promotionType) { e = e->IgnoreParens(); @@ -1758,6 +1787,15 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { ce->getExprLoc(), opts); } + case CK_FloatingComplexToReal: + case CK_IntegralComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: { + mlir::Value value = cgf.emitComplexExpr(subExpr); + return emitComplexToScalarConversion(cgf.getLoc(ce->getExprLoc()), value, + kind, destTy); + } + case CK_FloatingRealToComplex: case CK_FloatingComplexCast: case CK_IntegralRealToComplex: diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index f0416b6aba6e4..cd77166622fac 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -489,6 +489,104 @@ LogicalResult cir::CastOp::verify() { return emitOpError() << "requires two types differ in addrspace only"; return success(); } + case cir::CastKind::float_to_complex: { + if (!mlir::isa<cir::FPTypeInterface>(srcType)) + return emitOpError() << "requires !cir.float type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy) + return emitOpError() << "requires !cir.complex type for result"; + if (srcType != resComplexTy.getElementType()) + return emitOpError() << "requires source type match result element type"; + return success(); + } + case cir::CastKind::int_to_complex: { + if (!mlir::isa<cir::IntType>(srcType)) + return emitOpError() << "requires !cir.int type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy) + return emitOpError() << "requires !cir.complex type for result"; + if (srcType != resComplexTy.getElementType()) + return emitOpError() << "requires source type match result element type"; + return success(); + } + case cir::CastKind::float_complex_to_real: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy) + return emitOpError() << "requires !cir.complex type for source"; + if (!mlir::isa<cir::FPTypeInterface>(resType)) + return emitOpError() << "requires !cir.float type for result"; + if (srcComplexTy.getElementType() != resType) + return emitOpError() << "requires source element type match result type"; + return success(); + } + case cir::CastKind::int_complex_to_real: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy) + return emitOpError() << "requires !cir.complex type for source"; + if (!mlir::isa<cir::IntType>(resType)) + return emitOpError() << "requires !cir.int type for result"; + if (srcComplexTy.getElementType() != resType) + return emitOpError() << "requires source element type match result type"; + return success(); + } + case cir::CastKind::float_complex_to_bool: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + if (!mlir::isa<cir::BoolType>(resType)) + return emitOpError() << "requires !cir.bool type for result"; + return success(); + } + case cir::CastKind::int_complex_to_bool: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + if (!mlir::isa<cir::BoolType>(resType)) + return emitOpError() << "requires !cir.bool type for result"; + return success(); + } + case cir::CastKind::float_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for result"; + return success(); + } + case cir::CastKind::float_complex_to_int_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for result"; + return success(); + } + case cir::CastKind::int_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for result"; + return success(); + } + case cir::CastKind::int_complex_to_float_complex: { + auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType); + if (!srcComplexTy || !srcComplexTy.isIntegerComplex()) + return emitOpError() << "requires integer !cir.complex type for source"; + auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType); + if (!resComplexTy || !resComplexTy.isFloatingPointComplex()) + return emitOpError() + << "requires floating point !cir.complex type for result"; + return success(); + } default: llvm_unreachable("Unknown CastOp kind?"); } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 8f848c7345610..57e975b6e834d 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -13,6 +13,7 @@ #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h" +#include <iostream> #include <memory> using namespace mlir; @@ -24,11 +25,118 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOperation() override; void runOnOp(mlir::Operation *op); + void lowerCastOp(cir::CastOp op); void lowerUnaryOp(cir::UnaryOp op); }; } // namespace +static mlir::Value lowerScalarToComplexCast(MLIRContext &ctx, CastOp op) { + CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + mlir::Value imag = builder.getNullValue(src.getType(), op.getLoc()); + return builder.createComplexCreate(op.getLoc(), src, imag); +} + +static mlir::Value lowerComplexToScalarCast(MLIRContext &ctx, CastOp op) { + CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + if (!mlir::isa<cir::BoolType>(op.getType())) + return builder.createComplexReal(op.getLoc(), src); + + // Complex cast to bool: (bool)(a+bi) => (bool)a || (bool)b + mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); + mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src); + + cir::CastKind elemToBoolKind; + if (op.getKind() == cir::CastKind::float_complex_to_bool) + elemToBoolKind = cir::CastKind::float_to_bool; + else if (op.getKind() == cir::CastKind::int_complex_to_bool) + elemToBoolKind = cir::CastKind::int_to_bool; + else + llvm_unreachable("invalid complex to bool cast kind"); + + cir::BoolType boolTy = builder.getBoolTy(); + mlir::Value srcRealToBool = + builder.createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy); + mlir::Value srcImagToBool = + builder.createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy); + + // srcRealToBool || srcImagToBool + return builder.createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool); +} + +static mlir::Value lowerComplexToComplexCast(MLIRContext &ctx, CastOp op) { + CIRBaseBuilderTy builder(ctx); + builder.setInsertionPoint(op); + + mlir::Value src = op.getSrc(); + auto dstComplexElemTy = + mlir::cast<cir::ComplexType>(op.getType()).getElementType(); + + mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); + mlir::Value srcImag = builder.createComplexReal(op.getLoc(), src); + + cir::CastKind scalarCastKind; + switch (op.getKind()) { + case cir::CastKind::float_complex: + scalarCastKind = cir::CastKind::floating; + break; + case cir::CastKind::float_complex_to_int_complex: + scalarCastKind = cir::CastKind::float_to_int; + break; + case cir::CastKind::int_complex: + scalarCastKind = cir::CastKind::integral; + break; + case cir::CastKind::int_complex_to_float_complex: + scalarCastKind = cir::CastKind::int_to_float; + break; + default: + llvm_unreachable("invalid complex to complex cast kind"); + } + + mlir::Value dstReal = builder.createCast(op.getLoc(), scalarCastKind, srcReal, + dstComplexElemTy); + mlir::Value dstImag = builder.createCast(op.getLoc(), scalarCastKind, srcImag, + dstComplexElemTy); + return builder.createComplexCreate(op.getLoc(), dstReal, dstImag); +} + +void LoweringPreparePass::lowerCastOp(cir::CastOp op) { + mlir::Value loweredValue; + switch (op.getKind()) { + case cir::CastKind::float_to_complex: + case cir::CastKind::int_to_complex: + loweredValue = lowerScalarToComplexCast(getContext(), op); + break; + + case cir::CastKind::float_complex_to_real: + case cir::CastKind::int_complex_to_real: + case cir::CastKind::float_complex_to_bool: + case cir::CastKind::int_complex_to_bool: { + loweredValue = lowerComplexToScalarCast(getContext(), op); + break; + } + + case cir::CastKind::float_complex: + case cir::CastKind::float_complex_to_int_complex: + case cir::CastKind::int_complex: + case cir::CastKind::int_complex_to_float_complex: + loweredValue = lowerComplexToComplexCast(getContext(), op); + break; + + default: + return; + } + + op.replaceAllUsesWith(loweredValue); + op.erase(); +} + void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { mlir::Type ty = op.getType(); if (!mlir::isa<cir::ComplexType>(ty)) @@ -72,8 +180,11 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { } void LoweringPreparePass::runOnOp(mlir::Operation *op) { - if (auto unary = dyn_cast<cir::UnaryOp>(op)) + if (auto cast = dyn_cast<cir::CastOp>(op)) { + lowerCastOp(cast); + } else if (auto unary = dyn_cast<cir::UnaryOp>(op)) { lowerUnaryOp(unary); + } } void LoweringPreparePass::runOnOperation() { @@ -82,7 +193,7 @@ void LoweringPreparePass::runOnOperation() { llvm::SmallVector<mlir::Operation *> opsToTransform; op->walk([&](mlir::Operation *op) { - if (mlir::isa<cir::UnaryOp>(op)) + if (mlir::isa<cir::CastOp, cir::UnaryOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/complex-cast.cpp b/clang/test/CIR/CodeGen/complex-cast.cpp new file mode 100644 index 0000000000000..d9b23c7f70f4b --- /dev/null +++ b/clang/test/CIR/CodeGen/complex-cast.cpp @@ -0,0 +1,258 @@ +// 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 + +double _Complex cd; +float _Complex cf; +int _Complex ci; +short _Complex cs; +double sd; +int si; +bool b; + +void scalar_to_complex() { + cd = sd; + ci = si; + cd = si; + ci = sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %{{.+}} = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void scalar_to_complex_explicit() { + cd = (double _Complex)sd; + ci = (int _Complex)si; + cd = (double _Complex)si; + ci = (int _Complex)sd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %{{.*}} : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr @cd, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %{{.*}} : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { i32, i32 } %[[TMP]], i32 0, 1 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr @ci, i32 0, i32 1), align 4 + +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %{{.*}} : !s32i), !cir.double +// CIR-BEFORE: %[[FP_TO_COMPLEX:.*]] = cir.cast(float_to_complex, %[[INT_TO_FP]] : !cir.double), !cir.complex<!cir.double> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(int_to_float, %[[TMP]] : !s32i), !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 +// LLVM-NEXT: %{{.+}} = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 + +// OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 +// OGCG: store double 0.000000e+00, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %{{.*}} : !cir.double), !s32i +// CIR-BEFORE: %[[INT_TO_COMPLEX:.*]] = cir.cast(int_to_complex, %[[FP_TO_INT]] : !s32i), !cir.complex<!s32i> + +// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.double>, !cir.double +// CIR-AFTER-NEXT: %[[REAL:.*]] = cir.cast(float_to_int, %[[TMP]] : !cir.double), !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.const #cir.int<0> : !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.complex.create %[[REAL]], %[[IMAG]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// LLVM-NEXT: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL]], 0 +// LLVM-NEXT: %{{.*}} = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1 + +// OGCG: %[[TMP:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[REAL:.*]] = fptosi double %[[TMP]] to i32 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 +// OGCG: store i32 0, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + +void complex_to_scalar() { + sd = (double)cd; + si = (int)ci; + sd = (double)ci; + si = (int)cd; +} + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double + +// LLVM: %{{.*}} = extractvalue { double, double } %{{.*}}, 0 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: store double %[[REAL]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i + +// CIR-AFTER: %{{.*}} = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i + +// LLVM: %{{.*}} = extractvalue { i32, i32 } %{{.*}}, 0 + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: store i32 %[[REAL]], ptr {{.*}}, align 4 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_REAL:.*]] = cir.cast(int_complex_to_real, %{{.*}} : !cir.complex<!s32i>), !s32i +// CIR-BEFORE: %[[INT_TO_FP:.*]] = cir.cast(int_to_float, %[[INT_COMPLEX_TO_REAL]] : !s32i), !cir.double + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(int_to_float, %[[REAL]] : !s32i), !cir.double + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.+}}, 0 +// LLVM-NEXT: %{{.*}} = sitofp i32 %[[REAL]] to double + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[INT_TO_FP:.*]] = sitofp i32 %[[REAL]] to double +// OGCG: store double %[[INT_TO_FP]], ptr {{.*}}, align 8 + +// CIR-BEFORE: %[[FP_TO_COMPLEX_REAL:.*]] = cir.cast(float_complex_to_real, %{{.*}} : !cir.complex<!cir.double>), !cir.double +// CIR-BEFORE: %[[FP_TO_INT:.*]] = cir.cast(float_to_int, %[[FP_TO_COMPLEX_REAL]] : !cir.double), !s32i + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %{{.*}} = cir.cast(float_to_int, %[[REAL]] : !cir.double), !s32i + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.+}}, 0 +// LLVM-NEXT: %{{.*}} = fptosi double %[[REAL]] to i32 + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[FP_TO_INT:.*]] = fptosi double %[[REAL]] to i32 +// OGCG: store i32 %[[FP_TO_INT]], ptr {{.*}}, align 4 + +void complex_to_bool() { + b = (bool)cd; + b = (bool)ci; +} + +// CIR-BEFORE: %[[FP_COMPLEX_TO_BOOL:.*]] = cir.cast(float_complex_to_bool, %{{.*}} : !cir.complex<!cir.double>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.double> -> !cir.double +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[REAL]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[IMAG]] : !cir.double), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.+}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { double, double } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// LLVM-NEXT: %{{.*}} = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] + +// OGCG: %[[REAL:.*]] = load double, ptr {{.*}}, align 8 +// OGCG: %[[IMAG:.*]] = load double, ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 +// OGCG: %[[REAL_TO_BOOL:.*]] = fcmp une double %[[REAL]], 0.000000e+00 +// OGCG: %[[IMAG_TO_BOOL:.*]] = fcmp une double %[[IMAG]], 0.000000e+00 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +// CIR-BEFORE: %[[INT_COMPLEX_TO_BOOL:.*]] = cir.cast(int_complex_to_bool, %{{.*}} : !cir.complex<!s32i>), !cir.bool + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s32i> -> !s32i +// CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[REAL]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(int_to_bool, %[[IMAG]] : !s32i), !cir.bool +// CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true +// CIR-AFTER-NEXT: %{{.+}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool + +// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0 +// LLVM-NEXT: %[[IMAG:.*]] = extractvalue { i32, i32 } %{{.*}}, 1 +// LLVM-NEXT: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// LLVM-NEXT: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// LLVM-NEXT: %{{.*}} = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] + +// OGCG: %[[REAL:.*]] = load i32, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load i32, ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_TO_BOOL:.*]] = icmp ne i32 %[[REAL]], 0 +// OGCG: %[[IMAG_TO_BOOL:.*]] = icmp ne i32 %[[IMAG]], 0 +// OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] +// OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 +// OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 >From 13cc762c9ed82cf20be28c9d5dfc5f92907b73c9 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Mon, 21 Jul 2025 17:52:15 +0200 Subject: [PATCH 2/4] Address code review comments --- clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 9 +++++---- clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 93af2ac536429..d18046ae2770a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -41,11 +41,12 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { bool isInit); /// Emit a cast from complex value Val to DestType. - mlir::Value emitComplexToComplexCast(mlir::Value Val, QualType SrcType, - QualType DestType, SourceLocation Loc); + mlir::Value emitComplexToComplexCast(mlir::Value value, QualType srcType, + QualType destType, SourceLocation loc); + /// Emit a cast from scalar value Val to DestType. - mlir::Value emitScalarToComplexCast(mlir::Value Val, QualType SrcType, - QualType DestType, SourceLocation Loc); + mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType, + QualType destType, SourceLocation loc); mlir::Value VisitAbstractConditionalOperator(const AbstractConditionalOperator *e); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 57e975b6e834d..2ee85d8308616 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -66,7 +66,6 @@ static mlir::Value lowerComplexToScalarCast(MLIRContext &ctx, CastOp op) { mlir::Value srcImagToBool = builder.createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy); - // srcRealToBool || srcImagToBool return builder.createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool); } >From 7c43c07175f15c894095f646f2ef0614fef9b90f Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Mon, 21 Jul 2025 18:18:50 +0200 Subject: [PATCH 3/4] Address code review comments --- .../Dialect/Transforms/LoweringPrepare.cpp | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 2ee85d8308616..2c43c25404d6c 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -31,7 +31,8 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { } // namespace -static mlir::Value lowerScalarToComplexCast(MLIRContext &ctx, CastOp op) { +static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, + cir::CastOp op) { CIRBaseBuilderTy builder(ctx); builder.setInsertionPoint(op); @@ -40,7 +41,9 @@ static mlir::Value lowerScalarToComplexCast(MLIRContext &ctx, CastOp op) { return builder.createComplexCreate(op.getLoc(), src, imag); } -static mlir::Value lowerComplexToScalarCast(MLIRContext &ctx, CastOp op) { +static mlir::Value lowerComplexToScalarCast(mlir::MLIRContext &ctx, + cir::CastOp op, + cir::CastKind elemToBoolKind) { CIRBaseBuilderTy builder(ctx); builder.setInsertionPoint(op); @@ -52,24 +55,17 @@ static mlir::Value lowerComplexToScalarCast(MLIRContext &ctx, CastOp op) { mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src); - cir::CastKind elemToBoolKind; - if (op.getKind() == cir::CastKind::float_complex_to_bool) - elemToBoolKind = cir::CastKind::float_to_bool; - else if (op.getKind() == cir::CastKind::int_complex_to_bool) - elemToBoolKind = cir::CastKind::int_to_bool; - else - llvm_unreachable("invalid complex to bool cast kind"); - cir::BoolType boolTy = builder.getBoolTy(); mlir::Value srcRealToBool = builder.createCast(op.getLoc(), elemToBoolKind, srcReal, boolTy); mlir::Value srcImagToBool = builder.createCast(op.getLoc(), elemToBoolKind, srcImag, boolTy); - return builder.createLogicalOr(op.getLoc(), srcRealToBool, srcImagToBool); } -static mlir::Value lowerComplexToComplexCast(MLIRContext &ctx, CastOp op) { +static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, + cir::CastOp op, + cir::CastKind scalarCastKind) { CIRBaseBuilderTy builder(ctx); builder.setInsertionPoint(op); @@ -80,24 +76,6 @@ static mlir::Value lowerComplexToComplexCast(MLIRContext &ctx, CastOp op) { mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); mlir::Value srcImag = builder.createComplexReal(op.getLoc(), src); - cir::CastKind scalarCastKind; - switch (op.getKind()) { - case cir::CastKind::float_complex: - scalarCastKind = cir::CastKind::floating; - break; - case cir::CastKind::float_complex_to_int_complex: - scalarCastKind = cir::CastKind::float_to_int; - break; - case cir::CastKind::int_complex: - scalarCastKind = cir::CastKind::integral; - break; - case cir::CastKind::int_complex_to_float_complex: - scalarCastKind = cir::CastKind::int_to_float; - break; - default: - llvm_unreachable("invalid complex to complex cast kind"); - } - mlir::Value dstReal = builder.createCast(op.getLoc(), scalarCastKind, srcReal, dstComplexElemTy); mlir::Value dstImag = builder.createCast(op.getLoc(), scalarCastKind, srcImag, @@ -114,19 +92,42 @@ void LoweringPreparePass::lowerCastOp(cir::CastOp op) { break; case cir::CastKind::float_complex_to_real: - case cir::CastKind::int_complex_to_real: - case cir::CastKind::float_complex_to_bool: + case cir::CastKind::int_complex_to_real: { + loweredValue = lowerComplexToScalarCast(getContext(), op, op.getKind()); + break; + } + + case cir::CastKind::float_complex_to_bool: { + loweredValue = lowerComplexToScalarCast(getContext(), op, + cir::CastKind::float_to_bool); + break; + } case cir::CastKind::int_complex_to_bool: { - loweredValue = lowerComplexToScalarCast(getContext(), op); + loweredValue = + lowerComplexToScalarCast(getContext(), op, cir::CastKind::int_to_bool); break; } - case cir::CastKind::float_complex: - case cir::CastKind::float_complex_to_int_complex: - case cir::CastKind::int_complex: - case cir::CastKind::int_complex_to_float_complex: - loweredValue = lowerComplexToComplexCast(getContext(), op); + case cir::CastKind::float_complex: { + loweredValue = + lowerComplexToComplexCast(getContext(), op, cir::CastKind::floating); + break; + } + case cir::CastKind::float_complex_to_int_complex: { + loweredValue = lowerComplexToComplexCast(getContext(), op, + cir::CastKind::float_to_int); break; + } + case cir::CastKind::int_complex: { + loweredValue = + lowerComplexToComplexCast(getContext(), op, cir::CastKind::integral); + break; + } + case cir::CastKind::int_complex_to_float_complex: { + loweredValue = lowerComplexToComplexCast(getContext(), op, + cir::CastKind::int_to_float); + break; + } default: return; >From 1c6ce40ab687f37fd8590e6de98cb4a7c4e4d62a Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Mon, 21 Jul 2025 19:26:15 +0200 Subject: [PATCH 4/4] Fix Complex to Complex cast --- .../Dialect/Transforms/LoweringPrepare.cpp | 81 +++++++------------ clang/test/CIR/CodeGen/complex-cast.cpp | 56 ++++++++++++- 2 files changed, 84 insertions(+), 53 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 2c43c25404d6c..5612b9d173445 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -74,7 +74,7 @@ static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, mlir::cast<cir::ComplexType>(op.getType()).getElementType(); mlir::Value srcReal = builder.createComplexReal(op.getLoc(), src); - mlir::Value srcImag = builder.createComplexReal(op.getLoc(), src); + mlir::Value srcImag = builder.createComplexImag(op.getLoc(), src); mlir::Value dstReal = builder.createCast(op.getLoc(), scalarCastKind, srcReal, dstComplexElemTy); @@ -84,57 +84,36 @@ static mlir::Value lowerComplexToComplexCast(mlir::MLIRContext &ctx, } void LoweringPreparePass::lowerCastOp(cir::CastOp op) { - mlir::Value loweredValue; - switch (op.getKind()) { - case cir::CastKind::float_to_complex: - case cir::CastKind::int_to_complex: - loweredValue = lowerScalarToComplexCast(getContext(), op); - break; - - case cir::CastKind::float_complex_to_real: - case cir::CastKind::int_complex_to_real: { - loweredValue = lowerComplexToScalarCast(getContext(), op, op.getKind()); - break; - } - - case cir::CastKind::float_complex_to_bool: { - loweredValue = lowerComplexToScalarCast(getContext(), op, - cir::CastKind::float_to_bool); - break; - } - case cir::CastKind::int_complex_to_bool: { - loweredValue = - lowerComplexToScalarCast(getContext(), op, cir::CastKind::int_to_bool); - break; - } - - case cir::CastKind::float_complex: { - loweredValue = - lowerComplexToComplexCast(getContext(), op, cir::CastKind::floating); - break; + mlir::MLIRContext &ctx = getContext(); + mlir::Value loweredValue = [&]() -> Value { + switch (op.getKind()) { + case cir::CastKind::float_to_complex: + case cir::CastKind::int_to_complex: + return lowerScalarToComplexCast(ctx, op); + case cir::CastKind::float_complex_to_real: + case cir::CastKind::int_complex_to_real: + return lowerComplexToScalarCast(ctx, op, op.getKind()); + case cir::CastKind::float_complex_to_bool: + return lowerComplexToScalarCast(ctx, op, cir::CastKind::float_to_bool); + case cir::CastKind::int_complex_to_bool: + return lowerComplexToScalarCast(ctx, op, cir::CastKind::int_to_bool); + case cir::CastKind::float_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::floating); + case cir::CastKind::float_complex_to_int_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::float_to_int); + case cir::CastKind::int_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::integral); + case cir::CastKind::int_complex_to_float_complex: + return lowerComplexToComplexCast(ctx, op, cir::CastKind::int_to_float); + default: + return nullptr; + } + }(); + + if (loweredValue) { + op.replaceAllUsesWith(loweredValue); + op.erase(); } - case cir::CastKind::float_complex_to_int_complex: { - loweredValue = lowerComplexToComplexCast(getContext(), op, - cir::CastKind::float_to_int); - break; - } - case cir::CastKind::int_complex: { - loweredValue = - lowerComplexToComplexCast(getContext(), op, cir::CastKind::integral); - break; - } - case cir::CastKind::int_complex_to_float_complex: { - loweredValue = lowerComplexToComplexCast(getContext(), op, - cir::CastKind::int_to_float); - break; - } - - default: - return; - } - - op.replaceAllUsesWith(loweredValue); - op.erase(); } void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { diff --git a/clang/test/CIR/CodeGen/complex-cast.cpp b/clang/test/CIR/CodeGen/complex-cast.cpp index d9b23c7f70f4b..e94e831750f92 100644 --- a/clang/test/CIR/CodeGen/complex-cast.cpp +++ b/clang/test/CIR/CodeGen/complex-cast.cpp @@ -59,7 +59,7 @@ void scalar_to_complex() { // LLVM: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 // LLVM-NEXT: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double // LLVM-NEXT: %[[TMP_2:.*]] = insertvalue { double, double } undef, double %[[REAL]], 0 -// LLVM-NEXT: %{{.+}} = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 +// LLVM-NEXT: %{{.*}} = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1 // OGCG: %[[TMP:.*]] = load i32, ptr {{.*}}, align 4 // OGCG: %[[REAL:.*]] = sitofp i32 %[[TMP]] to double @@ -218,7 +218,7 @@ void complex_to_bool() { // CIR-AFTER-NEXT: %[[REAL_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[REAL]] : !cir.double), !cir.bool // CIR-AFTER-NEXT: %[[IMAG_TO_BOOL:.*]] = cir.cast(float_to_bool, %[[IMAG]] : !cir.double), !cir.bool // CIR-AFTER-NEXT: %[[CONST_TRUE:.*]] = cir.const #true -// CIR-AFTER-NEXT: %{{.+}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool +// CIR-AFTER-NEXT: %{{.*}} = cir.select if %[[REAL_TO_BOOL]] then %[[CONST_TRUE]] else %[[IMAG_TO_BOOL]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool // LLVM: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0 // LLVM-NEXT: %[[IMAG:.*]] = extractvalue { double, double } %{{.*}}, 1 @@ -256,3 +256,55 @@ void complex_to_bool() { // OGCG: %[[COMPLEX_TO_BOOL:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]] // OGCG: %[[BOOL_TO_INT:.*]] = zext i1 %[[COMPLEX_TO_BOOL]] to i8 // OGCG: store i8 %[[BOOL_TO_INT]], ptr {{.*}}, align 1 + +void complex_to_complex_cast() { + cd = cf; + ci = cs; +} + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-BEFORE: %[[FP_COMPLEX:.*]] = cir.cast(float_complex, %[[TMP]] : !cir.complex<!cir.float>), !cir.complex<!cir.double> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER: %[[REAL_FP_CAST:.*]] = cir.cast(floating, %[[REAL]] : !cir.float), !cir.double +// CIR-AFTER: %[[IMAG_FP_CAST:.*]] = cir.cast(floating, %[[IMAG]] : !cir.float), !cir.double +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_FP_CAST]], %[[IMAG_FP_CAST]] : !cir.double -> !cir.complex<!cir.double> + +// LLVM: %[[REAL:.*]] = extractvalue { float, float } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %{{.*}}, 1 +// LLVM: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// LLVM: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// LLVM: %[[TMP:.*]] = insertvalue { double, double } undef, double %[[REAL_FP_CAST]], 0 +// LLVM: %{{.*}} = insertvalue { double, double } %[[TMP]], double %5, 1 + +// OGCG: %[[REAL:.*]] = load float, ptr {{.*}}, align 4 +// OGCG: %[[IMAG:.*]] = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr {{.*}}, i32 0, i32 1), align 4 +// OGCG: %[[REAL_FP_CAST:.*]] = fpext float %[[REAL]] to double +// OGCG: %[[IMAG_FP_CAST:.*]] = fpext float %[[IMAG]] to double +// OGCG: store double %[[REAL_FP_CAST]], ptr {{.*}}, align 8 +// OGCG: store double %[[IMAG_FP_CAST]], ptr getelementptr inbounds nuw ({ double, double }, ptr {{.*}}, i32 0, i32 1), align 8 + +// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.complex<!s16i>>, !cir.complex<!s16i> +// CIR-BEFORE: %[[INT_COMPLEX:.*]] = cir.cast(int_complex, %[[TMP]] : !cir.complex<!s16i>), !cir.complex<!s32i> + +// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %{{.*}} : !cir.complex<!s16i> -> !s16i +// CIR-AFTER: %[[REAL_INT_CAST:.*]] = cir.cast(integral, %[[REAL]] : !s16i), !s32i +// CIR-AFTER: %[[IMAG_INT_CAST:.*]] = cir.cast(integral, %[[IMAG]] : !s16i), !s32i +// CIR-AFTER: %{{.*}} = cir.complex.create %[[REAL_INT_CAST]], %[[IMAG_INT_CAST]] : !s32i -> !cir.complex<!s32i> + +// LLVM: %[[REAL:.*]] = extractvalue { i16, i16 } %{{.*}}, 0 +// LLVM: %[[IMAG:.*]] = extractvalue { i16, i16 } %{{.*}}, 1 +// LLVM: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// LLVM: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// LLVM: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[REAL_INT_CAST]], 0 +// LLVM: %{{.*}} = insertvalue { i32, i32 } %[[TMP]], i32 %[[IMAG_INT_CAST]], 1 + +// OGCG: %[[REAL:.*]] = load i16, ptr {{.*}}, align 2 +// OGCG: %[[IMAG:.*]] = load i16, ptr getelementptr inbounds nuw ({ i16, i16 }, ptr {{.*}}, i32 0, i32 1), align 2 +// OGCG: %[[REAL_INT_CAST:.*]] = sext i16 %[[REAL]] to i32 +// OGCG: %[[IMAG_INT_CAST:.*]] = sext i16 %[[IMAG]] to i32 +// OGCG: store i32 %[[REAL_INT_CAST]], ptr {{.*}}, align 4 +// OGCG: store i32 %[[IMAG_INT_CAST]], ptr getelementptr inbounds nuw ({ i32, i32 }, ptr {{.*}}, i32 0, i32 1), align 4 + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits