[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
Morris Hafner via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 13 09:11:07 PDT 2025
https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/130690
>From 4d4e2dab5bff514081b63f1d2078b0085d46cafa Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 12 Mar 2025 16:26:08 -0700
Subject: [PATCH 1/9] [CIR] Upstream CastOp and scalar conversions
This patch upstreams ClangIR's CastOp with the following exceptions:
- No Fixed/FP conversions
- No casts between value categories
- No complex casts
- No array_to_ptrdecay
- No address_space
- No casts involving record types (member pointers, base/derived casts)
- No casts specific to ObjC or OpenCL
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 62 +++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 105 +++++
clang/include/clang/CIR/MissingFeatures.h | 14 +-
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 9 +
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 400 +++++++++++++++++-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 +
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 170 ++++++++
clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp | 27 ++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 207 +++++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 16 +
clang/test/CIR/CodeGen/cast.cpp | 58 +++
clang/test/CIR/IR/cast.cir | 23 +
clang/test/CIR/Lowering/cast.cir | 92 ++++
13 files changed, 1174 insertions(+), 12 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/cast.cpp
create mode 100644 clang/test/CIR/IR/cast.cir
create mode 100644 clang/test/CIR/Lowering/cast.cir
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 017ae0c53a984..e5e8132e9f527 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -13,6 +13,7 @@
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "llvm/Support/ErrorHandling.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
@@ -78,6 +79,67 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::StoreOp>(loc, val, dst);
}
+ //===--------------------------------------------------------------------===//
+ // Cast/Conversion Operators
+ //===--------------------------------------------------------------------===//
+
+ mlir::Value createCast(mlir::Location loc, cir::CastKind kind,
+ mlir::Value src, mlir::Type newTy) {
+ if (newTy == src.getType())
+ return src;
+ return create<cir::CastOp>(loc, newTy, kind, src);
+ }
+
+ mlir::Value createCast(cir::CastKind kind, mlir::Value src,
+ mlir::Type newTy) {
+ if (newTy == src.getType())
+ return src;
+ return createCast(src.getLoc(), kind, src, newTy);
+ }
+
+ mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) {
+ return createCast(cir::CastKind::integral, src, newTy);
+ }
+
+ mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) {
+ return createCast(cir::CastKind::int_to_ptr, src, newTy);
+ }
+
+ mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) {
+ return createCast(cir::CastKind::ptr_to_int, src, newTy);
+ }
+
+ mlir::Value createPtrToBoolCast(mlir::Value v) {
+ return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy());
+ }
+
+ mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) {
+ return createCast(cir::CastKind::bool_to_int, src, newTy);
+ }
+
+ mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) {
+ return createCast(cir::CastKind::bitcast, src, newTy);
+ }
+
+ mlir::Value createBitcast(mlir::Location loc, mlir::Value src,
+ mlir::Type newTy) {
+ return createCast(loc, cir::CastKind::bitcast, src, newTy);
+ }
+
+ mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) {
+ assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src");
+ return createBitcast(src, getPointerTo(newPointeeTy));
+ }
+
+ mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
+ mlir::Type newTy) {
+ return createCast(loc, cir::CastKind::address_space, src, newTy);
+ }
+
+ mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy) {
+ return createAddrSpaceCast(src.getLoc(), src, newTy);
+ }
+
//
// Block handling helpers
// ----------------------
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 77c43e5ace64a..9797960e00867 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -78,6 +78,111 @@ class LLVMLoweringInfo {
class CIR_Op<string mnemonic, list<Trait> traits = []> :
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
+//===----------------------------------------------------------------------===//
+// CastOp
+//===----------------------------------------------------------------------===//
+
+// The enumaration value isn't in sync with clang.
+def CK_IntegralToBoolean : I32EnumAttrCase<"int_to_bool", 1>;
+def CK_ArrayToPointerDecay : I32EnumAttrCase<"array_to_ptrdecay", 2>;
+def CK_IntegralCast : I32EnumAttrCase<"integral", 3>;
+def CK_BitCast : I32EnumAttrCase<"bitcast", 4>;
+def CK_FloatingCast : I32EnumAttrCase<"floating", 5>;
+def CK_PtrToBoolean : I32EnumAttrCase<"ptr_to_bool", 6>;
+def CK_FloatToIntegral : I32EnumAttrCase<"float_to_int", 7>;
+def CK_IntegralToPointer : I32EnumAttrCase<"int_to_ptr", 8>;
+def CK_PointerToIntegral : I32EnumAttrCase<"ptr_to_int", 9>;
+def CK_FloatToBoolean : I32EnumAttrCase<"float_to_bool", 10>;
+def CK_BooleanToIntegral : I32EnumAttrCase<"bool_to_int", 11>;
+def CK_IntegralToFloat : I32EnumAttrCase<"int_to_float", 12>;
+def CK_BooleanToFloat : I32EnumAttrCase<"bool_to_float", 13>;
+def CK_AddressSpaceConversion : I32EnumAttrCase<"address_space", 14>;
+def CK_FloatToComplex : I32EnumAttrCase<"float_to_complex", 15>;
+def CK_IntegralToComplex : I32EnumAttrCase<"int_to_complex", 16>;
+def CK_FloatComplexToReal : I32EnumAttrCase<"float_complex_to_real", 17>;
+def CK_IntegralComplexToReal : I32EnumAttrCase<"int_complex_to_real", 18>;
+def CK_FloatComplexToBoolean : I32EnumAttrCase<"float_complex_to_bool", 19>;
+def CK_IntegralComplexToBoolean : I32EnumAttrCase<"int_complex_to_bool", 20>;
+def CK_FloatComplexCast : I32EnumAttrCase<"float_complex", 21>;
+def CK_FloatComplexToIntegralComplex
+ : I32EnumAttrCase<"float_complex_to_int_complex", 22>;
+def CK_IntegralComplexCast : I32EnumAttrCase<"int_complex", 23>;
+def CK_IntegralComplexToFloatComplex
+ : I32EnumAttrCase<"int_complex_to_float_complex", 24>;
+def CK_MemberPtrToBoolean : I32EnumAttrCase<"member_ptr_to_bool", 25>;
+
+def CastKind : I32EnumAttr<
+ "CastKind",
+ "cast kind",
+ [CK_IntegralToBoolean, CK_ArrayToPointerDecay, CK_IntegralCast,
+ CK_BitCast, CK_FloatingCast, CK_PtrToBoolean, CK_FloatToIntegral,
+ CK_IntegralToPointer, CK_PointerToIntegral, CK_FloatToBoolean,
+ CK_BooleanToIntegral, CK_IntegralToFloat, CK_BooleanToFloat,
+ CK_AddressSpaceConversion, CK_FloatToComplex, CK_IntegralToComplex,
+ CK_FloatComplexToReal, CK_IntegralComplexToReal, CK_FloatComplexToBoolean,
+ CK_IntegralComplexToBoolean, CK_FloatComplexCast,
+ CK_FloatComplexToIntegralComplex, CK_IntegralComplexCast,
+ CK_IntegralComplexToFloatComplex, CK_MemberPtrToBoolean]> {
+ let cppNamespace = "::cir";
+}
+
+def CastOp : CIR_Op<"cast",
+ [Pure,
+ DeclareOpInterfaceMethods<PromotableOpInterface>]> {
+ // FIXME: not all conversions are free of side effects.
+ let summary = "Conversion between values of different types";
+ let description = [{
+ Apply C/C++ usual conversions rules between values. Currently supported kinds:
+
+ - `array_to_ptrdecay`
+ - `bitcast`
+ - `integral`
+ - `int_to_bool`
+ - `int_to_float`
+ - `floating`
+ - `float_to_int`
+ - `float_to_bool`
+ - `ptr_to_int`
+ - `ptr_to_bool`
+ - `bool_to_int`
+ - `bool_to_float`
+ - `address_space`
+ - `float_to_complex`
+ - `int_to_complex`
+ - `float_complex_to_real`
+ - `int_complex_to_real`
+ - `float_complex_to_bool`
+ - `int_complex_to_bool`
+ - `float_complex`
+ - `float_complex_to_int_complex`
+ - `int_complex`
+ - `int_complex_to_float_complex`
+
+ This is effectively a subset of the rules from
+ `llvm-project/clang/include/clang/AST/OperationKinds.def`; but note that some
+ of the conversions aren't implemented in terms of `cir.cast`, `lvalue-to-rvalue`
+ for instance is modeled as a regular `cir.load`.
+
+ ```mlir
+ %4 = cir.cast (int_to_bool, %3 : i32), !cir.bool
+ ...
+ %x = cir.cast(array_to_ptrdecay, %0 : !cir.ptr<!cir.array<i32 x 10>>), !cir.ptr<i32>
+ ```
+ }];
+
+ let arguments = (ins CastKind:$kind, CIR_AnyType:$src);
+ let results = (outs CIR_AnyType:$result);
+
+ let assemblyFormat = [{
+ `(` $kind `,` $src `:` type($src) `)`
+ `,` type($result) attr-dict
+ }];
+
+ // The input and output types should match the cast kind.
+ let hasVerifier = 1;
+ let hasFolder = 1;
+}
+
//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index e8d3eff79d0b2..5fc9c73bdd05a 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -73,17 +73,29 @@ struct MissingFeatures {
static bool opFuncVisibility() { return false; }
// Misc
- static bool scalarConversionOpts() { return false; }
+ static bool cxxABI() { return false; }
static bool tryEmitAsConstant() { return false; }
static bool constructABIArgDirectExtend() { return false; }
static bool opGlobalViewAttr() { return false; }
static bool lowerModeOptLevel() { return false; }
static bool opTBAA() { return false; }
+ static bool opCmp() { return false; }
static bool objCLifetime() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool astVarDeclInterface() { return false; }
static bool stackSaveOp() { return false; }
static bool aggValueSlot() { return false; }
+ static bool scalableVectors() { return false; }
+ static bool fpConstraints() { return false; }
+ static bool sanitizers() { return false; }
+ static bool addHeapAllocSiteMetadata() { return false; }
+ static bool targetCodeGenInfoGetNullPointer() { return false; }
+
+ // Missing types
+ static bool dataMemberType() { return false; }
+ static bool methodType() { return false; }
+ static bool matrixType() { return false; }
+ static bool vectorType() { return false; }
};
} // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 01d56963883cc..76e6c53d9b6e2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
#include "CIRGenTypeCache.h"
+#include "clang/CIR/MissingFeatures.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
@@ -33,6 +34,14 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
llvm_unreachable("NYI: PPC double-double format for long double");
llvm_unreachable("Unsupported format for long double");
}
+
+ bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
+
+ // Creates constant nullptr for pointer type ty.
+ cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
+ assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
+ return create<cir::ConstantOp>(loc, ty, getConstPtrAttr(ty, 0));
+ }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index b9e56dc4123d6..df9447841800a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -36,6 +36,18 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
bool ira = false)
: cgf(cgf), builder(builder), ignoreResultAssign(ira) {}
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ bool TestAndClearIgnoreResultAssign() {
+ bool i = ignoreResultAssign;
+ ignoreResultAssign = false;
+ return i;
+ }
+
+ mlir::Type convertType(QualType t) { return cgf.convertType(t); }
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
@@ -68,14 +80,14 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {
- mlir::Type type = cgf.convertType(e->getType());
+ mlir::Type type = convertType(e->getType());
return builder.create<cir::ConstantOp>(
cgf.getLoc(e->getExprLoc()), type,
builder.getAttr<cir::IntAttr>(type, e->getValue()));
}
mlir::Value VisitFloatingLiteral(const FloatingLiteral *e) {
- mlir::Type type = cgf.convertType(e->getType());
+ mlir::Type type = convertType(e->getType());
assert(mlir::isa<cir::CIRFPTypeInterface>(type) &&
"expect floating-point type");
return builder.create<cir::ConstantOp>(
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
- mlir::Type type = cgf.convertType(e->getType());
+ mlir::Type type = convertType(e->getType());
return builder.create<cir::ConstantOp>(
cgf.getLoc(e->getExprLoc()), type,
builder.getCIRBoolAttr(e->getValue()));
}
- mlir::Value VisitCastExpr(CastExpr *E);
+ mlir::Value VisitCastExpr(CastExpr *e);
+
+ mlir::Value VisitExplicitCastExpr(ExplicitCastExpr *e) {
+ return VisitCastExpr(e);
+ }
+
+ /// Perform a pointer to boolean conversion.
+ mlir::Value emitPointerToBoolConversion(mlir::Value v, QualType qt) {
+ // TODO(cir): comparing the ptr to null is done when lowering CIR to LLVM.
+ // We might want to have a separate pass for these types of conversions.
+ return cgf.getBuilder().createPtrToBoolCast(v);
+ }
+
+ mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
+ auto boolTy = builder.getBoolTy();
+ return builder.create<cir::CastOp>(loc, boolTy,
+ cir::CastKind::float_to_bool, src);
+ }
+
+ mlir::Value emitIntToBoolConversion(mlir::Value srcVal, mlir::Location loc) {
+ // Because of the type rules of C, we often end up computing a
+ // logical value, then zero extending it to int, then wanting it
+ // as a logical value again.
+ // TODO: optimize this common case here or leave it for later
+ // CIR passes?
+ mlir::Type boolTy = convertType(cgf.getContext().BoolTy);
+ return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,
+ srcVal);
+ }
+
+ /// Convert the specified expression value to a boolean (!cir.bool) truth
+ /// value. This is equivalent to "Val != 0".
+ mlir::Value emitConversionToBool(mlir::Value src, QualType srcType,
+ mlir::Location loc) {
+ assert(srcType.isCanonical() && "EmitScalarConversion strips typedefs");
+
+ if (srcType->isRealFloatingType())
+ return emitFloatToBoolConversion(src, loc);
+
+ if ([[maybe_unused]] auto *mpt = llvm::dyn_cast<MemberPointerType>(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+ if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+ assert(::mlir::isa<cir::PointerType>(src.getType()));
+ return emitPointerToBoolConversion(src, srcType);
+ }
+
+ // Emit a conversion from the specified type to the specified destination
+ // type, both of which are CIR scalar types.
+ struct ScalarConversionOpts {
+ bool treatBooleanAsSigned;
+ bool emitImplicitIntegerTruncationChecks;
+ bool emitImplicitIntegerSignChangeChecks;
+
+ ScalarConversionOpts()
+ : treatBooleanAsSigned(false),
+ emitImplicitIntegerTruncationChecks(false),
+ emitImplicitIntegerSignChangeChecks(false) {}
+
+ ScalarConversionOpts(clang::SanitizerSet sanOpts)
+ : treatBooleanAsSigned(false),
+ emitImplicitIntegerTruncationChecks(
+ sanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)),
+ emitImplicitIntegerSignChangeChecks(
+ sanOpts.has(SanitizerKind::ImplicitIntegerSignChange)) {}
+ };
+
+ // Conversion from bool, integral, or floating-point to integral or
+ // floating-point. Conversions involving other types are handled elsewhere.
+ // Conversion to bool is handled elsewhere because that's a comparison against
+ // zero, not a simple cast. This handles both individual scalars and vectors.
+ mlir::Value emitScalarCast(mlir::Value src, QualType srcType,
+ QualType dstType, mlir::Type srcTy,
+ mlir::Type dstTy, ScalarConversionOpts opts) {
+ assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
+ "Internal error: matrix types not handled by this function.");
+ if (mlir::isa<mlir::IntegerType>(srcTy) ||
+ mlir::isa<mlir::IntegerType>(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+ mlir::Type fullDstTy = dstTy;
+ assert(!cir::MissingFeatures::vectorType());
+
+ std::optional<cir::CastKind> castKind;
+
+ if (mlir::isa<cir::BoolType>(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+ cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+ castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ castKind = cir::CastKind::bool_to_float;
+ } else {
+ llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+ } else if (cgf.getBuilder().isInt(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+ castKind = cir::CastKind::integral;
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ castKind = cir::CastKind::int_to_float;
+ } else {
+ llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+ // If we can't recognize overflow as undefined behavior, assume that
+ // overflow saturates. This protects against normal optimizations if we
+ // are compiling with non-standard FP semantics.
+ if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
+ cgf.getCIRGenModule().errorNYI("strict float cast overflow");
+ assert(!cir::MissingFeatures::fpConstraints());
+ castKind = cir::CastKind::float_to_int;
+ } else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ cgf.getCIRGenModule().errorNYI("floating point casts");
+ } else {
+ llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+ } else {
+ llvm_unreachable("Internal error: Cast from unexpected type");
+ }
+
+ assert(castKind.has_value() && "Internal error: CastKind not set.");
+ return builder.create<cir::CastOp>(src.getLoc(), fullDstTy, *castKind, src);
+ }
/// Emit a conversion from the specified type to the specified destination
/// type, both of which are CIR scalar types.
/// TODO: do we need ScalarConversionOpts here? Should be done in another
/// pass.
- mlir::Value emitScalarConversion(mlir::Value src, QualType srcType,
- QualType dstType, SourceLocation loc) {
- // No sort of type conversion is implemented yet, but the path for implicit
- // paths goes through here even if the type isn't being changed.
+ mlir::Value
+ emitScalarConversion(mlir::Value src, QualType srcType, QualType dstType,
+ SourceLocation loc,
+ ScalarConversionOpts opts = ScalarConversionOpts()) {
+ // All conversions involving fixed point types should be handled by the
+ // emitFixedPoint family functions. This is done to prevent bloating up
+ // this function more, and although fixed point numbers are represented by
+ // integers, we do not want to follow any logic that assumes they should be
+ // treated as integers.
+ // TODO(leonardchan): When necessary, add another if statement checking for
+ // conversions to fixed point types from other types.
+ // conversions to fixed point types from other types.
+ if (srcType->isFixedPointType())
+ cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
+ else if (dstType->isFixedPointType())
+ cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
+
srcType = srcType.getCanonicalType();
dstType = dstType.getCanonicalType();
- if (srcType == dstType)
+ if (srcType == dstType) {
+ if (opts.emitImplicitIntegerSignChangeChecks)
+ cgf.getCIRGenModule().errorNYI(loc,
+ "implicit integer sign change checks");
return src;
+ }
+
+ if (dstType->isVoidType())
+ return nullptr;
+
+ mlir::Type srcTy = src.getType();
+
+ // Handle conversions to bool first, they are special: comparisons against
+ // 0.
+ if (dstType->isBooleanType())
+ return emitConversionToBool(src, srcType, cgf.getLoc(loc));
+
+ mlir::Type dstTy = convertType(dstType);
+
+ if (srcType->isHalfType() &&
+ !cgf.getContext().getLangOpts().NativeHalfType) {
+ // Cast to FP using the intrinsic if the half type itself isn't supported.
+ if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
+ cgf.getCIRGenModule().errorNYI(loc,
+ "cast via llvm.convert.from.fp16");
+ } else {
+ // Cast to other types through float, using either the intrinsic or
+ // FPExt, depending on whether the half type itself is supported (as
+ // opposed to operations on half, available with NativeHalfType).
+ if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
+ cgf.getCIRGenModule().errorNYI(loc,
+ "cast via llvm.convert.from.fp16");
+ } else {
+ src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating,
+ src, cgf.FloatTy);
+ }
+ srcType = cgf.getContext().FloatTy;
+ srcTy = cgf.FloatTy;
+ }
+ }
+
+ // TODO(cir): LLVM codegen ignore conversions like int -> uint,
+ // is there anything to be done for CIR here?
+ if (srcTy == dstTy) {
+ if (opts.emitImplicitIntegerSignChangeChecks)
+ cgf.getCIRGenModule().errorNYI(loc,
+ "implicit integer sign change checks");
+ return src;
+ }
+
+ // Handle pointer conversions next: pointers can only be converted to/from
+ // other pointers and integers. Check for pointer types in terms of LLVM, as
+ // some native types (like Obj-C id) may map to a pointer type.
+ if (auto dstPT = dyn_cast<cir::PointerType>(dstTy)) {
+ cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
+ }
+
+ if (isa<cir::PointerType>(srcTy)) {
+ // Must be an ptr to int cast.
+ assert(isa<cir::IntType>(dstTy) && "not ptr->int?");
+ return builder.createPtrToInt(src, dstTy);
+ }
+
+ // A scalar can be splatted to an extended vector of the same element type
+ if (dstType->isExtVectorType() && !srcType->isVectorType()) {
+ // Sema should add casts to make sure that the source expression's type
+ // is the same as the vector's element type (sans qualifiers)
+ assert(dstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
+ srcType.getTypePtr() &&
+ "Splatted expr doesn't match with vector element type?");
+
+ llvm_unreachable("not implemented");
+ }
+
+ if (srcType->isMatrixType() && dstType->isMatrixType())
+ cgf.getCIRGenModule().errorNYI(loc,
+ "matrix type to matrix type conversion");
+ assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
+ "Internal error: conversion between matrix type and scalar type");
+
+ // Finally, we have the arithmetic types or vectors of arithmetic types.
+ mlir::Value res = nullptr;
+ mlir::Type resTy = dstTy;
+
+ res = emitScalarCast(src, srcType, dstType, srcTy, dstTy, opts);
+
+ if (dstTy != resTy) {
+ if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
+ cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");
+ } else {
+ res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
+ resTy);
+ }
+ }
+
+ if (opts.emitImplicitIntegerTruncationChecks)
+ cgf.getCIRGenModule().errorNYI(loc, "implicit integer truncation checks");
+
+ if (opts.emitImplicitIntegerSignChangeChecks)
+ cgf.getCIRGenModule().errorNYI(loc,
+ "implicit integer sign change checks");
+
+ return res;
cgf.getCIRGenModule().errorNYI(loc,
"emitScalarConversion for unequal types");
@@ -121,6 +373,13 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr *e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));
}
+[[maybe_unused]] static bool MustVisitNullValue(const Expr *e) {
+ // If a null pointer expression's type is the C++0x nullptr_t, then
+ // it's not necessarily a simple constant and it must be evaluated
+ // for its potential side effects.
+ return e->getType()->isNullPtrType();
+}
+
// Emit code for an explicit or implicit cast. Implicit
// casts have to handle a more broad range of conversions than explicit
// casts, as they handle things like function to ptr-to-function decay
@@ -130,17 +389,136 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
QualType destTy = ce->getType();
CastKind kind = ce->getCastKind();
+ // These cases are generally not written to ignore the result of evaluating
+ // their sub-expressions, so we clear this now.
+ [[maybe_unused]] bool ignored = TestAndClearIgnoreResultAssign();
+
switch (kind) {
+ case clang::CK_Dependent:
+ llvm_unreachable("dependent cast kind in CIR gen!");
+ case clang::CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_BitCast: {
+ auto src = Visit(const_cast<Expr *>(e));
+ mlir::Type dstTy = convertType(destTy);
+
+ assert(!cir::MissingFeatures::addressSpace());
+
+ if (cgf.sanOpts.has(SanitizerKind::CFIUnrelatedCast))
+ cgf.getCIRGenModule().errorNYI(e->getSourceRange(), "sanitizer support");
+
+ if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
+ cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ "strict vtable pointers");
+
+ // Update heapallocsite metadata when there is an explicit pointer cast.
+ assert(!cir::MissingFeatures::addHeapAllocSiteMetadata());
+
+ // If Src is a fixed vector and Dst is a scalable vector, and both have the
+ // same element type, use the llvm.vector.insert intrinsic to perform the
+ // bitcast.
+ assert(!cir::MissingFeatures::scalableVectors());
+
+ // If Src is a scalable vector and Dst is a fixed vector, and both have the
+ // same element type, use the llvm.vector.extract intrinsic to perform the
+ // bitcast.
+ assert(!cir::MissingFeatures::scalableVectors());
+
+ // Perform VLAT <-> VLST bitcast through memory.
+ // TODO: since the llvm.experimental.vector.{insert,extract} intrinsics
+ // require the element types of the vectors to be the same, we
+ // need to keep this around for bitcasts between VLAT <-> VLST where
+ // the element types of the vectors are not the same, until we figure
+ // out a better way of doing these casts.
+ assert(!cir::MissingFeatures::scalableVectors());
+
+ return cgf.getBuilder().createBitcast(cgf.getLoc(e->getSourceRange()), src,
+ dstTy);
+ }
+
+ case CK_AtomicToNonAtomic:
+ cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ "CastExpr: ", ce->getCastKindName());
+ break;
+ case CK_NonAtomicToAtomic:
+ case CK_UserDefinedConversion:
+ return Visit(const_cast<Expr *>(e));
+ case CK_NoOp: {
+ auto v = Visit(const_cast<Expr *>(e));
+ if (v) {
+ // CK_NoOp can model a pointer qualification conversion, which can remove
+ // an array bound and change the IR type.
+ // FIXME: Once pointee types are removed from IR, remove this.
+ auto t = convertType(destTy);
+ if (t != v.getType())
+ cgf.getCIRGenModule().errorNYI("pointer qualification conversion");
+ }
+ return v;
+ }
+
+ case CK_NullToPointer: {
+ if (MustVisitNullValue(e))
+ cgf.getCIRGenModule().errorNYI(
+ e->getSourceRange(), "ignored expression on null to pointer cast");
+
+ // Note that DestTy is used as the MLIR type instead of a custom
+ // nullptr type.
+ mlir::Type ty = convertType(destTy);
+ return builder.getNullPtr(ty, cgf.getLoc(e->getExprLoc()));
+ }
+
case CK_LValueToRValue:
assert(cgf.getContext().hasSameUnqualifiedType(e->getType(), destTy));
assert(e->isGLValue() && "lvalue-to-rvalue applied to r-value!");
return Visit(const_cast<Expr *>(e));
case CK_IntegralCast: {
- assert(!cir::MissingFeatures::scalarConversionOpts());
+ ScalarConversionOpts opts;
+ if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
+ if (!ice->isPartOfExplicitCast())
+ opts = ScalarConversionOpts(cgf.sanOpts);
+ }
return emitScalarConversion(Visit(e), e->getType(), destTy,
- ce->getExprLoc());
+ ce->getExprLoc(), opts);
+ }
+
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexCast:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ case CK_FloatingComplexToIntegralComplex:
+ llvm_unreachable("scalar cast to non-scalar value");
+
+ case CK_PointerToIntegral: {
+ assert(!destTy->isBooleanType() && "bool should use PointerToBool");
+ if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
+ llvm_unreachable("NYI");
+ return builder.createPtrToInt(Visit(e), convertType(destTy));
+ }
+ case CK_ToVoid:
+ cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ "ignored expression on void cast");
+ return nullptr;
+
+ case CK_IntegralToBoolean:
+ return emitIntToBoolConversion(Visit(e), cgf.getLoc(ce->getSourceRange()));
+
+ case CK_PointerToBoolean:
+ return emitPointerToBoolConversion(Visit(e), e->getType());
+ case CK_FloatingToBoolean:
+ return emitFloatToBoolConversion(Visit(e), cgf.getLoc(e->getExprLoc()));
+ case CK_MemberPointerToBoolean: {
+ mlir::Value memPtr = Visit(e);
+ return builder.createCast(cgf.getLoc(ce->getSourceRange()),
+ cir::CastKind::member_ptr_to_bool, memPtr,
+ cgf.convertType(destTy));
}
+ return nullptr;
default:
cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5ab882666f3e0..33868cd7b3d50 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -73,6 +73,9 @@ class CIRGenFunction : public CIRGenTypeCache {
return &fn.getRegion().front();
}
+ /// Sanitizers enabled for this function.
+ clang::SanitizerSet sanOpts;
+
mlir::Type convertTypeForMem(QualType T);
mlir::Type convertType(clang::QualType T);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d041791770d82..6e45303a4f287 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -182,6 +182,176 @@ OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) {
return getValue();
}
+//===----------------------------------------------------------------------===//
+// CastOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::CastOp::verify() {
+ auto resType = getResult().getType();
+ auto srcType = getSrc().getType();
+
+ switch (getKind()) {
+ case cir::CastKind::int_to_bool: {
+ if (!mlir::isa<cir::BoolType>(resType))
+ return emitOpError() << "requires !cir.bool type for result";
+ if (!mlir::isa<cir::IntType>(srcType))
+ return emitOpError() << "requires !cir.int type for source";
+ return success();
+ }
+ case cir::CastKind::ptr_to_bool: {
+ if (!mlir::isa<cir::BoolType>(resType))
+ return emitOpError() << "requires !cir.bool type for result";
+ if (!mlir::isa<cir::PointerType>(srcType))
+ return emitOpError() << "requires !cir.ptr type for source";
+ return success();
+ }
+ case cir::CastKind::integral: {
+ if (!mlir::isa<cir::IntType>(resType))
+ return emitOpError() << "requires !cir.int type for result";
+ if (!mlir::isa<cir::IntType>(srcType))
+ return emitOpError() << "requires !cir.int type for source";
+ return success();
+ }
+ case cir::CastKind::bitcast: {
+ // Handle the pointer types first.
+ auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);
+ auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);
+
+ if (srcPtrTy && resPtrTy) {
+ return success();
+ }
+
+ return success();
+ }
+ case cir::CastKind::floating: {
+ if (!mlir::isa<cir::CIRFPTypeInterface>(srcType) ||
+ !mlir::isa<cir::CIRFPTypeInterface>(resType))
+ return emitOpError() << "requires !cir.float type for source and result";
+ return success();
+ }
+ case cir::CastKind::float_to_int: {
+ if (!mlir::isa<cir::CIRFPTypeInterface>(srcType))
+ return emitOpError() << "requires !cir.float type for source";
+ if (!mlir::dyn_cast<cir::IntType>(resType))
+ return emitOpError() << "requires !cir.int type for result";
+ return success();
+ }
+ case cir::CastKind::int_to_ptr: {
+ if (!mlir::dyn_cast<cir::IntType>(srcType))
+ return emitOpError() << "requires !cir.int type for source";
+ if (!mlir::dyn_cast<cir::PointerType>(resType))
+ return emitOpError() << "requires !cir.ptr type for result";
+ return success();
+ }
+ case cir::CastKind::ptr_to_int: {
+ if (!mlir::dyn_cast<cir::PointerType>(srcType))
+ return emitOpError() << "requires !cir.ptr type for source";
+ if (!mlir::dyn_cast<cir::IntType>(resType))
+ return emitOpError() << "requires !cir.int type for result";
+ return success();
+ }
+ case cir::CastKind::float_to_bool: {
+ if (!mlir::isa<cir::CIRFPTypeInterface>(srcType))
+ return emitOpError() << "requires !cir.float type for source";
+ if (!mlir::isa<cir::BoolType>(resType))
+ return emitOpError() << "requires !cir.bool type for result";
+ return success();
+ }
+ case cir::CastKind::bool_to_int: {
+ if (!mlir::isa<cir::BoolType>(srcType))
+ return emitOpError() << "requires !cir.bool type for source";
+ if (!mlir::isa<cir::IntType>(resType))
+ return emitOpError() << "requires !cir.int type for result";
+ return success();
+ }
+ case cir::CastKind::int_to_float: {
+ if (!mlir::isa<cir::IntType>(srcType))
+ return emitOpError() << "requires !cir.int type for source";
+ if (!mlir::isa<cir::CIRFPTypeInterface>(resType))
+ return emitOpError() << "requires !cir.float type for result";
+ return success();
+ }
+ case cir::CastKind::bool_to_float: {
+ if (!mlir::isa<cir::BoolType>(srcType))
+ return emitOpError() << "requires !cir.bool type for source";
+ if (!mlir::isa<cir::CIRFPTypeInterface>(resType))
+ return emitOpError() << "requires !cir.float type for result";
+ return success();
+ }
+ case cir::CastKind::address_space: {
+ auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);
+ auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);
+ if (!srcPtrTy || !resPtrTy)
+ return emitOpError() << "requires !cir.ptr type for source and result";
+ if (srcPtrTy.getPointee() != resPtrTy.getPointee())
+ return emitOpError() << "requires two types differ in addrspace only";
+ return success();
+ }
+ }
+
+ llvm_unreachable("Unknown CastOp kind?");
+}
+
+static bool isIntOrBoolCast(cir::CastOp op) {
+ auto kind = op.getKind();
+ return kind == cir::CastKind::bool_to_int ||
+ kind == cir::CastKind::int_to_bool || kind == cir::CastKind::integral;
+}
+
+static Value tryFoldCastChain(cir::CastOp op) {
+ cir::CastOp head = op, tail = op;
+
+ while (op) {
+ if (!isIntOrBoolCast(op))
+ break;
+ head = op;
+ op = dyn_cast_or_null<cir::CastOp>(head.getSrc().getDefiningOp());
+ }
+
+ if (head == tail)
+ return {};
+
+ // if bool_to_int -> ... -> int_to_bool: take the bool
+ // as we had it was before all casts
+ if (head.getKind() == cir::CastKind::bool_to_int &&
+ tail.getKind() == cir::CastKind::int_to_bool)
+ return head.getSrc();
+
+ // if int_to_bool -> ... -> int_to_bool: take the result
+ // of the first one, as no other casts (and ext casts as well)
+ // don't change the first result
+ if (head.getKind() == cir::CastKind::int_to_bool &&
+ tail.getKind() == cir::CastKind::int_to_bool)
+ return head.getResult();
+
+ return {};
+}
+
+OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
+ if (getSrc().getType() == getResult().getType()) {
+ switch (getKind()) {
+ case cir::CastKind::integral: {
+ // TODO: for sign differences, it's possible in certain conditions to
+ // create a new attribute that's capable of representing the source.
+ llvm::SmallVector<mlir::OpFoldResult, 1> foldResults;
+ auto foldOrder = getSrc().getDefiningOp()->fold(foldResults);
+ if (foldOrder.succeeded() && mlir::isa<mlir::Attribute>(foldResults[0]))
+ return mlir::cast<mlir::Attribute>(foldResults[0]);
+ return {};
+ }
+ case cir::CastKind::bitcast:
+ case cir::CastKind::address_space:
+ case cir::CastKind::float_complex:
+ case cir::CastKind::int_complex: {
+ return getSrc();
+ }
+ default:
+ return {};
+ }
+ }
+ return tryFoldCastChain(*this);
+}
+
//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
index 5e44837979af3..9cd5c54e6c19e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
@@ -15,6 +15,15 @@
using namespace mlir;
+/// Conditions the deletion of the operation to the removal of all its uses.
+static bool forwardToUsers(Operation *op,
+ SmallVectorImpl<OpOperand *> &newBlockingUses) {
+ for (Value result : op->getResults())
+ for (OpOperand &use : result.getUses())
+ newBlockingUses.push_back(&use);
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Interfaces for AllocaOp
//===----------------------------------------------------------------------===//
@@ -108,3 +117,21 @@ DeletionKind cir::StoreOp::removeBlockingUses(
const DataLayout &dataLayout) {
return DeletionKind::Delete;
}
+
+//===----------------------------------------------------------------------===//
+// Interfaces for CastOp
+//===----------------------------------------------------------------------===//
+
+bool cir::CastOp::canUsesBeRemoved(
+ const SmallPtrSetImpl<OpOperand *> &blockingUses,
+ SmallVectorImpl<OpOperand *> &newBlockingUses,
+ const DataLayout &dataLayout) {
+ if (getKind() == cir::CastKind::bitcast)
+ return forwardToUsers(*this, newBlockingUses);
+ return false;
+}
+
+DeletionKind cir::CastOp::removeBlockingUses(
+ const SmallPtrSetImpl<OpOperand *> &blockingUses, OpBuilder &builder) {
+ return DeletionKind::Delete;
+}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 79ec0696eb180..4125525583f33 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -42,6 +42,21 @@ using namespace llvm;
namespace cir {
namespace direct {
+//===----------------------------------------------------------------------===//
+// Helper Methods
+//===----------------------------------------------------------------------===//
+
+namespace {
+/// If the given type is a vector type, return the vector's element type.
+/// Otherwise return the given type unchanged.
+// TODO(cir): Return the vector element type once we have support for vectors
+// instead of the identity type.
+mlir::Type elementTypeIfVector(mlir::Type type) {
+ assert(!cir::MissingFeatures::vectorType());
+ return type;
+}
+} // namespace
+
/// Given a type convertor and a data layout, convert the given type to a type
/// that is suitable for memory operations. For example, this can be used to
/// lower cir.bool accesses to i8.
@@ -142,6 +157,24 @@ mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {
llvm_unreachable("Unknown CIR linkage type");
}
+static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
+ mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
+ bool isUnsigned, uint64_t cirSrcWidth,
+ uint64_t cirDstIntWidth) {
+ if (cirSrcWidth == cirDstIntWidth)
+ return llvmSrc;
+
+ auto loc = llvmSrc.getLoc();
+ if (cirSrcWidth < cirDstIntWidth) {
+ if (isUnsigned)
+ return rewriter.create<mlir::LLVM::ZExtOp>(loc, llvmDstIntTy, llvmSrc);
+ return rewriter.create<mlir::LLVM::SExtOp>(loc, llvmDstIntTy, llvmSrc);
+ }
+
+ // Otherwise truncate
+ return rewriter.create<mlir::LLVM::TruncOp>(loc, llvmDstIntTy, llvmSrc);
+}
+
class CIRAttrToValue {
public:
CIRAttrToValue(mlir::Operation *parentOp,
@@ -247,6 +280,179 @@ struct ConvertCIRToLLVMPass
StringRef getArgument() const override { return "cir-flat-to-llvm"; }
};
+mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {
+ return getTypeConverter()->convertType(ty);
+}
+
+mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
+ cir::CastOp castOp, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ // For arithmetic conversions, LLVM IR uses the same instruction to convert
+ // both individual scalars and entire vectors. This lowering pass handles
+ // both situations.
+
+ switch (castOp.getKind()) {
+ case cir::CastKind::array_to_ptrdecay: {
+ const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType());
+ auto sourceValue = adaptor.getOperands().front();
+ auto targetType = convertTy(ptrTy);
+ auto elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
+ ptrTy.getPointee());
+ auto offset = llvm::SmallVector<mlir::LLVM::GEPArg>{0};
+ rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
+ castOp, targetType, elementTy, sourceValue, offset);
+ break;
+ }
+ case cir::CastKind::int_to_bool:
+ assert(!cir::MissingFeatures::opCmp());
+ break;
+ case cir::CastKind::integral: {
+ auto srcType = castOp.getSrc().getType();
+ auto dstType = castOp.getResult().getType();
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstType = getTypeConverter()->convertType(dstType);
+ cir::IntType srcIntType =
+ mlir::cast<cir::IntType>(elementTypeIfVector(srcType));
+ cir::IntType dstIntType =
+ mlir::cast<cir::IntType>(elementTypeIfVector(dstType));
+ rewriter.replaceOp(castOp, getLLVMIntCast(rewriter, llvmSrcVal, llvmDstType,
+ srcIntType.isUnsigned(),
+ srcIntType.getWidth(),
+ dstIntType.getWidth()));
+ break;
+ }
+ case cir::CastKind::floating: {
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy =
+ getTypeConverter()->convertType(castOp.getResult().getType());
+
+ auto srcTy = elementTypeIfVector(castOp.getSrc().getType());
+ auto dstTy = elementTypeIfVector(castOp.getResult().getType());
+
+ if (!mlir::isa<cir::CIRFPTypeInterface>(dstTy) ||
+ !mlir::isa<cir::CIRFPTypeInterface>(srcTy))
+ return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy;
+
+ auto getFloatWidth = [](mlir::Type ty) -> unsigned {
+ return mlir::cast<cir::CIRFPTypeInterface>(ty).getWidth();
+ };
+
+ if (getFloatWidth(srcTy) > getFloatWidth(dstTy))
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FPTruncOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ else
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FPExtOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::int_to_ptr: {
+ auto dstTy = mlir::cast<cir::PointerType>(castOp.getType());
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::ptr_to_int: {
+ auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::float_to_bool: {
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto kind = mlir::LLVM::FCmpPredicate::une;
+
+ // Check if float is not equal to zero.
+ auto zeroFloat = rewriter.create<mlir::LLVM::ConstantOp>(
+ castOp.getLoc(), llvmSrcVal.getType(),
+ mlir::FloatAttr::get(llvmSrcVal.getType(), 0.0));
+
+ // Extend comparison result to either bool (C++) or int (C).
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(castOp, kind, llvmSrcVal,
+ zeroFloat);
+
+ return mlir::success();
+ }
+ case cir::CastKind::bool_to_int: {
+ auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType());
+ auto llvmDstTy =
+ mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy));
+ if (llvmSrcTy.getWidth() == llvmDstTy.getWidth())
+ rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ else
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::bool_to_float: {
+ auto dstTy = castOp.getType();
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::int_to_float: {
+ auto dstTy = castOp.getType();
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getSrc().getType()))
+ .isSigned())
+ rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ else
+ rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::float_to_int: {
+ auto dstTy = castOp.getType();
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ if (mlir::cast<cir::IntType>(
+ elementTypeIfVector(castOp.getResult().getType()))
+ .isSigned())
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ else
+ rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ return mlir::success();
+ }
+ case cir::CastKind::bitcast:
+ assert(!MissingFeatures::cxxABI());
+ assert(!MissingFeatures::dataMemberType());
+ break;
+ case cir::CastKind::ptr_to_bool:
+ assert(!cir::MissingFeatures::opCmp());
+ break;
+ case cir::CastKind::address_space: {
+ auto dstTy = castOp.getType();
+ auto llvmSrcVal = adaptor.getOperands().front();
+ auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(castOp, llvmDstTy,
+ llvmSrcVal);
+ break;
+ }
+ case cir::CastKind::member_ptr_to_bool:
+ assert(!MissingFeatures::cxxABI());
+ assert(!MissingFeatures::methodType());
+ break;
+ default: {
+ return castOp.emitError("Unhandled cast kind: ")
+ << castOp.getKindAttrName();
+ }
+ }
+
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
cir::AllocaOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -696,6 +902,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);
patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
+ patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
patterns.add<CIRToLLVMConstantOpLowering>(converter, patterns.getContext(),
dl);
patterns.add<
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index d090bbe4f2e10..5fc248778e9bc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -22,6 +22,22 @@ namespace direct {
mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
+class CIRToLLVMCastOpLowering : public mlir::OpConversionPattern<cir::CastOp> {
+ mlir::DataLayout const &dataLayout;
+
+ mlir::Type convertTy(mlir::Type ty) const;
+
+public:
+ CIRToLLVMCastOpLowering(const mlir::TypeConverter &typeConverter,
+ mlir::MLIRContext *context,
+ mlir::DataLayout const &dataLayout)
+ : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {}
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::CastOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMReturnOpLowering
: public mlir::OpConversionPattern<cir::ReturnOp> {
public:
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
new file mode 100644
index 0000000000000..29d34e87c398d
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+unsigned char cxxstaticcast_0(unsigned int x) {
+ return static_cast<unsigned char>(x);
+}
+
+// CHECK: cir.func @cxxstaticcast_0
+// CHECK: %0 = cir.alloca !cir.int<u, 32>, !cir.ptr<!cir.int<u, 32>>, ["x", init] {alignment = 4 : i64}
+// CHECK: cir.store %arg0, %0 : !cir.int<u, 32>, !cir.ptr<!cir.int<u, 32>>
+// CHECK: %1 = cir.load %0 : !cir.ptr<!cir.int<u, 32>>, !cir.int<u, 32>
+// CHECK: %2 = cir.cast(integral, %1 : !cir.int<u, 32>), !cir.int<u, 8>
+// CHECK: cir.return %2 : !cir.int<u, 8>
+// CHECK: }
+
+
+int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) {
+// CHECK: cir.func @cStyleCasts_0
+
+ char a = (char)x1; // truncate
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<s, 8>
+
+ short b = (short)x2; // truncate with sign
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<s, 32>), !cir.int<s, 16>
+
+ long long c = (long long)x1; // zero extend
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<s, 64>
+
+ long long d = (long long)x2; // sign extend
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<s, 32>), !cir.int<s, 64>
+
+ unsigned ui = (unsigned)x2; // sign drop
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<s, 32>), !cir.int<u, 32>
+
+ int si = (int)x1; // sign add
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<s, 32>
+
+ unsigned uu = (unsigned)x1; // should not be generated
+ // CHECK-NOT: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<u, 32>
+
+ bool ib = (bool)x1; // No checking, because this isn't a regular cast.
+
+ int bi = (int)ib; // bool to int
+ // CHECK: %{{[0-9]+}} = cir.cast(bool_to_int, %{{[0-9]+}} : !cir.bool), !cir.int<s, 32>
+
+ return 0;
+}
+
+bool cptr(void *d) {
+ bool x = d;
+ return x;
+}
+
+// CHECK: cir.func @cptr(%arg0: !cir.ptr<!cir.void>
+// CHECK: %0 = cir.alloca !cir.ptr<!cir.void>, !cir.ptr<!cir.ptr<!cir.void>>, ["d", init] {alignment = 8 : i64}
+
+// CHECK: %2 = cir.load %0 : !cir.ptr<!cir.ptr<!cir.void>>, !cir.ptr<!cir.void>
+// CHECK: %3 = cir.cast(ptr_to_bool, %2 : !cir.ptr<!cir.void>), !cir.bool
diff --git a/clang/test/CIR/IR/cast.cir b/clang/test/CIR/IR/cast.cir
new file mode 100644
index 0000000000000..de3cc37467eff
--- /dev/null
+++ b/clang/test/CIR/IR/cast.cir
@@ -0,0 +1,23 @@
+// RUN: cir-opt %s | cir-opt | FileCheck %s
+!s32i = !cir.int<s, 32>
+
+module {
+ cir.func @yolo(%arg0 : !s32i) {
+ %a = cir.cast (int_to_bool, %arg0 : !s32i), !cir.bool
+
+ %0 = cir.const #cir.int<0> : !s32i
+ cir.return
+ }
+
+ cir.func @bitcast(%p: !cir.ptr<!s32i>) {
+ %0 = cir.cast(bitcast, %p : !cir.ptr<!s32i>), !cir.ptr<f32>
+ cir.return
+ }
+}
+
+// CHECK: cir.func @yolo(%arg0: !cir.int<s, 32>)
+// CHECK: %0 = cir.cast(int_to_bool, %arg0 : !cir.int<s, 32>), !cir.bool
+// CHECK: %1 = cir.const #cir.int<0> : !cir.int<s, 32>
+
+// CHECK: cir.func @bitcast
+// CHECK: %0 = cir.cast(bitcast, %arg0 : !cir.ptr<!cir.int<s, 32>>), !cir.ptr<f32>
diff --git a/clang/test/CIR/Lowering/cast.cir b/clang/test/CIR/Lowering/cast.cir
new file mode 100644
index 0000000000000..b2d0a6d42eeb1
--- /dev/null
+++ b/clang/test/CIR/Lowering/cast.cir
@@ -0,0 +1,92 @@
+// RUN: cir-opt %s -cir-to-llvm -o %t.cir
+// RUN: FileCheck %s --input-file=%t.cir
+
+!s16i = !cir.int<s, 16>
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+!s8i = !cir.int<s, 8>
+!u32i = !cir.int<u, 32>
+!u8i = !cir.int<u, 8>
+!u64i = !cir.int<u, 64>
+
+module {
+ cir.func @cStyleCasts(%arg0: !u32i, %arg1: !s32i, %arg2: !cir.float, %arg3: !cir.double) -> !s32i {
+ // CHECK: llvm.func @cStyleCasts
+ %0 = cir.alloca !u32i, !cir.ptr<!u32i>, ["x1", init] {alignment = 4 : i64}
+ %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x2", init] {alignment = 4 : i64}
+ %20 = cir.alloca !s16i, !cir.ptr<!s16i>, ["x4", init] {alignment = 2 : i64}
+ %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
+ %3 = cir.alloca !s8i, !cir.ptr<!s8i>, ["a", init] {alignment = 1 : i64}
+ %4 = cir.alloca !s16i, !cir.ptr<!s16i>, ["b", init] {alignment = 2 : i64}
+ %5 = cir.alloca !s64i, !cir.ptr<!s64i>, ["c", init] {alignment = 8 : i64}
+ %6 = cir.alloca !s64i, !cir.ptr<!s64i>, ["d", init] {alignment = 8 : i64}
+ %8 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["e", init] {alignment = 8 : i64}
+ cir.store %arg0, %0 : !u32i, !cir.ptr<!u32i>
+ cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i>
+
+ // Integer casts.
+ %9 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %10 = cir.cast(integral, %9 : !u32i), !s8i
+ // CHECK: %{{[0-9]+}} = llvm.trunc %{{[0-9]+}} : i32 to i8
+ cir.store %10, %3 : !s8i, !cir.ptr<!s8i>
+ %11 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %12 = cir.cast(integral, %11 : !s32i), !s16i
+ // CHECK: %{{[0-9]+}} = llvm.trunc %{{[0-9]+}} : i32 to i16
+ cir.store %12, %4 : !s16i, !cir.ptr<!s16i>
+ %13 = cir.load %0 : !cir.ptr<!u32i>, !u32i
+ %14 = cir.cast(integral, %13 : !u32i), !s64i
+ // CHECK: %{{[0-9]+}} = llvm.zext %{{[0-9]+}} : i32 to i64
+ cir.store %14, %5 : !s64i, !cir.ptr<!s64i>
+ %15 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ %16 = cir.cast(integral, %15 : !s32i), !s64i
+ // CHECK: %{{[0-9]+}} = llvm.sext %{{[0-9]+}} : i32 to i64
+ %30 = cir.cast(integral, %arg1 : !s32i), !u32i
+ // Should not produce a cast.
+ %32 = cir.cast(integral, %arg0 : !u32i), !s32i
+ // Should not produce a cast.
+ %21 = cir.load %20 : !cir.ptr<!s16i>, !s16i
+ %22 = cir.cast(integral, %21 : !s16i), !u64i
+ // CHECK: %[[TMP:[0-9]+]] = llvm.sext %{{[0-9]+}} : i16 to i64
+
+ // Pointer casts.
+ cir.store %16, %6 : !s64i, !cir.ptr<!s64i>
+ %23 = cir.cast(int_to_ptr, %22 : !u64i), !cir.ptr<!u8i>
+ // CHECK: %[[TMP2:[0-9]+]] = llvm.inttoptr %[[TMP]] : i64 to !llvm.ptr
+ %24 = cir.cast(ptr_to_int, %23 : !cir.ptr<!u8i>), !s32i
+ // CHECK: %{{[0-9]+}} = llvm.ptrtoint %[[TMP2]] : !llvm.ptr to i32
+ %29 = cir.cast(ptr_to_bool, %23 : !cir.ptr<!u8i>), !cir.bool
+
+ // Floating point casts.
+ %25 = cir.cast(int_to_float, %arg1 : !s32i), !cir.float
+ // CHECK: %{{.+}} = llvm.sitofp %{{.+}} : i32 to f32
+ %26 = cir.cast(int_to_float, %arg0 : !u32i), !cir.float
+ // CHECK: %{{.+}} = llvm.uitofp %{{.+}} : i32 to f32
+ %27 = cir.cast(float_to_int, %arg2 : !cir.float), !s32i
+ // CHECK: %{{.+}} = llvm.fptosi %{{.+}} : f32 to i32
+ %28 = cir.cast(float_to_int, %arg2 : !cir.float), !u32i
+ // CHECK: %{{.+}} = llvm.fptoui %{{.+}} : f32 to i32
+ %18 = cir.const #cir.int<0> : !s32i
+ // CHECK: %{{.+}} = llvm.fptrunc %{{.+}} : f64 to f32
+ %34 = cir.cast(floating, %arg3 : !cir.double), !cir.float
+
+ cir.store %18, %2 : !s32i, !cir.ptr<!s32i>
+ %19 = cir.load %2 : !cir.ptr<!s32i>, !s32i
+ cir.return %19 : !s32i
+ }
+
+ cir.func @testBoolToIntCast(%arg0: !cir.bool) {
+ // CHECK: llvm.func @testBoolToIntCast
+ %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["bl", init] {alignment = 1 : i64}
+ %1 = cir.alloca !u8i, !cir.ptr<!u8i>, ["y", init] {alignment = 1 : i64}
+ cir.store %arg0, %0 : !cir.bool, !cir.ptr<!cir.bool>
+
+ %2 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+ %3 = cir.cast(bool_to_int, %2 : !cir.bool), !u8i
+ // CHECK: %[[LOAD_BOOL:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i8
+ // CHECK: %[[TRUNC:.*]] = llvm.trunc %[[LOAD_BOOL]] : i8 to i1
+ // CHECK: %[[EXT:.*]] = llvm.zext %[[TRUNC]] : i1 to i8
+
+ cir.store %3, %1 : !u8i, !cir.ptr<!u8i>
+ cir.return
+ }
+}
>From b0d7cf559f1219f6ff355d47726f13148d03396f Mon Sep 17 00:00:00 2001
From: Morris Hafner <mmha at users.noreply.github.com>
Date: Tue, 11 Mar 2025 11:12:54 -0700
Subject: [PATCH 2/9] Update clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Co-authored-by: Erich Keane <ekeane at nvidia.com>
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index df9447841800a..3d5862949b51f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -141,7 +141,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (srcType->isRealFloatingType())
return emitFloatToBoolConversion(src, loc);
- if ([[maybe_unused]] auto *mpt = llvm::dyn_cast<MemberPointerType>(srcType))
+ if (llvm::isa<MemberPointerType>(srcType))
cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
if (srcType->isIntegerType())
>From 33af0d2004024dcced94bd8c4b9ba5134cfa2ae0 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Tue, 11 Mar 2025 17:13:53 -0700
Subject: [PATCH 3/9] Address some review feedback
- Remove dead functions
- Remove convertType helper function
- rename some variables
- change __fp16 conversion codegen to emit cast even if intrinsic is requested
- Move some CHECK-NOT tests out into a separate function
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 14 --
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 128 ++++++++----------
clang/test/CIR/CodeGen/cast.cpp | 18 ++-
3 files changed, 72 insertions(+), 88 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index e5e8132e9f527..f88862d514731 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -126,20 +126,6 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createCast(loc, cir::CastKind::bitcast, src, newTy);
}
- mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) {
- assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src");
- return createBitcast(src, getPointerTo(newPointeeTy));
- }
-
- mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
- mlir::Type newTy) {
- return createCast(loc, cir::CastKind::address_space, src, newTy);
- }
-
- mlir::Value createAddrSpaceCast(mlir::Value src, mlir::Type newTy) {
- return createAddrSpaceCast(src.getLoc(), src, newTy);
- }
-
//
// Block handling helpers
// ----------------------
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3d5862949b51f..60a1f465b645b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -32,21 +32,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
bool ignoreResultAssign;
public:
- ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
- bool ira = false)
- : cgf(cgf), builder(builder), ignoreResultAssign(ira) {}
-
- //===--------------------------------------------------------------------===//
- // Utilities
- //===--------------------------------------------------------------------===//
-
- bool TestAndClearIgnoreResultAssign() {
- bool i = ignoreResultAssign;
- ignoreResultAssign = false;
- return i;
- }
-
- mlir::Type convertType(QualType t) { return cgf.convertType(t); }
+ ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder)
+ : cgf(cgf), builder(builder) {}
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -80,14 +67,14 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {
- mlir::Type type = convertType(e->getType());
+ mlir::Type type = cgf.convertType(e->getType());
return builder.create<cir::ConstantOp>(
cgf.getLoc(e->getExprLoc()), type,
builder.getAttr<cir::IntAttr>(type, e->getValue()));
}
mlir::Value VisitFloatingLiteral(const FloatingLiteral *e) {
- mlir::Type type = convertType(e->getType());
+ mlir::Type type = cgf.convertType(e->getType());
assert(mlir::isa<cir::CIRFPTypeInterface>(type) &&
"expect floating-point type");
return builder.create<cir::ConstantOp>(
@@ -96,7 +83,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
- mlir::Type type = convertType(e->getType());
+ mlir::Type type = cgf.convertType(e->getType());
return builder.create<cir::ConstantOp>(
cgf.getLoc(e->getExprLoc()), type,
builder.getCIRBoolAttr(e->getValue()));
@@ -127,7 +114,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// as a logical value again.
// TODO: optimize this common case here or leave it for later
// CIR passes?
- mlir::Type boolTy = convertType(cgf.getContext().BoolTy);
+ mlir::Type boolTy = cgf.convertType(cgf.getContext().BoolTy);
return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,
srcVal);
}
@@ -192,21 +179,19 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (mlir::isa<cir::BoolType>(srcTy)) {
if (opts.treatBooleanAsSigned)
cgf.getCIRGenModule().errorNYI("signed bool");
- if (cgf.getBuilder().isInt(dstTy)) {
+ if (cgf.getBuilder().isInt(dstTy))
castKind = cir::CastKind::bool_to_int;
- } else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy))
castKind = cir::CastKind::bool_to_float;
- } else {
+ else
llvm_unreachable("Internal error: Cast to unexpected type");
- }
} else if (cgf.getBuilder().isInt(srcTy)) {
- if (cgf.getBuilder().isInt(dstTy)) {
+ if (cgf.getBuilder().isInt(dstTy))
castKind = cir::CastKind::integral;
- } else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy))
castKind = cir::CastKind::int_to_float;
- } else {
+ else
llvm_unreachable("Internal error: Cast to unexpected type");
- }
} else if (mlir::isa<cir::CIRFPTypeInterface>(srcTy)) {
if (cgf.getBuilder().isInt(dstTy)) {
// If we can't recognize overflow as undefined behavior, assume that
@@ -262,19 +247,19 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (dstType->isVoidType())
return nullptr;
- mlir::Type srcTy = src.getType();
+ mlir::Type mlirSrcType = src.getType();
// Handle conversions to bool first, they are special: comparisons against
// 0.
if (dstType->isBooleanType())
return emitConversionToBool(src, srcType, cgf.getLoc(loc));
- mlir::Type dstTy = convertType(dstType);
+ mlir::Type mlirDstType = cgf.convertType(dstType);
if (srcType->isHalfType() &&
!cgf.getContext().getLangOpts().NativeHalfType) {
// Cast to FP using the intrinsic if the half type itself isn't supported.
- if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
+ if (mlir::isa<cir::CIRFPTypeInterface>(mlirDstType)) {
if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
cgf.getCIRGenModule().errorNYI(loc,
"cast via llvm.convert.from.fp16");
@@ -285,18 +270,19 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
cgf.getCIRGenModule().errorNYI(loc,
"cast via llvm.convert.from.fp16");
- } else {
- src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating,
- src, cgf.FloatTy);
+ // FIXME(cir): For now lets pretend we shouldn't use the conversion
+ // intrinsics and insert a cast here unconditionally.
}
+ src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
+ cgf.FloatTy);
srcType = cgf.getContext().FloatTy;
- srcTy = cgf.FloatTy;
+ mlirSrcType = cgf.FloatTy;
}
}
// TODO(cir): LLVM codegen ignore conversions like int -> uint,
// is there anything to be done for CIR here?
- if (srcTy == dstTy) {
+ if (mlirSrcType == mlirDstType) {
if (opts.emitImplicitIntegerSignChangeChecks)
cgf.getCIRGenModule().errorNYI(loc,
"implicit integer sign change checks");
@@ -306,14 +292,14 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// Handle pointer conversions next: pointers can only be converted to/from
// other pointers and integers. Check for pointer types in terms of LLVM, as
// some native types (like Obj-C id) may map to a pointer type.
- if (auto dstPT = dyn_cast<cir::PointerType>(dstTy)) {
+ if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
}
- if (isa<cir::PointerType>(srcTy)) {
+ if (isa<cir::PointerType>(mlirSrcType)) {
// Must be an ptr to int cast.
- assert(isa<cir::IntType>(dstTy) && "not ptr->int?");
- return builder.createPtrToInt(src, dstTy);
+ assert(isa<cir::IntType>(mlirDstType) && "not ptr->int?");
+ return builder.createPtrToInt(src, mlirDstType);
}
// A scalar can be splatted to an extended vector of the same element type
@@ -335,11 +321,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// Finally, we have the arithmetic types or vectors of arithmetic types.
mlir::Value res = nullptr;
- mlir::Type resTy = dstTy;
+ mlir::Type resTy = mlirDstType;
- res = emitScalarCast(src, srcType, dstType, srcTy, dstTy, opts);
+ res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
- if (dstTy != resTy) {
+ if (mlirDstType != resTy) {
if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");
} else {
@@ -385,13 +371,13 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr *e) {
// casts, as they handle things like function to ptr-to-function decay
// etc.
mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
- Expr *e = ce->getSubExpr();
+ Expr *subExpr = ce->getSubExpr();
QualType destTy = ce->getType();
CastKind kind = ce->getCastKind();
// These cases are generally not written to ignore the result of evaluating
// their sub-expressions, so we clear this now.
- [[maybe_unused]] bool ignored = TestAndClearIgnoreResultAssign();
+ ignoreResultAssign = false;
switch (kind) {
case clang::CK_Dependent:
@@ -403,16 +389,17 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast: {
- auto src = Visit(const_cast<Expr *>(e));
- mlir::Type dstTy = convertType(destTy);
+ mlir::Value src = Visit(const_cast<Expr *>(subExpr));
+ mlir::Type dstTy = cgf.convertType(destTy);
assert(!cir::MissingFeatures::addressSpace());
if (cgf.sanOpts.has(SanitizerKind::CFIUnrelatedCast))
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(), "sanitizer support");
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+ "sanitizer support");
if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"strict vtable pointers");
// Update heapallocsite metadata when there is an explicit pointer cast.
@@ -436,24 +423,24 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
// out a better way of doing these casts.
assert(!cir::MissingFeatures::scalableVectors());
- return cgf.getBuilder().createBitcast(cgf.getLoc(e->getSourceRange()), src,
- dstTy);
+ return cgf.getBuilder().createBitcast(cgf.getLoc(subExpr->getSourceRange()),
+ src, dstTy);
}
case CK_AtomicToNonAtomic:
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"CastExpr: ", ce->getCastKindName());
break;
case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
- return Visit(const_cast<Expr *>(e));
+ return Visit(const_cast<Expr *>(subExpr));
case CK_NoOp: {
- auto v = Visit(const_cast<Expr *>(e));
+ auto v = Visit(const_cast<Expr *>(subExpr));
if (v) {
// CK_NoOp can model a pointer qualification conversion, which can remove
// an array bound and change the IR type.
// FIXME: Once pointee types are removed from IR, remove this.
- auto t = convertType(destTy);
+ mlir::Type t = cgf.convertType(destTy);
if (t != v.getType())
cgf.getCIRGenModule().errorNYI("pointer qualification conversion");
}
@@ -461,20 +448,21 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
}
case CK_NullToPointer: {
- if (MustVisitNullValue(e))
+ if (MustVisitNullValue(subExpr))
cgf.getCIRGenModule().errorNYI(
- e->getSourceRange(), "ignored expression on null to pointer cast");
+ subExpr->getSourceRange(),
+ "ignored expression on null to pointer cast");
// Note that DestTy is used as the MLIR type instead of a custom
// nullptr type.
- mlir::Type ty = convertType(destTy);
- return builder.getNullPtr(ty, cgf.getLoc(e->getExprLoc()));
+ mlir::Type ty = cgf.convertType(destTy);
+ return builder.getNullPtr(ty, cgf.getLoc(subExpr->getExprLoc()));
}
case CK_LValueToRValue:
- assert(cgf.getContext().hasSameUnqualifiedType(e->getType(), destTy));
- assert(e->isGLValue() && "lvalue-to-rvalue applied to r-value!");
- return Visit(const_cast<Expr *>(e));
+ assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(), destTy));
+ assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
+ return Visit(const_cast<Expr *>(subExpr));
case CK_IntegralCast: {
ScalarConversionOpts opts;
@@ -482,7 +470,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
if (!ice->isPartOfExplicitCast())
opts = ScalarConversionOpts(cgf.sanOpts);
}
- return emitScalarConversion(Visit(e), e->getType(), destTy,
+ return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
ce->getExprLoc(), opts);
}
@@ -498,22 +486,24 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
assert(!destTy->isBooleanType() && "bool should use PointerToBool");
if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
llvm_unreachable("NYI");
- return builder.createPtrToInt(Visit(e), convertType(destTy));
+ return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
}
case CK_ToVoid:
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"ignored expression on void cast");
return nullptr;
case CK_IntegralToBoolean:
- return emitIntToBoolConversion(Visit(e), cgf.getLoc(ce->getSourceRange()));
+ return emitIntToBoolConversion(Visit(subExpr),
+ cgf.getLoc(ce->getSourceRange()));
case CK_PointerToBoolean:
- return emitPointerToBoolConversion(Visit(e), e->getType());
+ return emitPointerToBoolConversion(Visit(subExpr), subExpr->getType());
case CK_FloatingToBoolean:
- return emitFloatToBoolConversion(Visit(e), cgf.getLoc(e->getExprLoc()));
+ return emitFloatToBoolConversion(Visit(subExpr),
+ cgf.getLoc(subExpr->getExprLoc()));
case CK_MemberPointerToBoolean: {
- mlir::Value memPtr = Visit(e);
+ mlir::Value memPtr = Visit(subExpr);
return builder.createCast(cgf.getLoc(ce->getSourceRange()),
cir::CastKind::member_ptr_to_bool, memPtr,
cgf.convertType(destTy));
@@ -521,7 +511,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
return nullptr;
default:
- cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"CastExpr: ", ce->getCastKindName());
}
return {};
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index 29d34e87c398d..d8bf7ca66b6a3 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -35,11 +35,7 @@ int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) {
int si = (int)x1; // sign add
// CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<s, 32>
- unsigned uu = (unsigned)x1; // should not be generated
- // CHECK-NOT: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int<u, 32>), !cir.int<u, 32>
-
- bool ib = (bool)x1; // No checking, because this isn't a regular cast.
-
+ bool ib;
int bi = (int)ib; // bool to int
// CHECK: %{{[0-9]+}} = cir.cast(bool_to_int, %{{[0-9]+}} : !cir.bool), !cir.int<s, 32>
@@ -56,3 +52,15 @@ bool cptr(void *d) {
// CHECK: %2 = cir.load %0 : !cir.ptr<!cir.ptr<!cir.void>>, !cir.ptr<!cir.void>
// CHECK: %3 = cir.cast(ptr_to_bool, %2 : !cir.ptr<!cir.void>), !cir.bool
+
+void should_not_cast() {
+ unsigned x1;
+
+ unsigned uu = (unsigned)x1;
+ bool ib = (bool)x1;
+ return (void) x1;
+}
+
+// CHECK: cir.func @should_not_cast
+// CHECK-NOT: cir.cast
+// CHECK: }
>From 07e2e2397558244dcf8824dcb6ed1bb07c3b4137 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 12 Mar 2025 14:26:10 -0700
Subject: [PATCH 4/9] More review feedback changes
- CastKind enum now aligns with classic codegen CastKind
- Try to emit a value of the expected type after errorNYI()s
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 119 +++++++++++++------
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 59 ++++++---
clang/test/CIR/CodeGen/cast.cpp | 1 -
3 files changed, 127 insertions(+), 52 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9797960e00867..fb76ce6b51f1d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -82,47 +82,92 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
// CastOp
//===----------------------------------------------------------------------===//
-// The enumaration value isn't in sync with clang.
-def CK_IntegralToBoolean : I32EnumAttrCase<"int_to_bool", 1>;
-def CK_ArrayToPointerDecay : I32EnumAttrCase<"array_to_ptrdecay", 2>;
-def CK_IntegralCast : I32EnumAttrCase<"integral", 3>;
-def CK_BitCast : I32EnumAttrCase<"bitcast", 4>;
-def CK_FloatingCast : I32EnumAttrCase<"floating", 5>;
-def CK_PtrToBoolean : I32EnumAttrCase<"ptr_to_bool", 6>;
-def CK_FloatToIntegral : I32EnumAttrCase<"float_to_int", 7>;
-def CK_IntegralToPointer : I32EnumAttrCase<"int_to_ptr", 8>;
-def CK_PointerToIntegral : I32EnumAttrCase<"ptr_to_int", 9>;
-def CK_FloatToBoolean : I32EnumAttrCase<"float_to_bool", 10>;
-def CK_BooleanToIntegral : I32EnumAttrCase<"bool_to_int", 11>;
-def CK_IntegralToFloat : I32EnumAttrCase<"int_to_float", 12>;
-def CK_BooleanToFloat : I32EnumAttrCase<"bool_to_float", 13>;
-def CK_AddressSpaceConversion : I32EnumAttrCase<"address_space", 14>;
-def CK_FloatToComplex : I32EnumAttrCase<"float_to_complex", 15>;
-def CK_IntegralToComplex : I32EnumAttrCase<"int_to_complex", 16>;
-def CK_FloatComplexToReal : I32EnumAttrCase<"float_complex_to_real", 17>;
-def CK_IntegralComplexToReal : I32EnumAttrCase<"int_complex_to_real", 18>;
-def CK_FloatComplexToBoolean : I32EnumAttrCase<"float_complex_to_bool", 19>;
-def CK_IntegralComplexToBoolean : I32EnumAttrCase<"int_complex_to_bool", 20>;
-def CK_FloatComplexCast : I32EnumAttrCase<"float_complex", 21>;
-def CK_FloatComplexToIntegralComplex
- : I32EnumAttrCase<"float_complex_to_int_complex", 22>;
-def CK_IntegralComplexCast : I32EnumAttrCase<"int_complex", 23>;
-def CK_IntegralComplexToFloatComplex
- : I32EnumAttrCase<"int_complex_to_float_complex", 24>;
-def CK_MemberPtrToBoolean : I32EnumAttrCase<"member_ptr_to_bool", 25>;
+// CK_Dependent
+def CK_BitCast : I32EnumAttrCase<"bitcast", 1>;
+// CK_LValueBitCast
+// CK_LValueToRValueBitCast
+// CK_LValueToRValue
+// CK_NoOp
+// CK_BaseToDerived
+// CK_DerivedToBase
+// CK_UncheckedDerivedToBase
+// CK_Dynamic
+// CK_ToUnion
+def CK_ArrayToPointerDecay : I32EnumAttrCase<"array_to_ptrdecay", 11>;
+// CK_FunctionToPointerDecay
+// CK_NullToPointer
+// CK_NullToMemberPointer
+// CK_BaseToDerivedMemberPointer
+// CK_DerivedToBaseMemberPointer
+def CK_MemberPointerToBoolean : I32EnumAttrCase<"member_ptr_to_bool", 17>;
+// CK_ReinterpretMemberPointer
+// CK_UserDefinedConversion
+// CK_ConstructorConversion
+def CK_IntegralToPointer : I32EnumAttrCase<"int_to_ptr", 21>;
+def CK_PointerToIntegral : I32EnumAttrCase<"ptr_to_int", 22>;
+def CK_PointerToBoolean : I32EnumAttrCase<"ptr_to_bool", 23>;
+// CK_ToVoid
+// CK_MatrixCast
+// CK_VectorSplat
+def CK_IntegralCast : I32EnumAttrCase<"integral", 27>;
+def CK_IntegralToBoolean : I32EnumAttrCase<"int_to_bool", 28>;
+def CK_IntegralToFloating : I32EnumAttrCase<"int_to_float", 29>;
+// CK_FloatingToFixedPoint
+// CK_FixedPointToFloating
+// CK_FixedPointCast
+// CK_FixedPointToIntegral
+// CK_IntegralToFixedPoint
+// CK_FixedPointToBoolean
+def CK_FloatingToIntegral : I32EnumAttrCase<"float_to_int", 36>;
+def CK_FloatingToBoolean : I32EnumAttrCase<"float_to_bool", 37>;
+def CK_BooleanToSignedIntegral : I32EnumAttrCase<"bool_to_int", 38>;
+def CK_FloatingCast : I32EnumAttrCase<"floating", 39>;
+// CK_CPointerToObjCPointerCast
+// CK_BlockPointerToObjCPointerCast
+// CK_AnyPointerToBlockPointerCast
+// CK_ObjCObjectLValueCast
+// CK_FloatingRealToComplex
+// CK_FloatingComplexToReal
+// CK_FloatingComplexToBoolean
+def CK_FloatingComplexCast : I32EnumAttrCase<"float_complex", 47>;
+// CK_FloatingComplexToIntegralComplex
+// CK_IntegralRealToComplex
+def CK_IntegralComplexToReal : I32EnumAttrCase<"int_complex_to_real", 50>;
+def CK_IntegralComplexToBoolean : I32EnumAttrCase<"int_complex_to_bool", 51>;
+def CK_IntegralComplexCast : I32EnumAttrCase<"int_complex", 52>;
+def CK_IntegralComplexToFloatingComplex
+ : I32EnumAttrCase<"int_complex_to_float_complex", 53>;
+// CK_ARCProduceObject
+// CK_ARCConsumeObject
+// CK_ARCReclaimReturnedObject
+// CK_ARCExtendBlockObject
+// CK_AtomicToNonAtomic
+// CK_NonAtomicToAtomic
+// CK_CopyAndAutoreleaseBlockObject
+// CK_BuiltinFnToFnPtr
+// CK_ZeroToOCLOpaqueType
+def CK_AddressSpaceConversion : I32EnumAttrCase<"address_space", 63>;
+// CK_IntToOCLSampler
+// CK_HLSLVectorTruncation
+// CK_HLSLArrayRValue
+// CK_HLSLElementwiseCast
+// CK_HLSLAggregateSplatCast
+
+// Enums below are specific to CIR and don't have a correspondence to classic
+// codegen:
+def CK_BooleanToFloat : I32EnumAttrCase<"bool_to_float", 1000>;
def CastKind : I32EnumAttr<
"CastKind",
"cast kind",
- [CK_IntegralToBoolean, CK_ArrayToPointerDecay, CK_IntegralCast,
- CK_BitCast, CK_FloatingCast, CK_PtrToBoolean, CK_FloatToIntegral,
- CK_IntegralToPointer, CK_PointerToIntegral, CK_FloatToBoolean,
- CK_BooleanToIntegral, CK_IntegralToFloat, CK_BooleanToFloat,
- CK_AddressSpaceConversion, CK_FloatToComplex, CK_IntegralToComplex,
- CK_FloatComplexToReal, CK_IntegralComplexToReal, CK_FloatComplexToBoolean,
- CK_IntegralComplexToBoolean, CK_FloatComplexCast,
- CK_FloatComplexToIntegralComplex, CK_IntegralComplexCast,
- CK_IntegralComplexToFloatComplex, CK_MemberPtrToBoolean]> {
+ [CK_BitCast, CK_ArrayToPointerDecay, CK_MemberPointerToBoolean,
+ CK_IntegralToPointer, CK_PointerToIntegral, CK_PointerToBoolean,
+ CK_IntegralCast, CK_IntegralToBoolean, CK_IntegralToFloating,
+ CK_FloatingToIntegral, CK_FloatingToBoolean, CK_BooleanToSignedIntegral,
+ CK_FloatingCast, CK_FloatingComplexCast, CK_IntegralComplexToReal,
+ CK_IntegralComplexToBoolean, CK_IntegralComplexCast,
+ CK_IntegralComplexToFloatingComplex, CK_AddressSpaceConversion,
+ CK_BooleanToFloat]> {
let cppNamespace = "::cir";
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 60a1f465b645b..cebf190ffc81f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -128,8 +128,16 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (srcType->isRealFloatingType())
return emitFloatToBoolConversion(src, loc);
- if (llvm::isa<MemberPointerType>(srcType))
+ if (llvm::isa<MemberPointerType>(srcType)) {
cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+ auto boolType = cgf.getContext().getBOOLType();
+ auto cirBoolType = cgf.convertType(boolType);
+ CharUnits alignment = cgf.getContext().getTypeAlignInChars(boolType);
+ auto addr =
+ builder.createAlloca(loc, builder.getPointerTo(cirBoolType),
+ cirBoolType, {}, cgf.cgm.getSize(alignment));
+ return builder.createLoad(loc, addr);
+ }
if (srcType->isIntegerType())
return emitIntToBoolConversion(src, loc);
@@ -203,6 +211,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
castKind = cir::CastKind::float_to_int;
} else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
cgf.getCIRGenModule().errorNYI("floating point casts");
+ CharUnits alignment = cgf.getContext().getTypeAlignInChars(dstType);
+ auto addr =
+ builder.createAlloca(src.getLoc(), builder.getPointerTo(dstTy),
+ dstTy, {}, cgf.cgm.getSize(alignment));
+ return builder.createLoad(src.getLoc(), addr);
} else {
llvm_unreachable("Internal error: Cast to unexpected type");
}
@@ -230,10 +243,10 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// TODO(leonardchan): When necessary, add another if statement checking for
// conversions to fixed point types from other types.
// conversions to fixed point types from other types.
- if (srcType->isFixedPointType())
- cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
- else if (dstType->isFixedPointType())
+ if (srcType->isFixedPointType() || dstType->isFixedPointType()) {
cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
+ return nullptr;
+ }
srcType = srcType.getCanonicalType();
dstType = dstType.getCanonicalType();
@@ -294,6 +307,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// some native types (like Obj-C id) may map to a pointer type.
if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
+ CharUnits alignment = cgf.getContext().getTypeAlignInChars(dstType);
+ auto addr =
+ builder.createAlloca(src.getLoc(), builder.getPointerTo(dstPT), dstPT,
+ {}, cgf.cgm.getSize(alignment));
+ return builder.createLoad(src.getLoc(), addr);
}
if (isa<cir::PointerType>(mlirSrcType)) {
@@ -310,7 +328,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
srcType.getTypePtr() &&
"Splatted expr doesn't match with vector element type?");
- llvm_unreachable("not implemented");
+ cgf.getCIRGenModule().errorNYI(loc, "vector splatting");
+ return nullptr;
}
if (srcType->isMatrixType() && dstType->isMatrixType())
@@ -328,10 +347,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (mlirDstType != resTy) {
if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");
- } else {
- res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
- resTy);
}
+ // FIXME(cir): For now we never use FP16 conversion intrinsics even if
+ // required by the target. Change that once this is implemented
+ res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
+ resTy);
}
if (opts.emitImplicitIntegerTruncationChecks)
@@ -342,10 +362,6 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
"implicit integer sign change checks");
return res;
-
- cgf.getCIRGenModule().errorNYI(loc,
- "emitScalarConversion for unequal types");
- return {};
}
};
@@ -485,7 +501,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
case CK_PointerToIntegral: {
assert(!destTy->isBooleanType() && "bool should use PointerToBool");
if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
- llvm_unreachable("NYI");
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+ "strict vtable pointers");
return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
}
case CK_ToVoid:
@@ -493,6 +510,21 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
"ignored expression on void cast");
return nullptr;
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingCast:
+ case CK_FixedPointToFloating:
+ case CK_FloatingToFixedPoint: {
+ if (kind == CK_FixedPointToFloating || kind == CK_FloatingToFixedPoint) {
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+ "fixed point casts");
+ return {};
+ }
+ cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(), "fp options");
+ return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
+ ce->getExprLoc());
+ }
+
case CK_IntegralToBoolean:
return emitIntToBoolConversion(Visit(subExpr),
cgf.getLoc(ce->getSourceRange()));
@@ -508,7 +540,6 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
cir::CastKind::member_ptr_to_bool, memPtr,
cgf.convertType(destTy));
}
- return nullptr;
default:
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index d8bf7ca66b6a3..9fd42e6611aa0 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -58,7 +58,6 @@ void should_not_cast() {
unsigned uu = (unsigned)x1;
bool ib = (bool)x1;
- return (void) x1;
}
// CHECK: cir.func @should_not_cast
>From b61de3f14f5b23bc644a061fd3d42c9d41ecd1c8 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mmha at users.noreply.github.com>
Date: Wed, 12 Mar 2025 14:35:51 -0700
Subject: [PATCH 5/9] Update clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Co-authored-by: Erich Keane <ekeane at nvidia.com>
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index cebf190ffc81f..82f64888f406a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -305,7 +305,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// Handle pointer conversions next: pointers can only be converted to/from
// other pointers and integers. Check for pointer types in terms of LLVM, as
// some native types (like Obj-C id) may map to a pointer type.
- if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
+ if (isa_cast<cir::PointerType>(mlirDstType)) {
cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
CharUnits alignment = cgf.getContext().getTypeAlignInChars(dstType);
auto addr =
>From 1499bdc150894ffcafdeb4ea801dcdbdf48af04c Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 12 Mar 2025 16:24:22 -0700
Subject: [PATCH 6/9] Addressing more review feedback - Add createDummyValue
functions - Create Bool/Ptr constants on errorNYIs - return {} instead of
nullptr - Replace auto with types
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 9 +++
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 7 +++
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 57 ++++++++----------
clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 +
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 60 +++++++++----------
5 files changed, 72 insertions(+), 63 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index f88862d514731..e58435cde742a 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Type.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -79,6 +80,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::StoreOp>(loc, val, dst);
}
+ mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
+ clang::CharUnits alignment) {
+auto addr =
+createAlloca(loc, getPointerTo(type), type, {},
+getSizeFromCharUnits(getContext(), alignment));
+return createLoad(loc, addr);
+}
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5b81fe172e645..196d14f372333 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -216,6 +216,13 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
return addr;
}
+mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
+ clang::QualType qt) {
+ mlir::Type t = convertType(qt);
+ CharUnits alignment = getContext().getTypeAlignInChars(qt);
+ return builder.createDummyValue(loc, t, alignment);
+}
+
/// This creates an alloca and inserts it at the current insertion point of the
/// builder.
Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 82f64888f406a..56075f91de806 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -103,7 +103,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
mlir::Value emitFloatToBoolConversion(mlir::Value src, mlir::Location loc) {
- auto boolTy = builder.getBoolTy();
+ cir::BoolType boolTy = builder.getBoolTy();
return builder.create<cir::CastOp>(loc, boolTy,
cir::CastKind::float_to_bool, src);
}
@@ -114,7 +114,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// as a logical value again.
// TODO: optimize this common case here or leave it for later
// CIR passes?
- mlir::Type boolTy = cgf.convertType(cgf.getContext().BoolTy);
+ cir::BoolType boolTy = builder.getBoolTy();
return builder.create<cir::CastOp>(loc, boolTy, cir::CastKind::int_to_bool,
srcVal);
}
@@ -130,13 +130,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (llvm::isa<MemberPointerType>(srcType)) {
cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
- auto boolType = cgf.getContext().getBOOLType();
- auto cirBoolType = cgf.convertType(boolType);
- CharUnits alignment = cgf.getContext().getTypeAlignInChars(boolType);
- auto addr =
- builder.createAlloca(loc, builder.getPointerTo(cirBoolType),
- cirBoolType, {}, cgf.cgm.getSize(alignment));
- return builder.createLoad(loc, addr);
+ mlir::Type boolType = builder.getBoolTy();
+ return builder.create<cir::ConstantOp>(loc, boolType,
+ builder.getCIRBoolAttr(false));
}
if (srcType->isIntegerType())
@@ -175,9 +171,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Type dstTy, ScalarConversionOpts opts) {
assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
"Internal error: matrix types not handled by this function.");
- if (mlir::isa<mlir::IntegerType>(srcTy) ||
- mlir::isa<mlir::IntegerType>(dstTy))
- llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+ assert(!(mlir::isa<mlir::IntegerType>(srcTy) ||
+ mlir::isa<mlir::IntegerType>(dstTy)) &&
+ "Obsolete code. Don't use mlir::IntegerType with CIR.");
mlir::Type fullDstTy = dstTy;
assert(!cir::MissingFeatures::vectorType());
@@ -211,11 +207,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
castKind = cir::CastKind::float_to_int;
} else if (mlir::isa<cir::CIRFPTypeInterface>(dstTy)) {
cgf.getCIRGenModule().errorNYI("floating point casts");
- CharUnits alignment = cgf.getContext().getTypeAlignInChars(dstType);
- auto addr =
- builder.createAlloca(src.getLoc(), builder.getPointerTo(dstTy),
- dstTy, {}, cgf.cgm.getSize(alignment));
- return builder.createLoad(src.getLoc(), addr);
+ return builder.getNullPtr(dstTy, src.getLoc());
} else {
llvm_unreachable("Internal error: Cast to unexpected type");
}
@@ -245,7 +237,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// conversions to fixed point types from other types.
if (srcType->isFixedPointType() || dstType->isFixedPointType()) {
cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions");
- return nullptr;
+ return {};
}
srcType = srcType.getCanonicalType();
@@ -258,7 +250,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
if (dstType->isVoidType())
- return nullptr;
+ return {};
mlir::Type mlirSrcType = src.getType();
@@ -280,12 +272,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// Cast to other types through float, using either the intrinsic or
// FPExt, depending on whether the half type itself is supported (as
// opposed to operations on half, available with NativeHalfType).
- if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
+ if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
cgf.getCIRGenModule().errorNYI(loc,
"cast via llvm.convert.from.fp16");
- // FIXME(cir): For now lets pretend we shouldn't use the conversion
- // intrinsics and insert a cast here unconditionally.
- }
+ // FIXME(cir): For now lets pretend we shouldn't use the conversion
+ // intrinsics and insert a cast here unconditionally.
src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
cgf.FloatTy);
srcType = cgf.getContext().FloatTy;
@@ -307,11 +298,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// some native types (like Obj-C id) may map to a pointer type.
if (isa_cast<cir::PointerType>(mlirDstType)) {
cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
- CharUnits alignment = cgf.getContext().getTypeAlignInChars(dstType);
- auto addr =
- builder.createAlloca(src.getLoc(), builder.getPointerTo(dstPT), dstPT,
- {}, cgf.cgm.getSize(alignment));
- return builder.createLoad(src.getLoc(), addr);
+ return builder.getNullPtr(dstPT, src.getLoc());
}
if (isa<cir::PointerType>(mlirSrcType)) {
@@ -329,12 +316,14 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
"Splatted expr doesn't match with vector element type?");
cgf.getCIRGenModule().errorNYI(loc, "vector splatting");
- return nullptr;
+ return {};
}
- if (srcType->isMatrixType() && dstType->isMatrixType())
+ if (srcType->isMatrixType() && dstType->isMatrixType()) {
cgf.getCIRGenModule().errorNYI(loc,
"matrix type to matrix type conversion");
+ return {};
+ }
assert(!srcType->isMatrixType() && !dstType->isMatrixType() &&
"Internal error: conversion between matrix type and scalar type");
@@ -443,10 +432,12 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
src, dstTy);
}
- case CK_AtomicToNonAtomic:
+ case CK_AtomicToNonAtomic: {
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"CastExpr: ", ce->getCastKindName());
- break;
+ mlir::Location loc = cgf.getLoc(subExpr->getSourceRange());
+ return cgf.createDummyValue(loc, destTy);
+ }
case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
return Visit(const_cast<Expr *>(subExpr));
@@ -508,7 +499,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
case CK_ToVoid:
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
"ignored expression on void cast");
- return nullptr;
+ return {};
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 33868cd7b3d50..8f60c5d900d94 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -109,6 +109,8 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,
mlir::Location loc, clang::CharUnits alignment);
+ mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt);
+
private:
// Track current variable initialization (if there's one)
const clang::VarDecl *currVarDecl = nullptr;
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 4125525583f33..cb38c4e36a759 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -294,10 +294,10 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
switch (castOp.getKind()) {
case cir::CastKind::array_to_ptrdecay: {
const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType());
- auto sourceValue = adaptor.getOperands().front();
- auto targetType = convertTy(ptrTy);
- auto elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
- ptrTy.getPointee());
+ mlir::Value sourceValue = adaptor.getOperands().front();
+ mlir::Type targetType = convertTy(ptrTy);
+ mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
+ ptrTy.getPointee());
auto offset = llvm::SmallVector<mlir::LLVM::GEPArg>{0};
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
castOp, targetType, elementTy, sourceValue, offset);
@@ -307,10 +307,10 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::opCmp());
break;
case cir::CastKind::integral: {
- auto srcType = castOp.getSrc().getType();
- auto dstType = castOp.getResult().getType();
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstType = getTypeConverter()->convertType(dstType);
+ mlir::Type srcType = castOp.getSrc().getType();
+ mlir::Type dstType = castOp.getResult().getType();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstType = getTypeConverter()->convertType(dstType);
cir::IntType srcIntType =
mlir::cast<cir::IntType>(elementTypeIfVector(srcType));
cir::IntType dstIntType =
@@ -322,12 +322,12 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
break;
}
case cir::CastKind::floating: {
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy =
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy =
getTypeConverter()->convertType(castOp.getResult().getType());
- auto srcTy = elementTypeIfVector(castOp.getSrc().getType());
- auto dstTy = elementTypeIfVector(castOp.getResult().getType());
+ mlir::Type srcTy = elementTypeIfVector(castOp.getSrc().getType());
+ mlir::Type dstTy = elementTypeIfVector(castOp.getResult().getType());
if (!mlir::isa<cir::CIRFPTypeInterface>(dstTy) ||
!mlir::isa<cir::CIRFPTypeInterface>(srcTy))
@@ -347,22 +347,22 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
}
case cir::CastKind::int_to_ptr: {
auto dstTy = mlir::cast<cir::PointerType>(castOp.getType());
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(castOp, llvmDstTy,
llvmSrcVal);
return mlir::success();
}
case cir::CastKind::ptr_to_int: {
auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(castOp, llvmDstTy,
llvmSrcVal);
return mlir::success();
}
case cir::CastKind::float_to_bool: {
- auto llvmSrcVal = adaptor.getOperands().front();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
auto kind = mlir::LLVM::FCmpPredicate::une;
// Check if float is not equal to zero.
@@ -378,7 +378,7 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
}
case cir::CastKind::bool_to_int: {
auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
- auto llvmSrcVal = adaptor.getOperands().front();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType());
auto llvmDstTy =
mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy));
@@ -391,17 +391,17 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
return mlir::success();
}
case cir::CastKind::bool_to_float: {
- auto dstTy = castOp.getType();
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Type dstTy = castOp.getType();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,
llvmSrcVal);
return mlir::success();
}
case cir::CastKind::int_to_float: {
- auto dstTy = castOp.getType();
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Type dstTy = castOp.getType();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getSrc().getType()))
.isSigned())
rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(castOp, llvmDstTy,
@@ -412,9 +412,9 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
return mlir::success();
}
case cir::CastKind::float_to_int: {
- auto dstTy = castOp.getType();
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Type dstTy = castOp.getType();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
if (mlir::cast<cir::IntType>(
elementTypeIfVector(castOp.getResult().getType()))
.isSigned())
@@ -433,9 +433,9 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::opCmp());
break;
case cir::CastKind::address_space: {
- auto dstTy = castOp.getType();
- auto llvmSrcVal = adaptor.getOperands().front();
- auto llvmDstTy = getTypeConverter()->convertType(dstTy);
+ mlir::Type dstTy = castOp.getType();
+ mlir::Value llvmSrcVal = adaptor.getOperands().front();
+ mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(castOp, llvmDstTy,
llvmSrcVal);
break;
>From 687b888ad620b5511fd5d851dae6b077146189e9 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 12 Mar 2025 16:40:29 -0700
Subject: [PATCH 7/9] Add support for CK_ToVoid
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 5 ++---
clang/test/CIR/CodeGen/cast.cpp | 1 +
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 56075f91de806..7da2f1d2030bc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -296,7 +296,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// Handle pointer conversions next: pointers can only be converted to/from
// other pointers and integers. Check for pointer types in terms of LLVM, as
// some native types (like Obj-C id) may map to a pointer type.
- if (isa_cast<cir::PointerType>(mlirDstType)) {
+ if (auto dstPT = dyn_cast<cir::PointerType>(mlirDstType)) {
cgf.getCIRGenModule().errorNYI(loc, "pointer casts");
return builder.getNullPtr(dstPT, src.getLoc());
}
@@ -497,8 +497,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
}
case CK_ToVoid:
- cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
- "ignored expression on void cast");
+ cgf.emitIgnoredExpr(subExpr);
return {};
case CK_IntegralToFloating:
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index 9fd42e6611aa0..9958eaf5e64a5 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -58,6 +58,7 @@ void should_not_cast() {
unsigned uu = (unsigned)x1;
bool ib = (bool)x1;
+ (void) ib;
}
// CHECK: cir.func @should_not_cast
>From 6f6a938c569ee60c90165126607ac4657ff52f91 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Wed, 12 Mar 2025 16:46:00 -0700
Subject: [PATCH 8/9] clang-format
---
.../clang/CIR/Dialect/Builder/CIRBaseBuilder.h | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index e58435cde742a..32d1af677c62b 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -81,12 +81,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
}
mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
- clang::CharUnits alignment) {
-auto addr =
-createAlloca(loc, getPointerTo(type), type, {},
-getSizeFromCharUnits(getContext(), alignment));
-return createLoad(loc, addr);
-}
+ clang::CharUnits alignment) {
+ auto addr = createAlloca(loc, getPointerTo(type), type, {},
+ getSizeFromCharUnits(getContext(), alignment));
+ return createLoad(loc, addr);
+ }
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
>From 69b635658d4127b7e3b7e5d30f3cc636e94b41d2 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mmha at users.noreply.github.com>
Date: Thu, 13 Mar 2025 09:03:17 -0700
Subject: [PATCH 9/9] Update
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Co-authored-by: Erich Keane <ekeane at nvidia.com>
---
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index cb38c4e36a759..3644f72f821ee 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -298,7 +298,7 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
mlir::Type targetType = convertTy(ptrTy);
mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
ptrTy.getPointee());
- auto offset = llvm::SmallVector<mlir::LLVM::GEPArg>{0};
+ llvm::SmallVector<mlir::LLVM::GEPArg> offset{0};
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
castOp, targetType, elementTy, sourceValue, offset);
break;
More information about the cfe-commits
mailing list