[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +78,111 @@ class LLVMLoweringInfo {
class CIR_Op traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--===//
+
+// The enumaration value isn't in sync with clang.
mmha wrote:
I tried to get the enums in sync. Good news is I found a couple of unused
casting kinds wrt. complex numbers which I removed. Bad news is I found one
casting kind (bool to float) that's specific to CIR: llvm/clangir#290. I moved
it to the bottom on the list so the enum values of classic CG and CIR match up.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +364,173 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
andykaylor wrote:
Yes, I agree that keeping the store is necessary. My point was that even in the
incubator this value is being used.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +375,174 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
erichkeane wrote:
Is this variable used?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir andykaylor wrote: It looks like floating casts are still missing. Can you add float-to-double and double-to-float test? https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/andykaylor approved this pull request. LGTM with one very minor nit https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir
-emit-cir -DCIR_ONLY %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value
-fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+
+unsigned char cxxstaticcast_0(unsigned int x) {
+ return static_cast(x);
+}
+
+// CIR: cir.func @cxxstaticcast_0
+// CIR:%0 = cir.alloca !cir.int, !cir.ptr>, ["x",
init] {alignment = 4 : i64}
andykaylor wrote:
You should use pattern matching for %0 and similar values.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/andykaylor edited https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +364,173 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
mmha wrote:
Note that `ignoreResultAssign` is a member variable and retains its value while
we visit the expression. We might get called recursively so we should keep this
store.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,79 @@
+// 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(x);
+}
+
+// CHECK: cir.func @cxxstaticcast_0
+// CHECK:%0 = cir.alloca !cir.int, !cir.ptr>, ["x",
init] {alignment = 4 : i64}
+// CHECK:cir.store %arg0, %0 : !cir.int, !cir.ptr>
+// CHECK:%1 = cir.load %0 : !cir.ptr>, !cir.int
+// CHECK:%2 = cir.cast(integral, %1 : !cir.int), !cir.int
+// CHECK:cir.return %2 : !cir.int
+// 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),
!cir.int
mmha wrote:
I expanded the tests to include LLVM lowering where feasible. `int_to_bool` is
implemented in CIR but not in the lowering (as that requires comparisons) so I
`ifdef`ed those out for the LLVM checks.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +364,173 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
andykaylor wrote:
The incubator does use the value returned by `TestAndClearIgnoreResultAssign()`
in `VisitBinAssign()` and `emitCompoundAssign()` so we'll probably want to keep
the call in those places, but I don't see any value in calling the function
when we aren't using the value returned.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,79 @@
+// 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(x);
+}
+
+// CHECK: cir.func @cxxstaticcast_0
+// CHECK:%0 = cir.alloca !cir.int, !cir.ptr>, ["x",
init] {alignment = 4 : i64}
+// CHECK:cir.store %arg0, %0 : !cir.int, !cir.ptr>
+// CHECK:%1 = cir.load %0 : !cir.ptr>, !cir.int
+// CHECK:%2 = cir.cast(integral, %1 : !cir.int), !cir.int
+// CHECK:cir.return %2 : !cir.int
+// 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),
!cir.int
andykaylor wrote:
Maybe add checks for lowering (to LLVM IR through clangir and using classic
codegen) here also?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir bcardosolopes wrote: Has this been addressed? https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/bcardosolopes approved this pull request. LGTM pending on question left in one comment https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/bcardosolopes edited https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(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(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy))
+castKind = cir::CastKind::bool_to_int;
+ else if (mlir::isa(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(dstTy))
+castKind = cir::CastKind::int_to_float;
+ else
+llvm_unreachable("Internal error: Cast to unexpected type");
+
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +375,174 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
erichkeane wrote:
I spent a while trying to repro the warning I could swear I've seen before, but
I've not been able to get this to happen. So disregard.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/erichkeane approved this pull request. 1 nit, else LGTM. https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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(castOp.getType());
+mlir::Value sourceValue = adaptor.getOperands().front();
+mlir::Type targetType = convertTy(ptrTy);
+mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(),
dataLayout,
+ptrTy.getPointee());
+auto offset = llvm::SmallVector{0};
erichkeane wrote:
```suggestion
llvm::SmallVector offset{0};
```
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/erichkeane edited https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +375,174 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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;
erichkeane wrote:
You'll have to do a void cast on it then, else this will cause a warning.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/130690
>From a945e21869e5276c66ac979acd893d9bd9afe2cc Mon Sep 17 00:00:00 2001
From: Morris Hafner
Date: Mon, 10 Mar 2025 16:18:34 -0700
Subject: [PATCH 1/4] [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(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(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(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 traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
erichkeane wrote:
I realize this made sense in the case of 'switching from this function to
another' in the incubator, but I think this should probably be an assert
instead.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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();
erichkeane wrote:
probably can't do `auto` here either.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
erichkeane wrote:
Same comment again.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +375,174 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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(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(subExpr));
+ case CK_NoOp: {
+auto v = Visit(const_cast(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(e));
+assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(),
destTy));
+assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
+return Visit(const_cast(subExpr));
case CK_IntegralCast: {
-assert(!cir::MissingFeatures::scalarConversionOpts());
-return emitScalarConversion(Visit(e), e->getType(), destTy,
+ScalarConversionOpts opts;
+if (auto *ice = dyn_cast(ce)) {
+ if (!ice->isPartOfExplicitCast())
+
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(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);
erichkeane wrote:
I think you mentioned we dont have constants implemented? Else just a bool
constant would be sufficient I would expect.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(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(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy))
+castKind = cir::CastKind::bool_to_int;
+ else if (mlir::isa(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(dstTy))
+castKind = cir::CastKind::int_to_float;
+ else
+llvm_unreachable("Internal error: Cast to unexpected type");
+
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType)) {
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+ auto boolType = cgf.getContext().getBOOLType();
erichkeane wrote:
Another case we can't use autos. Also a 3rd way to get a `bool` type?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +78,156 @@ class LLVMLoweringInfo {
class CIR_Op traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--===//
+
+// CK_Dependent
erichkeane wrote:
Neat! Thank you!
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,24 +89,279 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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);
erichkeane wrote:
why convertType here but `getBoolTy` on 106?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +375,174 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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(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(subExpr));
+ case CK_NoOp: {
+auto v = Visit(const_cast(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(e));
+assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(),
destTy));
+assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
+return Visit(const_cast(subExpr));
case CK_IntegralCast: {
-assert(!cir::MissingFeatures::scalarConversionOpts());
-return emitScalarConversion(Visit(e), e->getType(), destTy,
+ScalarConversionOpts opts;
+if (auto *ice = dyn_cast(ce)) {
+ if (!ice->isPartOfExplicitCast())
+
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +359,159 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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(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;
erichkeane wrote:
still, atomic-to-non-atomic cast can change types, so probably should return
something.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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(castOp.getType());
+auto sourceValue = adaptor.getOperands().front();
erichkeane wrote:
A LOT of uses of 'auto' in this function that don't match our coding standard.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/130690
>From a945e21869e5276c66ac979acd893d9bd9afe2cc Mon Sep 17 00:00:00 2001
From: Morris Hafner
Date: Mon, 10 Mar 2025 16:18:34 -0700
Subject: [PATCH 1/5] [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(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(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(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 traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy))
+castKind = cir::CastKind::bool_to_int;
+ else if (mlir::isa(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(dstTy))
+castKind = cir::CastKind::int_to_float;
+ else
+llvm_unreachable("Internal error: Cast to unexpected type");
+} else if (mlir::isa(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 f
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy))
+castKind = cir::CastKind::bool_to_int;
+ else if (mlir::isa(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(dstTy))
+castKind = cir::CastKind::int_to_float;
+ else
+llvm_unreachable("Internal error: Cast to unexpected type");
+} else if (mlir::isa(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 f
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +359,159 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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(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(subExpr));
+ case CK_NoOp: {
+auto v = Visit(const_cast(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(e));
+assert(cgf.getContext().hasSameUnqualifiedType(subExpr->getType(),
destTy));
+assert(subExpr->isGLValue() && "lvalue-to-rvalue applied to r-value!");
+return Visit(const_cast(subExpr));
case CK_IntegralCast: {
-assert(!cir::MissingFeatures::scalarConversionOpts());
-return emitScalarConversion(Visit(e), e->getType(), destTy,
-ce->getExprLoc());
+ScalarConversionOpts opts;
+if (auto *ice = dyn_cast(c
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -121,29 +359,159 @@ mlir::Value CIRGenFunction::emitScalarExpr(const Expr
*e) {
return ScalarExprEmitter(*this, builder).Visit(const_cast(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(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;
erichkeane wrote:
what does this fall through to? Does it result in a sensible value?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +78,111 @@ class LLVMLoweringInfo {
class CIR_Op traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--===//
+
+// The enumaration value isn't in sync with clang.
erichkeane wrote:
We'd discussed offline about trying to sync the two enums in some way, right?
Was that not something viable?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy))
+castKind = cir::CastKind::bool_to_int;
+ else if (mlir::isa(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(dstTy))
+castKind = cir::CastKind::int_to_float;
+ else
+llvm_unreachable("Internal error: Cast to unexpected type");
+} else if (mlir::isa(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 f
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -90,20 +89,259 @@ class ScalarExprEmitter : public
StmtVisitor {
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
erichkeane wrote:
This branch needs to return something.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +79,67 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create(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(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(src.getType()) && "expected ptr src");
+return createBitcast(src, getPointerTo(newPointeeTy));
+ }
+
+ mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
mmha wrote:
Correct. I removed these two functions again for now.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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(x);
+}
+
+// CHECK: cir.func @cxxstaticcast_0
+// CHECK:%0 = cir.alloca !cir.int, !cir.ptr>, ["x",
init] {alignment = 4 : i64}
+// CHECK:cir.store %arg0, %0 : !cir.int, !cir.ptr>
+// CHECK:%1 = cir.load %0 : !cir.ptr>, !cir.int
+// CHECK:%2 = cir.cast(integral, %1 : !cir.int), !cir.int
+// CHECK:cir.return %2 : !cir.int
+// 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),
!cir.int
+
+ short b = (short)x2; // truncate with sign
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int),
!cir.int
+
+ long long c = (long long)x1; // zero extend
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int),
!cir.int
+
+ long long d = (long long)x2; // sign extend
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int),
!cir.int
+
+ unsigned ui = (unsigned)x2; // sign drop
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int),
!cir.int
+
+ int si = (int)x1; // sign add
+ // CHECK: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int),
!cir.int
+
+ unsigned uu = (unsigned)x1; // should not be generated
+ // CHECK-NOT: %{{[0-9]+}} = cir.cast(integral, %{{[0-9]+}} : !cir.int), !cir.int
andykaylor wrote:
I think this check is too specific for CHECK-NOT. Maybe move the cases that
shouldn't cast to a separate function and just CHECK-NOT for `cir.cast` between
the function start and end braces.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -36,6 +36,18 @@ class ScalarExprEmitter : public
StmtVisitor {
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); }
andykaylor wrote:
As discussed earlier, let's get rid of wrapper functions like this.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir andykaylor wrote: Can you expand this test to cover all the cast types you're adding (or remove any that can't be supported yet)? https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +79,67 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create(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(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(src.getType()) && "expected ptr src");
+return createBitcast(src, getPointerTo(newPointeeTy));
+ }
+
+ mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
andykaylor wrote:
I'm guessing these aren't used either. I don't think we have upstreamed any
address space support, have we?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -36,6 +36,18 @@ class ScalarExprEmitter : public
StmtVisitor {
bool ira = false)
: cgf(cgf), builder(builder), ignoreResultAssign(ira) {}
+
//======//
+ // Utilities
+
//======//
+
+ bool TestAndClearIgnoreResultAssign() {
andykaylor wrote:
So, maybe replace calls to this with `std::exchange(ignoreResultAssign,
false)`? That's just as long, but maybe a bit clearer.
I notice there are several places (in the incubator and the classic codegen)
that call this function and then don't use the result. I'm not sure why they're
doing that rather than just `ignoreResultAssign = false;`.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
andykaylor wrote:
We don't need braces with single-statement bodies. (Complete rules here:
https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements)
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/130690
>From b9a55d112998c468cce5cabff33939e4412e7ded Mon Sep 17 00:00:00 2001
From: Morris Hafner
Date: Mon, 10 Mar 2025 16:18:34 -0700
Subject: [PATCH 1/2] [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(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(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(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 e2ab50c78ec2d..caef0947d0b16 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 traits = []> :
Op, LLVMLoweringInfo;
+//===--===//
+// CastOp
+//===--
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -36,6 +36,18 @@ class ScalarExprEmitter : public
StmtVisitor {
bool ira = false)
: cgf(cgf), builder(builder), ignoreResultAssign(ira) {}
+
//======//
+ // Utilities
+
//======//
+
+ bool TestAndClearIgnoreResultAssign() {
mmha wrote:
I noticed that the underlying variable is never read from, making this dead
code. I removed it.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +79,67 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create(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(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) {
mmha wrote:
This is a utility function used in a couple of other `create` or `emit`
functions in the incubator, for example to cast the pointer type in
`createLoad` and `createStore` in the incubator.
Looking at it again this function isn't used in this patch and I copied this by
accident. I'll remove it for now.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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();
erichkeane wrote:
```suggestion
TestAndClearIgnoreResultAssign();
```
More interestingly, why not just ignoreResultAssign = false; or something?
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -78,6 +79,67 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create(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(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) {
erichkeane wrote:
I'm not terribly sure what is going on here, can you share what the point of
this function is? It seems like an odd operation to model specifically (that
is, bitcast(&Thing)).
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/erichkeane edited https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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(e));
erichkeane wrote:
another place we can't use auto.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -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(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(e));
+ case CK_NoOp: {
+auto v = Visit(const_cast(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);
erichkeane wrote:
not a place we can use `auto`.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
erichkeane wrote:
```suggestion
if (llvm::isa(srcType))
```
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
https://github.com/erichkeane commented: We have to be mroe careful I think with uses of the `errorNYI` in a few places, we are using it too much like `assert` when it is more like `emitDiag`. Also, this patch uses `auto` a bunch in ways that are contrary to the coding standard. See : https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable `auto` is really only to be used (rule of thumb) when the type is already 'listed' on the RHS, or naming the type is so obnoxious as to be irrelevant (iterators/etc). https://github.com/llvm/llvm-project/pull/130690 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -84,26 +96,266 @@ class ScalarExprEmitter : public
StmtVisitor {
}
mlir::Value VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *e) {
-mlir::Type type = cgf.convertType(e->getType());
+mlir::Type type = convertType(e->getType());
return builder.create(
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(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(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(srcType))
+ cgf.getCIRGenModule().errorNYI(loc, "member pointer to bool conversion");
+
+if (srcType->isIntegerType())
+ return emitIntToBoolConversion(src, loc);
+
+assert(::mlir::isa(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(srcTy) ||
+mlir::isa(dstTy))
+ llvm_unreachable("Obsolete code. Don't use mlir::IntegerType with CIR.");
+
+mlir::Type fullDstTy = dstTy;
+assert(!cir::MissingFeatures::vectorType());
+
+std::optional castKind;
+
+if (mlir::isa(srcTy)) {
+ if (opts.treatBooleanAsSigned)
+cgf.getCIRGenModule().errorNYI("signed bool");
+ if (cgf.getBuilder().isInt(dstTy)) {
+castKind = cir::CastKind::bool_to_int;
+ } else if (mlir::isa(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(dstTy)) {
+castKind = cir::CastKind::int_to_float;
+ } else {
+llvm_unreachable("Internal error: Cast to unexpected type");
+ }
+} else if (mlir::isa(srcTy)) {
+ if (cgf.getBuilder().isInt(dstTy)) {
+/
[clang] [CIR] Upstream CastOp and scalar conversions (PR #130690)
@@ -36,6 +36,18 @@ class ScalarExprEmitter : public
StmtVisitor {
bool ira = false)
: cgf(cgf), builder(builder), ignoreResultAssign(ira) {}
+
//======//
+ // Utilities
+
//======//
+
+ bool TestAndClearIgnoreResultAssign() {
erichkeane wrote:
Oh boy this name is a bit of a word-soup :D This is actually more of an
`exchange` in c++ parlance.
https://github.com/llvm/llvm-project/pull/130690
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
