[llvm-branch-commits] [clang] [Clang] Fix __builtin_clear_padding() for bitfields (PR #216063)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 13 07:25:31 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang
Author: Victor Campos (vhscampos)
<details>
<summary>Changes</summary>
This patch fixes the padding clearing logic for bitfields.
The padding clearing logic for bitfields is wrong for these cases:
- Over-sized bitfields don't have their padding bits recognised as such.
- In big endian mode, the occupied bits are wrongly determined because the different byte order is dismissed.
Assisted-by: Codex. Used to help debugging.
---
Patch is 311.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/216063.diff
3 Files Affected:
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+66-4)
- (modified) clang/test/CodeGen/builtin-clear-padding-codegen.c (+1909-58)
- (modified) clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp (+2941-74)
``````````diff
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 13aff2ef13eb9..24b2987923e26 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2672,6 +2672,69 @@ struct PaddingClearer {
return CGF.getContext().getTypeSize(Ty);
}
+ /// Compute the occupied bit intervals for a bitfield.
+ ///
+ /// In the case of little endian, the occupied bits are always contiguous so a
+ /// single interval is sufficient; whereas in big endian mode, the occupied
+ /// bits are not necessarily contiguous since the byte order is reversed. Care
+ /// is also taken if the bitfield is volatile because the field size and
+ /// offset can be different in this case.
+ SmallVector<BitInterval>
+ computeBitfieldOccupiedIntervals(const RecordDecl *RD, const FieldDecl *Field,
+ uint64_t StartBitOffset) const {
+ const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD);
+ const CGBitFieldInfo &Info = Layout.getBitFieldInfo(Field);
+ bool IsLittleEndian = CGF.getTarget().isLittleEndian();
+ bool IsVolatile = Field->getType().isVolatileQualified() &&
+ Info.VolatileStorageSize != 0 &&
+ CGF.CGM.getTarget().getABI().starts_with("aapcs");
+
+ uint64_t DeclaredTySizeInBits =
+ getScalarOccupiedSizeInBits(Field->getType());
+ // In case of over-sized bitfields, the number of bits actually occupied
+ // with values is smaller than the declared bitfield width (Info.Size).
+ uint64_t ValueSizeInBits =
+ std::min(static_cast<uint64_t>(Info.Size), DeclaredTySizeInBits);
+
+ const uint64_t Offset = IsVolatile ? Info.VolatileOffset : Info.Offset;
+
+ // This calculation looks different between volatile and non-volatile
+ // because StorageOffset is in bytes, whereas VolatileStorageOffset is in
+ // VolatileStorageSize units.
+ const uint64_t StorageOffset =
+ IsVolatile ? Info.VolatileStorageOffset.getQuantity() *
+ Info.VolatileStorageSize
+ : CGF.getContext().toBits(Info.StorageOffset);
+
+ if (IsLittleEndian)
+ return {BitInterval{StartBitOffset + StorageOffset + Offset,
+ StartBitOffset + StorageOffset + Offset +
+ ValueSizeInBits}};
+
+ const uint64_t StorageSize =
+ IsVolatile ? Info.VolatileStorageSize : Info.StorageSize;
+ const uint64_t BitsInByte = CGF.getContext().getCharWidth();
+
+ SmallVector<BitInterval> Intervals;
+
+ for (uint64_t Start = Offset, End = Start + ValueSizeInBits; Start < End;
+ Start = (Start + BitsInByte) & (~0UL << 3)) {
+ uint64_t ByteBoundaryStart = Start & (~0UL << 3);
+ uint64_t ByteBoundaryEnd = ByteBoundaryStart + BitsInByte;
+ uint64_t OffsetWithinByte = Start - ByteBoundaryStart;
+ uint64_t SizeWithinByte =
+ std::min(End - Start, BitsInByte - OffsetWithinByte);
+ uint64_t ByteOffset = StorageSize - ByteBoundaryEnd;
+
+ BitInterval BI{StartBitOffset + StorageOffset + ByteOffset +
+ OffsetWithinByte,
+ StartBitOffset + StorageOffset + ByteOffset +
+ OffsetWithinByte + SizeWithinByte};
+ Intervals.push_back(std::move(BI));
+ }
+ return Intervals;
+ }
+
/// Compute the occupied bit intervals for a BitInt.
///
/// In the case of little endian, the occupied bits are always contiguous so a
@@ -2816,12 +2879,11 @@ struct PaddingClearer {
if (Field->isUnnamedBitField())
continue;
- auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
if (Field->isBitField()) {
- OccuppiedIntervals.push_back(BitInterval{
- StartBitOffset + FieldOffset,
- StartBitOffset + FieldOffset + Field->getBitWidthValue()});
+ OccuppiedIntervals.append(
+ computeBitfieldOccupiedIntervals(R, Field, StartBitOffset));
} else {
+ auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
/*VisitVirtualBase*/ true});
}
diff --git a/clang/test/CodeGen/builtin-clear-padding-codegen.c b/clang/test/CodeGen/builtin-clear-padding-codegen.c
index fceb7b623ba6d..7e709f4fcbf98 100644
--- a/clang/test/CodeGen/builtin-clear-padding-codegen.c
+++ b/clang/test/CodeGen/builtin-clear-padding-codegen.c
@@ -3,8 +3,8 @@
// RUN: %clang_cc1 -std=c11 -triple=x86_64-pc-windows-msvc -emit-llvm -o - %s | FileCheck %s --check-prefix=WINDOWS
// RUN: %clang_cc1 -std=c11 -triple=armv7a-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM-LE
// RUN: %clang_cc1 -std=c11 -triple=armebv7a-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM-BE
-// RUN: %clang_cc1 -std=c11 -triple=aarch64-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM-LE
-// RUN: %clang_cc1 -std=c11 -triple=aarch64_be-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM-BE
+// RUN: %clang_cc1 -std=c11 -triple=aarch64-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=AARCH64-LE
+// RUN: %clang_cc1 -std=c11 -triple=aarch64_be-none-eabi -emit-llvm -o - %s | FileCheck %s --check-prefix=AARCH64-BE
struct Empty {};
@@ -31,6 +31,38 @@ struct Empty {};
// WINDOWS-NEXT: store i8 0, ptr %4, align 1
// WINDOWS-NEXT: ret void
//
+// ARM-LE-LABEL: define dso_local void @testEmpty(
+// ARM-LE-SAME: ptr noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] {
+// ARM-LE-NEXT: [[ENTRY:.*:]]
+// ARM-LE-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 4
+// ARM-LE-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 4
+// ARM-LE-NEXT: ret void
+//
+// ARM-BE-LABEL: define dso_local void @testEmpty(
+// ARM-BE-SAME: ptr noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] {
+// ARM-BE-NEXT: [[ENTRY:.*:]]
+// ARM-BE-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 4
+// ARM-BE-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 4
+// ARM-BE-NEXT: ret void
+//
+// AARCH64-LE-LABEL: define dso_local void @testEmpty(
+// AARCH64-LE-SAME: ptr noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] {
+// AARCH64-LE-NEXT: [[ENTRY:.*:]]
+// AARCH64-LE-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-LE-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// AARCH64-LE-NEXT: ret void
+//
+// AARCH64-BE-LABEL: define dso_local void @testEmpty(
+// AARCH64-BE-SAME: ptr noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] {
+// AARCH64-BE-NEXT: [[ENTRY:.*:]]
+// AARCH64-BE-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-BE-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[E_ADDR]], align 8
+// AARCH64-BE-NEXT: ret void
+//
void testEmpty(struct Empty *e) {
// Emtpy struct is empty in C in Itanium ABI, no padding
// Emtpy struct has 4 bytes in C in clang's MSVC ABI
@@ -53,6 +85,38 @@ void testEmpty(struct Empty *e) {
// WINDOWS-NEXT: %0 = load ptr, ptr %i.addr, align 8
// WINDOWS-NEXT: ret void
//
+// ARM-LE-LABEL: define dso_local void @testPrimitiveNoPadding(
+// ARM-LE-SAME: ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// ARM-LE-NEXT: [[ENTRY:.*:]]
+// ARM-LE-NEXT: [[I_ADDR:%.*]] = alloca ptr, align 4
+// ARM-LE-NEXT: store ptr [[I]], ptr [[I_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[I_ADDR]], align 4
+// ARM-LE-NEXT: ret void
+//
+// ARM-BE-LABEL: define dso_local void @testPrimitiveNoPadding(
+// ARM-BE-SAME: ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// ARM-BE-NEXT: [[ENTRY:.*:]]
+// ARM-BE-NEXT: [[I_ADDR:%.*]] = alloca ptr, align 4
+// ARM-BE-NEXT: store ptr [[I]], ptr [[I_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[I_ADDR]], align 4
+// ARM-BE-NEXT: ret void
+//
+// AARCH64-LE-LABEL: define dso_local void @testPrimitiveNoPadding(
+// AARCH64-LE-SAME: ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// AARCH64-LE-NEXT: [[ENTRY:.*:]]
+// AARCH64-LE-NEXT: [[I_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-LE-NEXT: store ptr [[I]], ptr [[I_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[I_ADDR]], align 8
+// AARCH64-LE-NEXT: ret void
+//
+// AARCH64-BE-LABEL: define dso_local void @testPrimitiveNoPadding(
+// AARCH64-BE-SAME: ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// AARCH64-BE-NEXT: [[ENTRY:.*:]]
+// AARCH64-BE-NEXT: [[I_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-BE-NEXT: store ptr [[I]], ptr [[I_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[I_ADDR]], align 8
+// AARCH64-BE-NEXT: ret void
+//
void testPrimitiveNoPadding(int *i) {
// This should not clear any padding, since int has no padding.
__builtin_clear_padding(i);
@@ -86,6 +150,38 @@ void testPrimitiveNoPadding(int *i) {
// WINDOWS-NEXT: %0 = load ptr, ptr %ld.addr, align 8
// WINDOWS-NEXT: ret void
//
+// ARM-LE-LABEL: define dso_local void @testPrimitiveLongDouble(
+// ARM-LE-SAME: ptr noundef [[LD:%.*]]) #[[ATTR0]] {
+// ARM-LE-NEXT: [[ENTRY:.*:]]
+// ARM-LE-NEXT: [[LD_ADDR:%.*]] = alloca ptr, align 4
+// ARM-LE-NEXT: store ptr [[LD]], ptr [[LD_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[LD_ADDR]], align 4
+// ARM-LE-NEXT: ret void
+//
+// ARM-BE-LABEL: define dso_local void @testPrimitiveLongDouble(
+// ARM-BE-SAME: ptr noundef [[LD:%.*]]) #[[ATTR0]] {
+// ARM-BE-NEXT: [[ENTRY:.*:]]
+// ARM-BE-NEXT: [[LD_ADDR:%.*]] = alloca ptr, align 4
+// ARM-BE-NEXT: store ptr [[LD]], ptr [[LD_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[LD_ADDR]], align 4
+// ARM-BE-NEXT: ret void
+//
+// AARCH64-LE-LABEL: define dso_local void @testPrimitiveLongDouble(
+// AARCH64-LE-SAME: ptr noundef [[LD:%.*]]) #[[ATTR0]] {
+// AARCH64-LE-NEXT: [[ENTRY:.*:]]
+// AARCH64-LE-NEXT: [[LD_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-LE-NEXT: store ptr [[LD]], ptr [[LD_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[LD_ADDR]], align 8
+// AARCH64-LE-NEXT: ret void
+//
+// AARCH64-BE-LABEL: define dso_local void @testPrimitiveLongDouble(
+// AARCH64-BE-SAME: ptr noundef [[LD:%.*]]) #[[ATTR0]] {
+// AARCH64-BE-NEXT: [[ENTRY:.*:]]
+// AARCH64-BE-NEXT: [[LD_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-BE-NEXT: store ptr [[LD]], ptr [[LD_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[LD_ADDR]], align 8
+// AARCH64-BE-NEXT: ret void
+//
void testPrimitiveLongDouble(long double *ld) {
// padding [10, 15] on x86
__builtin_clear_padding(ld);
@@ -127,82 +223,254 @@ void testPrimitiveLongDouble(long double *ld) {
// WINDOWS-NEXT: ret void
//
// ARM-LE-LABEL: define dso_local void @testBitInt(
-// ARM-LE: [[OBJ:%.*]] = load ptr, ptr {{.*}}, align {{[0-9]+}}
-// ARM-LE-NEXT: [[BYTE12:%.*]] = getelementptr i8, ptr [[OBJ]], i32 12
-// ARM-LE-NEXT: [[VALUE:%.*]] = load i8, ptr [[BYTE12]], align 4
-// ARM-LE-NEXT: [[MASKED:%.*]] = and i8 [[VALUE]], 1
-// ARM-LE-NEXT: store i8 [[MASKED]], ptr [[BYTE12]], align 4
-// ARM-LE-NEXT: [[BYTE13:%.*]] = getelementptr i8, ptr [[OBJ]], i32 13
-// ARM-LE-NEXT: store i8 0, ptr [[BYTE13]], align 1
-// ARM-LE-NEXT: [[BYTE14:%.*]] = getelementptr i8, ptr [[OBJ]], i32 14
-// ARM-LE-NEXT: store i8 0, ptr [[BYTE14]], align 2
-// ARM-LE-NEXT: [[BYTE15:%.*]] = getelementptr i8, ptr [[OBJ]], i32 15
-// ARM-LE-NEXT: store i8 0, ptr [[BYTE15]], align 1
-// ARM-LE-NEXT: ret void
+// ARM-LE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// ARM-LE-NEXT: [[ENTRY:.*:]]
+// ARM-LE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 4
+// ARM-LE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12
+// ARM-LE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4
+// ARM-LE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 1
+// ARM-LE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4
+// ARM-LE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13
+// ARM-LE-NEXT: store i8 0, ptr [[TMP4]], align 1
+// ARM-LE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14
+// ARM-LE-NEXT: store i8 0, ptr [[TMP5]], align 2
+// ARM-LE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15
+// ARM-LE-NEXT: store i8 0, ptr [[TMP6]], align 1
+// ARM-LE-NEXT: ret void
//
// ARM-BE-LABEL: define dso_local void @testBitInt(
-// ARM-BE: [[OBJ:%.*]] = load ptr, ptr {{.*}}, align {{[0-9]+}}
-// ARM-BE-NEXT: [[BYTE0:%.*]] = getelementptr i8, ptr [[OBJ]], i32 0
-// ARM-BE-NEXT: store i8 0, ptr [[BYTE0]], align {{[0-9]+}}
-// ARM-BE-NEXT: [[BYTE1:%.*]] = getelementptr i8, ptr [[OBJ]], i32 1
-// ARM-BE-NEXT: store i8 0, ptr [[BYTE1]], align 1
-// ARM-BE-NEXT: [[BYTE2:%.*]] = getelementptr i8, ptr [[OBJ]], i32 2
-// ARM-BE-NEXT: store i8 0, ptr [[BYTE2]], align 2
-// ARM-BE-NEXT: [[BYTE3:%.*]] = getelementptr i8, ptr [[OBJ]], i32 3
-// ARM-BE-NEXT: [[VALUE:%.*]] = load i8, ptr [[BYTE3]], align 1
-// ARM-BE-NEXT: [[MASKED:%.*]] = and i8 [[VALUE]], 1
-// ARM-BE-NEXT: store i8 [[MASKED]], ptr [[BYTE3]], align 1
-// ARM-BE-NEXT: ret void
+// ARM-BE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// ARM-BE-NEXT: [[ENTRY:.*:]]
+// ARM-BE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 4
+// ARM-BE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0
+// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 8
+// ARM-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1
+// ARM-BE-NEXT: store i8 0, ptr [[TMP2]], align 1
+// ARM-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2
+// ARM-BE-NEXT: store i8 0, ptr [[TMP3]], align 2
+// ARM-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// ARM-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1
+// ARM-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
+// ARM-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1
+// ARM-BE-NEXT: ret void
+//
+// AARCH64-LE-LABEL: define dso_local void @testBitInt(
+// AARCH64-LE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// AARCH64-LE-NEXT: [[ENTRY:.*:]]
+// AARCH64-LE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-LE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 12
+// AARCH64-LE-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4
+// AARCH64-LE-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 1
+// AARCH64-LE-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4
+// AARCH64-LE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 13
+// AARCH64-LE-NEXT: store i8 0, ptr [[TMP4]], align 1
+// AARCH64-LE-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 14
+// AARCH64-LE-NEXT: store i8 0, ptr [[TMP5]], align 2
+// AARCH64-LE-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 15
+// AARCH64-LE-NEXT: store i8 0, ptr [[TMP6]], align 1
+// AARCH64-LE-NEXT: ret void
+//
+// AARCH64-BE-LABEL: define dso_local void @testBitInt(
+// AARCH64-BE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// AARCH64-BE-NEXT: [[ENTRY:.*:]]
+// AARCH64-BE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-BE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0
+// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 16
+// AARCH64-BE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1
+// AARCH64-BE-NEXT: store i8 0, ptr [[TMP2]], align 1
+// AARCH64-BE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2
+// AARCH64-BE-NEXT: store i8 0, ptr [[TMP3]], align 2
+// AARCH64-BE-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// AARCH64-BE-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1
+// AARCH64-BE-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
+// AARCH64-BE-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1
+// AARCH64-BE-NEXT: ret void
//
void testBitInt(_BitInt(97) *bi) {
// Storage is widened to 128 bits; clear bits [97, 128).
__builtin_clear_padding(bi);
}
+// LINUX-LABEL: define dso_local void @testBitIntByteAligned(
+// LINUX-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// LINUX-NEXT: [[ENTRY:.*:]]
+// LINUX-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// LINUX-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// LINUX-NEXT: store i8 0, ptr [[TMP1]], align 1
+// LINUX-NEXT: ret void
+//
+// WINDOWS-LABEL: define dso_local void @testBitIntByteAligned(
+// WINDOWS-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// WINDOWS-NEXT: [[ENTRY:.*:]]
+// WINDOWS-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// WINDOWS-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// WINDOWS-NEXT: store i8 0, ptr [[TMP1]], align 1
+// WINDOWS-NEXT: ret void
+//
// ARM-LE-LABEL: define dso_local void @testBitIntByteAligned(
-// ARM-LE: [[OBJ:%.*]] = load ptr, ptr {{.*}}, align {{[0-9]+}}
-// ARM-LE-NEXT: [[BYTE3:%.*]] = getelementptr i8, ptr [[OBJ]], i32 3
-// ARM-LE-NEXT: store i8 0, ptr [[BYTE3]], align 1
-// ARM-LE-NEXT: ret void
+// ARM-LE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// ARM-LE-NEXT: [[ENTRY:.*:]]
+// ARM-LE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 4
+// ARM-LE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 4
+// ARM-LE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// ARM-LE-NEXT: store i8 0, ptr [[TMP1]], align 1
+// ARM-LE-NEXT: ret void
//
// ARM-BE-LABEL: define dso_local void @testBitIntByteAligned(
-// ARM-BE: [[OBJ:%.*]] = load ptr, ptr {{.*}}, align {{[0-9]+}}
-// ARM-BE-NEXT: [[BYTE0:%.*]] = getelementptr i8, ptr [[OBJ]], i32 0
-// ARM-BE-NEXT: store i8 0, ptr [[BYTE0]], align 4
-// ARM-BE-NEXT: ret void
+// ARM-BE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// ARM-BE-NEXT: [[ENTRY:.*:]]
+// ARM-BE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 4
+// ARM-BE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 4
+// ARM-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0
+// ARM-BE-NEXT: store i8 0, ptr [[TMP1]], align 4
+// ARM-BE-NEXT: ret void
+//
+// AARCH64-LE-LABEL: define dso_local void @testBitIntByteAligned(
+// AARCH64-LE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// AARCH64-LE-NEXT: [[ENTRY:.*:]]
+// AARCH64-LE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-LE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// AARCH64-LE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3
+// AARCH64-LE-NEXT: store i8 0, ptr [[TMP1]], align 1
+// AARCH64-LE-NEXT: ret void
+//
+// AARCH64-BE-LABEL: define dso_local void @testBitIntByteAligned(
+// AARCH64-BE-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// AARCH64-BE-NEXT: [[ENTRY:.*:]]
+// AARCH64-BE-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// AARCH64-BE-NEXT: store ptr [[BI]], ptr [[BI_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BI_ADDR]], align 8
+// AARCH64-BE-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0
+// AARCH64-BE-NEXT: store i8 0, ptr [[TMP1]], align 4
+// AARCH64-BE-NEXT: ret void
//
void testBitIntByteAligned(_BitInt(24) *bi) {
// Storage is widened to 32 bits; clear the leading or trailing byte.
__builtin_clear_padding(bi);
}
+// LINUX-LABEL: define dso_local void @testVolatileBitInt(
+// LINUX-SAME: ptr noundef [[BI:%.*]]) #[[ATTR0]] {
+// LINUX-NEXT: [[ENTRY:.*:]]
+// LINUX-NEXT: [[BI_ADDR:%.*]] = alloca ptr, align 8
+// LI...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/216063
More information about the llvm-branch-commits
mailing list