Skip to content

Commit 4d4609a

Browse files
committed
[os_log][SIL Optimization] Modify the OSLogOptimization pass to run
on ownership SIL.
1 parent 27eefd7 commit 4d4609a

File tree

1 file changed

+159
-53
lines changed

1 file changed

+159
-53
lines changed

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 159 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
///
5959
/// The function 'OSLogOptimization::run' implements the overall driver for
6060
/// 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
6262
/// 'constantFold' is a driver for the steps 2 to 4. Step 2 is implemented by
6363
/// the function 'collectConstants', step 3 by 'detectAndDiagnoseErrors', and
6464
/// step 4 by 'substituteConstants' and 'emitCodeForSymbolicValue'.
@@ -169,20 +169,32 @@ class FoldState {
169169
/// Information needed for folding strings.
170170
StringSILInfo stringInfo;
171171

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+
172181
private:
173-
/// Single-valued instructions that were found to be constants during
182+
/// SIL values that were found to be constants during
174183
/// constant evaluation.
175-
SmallVector<SingleValueInstruction *, 4> constantValuedInstructions;
184+
SmallVector<SILValue, 4> constantSILValues;
176185

177186
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()) {}
179191

180-
void addConstantInstruction(SingleValueInstruction *value) {
181-
constantValuedInstructions.push_back(value);
192+
void addConstantSILValue(SILValue value) {
193+
constantSILValues.push_back(value);
182194
}
183195

184-
ArrayRef<SingleValueInstruction *> getConstantInstructions() {
185-
return ArrayRef<SingleValueInstruction *>(constantValuedInstructions);
196+
ArrayRef<SILValue> getConstantSILValues() {
197+
return ArrayRef<SILValue>(constantSILValues);
186198
}
187199
};
188200

@@ -266,39 +278,40 @@ evaluateOrSkip(ConstExprStepEvaluator &stepEval,
266278
/// used only on string literals.
267279
/// - StructInst cannot be folded. We can only fold its arguments and not the
268280
/// 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;
272285

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) &&
275292
isIntegerOrStringType(silType, astContext));
276293
}
277294

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'.
281300
/// \returns error information for emitting diagnostics if the evaluation
282301
/// failed.
283-
static Optional<SymbolicValue>
284-
collectConstants(SILInstruction *start, SingleValueInstruction *oslogMessage,
285-
FoldState &foldState) {
302+
static Optional<SymbolicValue> collectConstants(FoldState &foldState) {
286303

287304
ConstExprStepEvaluator &constantEvaluator = foldState.constantEvaluator;
288-
SILBasicBlock::iterator currI = start->getIterator();
305+
SILBasicBlock::iterator currI = foldState.beginInstruction->getIterator();
306+
auto &endInstructions = foldState.endInstructions;
289307

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.
292310
while (true) {
293311
SILInstruction *currInst = &(*currI);
294312

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;
302315

303316
// Initialize string info from this instruction if possible.
304317
foldState.stringInfo.extractStringInfoFromInstruction(currInst);
@@ -313,17 +326,17 @@ collectConstants(SILInstruction *start, SingleValueInstruction *oslogMessage,
313326
// Set the next instruction to continue evaluation from.
314327
currI = nextI.getValue();
315328

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;
322334

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+
}
327340
}
328341
}
329342
return None; // No error.
@@ -409,27 +422,117 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal,
409422
}
410423
}
411424

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+
412503
/// Given a fold state with constant-valued instructions, substitute the
413504
/// instructions with the constant values. The constant values could be strings
414505
/// or Stdlib integer-struct values or builtin integers.
415506
static void substituteConstants(FoldState &foldState) {
416507

417508
ConstExprStepEvaluator &evaluator = foldState.constantEvaluator;
418-
419509
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();
428523
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());
430529

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.
433536
}
434537

435538
recursivelyDeleteTriviallyDeadInstructions(deletedInsts, true,
@@ -525,9 +628,12 @@ static void constantFold(SILInstruction *start,
525628
SingleValueInstruction *oslogMessage) {
526629

527630
// 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);
529635

530-
auto errorInfo = collectConstants(start, oslogMessage, state);
636+
auto errorInfo = collectConstants(state);
531637

532638
// At this point, the `OSLogMessage` instance should be mapped to a symbolic
533639
// value in the interpreter state. Furthermore, its format string and

0 commit comments

Comments
 (0)