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
|
//===--- Context.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_CONTEXT_H
#define SWIFT_SILOPTIMIZER_SEMANTICARC_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"
#include "llvm/Support/Compiler.h"
namespace swift {
namespace semanticarc {
struct LLVM_LIBRARY_VISIBILITY Context {
SILFunction &fn;
ARCTransformKind transformKind = ARCTransformKind::All;
DeadEndBlocks &deadEndBlocks;
ValueLifetimeAnalysis::Frontier lifetimeFrontier;
SmallMultiMapCache<SILValue, Operand *> addressToExhaustiveWriteListCache;
/// Are we assuming that we reached a fix point and are re-processing to
/// prepare to use the phiToIncomingValueMultiMap.
bool assumingAtFixedPoint = false;
/// A map from a value that acts as a "joined owned introducer" in the def-use
/// graph.
///
/// A "joined owned introducer" is a value with owned ownership whose
/// ownership is derived from multiple non-trivial owned operands of a related
/// instruction. Some examples are phi arguments, tuples, structs. Naturally,
/// all of these instructions must be non-unary instructions and only have
/// this property if they have multiple operands that are non-trivial.
///
/// In such a case, we can not just treat them like normal forwarding concepts
/// since we can only eliminate optimize such a value if we are able to reason
/// about all of its operands together jointly. This is not amenable to a
/// small peephole analysis.
///
/// Instead, as we perform the peephole analysis, using the multimap, we map
/// each joined owned value introducer to the set of its @owned operands that
/// we thought we could convert to guaranteed only if we could do the same to
/// the joined owned value introducer. Then once we finish performing
/// peepholes, we iterate through the map and see if any of our joined phi
/// ranges had all of their operand's marked with this property by iterating
/// over the multimap. Since we are dealing with owned values and we know that
/// our LiveRange can not see through joined live ranges, we know that we
/// should only be able to have a single owned value introducer for each
/// consumed operand.
///
/// NOTE: To work around potential invalidation of our consuming operands when
/// adding values to edges on the CFG, we store our Operands as a
/// SILBasicBlock and an operand number. We only add values to edges and never
/// remove/modify edges so the operand number should be safe.
struct ConsumingOperandState {
PointerUnion<SILBasicBlock *, SILInstruction *> parent;
unsigned operandNumber;
ConsumingOperandState() : parent(nullptr), operandNumber(UINT_MAX) {}
ConsumingOperandState(Operand *op)
: parent(), operandNumber(op->getOperandNumber()) {
if (auto *ti = dyn_cast<TermInst>(op->getUser())) {
parent = ti->getParent();
} else {
parent = op->getUser();
}
}
ConsumingOperandState(const ConsumingOperandState &other) :
parent(other.parent), operandNumber(other.operandNumber) {}
ConsumingOperandState &operator=(const ConsumingOperandState &other) {
parent = other.parent;
operandNumber = other.operandNumber;
return *this;
}
~ConsumingOperandState() = default;
operator bool() const {
return bool(parent) && operandNumber != UINT_MAX;
}
};
FrozenMultiMap<SILValue, ConsumingOperandState>
joinedOwnedIntroducerToConsumedOperands;
/// If set to true, then we should only run cheap optimizations that do not
/// build up data structures or analyze code in depth.
///
/// As an example, we do not do load [copy] optimizations here since they
/// generally involve more complex analysis, but simple peepholes of
/// copy_values we /do/ allow.
bool onlyMandatoryOpts;
/// Callbacks that we must use to remove or RAUW values.
InstModCallbacks instModCallbacks;
using FrozenMultiMapRange =
decltype(joinedOwnedIntroducerToConsumedOperands)::PairToSecondEltRange;
DeadEndBlocks &getDeadEndBlocks() { return deadEndBlocks; }
Context(SILFunction &fn, DeadEndBlocks &deBlocks, bool onlyMandatoryOpts,
InstModCallbacks callbacks)
: fn(fn), deadEndBlocks(deBlocks), lifetimeFrontier(),
addressToExhaustiveWriteListCache(constructCacheValue),
onlyMandatoryOpts(onlyMandatoryOpts), instModCallbacks(callbacks) {}
void verify() const;
bool shouldPerform(ARCTransformKind testKind) const {
// When asserts are enabled, we allow for specific arc transforms to be
// turned on/off via LLVM args. So check that if we have asserts, perform
// all optimizations otherwise.
#ifndef NDEBUG
if (transformKind == ARCTransformKind::Invalid)
return false;
return bool(testKind & transformKind);
#else
return true;
#endif
}
void reset() {
lifetimeFrontier.clear();
addressToExhaustiveWriteListCache.clear();
joinedOwnedIntroducerToConsumedOperands.reset();
}
private:
static bool
constructCacheValue(SILValue initialValue,
SmallVectorImpl<Operand *> &wellBehavedWriteAccumulator);
};
} // namespace semanticarc
} // namespace swift
#endif
|