Author: adams381 Date: 2026-06-15T14:51:47-05:00 New Revision: c194b5ff3d30517493a25a8f0c9f62ba86ba5360
URL: https://github.com/llvm/llvm-project/commit/c194b5ff3d30517493a25a8f0c9f62ba86ba5360 DIFF: https://github.com/llvm/llvm-project/commit/c194b5ff3d30517493a25a8f0c9f62ba86ba5360.diff LOG: [CIR] Lower vector integer/float to bool casts (#203397) An ext_vector integer-to-bool or float-to-bool conversion (e.g. `__builtin_convertvector` from `int4` to `bool4`) crashed clang in `emitScalarCast` (`CIRGenExprScalar.cpp`). `emitScalarConversion` only special-cases scalar bool (`dstType->isBooleanType()`), so a vector-of-bool destination fell through to `emitScalarCast`, whose integer/float source branches had no bool-element destination case and hit `llvm_unreachable`. The fix adds the `int_to_bool`/`float_to_bool` cast kinds for a bool element destination, mirroring the bool-source branch. It also builds the LowerToLLVM zero operand via `getZeroAttr` so it splats for vectors, and compares element widths in `bool_to_int` so the round trip lowers for vectors too. The conversion now lowers to an elementwise `icmp ne` / `fcmp une` against zero, matching classic codegen. libcxx's vectorized comparison helpers (e.g. `flat_map`/`flat_multimap` construction, `ranges::starts_with`) reach this path; this clears the crash, though those tests still hit unrelated NYIs. Added: clang/test/CIR/CodeGen/vector-convert-to-bool.c Modified: clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 6bad03f92bfc7..f93380ef62132 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -539,6 +539,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { castKind = cir::CastKind::integral; else if (mlir::isa<cir::FPTypeInterface>(dstTy)) castKind = cir::CastKind::int_to_float; + else if (mlir::isa<cir::BoolType>(dstTy)) + castKind = cir::CastKind::int_to_bool; else llvm_unreachable("Internal error: Cast to unexpected type"); } else if (mlir::isa<cir::FPTypeInterface>(srcTy)) { @@ -553,6 +555,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) { // TODO: split this to createFPExt/createFPTrunc return builder.createFloatingCast(src, fullDstTy); + } else if (mlir::isa<cir::BoolType>(dstTy)) { + castKind = cir::CastKind::float_to_bool; } else { llvm_unreachable("Internal error: Cast to unexpected type"); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index d93888cd0b601..c844375a000e0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1257,8 +1257,12 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite( } case cir::CastKind::int_to_bool: { mlir::Value llvmSrcVal = adaptor.getSrc(); + // getZeroAttr yields a splat for vector source types so this also + // handles element-wise int-to-bool conversions (e.g. an ext_vector + // __builtin_convertvector to bool). mlir::Value zeroInt = mlir::LLVM::ConstantOp::create( - rewriter, castOp.getLoc(), llvmSrcVal.getType(), 0); + rewriter, castOp.getLoc(), llvmSrcVal.getType(), + rewriter.getZeroAttr(llvmSrcVal.getType())); rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroInt); break; @@ -1321,10 +1325,12 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite( mlir::Value llvmSrcVal = adaptor.getSrc(); auto kind = mlir::LLVM::FCmpPredicate::une; - // Check if float is not equal to zero. + // Check if float is not equal to zero. getZeroAttr yields a splat + // for vector source types so this also handles element-wise + // float-to-bool conversions. auto zeroFloat = mlir::LLVM::ConstantOp::create( rewriter, castOp.getLoc(), llvmSrcVal.getType(), - mlir::FloatAttr::get(llvmSrcVal.getType(), 0.0)); + rewriter.getZeroAttr(llvmSrcVal.getType())); // Extend comparison result to either bool (C++) or int (C). rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(castOp, kind, llvmSrcVal, @@ -1333,13 +1339,15 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite( return mlir::success(); } case cir::CastKind::bool_to_int: { - auto dstTy = mlir::cast<cir::IntType>(castOp.getType()); + mlir::Type dstTy = castOp.getType(); mlir::Value llvmSrcVal = adaptor.getSrc(); - auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType()); - auto llvmDstTy = - mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy)); + mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy); + // Compare element widths so this also handles vector bool -> int casts. + auto srcElemTy = mlir::cast<mlir::IntegerType>( + elementTypeIfVector(llvmSrcVal.getType())); + auto dstElemTy = mlir::cast<cir::IntType>(elementTypeIfVector(dstTy)); - if (llvmSrcTy.getWidth() == llvmDstTy.getWidth()) + if (srcElemTy.getWidth() == dstElemTy.getWidth()) rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy, llvmSrcVal); else diff --git a/clang/test/CIR/CodeGen/vector-convert-to-bool.c b/clang/test/CIR/CodeGen/vector-convert-to-bool.c new file mode 100644 index 0000000000000..273aa3b380c41 --- /dev/null +++ b/clang/test/CIR/CodeGen/vector-convert-to-bool.c @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +typedef int int4 __attribute__((ext_vector_type(4))); +typedef long long2 __attribute__((ext_vector_type(2))); +typedef float float4 __attribute__((ext_vector_type(4))); +typedef _Bool bool4 __attribute__((ext_vector_type(4))); +typedef _Bool bool2 __attribute__((ext_vector_type(2))); + +// The bool vector is kept in registers (round-tripped back to an integer +// vector) so this isolates the element-wise int/float <-> bool casts. + +int4 int_to_bool_vec(int4 a) { + return __builtin_convertvector(__builtin_convertvector(a, bool4), int4); +} + +// CIR-LABEL: cir.func{{.*}} @int_to_bool_vec +// CIR: %[[M:.*]] = cir.cast int_to_bool %{{.+}} : !cir.vector<4 x !s32i> -> !cir.vector<4 x !cir.bool> +// CIR: cir.cast bool_to_int %[[M]] : !cir.vector<4 x !cir.bool> -> !cir.vector<4 x !s32i> + +// LLVM-LABEL: @int_to_bool_vec +// LLVM: %[[M:.*]] = icmp ne <4 x i32> %{{.+}}, zeroinitializer +// LLVM: zext <4 x i1> %[[M]] to <4 x i32> + +long2 long_to_bool_vec(long2 a) { + return __builtin_convertvector(__builtin_convertvector(a, bool2), long2); +} + +// CIR-LABEL: cir.func{{.*}} @long_to_bool_vec +// CIR: %[[M:.*]] = cir.cast int_to_bool %{{.+}} : !cir.vector<2 x !s64i> -> !cir.vector<2 x !cir.bool> +// CIR: cir.cast bool_to_int %[[M]] : !cir.vector<2 x !cir.bool> -> !cir.vector<2 x !s64i> + +// LLVM-LABEL: @long_to_bool_vec +// LLVM: %[[M:.*]] = icmp ne <2 x i64> %{{.+}}, zeroinitializer +// LLVM: zext <2 x i1> %[[M]] to <2 x i64> + +int4 float_to_bool_vec(float4 a) { + return __builtin_convertvector(__builtin_convertvector(a, bool4), int4); +} + +// CIR-LABEL: cir.func{{.*}} @float_to_bool_vec +// CIR: %[[M:.*]] = cir.cast float_to_bool %{{.+}} : !cir.vector<4 x !cir.float> -> !cir.vector<4 x !cir.bool> +// CIR: cir.cast bool_to_int %[[M]] : !cir.vector<4 x !cir.bool> -> !cir.vector<4 x !s32i> + +// LLVM-LABEL: @float_to_bool_vec +// LLVM: %[[M:.*]] = fcmp une <4 x float> %{{.+}}, zeroinitializer +// LLVM: zext <4 x i1> %[[M]] to <4 x i32> + +float4 bool_to_float_vec(int4 a) { + return __builtin_convertvector(__builtin_convertvector(a, bool4), float4); +} + +// CIR-LABEL: cir.func{{.*}} @bool_to_float_vec +// CIR: %[[M:.*]] = cir.cast int_to_bool %{{.+}} : !cir.vector<4 x !s32i> -> !cir.vector<4 x !cir.bool> +// CIR: cir.cast bool_to_float %[[M]] : !cir.vector<4 x !cir.bool> -> !cir.vector<4 x !cir.float> + +// LLVM-LABEL: @bool_to_float_vec +// LLVM: %[[M:.*]] = icmp ne <4 x i32> %{{.+}}, zeroinitializer +// LLVM: uitofp <4 x i1> %[[M]] to <4 x float> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
