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 -> 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.
---
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