Skip to content

Commit ba79967

Browse files
Merge pull request swiftlang#28350 from ravikandhadai/oslog-exec-test-enable
[OSLogOptimization] Fix a bug in the replaceAllUsesAndFixLifetimes function of the OSLogOptimization pass
2 parents 2fa65ae + f319f15 commit ba79967

File tree

3 files changed

+142
-270
lines changed

3 files changed

+142
-270
lines changed

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 71 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#include "swift/SIL/BasicBlockUtils.h"
8484
#include "swift/SIL/CFG.h"
8585
#include "swift/SIL/InstructionUtils.h"
86+
#include "swift/SIL/OwnershipUtils.h"
8687
#include "swift/SIL/SILBasicBlock.h"
8788
#include "swift/SIL/SILBuilder.h"
8889
#include "swift/SIL/SILConstants.h"
@@ -511,7 +512,6 @@ static SILValue emitCodeForConstantArray(ArrayRef<SILValue> elements,
511512
assert(astContext.getArrayDecl() ==
512513
arrayType->getNominalOrBoundGenericNominal());
513514
SILModule &module = builder.getModule();
514-
SILFunction &fun = builder.getFunction();
515515

516516
// Create a SILValue for the number of elements.
517517
unsigned numElements = elements.size();
@@ -539,19 +539,10 @@ static SILValue emitCodeForConstantArray(ArrayRef<SILValue> elements,
539539
loc, arrayAllocateRef, subMap, ArrayRef<SILValue>(numElementsSIL), false);
540540

541541
// Extract the elements of the tuple returned by the call to the allocator.
542-
SILValue arraySIL;
543-
SILValue storagePointerSIL;
544-
if (fun.hasOwnership()) {
545-
DestructureTupleInst *destructureInst =
546-
builder.createDestructureTuple(loc, applyInst);
547-
arraySIL = destructureInst->getResults()[0];
548-
storagePointerSIL = destructureInst->getResults()[1];
549-
} else {
550-
SILType arraySILType = SILType::getPrimitiveObjectType(arrayType);
551-
arraySIL = builder.createTupleExtract(loc, applyInst, 0, arraySILType);
552-
storagePointerSIL = builder.createTupleExtract(
553-
loc, applyInst, 1, SILType::getRawPointerType(astContext));
554-
}
542+
DestructureTupleInst *destructureInst =
543+
builder.createDestructureTuple(loc, applyInst);
544+
SILValue arraySIL = destructureInst->getResults()[0];
545+
SILValue storagePointerSIL = destructureInst->getResults()[1];
555546

556547
if (elements.empty()) {
557548
// Nothing more to be done if we are creating an empty array.
@@ -847,20 +838,21 @@ getEndPointsOfDataDependentChain(SILValue value, SILFunction *fun,
847838
}
848839
}
849840

850-
/// Given an instruction \p inst, invoke the given clean-up function \p cleanup
851-
/// on its lifetime frontier, which are instructions that follow the last use of
852-
/// the results of \c inst. E.g. the clean-up function could destory/release
853-
/// the function result.
854-
static void
855-
cleanupAtEndOfLifetime(SILInstruction *inst,
856-
llvm::function_ref<void(SILInstruction *)> cleanup) {
857-
ValueLifetimeAnalysis lifetimeAnalysis = ValueLifetimeAnalysis(inst);
858-
ValueLifetimeAnalysis::Frontier frontier;
859-
(void)lifetimeAnalysis.computeFrontier(
860-
frontier, ValueLifetimeAnalysis::AllowToModifyCFG);
861-
for (SILInstruction *lifetimeEndInst : frontier) {
862-
cleanup(lifetimeEndInst);
863-
}
841+
/// Given a guaranteed SILValue \p value, return a borrow-scope introducing
842+
/// value, if there is exactly one such introducing value. Otherwise, return
843+
/// None. There can be multiple borrow scopes for a SILValue iff it is derived
844+
/// from a guaranteed basic block parameter representing a phi node.
845+
static Optional<BorrowScopeIntroducingValue>
846+
getUniqueBorrowScopeIntroducingValue(SILValue value) {
847+
assert(value.getOwnershipKind() == ValueOwnershipKind::Guaranteed &&
848+
"parameter must be a guarenteed value");
849+
SmallVector<BorrowScopeIntroducingValue, 4> borrowIntroducers;
850+
getUnderlyingBorrowIntroducingValues(value, borrowIntroducers);
851+
assert(borrowIntroducers.size() > 0 &&
852+
"folding guaranteed value with no borrow introducer");
853+
if (borrowIntroducers.size() > 1)
854+
return None;
855+
return borrowIntroducers[0];
864856
}
865857

866858
/// Replace all uses of \c originalVal by \c foldedVal and adjust lifetimes of
@@ -889,45 +881,7 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
889881
return;
890882
}
891883
assert(!foldedVal->getType().isTrivial(*fun));
892-
893-
if (!fun->hasOwnership()) {
894-
// In non-ownership SIL, handle only folding of struct_extract instruction,
895-
// which is the only important instruction that should be folded by this
896-
// pass. The logic used here is not correct in general and overfits a
897-
// specific form of SIL. This code should be removed once OSSA is enabled
898-
// for this pass.
899-
// TODO: this code can be safely removed once ownership SIL becomes the
900-
// default SIL this pass works on.
901-
assert(isa<StructExtractInst>(originalInst) &&
902-
!originalVal->getType().isAddress());
903-
904-
// First, replace all uses of originalVal by foldedVal, and then adjust
905-
// their lifetimes if necessary.
906-
originalVal->replaceAllUsesWith(foldedVal);
907-
908-
unsigned retainCount = 0;
909-
unsigned consumeCount = 0;
910-
for (Operand *use : foldedVal->getUses()) {
911-
SILInstruction *user = use->getUser();
912-
if (isa<ReleaseValueInst>(user) || isa<StoreInst>(user))
913-
consumeCount++;
914-
if (isa<RetainValueInst>(user))
915-
retainCount++;
916-
// Note that there could other consuming operations but they are not
917-
// handled here as this code should be phased out soon.
918-
}
919-
if (consumeCount > retainCount) {
920-
// The original value was at +1 and therefore consumed at the end. Since
921-
// the foldedVal is also at +1 there is nothing to be done.
922-
return;
923-
}
924-
cleanupAtEndOfLifetime(foldedInst, [&](SILInstruction *lifetimeEndInst) {
925-
SILBuilderWithScope builder(lifetimeEndInst);
926-
builder.emitReleaseValue(lifetimeEndInst->getLoc(), foldedVal);
927-
});
928-
return;
929-
}
930-
884+
assert(fun->hasOwnership());
931885
assert(foldedVal.getOwnershipKind() == ValueOwnershipKind::Owned &&
932886
"constant value must have owned ownership kind");
933887

@@ -943,22 +897,36 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal,
943897
return;
944898
}
945899

