1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
//===--- 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, DeadEndBlocks &deBlocks,
bool onlyMandatoryOpts)
: ctx(fn, deBlocks, onlyMandatoryOpts,
InstModCallbacks()
.onDelete(
[this](SILInstruction *inst) { eraseInstruction(inst); })
.onSetUseValue([this](Operand *use, SILValue newValue) {
use->set(newValue);
worklist.insert(newValue);
})) {}
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()) {
std::optional<SILValue> nextValue =
visitedSinceLastMutation.pop_back_val();
if (!nextValue.has_value()) {
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 ctx.instModCallbacks; }
bool visitSILInstruction(SILInstruction *i) {
assert((isa<OwnershipForwardingTermInst>(i) ||
!ForwardingInstruction::isa(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 || !ForwardingInstruction::isa(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 visitMoveValueInst(MoveValueInst *mvi);
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::MoveValueInst:
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(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)
FORWARDING_INST(FunctionExtractIsolation)
#undef FORWARDING_INST
bool processWorklist();
bool optimize();
bool optimizeWithoutFixedPoint();
bool performLoadCopyToLoadBorrowOptimization(LoadInst *li, SILValue original);
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
|