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

Reply via email to