File: OwnershipLiveRange.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 (214 lines) | stat: -rw-r--r-- 8,211 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
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
//===--- OwnershipLiveRange.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_OWNERSHIPLIVERANGE_H
#define SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H

#include "swift/SIL/OwnershipUtils.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/ValueLifetime.h"

namespace swift {
namespace semanticarc {

/// This class represents an "extended live range" of an owned value. Such a
/// representation includes:
///
/// 1. The owned introducing value.
/// 2. Any forwarding instructions that consume the introduced value
///    (transitively) and then propagate a new owned value.
/// 3. Transitive destroys on the forwarding instructions/destroys on the owned
///    introducing value.
/// 4. Any unknown consuming uses that are not understood by this code.
///
/// This allows for this to be used to convert such a set of uses from using
/// owned ownership to using guaranteed ownership by converting the
/// destroy_value -> end_borrow and "flipping" the ownership of individual
/// forwarding instructions.
///
/// NOTE: We do not look through "phi nodes" in the ownership graph (e.x.: real
/// phi arguments, struct, tuple). Instead we represent those as nodes in a
/// larger phi ownership web, connected via individual OwnershipLiveRange.
class LLVM_LIBRARY_VISIBILITY OwnershipLiveRange {
  /// The value that we are computing the LiveRange for. Expected to be an owned
  /// introducer and not to be forwarding.
  OwnedValueIntroducer introducer;

  /// A vector that we store all of our uses into.
  ///
  /// Some properties of this array are:
  ///
  /// 1. It is only mutated in the constructor of LiveRange.
  ///
  /// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are
  /// views into this array. We store the respective uses in the aforementioned
  /// order. This is why it is important not to mutate consumingUses after we
  /// construct the LiveRange since going from small -> large could invalidate
  /// the uses.
  SmallVector<Operand *, 6> consumingUses;

  /// A list of destroy_values of the live range.
  ///
  /// This is just a view into consuming uses.
  ArrayRef<Operand *> destroyingUses;

  /// A list of forwarding instructions that forward owned ownership, but that
  /// are also able to be converted to guaranteed ownership.
  ///
  /// If we are able to eliminate this LiveRange due to it being from a
  /// guaranteed value, we must flip the ownership of all of these instructions
  /// to guaranteed from owned.
  ///
  /// NOTE: Normally only destroying or consuming uses end the live range. We
  /// copy these transitive uses as well into the consumingUses array since
  /// transitive uses can extend a live range up to an unreachable block without
  /// ultimately being consuming. In such a situation if we did not also store
  /// this into consuming uses, we would not be able to ascertain just using the
  /// "consumingUses" array the true lifetime of the OwnershipLiveRange.
  ///
  /// Corresponds to isOwnershipForwardingInst(...).
  ArrayRef<Operand *> ownershipForwardingUses;

  /// Consuming uses that we were not able to understand as a forwarding
  /// instruction or a destroy_value. These must be passed a strongly control
  /// equivalent +1 value.
  ArrayRef<Operand *> unknownConsumingUses;

public:
  OwnershipLiveRange(SILValue value);
  OwnershipLiveRange(const OwnershipLiveRange &) = delete;
  OwnershipLiveRange &operator=(const OwnershipLiveRange &) = delete;

  enum class HasConsumingUse_t {
    No = 0,
    YesButAllPhiArgs = 1,
    Yes = 2,
  };

  /// Return true if v only has invalidating uses that are destroy_value. Such
  /// an owned value is said to represent a dead "live range".
  ///
  /// Semantically this implies that a value is never passed off as +1 to memory
  /// or another function implying it can be used everywhere at +0.
  HasConsumingUse_t
  hasUnknownConsumingUse(bool assumingFixedPoint = false) const;

  /// Return an array ref to /all/ consuming uses. Will include all 3 sorts of
  /// consuming uses: destroying uses, forwarding consuming uses, and unknown
  /// forwarding instruction.
  ArrayRef<Operand *> getAllConsumingUses() const { return consumingUses; }

