Skip to content

Commit de34abe

Browse files
committed
Fix LocalVariableReachableAccess to handle potential reassignment.
Define LocalAccessInfo._isFullyAssigned to mean that the access does not read the incoming value. Then treat any assignment that isn't full as a potential read.
1 parent 6e0eeb0 commit de34abe

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,12 @@ class LocalVariableAccessInfo: CustomStringConvertible {
180180
case .beginAccess:
181181
switch (localAccess.instruction as! BeginAccessInst).accessKind {
182182
case .read, .deinit:
183-
_isFullyAssigned = .no
183+
self._isFullyAssigned = .no
184184
case .`init`, .modify:
185185
break // lazily compute full assignment
186186
}
187187
case .load, .dependenceSource, .dependenceDest:
188-
_isFullyAssigned = .no
188+
self._isFullyAssigned = .no
189189
case .store, .storeBorrow:
190190
if let store = localAccess.instruction as? StoringInstruction {
191191
self._isFullyAssigned = LocalVariableAccessInfo.isBase(address: store.destination) ? .value : .no
@@ -196,20 +196,22 @@ class LocalVariableAccessInfo: CustomStringConvertible {
196196
case .apply:
197197
// This logic is consistent with AddressInitializationWalker.appliedAddressUse()
198198
let apply = localAccess.instruction as! FullApplySite
199-
if let convention = apply.convention(of: localAccess.operand!) {
200-
if convention.isIndirectOut {
201-
self._isFullyAssigned = .value
202-
}
203-
if convention.isInout {
204-
self._isFullyAssigned = apply.fullyAssigns(operand: localAccess.operand!)
205-
}
199+
guard let convention = apply.convention(of: localAccess.operand!) else {
200+
self._isFullyAssigned = .no
201+
break
202+
}
203+
if convention.isIndirectOut {
204+
self._isFullyAssigned = .value
205+
} else if convention.isInout {
206+
self._isFullyAssigned = apply.fullyAssigns(operand: localAccess.operand!)
207+
} else {
208+
self._isFullyAssigned = .no
206209
}
207-
_isFullyAssigned = .no
208210
case .escape:
209-
_isFullyAssigned = .no
211+
self._isFullyAssigned = .no
210212
self.hasEscaped = true
211213
case .inoutYield:
212-
_isFullyAssigned = .no
214+
self._isFullyAssigned = .no
213215
case .incomingArgument, .outgoingArgument, .deadEnd:
214216
fatalError("Function arguments are never mapped to LocalVariableAccessInfo")
215217
}
@@ -222,7 +224,7 @@ class LocalVariableAccessInfo: CustomStringConvertible {
222224
var isEscape: Bool { access.isEscape }
223225

224226
/// Is this access a full assignment such that none of the variable's components are reachable from a previous
225-
/// access.
227+
/// access? Only returns '.value' if this access does not read the incoming value.
226228
func isFullyAssigned(_ context: Context) -> IsFullyAssigned {
227229
if let cached = _isFullyAssigned {
228230
return cached
@@ -232,7 +234,8 @@ class LocalVariableAccessInfo: CustomStringConvertible {
232234
}
233235
assert(isModify)
234236
let beginAccess = access.instruction as! BeginAccessInst
235-
if AddressInitializationWalker.findSingleInitializer(ofAddress: beginAccess, requireFullyAssigned: .value, context)
237+
if AddressInitializationWalker.findSingleInitializer(ofAddress: beginAccess, requireFullyAssigned: .value,
238+
allowRead: false, context)
236239
!= nil {
237240
_isFullyAssigned = .value
238241
} else if AddressInitializationWalker.findSingleInitializer(ofAddress: beginAccess,
@@ -956,7 +959,7 @@ extension LocalVariableReachableAccess {
956959
currentEffect = mode.getForwardEffect(BlockEffect(for: accessInfo, accessMap.context)).meet(currentEffect)
957960
switch currentEffect! {
958961
case .assign:
959-
if mode == .livenessUses {
962+
if mode == .livenessUses || accessInfo.isFullyAssigned(context) != .value {
960963
accessStack.push(accessInfo.access)
961964
}
962965
return currentEffect

0 commit comments

Comments
 (0)