946-
// Here, originalVal is not owned. Hence, borrow form foldedVal and use the
947-
// borrow in place of originalVal. Also, destroy foldedVal at the end of its
948-
// lifetime.
900+
// Here, originalVal is guaranteed. It must belong to a borrow scope that
901+
// begins at a scope introducing instruction e.g. begin_borrow or load_borrow.
902+
// The foldedVal should also have been inserted at the beginning of the scope.
903+
// Therefore, create a borrow of foldedVal at the beginning of the scope and
904+
// use the borrow in place of the originalVal. Also, end the borrow and
905+
// destroy foldedVal at the end of the borrow scope.
949906
assert(originalVal.getOwnershipKind() == ValueOwnershipKind::Guaranteed);
950907

951-
SILBuilderWithScope builder(&*std::next(foldedInst->getIterator()));
952-
BeginBorrowInst *borrow =
953-
builder.createBeginBorrow(foldedInst->getLoc(), foldedVal);
908+
Optional<BorrowScopeIntroducingValue> originalScopeBegin =
909+
getUniqueBorrowScopeIntroducingValue(originalVal);
910+
assert(originalScopeBegin &&
911+
"value without a unique borrow scope should not have been folded");
912+
SILInstruction *scopeBeginInst =
913+
originalScopeBegin->value->getDefiningInstruction();
914+
assert(scopeBeginInst);
915+
916+
SILBuilderWithScope builder(scopeBeginInst);
917+
SILValue borrow =
918+
builder.emitBeginBorrowOperation(scopeBeginInst->getLoc(), foldedVal);
954919

