1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H
#define LLVM_CLANG_LIB_CIR_CIRGENRECORDLAYOUT_H
#include "clang/AST/Decl.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
namespace clang::CIRGen {
/// Record with information about how a bitfield should be accessed. This is
/// very similar to what LLVM codegen does, once CIR evolves it's possible we
/// can use a more higher level representation.
///
/// Often we lay out a sequence of bitfields as a contiguous sequence of bits.
/// When the AST record layout does this, we represent it in CIR as a
/// `!cir.record` type, which directly reflects the structure's layout,
/// including bitfield packing and padding, using CIR types such as
/// `!cir.bool`, `!s8i`, `!u16i`.
///
/// To access a particular bitfield in CIR, we use the operations
/// `cir.get_bitfield` (`GetBitfieldOp`) or `cir.set_bitfield`
/// (`SetBitfieldOp`). These operations rely on the `bitfield_info`
/// attribute, which provides detailed metadata required for access,
/// such as the size and offset of the bitfield, the type and size of
/// the underlying storage, and whether the value is signed.
/// The CIRGenRecordLayout also has a bitFields map which encodes which
/// byte-sequence this bitfield falls within. Let's assume the following C
/// struct:
///
/// struct S {
/// char a, b, c;
/// unsigned bits : 3;
/// unsigned more_bits : 4;
/// unsigned still_more_bits : 7;
/// };
///
/// This will end up as the following cir.record. The bitfield members are
/// represented by one !u16i value, and the array provides padding to align the
/// struct to a 4-byte alignment.
///
/// !rec_S = !cir.record<struct "S" padded {!s8i, !s8i, !s8i, !u16i,
/// !cir.array<!u8i x 3>}>
///
/// When generating code to access more_bits, we'll generate something
/// essentially like this:
///
/// #bfi_more_bits = #cir.bitfield_info<name = "more_bits", storage_type =
/// !u16i, size = 4, offset = 3, is_signed = false>
///
/// cir.func @store_field() {
/// %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s"] {alignment = 4 : i64}
/// %1 = cir.const #cir.int<2> : !s32i
/// %2 = cir.cast(integral, %1 : !s32i), !u32i
/// %3 = cir.get_member %0[3] {name = "more_bits"} : !cir.ptr<!rec_S> ->
/// !cir.ptr<!u16i>
/// %4 = cir.set_bitfield(#bfi_more_bits, %3 :
/// !cir.ptr<!u16i>, %2 : !u32i) -> !u32i
/// cir.return
/// }
///
struct CIRGenBitFieldInfo {
/// The offset within a contiguous run of bitfields that are represented as
/// a single "field" within the cir.record type. This offset is in bits.
unsigned offset : 16;
/// The total size of the bit-field, in bits.
unsigned size : 15;
/// Whether the bit-field is signed.
unsigned isSigned : 1;
/// The storage size in bits which should be used when accessing this
/// bitfield.
unsigned storageSize;
/// The offset of the bitfield storage from the start of the record.
clang::CharUnits storageOffset;
/// The offset within a contiguous run of bitfields that are represented as a
/// single "field" within the cir.record type, taking into account the AAPCS
/// rules for volatile bitfields. This offset is in bits.
unsigned volatileOffset : 16;
/// The storage size in bits which should be used when accessing this
/// bitfield.
unsigned volatileStorageSize;
/// The offset of the bitfield storage from the start of the record.
clang::CharUnits volatileStorageOffset;
/// The name of a bitfield
llvm::StringRef name;
// The actual storage type for the bitfield
mlir::Type storageType;
CIRGenBitFieldInfo()
: offset(), size(), isSigned(), storageSize(), volatileOffset(),
volatileStorageSize() {}
CIRGenBitFieldInfo(unsigned offset, unsigned size, bool isSigned,
unsigned storageSize, clang::CharUnits storageOffset)
: offset(offset), size(size), isSigned(isSigned),
storageSize(storageSize), storageOffset(storageOffset) {}
void print(llvm::raw_ostream &os) const;
LLVM_DUMP_METHOD void dump() const;
};
/// This class handles record and union layout info while lowering AST types
/// to CIR types.
///
/// These layout objects are only created on demand as CIR generation requires.
class CIRGenRecordLayout {
friend class CIRGenTypes;
CIRGenRecordLayout(const CIRGenRecordLayout &) = delete;
void operator=(const CIRGenRecordLayout &) = delete;
private:
/// The CIR type corresponding to this record layout; used when laying it out
/// as a complete object.
cir::RecordType completeObjectType;
/// The CIR type for the non-virtual part of this record layout; used when
/// laying it out as a base subobject.
cir::RecordType baseSubobjectType;
/// Map from (non-bit-field) record field to the corresponding cir record type
/// field no. This info is populated by the record builder.
llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldIdxMap;
// FIXME: Maybe we could use CXXBaseSpecifier as the key and use a single map
// for both virtual and non-virtual bases.
llvm::DenseMap<const clang::CXXRecordDecl *, unsigned> nonVirtualBases;
/// Map from virtual bases to their field index in the complete object.
llvm::DenseMap<const clang::CXXRecordDecl *, unsigned>
completeObjectVirtualBases;
/// Map from (bit-field) record field to the corresponding CIR record type
/// field no. This info is populated by record builder.
llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo> bitFields;
/// False if any direct or indirect subobject of this class, when considered
/// as a complete object, requires a non-zero bitpattern when
/// zero-initialized.
LLVM_PREFERRED_TYPE(bool)
unsigned zeroInitializable : 1;
/// False if any direct or indirect subobject of this class, when considered
/// as a base subobject, requires a non-zero bitpattern when zero-initialized.
LLVM_PREFERRED_TYPE(bool)
unsigned zeroInitializableAsBase : 1;
public:
CIRGenRecordLayout(cir::RecordType completeObjectType,
cir::RecordType baseSubobjectType, bool zeroInitializable,
bool zeroInitializableAsBase)
: completeObjectType(completeObjectType),
baseSubobjectType(baseSubobjectType),
zeroInitializable(zeroInitializable),
zeroInitializableAsBase(zeroInitializableAsBase) {}
/// Return the "complete object" LLVM type associated with
/// this record.
cir::RecordType getCIRType() const { return completeObjectType; }
/// Return the "base subobject" LLVM type associated with
/// this record.
cir::RecordType getBaseSubobjectCIRType() const { return baseSubobjectType; }
/// Return cir::RecordType element number that corresponds to the field FD.
unsigned getCIRFieldNo(const clang::FieldDecl *fd) const {
fd = fd->getCanonicalDecl();
assert(fieldIdxMap.count(fd) && "Invalid field for record!");
return fieldIdxMap.lookup(fd);
}
/// Check whether this struct can be C++ zero-initialized
/// with a zeroinitializer.
bool isZeroInitializable() const { return zeroInitializable; }
/// Check whether this struct can be C++ zero-initialized
/// with a zeroinitializer when considered as a base subobject.
bool isZeroInitializableAsBase() const { return zeroInitializableAsBase; }
/// Return the BitFieldInfo that corresponds to the field FD.
const CIRGenBitFieldInfo &getBitFieldInfo(const clang::FieldDecl *fd) const {
fd = fd->getCanonicalDecl();
assert(fd->isBitField() && "Invalid call for non-bit-field decl!");
llvm::DenseMap<const clang::FieldDecl *, CIRGenBitFieldInfo>::const_iterator
it = bitFields.find(fd);
assert(it != bitFields.end() && "Unable to find bitfield info");
return it->second;
}
void print(raw_ostream &os) const;
LLVM_DUMP_METHOD void dump() const;
};
} // namespace clang::CIRGen
#endif
|