https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/212146
>From 49aa8c6c0ca098570cd3df463af75fe30460bf87 Mon Sep 17 00:00:00 2001 From: Amr Hesham <[email protected]> Date: Thu, 6 Aug 2026 11:02:11 +0200 Subject: [PATCH] [CIR] Support load/store for Vector of bools --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 26 +--------- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 32 +++++++++++-- clang/test/CIR/CodeGen/vector-bool.cpp | 47 +++++++++++++++++++ 3 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 clang/test/CIR/CodeGen/vector-bool.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index eef1cda1c90f9..34c7efc208ca2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -469,18 +469,10 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr, bool isNontemporal) { if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) { - // Boolean vectors use `iN` as storage type. - if (clangVecTy->isExtVectorBoolType()) - cgm.errorNYI(addr.getPointer().getLoc(), - "emitStoreOfScalar ExtVectorBoolType"); - // Handle vectors of size 3 like size 4 for better performance. - const mlir::Type elementType = addr.getElementType(); - const auto vecTy = cast<cir::VectorType>(elementType); - // TODO(CIR): Use `ABIInfo::getOptimalVectorMemoryType` once it upstreamed assert(!cir::MissingFeatures::cirgenABIInfo()); - if (vecTy.getSize() == 3 && !getLangOpts().PreserveVec3Type) + if (clangVecTy->getNumElements() == 3 && !getLangOpts().PreserveVec3Type) cgm.errorNYI(addr.getPointer().getLoc(), "emitStoreOfScalar Vec3 & PreserveVec3Type disabled"); } @@ -707,14 +699,8 @@ LValue CIRGenFunction::emitLValueForFieldInitialization( mlir::Value CIRGenFunction::emitToMemory(mlir::Value value, QualType ty) { if (auto *atomicTy = ty->getAs<AtomicType>()) ty = atomicTy->getValueType(); - - if (ty->isExtVectorBoolType()) { - cgm.errorNYI("emitToMemory: extVectorBoolType"); - } - // Unlike in classic codegen CIR, bools are kept as `cir.bool` and BitInts are // kept as `cir.int<N>` until further lowering - return value; } @@ -748,18 +734,10 @@ mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile, // Traditional LLVM codegen handles thread local separately, CIR handles // as part of getAddrOfGlobalVar (GetGlobalOp). mlir::Type eltTy = addr.getElementType(); - if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) { - if (clangVecTy->isExtVectorBoolType()) { - cgm.errorNYI(loc, "emitLoadOfScalar: ExtVectorBoolType"); - return nullptr; - } - - const auto vecTy = cast<cir::VectorType>(eltTy); - // Handle vectors of size 3 like size 4 for better performance. assert(!cir::MissingFeatures::cirgenABIInfo()); - if (vecTy.getSize() == 3 && !getLangOpts().PreserveVec3Type) + if (clangVecTy->getNumElements() == 3 && !getLangOpts().PreserveVec3Type) cgm.errorNYI(addr.getPointer().getLoc(), "emitLoadOfScalar Vec3 & PreserveVec3Type disabled"); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 08c2405547dae..8e0ada62a5cb0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -115,6 +115,13 @@ static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, dataLayout.getTypeSizeInBits(type)); } + if (auto vecTy = mlir::dyn_cast<cir::VectorType>(type)) { + if (mlir::isa<cir::BoolType>(vecTy.getElementType())) { + uint64_t bytePadded = std::max<uint64_t>(vecTy.getSize(), 8); + return mlir::IntegerType::get(type.getContext(), bytePadded); + } + } + // _BitInt(N) keeps its literal width as a value but is stored in a padded // integer iM in memory, the same way bool is i1 as a value and i8 in memory. // The byte-array storage form for wide split widths is not implemented; a @@ -194,9 +201,9 @@ lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) { /// the memory represetnation of a CIR type is not equal to its scalar /// representation. static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter &converter, mlir::DataLayout const &dataLayout, cir::LoadOp op, mlir::Value value) { - // TODO(cir): Handle other types similarly to clang's codegen EmitFromMemory if (auto boolTy = mlir::dyn_cast<cir::BoolType>(op.getType())) { // Create a cast value from specified size in datalayout to i1 @@ -204,6 +211,15 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, return createIntCast(rewriter, value, rewriter.getI1Type()); } + // 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); + } + } + // Truncate the padded storage integer back to the _BitInt's literal width. if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getType()); intTy && intTy.isBitInt()) @@ -228,6 +244,16 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter, return createIntCast(rewriter, value, memType); } + // Boolean vectors use `iN` as storage type + if (auto vecTy = mlir::dyn_cast<cir::VectorType>(origType)) { + 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); + return mlir::LLVM::BitcastOp::create(rewriter, value.getLoc(), resultTy, + value); + } + } + // Sign/zero-extend the _BitInt value to its padded storage integer. if (auto intTy = mlir::dyn_cast<cir::IntType>(origType); intTy && intTy.isBitInt()) @@ -2244,8 +2270,8 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite( newLoad->setAttr("cir.riscv_nontemporal_domain", domain); // Convert adapted result to its original type if needed. - mlir::Value result = - emitFromMemory(rewriter, dataLayout, op, newLoad.getResult()); + mlir::Value result = emitFromMemory(rewriter, *getTypeConverter(), dataLayout, + op, newLoad.getResult()); rewriter.replaceOp(op, result); assert(!cir::MissingFeatures::opLoadStoreTbaa()); return mlir::LogicalResult::success(); diff --git a/clang/test/CIR/CodeGen/vector-bool.cpp b/clang/test/CIR/CodeGen/vector-bool.cpp new file mode 100644 index 0000000000000..b5e8b9b3a2c88 --- /dev/null +++ b/clang/test/CIR/CodeGen/vector-bool.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -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 -Wno-unused-value -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 -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +typedef bool v8b __attribute__((ext_vector_type(8))); + +void vec_bool_without_padding_needed() { + v8b a; + v8b b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!cir.vector<8 x !cir.bool>> +// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!cir.vector<8 x !cir.bool>> + +// LLVM: %[[A_ADDR:.*]] = alloca i8, i64 1, align 1 +// LLVM: %[[B_ADDR:.*]] = alloca i8, i64 1, align 1 + +// OGCG: %[[A_ADDR:.*]] = alloca i8, align 1 +// OGCG: %[[B_ADDR:.*]] = alloca i8, align 1 + +void vec_bool_load_store_without_padding_needed() { + v8b a; + v8b b; + a = b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!cir.vector<8 x !cir.bool>> +// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!cir.vector<8 x !cir.bool>> +// CIR: %[[TMP_B:.*]] = cir.load {{.*}} %[[B_ADDR]] : !cir.ptr<!cir.vector<8 x !cir.bool>>, !cir.vector<8 x !cir.bool> +// CIR: cir.store {{.*}} %[[TMP_B]], %[[A_ADDR]] : !cir.vector<8 x !cir.bool>, !cir.ptr<!cir.vector<8 x !cir.bool>> + +// LLVM: %[[A_ADDR:.*]] = alloca i8, i64 1, align 1 +// LLVM: %[[B_ADDR:.*]] = alloca i8, i64 1, 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: %[[TMP_B_I8:.*]] = bitcast <8 x i1> %[[TMP_B_VEC]] to i8 +// LLVM: store i8 %[[TMP_B_I8]], ptr %[[A_ADDR]], align 1 + +// OGCG: %[[A_ADDR:.*]] = alloca i8, align 1 +// OGCG: %[[B_ADDR:.*]] = alloca i8, align 1 +// OGCG: %[[TMP_B:.*]] = load i8, ptr %b, align 1 +// OGCG: %[[TMP_B_VEC:.*]] = bitcast i8 %[[TMP_B]] to <8 x i1> +// OGCG: %[[TMP_B_I8:.*]] = bitcast <8 x i1> %[[TMP_B_VEC]] to i8 +// OGCG: store i8 %[[TMP_B_I8]], ptr %[[A_ADDR]], align 1 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
