llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

I've worked through this quite a bit, and spent some time working on seeing if 
I could do this during LowerToLLVM, however this causes a ton of complication, 
as this level of change affects basically every member-access invariant that we 
have.  Additionally, we have prior art (bool -&gt; 8 bits, FP80 -&gt; 128 
bits), that I think it makes sense at least to 'put it with the rest'.

The problem is that the 'i' types for bitint(which they are lowered to) don't 
match alignment-wise to the BitInt types.  As a result, unless we do a bunch of 
transformations to change the struct/array/etc types (plus
    the get-member/initialization, etc stuff this entails), we're going
to be reprensenting these types incorrectly. We have prior art for this as 
well, particularly around zero-length bitfields (which we represent
    as a field in the LLVM-IR to prevent the above conflicts).

This patch does this layout at the CIR level, which gives us layout parity to 
LLVM-IR, as well as making sure we represent things correctly in LLVM-IR.

Note: This patch was heavily authored by Claude, though I've done my best to 
review and confirm every line of it.

---

Patch is 39.29 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/219487.diff


12 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+11) 
- (modified) clang/include/clang/CIR/LoweringHelpers.h (+4) 
- (modified) clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp (+17-7) 
- (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+20-1) 
- (modified) 
clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp 
(+19-2) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+1-64) 
- (modified) clang/lib/CIR/Lowering/LoweringHelpers.cpp (+56-2) 
- (modified) clang/test/CIR/CodeGen/attr-noundef.cpp (+2-2) 
- (added) clang/test/CIR/CodeGen/bitint-record-layout.c (+224) 
- (modified) clang/test/CIR/CodeGen/bitint-split-storage-nyi.c (+22) 
- (added) clang/test/CIR/CodeGen/bitint-union-init.c (+15) 
- (modified) clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c (+4-4) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index acbd6ad071d63..26c0f7689d97b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -93,6 +93,17 @@ def CIR_IntType : CIR_Type<"Int", "int", [
     /// Returns a maximum bitwidth of cir::IntType.
     /// Matches llvm::IntegerType::MAX_INT_BITS (1 << 23).
     static unsigned maxBitwidth() { return (1 << 23); }
+
+    /// The bit-width of this integer type when stored via LLVM-IR. This
+    /// is just sizeof(ty)*CHAR_BIT for all but _BitInt, which is represented 
as
+    /// widened for layout.
+    unsigned getStorageTypeWidth(const mlir::DataLayout &dataLayout) const;
+
+    /// Like getStorageTypeWidth, this gets the alignment of the type when
+    /// lowered to LLVM-IR for the purposes of ensuring we get layout correct
+    /// for record types (particularly around _BitInt, which has a different
+    /// alignment in LLVM-IR vs the FE).
+    uint64_t getStorageTypeAlignment(const mlir::DataLayout &dataLayout) const;
   }];
   let genVerifyDecl = 1;
 }
diff --git a/clang/include/clang/CIR/LoweringHelpers.h 
b/clang/include/clang/CIR/LoweringHelpers.h
index f0f65bb317521..fe61db3fc5d25 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -76,4 +76,8 @@ mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs,
                       const llvm::APInt &rhs);
 
 mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs);
+
+mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
+                                mlir::DataLayout const &dataLayout,
+                                mlir::Type type);
 #endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index a103b68331a8d..7451bf6fbd4aa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -152,7 +152,17 @@ struct CIRRecordLowering final {
   CharUnits getSizeInBits(mlir::Type ty) {
     return CharUnits::fromQuantity(dataLayout.layout.getTypeSizeInBits(ty));
   }
-  CharUnits getAlignment(mlir::Type Ty) {
+
+  CharUnits getMemberAlignment(mlir::Type Ty) {
+    // Recurse on Arrays, they have the member alignment of their element type.
+    if (auto arrayTy = mlir::dyn_cast<cir::ArrayType>(Ty))
+      return getMemberAlignment(arrayTy.getElementType());
+    // Int types (_BitInt in particular) share the alignment of their storage
+    // type.
+    if (auto intTy = mlir::dyn_cast<cir::IntType>(Ty))
+      return CharUnits::fromQuantity(
+          intTy.getStorageTypeAlignment(dataLayout.layout));
+
     return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty));
   }
 
