Skip to content

Commit ba35004

Browse files
[CIR] Add support for discrete bit-field ABI (#1860)
This PR adds support for the **discrete bit-field layout**, which is used in the Microsoft bit-field ABI. Since ClangIR does not currently support the Microsoft ABI, this uses the compiler flag ```bash -mms-bitfields Set the default structure layout to be compatible with the Microsoft compiler standard ``` Fixes #1798
1 parent 9b5498a commit ba35004

File tree

3 files changed

+116
-2
lines changed

3 files changed

+116
-2
lines changed

clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ class CIRDataLayout {
9595
return llvm::alignTo(getTypeStoreSize(Ty), getABITypeAlign(Ty).value());
9696
}
9797

98+
/// Returns the offset in bits between successive objects of the
99+
/// specified type, including alignment padding; always a multiple of 8.
100+
///
101+
/// If Ty is a scalable vector type, the scalable property will be set and
102+
/// the runtime size will be a positive integer multiple of the base size.
103+
///
104+
/// This is the amount that alloca reserves for this type. For example,
105+
/// returns 96 or 128 for x86_fp80, depending on alignment.
106+
llvm::TypeSize getTypeAllocSizeInBits(mlir::Type ty) const {
107+
return 8 * getTypeAllocSize(ty);
108+
}
109+
98110
llvm::TypeSize getPointerTypeSizeInBits(mlir::Type Ty) const {
99111
assert(mlir::isa<cir::PointerType>(Ty) &&
100112
"This should only be called with a pointer type");

clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,44 @@ RecordDecl::field_iterator
513513
CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
514514
RecordDecl::field_iterator FieldEnd) {
515515

516-
if (isDiscreteBitFieldABI())
517-
llvm_unreachable("NYI");
516+
if (isDiscreteBitFieldABI()) {
517+
// run stores the first element of the current run of bitfields. FieldEnd is
518+
// used as a special value to note that we don't have a current run. A
519+
// bitfield run is a contiguous collection of bitfields that can be stored
520+
// in the same storage block. Zero-sized bitfields and bitfields that would
521+
// cross an alignment boundary break a run and start a new one.
522+
RecordDecl::field_iterator run = FieldEnd;
523+
// tail is the offset of the first bit off the end of the current run. It's
524+
// used to determine if the ASTRecordLayout is treating these two bitfields
525+
// as contiguous. StartBitOffset is offset of the beginning of the Run.
526+
uint64_t startBitOffset, tail = 0;
527+
for (; Field != FieldEnd && Field->isBitField(); ++Field) {
528+
// Zero-width bitfields end runs.
529+
if (Field->isZeroLengthBitField()) {
530+
run = FieldEnd;
531+
continue;
532+
}
533+
uint64_t bitOffset = getFieldBitOffset(*Field);
534+
mlir::Type type = cirGenTypes.convertTypeForMem(Field->getType());
535+
// If we don't have a run yet, or don't live within the previous run's
536+
// allocated storage then we allocate some storage and start a new run.
537+
if (run == FieldEnd || bitOffset >= tail) {
538+
run = Field;
539+
startBitOffset = bitOffset;
540+
tail = startBitOffset + dataLayout.getTypeAllocSizeInBits(type);
541+
// Add the storage member to the record. This must be added to the
542+
// record before the bitfield members so that it gets laid out before
543+
// the bitfields it contains get laid out.
544+
members.push_back(StorageInfo(bitsToCharUnits(startBitOffset), type));
545+
}
546+
// Bitfields get the offset of their storage but come afterward and remain
547+
// there after a stable sort.
548+
members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),
549+
MemberInfo::InfoKind::Field, nullptr,
550+
*Field));
551+
}
552+
return Field;
553+
}
518554

519555
CharUnits RegSize =
520556
bitsToCharUnits(astContext.getTargetInfo().getRegisterWidth());
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
7+
8+
struct s1 {
9+
int f32 : 2;
10+
long long f64 : 30;
11+
} s1;
12+
13+
// CIR-DAG: !rec_s1 = !cir.record<struct "s1" {!s32i, !s64i} #cir.record.decl.ast>
14+
// LLVM-DAG: %struct.s1 = type { i32, i64 }
15+
// OGCG-DAG: %struct.s1 = type { i32, i64 }
16+
17+
struct s2 {
18+
int a : 24;
19+
char b;
20+
int c : 30;
21+
} Clip;
22+
23+
// CIR-DAG: !rec_s2 = !cir.record<struct "s2" {!s32i, !s8i, !s32i} #cir.record.decl.ast>
24+
// LLVM-DAG: %struct.s2 = type { i32, i8, i32 }
25+
// OGCG-DAG: %struct.s2 = type { i32, i8, i32 }
26+
27+
#pragma pack (push,1)
28+
29+
struct Inner {
30+
unsigned int A : 1;
31+
unsigned int B : 1;
32+
unsigned int C : 1;
33+
unsigned int D : 30;
34+
} Inner;
35+
36+
#pragma pack (pop)
37+
38+
// CIR-DAG: !rec_Inner = !cir.record<struct "Inner" {!u32i, !u32i} #cir.record.decl.ast>
39+
// LLVM-DAG: %struct.Inner = type { i32, i32 }
40+
// OGCG-DAG: %struct.Inner = type { i32, i32 }
41+
42+
#pragma pack(push, 1)
43+
44+
union HEADER {
45+
struct A {
46+
int : 3; // Bits 2:0
47+
int a : 9; // Bits 11:3
48+
int : 12; // Bits 23:12
49+
int b : 17; // Bits 40:24
50+
int : 7; // Bits 47:41
51+
int c : 4; // Bits 51:48
52+
int : 4; // Bits 55:52
53+
int d : 3; // Bits 58:56
54+
int : 5; // Bits 63:59
55+
} Bits;
56+
} HEADER;
57+
58+
#pragma pack(pop)
59+
60+
// CIR-DAG: !rec_A = !cir.record<struct "A" {!s32i, !s32i, !s32i} #cir.record.decl.ast>
61+
// CIR-DAG: !rec_HEADER = !cir.record<union "HEADER" {!rec_A} #cir.record.decl.ast>
62+
// LLVM-DAG: %struct.A = type { i32, i32, i32 }
63+
// LLVM-DAG: %union.HEADER = type { %struct.A }
64+
// OGCG-DAG: %struct.A = type { i32, i32, i32 }
65+
// OGCG-DAG: %union.HEADER = type { %struct.A }
66+

0 commit comments

Comments
 (0)