Skip to content

Commit fbec126

Browse files
authored
Merge pull request swiftlang#30188 from gottesmm/pr-24ee27844856cfe5e2af48e29b5fb48d33fe3a99
2 parents 261e9e4 + 847ad07 commit fbec126

File tree

9 files changed

+205
-164
lines changed

9 files changed

+205
-164
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
//===--- LinearLifetimeChecker.h ------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SIL_LINEARLIFETIMECHECKER_H
14+
#define SWIFT_SIL_LINEARLIFETIMECHECKER_H
15+
16+
#include "swift/Basic/Debug.h"
17+
#include "swift/Basic/LLVM.h"
18+
#include "swift/SIL/BranchPropagatedUser.h"
19+
#include "swift/SIL/SILArgument.h"
20+
#include "swift/SIL/SILInstruction.h"
21+
#include "swift/SIL/SILValue.h"
22+
#include "llvm/ADT/SmallPtrSet.h"
23+
#include "llvm/ADT/SmallVector.h"
24+
25+
namespace swift {
26+
27+
class SILBasicBlock;
28+
class SILInstruction;
29+
class SILModule;
30+
class SILValue;
31+
class DeadEndBlocks;
32+
class BranchPropagatedUser;
33+
34+
namespace ownership {
35+
36+
struct ErrorBehaviorKind {
37+
enum inner_t {
38+
Invalid = 0,
39+
ReturnFalse = 1,
40+
PrintMessage = 2,
41+
Assert = 4,
42+
ReturnFalseOnLeak = 8,
43+
PrintMessageAndReturnFalse = PrintMessage | ReturnFalse,
44+
PrintMessageAndAssert = PrintMessage | Assert,
45+
ReturnFalseOnLeakAssertOtherwise = ReturnFalseOnLeak | Assert,
46+
} Value;
47+
48+
ErrorBehaviorKind() : Value(Invalid) {}
49+
ErrorBehaviorKind(inner_t Inner) : Value(Inner) { assert(Value != Invalid); }
50+
51+
bool shouldAssert() const {
52+
assert(Value != Invalid);
53+
return Value & Assert;
54+
}
55+
56+
bool shouldReturnFalseOnLeak() const {
57+
assert(Value != Invalid);
58+
return Value & ReturnFalseOnLeak;
59+
}
60+
61+
bool shouldPrintMessage() const {
62+
assert(Value != Invalid);
63+
return Value & PrintMessage;
64+
}
65+
66+
bool shouldReturnFalse() const {
67+
assert(Value != Invalid);
68+
return Value & ReturnFalse;
69+
}
70+
};
71+
72+
} // end namespace ownership
73+
74+
class LinearLifetimeError {
75+
ownership::ErrorBehaviorKind errorBehavior;
76+
bool foundUseAfterFree = false;
77+
bool foundLeak = false;
78+
bool foundOverConsume = false;
79+
80+
public:
81+
LinearLifetimeError(ownership::ErrorBehaviorKind errorBehavior)
82+
: errorBehavior(errorBehavior) {}
83+
84+
bool getFoundError() const {
85+
return foundUseAfterFree || foundLeak || foundOverConsume;
86+
}
87+
88+
bool getFoundLeak() const { return foundLeak; }
89+
90+
bool getFoundUseAfterFree() const { return foundUseAfterFree; }
91+
92+
bool getFoundOverConsume() const { return foundOverConsume; }
93+
94+
void handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) {
95+
foundLeak = true;
96+
97+
if (errorBehavior.shouldPrintMessage())
98+
messagePrinterFunc();
99+
100+
if (errorBehavior.shouldReturnFalseOnLeak())
101+
return;
102+
103+
// We already printed out our error if we needed to, so don't pass it along.
104+
handleError([]() {});
105+
}
106+
107+
void handleOverConsume(llvm::function_ref<void()> &&messagePrinterFunc) {
108+
foundOverConsume = true;
109+
handleError(std::move(messagePrinterFunc));
110+
}
111+
112+
void handleUseAfterFree(llvm::function_ref<void()> &&messagePrinterFunc) {
113+
foundUseAfterFree = true;
114+
handleError(std::move(messagePrinterFunc));
115+
}
116+
117+
private:
118+
void handleError(llvm::function_ref<void()> &&messagePrinterFunc) {
119+
if (errorBehavior.shouldPrintMessage())
120+
messagePrinterFunc();
121+
122+
if (errorBehavior.shouldReturnFalse()) {
123+
return;
124+
}
125+
126+
assert(errorBehavior.shouldAssert() && "At this point, we should assert");
127+
llvm_unreachable("triggering standard assertion failure routine");
128+
}
129+
};
130+
131+
/// A class used to validate linear lifetime with respect to an SSA-like
132+
/// definition.
133+
///
134+
/// This class is able to both validate that a linear lifetime has been properly
135+
/// constructed (for verification and safety purposes) as well as return to the
136+
/// caller upon failure, what the failure was. In certain cases (for instance if
137+
/// there exists a path without a non-consuming use), the class will report back
138+
/// the specific insertion points needed to insert these compensating releases.
139+
///
140+
/// DISCUSSION: A linear lifetime consists of a starting block or instruction
141+
/// and a list of non-consuming uses and a set of consuming uses. The consuming
142+
/// uses must not be reachable from each other and jointly post-dominate all
143+
/// consuming uses as well as the defining block/instruction.
144+
class LinearLifetimeChecker {
145+
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
146+
DeadEndBlocks &deadEndBlocks;
147+
148+
public:
149+
LinearLifetimeChecker(SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
150+
DeadEndBlocks &deadEndBlocks)
151+
: visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {}
152+
153+
/// Returns true if:
154+
///
155+
/// 1. No consuming uses are reachable from any other consuming use, from any
156+
/// non-consuming uses, or from the producer instruction.
157+
/// 2. The consuming use set jointly post dominates producers and all non
158+
/// consuming uses.
159+
///
160+
/// Returns false otherwise.
161+
///
162+
/// \p value The value whose lifetime we are checking.
163+
/// \p consumingUses the array of users that destroy or consume a value.
164+
/// \p nonConsumingUses regular uses
165+
/// \p errorBehavior If we detect an error, should we return false or hard
166+
/// error.
167+
/// \p leakingBlocks If non-null a list of blocks where the value was detected
168+
/// to leak. Can be used to insert missing destroys.
169+
LinearLifetimeError
170+
checkValue(SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
171+
ArrayRef<BranchPropagatedUser> nonConsumingUses,
172+
ownership::ErrorBehaviorKind errorBehavior,
173+
SmallVectorImpl<SILBasicBlock *> *leakingBlocks = nullptr);
174+
175+
/// Returns true that \p value forms a linear lifetime with consuming uses \p
176+
/// consumingUses, non consuming uses \p nonConsumingUses. Returns false
177+
/// otherwise.
178+
bool validateLifetime(SILValue value,
179+
ArrayRef<BranchPropagatedUser> consumingUses,
180+
ArrayRef<BranchPropagatedUser> nonConsumingUses) {
181+
return !checkValue(value, consumingUses, nonConsumingUses,
182+
ownership::ErrorBehaviorKind::ReturnFalse,
183+
nullptr /*leakingBlocks*/)
184+
.getFoundError();
185+
}
186+
187+
bool validateLifetime(SILValue value,
188+
ArrayRef<SILInstruction *> consumingUses,
189+
ArrayRef<SILInstruction *> nonConsumingUses) {
190+
return validateLifetime(
191+
value, BranchPropagatedUser::convertFromInstArray(consumingUses),
192+
BranchPropagatedUser::convertFromInstArray(nonConsumingUses));
193+
}
194+
};
195+
196+
} // namespace swift
197+
198+
#endif

