https://github.com/xiongzile updated https://github.com/llvm/llvm-project/pull/225494
>From aa4b747ea45d05e37ec6f8d30b3f0dd1821c7d39 Mon Sep 17 00:00:00 2001 From: Elio <[email protected]> Date: Wed, 23 Sep 2026 03:10:13 +0800 Subject: [PATCH 1/6] [Clang][CodeGen] Fix oversized bit-field placement on big-endian CodeGen treated the full declared width of an oversized bit-field as value bits. On big-endian targets that stored the value at the low end of the storage unit, so `unsigned char value : 16` initialized to 0xAB landed in memory as 00 AB and was loaded from the second byte. Clamp the value width to the declared type before the big-endian offset adjustment, matching CGBitFieldInfo::MakeInfo. --- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 5 ++ .../aarch64-be-oversized-bitfield.cpp | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index d98d7c0c96dc3..56199dc18b794 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -243,6 +243,11 @@ void CGRecordLowering::setBitFieldInfo( Info.StorageOffset = StartOffset; if (Info.Size > Info.StorageSize) Info.Size = Info.StorageSize; + // CGBitFieldInfo::MakeInfo does the same clamp + llvm::Type *FieldType = Types.ConvertTypeForMem(FD->getType()); + unsigned FieldTypeSize = DataLayout.getTypeAllocSizeInBits(FieldType); + if (Info.Size > FieldTypeSize) + Info.Size = FieldTypeSize; // Reverse the bit offsets for big endian machines. Because we represent // a bitfield as a single large integer load, we can imagine the bits // counting from the most-significant-bit instead of the diff --git a/clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp b/clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp new file mode 100644 index 0000000000000..8dc72c55f984d --- /dev/null +++ b/clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++17 -emit-llvm -O0 \ +// RUN: -fdump-record-layouts-simple -o %t.be.ll %s | FileCheck %s --check-prefix=LAYOUT-BE +// RUN: FileCheck %s --check-prefix=BE <%t.be.ll +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -emit-llvm -O0 \ +// RUN: -fdump-record-layouts-simple -o %t.le.ll %s | FileCheck %s --check-prefix=LAYOUT-LE +// RUN: FileCheck %s --check-prefix=LE <%t.le.ll + +// An oversized bit-field has a declared width larger than its type. Only the +// type width is a value; the rest is padding, and the value bits come first. +// On AArch64 big endian that places 0xAB in the high byte of the 16-bit +// container (memory AB 00). A load therefore shifts the container right by 8. +// Little endian keeps the value in the low byte (memory AB 00 as well, as the +// integer 0x00AB). + +#pragma clang diagnostic ignored "-Wbitfield-width" + +struct S { + unsigned char value : 16; +}; + +// LAYOUT-BE: BitFields:[ +// LAYOUT-BE-NEXT: <CGBitFieldInfo Offset:8 Size:8 IsSigned:0 StorageSize:16 StorageOffset:0 +// LAYOUT-BE-NEXT: ]> +// LAYOUT-LE: BitFields:[ +// LAYOUT-LE-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:16 StorageOffset:0 +// LAYOUT-LE-NEXT: ]> + +// First byte is 0xAB. The padding byte is not the value. +// BE: @global = global { i8, i8 } { i8 -85, i8 undef }, align 2 +// LE: @global = global { i8, i8 } { i8 -85, i8 undef }, align 2 +extern "C" S global = {0xAB}; + +// BE-LABEL: define {{.*}} @get( +// BE: [[P:%.*]] = load ptr, ptr %p.addr +// BE: [[LOAD:%.*]] = load i16, ptr [[P]] +// BE-NEXT: [[SHL:%.*]] = lshr i16 [[LOAD]], 8 +// BE-NEXT: trunc i16 [[SHL]] to i8 +// +// LE-LABEL: define {{.*}} @get( +// LE: [[P:%.*]] = load ptr, ptr %p.addr +// LE: [[LOAD:%.*]] = load i16, ptr [[P]] +// LE-NOT: lshr +// LE: [[CLEAR:%.*]] = and i16 [[LOAD]], 255 +// LE-NEXT: trunc i16 [[CLEAR]] to i8 +extern "C" unsigned char get(const S *p) { + return p->value; +} >From 7c0868223ac0cdb79ee75007c2b13f0977ace40f Mon Sep 17 00:00:00 2001 From: Elio <[email protected]> Date: Wed, 23 Sep 2026 03:10:14 +0800 Subject: [PATCH 2/6] [Clang] Adjust padding calculation for corrected oversized bit-fields __builtin_clear_padding located occupied bits using the old big-endian layout, which placed padding before the value of an oversized bit-field. After the CodeGen fix, value bits come first. Size the value container to the field type and keep only the low-order occupied bits inside it, so clear_padding no longer zeroes the value. --- clang/lib/AST/ASTContext.cpp | 27 +- .../builtin-clear-padding-codegen.cpp | 395 ++++++------------ 2 files changed, 152 insertions(+), 270 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e74423ca8c8a1..f2d7ebcbd3c5e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -15917,13 +15917,15 @@ struct PaddingCalculator { const uint64_t DeclaredSizeInBits = Field->getBitWidthValue(); - // Handle over-sized bitfields: - // unsigned char a : 12; - // In this case, DeclaredSizeInBits is 12, but the actually occupied bit - // size is 8, while the remaining 4 bits are padding. - const uint64_t OccupiedSizeInBits = - std::min(DeclaredSizeInBits, - static_cast<uint64_t>(Ctx.getIntWidth(Field->getType()))); + // Oversized bit-fields (declared width larger than the field type) keep + // only the type's width as the value container. The extra declared bits + // are padding and follow that container (Itanium C++ ABI 2.4). + // getIntWidth may be narrower still (bool, _BitInt); those occupied bits + // are the low-order bits of the value container. + const uint64_t ValueFieldBits = + std::min(DeclaredSizeInBits, Ctx.getTypeSize(Field->getType())); + const uint64_t OccupiedSizeInBits = std::min( + ValueFieldBits, static_cast<uint64_t>(Ctx.getIntWidth(Field->getType()))); if (Ctx.getTargetInfo().isLittleEndian()) { OccuppiedIntervals.push_back( @@ -15941,14 +15943,11 @@ struct PaddingCalculator { // the partially occupied bytes in either end, if present, their bit // intervals need to be adjusted so that they count from the MSB instead. // - // FIXME: For over-sized bitfields in BE, Clang allocates padding bits - // before the occupied bits. This violates the ABI rules, which say that - // padding should be allocated after, regardless of endianness (Itanium C++ - // ABI ยง2.4, II.1(b)). The current code accommodates for Clang's current - // behaviour though, and bumps Start forward to skip the leading padding - // bits. + // Within the value container, occupied bits are its low-order bits, which + // are allocated last. Padding from an oversized declared width follows + // the container. const uint64_t Start = - StartBitOffset + DeclaredSizeInBits - OccupiedSizeInBits; + StartBitOffset + ValueFieldBits - OccupiedSizeInBits; const uint64_t End = Start + OccupiedSizeInBits; const uint64_t CharWidth = Ctx.getCharWidth(); diff --git a/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp b/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp index 7de1b0bb59fc5..599a8ba03c30d 100644 --- a/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp +++ b/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp @@ -1782,32 +1782,20 @@ struct OversizedBitfield { // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// ARM-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// ARM-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// ARM-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// ARM-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// ARM-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// ARM-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// ARM-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// ARM-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// ARM-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// ARM-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// ARM-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// ARM-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// ARM-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// ARM-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// ARM-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// ARM-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// ARM-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// ARM-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testOversizedBitfield( @@ -1816,32 +1804,20 @@ struct OversizedBitfield { // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// AARCH64-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// AARCH64-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// AARCH64-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// AARCH64-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// AARCH64-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// AARCH64-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// AARCH64-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// AARCH64-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// AARCH64-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// AARCH64-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testOversizedBitfield(struct OversizedBitfield *s) { @@ -1898,32 +1874,20 @@ extern "C" void testOversizedBitfield(struct OversizedBitfield *s) { // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// ARM-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// ARM-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// ARM-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// ARM-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// ARM-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// ARM-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// ARM-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// ARM-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// ARM-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// ARM-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// ARM-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// ARM-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// ARM-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// ARM-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// ARM-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// ARM-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// ARM-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// ARM-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testOversizedBitfieldVolatileStruct( @@ -1932,32 +1896,20 @@ extern "C" void testOversizedBitfield(struct OversizedBitfield *s) { // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// AARCH64-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// AARCH64-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// AARCH64-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// AARCH64-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// AARCH64-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// AARCH64-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// AARCH64-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// AARCH64-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// AARCH64-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// AARCH64-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testOversizedBitfieldVolatileStruct( @@ -2021,32 +1973,20 @@ struct VolatileOversizedBitfield { // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// ARM-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// ARM-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// ARM-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// ARM-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// ARM-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// ARM-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// ARM-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// ARM-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// ARM-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// ARM-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// ARM-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// ARM-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// ARM-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// ARM-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// ARM-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// ARM-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// ARM-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// ARM-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testVolatileOversizedBitfield( @@ -2055,32 +1995,20 @@ struct VolatileOversizedBitfield { // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// AARCH64-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// AARCH64-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// AARCH64-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// AARCH64-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// AARCH64-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// AARCH64-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// AARCH64-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// AARCH64-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// AARCH64-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// AARCH64-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testVolatileOversizedBitfield( @@ -2138,32 +2066,20 @@ extern "C" void testVolatileOversizedBitfield( // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// ARM-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// ARM-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// ARM-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// ARM-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// ARM-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// ARM-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// ARM-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// ARM-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// ARM-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// ARM-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// ARM-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// ARM-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// ARM-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// ARM-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// ARM-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// ARM-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// ARM-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// ARM-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// ARM-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// ARM-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// ARM-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testVolatileOversizedBitfieldVolatileStruct( @@ -2172,32 +2088,20 @@ extern "C" void testVolatileOversizedBitfield( // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 63 -// AARCH64-BE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 -// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -64 -// AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 2 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 -// AARCH64-BE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP0]], i32 8 -// AARCH64-BE-NEXT: [[TMP10:%.*]] = load i8, ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP11:%.*]] = and i8 [[TMP10]], 31 -// AARCH64-BE-NEXT: store i8 [[TMP11]], ptr [[TMP9]], align 4 -// AARCH64-BE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 -// AARCH64-BE-NEXT: [[TMP13:%.*]] = load i8, ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP14:%.*]] = and i8 [[TMP13]], -32 -// AARCH64-BE-NEXT: store i8 [[TMP14]], ptr [[TMP12]], align 4 -// AARCH64-BE-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP15]], align 1 -// AARCH64-BE-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP16]], align 2 -// AARCH64-BE-NEXT: [[TMP17:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP17]], align 1 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 +// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP4]], align 4 +// AARCH64-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP5]], align 1 +// AARCH64-BE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP6]], align 2 +// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP7]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testVolatileOversizedBitfieldVolatileStruct( @@ -4838,8 +4742,8 @@ extern "C" void testPackedBooleanVectorWithFullyPaddingBytes(bool33 *v) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wbitfield-width" -// Match Clang's existing oversized-field representation. On big endian the -// occupied byte is byte 1, so clearing padding must leave that byte intact. +// Value bits occupy the first byte on both endians. The second byte is +// padding and must be cleared. struct BitfieldOversizedAligned { unsigned char value : 16; }; @@ -4870,8 +4774,8 @@ struct BitfieldOversizedAligned { // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 2 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testBitfieldOversizedAligned( @@ -4880,16 +4784,15 @@ struct BitfieldOversizedAligned { // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 2 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testBitfieldOversizedAligned(BitfieldOversizedAligned *s) { __builtin_clear_padding(s); } -// The occupied bits cross a byte boundary after more than one byte of leading -// padding on big endian. The declared width also exceeds the allocation type. +// Eight value bits occupy the first byte. The rest of the allocation is padding. struct BitfieldOversizedBeyondBoundary { unsigned char value : 17; }; @@ -4928,18 +4831,12 @@ struct BitfieldOversizedBeyondBoundary { // ARM-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 4 // ARM-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 4 // ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 4 -// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 2 -// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 -// ARM-BE-NEXT: [[TMP4:%.*]] = and i8 [[TMP3]], 127 -// ARM-BE-NEXT: store i8 [[TMP4]], ptr [[TMP2]], align 1 -// ARM-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 2 -// ARM-BE-NEXT: [[TMP7:%.*]] = and i8 [[TMP6]], -128 -// ARM-BE-NEXT: store i8 [[TMP7]], ptr [[TMP5]], align 2 -// ARM-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// ARM-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 +// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testBitfieldOversizedBeyondBoundary( @@ -4948,18 +4845,12 @@ struct BitfieldOversizedBeyondBoundary { // AARCH64-BE-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 // AARCH64-BE-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 // AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 -// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 2 -// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1 -// AARCH64-BE-NEXT: [[TMP4:%.*]] = and i8 [[TMP3]], 127 -// AARCH64-BE-NEXT: store i8 [[TMP4]], ptr [[TMP2]], align 1 -// AARCH64-BE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 2 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = and i8 [[TMP6]], -128 -// AARCH64-BE-NEXT: store i8 [[TMP7]], ptr [[TMP5]], align 2 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 -// AARCH64-BE-NEXT: store i8 0, ptr [[TMP8]], align 1 +// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 1 +// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 2 +// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 1 // AARCH64-BE-NEXT: ret void // extern "C" void testBitfieldOversizedBeyondBoundary( @@ -5030,14 +4921,10 @@ struct BitfieldOversizedValueTypes { // ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 2 // ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 // ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 2 -// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// ARM-BE-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 1 -// ARM-BE-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 -// ARM-BE-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 1 -// ARM-BE-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// ARM-BE-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 2 -// ARM-BE-NEXT: [[TMP12:%.*]] = and i8 [[TMP11]], -15 -// ARM-BE-NEXT: store i8 [[TMP12]], ptr [[TMP10]], align 2 +// ARM-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// ARM-BE-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 2 +// ARM-BE-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 1 +// ARM-BE-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 2 // ARM-BE-NEXT: ret void // // AARCH64-BE-LABEL: define dso_local void @testBitfieldOversizedValueTypes( @@ -5054,14 +4941,10 @@ struct BitfieldOversizedValueTypes { // AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 2 // AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 // AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 2 -// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 -// AARCH64-BE-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 1 -// AARCH64-BE-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 -// AARCH64-BE-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 1 -// AARCH64-BE-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 -// AARCH64-BE-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 2 -// AARCH64-BE-NEXT: [[TMP12:%.*]] = and i8 [[TMP11]], -15 -// AARCH64-BE-NEXT: store i8 [[TMP12]], ptr [[TMP10]], align 2 +// AARCH64-BE-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// AARCH64-BE-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 2 +// AARCH64-BE-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 1 +// AARCH64-BE-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 2 // AARCH64-BE-NEXT: ret void // extern "C" void testBitfieldOversizedValueTypes( >From a57f09dfe74547b919b2423d5e93db1803a020b8 Mon Sep 17 00:00:00 2001 From: Zile Xiong <[email protected]> Date: Wed, 23 Sep 2026 11:09:43 +0800 Subject: [PATCH 3/6] clang-format --- clang/lib/AST/ASTContext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f2d7ebcbd3c5e..c6554fc58f198 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -15924,8 +15924,9 @@ struct PaddingCalculator { // are the low-order bits of the value container. const uint64_t ValueFieldBits = std::min(DeclaredSizeInBits, Ctx.getTypeSize(Field->getType())); - const uint64_t OccupiedSizeInBits = std::min( - ValueFieldBits, static_cast<uint64_t>(Ctx.getIntWidth(Field->getType()))); + const uint64_t OccupiedSizeInBits = + std::min(ValueFieldBits, + static_cast<uint64_t>(Ctx.getIntWidth(Field->getType()))); if (Ctx.getTargetInfo().isLittleEndian()) { OccuppiedIntervals.push_back( @@ -15946,8 +15947,7 @@ struct PaddingCalculator { // Within the value container, occupied bits are its low-order bits, which // are allocated last. Padding from an oversized declared width follows // the container. - const uint64_t Start = - StartBitOffset + ValueFieldBits - OccupiedSizeInBits; + const uint64_t Start = StartBitOffset + ValueFieldBits - OccupiedSizeInBits; const uint64_t End = Start + OccupiedSizeInBits; const uint64_t CharWidth = Ctx.getCharWidth(); >From 039a4270357f30a18875a287c80a497a77e90290 Mon Sep 17 00:00:00 2001 From: Zile Xiong <[email protected]> Date: Wed, 23 Sep 2026 11:23:18 +0800 Subject: [PATCH 4/6] add systemZ and powerPC tests --- ...ld.cpp => big-endian-oversized-bitfield.cpp} | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) rename clang/test/CodeGenCXX/{aarch64-be-oversized-bitfield.cpp => big-endian-oversized-bitfield.cpp} (63%) diff --git a/clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp similarity index 63% rename from clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp rename to clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp index 8dc72c55f984d..0e37c714e853d 100644 --- a/clang/test/CodeGenCXX/aarch64-be-oversized-bitfield.cpp +++ b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp @@ -4,13 +4,22 @@ // RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -emit-llvm -O0 \ // RUN: -fdump-record-layouts-simple -o %t.le.ll %s | FileCheck %s --check-prefix=LAYOUT-LE // RUN: FileCheck %s --check-prefix=LE <%t.le.ll +// RUN: %clang_cc1 -triple s390x-linux-gnu -std=c++17 -emit-llvm -O0 \ +// RUN: -fdump-record-layouts-simple -o %t.s390x.ll %s | FileCheck %s --check-prefix=LAYOUT-BE +// RUN: FileCheck %s --check-prefix=BE <%t.s390x.ll +// RUN: %clang_cc1 -triple powerpc64-linux-gnu -std=c++17 -emit-llvm -O0 \ +// RUN: -fdump-record-layouts-simple -o %t.ppc64.ll %s | FileCheck %s --check-prefix=LAYOUT-BE +// RUN: FileCheck %s --check-prefix=BE <%t.ppc64.ll +// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -std=c++17 -emit-llvm -O0 \ +// RUN: -fdump-record-layouts-simple -o %t.ppc64le.ll %s | FileCheck %s --check-prefix=LAYOUT-LE +// RUN: FileCheck %s --check-prefix=LE <%t.ppc64le.ll // An oversized bit-field has a declared width larger than its type. Only the // type width is a value; the rest is padding, and the value bits come first. -// On AArch64 big endian that places 0xAB in the high byte of the 16-bit -// container (memory AB 00). A load therefore shifts the container right by 8. -// Little endian keeps the value in the low byte (memory AB 00 as well, as the -// integer 0x00AB). +// Big endian (AArch64, SystemZ, PowerPC) places 0xAB in the high byte of the +// 16-bit container (memory AB 00). A load therefore shifts the container right +// by 8. Little endian keeps the value in the low byte (memory AB 00 as well, +// as the integer 0x00AB) and masks instead of shifting. #pragma clang diagnostic ignored "-Wbitfield-width" >From 1389a5ca38412d6fb884dd283f8db6f4df7f8bf4 Mon Sep 17 00:00:00 2001 From: Zile Xiong <[email protected]> Date: Wed, 23 Sep 2026 12:40:09 +0800 Subject: [PATCH 5/6] remove le tests --- .../big-endian-oversized-bitfield.cpp | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp index 0e37c714e853d..cad72482c372a 100644 --- a/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp +++ b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp @@ -1,25 +1,18 @@ // RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++17 -emit-llvm -O0 \ // RUN: -fdump-record-layouts-simple -o %t.be.ll %s | FileCheck %s --check-prefix=LAYOUT-BE // RUN: FileCheck %s --check-prefix=BE <%t.be.ll -// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -emit-llvm -O0 \ -// RUN: -fdump-record-layouts-simple -o %t.le.ll %s | FileCheck %s --check-prefix=LAYOUT-LE -// RUN: FileCheck %s --check-prefix=LE <%t.le.ll // RUN: %clang_cc1 -triple s390x-linux-gnu -std=c++17 -emit-llvm -O0 \ // RUN: -fdump-record-layouts-simple -o %t.s390x.ll %s | FileCheck %s --check-prefix=LAYOUT-BE // RUN: FileCheck %s --check-prefix=BE <%t.s390x.ll // RUN: %clang_cc1 -triple powerpc64-linux-gnu -std=c++17 -emit-llvm -O0 \ // RUN: -fdump-record-layouts-simple -o %t.ppc64.ll %s | FileCheck %s --check-prefix=LAYOUT-BE // RUN: FileCheck %s --check-prefix=BE <%t.ppc64.ll -// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -std=c++17 -emit-llvm -O0 \ -// RUN: -fdump-record-layouts-simple -o %t.ppc64le.ll %s | FileCheck %s --check-prefix=LAYOUT-LE -// RUN: FileCheck %s --check-prefix=LE <%t.ppc64le.ll // An oversized bit-field has a declared width larger than its type. Only the // type width is a value; the rest is padding, and the value bits come first. // Big endian (AArch64, SystemZ, PowerPC) places 0xAB in the high byte of the // 16-bit container (memory AB 00). A load therefore shifts the container right -// by 8. Little endian keeps the value in the low byte (memory AB 00 as well, -// as the integer 0x00AB) and masks instead of shifting. +// by 8. #pragma clang diagnostic ignored "-Wbitfield-width" @@ -30,13 +23,9 @@ struct S { // LAYOUT-BE: BitFields:[ // LAYOUT-BE-NEXT: <CGBitFieldInfo Offset:8 Size:8 IsSigned:0 StorageSize:16 StorageOffset:0 // LAYOUT-BE-NEXT: ]> -// LAYOUT-LE: BitFields:[ -// LAYOUT-LE-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:16 StorageOffset:0 -// LAYOUT-LE-NEXT: ]> // First byte is 0xAB. The padding byte is not the value. // BE: @global = global { i8, i8 } { i8 -85, i8 undef }, align 2 -// LE: @global = global { i8, i8 } { i8 -85, i8 undef }, align 2 extern "C" S global = {0xAB}; // BE-LABEL: define {{.*}} @get( @@ -44,13 +33,6 @@ extern "C" S global = {0xAB}; // BE: [[LOAD:%.*]] = load i16, ptr [[P]] // BE-NEXT: [[SHL:%.*]] = lshr i16 [[LOAD]], 8 // BE-NEXT: trunc i16 [[SHL]] to i8 -// -// LE-LABEL: define {{.*}} @get( -// LE: [[P:%.*]] = load ptr, ptr %p.addr -// LE: [[LOAD:%.*]] = load i16, ptr [[P]] -// LE-NOT: lshr -// LE: [[CLEAR:%.*]] = and i16 [[LOAD]], 255 -// LE-NEXT: trunc i16 [[CLEAR]] to i8 extern "C" unsigned char get(const S *p) { return p->value; } >From a4ead86d3723bc5b24fc818ceab1f268ed788d66 Mon Sep 17 00:00:00 2001 From: Zile Xiong <[email protected]> Date: Thu, 24 Sep 2026 14:11:19 +0800 Subject: [PATCH 6/6] add set test --- .../big-endian-oversized-bitfield.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp index cad72482c372a..0dda596725bed 100644 --- a/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp +++ b/clang/test/CodeGenCXX/big-endian-oversized-bitfield.cpp @@ -12,7 +12,7 @@ // type width is a value; the rest is padding, and the value bits come first. // Big endian (AArch64, SystemZ, PowerPC) places 0xAB in the high byte of the // 16-bit container (memory AB 00). A load therefore shifts the container right -// by 8. +// by 8. A store shifts the new value left by 8 and keeps the low byte. #pragma clang diagnostic ignored "-Wbitfield-width" @@ -26,13 +26,28 @@ struct S { // First byte is 0xAB. The padding byte is not the value. // BE: @global = global { i8, i8 } { i8 -85, i8 undef }, align 2 -extern "C" S global = {0xAB}; +S global = {0xAB}; -// BE-LABEL: define {{.*}} @get( +// BE-LABEL: define {{.*}} @_Z3getPK1S( // BE: [[P:%.*]] = load ptr, ptr %p.addr // BE: [[LOAD:%.*]] = load i16, ptr [[P]] // BE-NEXT: [[SHL:%.*]] = lshr i16 [[LOAD]], 8 // BE-NEXT: trunc i16 [[SHL]] to i8 -extern "C" unsigned char get(const S *p) { +unsigned char get(const S *p) { return p->value; } + +// The value goes in the high byte. The low byte is padding and is preserved. +// BE-LABEL: define {{.*}} @_Z3setP1Sh( +// BE: [[V:%.*]] = load i8, ptr %v.addr +// BE: [[PTR:%.*]] = load ptr, ptr %p.addr +// BE: [[EXT:%.*]] = zext i8 [[V]] to i16 +// BE: [[OLD:%.*]] = load i16, ptr [[PTR]] +// BE-NEXT: [[MASKED:%.*]] = and i16 [[EXT]], 255 +// BE-NEXT: [[SHIFTED:%.*]] = shl i16 [[MASKED]], 8 +// BE-NEXT: [[KEPT:%.*]] = and i16 [[OLD]], 255 +// BE-NEXT: [[MERGED:%.*]] = or i16 [[KEPT]], [[SHIFTED]] +// BE-NEXT: store i16 [[MERGED]], ptr [[PTR]] +void set(S *p, unsigned char v) { + p->value = v; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
