mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Although I don't plan to bring over new assertions wholesale into the current qualification branch, it's entirely possible that various minor changes in main will use the new assertions; having this basic support in the release branch will simplify that. (This is why I'm adding the includes as a separate pass from rewriting the individual assertions)
124 lines
4.3 KiB
C++
124 lines
4.3 KiB
C++
//===--- SemanticARCOptVisitor.cpp ----------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
///
|
|
/// Implementation of the main optimize loop of the ARC visitor peephole
|
|
/// optimizer.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SemanticARCOptVisitor.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Defer.h"
|
|
#include "swift/SIL/DebugUtils.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::semanticarc;
|
|
|
|
bool SemanticARCOptVisitor::optimizeWithoutFixedPoint() {
|
|
bool madeChange = false;
|
|
|
|
// First process the worklist until we reach a fixed point.
|
|
madeChange |= processWorklist();
|
|
|
|
return madeChange;
|
|
}
|
|
|
|
bool SemanticARCOptVisitor::optimize() {
|
|
bool madeChange = false;
|
|
|
|
// First process the worklist until we reach a fixed point.
|
|
madeChange |= processWorklist();
|
|
|
|
{
|
|
// If we made a change, set that we assume we are at fixed point and then
|
|
// re-run the worklist so that we can
|
|
// properly seeded the ARC peephole map.
|
|
ctx.assumingAtFixedPoint = true;
|
|
SWIFT_DEFER { ctx.assumingAtFixedPoint = false; };
|
|
|
|
// Add everything in visitedSinceLastMutation to the worklist so we
|
|
// recompute our fixed point.
|
|
drainVisitedSinceLastMutationIntoWorklist();
|
|
|
|
// Then re-run the worklist. We shouldn't modify anything since we are at a
|
|
// fixed point and are just using this to seed the
|
|
// joinedOwnedIntroducerToConsumedOperands after we have finished changing
|
|
// things. If we did change something, we did something weird, so assert!
|
|
bool madeAdditionalChanges = processWorklist();
|
|
(void)madeAdditionalChanges;
|
|
assert(!madeAdditionalChanges && "Should be at the fixed point");
|
|
}
|
|
|
|
return madeChange;
|
|
}
|
|
|
|
bool SemanticARCOptVisitor::processWorklist() {
|
|
// NOTE: The madeChange here is not strictly necessary since we only have
|
|
// items added to the worklist today if we have already made /some/ sort of
|
|
// change. That being said, I think there is a low cost to including this here
|
|
// and makes the algorithm more correct, visually and in the face of potential
|
|
// refactoring.
|
|
bool madeChange = false;
|
|
|
|
while (!worklist.empty()) {
|
|
// Pop the last element off the list. If we were returned None, we blotted
|
|
// this element, so skip it.
|
|
SILValue next = worklist.pop_back_val().value_or(SILValue());
|
|
if (!next)
|
|
continue;
|
|
|
|
// First check if this is a value that we have visited since the last time
|
|
// we erased an instruction. If we have visited it, skip it. Every time we
|
|
// modify something, we should be deleting an instruction, so we have not
|
|
// found any further information.
|
|
if (!visitedSinceLastMutation.insert(next).second) {
|
|
continue;
|
|
}
|
|
|
|
// First check if this is an instruction that is trivially dead. This can
|
|
// occur if we eliminate rr traffic resulting in dead projections and the
|
|
// like.
|
|
//
|
|
// If we delete, we first add all of our deleted instructions operands to
|
|
// the worklist and then remove all results (since we are going to delete
|
|
// the instruction).
|
|
if (auto *defInst = next->getDefiningInstruction()) {
|
|
if (isInstructionTriviallyDead(defInst)) {
|
|
assert(!ctx.assumingAtFixedPoint &&
|
|
"Assumed was at fixed point and recomputing state?!");
|
|
deleteAllDebugUses(defInst);
|
|
eraseInstruction(defInst);
|
|
madeChange = true;
|
|
ctx.verify();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Otherwise, if we have a single value instruction (to be expanded later
|
|
// perhaps), try to visit that value recursively.
|
|
if (auto *svi = dyn_cast<SingleValueInstruction>(next)) {
|
|
bool madeSingleChange = visit(svi);
|
|
assert((!madeSingleChange || !ctx.assumingAtFixedPoint) &&
|
|
"Assumed was at fixed point and modified state?!");
|
|
madeChange |= madeSingleChange;
|
|
if (madeSingleChange) {
|
|
ctx.verify();
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return madeChange;
|
|
}
|