@@ -744,11 +754,11 @@ void CIRRecordLowering::determinePacked(bool nvBaseType) {
       continue;
     // If any member falls at an offset that it not a multiple of its 
alignment,
     // then the entire record must be packed.
-    if (!member.offset.isMultipleOf(getAlignment(member.data)))
+    if (!member.offset.isMultipleOf(getMemberAlignment(member.data)))
       packed = true;
     if (member.offset < nvSize)
-      nvAlignment = std::max(nvAlignment, getAlignment(member.data));
-    alignment = std::max(alignment, getAlignment(member.data));
+      nvAlignment = std::max(nvAlignment, getMemberAlignment(member.data));
+    alignment = std::max(alignment, getMemberAlignment(member.data));
   }
   // If the size of the record (the capstone's offset) is not a multiple of the
   // record's alignment, it must be packed.
@@ -786,8 +796,8 @@ void CIRRecordLowering::insertPadding() {
     CharUnits offset = member.offset;
     assert(offset >= size);
     // Insert padding if we need to.
-    if (offset !=
-        size.alignTo(packed ? CharUnits::One() : getAlignment(member.data)))
+    if (offset != size.alignTo(packed ? CharUnits::One()
+                                      : getMemberAlignment(member.data)))
       padding.push_back(std::make_pair(size, offset - size));
     size = offset + getSize(member.data);
   }
@@ -1055,7 +1065,7 @@ void CIRRecordLowering::lowerUnion(bool 
nonVirtualBaseType) {
     // Else we just add padding normally.
     appendPaddingBytes(layoutSize - getSize(storageType));
   }
-  packed = !layoutSize.isMultipleOf(getAlignment(storageType));
+  packed = !layoutSize.isMultipleOf(getMemberAlignment(storageType));
 }
 
 bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 1bed5de96474a..897063171e76a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -846,6 +846,8 @@ UnionType::getTypeSizeInBits(const mlir::DataLayout 
&dataLayout,
 uint64_t
 UnionType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
                            ::mlir::DataLayoutEntryListRef params) const {
+  if (getPacked())
+    return 1;
   mlir::Type storage = getUnionStorageType(dataLayout);
   if (!storage)
     return 1;
@@ -1029,7 +1031,24 @@ void IntType::print(mlir::AsmPrinter &printer) const {
 llvm::TypeSize
 IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
                            mlir::DataLayoutEntryListRef params) const {
-  return llvm::TypeSize::getFixed(getWidth());
+  return llvm::TypeSize::getFixed(getStorageTypeWidth(dataLayout));
+}
+
+unsigned
+IntType::getStorageTypeWidth(const mlir::DataLayout &dataLayout) const {
+  if (!isBitInt())
+    return getWidth();
+  uint64_t alignBits = getABIAlignment(dataLayout, {}) * 8;
+  return static_cast<unsigned>(llvm::alignTo(getWidth(), alignBits));
+}
+
+uint64_t
+IntType::getStorageTypeAlignment(const mlir::DataLayout &dataLayout) const {
+  if (!isBitInt())
+    return getABIAlignment(dataLayout, {});
+  auto storageTy =
+      mlir::IntegerType::get(getContext(), getStorageTypeWidth(dataLayout));
+  return dataLayout.getTypeABIAlignment(storageTy);
 }
 
 uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
diff --git 
a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index 8d4c3b19c213d..8cf332bbbefa3 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -274,6 +274,22 @@ mlir::ArrayAttr updateResAttrs(mlir::MLIRContext *ctx,
   return mlir::ArrayAttr::get(ctx, {mlir::DictionaryAttr::get(ctx, attrs)});
 }
 
+/// The number of bytes a coercion memory slot needs to hold a value of type
+/// \p ty without truncating it. For most types this is the ordinary storage
+/// size. For a _BitInt it is deliberately the value's own literal byte
+/// footprint (ceil(width/8)) rather than the wider, ABI-alignment-padded
+/// footprint a _BitInt gets as a record member (see
+/// cir::IntType::getStorageTypeWidth): this coercion is about how many bytes
+/// the *value* needs to round-trip, not how a record would lay it out, and
+/// those are genuinely different questions for a _BitInt (e.g. _BitInt(33)
+/// only needs 5 bytes here, even though it occupies 8 padded bytes as a
+/// record member).
+static uint64_t coercionByteSize(mlir::Type ty, const mlir::DataLayout &dl) {
+  if (auto intTy = mlir::dyn_cast<cir::IntType>(ty))
+    return llvm::divideCeil(intTy.getWidth(), 8);
+  return dl.getTypeSize(ty);
+}
+
 /// Coerce \p src into a temporary memory slot typed for \p dstTy at the
 /// current builder insertion point, and return the destination-typed pointer
 /// to that slot without loading the value back out.  This is the shared
@@ -310,8 +326,9 @@ emitCoercionToMemory(mlir::OpBuilder &builder, 
mlir::Location loc,
   uint64_t srcAlign = dl.getTypeABIAlignment(srcTy);
   uint64_t dstAlign = dl.getTypeABIAlignment(dstTy);
   uint64_t allocaAlign = std::max(srcAlign, dstAlign);
-  mlir::Type slotTy =
-      dl.getTypeSize(srcTy) >= dl.getTypeSize(dstTy) ? srcTy : dstTy;
+  mlir::Type slotTy = coercionByteSize(srcTy, dl) >= coercionByteSize(dstTy, 
dl)
+                          ? srcTy
+                          : dstTy;
 
   auto slotPtrTy = cir::PointerType::get(slotTy);
   auto srcPtrTy = cir::PointerType::get(srcTy);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9ee597b81df24..66de2388c2345 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -76,69 +76,6 @@ 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.
-static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
-                                       mlir::DataLayout const &dataLayout,
-                                       mlir::Type type) {
-  // TODO(cir): Handle other types similarly to clang's codegen
-  // convertTypeForMemory
-  if (isa<cir::BoolType>(type)) {
-    return mlir::IntegerType::get(type.getContext(),
-                                  dataLayout.getTypeSizeInBits(type));
-  }
-
-  if (auto vecTy = mlir::dyn_cast<cir::VectorType>(type)) {
-    if (mlir::isa<cir::BoolType>(vecTy.getElementType())) {
-      assert(!cir::MissingFeatures::hlsl());
-      // Pad to at least one byte.
-      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
-  // 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);
-}
-
 /// 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).
@@ -179,7 +116,7 @@ static mlir::Value
 castBitIntMemoryStorage(mlir::ConversionPatternRewriter &rewriter,
                         const mlir::DataLayout &dataLayout, cir::IntType intTy,
                         mlir::Value value, bool toMemory) {
-  unsigned storageBits = getBitIntMemoryStorageBits(intTy, dataLayout);
+  unsigned storageBits = intTy.getStorageTypeWidth(dataLayout);
   if (storageBits == intTy.getWidth())
     return value;
   unsigned dstBits = toMemory ? storageBits : intTy.getWidth();
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 9ffb62a9cd026..1dad8beaa4bce 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -16,6 +16,60 @@
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/SymbolTable.h"
 #include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "clang/CIR/MissingFeatures.h"
+
+namespace {
+/// 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.
+bool isSplitStorageBitInt(cir::IntType ty, const mlir::DataLayout &dataLayout) 
{
+  if (!ty.isBitInt())
+    return false;
+  unsigned storageBits = ty.getStorageTypeWidth(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;
+}
+} // namespace
+
+mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
+                                mlir::DataLayout const &dataLayout,
+                                mlir::Type type) {
+  // TODO(cir): Handle other types similarly to clang's codegen
+  // convertTypeForMemory
+  if (mlir::isa<cir::BoolType>(type)) {
+    return mlir::IntegerType::get(type.getContext(),
+                                  dataLayout.getTypeSizeInBits(type));
+  }
+
+  if (auto vecTy = mlir::dyn_cast<cir::VectorType>(type)) {
+    if (mlir::isa<cir::BoolType>(vecTy.getElementType())) {
+      assert(!cir::MissingFeatures::hlsl());
+      // Pad to at least one byte.
+      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 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(),
+                                  intTy.getStorageTypeWidth(dataLayout));
+  }
+
+  return converter.convertType(type);
+}
 
 static unsigned getIntOrBoolBitWidth(mlir::Type ty) {
   if (auto intTy = mlir::dyn_cast<cir::IntType>(ty))
@@ -539,8 +593,8 @@ static mlir::Type adjustGlobalUnionTypeForInit(
   // Unions can only initialize one field, so this has to be sizeof-one.
   assert(constRecord.getMembers().size() == 1);
   mlir::Attribute member = constRecord.getMembers()[0];
-  mlir::Type memberTy =
-      converter.convertType(mlir::cast<mlir::TypedAttr>(member).getType());
+  mlir::Type memberTy = convertTypeForMemory(
+      converter, dataLayout, mlir::cast<mlir::TypedAttr>(member).getType());
 
   // The active member may itself need adjusting (e.g. it is a nested union, or
   // a struct containing one), so recurse before using its type below.
diff --git a/clang/test/CIR/CodeGen/attr-noundef.cpp 
b/clang/test/CIR/CodeGen/attr-noundef.cpp
index 856448be00247..f73d984d4e536 100644
--- a/clang/test/CIR/CodeGen/attr-noundef.cpp
+++ b/clang/test/CIR/CodeGen/attr-noundef.cpp
@@ -228,8 +228,8 @@ void pass_large_BitInt(_BitInt(127) e) {
 // CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic17pass_large_BitIntEDB127_
 
 // LLVM: define {{.*}} i3 @_ZN12check_exotic10ret_BitIntEv(
-// LLVM: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 %
-// LLVM: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i127 %
+// LLVM: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef %
+// LLVM: define {{.*}} void @_ZN12check_exotic17pass_large_BitIntEDB127_(i127 
noundef %
 
 // OGCG: define {{.*}} noundef signext i3 @_ZN12check_exotic10ret_BitIntEv(
 // OGCG: define {{.*}} void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef 
signext %
diff --git a/clang/test/CIR/CodeGen/bitint-record-layout.c 
b/clang/test/CIR/CodeGen/bitint-record-layout.c
new file mode 100644
index 0000000000000..3a4bf8cfaf105
--- /dev/null
+++ b/clang/test/CIR/CodeGen/bitint-record-layout.c
@@ -0,0 +1,224 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM,LLVMCIR --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll 
+// RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s
+
+union JustBIUnion {
+  _BitInt(65) bi;
+};
+// CIR-DAG: !rec_JustBIUnion = !cir.union<"JustBIUnion" {data !cir.int<s, 65, 
bitint>}>
+// LLVM-DAG: %union.JustBIUnion = type { i128 }
+
+struct SmallerUnionMem { long long a; int b; };
+// CIR-DAG: !rec_SmallerUnionMem = !cir.struct<"SmallerUnionMem" {data !s64i, 
data !s32i}>
+// LLVM-DAG: %struct.SmallerUnionMem = type { i64, i32 }
+
+union BIUnion {
+  _BitInt(65) bi;
+  struct SmallerUnionMem m;
+};
+// CIR-DAG: !rec_BIUnion = !cir.union<"BIUnion" {data !cir.int<s, 65, bitint>, 
data !rec_SmallerUnionMem}>
+// LLVM-DAG: %union.BIUnion = type { i128 }
+
+union BIUnionArr {
+  _BitInt(65) bi;
+  char arr[20];
+};
+// CIR-DAG: !rec_BIUnionArr = !cir.union<"BIUnionArr" packed {data !cir.int<s, 
65, bitint>, data !cir.array<!s8i x 20>}, padding = {!cir.array<!u8i x 8>}>
+// LLVM-DAG: %union.BIUnionArr = type <{ i128, [8 x i8] }>
+
+struct First65 {
+  _BitInt(65) bi;
+  int i;
+};
+// CIR-DAG: !rec_First65 = !cir.struct<"First65" packed {data !cir.int<s, 65, 
bitint>, data !s32i, pad !cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.First65 = type <{ i128, i32, [4 x i8] }>
+
+struct Middle65 {
+  char c;
+  _BitInt(65) bi;
+  int i;
+};
+// CIR-DAG: !rec_Middle65 = !cir.struct<"Middle65" packed {data !s8i, pad 
!cir.array<!u8i x 7>, data !cir.int<s, 65, bitint>, data !s32i, pad 
!cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.Middle65 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }>
+
+struct Last65 {
+  int i;
+  _BitInt(65) bi;
+};
+// CIR-DAG: !rec_Last65 = !cir.struct<"Last65" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !cir.int<s, 65, bitint>}>
+// LLVM-DAG: %struct.Last65 = type <{ i32, [4 x i8], i128 }>
+
+struct First127 {
+  _BitInt(127) bi;
+  int i;
+};
+// CIR-DAG: !rec_First127 = !cir.struct<"First127" packed {data !cir.int<s, 
127, bitint>, data !s32i, pad !cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.First127 = type <{ i128, i32, [4 x i8] }>
+
+struct Middle127 {
+  char c;
+  _BitInt(127) bi;
+  int i;
+};
+// CIR-DAG: !rec_Middle127 = !cir.struct<"Middle127" packed {data !s8i, pad 
!cir.array<!u8i x 7>, data !cir.int<s, 127, bitint>, data !s32i, pad 
!cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.Middle127 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }>
+
+struct Last127 {
+  int i;
+  _BitInt(127) bi;
+};
+// CIR-DAG: !rec_Last127 = !cir.struct<"Last127" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !cir.int<s, 127, bitint>}>
+// LLVM-DAG: %struct.Last127 = type <{ i32, [4 x i8], i128 }>
+
+struct First128 {
+  _BitInt(128) bi;
+  int i;
+};
+// CIR-DAG: !rec_First128 = !cir.struct<"First128" packed {data !s128i_bitint, 
data !s32i, pad !cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.First128 = type <{ i128, i32, [4 x i8] }>
+
+struct Middle128 {
+  char c;
+  _BitInt(128) bi;
+  int i;
+};
+// CIR-DAG: !rec...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/219487
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to