| //===--- 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/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().getValueOr(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; |
| } |