[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)

Morris Hafner via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 12 15:54:48 PDT 2025


================
@@ -121,29 +375,174 @@ 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
 // 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.
+  ignoreResultAssign = false;
+
   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: {
+    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(subExpr->getSourceRange(),
+                                     "sanitizer support");
+
+    if (cgf.cgm.getCodeGenOpts().StrictVTablePointers)
+      cgf.getCIRGenModule().errorNYI(subExpr->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(subExpr->getSourceRange()),
+                                          src, dstTy);
+  }
+
+  case CK_AtomicToNonAtomic:
+    cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+                                   "CastExpr: ", ce->getCastKindName());
+    break;
+  case CK_NonAtomicToAtomic:
+  case CK_UserDefinedConversion:
+    return Visit(const_cast<Expr *>(subExpr));
+  case CK_NoOp: {
+    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.
+      mlir::Type t = cgf.convertType(destTy);
+      if (t != v.getType())
+        cgf.getCIRGenModule().errorNYI("pointer qualification conversion");
+    }
+    return v;
+  }
+
+  case CK_NullToPointer: {
+    if (MustVisitNullValue(subExpr))
+      cgf.getCIRGenModule().errorNYI(
+          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 = 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: {
-    assert(!cir::MissingFeatures::scalarConversionOpts());
-    return emitScalarConversion(Visit(e), e->getType(), destTy,
+    ScalarConversionOpts opts;
+    if (auto *ice = dyn_cast<ImplicitCastExpr>(ce)) {
+      if (!ice->isPartOfExplicitCast())
+        opts = ScalarConversionOpts(cgf.sanOpts);
+    }
+    return emitScalarConversion(Visit(subExpr), subExpr->getType(), destTy,
+                                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)
+      cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+                                     "strict vtable pointers");
+    return builder.createPtrToInt(Visit(subExpr), cgf.convertType(destTy));
+  }
+  case CK_ToVoid:
+    cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
+                                   "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 {};
----------------
mmha wrote:

Good to know you standardized on `{}`. I changed all instances of `return nullptr` to that.

https://github.com/llvm/llvm-project/pull/130690


More information about the cfe-commits mailing list