  ArrayRef<Operand *> getDestroyingUses() const { return destroyingUses; }

  ArrayRef<Operand *> getUnknownConsumingUses() const {
    return unknownConsumingUses;
  }

private:
  struct OperandToUser;

public:
  using DestroyingInstsRange =
      TransformRange<ArrayRef<Operand *>, OperandToUser>;
  DestroyingInstsRange getDestroyingInsts() const;

  using ConsumingInstsRange =
      TransformRange<ArrayRef<Operand *>, OperandToUser>;
  ConsumingInstsRange getAllConsumingInsts() const;

  /// If this LiveRange has a single destroying use, return that use. Otherwise,
  /// return nullptr.
  Operand *getSingleDestroyingUse() const {
    if (destroyingUses.size() != 1) {
      return nullptr;
    }
    return destroyingUses.front();
  }

  /// If this LiveRange has a single unknown destroying use, return that
  /// use. Otherwise, return nullptr.
  Operand *getSingleUnknownConsumingUse() const {
    if (unknownConsumingUses.size() != 1) {
      return nullptr;
    }
    return unknownConsumingUses.front();
  }

  OwnedValueIntroducer getIntroducer() const { return introducer; }

  ArrayRef<Operand *> getOwnershipForwardingUses() const {
    return ownershipForwardingUses;
  }

  void convertOwnedGeneralForwardingUsesToGuaranteed() &&;

  /// A consuming operation that:
  ///
  /// 1. If \p insertEndBorrows is true inserts end borrows at all
  ///    destroying insts locations.
  ///
  /// 2. Deletes all destroy_values.
  ///
  /// 3. RAUW value with newGuaranteedValue.
  ///
  /// 4. Convert all of the general forwarding instructions from
  ///    @owned -> @guaranteed. "Like Dominoes".
  ///
  /// 5. Leaves all of the unknown consuming users alone. It is up to
  ///    the caller to handle converting their ownership.
  void convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
                                  InstModCallbacks callbacks) &&;

  /// A consuming operation that in order:
  ///
  /// 1. Converts the phi argument to be guaranteed via setOwnership.
  ///
  /// 2. If this consumes a borrow, insert end_borrows at the relevant
  /// destroy_values.
  ///
  /// 3. Deletes all destroy_values.
  ///
  /// 4. Converts all of the general forwarding instructions from @owned ->
  /// @guaranteed. "Like Dominoes".
  ///
  /// NOTE: This leaves all of the unknown consuming users alone. It is up to
  /// the caller to handle converting their ownership.
  ///
  /// NOTE: This routine leaves inserting begin_borrows for the incoming values
  /// to the caller since those are not part of the LiveRange itself.
  void convertJoinedLiveRangePhiToGuaranteed(
      DeadEndBlocks &deadEndBlocks, ValueLifetimeAnalysis::Frontier &scratch,
      InstModCallbacks callbacks) &&;

  /// Given a new guaranteed value, insert end_borrow for the newGuaranteedValue
  /// at all of our destroy_values in preparation for converting from owned to
  /// guaranteed.
  ///
  /// This is used when converting load [copy] -> load_borrow.
  void insertEndBorrowsAtDestroys(SILValue newGuaranteedValue,
                                  DeadEndBlocks &deadEndBlocks,
                                  ValueLifetimeAnalysis::Frontier &scratch);
};

struct OwnershipLiveRange::OperandToUser {
  OperandToUser() {}

  SILInstruction *operator()(const Operand *use) const {
    auto *nonConstUse = const_cast<Operand *>(use);
    return nonConstUse->getUser();
  }
};

} // namespace semanticarc
} // namespace swift

#endif // SWIFT_SILOPTIMIZER_SEMANTICARC_OWNERSHIPLIVERANGE_H