@@ -257,6 +257,8 @@ void IrAggr::addFieldInitializers(
257
257
const VarInitMap &explicitInitializers, AggregateDeclaration *decl,
258
258
unsigned &offset, unsigned &interfaceVtblIndex, bool &isPacked) {
259
259
260
+ using llvm::APInt;
261
+
260
262
if (ClassDeclaration *cd = decl->isClassDeclaration ()) {
261
263
if (cd->baseClass ) {
262
264
addFieldInitializers (constants, explicitInitializers, cd->baseClass ,
@@ -302,6 +304,9 @@ void IrAggr::addFieldInitializers(
302
304
: getDefaultInitializer (field);
303
305
};
304
306
307
+ // IR field index => APInt for bitfield group
308
+ std::unordered_map<unsigned , APInt> bitFieldGroupConstants;
309
+
305
310
const auto addToBitFieldGroup = [&](BitFieldDeclaration *bf,
306
311
unsigned fieldIndex, unsigned bitOffset) {
307
312
LLConstant *init = getFieldInit (bf);
@@ -310,20 +315,24 @@ void IrAggr::addFieldInitializers(
310
315
return ;
311
316
}
312
317
313
- LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
318
+ if (bitFieldGroupConstants.find (fieldIndex) ==
319
+ bitFieldGroupConstants.end ()) {
320
+ const auto fieldType =
321
+ llvm::cast<LLArrayType>(b.defaultTypes ()[fieldIndex]); // an i8 array
322
+ const auto bitFieldSize = fieldType->getNumElements ();
323
+ bitFieldGroupConstants.emplace (fieldIndex, APInt (bitFieldSize * 8 , 0 ));
324
+ }
325
+
326
+ APInt &constant = bitFieldGroupConstants[fieldIndex];
327
+ const auto intSizeInBits = constant.getBitWidth ();
314
328
315
- using llvm::APInt;
316
- const auto fieldType = b.defaultTypes ()[fieldIndex];
317
- const auto intSizeInBits = fieldType->getIntegerBitWidth ();
318
- const APInt oldVal =
319
- constant ? constant->getUniqueInteger () : APInt (intSizeInBits, 0 );
329
+ const APInt oldVal = constant;
320
330
const APInt bfVal = init->getUniqueInteger ().zextOrTrunc (intSizeInBits);
321
331
const APInt mask = APInt::getLowBitsSet (intSizeInBits, bf->fieldWidth )
322
332
<< bitOffset;
323
333
assert (!oldVal.intersects (mask) && " has masked bits set already" );
324
- const APInt newVal = oldVal | ((bfVal << bitOffset) & mask);
325
334
326
- constant = LLConstant::getIntegerValue (fieldType, newVal );
335
+ constant = oldVal | ((bfVal << bitOffset) & mask );
327
336
};
328
337
329
338
// add explicit and non-overlapping implicit initializers
@@ -333,7 +342,7 @@ void IrAggr::addFieldInitializers(
333
342
const auto fieldIndex = pair.second ;
334
343
335
344
if (auto bf = field->isBitFieldDeclaration ()) {
336
- // multiple bit fields can map to a single IR field (of integer type)
345
+ // multiple bit fields can map to a single IR field for the whole group
337
346
addToBitFieldGroup (bf, fieldIndex, bf->bitOffset );
338
347
} else {
339
348
LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
@@ -356,6 +365,25 @@ void IrAggr::addFieldInitializers(
356
365
(bf->offset - primary->offset ) * 8 + bf->bitOffset );
357
366
}
358
367
368
+ for (const auto &pair : bitFieldGroupConstants) {
369
+ const unsigned fieldIndex = pair.first ;
370
+ const APInt intValue = pair.second ;
371
+
372
+ LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
373
+ assert (!constant && " already have a constant for a bitfield group?" );
374
+
375
+ // convert APInt to i8 array
376
+ const auto i8Type = getI8Type ();
377
+ const auto numBytes = intValue.getBitWidth () / 8 ;
378
+ llvm::SmallVector<LLConstant *, 8 > bytes;
379
+ for (unsigned i = 0 ; i < numBytes; ++i) {
380
+ APInt byteVal = intValue.extractBits (8 , i * 8 );
381
+ bytes.push_back (LLConstant::getIntegerValue (i8Type, byteVal));
382
+ }
383
+
384
+ constant = llvm::ConstantArray::get (LLArrayType::get (i8Type, numBytes), bytes);
385
+ }
386
+
359
387
// TODO: sanity check that all explicit initializers have been dealt with?
360
388
// (potential issue for bitfields in unions...)
361
389
0 commit comments