include/swift/SIL/OwnershipUtils.h

Lines changed: 0 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
#include "swift/Basic/Debug.h"
1717
#include "swift/Basic/LLVM.h"
18-
#include "swift/SIL/BranchPropagatedUser.h"
1918
#include "swift/SIL/SILArgument.h"
2019
#include "swift/SIL/SILInstruction.h"
2120
#include "swift/SIL/SILValue.h"
@@ -29,169 +28,6 @@ class SILInstruction;
2928
class SILModule;
3029
class SILValue;
3130
class DeadEndBlocks;
32-
class BranchPropagatedUser;
33-
34-
namespace ownership {
35-
36-
struct ErrorBehaviorKind {
37-
enum inner_t {
38-
Invalid = 0,
39-
ReturnFalse = 1,
40-
PrintMessage = 2,
41-
Assert = 4,
42-
ReturnFalseOnLeak = 8,
43-
PrintMessageAndReturnFalse = PrintMessage | ReturnFalse,
44-
PrintMessageAndAssert = PrintMessage | Assert,
45-
ReturnFalseOnLeakAssertOtherwise = ReturnFalseOnLeak | Assert,
46-
} Value;
47-
48-
ErrorBehaviorKind() : Value(Invalid) {}
49-
ErrorBehaviorKind(inner_t Inner) : Value(Inner) { assert(Value != Invalid); }
50-
51-
bool shouldAssert() const {
52-
assert(Value != Invalid);
53-
return Value & Assert;
54-
}
55-
56-
bool shouldReturnFalseOnLeak() const {
57-
assert(Value != Invalid);
58-
return Value & ReturnFalseOnLeak;
59-
}
60-
61-
bool shouldPrintMessage() const {
62-
assert(Value != Invalid);
63-
return Value & PrintMessage;
64-
}
65-
66-
bool shouldReturnFalse() const {
67-
assert(Value != Invalid);
68-
return Value & ReturnFalse;
69-
}
70-
};
71-
72-
} // end namespace ownership
73-
74-
class LinearLifetimeError {
75-
ownership::ErrorBehaviorKind errorBehavior;
76-
bool foundUseAfterFree = false;
77-
bool foundLeak = false;
78-
bool foundOverConsume = false;
79-
80-
public:
81-
LinearLifetimeError(ownership::ErrorBehaviorKind errorBehavior)
82-
: errorBehavior(errorBehavior) {}
83-
84-
bool getFoundError() const {
85-
return foundUseAfterFree || foundLeak || foundOverConsume;
86-
}
87-
88-
bool getFoundLeak() const { return foundLeak; }
89-
90-
bool getFoundUseAfterFree() const { return foundUseAfterFree; }
91-
92-
bool getFoundOverConsume() const { return foundOverConsume; }
93-
94-
void handleLeak(llvm::function_ref<void()> &&messagePrinterFunc) {
95-
foundLeak = true;
96-
97-
if (errorBehavior.shouldPrintMessage())
98-
messagePrinterFunc();
99-
100-
if (errorBehavior.shouldReturnFalseOnLeak())
101-
return;
102-
103-
// We already printed out our error if we needed to, so don't pass it along.
104-
handleError([]() {});
105-
}
106-
107-
void handleOverConsume(llvm::function_ref<void()> &&messagePrinterFunc) {
108-
foundOverConsume = true;
109-
handleError(std::move(messagePrinterFunc));
110-
}
111-
112-
void handleUseAfterFree(llvm::function_ref<void()> &&messagePrinterFunc) {
113-
foundUseAfterFree = true;
114-
handleError(std::move(messagePrinterFunc));
115-
}
116-
117-
private:
118-
void handleError(llvm::function_ref<void()> &&messagePrinterFunc) {
119-
if (errorBehavior.shouldPrintMessage())
120-
messagePrinterFunc();
121-
122-
if (errorBehavior.shouldReturnFalse()) {
123-
return;
124-
}
125-
126-
assert(errorBehavior.shouldAssert() && "At this point, we should assert");
127-
llvm_unreachable("triggering standard assertion failure routine");
128-
}
129-
};
130-
131-
/// A class used to validate linear lifetime with respect to an SSA-like
132-
/// definition.
133-
///
134-
/// This class is able to both validate that a linear lifetime has been properly
135-
/// constructed (for verification and safety purposes) as well as return to the
136-
/// caller upon failure, what the failure was. In certain cases (for instance if
137-
/// there exists a path without a non-consuming use), the class will report back
138-
/// the specific insertion points needed to insert these compensating releases.
139-
///
140-
/// DISCUSSION: A linear lifetime consists of a starting block or instruction
141-
/// and a list of non-consuming uses and a set of consuming uses. The consuming
142-
/// uses must not be reachable from each other and jointly post-dominate all
143-
/// consuming uses as well as the defining block/instruction.
144-
class LinearLifetimeChecker {
145-
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks;
146-
DeadEndBlocks &deadEndBlocks;
147-
148-
public:
149-
LinearLifetimeChecker(SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
150-
DeadEndBlocks &deadEndBlocks)
151-
: visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {}
152-
153-
/// Returns true if:
154-
///
155-
/// 1. No consuming uses are reachable from any other consuming use, from any
156-
/// non-consuming uses, or from the producer instruction.
157-
/// 2. The consuming use set jointly post dominates producers and all non
158-
/// consuming uses.
159-
///
160-
/// Returns false otherwise.
161-
///
162-
/// \p value The value whose lifetime we are checking.
163-
/// \p consumingUses the array of users that destroy or consume a value.
164-
/// \p nonConsumingUses regular uses
165-
/// \p errorBehavior If we detect an error, should we return false or hard
166-
/// error.
167-
/// \p leakingBlocks If non-null a list of blocks where the value was detected
168-
/// to leak. Can be used to insert missing destroys.
169-
LinearLifetimeError
170-
checkValue(SILValue value, ArrayRef<BranchPropagatedUser> consumingUses,
171-
ArrayRef<BranchPropagatedUser> nonConsumingUses,
172-
ownership::ErrorBehaviorKind errorBehavior,
173-
SmallVectorImpl<SILBasicBlock *> *leakingBlocks = nullptr);
174-
175-
/// Returns true that \p value forms a linear lifetime with consuming uses \p
176-
/// consumingUses, non consuming uses \p nonConsumingUses. Returns false
177-
/// otherwise.
178-
bool validateLifetime(SILValue value,
179-
ArrayRef<BranchPropagatedUser> consumingUses,
180-
ArrayRef<BranchPropagatedUser> nonConsumingUses) {
181-
return !checkValue(value, consumingUses, nonConsumingUses,
182-
ownership::ErrorBehaviorKind::ReturnFalse,
183-
nullptr /*leakingBlocks*/)
184-
.getFoundError();
185-
}
186-
187-
bool validateLifetime(SILValue value,
188-
ArrayRef<SILInstruction *> consumingUses,
189-
ArrayRef<SILInstruction *> nonConsumingUses) {
190-
return validateLifetime(
191-
value, BranchPropagatedUser::convertFromInstArray(consumingUses),
192-
BranchPropagatedUser::convertFromInstArray(nonConsumingUses));
193-
}
194-
};
19531

19632
/// Returns true if v is an address or trivial.
19733
bool isValueAddressOrTrivial(SILValue v);

lib/SIL/LinearLifetimeChecker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
//===----------------------------------------------------------------------===//
2222

2323
#define DEBUG_TYPE "sil-linear-lifetime-checker"
24+
#include "swift/SIL/LinearLifetimeChecker.h"
2425
#include "swift/SIL/BasicBlockUtils.h"
2526
#include "swift/SIL/BranchPropagatedUser.h"
2627
#include "swift/SIL/OwnershipUtils.h"

lib/SIL/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/ApplySite.h"
14+
#include "swift/SIL/LinearLifetimeChecker.h"
1415
#include "swift/SIL/OwnershipUtils.h"
1516
#include "swift/SIL/SILBuiltinVisitor.h"
1617
#include "swift/SIL/SILInstruction.h"

0 commit comments

Comments
 (0)