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

Reply via email to