[clang] [CIR] Lower _BitInt to its in-memory storage integer (PR #206606)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 15:46:03 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: adams381
<details>
<summary>Changes</summary>
ClangIR keeps a `_BitInt(N)` at its literal width, but in memory it has to live in a wider padded integer, the same way `bool` is `i1` as a value and `i8` in memory. Because CIRGen emitted the constant at its exact width, the storage padding was left undefined: a `signed _BitInt(6) = -1` wrote `0x3f` where classic CodeGen and GCC write `0xff`. @<!-- -->andykaylor pointed this out on [#<!-- -->205605](https://github.com/llvm/llvm-project/pull/205605).
The fix widens `_BitInt` to its storage integer `iM` and sign/zero-extends by signedness during lowering to the LLVM dialect, the same place `bool` becomes `i8` (`convertTypeForMemory` and the to/from-memory helpers). CIRGen keeps the literal `!cir.int<N, bitint>` unchanged.
The byte-array storage form for wide "split" widths, where the storage integer's alloc size exceeds its store size (e.g. `_BitInt(129)` to `i192`, 32 vs 24 bytes), is not implemented. The global, alloca, load, and store lowerings report an NYI error and the aggregate type converters fail the conversion, rather than emit a wrong-sized integer. Atomic read-modify-write on a padded `_BitInt` and vector-of-`_BitInt` are also unimplemented.
The storage width comes from `IntType::getABIAlignment`, which assumes a fixed 64-bit maximum alignment (x86-64). It is verified byte-for-byte on x86-64; on targets with a larger maximum (e.g. AArch64) any width that would be mis-sized instead hits the split-storage NYI. On a target whose `_BitInt` maximum alignment is below 64 bits (e.g. a 32-bit target) the storage can be mis-sized. Making the computation target-aware needs the target's `getBitIntAlign`, which is not in the data layout, and is left as a follow-up.
The approach follows the RFC [Widen bool / _BitInt / ext-vector-bool to their in-memory types in lowering](https://discourse.llvm.org/t/rfc-clangir-widen-bool-bitint-ext-vector-bool-to-their-in-memory-types-in-lowering/91160). It supersedes [#<!-- -->205605](https://github.com/llvm/llvm-project/pull/205605), which emitted the constant at its literal width.
---
Patch is 27.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/206606.diff
8 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp (+4-3)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+174-19)
- (modified) clang/lib/CIR/Lowering/LoweringHelpers.cpp (+13-2)
- (modified) clang/test/CIR/CodeGen/array.cpp (+4-3)
- (added) clang/test/CIR/CodeGen/bitint-memory.c (+61)
- (added) clang/test/CIR/CodeGen/bitint-split-storage-nyi.c (+11)
- (modified) clang/test/CIR/CodeGen/bitint.c (+2-10)
- (modified) clang/test/CIR/Lowering/global-var-simple.cpp (+2-2)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 9ad172211ea60..3ba93fda17e68 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1255,9 +1255,10 @@ mlir::Attribute ConstantEmitter::emitForMemory(CIRGenModule &cgm,
cgm.errorNYI("emitForMemory: zero-extend HLSL bool vectors");
}
- if (destType->isBitIntType()) {
- cgm.errorNYI("emitForMemory: _BitInt type");
- }
+ // CIR represents source types as literally as possible. Some types, such as
+ // bool and _BitInt(N), are kept at their literal width here and expanded to
+ // their wider "in memory" types during lowering to the LLVM dialect, so the
+ // constant is already in the right form and needs no adjustment.
return c;
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index e0fc9e58ed4b7..71320837ae576 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -76,6 +76,32 @@ mlir::Type elementTypeIfVector(mlir::Type type) {
}
} // namespace
+/// In-memory storage width in bits for a _BitInt(N): N rounded up to the type's
+/// ABI alignment. This equals sizeof(_BitInt(N)) * 8 on the default target
+/// (e.g. _BitInt(6) -> 8, _BitInt(17) -> 32, _BitInt(128) -> 128).
+static unsigned getBitIntMemoryStorageBits(cir::IntType ty,
+ const mlir::DataLayout &dataLayout) {
+ uint64_t alignBits = ty.getABIAlignment(dataLayout, {}) * 8;
+ return llvm::alignTo(ty.getWidth(), alignBits);
+}
+
+/// A _BitInt(N) whose padded storage integer iM has a larger alloc size than
+/// its M/8 store size is laid out by clang as a byte array, not a plain integer
+/// (e.g. _BitInt(129) -> i192 with alloc size 32 != store size 24). That
+/// "split" storage form is not yet implemented; lowerings must detect it and
+/// report errorNYI rather than emit the wrong-sized integer.
+static bool isSplitStorageBitInt(cir::IntType ty,
+ const mlir::DataLayout &dataLayout) {
+ if (!ty.isBitInt())
+ return false;
+ unsigned storageBits = getBitIntMemoryStorageBits(ty, dataLayout);
+ auto storageTy = mlir::IntegerType::get(ty.getContext(), storageBits);
+ uint64_t storeSize = storageBits / 8;
+ uint64_t allocSize =
+ llvm::alignTo(storeSize, dataLayout.getTypeABIAlignment(storageTy));
+ return allocSize != storeSize;
+}
+
/// Given a type convertor and a data layout, convert the given type to a type
/// that is suitable for memory operations. For example, this can be used to
/// lower cir.bool accesses to i8.
@@ -89,9 +115,46 @@ static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
dataLayout.getTypeSizeInBits(type));
}
+ // _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
+ // null return signals that, and op lowerings turn it into errorNYI.
+ if (auto intTy = mlir::dyn_cast<cir::IntType>(type);
+ intTy && intTy.isBitInt()) {
+ if (isSplitStorageBitInt(intTy, dataLayout))
+ return {};
+ return mlir::IntegerType::get(
+ type.getContext(), getBitIntMemoryStorageBits(intTy, dataLayout));
+ }
+
return converter.convertType(type);
}
+/// True for a _BitInt atomic operand whose width is not a natural atomic-legal
+/// integer width. Such an operand's value type iN differs from its in-memory
+/// storage iM, and the atomic op lowerings here pass the value through without
+/// the widening the load/store helpers apply, so they must report errorNYI.
+static bool isUnsupportedBitIntAtomic(mlir::Type cirType) {
+ auto intTy = mlir::dyn_cast<cir::IntType>(cirType);
+ if (!intTy || !intTy.isBitInt())
+ return false;
+ unsigned width = intTy.getWidth();
+ return width != 8 && width != 16 && width != 32 && width != 64 &&
+ width != 128;
+}
+
+/// Alignment to use for a memory access whose op carries no explicit alignment.
+/// For _BitInt the storage integer iM's ABI alignment (e.g. i128's 16)
+/// over-aligns the value, so use the CIR _BitInt ABI alignment (e.g. 8).
+static uint64_t getMemoryFallbackAlignment(mlir::Type cirType,
+ mlir::Type llvmMemType,
+ const mlir::DataLayout &dataLayout) {
+ if (auto intTy = mlir::dyn_cast<cir::IntType>(cirType);
+ intTy && intTy.isBitInt())
+ return intTy.getABIAlignment(dataLayout, {});
+ return dataLayout.getTypeABIAlignment(llvmMemType);
+}
+
static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,
mlir::IntegerType dstTy,
bool isSigned = false) {
@@ -137,6 +200,16 @@ static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,
return createIntCast(rewriter, value, rewriter.getI1Type());
}
+ // 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()) {
+ unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout);
+ if (storageBits == intTy.getWidth())
+ return value;
+ return createIntCast(rewriter, value,
+ rewriter.getIntegerType(intTy.getWidth()));
+ }
+
return value;
}
@@ -155,6 +228,18 @@ static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,
return createIntCast(rewriter, value, memType);
}
+ // Sign/zero-extend the _BitInt value to its padded storage integer so the
+ // in-memory padding bits are well-defined (sign bits for signed, zero
+ // otherwise), matching classic CodeGen.
+ if (auto intTy = mlir::dyn_cast<cir::IntType>(origType);
+ intTy && intTy.isBitInt()) {
+ unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout);
+ if (storageBits == intTy.getWidth())
+ return value;
+ return createIntCast(rewriter, value, rewriter.getIntegerType(storageBits),
+ intTy.isSigned());
+ }
+
return value;
}
@@ -423,9 +508,14 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::BoolAttr boolAttr) {
/// IntAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {
mlir::Location loc = parentOp->getLoc();
- return mlir::LLVM::ConstantOp::create(
+ mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
+ // Materialize the value at its literal width, then widen to the in-memory
+ // storage type (a no-op except for _BitInt) so aggregate members built here
+ // match the iM struct/array fields produced by convertTypeForMemory.
+ mlir::Value val = mlir::LLVM::ConstantOp::create(
rewriter, loc, converter->convertType(intAttr.getType()),
intAttr.getValue());
+ return emitToMemory(rewriter, layout, intAttr.getType(), val);
}
/// FPAttr visitor.
@@ -709,15 +799,19 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) {
/// UndefAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::UndefAttr undefAttr) {
mlir::Location loc = parentOp->getLoc();
+ mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
return mlir::LLVM::UndefOp::create(
- rewriter, loc, converter->convertType(undefAttr.getType()));
+ rewriter, loc,
+ convertTypeForMemory(*converter, layout, undefAttr.getType()));
}
/// PoisonAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::PoisonAttr poisonAttr) {
mlir::Location loc = parentOp->getLoc();
+ mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
return mlir::LLVM::PoisonOp::create(
- rewriter, loc, converter->convertType(poisonAttr.getType()));
+ rewriter, loc,
+ convertTypeForMemory(*converter, layout, poisonAttr.getType()));
}
// VTableAttr visitor.
@@ -738,8 +832,9 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) {
/// ZeroAttr visitor.
mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr attr) {
mlir::Location loc = parentOp->getLoc();
- return mlir::LLVM::ZeroOp::create(rewriter, loc,
- converter->convertType(attr.getType()));
+ mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
+ return mlir::LLVM::ZeroOp::create(
+ rewriter, loc, convertTypeForMemory(*converter, layout, attr.getType()));
}
// This class handles rewriting initializer attributes for types that do not
@@ -758,7 +853,17 @@ class GlobalInitAttrRewriter {
}
mlir::Attribute visitCirAttr(cir::IntAttr attr) {
- return rewriter.getIntegerAttr(llvmType, attr.getValue());
+ // A _BitInt(N) global stores its value in a padded integer iM; sign/zero-
+ // extend the APInt to that width (a no-op for plain integers, whose value
+ // width already matches llvmType) so the IntegerAttr is well-typed.
+ llvm::APInt val = attr.getValue();
+ auto destTy = mlir::cast<mlir::IntegerType>(llvmType);
+ if (val.getBitWidth() != destTy.getWidth()) {
+ auto cirIntTy = mlir::cast<cir::IntType>(attr.getType());
+ val = cirIntTy.isSigned() ? val.sext(destTy.getWidth())
+ : val.zext(destTy.getWidth());
+ }
+ return rewriter.getIntegerAttr(llvmType, val);
}
mlir::Attribute visitCirAttr(cir::FPAttr attr) {
@@ -909,6 +1014,9 @@ getLLVMSyncScope(std::optional<cir::SyncScopeKind> syncScope) {
mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(
cir::AtomicCmpXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
+ if (isUnsupportedBitIntAtomic(op.getExpected().getType()))
+ return op.emitError()
+ << "NYI: atomic compare-exchange on a _BitInt with padded storage";
mlir::Value expected = adaptor.getExpected();
mlir::Value desired = adaptor.getDesired();
@@ -935,6 +1043,9 @@ mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(
mlir::LogicalResult CIRToLLVMAtomicXchgOpLowering::matchAndRewrite(
cir::AtomicXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
+ if (isUnsupportedBitIntAtomic(op.getVal().getType()))
+ return op.emitError()
+ << "NYI: atomic exchange on a _BitInt with padded storage";
assert(!cir::MissingFeatures::atomicSyncScopeID());
mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getMemOrder());
llvm::StringRef llvmSyncScope = getLLVMSyncScope(adaptor.getSyncScope());
@@ -1107,6 +1218,9 @@ mlir::Value CIRToLLVMAtomicFetchOpLowering::buildMinMaxPostOp(
mlir::LogicalResult CIRToLLVMAtomicFetchOpLowering::matchAndRewrite(
cir::AtomicFetchOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
+ if (isUnsupportedBitIntAtomic(op.getVal().getType()))
+ return op.emitError()
+ << "NYI: atomic fetch on a _BitInt with padded storage";
bool isInt = false;
bool isSignedInt = false;
if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getVal().getType())) {
@@ -1710,6 +1824,9 @@ mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
typeConverter->convertType(rewriter.getIndexType()), 1);
mlir::Type elementTy =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType());
+ if (!elementTy)
+ return op.emitError()
+ << "NYI: lowering alloca of a _BitInt with byte-array storage";
mlir::Type resultTy =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
@@ -1916,10 +2033,13 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(
mlir::ConversionPatternRewriter &rewriter) const {
const mlir::Type llvmTy =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
+ if (!llvmTy)
+ return op.emitError()
+ << "NYI: lowering load of a _BitInt with byte-array storage";
mlir::LLVM::AtomicOrdering ordering = getLLVMMemOrder(op.getMemOrder());
std::optional<size_t> opAlign = op.getAlignment();
- unsigned alignment =
- (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));
+ unsigned alignment = (unsigned)opAlign.value_or(
+ getMemoryFallbackAlignment(op.getType(), llvmTy, dataLayout));
assert(!cir::MissingFeatures::lowerModeOptLevel());
@@ -1946,6 +2066,9 @@ cir::direct::CIRToLLVMVecMaskedLoadOpLowering::matchAndRewrite(
mlir::ConversionPatternRewriter &rewriter) const {
const mlir::Type llvmResTy =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
+ if (!llvmResTy)
+ return op.emitError()
+ << "NYI: lowering masked load of a _BitInt with byte-array storage";
std::optional<size_t> opAlign = op.getAlignment();
unsigned alignment =
@@ -1965,11 +2088,15 @@ mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite(
cir::StoreOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
mlir::LLVM::AtomicOrdering memorder = getLLVMMemOrder(op.getMemOrder());
- const mlir::Type llvmTy =
- getTypeConverter()->convertType(op.getValue().getType());
+ mlir::Type valueType = op.getValue().getType();
+ if (auto intTy = mlir::dyn_cast<cir::IntType>(valueType);
+ intTy && isSplitStorageBitInt(intTy, dataLayout))
+ return op.emitError()
+ << "NYI: lowering store of a _BitInt with byte-array storage";
+ const mlir::Type llvmTy = getTypeConverter()->convertType(valueType);
std::optional<size_t> opAlign = op.getAlignment();
- unsigned alignment =
- (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));
+ unsigned alignment = (unsigned)opAlign.value_or(
+ getMemoryFallbackAlignment(valueType, llvmTy, dataLayout));
assert(!cir::MissingFeatures::lowerModeOptLevel());
@@ -2505,6 +2632,9 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
// This is the LLVM dialect type.
const mlir::Type llvmType =
convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType);
+ if (!llvmType)
+ return op.emitError()
+ << "NYI: lowering global of a _BitInt with byte-array storage";
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops.
@@ -3288,9 +3418,19 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
mlir::Type ty =
convertTypeForMemory(converter, dataLayout, type.getElementType());
+ // A null element type means an unsupported member (e.g. a _BitInt with
+ // byte-array storage); propagate the conversion failure.
+ if (!ty)
+ return {};
return mlir::LLVM::LLVMArrayType::get(ty, type.getSize());
});
converter.addConversion([&](cir::VectorType type) -> mlir::Type {
+ // Vector-of-_BitInt memory layout is not modeled here (the element would
+ // stay at its literal width); report a conversion failure rather than emit
+ // an unvalidated vector.
+ if (auto intTy = mlir::dyn_cast<cir::IntType>(type.getElementType());
+ intTy && intTy.isBitInt())
+ return {};
const mlir::Type ty = converter.convertType(type.getElementType());
return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()});
});
@@ -3342,8 +3482,15 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
});
converter.addConversion([&](cir::StructType type) -> mlir::Type {
llvm::SmallVector<mlir::Type> llvmMembers;
- for (mlir::Type ty : type.getMembers())
- llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));
+ for (mlir::Type ty : type.getMembers()) {
+ mlir::Type memberTy = convertTypeForMemory(converter, dataLayout, ty);
+ // A null member means an unsupported type (e.g. a _BitInt with byte-array
+ // storage); propagate the conversion failure instead of building an
+ // invalid struct body.
+ if (!memberTy)
+ return {};
+ llvmMembers.push_back(memberTy);
+ }
mlir::LLVM::LLVMStructType llvmStruct;
if (type.getName()) {
@@ -3361,11 +3508,19 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
converter.addConversion([&](cir::UnionType type) -> mlir::Type {
llvm::SmallVector<mlir::Type> llvmMembers;
if (!type.getMembers().empty())
- if (auto storage = type.getUnionStorageType(dataLayout))
- llvmMembers.push_back(
- convertTypeForMemory(converter, dataLayout, storage));
- if (mlir::Type pad = type.getPadding())
- llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, pad));
+ if (auto storage = type.getUnionStorageType(dataLayout)) {
+ mlir::Type storageTy =
+ convertTypeForMemory(converter, dataLayout, storage);
+ if (!storageTy)
+ return {};
+ llvmMembers.push_back(storageTy);
+ }
+ if (mlir::Type pad = type.getPadding()) {
+ mlir::Type padTy = convertTypeForMemory(converter, dataLayout, pad);
+ if (!padTy)
+ return {};
+ llvmMembers.push_back(padTy);
+ }
mlir::LLVM::LLVMStructType llvmStruct;
if (type.getName()) {
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index dfd8886cb8f1c..4b5b4bf9a1173 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -236,9 +236,15 @@ lowerConstArrayAttr(cir::ConstArrayAttr constArr,
if (mlir::isa<mlir::StringAttr>(constArr.getElts()))
return convertStringAttrToDenseElementsAttr(constArr,
converter->convertType(type));
- if (mlir::isa<cir::IntType>(type))
+ if (mlir::isa<cir::IntType>(type)) {
+ // A _BitInt array element is stored in a padded integer in memory; the
+ // dense-attribute path here cannot express that widening, so fall back to
+ // the insertvalue region, which widens each element via emitToMemory.
+ if (mlir::cast<cir::IntType>(type).isBitInt())
+ return std::nullopt;
return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>(
constArr, dims, type, converter->convertType(type));
+ }
if (mlir::isa<cir::BoolType>(type))
return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>(
@@ -297,9 +303,14 @@ lowerConstRecordMemberAttr(mlir::Attribute attr,
if (mlir::isa<cir::UndefAttr>(attr))
return mlir::LLVM::UndefAttr::get(ctx);
- if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr))
+ if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr)) {
+ // A _BitInt member is stored in a padded integer in memory; defer to the
+ // insertvalue region (CIRAttrToValue), which performs the extension.
+ if (mlir::cast<cir::IntType>(intAttr.getType()).isBitInt())
+ return std::nullopt;
return mlir::IntegerAttr::get(converter->convertType(intAttr.getType()),
intAttr.getValue());
+ }
if (auto boolAttr = mlir::dyn_cast<cir::BoolAttr>(attr))
return mlir::IntegerAttr::get(converter->convertType(boolAttr.getType()),
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 835166da8c7c6..9cba7c2b01162 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -534,11 +534,12 @@ void bitint_index_access(_BitInt(7) i) {
// CIR: cir.store{{.*}} %[[VAL]], %[[N_ADDR]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}} @_Z19bitint_index_accessDB7_(i7 {{[^)]*}})
-// LLVM: %[[I_ADDR:.*]] = alloca i7
+// LLVM: %[[I_ADDR:.*]] = alloca i8
// LLVM: %[[ARR_ADDR:.*]] = alloca [10 x i32]
// LLVM: %[[N_ADDR:.*]] = alloca i32
-// LLVM: %[[I:.*]] = load i7, ptr %[[I_ADDR]]
-// LLVM: %[[IDX:.*]] = sext i7 %[[I]] to i64
+// LLVM: %[[I:.*]] = load i8, ptr %[[I_ADDR]]
+// LLVM: %[[I_CAST:.*]] = trunc i8 %[[I]] to i7
+// LLVM: %[[IDX:.*]] = sext i7 %[[I_CAST]] to i64
// LLVM: %[[ELE:.*]] = getelementptr [10 x i32], ptr %[[ARR_ADDR]], i32 0, i64 %[[IDX]]
// LLVM: %[[VAL:.*]] = load i32, ptr %[[ELE]]
// LLVM: store i32 %[[VAL]], ptr %[[...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/206606
More information about the cfe-commits
mailing list