File: Context.h

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (158 lines) | stat: -rw-r--r-- 6,047 bytes parent folder | download
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