blob: ced5d731ee55286c711b75cffa24bdb9e00b47fd [file] [log] [blame]
//===--- SemanticARCOptVisitor.h ------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H
#define SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H
#include "Context.h"
#include "OwnershipLiveRange.h"
#include "SemanticARCOpts.h"
#include "swift/Basic/BlotSetVector.h"
#include "swift/Basic/FrozenMultiMap.h"
#include "swift/Basic/MultiMapCache.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/ValueLifetime.h"
namespace swift {
namespace semanticarc {
/// A visitor that optimizes ownership instructions and eliminates any trivially
/// dead code that results after optimization. It uses an internal worklist that
/// is initialized on construction with targets to avoid iterator invalidation
/// issues. Rather than revisit the entire CFG like SILCombine and other
/// visitors do, we maintain a visitedSinceLastMutation list to ensure that we
/// revisit all interesting instructions in between mutations.
struct LLVM_LIBRARY_VISIBILITY SemanticARCOptVisitor
: SILValueVisitor<SemanticARCOptVisitor, bool> {
/// Our main worklist. We use this after an initial run through.
SmallBlotSetVector<SILValue, 32> worklist;
/// A set of values that we have visited since the last mutation. We use this
/// to ensure that we do not visit values twice without mutating.
///
/// This is specifically to ensure that we do not go into an infinite loop
/// when visiting phi nodes.
SmallBlotSetVector<SILValue, 16> visitedSinceLastMutation;
Context ctx;
explicit SemanticARCOptVisitor(SILFunction &fn, bool onlyGuaranteedOpts)
: ctx(fn, onlyGuaranteedOpts,
InstModCallbacks(
[this](SILInstruction *inst) { eraseInstruction(inst); },
[](SILInstruction *) {}, [](SILValue, SILValue) {},
[this](SingleValueInstruction *i, SILValue value) {
eraseAndRAUWSingleValueInstruction(i, value);
})) {}
void reset() {
ctx.reset();
worklist.clear();
visitedSinceLastMutation.clear();
}
DeadEndBlocks &getDeadEndBlocks() { return ctx.getDeadEndBlocks(); }
/// Given a single value instruction, RAUW it with newValue, add newValue to
/// the worklist, and then call eraseInstruction on i.
void eraseAndRAUWSingleValueInstruction(SingleValueInstruction *i,
SILValue newValue) {
worklist.insert(newValue);
for (auto *use : i->getUses()) {
for (SILValue result : use->getUser()->getResults()) {
worklist.insert(result);
}
}
i->replaceAllUsesWith(newValue);
eraseInstructionAndAddOperandsToWorklist(i);
}
/// Add all operands of i to the worklist and then call eraseInstruction on
/// i. Assumes that the instruction doesnt have users.
void eraseInstructionAndAddOperandsToWorklist(SILInstruction *i) {
// Then copy all operands into the worklist for future processing.
for (SILValue v : i->getOperandValues()) {
worklist.insert(v);
}
eraseInstruction(i);
}
/// Pop values off of visitedSinceLastMutation, adding .some values to the
/// worklist.
void drainVisitedSinceLastMutationIntoWorklist() {
while (!visitedSinceLastMutation.empty()) {
Optional<SILValue> nextValue = visitedSinceLastMutation.pop_back_val();
if (!nextValue.hasValue()) {
continue;
}
worklist.insert(*nextValue);
}
}
/// Remove all results of the given instruction from the worklist and then
/// erase the instruction. Assumes that the instruction does not have any
/// users left.
void eraseInstruction(SILInstruction *i) {
// Remove all SILValues of the instruction from the worklist and then erase
// the instruction.
for (SILValue result : i->getResults()) {
worklist.erase(result);
visitedSinceLastMutation.erase(result);
}
i->eraseFromParent();
// Add everything else from visitedSinceLastMutation to the worklist.
drainVisitedSinceLastMutationIntoWorklist();
}
InstModCallbacks getCallbacks() {
return InstModCallbacks(
[this](SILInstruction *inst) { eraseInstruction(inst); },
[](SILInstruction *) {}, [](SILValue, SILValue) {},
[this](SingleValueInstruction *i, SILValue value) {
eraseAndRAUWSingleValueInstruction(i, value);
});
}
bool visitSILInstruction(SILInstruction *i) {
assert((isa<OwnershipForwardingTermInst>(i) ||
!isa<OwnershipForwardingInst>(i)) &&
"Should have forwarding visitor for all ownership forwarding "
"non-term instructions");
return false;
}
/// The default visitor.
bool visitValueBase(ValueBase *v) {
auto *inst = v->getDefiningInstruction();
(void)inst;
assert((!inst || !isa<OwnershipForwardingInst>(inst)) &&
"Should have forwarding visitor for all ownership forwarding "
"instructions");
return false;
}
bool visitCopyValueInst(CopyValueInst *cvi);
bool visitBeginBorrowInst(BeginBorrowInst *bbi);
bool visitLoadInst(LoadInst *li);
bool
visitUncheckedOwnershipConversionInst(UncheckedOwnershipConversionInst *uoci);
static bool shouldVisitInst(SILInstruction *i) {
switch (i->getKind()) {
default:
return false;
case SILInstructionKind::CopyValueInst:
case SILInstructionKind::BeginBorrowInst:
case SILInstructionKind::LoadInst:
case SILInstructionKind::UncheckedOwnershipConversionInst:
return true;
}
}
#define FORWARDING_INST(NAME) \
bool visit##NAME##Inst(NAME##Inst *cls) { \
for (SILValue v : cls->getResults()) { \
worklist.insert(v); \
} \
return false; \
}
FORWARDING_INST(Tuple)
FORWARDING_INST(Object)
FORWARDING_INST(Struct)
FORWARDING_INST(Enum)
FORWARDING_INST(UncheckedValueCast)
FORWARDING_INST(ThinToThickFunction)
FORWARDING_INST(OpenExistentialRef)
FORWARDING_INST(Upcast)
FORWARDING_INST(UncheckedRefCast)
FORWARDING_INST(ConvertFunction)
FORWARDING_INST(RefToBridgeObject)
FORWARDING_INST(BridgeObjectToRef)
FORWARDING_INST(UnconditionalCheckedCast)
FORWARDING_INST(UncheckedEnumData)
FORWARDING_INST(MarkUninitialized)
FORWARDING_INST(SelectEnum)
FORWARDING_INST(SelectValue)
FORWARDING_INST(DestructureStruct)
FORWARDING_INST(DestructureTuple)
FORWARDING_INST(TupleExtract)
FORWARDING_INST(StructExtract)
FORWARDING_INST(OpenExistentialValue)
FORWARDING_INST(OpenExistentialBoxValue)
FORWARDING_INST(MarkDependence)
FORWARDING_INST(InitExistentialRef)
FORWARDING_INST(DifferentiableFunction)
FORWARDING_INST(LinearFunction)
FORWARDING_INST(DifferentiableFunctionExtract)
FORWARDING_INST(LinearFunctionExtract)
#undef FORWARDING_INST
bool processWorklist();
bool optimize();
bool optimizeWithoutFixedPoint();
bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi);
bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi);
bool tryJoiningCopyValueLiveRangeWithOperand(CopyValueInst *cvi);
bool tryPerformOwnedCopyValueOptimization(CopyValueInst *cvi);
};
} // namespace semanticarc
} // namespace swift
#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_SEMANTICARCOPTVISITOR_H