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&lt;N, bitint&gt;` 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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to