[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 11 08:13:04 PDT 2025
================
@@ -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())
----------------
erichkeane wrote:
I wonder if modeling this cast is valuable particularly for static analysis...
https://github.com/llvm/llvm-project/pull/130690
More information about the cfe-commits
mailing list