================ @@ -90,24 +89,279 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { 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 = cgf.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 (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); + + 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"); + 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"); + } + } 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() || dstType->isFixedPointType()) { + cgf.getCIRGenModule().errorNYI(loc, "fixed point conversions"); + return nullptr; + } + 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; + } - cgf.getCIRGenModule().errorNYI(loc, - "emitScalarConversion for unequal types"); - return {}; + if (dstType->isVoidType()) + return nullptr; + + 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 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>(mlirDstType)) { + 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"); + // 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; + mlirSrcType = cgf.FloatTy; + } + } + + // TODO(cir): LLVM codegen ignore conversions like int -> uint, + // is there anything to be done for CIR here? + if (mlirSrcType == mlirDstType) { + 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 (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); ---------------- erichkeane wrote:
Wonder if there is use of a `createDummyValue` function in builder that does all this for us? https://github.com/llvm/llvm-project/pull/130690 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits