58
58
// /
59
59
// / The function 'OSLogOptimization::run' implements the overall driver for
60
60
// / steps 1 to 4. The function 'beginOfInterpolation' implements step 1. It
61
- // / computes the instruction from which start the evaluation. The function
61
+ // / computes the instruction from which the evaluation must start . The function
62
62
// / 'constantFold' is a driver for the steps 2 to 4. Step 2 is implemented by
63
63
// / the function 'collectConstants', step 3 by 'detectAndDiagnoseErrors', and
64
64
// / step 4 by 'substituteConstants' and 'emitCodeForSymbolicValue'.
@@ -169,20 +169,32 @@ class FoldState {
169
169
// / Information needed for folding strings.
170
170
StringSILInfo stringInfo;
171
171
172
+ // / Instruction from where folding must begin.
173
+ SILInstruction *beginInstruction;
174
+
175
+ // / Instructions that mark the end points of folding. No folded SIL value must
176
+ // / be usable beyond these instructions (in the control-flow order). These
177
+ // / instructions are also used to emit destory instructions for non-trivial,
178
+ // / SIL values emitted during folding.
179
+ SmallSetVector<SILInstruction *, 2 > endInstructions;
180
+
172
181
private:
173
- // / Single-valued instructions that were found to be constants during
182
+ // / SIL values that were found to be constants during
174
183
// / constant evaluation.
175
- SmallVector<SingleValueInstruction * , 4 > constantValuedInstructions ;
184
+ SmallVector<SILValue , 4 > constantSILValues ;
176
185
177
186
public:
178
- FoldState (SILFunction *fun) : constantEvaluator(allocator, fun) {}
187
+ FoldState (SILFunction *fun, SILInstruction *beginInst,
188
+ ArrayRef<SILInstruction *> endInsts)
189
+ : constantEvaluator(allocator, fun), beginInstruction(beginInst),
190
+ endInstructions (endInsts.begin(), endInsts.end()) {}
179
191
180
- void addConstantInstruction (SingleValueInstruction * value) {
181
- constantValuedInstructions .push_back (value);
192
+ void addConstantSILValue (SILValue value) {
193
+ constantSILValues .push_back (value);
182
194
}
183
195
184
- ArrayRef<SingleValueInstruction *> getConstantInstructions () {
185
- return ArrayRef<SingleValueInstruction *>(constantValuedInstructions );
196
+ ArrayRef<SILValue> getConstantSILValues () {
197
+ return ArrayRef<SILValue>(constantSILValues );
186
198
}
187
199
};
188
200
@@ -266,39 +278,40 @@ evaluateOrSkip(ConstExprStepEvaluator &stepEval,
266
278
// / used only on string literals.
267
279
// / - StructInst cannot be folded. We can only fold its arguments and not the
268
280
// / instruction itself.
269
- static bool isInstructionFoldable (SingleValueInstruction *inst) {
270
- ASTContext &astContext = inst->getFunction ()->getASTContext ();
271
- SILType silType = inst->getType ();
281
+ static bool isSILValueFoldable (SILValue value) {
282
+ SILInstruction *definingInst = value->getDefiningInstruction ();
283
+ if (!definingInst)
284
+ return false ;
272
285
273
- return (!silType.isAddress () && !isa<LiteralInst>(inst) &&
274
- !isa<StructInst>(inst) && !getStringMakeUTF8Init (inst) &&
286
+ ASTContext &astContext = definingInst->getFunction ()->getASTContext ();
287
+ SILType silType = value->getType ();
288
+
289
+ return (!silType.isAddress () && !isa<LiteralInst>(definingInst) &&
290
+ !isa<StructInst>(definingInst) &&
291
+ !getStringMakeUTF8Init (definingInst) &&
275
292
isIntegerOrStringType (silType, astContext));
276
293
}
277
294
278
- // / Constant evaluate the instructions from 'start' to the end of the function
279
- // / or until oslogMessage is released. Add foldable, constant-valued
280
- // / instructions discovered during the evaluation to the 'foldState' passed in.
295
+ // / Given a 'foldState', constant evaluate instructions from
296
+ // / 'foldState.beginInstruction' until an instruction in
297
+ // / 'foldState.endInstructions' is seen. Add foldable, constant-valued
298
+ // / instructions discovered during the evaluation to
299
+ // / 'foldState.constantSILValues'.
281
300
// / \returns error information for emitting diagnostics if the evaluation
282
301
// / failed.
283
- static Optional<SymbolicValue>
284
- collectConstants (SILInstruction *start, SingleValueInstruction *oslogMessage,
285
- FoldState &foldState) {
302
+ static Optional<SymbolicValue> collectConstants (FoldState &foldState) {
286
303
287
304
ConstExprStepEvaluator &constantEvaluator = foldState.constantEvaluator ;
288
- SILBasicBlock::iterator currI = start->getIterator ();
305
+ SILBasicBlock::iterator currI = foldState.beginInstruction ->getIterator ();
306
+ auto &endInstructions = foldState.endInstructions ;
289
307
290
- // The loop will return when it sees a return instruction or a release value
291
- // of oslogMessage .
308
+ // The loop will break when it sees a return instruction or an instruction in
309
+ // endInstructions .
292
310
while (true ) {
293
311
SILInstruction *currInst = &(*currI);
294
312
295
- // Break if currInst is a release_value of 'oslogMessage'.
296
- if (auto *releaseValueInst = dyn_cast<ReleaseValueInst>(currInst)) {
297
- if (releaseValueInst->getOperand ()->getDefiningInstruction () ==
298
- oslogMessage) {
299
- break ;
300
- }
301
- }
313
+ if (endInstructions.count (currInst))
314
+ break ;
302
315
303
316
// Initialize string info from this instruction if possible.
304
317
foldState.stringInfo .extractStringInfoFromInstruction (currInst);
@@ -313,17 +326,17 @@ collectConstants(SILInstruction *start, SingleValueInstruction *oslogMessage,
313
326
// Set the next instruction to continue evaluation from.
314
327
currI = nextI.getValue ();
315
328
316
- // If the instruction is foldable and if we found a constant value for
317
- // the result of the instruction, record it.
318
- auto *singleValInst = dyn_cast<SingleValueInstruction>(currInst);
319
- if (!singleValInst || !isInstructionFoldable (singleValInst)) {
320
- continue ;
321
- }
329
+ // If the instruction results are foldable and if we found a constant value
330
+ // for the results, record it.
331
+ for (SILValue instructionResult : currInst->getResults ()) {
332
+ if (!isSILValueFoldable (instructionResult))
333
+ continue ;
322
334
323
- Optional<SymbolicValue> constantVal =
324
- constantEvaluator.lookupConstValue (singleValInst);
325
- if (constantVal.hasValue ()) {
326
- foldState.addConstantInstruction (singleValInst);
335
+ Optional<SymbolicValue> constantVal =
336
+ constantEvaluator.lookupConstValue (instructionResult);
337
+ if (constantVal.hasValue ()) {
338
+ foldState.addConstantSILValue (instructionResult);
339
+ }
327
340
}
328
341
}
329
342
return None; // No error.
@@ -409,27 +422,117 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal,
409
422
}
410
423
}
411
424
425
+ // / Collect the end-of-lifetime instructions of the given SILValue. These are
426
+ // / either release_value or destroy_value instructions.
427
+ // / \param value SIL value whose end-of-lifetime instructions must be collected.
428
+ // / \param lifetimeEndInsts buffer for storing the found end-of-lifetime
429
+ // / instructions of 'value'.
430
+ static void getLifetimeEndInstructionsOfSILValue (
431
+ SILValue value, SmallVectorImpl<SILInstruction *> &lifetimeEndInsts) {
432
+
433
+ bool continueLifetimeEndInstructionSearch = true ;
434
+ SILValue currValue = value;
435
+
436
+ while (continueLifetimeEndInstructionSearch) {
437
+ continueLifetimeEndInstructionSearch = false ;
438
+
439
+ for (Operand *use : currValue->getUses ()) {
440
+ SILInstruction *user = use->getUser ();
441
+
442
+ if (isa<ReleaseValueInst>(user) || isa<DestroyValueInst>(user)) {
443
+ lifetimeEndInsts.push_back (user);
444
+ continue ;
445
+ }
446
+
447
+ if (isa<CopyValueInst>(user)) {
448
+ auto *copyValueInst = cast<CopyValueInst>(user);
449
+ // Continue looking for the end-of-lifetime instruction for the
450
+ // result of copy_value.
451
+ currValue = copyValueInst;
452
+ continueLifetimeEndInstructionSearch = true ;
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+ // / Emit instructions to destroy the folded value at the end of its use, if
459
+ // / required. Since this pass folds only integers or strings and since the
460
+ // / former is a trivial type, we only have to destroy strings that are folded.
461
+ // / For strings, a release_value (or a destory_value instruction in ownership
462
+ // / SIL) has to be emitted if it is not already present.
463
+ static void
464
+ destroyFoldedValueAtEndOfUse (SILValue foldedVal, SILValue originalVal,
465
+ ArrayRef<SILInstruction *> endOfUseInsts,
466
+ SILFunction *fun) {
467
+ // Folded value should have either trivial or owned ownership as it is an
468
+ // integer or string constant.
469
+ assert (foldedVal.getOwnershipKind () == ValueOwnershipKind::Any ||
470
+ foldedVal.getOwnershipKind () == ValueOwnershipKind::Owned);
471
+
472
+ // If the ownership kinds of folded and original values are both either
473
+ // owned or trivial, there is nothing to do.
474
+ if (foldedVal.getOwnershipKind () == originalVal.getOwnershipKind ()) {
475
+ return ;
476
+ }
477
+ assert (originalVal.getOwnershipKind () == ValueOwnershipKind::Guaranteed);
478
+
479
+ // Here, the original value may be at +0 and hence may not be released.
480
+ // However, the folded value should always be released.
481
+ SmallVector<SILInstruction *, 2 > lifeTimeEndInstsOfOriginal;
482
+ getLifetimeEndInstructionsOfSILValue (originalVal, lifeTimeEndInstsOfOriginal);
483
+
484
+ if (!lifeTimeEndInstsOfOriginal.empty ()) {
485
+ // Here, the original value is released, and so would be the folded value.
486
+ return ;
487
+ }
488
+
489
+ // Here, the original value is not released. Release the folded value at the
490
+ // 'endOfUse' instructions passed as parameter.
491
+ bool hasOwnership = fun->hasOwnership ();
492
+ for (SILInstruction *endInst : endOfUseInsts) {
493
+ SILBuilderWithScope builder (endInst);
494
+ if (hasOwnership) {
495
+ builder.createDestroyValue (endInst->getLoc (), foldedVal);
496
+ } else {
497
+ builder.createReleaseValue (endInst->getLoc (), foldedVal,
498
+ builder.getDefaultAtomicity ());
499
+ }
500
+ }
501
+ }
502
+
412
503
// / Given a fold state with constant-valued instructions, substitute the
413
504
// / instructions with the constant values. The constant values could be strings
414
505
// / or Stdlib integer-struct values or builtin integers.
415
506
static void substituteConstants (FoldState &foldState) {
416
507
417
508
ConstExprStepEvaluator &evaluator = foldState.constantEvaluator ;
418
-
419
509
SmallVector<SILInstruction *, 4 > deletedInsts;
420
- for (SingleValueInstruction *constantInst :
421
- foldState.getConstantInstructions ()) {
422
- SymbolicValue constantVal =
423
- evaluator.lookupConstValue (constantInst).getValue ();
424
-
425
- SILBuilderWithScope builder (constantInst);
426
- SILLocation loc = constantInst->getLoc ();
427
- SILType instType = constantInst->getType ();
510
+ auto endOfUseInsts = ArrayRef<SILInstruction *>(
511
+ foldState.endInstructions .begin (), foldState.endInstructions .end ());
512
+
513
+ for (SILValue constantSILValue : foldState.getConstantSILValues ()) {
514
+ SymbolicValue constantSymbolicVal =
515
+ evaluator.lookupConstValue (constantSILValue).getValue ();
516
+
517
+ SILInstruction *definingInst = constantSILValue->getDefiningInstruction ();
518
+ assert (definingInst);
519
+
520
+ SILBuilderWithScope builder (definingInst);
521
+ SILLocation loc = definingInst->getLoc ();
522
+ SILType instType = constantSILValue->getType ();
428
523
SILValue foldedSILVal = emitCodeForSymbolicValue (
429
- constantVal, instType, builder, loc, foldState.stringInfo );
524
+ constantSymbolicVal, instType, builder, loc, foldState.stringInfo );
525
+
526
+ // Add an instruction to end the lifetime of the foldedSILVal, if necessary.
527
+ destroyFoldedValueAtEndOfUse (foldedSILVal, constantSILValue, endOfUseInsts,
528
+ definingInst->getFunction ());
430
529
431
- constantInst->replaceAllUsesWith (foldedSILVal);
432
- deletedInsts.push_back (constantInst);
530
+ constantSILValue->replaceAllUsesWith (foldedSILVal);
531
+
532
+ if (isa<SingleValueInstruction>(definingInst)) {
533
+ deletedInsts.push_back (definingInst);
534
+ } // Otherwise, be conservative and do not delete the instruction as other
535
+ // results of the instruction could be used.
433
536
}
434
537
435
538
recursivelyDeleteTriviallyDeadInstructions (deletedInsts, true ,
@@ -525,9 +628,12 @@ static void constantFold(SILInstruction *start,
525
628
SingleValueInstruction *oslogMessage) {
526
629
527
630
// Initialize fold state.
528
- FoldState state (start->getFunction ());
631
+ SmallVector<SILInstruction *, 2 > lifetimeEndInsts;
632
+ getLifetimeEndInstructionsOfSILValue (oslogMessage, lifetimeEndInsts);
633
+
634
+ FoldState state (start->getFunction (), start, lifetimeEndInsts);
529
635
530
- auto errorInfo = collectConstants (start, oslogMessage, state);
636
+ auto errorInfo = collectConstants (state);
531
637
532
638
// At this point, the `OSLogMessage` instance should be mapped to a symbolic
533
639
// value in the interpreter state. Furthermore, its format string and
0 commit comments