@@ -56,14 +56,15 @@ struct CIRRecordLowering final {
56
56
};
57
57
// The constructor.
58
58
CIRRecordLowering (CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,
59
- bool isPacked );
59
+ bool packed );
60
60
61
61
// / Constructs a MemberInfo instance from an offset and mlir::Type.
62
62
MemberInfo makeStorageInfo (CharUnits offset, mlir::Type data) {
63
63
return MemberInfo (offset, MemberInfo::InfoKind::Field, data);
64
64
}
65
65
66
66
void lower ();
67
+ void lowerUnion ();
67
68
68
69
// / Determines if we need a packed llvm struct.
69
70
void determinePacked ();
@@ -83,6 +84,10 @@ struct CIRRecordLowering final {
83
84
return CharUnits::fromQuantity (dataLayout.layout .getTypeABIAlignment (Ty));
84
85
}
85
86
87
+ bool isZeroInitializable (const FieldDecl *fd) {
88
+ return cirGenTypes.isZeroInitializable (fd->getType ());
89
+ }
90
+
86
91
// / Wraps cir::IntType with some implicit arguments.
87
92
mlir::Type getUIntNType (uint64_t numBits) {
88
93
unsigned alignedBits = llvm::PowerOf2Ceil (numBits);
@@ -121,6 +126,13 @@ struct CIRRecordLowering final {
121
126
// / Fills out the structures that are ultimately consumed.
122
127
void fillOutputFields ();
123
128
129
+ void appendPaddingBytes (CharUnits size) {
130
+ if (!size.isZero ()) {
131
+ fieldTypes.push_back (getByteArrayType (size));
132
+ padded = true ;
133
+ }
134
+ }
135
+
124
136
CIRGenTypes &cirGenTypes;
125
137
CIRGenBuilderTy &builder;
126
138
const ASTContext &astContext;
@@ -130,12 +142,14 @@ struct CIRRecordLowering final {
130
142
std::vector<MemberInfo> members;
131
143
// Output fields, consumed by CIRGenTypes::computeRecordLayout
132
144
llvm::SmallVector<mlir::Type, 16 > fieldTypes;
133
- llvm::DenseMap<const FieldDecl *, unsigned > fields ;
145
+ llvm::DenseMap<const FieldDecl *, unsigned > fieldIdxMap ;
134
146
cir::CIRDataLayout dataLayout;
135
147
136
148
LLVM_PREFERRED_TYPE (bool )
137
149
unsigned zeroInitializable : 1 ;
138
150
LLVM_PREFERRED_TYPE (bool )
151
+ unsigned zeroInitializableAsBase : 1 ;
152
+ LLVM_PREFERRED_TYPE (bool )
139
153
unsigned packed : 1 ;
140
154
LLVM_PREFERRED_TYPE (bool )
141
155
unsigned padded : 1 ;
@@ -147,19 +161,19 @@ struct CIRRecordLowering final {
147
161
} // namespace
148
162
149
163
CIRRecordLowering::CIRRecordLowering (CIRGenTypes &cirGenTypes,
150
- const RecordDecl *recordDecl,
151
- bool isPacked)
164
+ const RecordDecl *recordDecl, bool packed)
152
165
: cirGenTypes(cirGenTypes), builder(cirGenTypes.getBuilder()),
153
166
astContext(cirGenTypes.getASTContext()), recordDecl(recordDecl),
154
167
astRecordLayout(
155
168
cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)),
156
169
dataLayout(cirGenTypes.getCGModule().getModule()),
157
- zeroInitializable(true ), packed(isPacked), padded(false ) {}
170
+ zeroInitializable(true ), zeroInitializableAsBase(true ), packed(packed),
171
+ padded(false ) {}
158
172
159
173
void CIRRecordLowering::lower () {
160
174
if (recordDecl->isUnion ()) {
161
- cirGenTypes. getCGModule (). errorNYI (recordDecl-> getSourceRange (),
162
- " lower: union " );
175
+ lowerUnion ();
176
+ assert (! cir::MissingFeatures::bitfields () );
163
177
return ;
164
178
}
165
179
@@ -194,7 +208,8 @@ void CIRRecordLowering::fillOutputFields() {
194
208
fieldTypes.push_back (member.data );
195
209
if (member.kind == MemberInfo::InfoKind::Field) {
196
210
if (member.fieldDecl )
197
- fields[member.fieldDecl ->getCanonicalDecl ()] = fieldTypes.size () - 1 ;
211
+ fieldIdxMap[member.fieldDecl ->getCanonicalDecl ()] =
212
+ fieldTypes.size () - 1 ;
198
213
// A field without storage must be a bitfield.
199
214
assert (!cir::MissingFeatures::bitfields ());
200
215
}
@@ -296,7 +311,7 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
296
311
assert (!cir::MissingFeatures::bitfields ());
297
312
298
313
// Add all the field numbers.
299
- rl->fieldInfo .swap (lowering.fields );
314
+ rl->fieldIdxMap .swap (lowering.fieldIdxMap );
300
315
301
316
// Dump the layout, if requested.
302
317
if (getASTContext ().getLangOpts ().DumpRecordLayouts ) {
@@ -306,3 +321,68 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
306
321
// TODO: implement verification
307
322
return rl;
308
323
}
324
+
325
+ void CIRRecordLowering::lowerUnion () {
326
+ CharUnits layoutSize = astRecordLayout.getSize ();
327
+ mlir::Type storageType = nullptr ;
328
+ bool seenNamedMember = false ;
329
+
330
+ // Iterate through the fields setting bitFieldInfo and the Fields array. Also
331
+ // locate the "most appropriate" storage type.
332
+ for (const FieldDecl *field : recordDecl->fields ()) {
333
+ mlir::Type fieldType;
334
+ if (field->isBitField ())
335
+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
336
+ " bitfields in lowerUnion" );
337
+ else
338
+ fieldType = getStorageType (field);
339
+
340
+ // This maps a field to its index. For unions, the index is always 0.
341
+ fieldIdxMap[field->getCanonicalDecl ()] = 0 ;
342
+
343
+ // Compute zero-initializable status.
344
+ // This union might not be zero initialized: it may contain a pointer to
345
+ // data member which might have some exotic initialization sequence.
346
+ // If this is the case, then we ought not to try and come up with a "better"
347
+ // type, it might not be very easy to come up with a Constant which
348
+ // correctly initializes it.
349
+ if (!seenNamedMember) {
350
+ seenNamedMember = field->getIdentifier ();
351
+ if (!seenNamedMember)
352
+ if (const RecordDecl *fieldRD = field->getType ()->getAsRecordDecl ())
353
+ seenNamedMember = fieldRD->findFirstNamedDataMember ();
354
+ if (seenNamedMember && !isZeroInitializable (field)) {
355
+ zeroInitializable = zeroInitializableAsBase = false ;
356
+ storageType = fieldType;
357
+ }
358
+ }
359
+
360
+ // Because our union isn't zero initializable, we won't be getting a better
361
+ // storage type.
362
+ if (!zeroInitializable)
363
+ continue ;
364
+
365
+ // Conditionally update our storage type if we've got a new "better" one.
366
+ if (!storageType || getAlignment (fieldType) > getAlignment (storageType) ||
367
+ (getAlignment (fieldType) == getAlignment (storageType) &&
368
+ getSize (fieldType) > getSize (storageType)))
369
+ storageType = fieldType;
370
+
371
+ // NOTE(cir): Track all union member's types, not just the largest one. It
372
+ // allows for proper type-checking and retain more info for analisys.
373
+ fieldTypes.push_back (fieldType);
374
+ }
375
+
376
+ if (!storageType)
377
+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
378
+ " No-storage Union NYI" );
379
+
380
+ if (layoutSize < getSize (storageType))
381
+ storageType = getByteArrayType (layoutSize);
382
+ else
383
+ appendPaddingBytes (layoutSize - getSize (storageType));
384
+
385
+ // Set packed if we need it.
386
+ if (layoutSize % getAlignment (storageType))
387
+ packed = true ;
388
+ }
0 commit comments