@@ -118,6 +118,9 @@ class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
118118 // / non-packed LLVM struct will give the correct layout.
119119 bool naturalLayout = true ;
120120
121+ bool split (size_t index, CharUnits hint);
122+ std::optional<size_t > splitAt (CharUnits pos);
123+
121124 static mlir::Attribute buildFrom (CIRGenModule &cgm, ArrayRef<Element> elems,
122125 CharUnits startOffset, CharUnits size,
123126 bool naturalLayout, mlir::Type desiredTy,
@@ -137,6 +140,10 @@ class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
137140 // / Update or overwrite the bits starting at \p offsetInBits with \p bits.
138141 bool addBits (llvm::APInt bits, uint64_t offsetInBits, bool allowOverwrite);
139142
143+ // / Attempt to condense the value starting at \p offset to a constant of type
144+ // / \p desiredTy.
145+ void condense (CharUnits offset, mlir::Type desiredTy);
146+
140147 // / Produce a constant representing the entire accumulated value, ideally of
141148 // / the specified type. If \p allowOversized, the constant might be larger
142149 // / than implied by \p desiredTy (eg, if there is a flexible array member).
@@ -176,6 +183,195 @@ bool ConstantAggregateBuilder::add(mlir::TypedAttr typedAttr, CharUnits offset,
176183 return false ;
177184}
178185
186+ bool ConstantAggregateBuilder::addBits (llvm::APInt bits, uint64_t offsetInBits,
187+ bool allowOverwrite) {
188+ const ASTContext &astContext = cgm.getASTContext ();
189+ const uint64_t charWidth = astContext.getCharWidth ();
190+ mlir::Type charTy = cgm.getBuilder ().getUIntNTy (charWidth);
191+
192+ // Offset of where we want the first bit to go within the bits of the
193+ // current char.
194+ unsigned offsetWithinChar = offsetInBits % charWidth;
195+
196+ // We split bit-fields up into individual bytes. Walk over the bytes and
197+ // update them.
198+ for (CharUnits offsetInChars =
199+ astContext.toCharUnitsFromBits (offsetInBits - offsetWithinChar);
200+ /* */ ; ++offsetInChars) {
201+ // Number of bits we want to fill in this char.
202+ unsigned wantedBits =
203+ std::min ((uint64_t )bits.getBitWidth (), charWidth - offsetWithinChar);
204+
205+ // Get a char containing the bits we want in the right places. The other
206+ // bits have unspecified values.
207+ llvm::APInt bitsThisChar = bits;
208+ if (bitsThisChar.getBitWidth () < charWidth)
209+ bitsThisChar = bitsThisChar.zext (charWidth);
210+ if (cgm.getDataLayout ().isBigEndian ()) {
211+ // Figure out how much to shift by. We may need to left-shift if we have
212+ // less than one byte of Bits left.
213+ int shift = bits.getBitWidth () - charWidth + offsetWithinChar;
214+ if (shift > 0 )
215+ bitsThisChar.lshrInPlace (shift);
216+ else if (shift < 0 )
217+ bitsThisChar = bitsThisChar.shl (-shift);
218+ } else {
219+ bitsThisChar = bitsThisChar.shl (offsetWithinChar);
220+ }
221+ if (bitsThisChar.getBitWidth () > charWidth)
222+ bitsThisChar = bitsThisChar.trunc (charWidth);
223+
224+ if (wantedBits == charWidth) {
225+ // Got a full byte: just add it directly.
226+ add (cir::IntAttr::get (charTy, bitsThisChar), offsetInChars,
227+ allowOverwrite);
228+ } else {
229+ // Partial byte: update the existing integer if there is one. If we
230+ // can't split out a 1-CharUnit range to update, then we can't add
231+ // these bits and fail the entire constant emission.
232+ std::optional<size_t > firstElemToUpdate = splitAt (offsetInChars);
233+ if (!firstElemToUpdate)
234+ return false ;
235+ std::optional<size_t > lastElemToUpdate =
236+ splitAt (offsetInChars + CharUnits::One ());
237+ if (!lastElemToUpdate)
238+ return false ;
239+ assert (*lastElemToUpdate - *firstElemToUpdate < 2 &&
240+ " should have at most one element covering one byte" );
241+
242+ // Figure out which bits we want and discard the rest.
243+ llvm::APInt updateMask (charWidth, 0 );
244+ if (cgm.getDataLayout ().isBigEndian ())
245+ updateMask.setBits (charWidth - offsetWithinChar - wantedBits,
246+ charWidth - offsetWithinChar);
247+ else
248+ updateMask.setBits (offsetWithinChar, offsetWithinChar + wantedBits);
249+ bitsThisChar &= updateMask;
250+ bool isNull = false ;
251+ if (*firstElemToUpdate < elements.size ()) {
252+ auto firstEltToUpdate =
253+ mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element );
254+ isNull = firstEltToUpdate && firstEltToUpdate.isNullValue ();
255+ }
256+
257+ if (*firstElemToUpdate == *lastElemToUpdate || isNull) {
258+ // All existing bits are either zero or undef.
259+ add (cir::IntAttr::get (charTy, bitsThisChar), offsetInChars,
260+ /* allowOverwrite*/ true );
261+ } else {
262+ cir::IntAttr ci =
263+ mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element );
264+ // In order to perform a partial update, we need the existing bitwise
265+ // value, which we can only extract for a constant int.
266+ if (!ci)
267+ return false ;
268+ // Because this is a 1-CharUnit range, the constant occupying it must
269+ // be exactly one CharUnit wide.
270+ assert (ci.getBitWidth () == charWidth && " splitAt failed" );
271+ assert ((!(ci.getValue () & updateMask) || allowOverwrite) &&
272+ " unexpectedly overwriting bitfield" );
273+ bitsThisChar |= (ci.getValue () & ~updateMask);
274+ elements[*firstElemToUpdate].element =
275+ cir::IntAttr::get (charTy, bitsThisChar);
276+ }
277+ }
278+
279+ // Stop if we've added all the bits.
280+ if (wantedBits == bits.getBitWidth ())
281+ break ;
282+
283+ // Remove the consumed bits from Bits.
284+ if (!cgm.getDataLayout ().isBigEndian ())
285+ bits.lshrInPlace (wantedBits);
286+ bits = bits.trunc (bits.getBitWidth () - wantedBits);
287+
288+ // The remaining bits go at the start of the following bytes.
289+ offsetWithinChar = 0 ;
290+ }
291+
292+ return true ;
293+ }
294+
295+ // / Returns a position within elements such that all elements
296+ // / before the returned index end before pos and all elements at or after
297+ // / the returned index begin at or after pos. Splits elements as necessary
298+ // / to ensure this. Returns std::nullopt if we find something we can't split.
299+ std::optional<size_t > ConstantAggregateBuilder::splitAt (CharUnits pos) {
300+ if (pos >= size)
301+ return elements.size ();
302+
303+ while (true ) {
304+ // Find the first element that starts after pos.
305+ Element *iter =
306+ llvm::upper_bound (elements, pos, [](CharUnits pos, const Element &elt) {
307+ return pos < elt.offset ;
308+ });
309+
310+ if (iter == elements.begin ())
311+ return 0 ;
312+
313+ size_t index = iter - elements.begin () - 1 ;
314+ const Element &elt = elements[index];
315+
316+ // If we already have an element starting at pos, we're done.
317+ if (elt.offset == pos)
318+ return index;
319+
320+ // Check for overlap with the element that starts before pos.
321+ CharUnits eltEnd = elt.offset + getSize (elt.element );
322+ if (eltEnd <= pos)
323+ return index + 1 ;
324+
325+ // Try to decompose it into smaller constants.
326+ if (!split (index, pos))
327+ return std::nullopt ;
328+ }
329+ }
330+
331+ // / Split the constant at index, if possible. Return true if we did.
332+ // / Hint indicates the location at which we'd like to split, but may be
333+ // / ignored.
334+ bool ConstantAggregateBuilder::split (size_t index, CharUnits hint) {
335+ cgm.errorNYI (" split constant at index" );
336+ return false ;
337+ }
338+
339+ void ConstantAggregateBuilder::condense (CharUnits offset,
340+ mlir::Type desiredTy) {
341+ CharUnits desiredSize = getSize (desiredTy);
342+
343+ std::optional<size_t > firstElemToReplace = splitAt (offset);
344+ if (!firstElemToReplace)
345+ return ;
346+ size_t first = *firstElemToReplace;
347+
348+ std::optional<size_t > lastElemToReplace = splitAt (offset + desiredSize);
349+ if (!lastElemToReplace)
350+ return ;
351+ size_t last = *lastElemToReplace;
352+
353+ size_t length = last - first;
354+ if (length == 0 )
355+ return ;
356+
357+ if (length == 1 && elements[first].offset == offset &&
358+ getSize (elements[first].element ) == desiredSize) {
359+ cgm.errorNYI (" re-wrapping single element records" );
360+ return ;
361+ }
362+
363+ // Build a new constant from the elements in the range.
364+ SmallVector<Element> subElems (elements.begin () + first,
365+ elements.begin () + last);
366+ mlir::Attribute replacement =
367+ buildFrom (cgm, subElems, offset, desiredSize,
368+ /* naturalLayout=*/ false , desiredTy, false );
369+
370+ // Replace the range with the condensed constant.
371+ Element newElt (mlir::cast<mlir::TypedAttr>(replacement), offset);
372+ replace (elements, first, last, {newElt});
373+ }
374+
179375mlir::Attribute
180376ConstantAggregateBuilder::buildFrom (CIRGenModule &cgm, ArrayRef<Element> elems,
181377 CharUnits startOffset, CharUnits size,
@@ -301,6 +497,9 @@ class ConstRecordBuilder {
301497 bool appendBytes (CharUnits fieldOffsetInChars, mlir::TypedAttr initCst,
302498 bool allowOverwrite = false );
303499
500+ bool appendBitField (const FieldDecl *field, uint64_t fieldOffset,
501+ cir::IntAttr ci, bool allowOverwrite = false );
502+
304503 bool build (InitListExpr *ile, bool allowOverwrite);
305504 bool build (const APValue &val, const RecordDecl *rd, bool isPrimaryBase,
306505 const CXXRecordDecl *vTableClass, CharUnits baseOffset);
@@ -325,6 +524,30 @@ bool ConstRecordBuilder::appendBytes(CharUnits fieldOffsetInChars,
325524 return builder.add (initCst, startOffset + fieldOffsetInChars, allowOverwrite);
326525}
327526
527+ bool ConstRecordBuilder::appendBitField (const FieldDecl *field,
528+ uint64_t fieldOffset, cir::IntAttr ci,
529+ bool allowOverwrite) {
530+ const CIRGenRecordLayout &rl =
531+ cgm.getTypes ().getCIRGenRecordLayout (field->getParent ());
532+ const CIRGenBitFieldInfo &info = rl.getBitFieldInfo (field);
533+ llvm::APInt fieldValue = ci.getValue ();
534+
535+ // Promote the size of FieldValue if necessary
536+ // FIXME: This should never occur, but currently it can because initializer
537+ // constants are cast to bool, and because clang is not enforcing bitfield
538+ // width limits.
539+ if (info.size > fieldValue.getBitWidth ())
540+ fieldValue = fieldValue.zext (info.size );
541+
542+ // Truncate the size of FieldValue to the bit field size.
543+ if (info.size < fieldValue.getBitWidth ())
544+ fieldValue = fieldValue.trunc (info.size );
545+
546+ return builder.addBits (fieldValue,
547+ cgm.getASTContext ().toBits (startOffset) + fieldOffset,
548+ allowOverwrite);
549+ }
550+
328551bool ConstRecordBuilder::build (InitListExpr *ile, bool allowOverwrite) {
329552 RecordDecl *rd = ile->getType ()
330553 ->castAs <clang::RecordType>()
@@ -407,12 +630,14 @@ bool ConstRecordBuilder::build(InitListExpr *ile, bool allowOverwrite) {
407630 } else {
408631 // Otherwise we have a bitfield.
409632 if (auto constInt = dyn_cast<cir::IntAttr>(eltInit)) {
410- assert (!cir::MissingFeatures::bitfields ());
411- cgm.errorNYI (field->getSourceRange (), " bitfields" );
633+ if (!appendBitField (field, layout.getFieldOffset (index), constInt,
634+ allowOverwrite))
635+ return false ;
636+ } else {
637+ // We are trying to initialize a bitfield with a non-trivial constant,
638+ // this must require run-time code.
639+ return false ;
412640 }
413- // We are trying to initialize a bitfield with a non-trivial constant,
414- // this must require run-time code.
415- return false ;
416641 }
417642 }
418643
@@ -510,8 +735,16 @@ bool ConstRecordBuilder::build(const APValue &val, const RecordDecl *rd,
510735 if (field->hasAttr <NoUniqueAddressAttr>())
511736 allowOverwrite = true ;
512737 } else {
513- assert (!cir::MissingFeatures::bitfields ());
514- cgm.errorNYI (field->getSourceRange (), " bitfields" );
738+ // Otherwise we have a bitfield.
739+ if (auto constInt = dyn_cast<cir::IntAttr>(eltInit)) {
740+ if (!appendBitField (field, layout.getFieldOffset (index) + offsetBits,
741+ constInt, allowOverwrite))
742+ return false ;
743+ } else {
744+ // We are trying to initialize a bitfield with a non-trivial constant,
745+ // this must require run-time code.
746+ return false ;
747+ }
515748 }
516749 }
517750
0 commit comments