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

source code of clang/lib/CIR/CodeGen/CIRGenRecordLayout.h