https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/205813
>From 88a2a6036cae2a5437e43d1d270157fcce309971 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Thu, 25 Jun 2026 13:17:11 +0000 Subject: [PATCH] [clang][test] Add more tests for __builtin_clear_padding Follow-up to https://github.com/llvm/llvm-project/pull/201102 which fixed Clang's `__builtin_clear_padding` treatment of unnamed bitfields. This patch adds some more test coverage (more layouts, and verifies IR). Used Claude to generate the layouts. Manually ran `llvm/utils/update_cc_test_checks.py` to generate the `CHECK` directives and confirmed that the bit-masks in the IR match the expected `__builtin_clear_padding` behaviour. Assisted-by: claude --- .../CodeGen/builtin-clear-padding-codegen.c | 249 ++++++++++++++++++ .../builtin-clear-padding-codegen.cpp | 249 ++++++++++++++++++ 2 files changed, 498 insertions(+) diff --git a/clang/test/CodeGen/builtin-clear-padding-codegen.c b/clang/test/CodeGen/builtin-clear-padding-codegen.c index 9d5e06c79fa94..c2602d8934bd7 100644 --- a/clang/test/CodeGen/builtin-clear-padding-codegen.c +++ b/clang/test/CodeGen/builtin-clear-padding-codegen.c @@ -991,3 +991,252 @@ void testAttributedLongDoubleType(LongDouble3Vec *v) { // long double elements occupy [0-9], [16-25], [32-41] on x86. __builtin_clear_padding(v); } + +struct UnnamedBitfieldSingleBit { + unsigned char a : 3; + unsigned char : 1; + unsigned char b : 4; +}; + +// LINUX-LABEL: define dso_local void @testUnnamedBitfieldSingleBit( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -9 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @testUnnamedBitfieldSingleBit( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -9 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldSingleBit(struct UnnamedBitfieldSingleBit *s) { + // byte 0: a[bits 0-2], unnamed[bit 3], b[bits 4-7] + // bit 3 must be cleared + // Mask: 0b11110111 == -9 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldMiddle { + unsigned char a : 3; + unsigned char : 2; + unsigned char b : 3; +}; + +// LINUX-LABEL: define dso_local void @testUnnamedBitfieldMiddle( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -25 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @testUnnamedBitfieldMiddle( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -25 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldMiddle(struct UnnamedBitfieldMiddle *s) { + // byte 0: a[0-2], unnamed[3-4], b[5-7] + // bits 3-4 must be cleared + // Mask: 0b11100111 == -25 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldSurrounding { + unsigned char : 2; + unsigned char a : 4; + unsigned char : 2; +}; + +// LINUX-LABEL: define dso_local void @testUnnamedBitfieldSurrounding( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -4 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 +// LINUX-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @testUnnamedBitfieldSurrounding( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -4 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 +// WINDOWS-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldSurrounding(struct UnnamedBitfieldSurrounding *s) { + // byte 0: unnamed[0-1], a[2-5], unnamed[6-7] + // bits 0-1 and 6-7 must be cleared + // Masks: + // 0b11111100 == -4 + // 0b00111111 == 63 + __builtin_clear_padding(s); +} + +struct UnnamedZeroWidthBitfield { + unsigned char a : 4; + unsigned int : 0; + unsigned int b : 4; +}; + +// LINUX-LABEL: define dso_local void @testUnnamedZeroWidthBitfield( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// LINUX-NEXT: store i8 0, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// LINUX-NEXT: store i8 0, ptr [[TMP5]], align 2 +// LINUX-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// LINUX-NEXT: store i8 0, ptr [[TMP6]], align 1 +// LINUX-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 4 +// LINUX-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 4 +// LINUX-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 +// LINUX-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 4 +// LINUX-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 5 +// LINUX-NEXT: store i8 0, ptr [[TMP10]], align 1 +// LINUX-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[TMP0]], i32 6 +// LINUX-NEXT: store i8 0, ptr [[TMP11]], align 2 +// LINUX-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 7 +// LINUX-NEXT: store i8 0, ptr [[TMP12]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @testUnnamedZeroWidthBitfield( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// WINDOWS-NEXT: store i8 0, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// WINDOWS-NEXT: store i8 0, ptr [[TMP5]], align 2 +// WINDOWS-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// WINDOWS-NEXT: store i8 0, ptr [[TMP6]], align 1 +// WINDOWS-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 4 +// WINDOWS-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 4 +// WINDOWS-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 +// WINDOWS-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 4 +// WINDOWS-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 5 +// WINDOWS-NEXT: store i8 0, ptr [[TMP10]], align 1 +// WINDOWS-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[TMP0]], i32 6 +// WINDOWS-NEXT: store i8 0, ptr [[TMP11]], align 2 +// WINDOWS-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 7 +// WINDOWS-NEXT: store i8 0, ptr [[TMP12]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedZeroWidthBitfield(struct UnnamedZeroWidthBitfield *s) { + // byte 0: a[0-3], unnamed[4-7] + // bytes 1-3: struct padding + // bytes 4-7: b[bits 0-3], tail padding[bits 4-31] + // + // byte 0: clear bits 4-7 + // mask: 0b00001111 == 15 + // + // byte 1-3: clear all bits + // 3 x store i8 0 + // + // byte 4-7: clear bits 4-31 + // mask: 0b00001111 == 15 + // 3 x store i8 0 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldMultiByte { + unsigned short a : 4; + unsigned short : 8; + unsigned short b : 4; +}; + +// LINUX-LABEL: define dso_local void @testUnnamedBitfieldMultiByte( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 2 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 2 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// LINUX-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -16 +// LINUX-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @testUnnamedBitfieldMultiByte( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 2 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 2 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// WINDOWS-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -16 +// WINDOWS-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldMultiByte(struct UnnamedBitfieldMultiByte *s) { + // 2 bytes: a[0-3], unnamed[4-11], b[12-15] + // byte 0: clear bits 4-7 + // byte 1: clear bits 0-3 + // + // Masks: + // 0b00001111 == 15 + // 0b11110000 == -16 + __builtin_clear_padding(s); +} diff --git a/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp b/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp index 05ea1265e75db..0705cc374ff09 100644 --- a/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp +++ b/clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp @@ -1519,3 +1519,252 @@ void testAttributedLongDoubleType(LongDouble3Vec *v) { // long double elements occupy [0-9], [16-25], [32-41] on x86. __builtin_clear_padding(v); } + +struct UnnamedBitfieldSingleBit { + unsigned char a : 3; + unsigned char : 1; + unsigned char b : 4; +}; + +// LINUX-LABEL: define dso_local void @_Z28testUnnamedBitfieldSingleBitP24UnnamedBitfieldSingleBit( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -9 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @_Z28testUnnamedBitfieldSingleBitP24UnnamedBitfieldSingleBit( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -9 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldSingleBit(struct UnnamedBitfieldSingleBit *s) { + // byte 0: a[bits 0-2], unnamed[bit 3], b[bits 4-7] + // bit 3 must be cleared + // Mask: 0b11110111 == -9 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldMiddle { + unsigned char a : 3; + unsigned char : 2; + unsigned char b : 3; +}; + +// LINUX-LABEL: define dso_local void @_Z25testUnnamedBitfieldMiddleP21UnnamedBitfieldMiddle( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -25 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @_Z25testUnnamedBitfieldMiddleP21UnnamedBitfieldMiddle( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -25 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldMiddle(struct UnnamedBitfieldMiddle *s) { + // byte 0: a[0-2], unnamed[3-4], b[5-7] + // bits 3-4 must be cleared + // Mask: 0b11100111 == -25 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldSurrounding { + unsigned char : 2; + unsigned char a : 4; + unsigned char : 2; +}; + +// LINUX-LABEL: define dso_local void @_Z30testUnnamedBitfieldSurroundingP26UnnamedBitfieldSurrounding( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -4 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 +// LINUX-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @_Z30testUnnamedBitfieldSurroundingP26UnnamedBitfieldSurrounding( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], -4 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 1 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 63 +// WINDOWS-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldSurrounding(struct UnnamedBitfieldSurrounding *s) { + // byte 0: unnamed[0-1], a[2-5], unnamed[6-7] + // bits 0-1 and 6-7 must be cleared + // Masks: + // 0b11111100 == -4 + // 0b00111111 == 63 + __builtin_clear_padding(s); +} + +struct UnnamedZeroWidthBitfield { + unsigned char a : 4; + unsigned int : 0; + unsigned int b : 4; +}; + +// LINUX-LABEL: define dso_local void @_Z28testUnnamedZeroWidthBitfieldP24UnnamedZeroWidthBitfield( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// LINUX-NEXT: store i8 0, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// LINUX-NEXT: store i8 0, ptr [[TMP5]], align 2 +// LINUX-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// LINUX-NEXT: store i8 0, ptr [[TMP6]], align 1 +// LINUX-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 4 +// LINUX-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 4 +// LINUX-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 +// LINUX-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 4 +// LINUX-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 5 +// LINUX-NEXT: store i8 0, ptr [[TMP10]], align 1 +// LINUX-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[TMP0]], i32 6 +// LINUX-NEXT: store i8 0, ptr [[TMP11]], align 2 +// LINUX-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 7 +// LINUX-NEXT: store i8 0, ptr [[TMP12]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @_Z28testUnnamedZeroWidthBitfieldP24UnnamedZeroWidthBitfield( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 4 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 4 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// WINDOWS-NEXT: store i8 0, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[TMP0]], i32 2 +// WINDOWS-NEXT: store i8 0, ptr [[TMP5]], align 2 +// WINDOWS-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr [[TMP0]], i32 3 +// WINDOWS-NEXT: store i8 0, ptr [[TMP6]], align 1 +// WINDOWS-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr [[TMP0]], i32 4 +// WINDOWS-NEXT: [[TMP8:%.*]] = load i8, ptr [[TMP7]], align 4 +// WINDOWS-NEXT: [[TMP9:%.*]] = and i8 [[TMP8]], 15 +// WINDOWS-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 4 +// WINDOWS-NEXT: [[TMP10:%.*]] = getelementptr i8, ptr [[TMP0]], i32 5 +// WINDOWS-NEXT: store i8 0, ptr [[TMP10]], align 1 +// WINDOWS-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[TMP0]], i32 6 +// WINDOWS-NEXT: store i8 0, ptr [[TMP11]], align 2 +// WINDOWS-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP0]], i32 7 +// WINDOWS-NEXT: store i8 0, ptr [[TMP12]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedZeroWidthBitfield(struct UnnamedZeroWidthBitfield *s) { + // byte 0: a[0-3], unnamed[4-7] + // bytes 1-3: struct padding + // bytes 4-7: b[bits 0-3], tail padding[bits 4-31] + // + // byte 0: clear bits 4-7 + // mask: 0b00001111 == 15 + // + // byte 1-3: clear all bits + // 3 x store i8 0 + // + // byte 4-7: clear bits 4-31 + // mask: 0b00001111 == 15 + // 3 x store i8 0 + __builtin_clear_padding(s); +} + +struct UnnamedBitfieldMultiByte { + unsigned short a : 4; + unsigned short : 8; + unsigned short b : 4; +}; + +// LINUX-LABEL: define dso_local void @_Z28testUnnamedBitfieldMultiByteP24UnnamedBitfieldMultiByte( +// LINUX-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// LINUX-NEXT: [[ENTRY:.*:]] +// LINUX-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// LINUX-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// LINUX-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// LINUX-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 2 +// LINUX-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// LINUX-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 2 +// LINUX-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// LINUX-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// LINUX-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -16 +// LINUX-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// LINUX-NEXT: ret void +// +// WINDOWS-LABEL: define dso_local void @_Z28testUnnamedBitfieldMultiByteP24UnnamedBitfieldMultiByte( +// WINDOWS-SAME: ptr noundef [[S:%.*]]) #[[ATTR0]] { +// WINDOWS-NEXT: [[ENTRY:.*:]] +// WINDOWS-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8 +// WINDOWS-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8 +// WINDOWS-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i32 0 +// WINDOWS-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 2 +// WINDOWS-NEXT: [[TMP3:%.*]] = and i8 [[TMP2]], 15 +// WINDOWS-NEXT: store i8 [[TMP3]], ptr [[TMP1]], align 2 +// WINDOWS-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP0]], i32 1 +// WINDOWS-NEXT: [[TMP5:%.*]] = load i8, ptr [[TMP4]], align 1 +// WINDOWS-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], -16 +// WINDOWS-NEXT: store i8 [[TMP6]], ptr [[TMP4]], align 1 +// WINDOWS-NEXT: ret void +// +void testUnnamedBitfieldMultiByte(struct UnnamedBitfieldMultiByte *s) { + // 2 bytes: a[0-3], unnamed[4-11], b[12-15] + // byte 0: clear bits 4-7 + // byte 1: clear bits 0-3 + // + // Masks: + // 0b00001111 == 15 + // 0b11110000 == -16 + __builtin_clear_padding(s); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