955920
originalVal->replaceAllUsesWith(borrow);
956921

957-
cleanupAtEndOfLifetime(borrow, [&](SILInstruction *lifetimeEndInst) {
958-
SILBuilderWithScope builder(lifetimeEndInst);
959-
builder.createEndBorrow(lifetimeEndInst->getLoc(), borrow);
960-
builder.emitDestroyValueOperation(lifetimeEndInst->getLoc(), foldedVal);
961-
});
922+
SmallVector<SILInstruction *, 4> scopeEndingInsts;
923+
originalScopeBegin->getLocalScopeEndingInstructions(scopeEndingInsts);
924+
925+
for (SILInstruction *scopeEndingInst : scopeEndingInsts) {
926+
SILBuilderWithScope builder(scopeEndingInst);
927+
builder.emitEndBorrowOperation(scopeEndingInst->getLoc(), borrow);
928+
builder.emitDestroyValueOperation(scopeEndingInst->getLoc(), foldedVal);
929+
}
962930
return;
963931
}
964932

@@ -978,13 +946,31 @@ static void substituteConstants(FoldState &foldState) {
978946
assert(definingInst);
979947
SILFunction *fun = definingInst->getFunction();
980948

981-
// Do not attempt to fold anything but struct_extract in non-OSSA.
982-
// TODO: this condition should be removed once migration OSSA is complete.
983-
if (!fun->hasOwnership() && !isa<StructExtractInst>(definingInst))
984-
continue;
949+
// Find an insertion point for inserting the new constant value. If we are
950+
// folding a value like struct_extract within a borrow scope, we need to
951+
// insert the constant value at the beginning of the borrow scope. This
952+
// is because the borrowed value is expected to be alive during its entire
953+
// borrow scope and could be stored into memory and accessed indirectly
954+
// without a copy e.g. using store_borrow within the borrow scope. On the
955+
// other hand, if we are folding an owned value, we can insert the constant
956+
// value at the point where the owned value is defined.
957+
SILInstruction *insertionPoint = definingInst;
958+
if (constantSILValue.getOwnershipKind() == ValueOwnershipKind::Guaranteed) {
959+
Optional<BorrowScopeIntroducingValue> borrowIntroducer =
960+
getUniqueBorrowScopeIntroducingValue(constantSILValue);
961+
if (!borrowIntroducer) {
962+
// This case happens only if constantSILValue is derived from a
963+
// guaranteed basic block parameter. This is unlikley because the values
964+
// that have to be folded should just be a struct-extract of an owned
965+
// instance of OSLogMessage.
966+
continue;
967+
}
968+
insertionPoint = borrowIntroducer->value->getDefiningInstruction();
969+
assert(insertionPoint && "borrow scope begnning is a parameter");
970+
}
985971

986-
SILBuilderWithScope builder(definingInst);
987-
SILLocation loc = definingInst->getLoc();
972+
SILBuilderWithScope builder(insertionPoint);
973+
SILLocation loc = insertionPoint->getLoc();
988974
CanType instType = constantSILValue->getType().getASTType();
989975
SILValue foldedSILVal = emitCodeForSymbolicValue(
990976
constantSymbolicVal, instType, builder, loc, foldState.stringInfo);
@@ -1068,6 +1054,7 @@ static bool constantFold(SILInstruction *start,
10681054
SingleValueInstruction *oslogMessage,
10691055
unsigned assertConfig) {
10701056
SILFunction *fun = start->getFunction();
1057+
assert(fun->hasOwnership() && "function not in ownership SIL");
10711058

10721059
// Initialize fold state.
10731060
SmallVector<SILInstruction *, 2> endUsersOfOSLogMessage;

0 commit comments

Comments
 (0)