Skip to content

Commit f2ec557

Browse files
committed
[OSLogOptimization] Improve the replaceAndFixLifetimes function
of the OSLogOptimization pass. This commit contain two changes: - It handles non-OSSA better (but it is meant to be phased out) so that array and closure folding can be supported - It fixes a bug in the OSSA folding by making sure that when an owned value replaces a guaranteed value, the owned value is borrowed and the borrow is used in place of the guaranteed value.
1 parent 63c1f84 commit f2ec557

File tree

2 files changed

+48
-15
lines changed

2 files changed

+48
-15
lines changed

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -631,25 +631,45 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
631631
"cannot constant fold a terminator instruction");
632632
assert(foldedInst && "constant value does not have a defining instruction");
633633

634-
// First, replace all uses of originalVal by foldedVal, and then adjust their
635-
// lifetimes if necessary.
636-
originalVal->replaceAllUsesWith(foldedVal);
637-
638634
if (originalVal->getType().isTrivial(*fun)) {
639635
assert(foldedVal->getType().isTrivial(*fun));
636+
// Just replace originalVal by foldedVal.
637+
originalVal->replaceAllUsesWith(foldedVal);
640638
return;
641639
}
642640
assert(!foldedVal->getType().isTrivial(*fun));
643641

644642
if (!fun->hasOwnership()) {
645643
// In non-ownership SIL, handle only folding of struct_extract instruction,
646644
// which is the only important instruction that should be folded by this
647-
// pass. Note that folding an arbitrary instruction in non-ownership SIL
648-
// makes updating reference counts of the original value much harder and
649-
// error prone.
645+
// pass. The logic used here is not correct in general and overfits a
646+
// specific form of SIL. This code should be removed once OSSA is enabled
647+
// for this pass.
650648
// TODO: this code can be safely removed once ownership SIL becomes the
651649
// default SIL this pass works on.
652-
assert(isa<StructExtractInst>(originalInst));
650+
assert(isa<StructExtractInst>(originalInst) &&
651+
!originalVal->getType().isAddress());
652+
653+
// First, replace all uses of originalVal by foldedVal, and then adjust
654+
// their lifetimes if necessary.
655+
originalVal->replaceAllUsesWith(foldedVal);
656+
657+
unsigned retainCount = 0;
658+
unsigned consumeCount = 0;
659+
for (Operand *use : foldedVal->getUses()) {
660+
SILInstruction *user = use->getUser();
661+
if (isa<ReleaseValueInst>(user) || isa<StoreInst>(user))
662+
consumeCount++;
663+
if (isa<RetainValueInst>(user))
664+
retainCount++;
665+
// Note that there could other consuming operations but they are not
666+
// handled here as this code should be phased out soon.
667+
}
668+
if (consumeCount > retainCount) {
669+
// The original value was at +1 and therefore consumed at the end. Since
670+
// the foldedVal is also at +1 there is nothing to be done.
671+
return;
672+
}
653673
cleanupAtEndOfLifetime(foldedInst, [&](SILInstruction *lifetimeEndInst) {
654674
SILBuilderWithScope builder(lifetimeEndInst);
655675
builder.emitReleaseValue(lifetimeEndInst->getLoc(), foldedVal);
@@ -661,6 +681,7 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
661681
"constant value must have owned ownership kind");
662682

663683
if (originalVal.getOwnershipKind() == ValueOwnershipKind::Owned) {
684+
originalVal->replaceAllUsesWith(foldedVal);
664685
// Destroy originalVal, which is now unused, immediately after its
665686
// definition. Note that originalVal's destorys are now transferred to
666687
// foldedVal.
@@ -671,10 +692,20 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
671692
return;
672693
}
673694

674-
// Here, originalVal is not owned. Hence, destroy foldedVal at the end of its
695+
// Here, originalVal is not owned. Hence, borrow form foldedVal and use the
696+
// borrow in place of originalVal. Also, destroy foldedVal at the end of its
675697
// lifetime.
676-
cleanupAtEndOfLifetime(foldedInst, [&](SILInstruction *lifetimeEndInst) {
698+
assert(originalVal.getOwnershipKind() == ValueOwnershipKind::Guaranteed);
699+
700+
SILBuilderWithScope builder(&*std::next(foldedInst->getIterator()));
701+
BeginBorrowInst *borrow =
702+
builder.createBeginBorrow(foldedInst->getLoc(), foldedVal);
703+
704+
originalVal->replaceAllUsesWith(borrow);
705+
706+
cleanupAtEndOfLifetime(borrow, [&](SILInstruction *lifetimeEndInst) {
677707
SILBuilderWithScope builder(lifetimeEndInst);
708+
builder.createEndBorrow(lifetimeEndInst->getLoc(), borrow);
678709
builder.emitDestroyValueOperation(lifetimeEndInst->getLoc(), foldedVal);
679710
});
680711
return;

test/SILOptimizer/OSLogPrototypeCompileTest.sil

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ bb0:
5959
return %13 : $()
6060
// CHECK-NOT: {{%.*}} = struct_extract {{%.*}} : $OSLogInterpolationStub, #OSLogInterpolationStub.formatString
6161
// CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString
62-
// CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[STRINGCONST:%[0-9]+]])
62+
// CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[BORROW:%[0-9]+]])
63+
// CHECK-DAG: [[BORROW]] = begin_borrow [[STRINGCONST:%[0-9]+]]
6364
// CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}})
6465
// CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
6566
// CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld"
@@ -175,7 +176,8 @@ bb0:
175176
// CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString
176177
// CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[BORROW:%[0-9]+]])
177178
// CHECK-DAG: [[BORROW]] = begin_borrow [[COPYVAL:%[0-9]+]]
178-
// CHECK-DAG: [[COPYVAL]] = copy_value [[STRINGCONST:%[0-9]+]]
179+
// CHECK-DAG: [[COPYVAL]] = copy_value [[BORROW2:%[0-9]+]]
180+
// CHECK-DAG: [[BORROW2]] = begin_borrow [[STRINGCONST:%[0-9]+]]
179181
// CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}})
180182
// CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
181183
// CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld"
@@ -278,7 +280,7 @@ bb1:
278280
cond_br %2, bb2, bb3
279281
// Check release of the folded value of %15.
280282
// CHECK-LABEL: bb1:
281-
// CHECK-NEXT: destroy_value [[STRINGCONST1:%[0-9]+]] : $String
283+
// CHECK: destroy_value [[STRINGCONST1:%[0-9]+]] : $String
282284

283285
bb2:
284286
%12 = apply %9(%11) : $@convention(thin) (@guaranteed String) -> ()
@@ -396,10 +398,10 @@ bb0:
396398
return %17 : $()
397399
// CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString
398400
// CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[CONSTCOPY:%[0-9]+]])
399-
// CHECK-DAG: [[CONSTCOPY]] = copy_value [[STRINGCONST:%[0-9]+]]
401+
// CHECK-DAG: [[CONSTCOPY]] = copy_value [[BORROW:%[0-9]+]]
402+
// CHECK-DAG: [[BORROW]] = begin_borrow [[STRINGCONST:%[0-9]+]]
400403
// CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}})
401404
// CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
402405
// CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld"
403406
// CHECK-DAG: destroy_value [[STRINGCONST]] : $String
404407
}
405-

0 commit comments

Comments
 (0)