@@ -67,8 +67,13 @@ struct ConstantAggregateBuilderUtils {
67
67
return getSize (C.getType ());
68
68
}
69
69
70
- mlir::Attribute getPadding (CharUnits PadSize) const {
71
- llvm_unreachable (" NYI" );
70
+ mlir::TypedAttr getPadding (CharUnits size) const {
71
+ auto eltTy = CGM.UCharTy ;
72
+ auto arSize = size.getQuantity ();
73
+ auto &bld = CGM.getBuilder ();
74
+ SmallVector<mlir::Attribute, 4 > elts (arSize, bld.getZeroAttr (eltTy));
75
+ return bld.getConstArray (mlir::ArrayAttr::get (bld.getContext (), elts),
76
+ bld.getArrayType (eltTy, arSize));
72
77
}
73
78
74
79
mlir::Attribute getZeroes (CharUnits ZeroSize) const {
@@ -186,7 +191,111 @@ bool ConstantAggregateBuilder::add(mlir::Attribute A, CharUnits Offset,
186
191
187
192
bool ConstantAggregateBuilder::addBits (llvm::APInt Bits, uint64_t OffsetInBits,
188
193
bool AllowOverwrite) {
189
- llvm_unreachable (" NYI" );
194
+ const ASTContext &Context = CGM.getASTContext ();
195
+ const uint64_t CharWidth = CGM.getASTContext ().getCharWidth ();
196
+ auto charTy = CGM.getBuilder ().getUIntNTy (CharWidth);
197
+ // Offset of where we want the first bit to go within the bits of the
198
+ // current char.
199
+ unsigned OffsetWithinChar = OffsetInBits % CharWidth;
200
+
201
+ // We split bit-fields up into individual bytes. Walk over the bytes and
202
+ // update them.
203
+ for (CharUnits OffsetInChars =
204
+ Context.toCharUnitsFromBits (OffsetInBits - OffsetWithinChar);
205
+ /* */ ; ++OffsetInChars) {
206
+ // Number of bits we want to fill in this char.
207
+ unsigned WantedBits =
208
+ std::min ((uint64_t )Bits.getBitWidth (), CharWidth - OffsetWithinChar);
209
+
210
+ // Get a char containing the bits we want in the right places. The other
211
+ // bits have unspecified values.
212
+ llvm::APInt BitsThisChar = Bits;
213
+ if (BitsThisChar.getBitWidth () < CharWidth)
214
+ BitsThisChar = BitsThisChar.zext (CharWidth);
215
+ if (CGM.getDataLayout ().isBigEndian ()) {
216
+ // Figure out how much to shift by. We may need to left-shift if we have
217
+ // less than one byte of Bits left.
218
+ int Shift = Bits.getBitWidth () - CharWidth + OffsetWithinChar;
219
+ if (Shift > 0 )
220
+ BitsThisChar.lshrInPlace (Shift);
221
+ else if (Shift < 0 )
222
+ BitsThisChar = BitsThisChar.shl (-Shift);
223
+ } else {
224
+ BitsThisChar = BitsThisChar.shl (OffsetWithinChar);
225
+ }
226
+ if (BitsThisChar.getBitWidth () > CharWidth)
227
+ BitsThisChar = BitsThisChar.trunc (CharWidth);
228
+
229
+ if (WantedBits == CharWidth) {
230
+ // Got a full byte: just add it directly.
231
+ add (mlir::cir::IntAttr::get (charTy, BitsThisChar), OffsetInChars,
232
+ AllowOverwrite);
233
+ } else {
234
+ // Partial byte: update the existing integer if there is one. If we
235
+ // can't split out a 1-CharUnit range to update, then we can't add
236
+ // these bits and fail the entire constant emission.
237
+ std::optional<size_t > FirstElemToUpdate = splitAt (OffsetInChars);
238
+ if (!FirstElemToUpdate)
239
+ return false ;
240
+ std::optional<size_t > LastElemToUpdate =
241
+ splitAt (OffsetInChars + CharUnits::One ());
242
+ if (!LastElemToUpdate)
243
+ return false ;
244
+ assert (*LastElemToUpdate - *FirstElemToUpdate < 2 &&
245
+ " should have at most one element covering one byte" );
246
+
247
+ // Figure out which bits we want and discard the rest.
248
+ llvm::APInt UpdateMask (CharWidth, 0 );
249
+ if (CGM.getDataLayout ().isBigEndian ())
250
+ UpdateMask.setBits (CharWidth - OffsetWithinChar - WantedBits,
251
+ CharWidth - OffsetWithinChar);
252
+ else
253
+ UpdateMask.setBits (OffsetWithinChar, OffsetWithinChar + WantedBits);
254
+ BitsThisChar &= UpdateMask;
255
+ bool isNull = false ;
256
+ if (*FirstElemToUpdate < Elems.size ()) {
257
+ auto firstEltToUpdate =
258
+ dyn_cast<mlir::cir::IntAttr>(Elems[*FirstElemToUpdate]);
259
+ isNull = firstEltToUpdate && firstEltToUpdate.isNullValue ();
260
+ }
261
+
262
+ if (*FirstElemToUpdate == *LastElemToUpdate || isNull) {
263
+ // All existing bits are either zero or undef.
264
+ add (CGM.getBuilder ().getAttr <mlir::cir::IntAttr>(charTy, BitsThisChar),
265
+ OffsetInChars, /* AllowOverwrite*/ true );
266
+ } else {
267
+ mlir::cir::IntAttr CI =
268
+ dyn_cast<mlir::cir::IntAttr>(Elems[*FirstElemToUpdate]);
269
+ // In order to perform a partial update, we need the existing bitwise
270
+ // value, which we can only extract for a constant int.
271
+ // auto *CI = dyn_cast<llvm::ConstantInt>(ToUpdate);
272
+ if (!CI)
273
+ return false ;
274
+ // Because this is a 1-CharUnit range, the constant occupying it must
275
+ // be exactly one CharUnit wide.
276
+ assert (CI.getBitWidth () == CharWidth && " splitAt failed" );
277
+ assert ((!(CI.getValue () & UpdateMask) || AllowOverwrite) &&
278
+ " unexpectedly overwriting bitfield" );
279
+ BitsThisChar |= (CI.getValue () & ~UpdateMask);
280
+ Elems[*FirstElemToUpdate] =
281
+ CGM.getBuilder ().getAttr <mlir::cir::IntAttr>(charTy, BitsThisChar);
282
+ }
283
+ }
284
+
285
+ // Stop if we've added all the bits.
286
+ if (WantedBits == Bits.getBitWidth ())
287
+ break ;
288
+
289
+ // Remove the consumed bits from Bits.
290
+ if (!CGM.getDataLayout ().isBigEndian ())
291
+ Bits.lshrInPlace (WantedBits);
292
+ Bits = Bits.trunc (Bits.getBitWidth () - WantedBits);
293
+
294
+ // The remanining bits go at the start of the following bytes.
295
+ OffsetWithinChar = 0 ;
296
+ }
297
+
298
+ return true ;
190
299
}
191
300
192
301
// / Returns a position within Elems and Offsets such that all elements
@@ -236,6 +345,7 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
236
345
237
346
if (Elems.empty ())
238
347
return {};
348
+ auto Offset = [&](size_t I) { return Offsets[I] - StartOffset; };
239
349
240
350
// If we want an array type, see if all the elements are the same type and
241
351
// appropriately spaced.
@@ -276,14 +386,44 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom(
276
386
// as a non-packed struct and do so opportunistically if possible.
277
387
llvm::SmallVector<mlir::Attribute, 32 > PackedElems;
278
388
if (!NaturalLayout) {
279
- llvm_unreachable (" NYI" );
389
+ CharUnits SizeSoFar = CharUnits::Zero ();
390
+ for (size_t I = 0 ; I != Elems.size (); ++I) {
391
+ mlir::TypedAttr C = Elems[I].dyn_cast <mlir::TypedAttr>();
392
+ assert (C && " expected typed attribute" );
393
+
394
+ CharUnits Align = Utils.getAlignment (C);
395
+ CharUnits NaturalOffset = SizeSoFar.alignTo (Align);
396
+ CharUnits DesiredOffset = Offset (I);
397
+ assert (DesiredOffset >= SizeSoFar && " elements out of order" );
398
+
399
+ if (DesiredOffset != NaturalOffset)
400
+ Packed = true ;
401
+ if (DesiredOffset != SizeSoFar)
402
+ PackedElems.push_back (Utils.getPadding (DesiredOffset - SizeSoFar));
403
+ PackedElems.push_back (Elems[I]);
404
+ SizeSoFar = DesiredOffset + Utils.getSize (C);
405
+ }
406
+ // If we're using the packed layout, pad it out to the desired size if
407
+ // necessary.
408
+ if (Packed) {
409
+ assert (SizeSoFar <= DesiredSize &&
410
+ " requested size is too small for contents" );
411
+
412
+ if (SizeSoFar < DesiredSize)
413
+ PackedElems.push_back (Utils.getPadding (DesiredSize - SizeSoFar));
414
+ }
280
415
}
281
416
282
- // TODO(cir): emit a #cir.zero if all elements are null values.
283
417
auto &builder = CGM.getBuilder ();
284
418
auto arrAttr = mlir::ArrayAttr::get (builder.getContext (),
285
419
Packed ? PackedElems : UnpackedElems);
286
- return builder.getConstStructOrZeroAttr (arrAttr, Packed, DesiredTy);
420
+ auto strType = builder.getCompleteStructType (arrAttr, Packed);
421
+
422
+ if (auto desired = dyn_cast<mlir::cir::StructType>(DesiredTy))
423
+ if (desired.isLayoutIdentical (strType))
424
+ strType = desired;
425
+
426
+ return builder.getConstStructOrZeroAttr (arrAttr, Packed, strType);
287
427
}
288
428
289
429
void ConstantAggregateBuilder::condense (CharUnits Offset,
@@ -353,7 +493,7 @@ class ConstStructBuilder {
353
493
bool AllowOverwrite = false );
354
494
355
495
bool AppendBitField (const FieldDecl *Field, uint64_t FieldOffset,
356
- mlir::IntegerAttr InitExpr, bool AllowOverwrite = false );
496
+ mlir::cir::IntAttr InitExpr, bool AllowOverwrite = false );
357
497
358
498
bool Build (InitListExpr *ILE, bool AllowOverwrite);
359
499
bool Build (const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
@@ -380,9 +520,26 @@ bool ConstStructBuilder::AppendBytes(CharUnits FieldOffsetInChars,
380
520
381
521
bool ConstStructBuilder::AppendBitField (const FieldDecl *Field,
382
522
uint64_t FieldOffset,
383
- mlir::IntegerAttr CI,
523
+ mlir::cir::IntAttr CI,
384
524
bool AllowOverwrite) {
385
- llvm_unreachable (" NYI" );
525
+ const auto &RL = CGM.getTypes ().getCIRGenRecordLayout (Field->getParent ());
526
+ const auto &Info = RL.getBitFieldInfo (Field);
527
+ llvm::APInt FieldValue = CI.getValue ();
528
+
529
+ // Promote the size of FieldValue if necessary
530
+ // FIXME: This should never occur, but currently it can because initializer
531
+ // constants are cast to bool, and because clang is not enforcing bitfield
532
+ // width limits.
533
+ if (Info.Size > FieldValue.getBitWidth ())
534
+ FieldValue = FieldValue.zext (Info.Size );
535
+
536
+ // Truncate the size of FieldValue to the bit field size.
537
+ if (Info.Size < FieldValue.getBitWidth ())
538
+ FieldValue = FieldValue.trunc (Info.Size );
539
+
540
+ return Builder.addBits (FieldValue,
541
+ CGM.getASTContext ().toBits (StartOffset) + FieldOffset,
542
+ AllowOverwrite);
386
543
}
387
544
388
545
static bool EmitDesignatedInitUpdater (ConstantEmitter &Emitter,
@@ -513,7 +670,16 @@ bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) {
513
670
if (Field->hasAttr <NoUniqueAddressAttr>())
514
671
AllowOverwrite = true ;
515
672
} else {
516
- llvm_unreachable (" NYI" );
673
+ // Otherwise we have a bitfield.
674
+ if (auto constInt = dyn_cast<mlir::cir::IntAttr>(EltInit)) {
675
+ if (!AppendBitField (Field, Layout.getFieldOffset (FieldNo), constInt,
676
+ AllowOverwrite))
677
+ return false ;
678
+ } else {
679
+ // We are trying to initialize a bitfield with a non-trivial constant,
680
+ // this must require run-time code.
681
+ return false ;
682
+ }
517
683
}
518
684
}
519
685
@@ -994,9 +1160,13 @@ buildArrayConstant(CIRGenModule &CGM, mlir::Type DesiredType,
994
1160
ArrayBound));
995
1161
}
996
1162
997
- // We have mixed types. Use a packed struct.
998
- assert (0 && " NYE" );
999
- return {};
1163
+ SmallVector<mlir::Attribute, 4 > Eles;
1164
+ Eles.reserve (Elements.size ());
1165
+ for (auto const &Element : Elements)
1166
+ Eles.push_back (Element);
1167
+
1168
+ auto arrAttr = mlir::ArrayAttr::get (builder.getContext (), Eles);
1169
+ return builder.getAnonConstStruct (arrAttr, false );
1000
1170
}
1001
1171
1002
1172
} // end anonymous namespace.
0 commit comments