Skip to content

Commit 82b7495

Browse files
committed
[NFC] SIL: Clarified deinit barrier APIs.
An instruction is a deinit barrier whenever one of three component predicates is true for it. In the case of applies, it is true whenever one of those three predicates is true for any of the instructions in any of its callees; that fact is cached in the side-effect analysis of every function. If side-effect analysis or callee analysis is unavailable, in order to define each of those three component predicates on a `FullApplySite`/`EndApplyInst`/`AbortApplyInst`, it would be necessary to define them to conservatively return true: it isn't known whether any of the instructions in any of the callees were deinit barriers. Refactored the two versions of the deinit barrier predicate (namely `Instruction.isDeinitBarrier(_:) and `swift::mayBeDeinitBarrierNotConsideringSideEffects`) to handle `FullApplySite`/`EndApplyInst`/`AbortApplyInst`s specially first (to look up the callees' side-effect and to conservatively bail, respectively). Asserted that the three component predicates are not called with `FullApplySite`/`EndApplyInst`/`AbortApplyInst`s. Callers should instead use the `isDeinitBarrier` APIs. An alternative would be to conservatively return true from the three components. That seems more likely to result in direct calls to these member predicates, however, and at the moment at least there is no reason for such calls to exist. If some other caller besides the deinit-barrier predicates needs to call this function, side-effect analysis should be updated to cache these three properties separately at that point.
1 parent f765f55 commit 82b7495

File tree

2 files changed

+40
-13
lines changed

2 files changed

+40
-13
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/CalleeAnalysis.swift

+29-9
Original file line numberDiff line numberDiff line change
@@ -98,30 +98,50 @@ public struct CalleeAnalysis {
9898
}
9999
}
100100

101-
extension FullApplySite {
101+
extension Value {
102102
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
103-
guard let callees = analysis.getCallees(callee: callee) else {
103+
guard let callees = analysis.getCallees(callee: self) else {
104104
return true
105105
}
106106
return callees.contains { $0.isDeinitBarrier }
107107
}
108108
}
109109

110-
extension Instruction {
111-
public final func maySynchronize(_ analysis: CalleeAnalysis) -> Bool {
112-
if let site = self as? FullApplySite {
113-
return site.isBarrier(analysis)
114-
}
115-
return maySynchronize
110+
extension FullApplySite {
111+
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
112+
return callee.isBarrier(analysis)
113+
}
114+
}
115+
116+
extension EndApplyInst {
117+
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
118+
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
116119
}
120+
}
121+
122+
extension AbortApplyInst {
123+
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
124+
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
125+
}
126+
}
117127

128+
extension Instruction {
118129
/// Whether lifetime ends of lexical values may safely be hoisted over this
119130
/// instruction.
120131
///
121132
/// Deinitialization barriers constrain variable lifetimes. Lexical
122133
/// end_borrow, destroy_value, and destroy_addr cannot be hoisted above them.
123134
public final func isDeinitBarrier(_ analysis: CalleeAnalysis) -> Bool {
124-
return mayAccessPointer || mayLoadWeakOrUnowned || maySynchronize(analysis)
135+
if let site = self as? FullApplySite {
136+
return site.isBarrier(analysis)
137+
}
138+
if let eai = self as? EndApplyInst {
139+
return eai.isBarrier(analysis)
140+
}
141+
if let aai = self as? AbortApplyInst {
142+
return aai.isBarrier(analysis)
143+
}
144+
return mayAccessPointer || mayLoadWeakOrUnowned || maySynchronize
125145
}
126146
}
127147

lib/SIL/Utils/MemAccessUtils.cpp

+11-4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ bool swift::isLetAddress(SILValue address) {
437437
//===----------------------------------------------------------------------===//
438438

439439
bool swift::mayAccessPointer(SILInstruction *instruction) {
440+
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
441+
!isa<AbortApplyInst>(instruction));
440442
if (!instruction->mayReadOrWriteMemory())
441443
return false;
442444
if (isa<BuiltinInst>(instruction)) {
@@ -455,6 +457,8 @@ bool swift::mayAccessPointer(SILInstruction *instruction) {
455457
}
456458

457459
bool swift::mayLoadWeakOrUnowned(SILInstruction *instruction) {
460+
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
461+
!isa<AbortApplyInst>(instruction));
458462
if (isa<BuiltinInst>(instruction)) {
459463
return instruction->mayReadOrWriteMemory();
460464
}
@@ -467,16 +471,19 @@ bool swift::mayLoadWeakOrUnowned(SILInstruction *instruction) {
467471
/// Conservatively, whether this instruction could involve a synchronization
468472
/// point like a memory barrier, lock or syscall.
469473
bool swift::maySynchronize(SILInstruction *instruction) {
474+
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
475+
!isa<AbortApplyInst>(instruction));
470476
if (isa<BuiltinInst>(instruction)) {
471477
return instruction->mayReadOrWriteMemory();
472478
}
473-
return FullApplySite::isa(instruction)
474-
|| isa<EndApplyInst>(instruction)
475-
|| isa<AbortApplyInst>(instruction)
476-
|| isa<HopToExecutorInst>(instruction);
479+
return isa<HopToExecutorInst>(instruction);
477480
}
478481

479482
bool swift::mayBeDeinitBarrierNotConsideringSideEffects(SILInstruction *instruction) {
483+
if (FullApplySite::isa(instruction) || isa<EndApplyInst>(instruction) ||
484+
isa<AbortApplyInst>(instruction)) {
485+
return true;
486+
}
480487
bool retval = mayAccessPointer(instruction)
481488
|| mayLoadWeakOrUnowned(instruction)
482489
|| maySynchronize(instruction);

0 commit comments

Comments
 (0)