Skip to content

[CIR] Support vector of bool with padding - #215850

Open
AmrDeveloper wants to merge 1 commit into
llvm:mainfrom
AmrDeveloper:cir_vec_bool_emit_bool_vec_conv
Open

[CIR] Support vector of bool with padding#215850
AmrDeveloper wants to merge 1 commit into
llvm:mainfrom
AmrDeveloper:cir_vec_bool_emit_bool_vec_conv

Conversation

@AmrDeveloper

Copy link
Copy Markdown
Member

Support the vector of bool emit from and to memory with padding

@llvmorg-github-actions llvmorg-github-actions Bot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Aug 12, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

Support the vector of bool emit from and to memory with padding


Full diff: https://github.com/llvm/llvm-project/pull/215850.diff

2 Files Affected:

  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+29-3)
  • (modified) clang/test/CIR/CodeGen/vector-bool.cpp (+21)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index ccdc974ca1b93..0aad68f83e9e4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -199,6 +199,24 @@ lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) {
   }
 }
 
+static mlir::Value
+emitBoolVecConversion(mlir::ConversionPatternRewriter &rewriter,
+                      mlir::Value srcVec, cir::VectorType srcTy,
+                      unsigned numElementsDst) {
+  unsigned numElementsSrc = srcTy.getSize();
+  if (numElementsSrc == numElementsDst)
+    return srcVec;
+
+  SmallVector<int32_t, 8> mask(numElementsDst, -1);
+  for (unsigned i : llvm::seq(std::min(numElementsDst, numElementsSrc)))
+    mask[i] = i;
+
+  mlir::Location loc = srcVec.getLoc();
+  auto poison = mlir::LLVM::PoisonOp::create(rewriter, loc, srcVec.getType());
+  return mlir::LLVM::ShuffleVectorOp::create(rewriter, loc, srcVec, poison,
+                                             mask);
+}
+
 /// Emits the value from memory as expected by its users. Should be called when
 /// the memory represetnation of a CIR type is not equal to its scalar
 /// representation.
@@ -216,9 +234,15 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,
   // Convert the `iN` back to boolean vectors
   if (auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) {
     if (mlir::isa<cir::BoolType>(vecTy.getElementType())) {
-      mlir::Type mlirVecTy = converter.convertType(vecTy);
-      return mlir::LLVM::BitcastOp::create(rewriter, value.getLoc(), mlirVecTy,
-                                           value);
+      auto rawIntTy = mlir::cast<mlir::IntegerType>(value.getType());
+      auto paddedVecTy =
+          cir::VectorType::get(vecTy.getElementType(), rawIntTy.getWidth());
+      mlir::Type mlirVecTy = converter.convertType(paddedVecTy);
+      // Bitcast iP --> <P x i1>.
+      auto v = mlir::LLVM::BitcastOp::create(rewriter, value.getLoc(),
+                                             mlirVecTy, value);
+      // Shuffle <P x i1> --> <N x i1> (N is the actual bit size).
+      return emitBoolVecConversion(rewriter, v, paddedVecTy, vecTy.getSize());
     }
   }
 
@@ -251,6 +275,8 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,
     if (mlir::isa<cir::BoolType>(vecTy.getElementType())) {
       uint64_t bytePadded = std::max<uint64_t>(vecTy.getSize(), 8);
       auto resultTy = mlir::IntegerType::get(origType.getContext(), bytePadded);
+      value =
+          emitBoolVecConversion(rewriter, value, vecTy, resultTy.getWidth());
       return mlir::LLVM::BitcastOp::create(rewriter, value.getLoc(), resultTy,
                                            value);
     }
diff --git a/clang/test/CIR/CodeGen/vector-bool.cpp b/clang/test/CIR/CodeGen/vector-bool.cpp
index 724d8109b048a..c777dc95414ab 100644
--- a/clang/test/CIR/CodeGen/vector-bool.cpp
+++ b/clang/test/CIR/CodeGen/vector-bool.cpp
@@ -5,6 +5,7 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
 // RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
 
+typedef bool v4b __attribute__((ext_vector_type(4)));
 typedef bool v8b __attribute__((ext_vector_type(8)));
 
 void vec_bool_without_padding_needed() {
@@ -62,3 +63,23 @@ void vec_bool_extract_insert_without_padding_needed() {
 // LLVM: %[[RESULT:.*]] = insertelement <8 x i1> %[[TMP_A_VEC]], i1 %[[B_ELEM_3]], i32 2
 // LLVM: %[[RESULT_I8:.*]] = bitcast <8 x i1> %[[RESULT]] to i8
 // LLVM: store i8 %[[RESULT_I8]], ptr %[[A_ADDR]], align 1
+
+void vec_bool_load_store_with_padding_needed() {
+  v4b a;
+  v4b b;
+  a = b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!cir.vector<4 x !cir.bool>>
+// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!cir.vector<4 x !cir.bool>>
+// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<4 x !cir.bool>>, !cir.vector<4 x !cir.bool>
+// CIR: cir.store {{.*}} %[[TMP_B]], %[[A_ADDR]] : !cir.vector<4 x !cir.bool>, !cir.ptr<!cir.vector<4 x !cir.bool>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca i8, {{.*}}align 1
+// LLVM: %[[B_ADDR:.*]] = alloca i8, {{.*}}align 1
+// LLVM: %[[TMP_B:.*]] = load i8, ptr %[[B_ADDR]], align 1
+// LLVM: %[[TMP_B_VEC:.*]] = bitcast i8 %[[TMP_B]] to <8 x i1>
+// LLVM: %[[EXTRACT_VEC:.*]] = shufflevector <8 x i1> %[[TMP_B_VEC]], <8 x i1> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// LLVM: %[[INSERT_VEC:.*]] = shufflevector <4 x i1> %[[EXTRACT_VEC]], <4 x i1> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
+// LLVM: %[[RESULT:.*]] = bitcast <8 x i1> %[[INSERT_VEC]] to i8
+// LLVM: store i8 %[[RESULT]], ptr %[[A_ADDR]], align 1

@bcardosolopes bcardosolopes left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM: two inline comments, neither blocking.

emitBoolVecConversion(mlir::ConversionPatternRewriter &rewriter,
mlir::Value srcVec, cir::VectorType srcTy,
unsigned numElementsDst) {
unsigned numElementsSrc = srcTy.getSize();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OG reads the source count off the value instead of taking a type alongside it (CodeGenFunction.cpp:3455, cast<llvm::FixedVectorType>(SrcVec->getType())). Same thing here would drop the parameter and remove any chance of srcTy and srcVec disagreeing about the lane count.

emitFromMemory then only needs paddedVecTy for the bitcast, and the call reads emitBoolVecConversion(rewriter, v, vecTy.getSize()).

// LLVM: %[[RESULT_I8:.*]] = bitcast <8 x i1> %[[RESULT]] to i8
// LLVM: store i8 %[[RESULT_I8]], ptr %[[A_ADDR]], align 1

void vec_bool_load_store_with_padding_needed() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytePadded is max(N, 8), so padding only ever happens below 8 lanes: 1 to 7 is the whole interesting range, and it's covered here for load/store only.

Can you add the v4b companion to vec_bool_extract_insert_without_padding_needed? That's the path where the shuffle has to land on exactly <4 x i1> for the extractelement/insertelement index to mean anything, so it's the more useful of the two. An odd size like ext_vector_type(3) would be a good second data point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants