https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/219487

>From d4a522af9b1910055fc051265a634051e5b5bb5d Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 26 Aug 2026 13:10:05 -0700
Subject: [PATCH] [CIR] Layout _BitInt types in record/array in CIR as it is in
 LLVM-IR

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 -> 8 bits, FP80 -> 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.
---
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  |  11 +
 clang/include/clang/CIR/LoweringHelpers.h     |   4 +
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp |  24 +-
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         |  21 +-
 .../TargetLowering/CIRABIRewriteContext.cpp   |  21 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  65 +----
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    |  58 ++++-
 clang/test/CIR/CodeGen/attr-noundef.cpp       |   4 +-
 clang/test/CIR/CodeGen/bitint-record-layout.c | 224 ++++++++++++++++++
 .../CIR/CodeGen/bitint-split-storage-nyi.c    |  22 ++
 .../call-conv-lowering-x86_64-variadic.c      |   8 +-
 11 files changed, 380 insertions(+), 82 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/bitint-record-layout.c

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_Middle128 = !cir.struct<"Middle128" packed {data !s8i, pad 
!cir.array<!u8i x 7>, data !s128i_bitint, data !s32i, pad !cir.array<!u8i x 4>}>
+// LLVM-DAG: %struct.Middle128 = type <{ i8, [7 x i8], i128, i32, [4 x i8] }>
+
+struct Last128 {
+  int i;
+  _BitInt(128) bi;
+};
+// CIR-DAG: !rec_Last128 = !cir.struct<"Last128" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !s128i_bitint}>
+// LLVM-DAG: %struct.Last128 = type <{ i32, [4 x i8], i128 }>
+
+struct ArrMem {
+  int i;
+  _BitInt(128) bi[2];
+};
+// CIR-DAG: !rec_ArrMem = !cir.struct<"ArrMem" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !cir.array<!s128i_bitint x 2>}>
+// LLVM-DAG: %struct.ArrMem = type <{ i32, [4 x i8], [2 x i128] }>
+
+struct Inner {
+  int i;
+  _BitInt(128) bi;
+};
+// CIR-DAG: !rec_Inner = !cir.struct<"Inner" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !s128i_bitint}>
+// LLVM-DAG: %struct.Inner = type <{ i32, [4 x i8], i128 }>
+struct Outer {
+  char c;
+  struct Inner inner;
+};
+// CIR-DAG: !rec_Outer = !cir.struct<"Outer" {data !s8i, pad !cir.array<!u8i x 
7>, data !rec_Inner}>
+// LLVM-DAG: %struct.Outer = type { i8, [7 x i8], %struct.Inner }
+
+struct Inner2 {
+  int i;
+  _BitInt(128) bi;
+};
+// CIR-DAG: !rec_Inner2 = !cir.struct<"Inner2" packed {data !s32i, pad 
!cir.array<!u8i x 4>, data !s128i_bitint}>
+// LLVM-DAG: %struct.Inner2 = type <{ i32, [4 x i8], i128 }>
+
+struct Outer2 {
+  char c;
+  struct Inner2 inner;
+  short s;
+};
+// CIR-DAG: !rec_Outer2 = !cir.struct<"Outer2" {data !s8i, pad !cir.array<!u8i 
x 7>, data !rec_Inner2, data !s16i, pad !cir.array<!u8i x 6>}>
+// LLVM-DAG: %struct.Outer2 = type { i8, [7 x i8], %struct.Inner2, i16, [6 x 
i8] }
+
+
+union JustBIUnion jbiu = { .bi = 54321 };
+// CIR-DAG: cir.global external @jbiu = #cir.const_record<{#cir.int<54321> : 
!cir.int<s, 65, bitint>}> : !rec_JustBIUnion {alignment = 8 : i64}
+// LLVM-DAG: @jbiu = global %union.JustBIUnion { i128 54321 }, align 8
+union BIUnion biunion = { .bi = 12345 };
+// CIR-DAG: cir.global external @biunion = #cir.const_record<{#cir.int<12345> 
: !cir.int<s, 65, bitint>}> : !rec_BIUnion {alignment = 8 : i64}
+// LLVM-DAG: @biunion = global %union.BIUnion { i128 12345 }, align 8
+
+union BIUnionArr biuarr = { .arr = { 'a', 'b', 'c' } };
+// CIR-DAG: cir.global external @biuarr = 
#cir.const_record<{#cir.const_array<[#cir.int<97> : !s8i, #cir.int<98> : !s8i, 
#cir.int<99> : !s8i], trailing_zeros> : !cir.array<!s8i x 20>}> : 
!rec_BIUnionArr {alignment = 8 : i64}
+// Classic-codegen represents the constant by splitting the init part of
+// the string and the zeros separately, plus not as a string.  Else this is 
effectively the same.
+// LLVMCIR-DAG: @biuarr = global <{ [20 x i8], [4 x i8] }> <{ [20 x i8] 
c"abc\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", [4 x i8] 
zeroinitializer }>, align 8
+// OGCG-DAG:    @biuarr = global { <{ i8, i8, i8, [17 x i8] }>, [4 x i8] } { 
<{ i8, i8, i8, [17 x i8] }> <{ i8 97, i8 98, i8 99, [17 x i8] zeroinitializer 
}>, [4 x i8] zeroinitializer }, align 8
+
+struct First65 f65[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @f65 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !cir.int<s, 65, bitint>, 
#cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First65, 
#cir.const_record<{#cir.int<3> : !cir.int<s, 65, bitint>, #cir.int<444> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First65]> : 
!cir.array<!rec_First65 x 2> {alignment = 16 : i64}
+// LLVM-DAG: @f65 = global [2 x %struct.First65] [%struct.First65 <{ i128 1, 
i32 222, [4 x i8] zeroinitializer }>, %struct.First65 <{ i128 3, i32 444, [4 x 
i8] zeroinitializer }>], align 16
+struct Middle65 m65[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @m65 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : 
!cir.array<!u8i x 7>, #cir.int<222> : !cir.int<s, 65, bitint>, #cir.int<0> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle65, 
#cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, 
#cir.int<444> : !cir.int<s, 65, bitint>, #cir.int<0> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>}> : !rec_Middle65]> : !cir.array<!rec_Middle65 x 2> 
{alignment = 16 : i64}
+// LLVM-DAG: @m65 = global [2 x %struct.Middle65] [%struct.Middle65 <{ i8 1, 
[7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, 
%struct.Middle65 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] 
zeroinitializer }>], align 16
+struct Last65 l65[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @l65 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<222> : !cir.int<s, 65, bitint>}> : !rec_Last65, 
#cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, 
#cir.int<444> : !cir.int<s, 65, bitint>}> : !rec_Last65]> : 
!cir.array<!rec_Last65 x 2> {alignment = 16 : i64}
+// LLVM-DAG: @l65 = global [2 x %struct.Last65] [%struct.Last65 <{ i32 1, [4 x 
i8] zeroinitializer, i128 222 }>, %struct.Last65 <{ i32 3, [4 x i8] 
zeroinitializer, i128 444 }>], align 16
+
+struct First127 f127[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @f127 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !cir.int<s, 127, bitint>, 
#cir.int<222> : !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First127, 
#cir.const_record<{#cir.int<3> : !cir.int<s, 127, bitint>, #cir.int<444> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First127]> : 
!cir.array<!rec_First127 x 2> {alignment = 16 : i64}
+// LLVM-DAG: @f127 = global [2 x %struct.First127] [%struct.First127 <{ i128 
1, i32 222, [4 x i8] zeroinitializer }>, %struct.First127 <{ i128 3, i32 444, 
[4 x i8] zeroinitializer }>], align 16
+struct Middle127 m127[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @m127 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : 
!cir.array<!u8i x 7>, #cir.int<222> : !cir.int<s, 127, bitint>, #cir.int<0> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle127, 
#cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, 
#cir.int<444> : !cir.int<s, 127, bitint>, #cir.int<0> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>}> : !rec_Middle127]> : !cir.array<!rec_Middle127 x 2> 
{alignment = 16 : i64}
+// LLVM-DAG: @m127 = global [2 x %struct.Middle127] [%struct.Middle127 <{ i8 
1, [7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, 
%struct.Middle127 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] 
zeroinitializer }>], align 16
+struct Last127 l127[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @l127 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<222> : !cir.int<s, 127, bitint>}> : 
!rec_Last127, #cir.const_record<{#cir.int<3> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<444> : !cir.int<s, 127, bitint>}> : 
!rec_Last127]> : !cir.array<!rec_Last127 x 2> {alignment = 16 : i64}
+// LLVM-DAG: @l127 = global [2 x %struct.Last127] [%struct.Last127 <{ i32 1, 
[4 x i8] zeroinitializer, i128 222 }>, %struct.Last127 <{ i32 3, [4 x i8] 
zeroinitializer, i128 444 }>], align 16
+
+struct First128 f128[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @f128 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s128i_bitint, #cir.int<222> 
: !s32i, #cir.zero : !cir.array<!u8i x 4>}> : !rec_First128, 
#cir.const_record<{#cir.int<3> : !s128i_bitint, #cir.int<444> : !s32i, 
#cir.zero : !cir.array<!u8i x 4>}> : !rec_First128]> : !cir.array<!rec_First128 
x 2> {alignment = 16 : i64}
+// LLVM-DAG: @f128 = global [2 x %struct.First128] [%struct.First128 <{ i128 
1, i32 222, [4 x i8] zeroinitializer }>, %struct.First128 <{ i128 3, i32 444, 
[4 x i8] zeroinitializer }>], align 16
+struct Middle128 m128[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @m128 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : 
!cir.array<!u8i x 7>, #cir.int<222> : !s128i_bitint, #cir.int<0> : !s32i, 
#cir.zero : !cir.array<!u8i x 4>}> : !rec_Middle128, 
#cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, 
#cir.int<444> : !s128i_bitint, #cir.int<0> : !s32i, #cir.zero : !cir.array<!u8i 
x 4>}> : !rec_Middle128]> : !cir.array<!rec_Middle128 x 2> {alignment = 16 : 
i64}
+// LLVM-DAG: @m128 = global [2 x %struct.Middle128] [%struct.Middle128 <{ i8 
1, [7 x i8] zeroinitializer, i128 222, i32 0, [4 x i8] zeroinitializer }>, 
%struct.Middle128 <{ i8 3, [7 x i8] zeroinitializer, i128 444, i32 0, [4 x i8] 
zeroinitializer }>], align 16
+struct Last128 l128[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @l128 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<222> : !s128i_bitint}> : !rec_Last128, 
#cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, 
#cir.int<444> : !s128i_bitint}> : !rec_Last128]> : !cir.array<!rec_Last128 x 2> 
{alignment = 16 : i64}
+// LLVM-DAG: @l128 = global [2 x %struct.Last128] [%struct.Last128 <{ i32 1, 
[4 x i8] zeroinitializer, i128 222 }>, %struct.Last128 <{ i32 3, [4 x i8] 
zeroinitializer, i128 444 }>], align 16
+
+struct ArrMem arrMem[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @arrMem = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.const_array<[#cir.int<222> : !s128i_bitint], 
trailing_zeros> : !cir.array<!s128i_bitint x 2>}> : !rec_ArrMem, 
#cir.const_record<{#cir.int<3> : !s32i, #cir.zero : !cir.array<!u8i x 4>, 
#cir.const_array<[#cir.int<444> : !s128i_bitint], trailing_zeros> : 
!cir.array<!s128i_bitint x 2>}> : !rec_ArrMem]> : !cir.array<!rec_ArrMem x 2> 
{alignment = 16 : i64}
+// LLVM-DAG: @arrMem = global [2 x %struct.ArrMem] [%struct.ArrMem <{ i32 1, 
[4 x i8] zeroinitializer, [2 x i128] [i128 222, i128 0] }>, %struct.ArrMem <{ 
i32 3, [4 x i8] zeroinitializer, [2 x i128] [i128 444, i128 0] }>], align 16
+
+struct Outer nestedArr[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @nestedArr = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : 
!cir.array<!u8i x 7>, #cir.const_record<{#cir.int<222> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner}> : 
!rec_Outer, #cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i 
x 7>, #cir.const_record<{#cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 
4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner}> : !rec_Outer]> : 
!cir.array<!rec_Outer x 2> {alignment = 16 : i64}
+// LLVM-DAG: @nestedArr = global [2 x %struct.Outer] [%struct.Outer { i8 1, [7 
x i8] zeroinitializer, %struct.Inner <{ i32 222, [4 x i8] zeroinitializer, i128 
0 }> }, %struct.Outer { i8 3, [7 x i8] zeroinitializer, %struct.Inner <{ i32 
444, [4 x i8] zeroinitializer, i128 0 }> }], align 16
+struct Outer2 nestedArr2[2] = {{1, 222}, {3, 444}};
+// CIR-DAG: cir.global external @nestedArr2 = 
#cir.const_array<[#cir.const_record<{#cir.int<1> : !s8i, #cir.zero : 
!cir.array<!u8i x 7>, #cir.const_record<{#cir.int<222> : !s32i, #cir.zero : 
!cir.array<!u8i x 4>, #cir.int<0> : !s128i_bitint}> : !rec_Inner2, #cir.int<0> 
: !s16i, #cir.zero : !cir.array<!u8i x 6>}> : !rec_Outer2, 
#cir.const_record<{#cir.int<3> : !s8i, #cir.zero : !cir.array<!u8i x 7>, 
#cir.const_record<{#cir.int<444> : !s32i, #cir.zero : !cir.array<!u8i x 4>, 
#cir.int<0> : !s128i_bitint}> : !rec_Inner2, #cir.int<0> : !s16i, #cir.zero : 
!cir.array<!u8i x 6>}> : !rec_Outer2]> : !cir.array<!rec_Outer2 x 2> {alignment 
= 16 : i64}
+// LLVM-DAG: @nestedArr2 = global [2 x %struct.Outer2] [%struct.Outer2 { i8 1, 
[7 x i8] zeroinitializer, %struct.Inner2 <{ i32 222, [4 x i8] zeroinitializer, 
i128 0 }>, i16 0, [6 x i8] zeroinitializer }, %struct.Outer2 { i8 3, [7 x i8] 
zeroinitializer, %struct.Inner2 <{ i32 444, [4 x i8] zeroinitializer, i128 0 
}>, i16 0, [6 x i8] zeroinitializer }], align 16
+
+_BitInt(128) get_bi(void) { return l128[1].bi; }
+// CIR-LABEL: cir.func no_inline dso_local @get_bi() -> !s128i_bitint
+// CIR-NEXT: %[[RET_ALLOC:.*]] = cir.alloca "__retval" align(8) : 
!cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @l128 : 
!cir.ptr<!cir.array<!rec_Last128 x 2>>
+// CIR-NEXT: %[[ARR_GEP:.*]] = cir.get_element %[[GET_GLOB]][%[[ONE]] : !s64i] 
: !cir.ptr<!cir.array<!rec_Last128 x 2>> -> !cir.ptr<!rec_Last128>
+// CIR-NEXT: %[[GET_BI:.*]] = cir.get_member %[[ARR_GEP]][2] {name = "bi"} : 
!cir.ptr<!rec_Last128> -> !cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[LOAD_BI:.*]] = cir.load align(8) %[[GET_BI]] : 
!cir.ptr<!s128i_bitint>, !s128i_bitint
+// CIR-NEXT: cir.store %[[LOAD_BI]], %[[RET_ALLOC]] : !s128i_bitint, 
!cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOC]] : 
!cir.ptr<!s128i_bitint>, !s128i_bitint
+// CIR-NEXT: cir.return %[[RET_LOAD]] : !s128i_bitint
+// LLVM-LABEL: define dso_local i128 @get_bi()
+// LLVM: load i128, ptr getelementptr inbounds nuw (i8, ptr @l128, i64 32), 
align 8
+
+_BitInt(128) get_bi2(void) { return arrMem[1].bi[1]; }
+// CIR-LABEL: cir.func no_inline dso_local @get_bi2() -> !s128i_bitint 
attributes {"cir.target-features" = "+cx8,+mmx,+sse,+sse2,+x87", nothrow} {
+// CIR-NEXT: %[[RET_ALLOC:.*]] = cir.alloca "__retval" align(8) : 
!cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR-NEXT: %[[ONE_2:.*]] = cir.const #cir.int<1> : !s64i
+// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @arrMem : 
!cir.ptr<!cir.array<!rec_ArrMem x 2>>
+// CIR-NEXT: %[[ARR_GEP:.*]] = cir.get_element %[[GET_GLOB]][%[[ONE_2]] : 
!s64i] : !cir.ptr<!cir.array<!rec_ArrMem x 2>> -> !cir.ptr<!rec_ArrMem>
+// CIR-NEXT: %[[GET_BI_ARR:.*]] = cir.get_member %[[ARR_GEP]][2] {name = "bi"} 
: !cir.ptr<!rec_ArrMem> -> !cir.ptr<!cir.array<!s128i_bitint x 2>>
+// CIR-NEXT: %[[GET_BI_ELT:.*]] = cir.get_element %[[GET_BI_ARR]][%[[ONE]] : 
!s64i] : !cir.ptr<!cir.array<!s128i_bitint x 2>> -> !cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[LOAD_BI:.*]] = cir.load align(8) %[[GET_BI_ELT]] : 
!cir.ptr<!s128i_bitint>, !s128i_bitint
+// CIR-NEXT: cir.store %[[LOAD_BI]], %[[RET_ALLOC]] : !s128i_bitint, 
!cir.ptr<!s128i_bitint>
+// CIR-NEXT: %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOC]] : 
!cir.ptr<!s128i_bitint>, !s128i_bitint
+// CIR-NEXT: cir.return %[[RET_LOAD]] : !s128i_bitint
+// LLVM-LABEL: define dso_local i128 @get_bi2()
+// LLVM: load i128, ptr getelementptr inbounds nuw (i8, ptr @arrMem, i64 64), 
align 8
+
+
+void force_emit() {
+  union BIUnionArr b;
+  struct SmallerUnionMem su;
+}
+
diff --git a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c 
b/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
index f536901476c62..a228506d9ad41 100644
--- a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
+++ b/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
@@ -4,6 +4,8 @@
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir 
-fno-clangir-call-conv-lowering -emit-llvm -DALLOCA %s -o - 2>&1 | FileCheck %s 
--check-prefix=ALLOCA
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir 
-fno-clangir-call-conv-lowering -emit-llvm -DSTORE %s -o - 2>&1 | FileCheck %s 
--check-prefix=STORE
 // RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir 
-fno-clangir-call-conv-lowering -emit-llvm -DLOAD %s -o - 2>&1 | FileCheck %s 
--check-prefix=LOAD
+// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir 
-fno-clangir-call-conv-lowering -emit-llvm -DSTRUCT %s -o - 2>&1 | FileCheck %s 
--check-prefix=STRUCT
+// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir 
-fno-clangir-call-conv-lowering -emit-llvm -DARRAY %s -o - 2>&1 | FileCheck %s 
--check-prefix=ARRAY
 
 #ifdef GLOBAL
 signed _BitInt(129) g129 = 1;
@@ -27,3 +29,23 @@ void store_lit(signed _BitInt(129) *p) { *p = (signed 
_BitInt(129))1; }
 int load_cmp(signed _BitInt(129) *p) { return *p != 0; }
 // LOAD: NYI: lowering load of a type with no memory representation
 #endif
+
+#ifdef STRUCT
+// FIXME: Make sure we test that the layout of this and the array struct are
+// 'correct' when this lowering is completed.
+struct HasWide129 {
+  int i;
+  signed _BitInt(129) bi;
+};
+struct HasWide129 g_struct;
+// STRUCT: NYI: lowering global of a type with no memory representation
+#endif
+
+#ifdef ARRAY
+struct HasWide129Array {
+  int i;
+  signed _BitInt(129) bi[2];
+};
+struct HasWide129Array g_array;
+// ARRAY: NYI: lowering global of a type with no memory representation
+#endif
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c 
b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
index e8785a0b283f1..6c00e8bfa8634 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
@@ -201,14 +201,14 @@ int call_wide_char(Pair2 p, WideChar w) { return vf(p, 
w); }
 // declared parameter.
 int ell_bitint17(Pair2 p, _BitInt(17) b) { return vf(p, b); }
 
-// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: 
!cir.int<s, 17, bitint> {llvm.signext} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: 
!cir.int<s, 17, bitint> {llvm.noundef, llvm.signext} loc({{.+}})) -> !s32i
 // CIR:         cir.store %arg1, %[[BSLOT:[0-9]+]] : !cir.int<s, 17, bitint>, 
!cir.ptr<!cir.int<s, 17, bitint>>
 // CIR:         %[[BV:[0-9]+]] = cir.load align(4) %[[BSLOT]] : 
!cir.ptr<!cir.int<s, 17, bitint>>, !cir.int<s, 17, bitint>
 // CIR:         %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
-// CIR:         cir.call @vf(%[[PV]], %[[BV]]) : (!u64i, !cir.int<s, 17, 
bitint> {llvm.signext}) -> !s32i
+// CIR:         cir.call @vf(%[[PV]], %[[BV]]) : (!u64i, !cir.int<s, 17, 
bitint> {llvm.noundef, llvm.signext}) -> !s32i
 
 // LLVM-CIR-LABEL: define dso_local i32 @ell_bitint17(
-// LLVM-CIR-SAME:    i64 %[[P:[0-9a-zA-Z._]+]], i17 signext 
%[[B:[0-9a-zA-Z._]+]])
+// LLVM-CIR-SAME:    i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef signext 
%[[B:[0-9a-zA-Z._]+]])
 // LLVM-OGCG-LABEL: define dso_local i32 @ell_bitint17(
 // LLVM-OGCG-SAME:    i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef signext 
%[[B:[0-9a-zA-Z._]+]])
 // LLVM:         %[[EXT:[0-9a-zA-Z._]+]] = sext i17 %[[B]] to i32
@@ -216,7 +216,7 @@ int ell_bitint17(Pair2 p, _BitInt(17) b) { return vf(p, b); 
}
 // LLVM:         %[[RE:[0-9a-zA-Z._]+]] = load i32, ptr %[[BSLOT]], align 4
 // LLVM:         %[[TR:[0-9a-zA-Z._]+]] = trunc i32 %[[RE]] to i17
 // LLVM:         %[[PV:[0-9a-zA-Z._]+]] = load i64, ptr %{{[0-9a-zA-Z._]+}}, 
align
-// LLVM-CIR:     call i32 (i64, ...) @vf(i64 %[[PV]], i17 signext %[[TR]])
+// LLVM-CIR:     call i32 (i64, ...) @vf(i64 %[[PV]], i17 noundef signext 
%[[TR]])
 // LLVM-OGCG:    call i32 (i64, ...) @vf(i64 %[[PV]], i17 noundef signext 
%[[TR]])
 
 // A width between 33 and 63 widens to one register.

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

Reply via email to