[clang] eb817c7 - [CIR] Upstream Cast kinds for ComplexType (#149717)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 23 10:22:43 PDT 2025
Author: Amr Hesham
Date: 2025-07-23T19:22:39+02:00
New Revision: eb817c7950d3f7b555034a983240a11b8c693dc4
URL: https://github.com/llvm/llvm-project/commit/eb817c7950d3f7b555034a983240a11b8c693dc4
DIFF: https://github.com/llvm/llvm-project/commit/eb817c7950d3f7b555034a983240a11b8c693dc4.diff
LOG: [CIR] Upstream Cast kinds for ComplexType (#149717)
This change adds support for cast kinds for ComplexType
https://github.com/llvm/llvm-project/issues/141365
Added:
clang/test/CIR/CodeGen/complex-cast.cpp
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
clang/lib/CIR/Dialect/IR/CIRDialect.cpp
clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 694e3691c9361..c54075e898bdb 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..d52da0cb32c53 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -34,11 +34,20 @@ 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 value, QualType srcType,
+ QualType destType, SourceLocation loc);
+
+ /// Emit a cast from scalar value Val to DestType.
+ mlir::Value emitScalarToComplexCast(mlir::Value value, QualType srcType,
+ QualType destType, SourceLocation loc);
+
mlir::Value
VisitAbstractConditionalOperator(const AbstractConditionalOperator *e);
mlir::Value VisitArraySubscriptExpr(Expr *e);
@@ -164,14 +173,106 @@ LValue ComplexExprEmitter::emitBinAssignLValue(const BinaryOperator *e,
mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
QualType destTy) {
switch (ck) {
+ case CK_Dependent:
+ llvm_unreachable("dependent type must be resolved before the CIR codegen");
+
case CK_NoOp:
case CK_LValueToRValue:
return Visit(op);
- default:
- break;
+
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
+ case CK_UserDefinedConversion: {
+ cgf.cgm.errorNYI(
+ "ComplexExprEmitter::emitCast Atmoic & UserDefinedConversion");
+ return {};
}
- cgf.cgm.errorNYI("ComplexType Cast");
- return {};
+
+ case CK_LValueBitCast: {
+ cgf.cgm.errorNYI("ComplexExprEmitter::emitCast CK_LValueBitCast");
+ return {};
+ }
+
+ case CK_LValueToRValueBitCast: {
+ cgf.cgm.errorNYI("ComplexExprEmitter::emitCast CK_LValueToRValueBitCast");
+ return {};
+ }
+
+ 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());
+ }
+
+ 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 +308,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 cf82d1d283058..2523b0ff33787 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
diff er 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..0f13417cdab29 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,97 @@ 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(mlir::MLIRContext &ctx,
+ cir::CastOp op) {
+ cir::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(mlir::MLIRContext &ctx,
+ cir::CastOp op,
+ cir::CastKind elemToBoolKind) {
+ cir::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::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(mlir::MLIRContext &ctx,
+ cir::CastOp op,
+ cir::CastKind scalarCastKind) {
+ 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.createComplexImag(op.getLoc(), src);
+
+ 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::MLIRContext &ctx = getContext();
+ mlir::Value loweredValue = [&]() -> mlir::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();
+ }
+}
+
void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
mlir::Type ty = op.getType();
if (!mlir::isa<cir::ComplexType>(ty))
@@ -72,7 +159,9 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
}
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
- if (auto unary = dyn_cast<cir::UnaryOp>(op))
+ if (auto cast = mlir::dyn_cast<cir::CastOp>(op))
+ lowerCastOp(cast);
+ else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);
}
@@ -82,7 +171,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..94f47e4730cc2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-cast.cpp
@@ -0,0 +1,328 @@
+// 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: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1
+// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8
+
+// 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: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1
+// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4
+
+// 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: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1
+// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8
+
+// 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: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1
+// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4
+
+// 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: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double 0.000000e+00, 1
+// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8
+
+// 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: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 0, 1
+// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4
+
+// 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: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP_2]], double 0.000000e+00, 1
+// LLVM-NEXT: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8
+
+// 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: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP_2]], i32 0, 1
+// LLVM-NEXT: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4
+
+// 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: %[[REAL:.*]] = extractvalue { double, double } %{{.*}}, 0
+// LLVM: store double %[[REAL]], ptr {{.*}}, align 8
+
+// 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: %[[REAL:.*]] = extractvalue { i32, i32 } %{{.*}}, 0
+// LLVM: store i32 %[[REAL]], ptr {{.*}}, align 4
+
+// 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: %[[REAL_TO_DOUBLE:.*]] = sitofp i32 %[[REAL]] to double
+// LLVM-NEXT: store double %[[REAL_TO_DOUBLE]], ptr {{.*}}, align 8
+
+// 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: %[[REAL_TO_INT:.*]] = fptosi double %[[REAL]] to i32
+// LLVM-NEXT: store i32 %[[REAL_TO_INT]], ptr {{.*}}, align 4
+
+// 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:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]]
+// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8
+// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1
+
+// 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:.*]] = or i1 %[[REAL_TO_BOOL]], %[[IMAG_TO_BOOL]]
+// LLVM-NEXT: %[[RESULT:.*]] = zext i1 %[[OR]] to i8
+// LLVM-NEXT: store i8 %[[RESULT]], ptr {{.*}}, align 1
+
+// 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
+
+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: %[[COMPLEX:.*]] = insertvalue { double, double } %[[TMP]], double %[[IMAG_FP_CAST]], 1
+// LLVM: store { double, double } %[[COMPLEX]], ptr {{.*}}, align 8
+
+// 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: %[[COMPLEX:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 %[[IMAG_INT_CAST]], 1
+// LLVM: store { i32, i32 } %[[COMPLEX]], ptr {{.*}}, align 4
+
+// 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
+
More information about the cfe-commits
mailing list