16
16
17
17
#include " llvm/IR/Constants.h"
18
18
19
+ #include " BitPatternReader.h"
20
+ #include " Explosion.h"
19
21
#include " GenConstant.h"
22
+ #include " GenEnum.h"
20
23
#include " GenIntegerLiteral.h"
21
24
#include " GenStruct.h"
22
25
#include " GenTuple.h"
@@ -115,43 +118,83 @@ llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM,
115
118
namespace {
116
119
117
120
// / Fill in the missing values for padding.
118
- void insertPadding (SmallVectorImpl<llvm::Constant * > &Elements ,
121
+ void insertPadding (SmallVectorImpl<Explosion > &elements ,
119
122
llvm::StructType *sTy ) {
120
123
// fill in any gaps, which are the explicit padding that swiftc inserts.
121
- for (unsigned i = 0 , e = Elements.size (); i != e; ++i) {
122
- auto &elt = Elements[i];
123
- if (elt == nullptr ) {
124
+ for (unsigned i = 0 , e = elements.size (); i != e; ++i) {
125
+ if (elements[i].empty ()) {
124
126
auto *eltTy = sTy ->getElementType (i);
125
127
assert (eltTy->isArrayTy () &&
126
128
eltTy->getArrayElementType ()->isIntegerTy (8 ) &&
127
129
" Unexpected non-byte-array type for constant struct padding" );
128
- elt = llvm::UndefValue::get (eltTy);
130
+ elements[i]. add ( llvm::UndefValue::get (eltTy) );
129
131
}
130
132
}
131
133
}
132
134
135
+ // / Creates a struct which contains all values of `explosions`.
136
+ // /
137
+ // / If all explosions have a single element and those elements match the
138
+ // / elements of `structTy`, it uses this type as result type.
139
+ // / Otherwise, it creates an anonymous struct. This can be the case for enums.
140
+ llvm::Constant *createStructFromExplosion (SmallVectorImpl<Explosion> &explosions,
141
+ llvm::StructType *structTy) {
142
+ assert (explosions.size () == structTy->getNumElements ());
143
+ bool canUseStructType = true ;
144
+ llvm::SmallVector<llvm::Constant *, 32 > values;
145
+ unsigned idx = 0 ;
146
+ for (auto &elmt : explosions) {
147
+ if (elmt.size () != 1 )
148
+ canUseStructType = false ;
149
+ for (llvm::Value *v : elmt.claimAll ()) {
150
+ if (v->getType () != structTy->getElementType (idx))
151
+ canUseStructType = false ;
152
+ values.push_back (cast<llvm::Constant>(v));
153
+ }
154
+ idx++;
155
+ }
156
+ if (canUseStructType) {
157
+ return llvm::ConstantStruct::get (structTy, values);
158
+ } else {
159
+ return llvm::ConstantStruct::getAnon (values, /* Packed=*/ true );
160
+ }
161
+ }
162
+
163
+ void initWithEmptyExplosions (SmallVectorImpl<Explosion> &explosions,
164
+ unsigned count) {
165
+ for (unsigned i = 0 ; i < count; i++) {
166
+ explosions.push_back (Explosion ());
167
+ }
168
+ }
169
+
133
170
template <typename InstTy, typename NextIndexFunc>
134
- llvm::Constant * emitConstantStructOrTuple (IRGenModule &IGM, InstTy inst,
135
- NextIndexFunc nextIndex) {
171
+ Explosion emitConstantStructOrTuple (IRGenModule &IGM, InstTy inst,
172
+ NextIndexFunc nextIndex, bool flatten ) {
136
173
auto type = inst->getType ();
137
174
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo (type).getStorageType ());
138
175
139
- SmallVector<llvm::Constant *, 32 > elts (sTy ->getNumElements (), nullptr );
176
+ SmallVector<Explosion, 32 > elements;
177
+ initWithEmptyExplosions (elements, sTy ->getNumElements ());
140
178
141
- // run over the Swift initializers, putting them into the struct as
142
- // appropriate.
143
179
for (unsigned i = 0 , e = inst->getElements ().size (); i != e; ++i) {
144
180
auto operand = inst->getOperand (i);
145
181
Optional<unsigned > index = nextIndex (IGM, type, i);
146
182
if (index.has_value ()) {
147
- assert (elts[index.value ()] == nullptr &&
183
+ unsigned idx = index.value ();
184
+ assert (elements[idx].empty () &&
148
185
" Unexpected constant struct field overlap" );
149
-
150
- elts[index.value ()] = emitConstantValue (IGM, operand);
186
+ elements[idx] = emitConstantValue (IGM, operand, flatten);
187
+ }
188
+ }
189
+ if (flatten) {
190
+ Explosion out;
191
+ for (auto &elmt : elements) {
192
+ out.add (elmt.claimAll ());
151
193
}
194
+ return out;
152
195
}
153
- insertPadding (elts , sTy );
154
- return llvm::ConstantStruct::get ( sTy , elts );
196
+ insertPadding (elements , sTy );
197
+ return createStructFromExplosion (elements, sTy );
155
198
}
156
199
} // end anonymous namespace
157
200
@@ -181,7 +224,36 @@ static BuiltinInst *getOffsetSubtract(const TupleExtractInst *TE, SILModule &M)
181
224
return BI;
182
225
}
183
226
184
- llvm::Constant *irgen::emitConstantValue (IRGenModule &IGM, SILValue operand) {
227
+ static bool isPowerOfTwo (unsigned x) {
228
+ return (x & -x) == x;
229
+ }
230
+
231
+ // / Replace i24, i40, i48 and i56 constants in `e` with the corresponding byte values.
232
+ // / Such unaligned integer constants are not correctly layed out in the data section.
233
+ static Explosion replaceUnalignedIntegerValues (IRGenModule &IGM, Explosion e) {
234
+ Explosion out;
235
+ while (!e.empty ()) {
236
+ llvm::Value *v = e.claimNext ();
237
+
238
+ if (auto *constInt = dyn_cast<llvm::ConstantInt>(v)) {
239
+ unsigned size = constInt->getBitWidth ();
240
+ if (size % 8 == 0 && !isPowerOfTwo (size)) {
241
+ BitPatternReader reader (constInt->getValue (), IGM.Triple .isLittleEndian ());
242
+ while (size > 0 ) {
243
+ APInt byte = reader.read (8 );
244
+ out.add (llvm::ConstantInt::get (IGM.getLLVMContext (), byte));
245
+ size -= 8 ;
246
+ }
247
+ continue ;
248
+ }
249
+ }
250
+ out.add (v);
251
+ }
252
+ return out;
253
+ }
254
+
255
+ Explosion irgen::emitConstantValue (IRGenModule &IGM, SILValue operand,
256
+ bool flatten) {
185
257
if (auto *SI = dyn_cast<StructInst>(operand)) {
186
258
// The only way to get a struct's stored properties (which we need to map to
187
259
// their physical/LLVM index) is to iterate over the properties
@@ -195,64 +267,83 @@ llvm::Constant *irgen::emitConstantValue(IRGenModule &IGM, SILValue operand) {
195
267
(void )_i;
196
268
auto *FD = *Iter++;
197
269
return irgen::getPhysicalStructFieldIndex (IGM, Type, FD);
198
- });
270
+ }, flatten );
199
271
} else if (auto *TI = dyn_cast<TupleInst>(operand)) {
200
272
return emitConstantStructOrTuple (IGM, TI,
201
- irgen::getPhysicalTupleElementStructIndex);
273
+ irgen::getPhysicalTupleElementStructIndex,
274
+ flatten);
275
+ } else if (auto *ei = dyn_cast<EnumInst>(operand)) {
276
+ Explosion data;
277
+ if (ei->hasOperand ()) {
278
+ data = emitConstantValue (IGM, ei->getOperand (), /* flatten=*/ true );
279
+ }
280
+ // Use `emitValueInjection` to create the enum constant.
281
+ // Usually this method creates code in the current function. But if all
282
+ // arguments to the enum are constant, the builder never has to emit an
283
+ // instruction. Instead it can constant fold everything and just returns
284
+ // the final constant.
285
+ Explosion out;
286
+ IRBuilder builder (IGM.getLLVMContext (), false );
287
+ getEnumImplStrategy (IGM, ei->getType ())
288
+ .emitValueInjection (IGM, builder, ei->getElement (), data, out);
289
+ return replaceUnalignedIntegerValues (IGM, std::move (out));
202
290
} else if (auto *ILI = dyn_cast<IntegerLiteralInst>(operand)) {
203
291
return emitConstantInt (IGM, ILI);
204
292
} else if (auto *FLI = dyn_cast<FloatLiteralInst>(operand)) {
205
293
return emitConstantFP (IGM, FLI);
206
294
} else if (auto *SLI = dyn_cast<StringLiteralInst>(operand)) {
207
295
return emitAddrOfConstantString (IGM, SLI);
208
296
} else if (auto *BI = dyn_cast<BuiltinInst>(operand)) {
297
+ auto args = BI->getArguments ();
209
298
switch (IGM.getSILModule ().getBuiltinInfo (BI->getName ()).ID ) {
210
299
case BuiltinValueKind::ZeroInitializer:
211
300
return emitConstantZero (IGM, BI);
212
301
case BuiltinValueKind::PtrToInt: {
213
- llvm::Constant *ptr = emitConstantValue (IGM, BI-> getArguments () [0 ]);
302
+ auto *ptr = emitConstantValue (IGM, args [0 ]). claimNextConstant ( );
214
303
return llvm::ConstantExpr::getPtrToInt (ptr, IGM.IntPtrTy );
215
304
}
216
305
case BuiltinValueKind::ZExtOrBitCast: {
217
- llvm::Constant *value = emitConstantValue (IGM, BI->getArguments ()[0 ]);
218
- return llvm::ConstantExpr::getZExtOrBitCast (value, IGM.getStorageType (BI->getType ()));
306
+ auto *val = emitConstantValue (IGM, args[0 ]).claimNextConstant ();
307
+ return llvm::ConstantExpr::getZExtOrBitCast (val,
308
+ IGM.getStorageType (BI->getType ()));
219
309
}
220
310
case BuiltinValueKind::StringObjectOr: {
221
311
// It is a requirement that the or'd bits in the left argument are
222
312
// initialized with 0. Therefore the or-operation is equivalent to an
223
313
// addition. We need an addition to generate a valid relocation.
224
- llvm::Constant *rhs = emitConstantValue (IGM, BI-> getArguments () [1 ]);
225
- if (auto *TE = dyn_cast<TupleExtractInst>(BI-> getArguments () [0 ])) {
314
+ auto *rhs = emitConstantValue (IGM, args [1 ]). claimNextConstant ( );
315
+ if (auto *TE = dyn_cast<TupleExtractInst>(args [0 ])) {
226
316
// Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits)
227
317
// This pattern appears in UTF8 String literal construction.
228
318
// Generate the equivalent: add(x, sub(bits - offset)
229
319
BuiltinInst *SubtrBI = getOffsetSubtract (TE, IGM.getSILModule ());
230
320
assert (SubtrBI && " unsupported argument of StringObjectOr" );
231
- auto *ptr = emitConstantValue (IGM, SubtrBI->getArguments ()[0 ]);
232
- auto *offset = emitConstantValue (IGM, SubtrBI->getArguments ()[1 ]);
321
+ auto subArgs = SubtrBI->getArguments ();
322
+ auto *ptr = emitConstantValue (IGM, subArgs[0 ]).claimNextConstant ();
323
+ auto *offset = emitConstantValue (IGM, subArgs[1 ]).claimNextConstant ();
233
324
auto *totalOffset = llvm::ConstantExpr::getSub (rhs, offset);
234
325
return llvm::ConstantExpr::getAdd (ptr, totalOffset);
235
326
}
236
- llvm::Constant *lhs = emitConstantValue (IGM, BI-> getArguments () [0 ]);
327
+ auto *lhs = emitConstantValue (IGM, args [0 ]). claimNextConstant ( );
237
328
return llvm::ConstantExpr::getAdd (lhs, rhs);
238
329
}
239
330
default :
240
331
llvm_unreachable (" unsupported builtin for constant expression" );
241
332
}
242
333
} else if (auto *VTBI = dyn_cast<ValueToBridgeObjectInst>(operand)) {
243
- auto *val = emitConstantValue (IGM, VTBI->getOperand ());
334
+ auto *val = emitConstantValue (IGM, VTBI->getOperand ()). claimNextConstant () ;
244
335
auto *sTy = IGM.getTypeInfo (VTBI->getType ()).getStorageType ();
245
336
return llvm::ConstantExpr::getIntToPtr (val, sTy );
246
337
247
338
} else if (auto *CFI = dyn_cast<ConvertFunctionInst>(operand)) {
248
- return emitConstantValue (IGM, CFI->getOperand ());
339
+ return emitConstantValue (IGM, CFI->getOperand ()). claimNextConstant () ;
249
340
250
341
} else if (auto *T2TFI = dyn_cast<ThinToThickFunctionInst>(operand)) {
251
342
SILType type = operand->getType ();
252
343
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo (type).getStorageType ());
253
344
254
345
auto *function = llvm::ConstantExpr::getBitCast (
255
- emitConstantValue (IGM, T2TFI->getCallee ()),
346
+ emitConstantValue (IGM, T2TFI->getCallee ()). claimNextConstant () ,
256
347
sTy ->getTypeAtIndex ((unsigned )0 ));
257
348
258
349
auto *context = llvm::ConstantExpr::getBitCast (
@@ -287,7 +378,9 @@ llvm::Constant *irgen::emitConstantValue(IRGenModule &IGM, SILValue operand) {
287
378
llvm::Constant *irgen::emitConstantObject (IRGenModule &IGM, ObjectInst *OI,
288
379
StructLayout *ClassLayout) {
289
380
auto *sTy = cast<llvm::StructType>(ClassLayout->getType ());
290
- SmallVector<llvm::Constant *, 32 > elts (sTy ->getNumElements (), nullptr );
381
+
382
+ SmallVector<Explosion, 32 > elements;
383
+ initWithEmptyExplosions (elements, sTy ->getNumElements ());
291
384
292
385
unsigned NumElems = OI->getAllElements ().size ();
293
386
assert (NumElems == ClassLayout->getElements ().size ());
@@ -297,9 +390,11 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
297
390
SILValue Val = OI->getAllElements ()[i];
298
391
const ElementLayout &EL = ClassLayout->getElements ()[i];
299
392
if (!EL.isEmpty ()) {
300
- unsigned EltIdx = EL.getStructIndex ();
301
- assert (EltIdx != 0 && " the first element is the object header" );
302
- elts[EltIdx] = emitConstantValue (IGM, Val);
393
+ unsigned idx = EL.getStructIndex ();
394
+ assert (idx != 0 && " the first element is the object header" );
395
+ assert (elements[idx].empty () &&
396
+ " Unexpected constant struct field overlap" );
397
+ elements[idx] = emitConstantValue (IGM, Val);
303
398
}
304
399
}
305
400
// Construct the object header.
@@ -322,14 +417,14 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
322
417
/* initializer*/ nullptr , " $ss19__EmptyArrayStorageCN" );
323
418
IGM.swiftStaticArrayMetadata = var;
324
419
}
325
- elts [0 ] = llvm::ConstantStruct::get (ObjectHeaderTy, {
420
+ elements [0 ]. add ( llvm::ConstantStruct::get (ObjectHeaderTy, {
326
421
IGM.swiftStaticArrayMetadata ,
327
- llvm::ConstantExpr::getPtrToInt (IGM.swiftImmortalRefCount , IGM.IntPtrTy )});
422
+ llvm::ConstantExpr::getPtrToInt (IGM.swiftImmortalRefCount , IGM.IntPtrTy )})) ;
328
423
} else {
329
- elts [0 ] = llvm::Constant::getNullValue (ObjectHeaderTy);
424
+ elements [0 ]. add ( llvm::Constant::getNullValue (ObjectHeaderTy) );
330
425
}
331
- insertPadding (elts , sTy );
332
- return llvm::ConstantStruct::get ( sTy , elts );
426
+ insertPadding (elements , sTy );
427
+ return createStructFromExplosion (elements, sTy );
333
428
}
334
429
335
430
void ConstantAggregateBuilderBase::addUniqueHash (StringRef data) {
0 commit comments