@@ -239,6 +239,13 @@ struct EscapeUtilityTypes {
239239 ///
240240 let followStores : Bool
241241
242+ /// Set to true if an address is stored.
243+ /// This unusual situation can happen if an address is converted to a raw pointer and that pointer
244+ /// is stored to a memory location.
245+ /// In this case the walkers need to follow load instructions even if the visitor and current projection
246+ /// path don't say so.
247+ let addressIsStored : Bool
248+
242249 /// Not nil, if the exact type of the current value is know.
243250 ///
244251 /// This is used for destructor analysis.
@@ -251,20 +258,29 @@ struct EscapeUtilityTypes {
251258 let knownType : Type ?
252259
253260 func with( projectionPath: SmallProjectionPath ) -> Self {
254- return Self ( projectionPath: projectionPath, followStores: self . followStores, knownType: self . knownType)
261+ return Self ( projectionPath: projectionPath, followStores: self . followStores,
262+ addressIsStored: self . addressIsStored, knownType: self . knownType)
255263 }
256264
257265 func with( followStores: Bool ) -> Self {
258- return Self ( projectionPath: self . projectionPath, followStores: followStores, knownType: self . knownType)
266+ return Self ( projectionPath: self . projectionPath, followStores: followStores,
267+ addressIsStored: self . addressIsStored, knownType: self . knownType)
259268 }
260269
270+ func with( addressStored: Bool ) -> Self {
271+ return Self ( projectionPath: self . projectionPath, followStores: self . followStores, addressIsStored: addressStored,
272+ knownType: self . knownType)
273+ }
274+
261275 func with( knownType: Type ? ) -> Self {
262- return Self ( projectionPath: self . projectionPath, followStores: self . followStores, knownType: knownType)
276+ return Self ( projectionPath: self . projectionPath, followStores: self . followStores,
277+ addressIsStored: self . addressIsStored, knownType: knownType)
263278 }
264279
265280 func merge( with other: EscapePath ) -> EscapePath {
266281 let mergedPath = self . projectionPath. merge ( with: other. projectionPath)
267282 let mergedFollowStores = self . followStores || other. followStores
283+ let mergedAddrStored = self . addressIsStored || other. addressIsStored
268284 let mergedKnownType : Type ?
269285 if let ty = self . knownType {
270286 if let otherTy = other. knownType, ty != otherTy {
@@ -275,7 +291,8 @@ struct EscapeUtilityTypes {
275291 } else {
276292 mergedKnownType = other. knownType
277293 }
278- return EscapePath ( projectionPath: mergedPath, followStores: mergedFollowStores, knownType: mergedKnownType)
294+ return EscapePath ( projectionPath: mergedPath, followStores: mergedFollowStores,
295+ addressIsStored: mergedAddrStored, knownType: mergedKnownType)
279296 }
280297 }
281298
@@ -362,7 +379,10 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
362379 }
363380 case is StoreInst , is StoreWeakInst , is StoreUnownedInst :
364381 let store = instruction as! StoringInstruction
365- assert ( operand == store. sourceOperand )
382+ assert ( operand == store. sourceOperand)
383+ if !followLoads( at: path) {
384+ return walkUp ( address: store. destination, path: path. with ( addressStored: true ) )
385+ }
366386 return walkUp ( address: store. destination, path: path)
367387 case is DestroyValueInst , is ReleaseValueInst , is StrongReleaseInst :
368388 if handleDestroy ( of: operand. value, path: path) == . abortWalk {
@@ -456,7 +476,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
456476 return walkUp ( value: store. source, path: path)
457477 }
458478 case let copyAddr as CopyAddrInst :
459- if !followLoads( at: path. projectionPath ) {
479+ if !followLoads( at: path) {
460480 return . continueWalk
461481 }
462482 if operand == copyAddr. sourceOperand {
@@ -491,7 +511,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
491511 // 2. something can escape in a destructor when the context is destroyed
492512 return walkDownUses ( ofValue: pai, path: path. with ( knownType: nil ) )
493513 case is LoadInst , is LoadWeakInst , is LoadUnownedInst , is LoadBorrowInst :
494- if !followLoads( at: path. projectionPath ) {
514+ if !followLoads( at: path) {
495515 return . continueWalk
496516 }
497517 let svi = instruction as! SingleValueInstruction
@@ -561,7 +581,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
561581 }
562582
563583 // Indirect arguments cannot escape the function, but loaded values from such can.
564- if !followLoads( at: path. projectionPath ) &&
584+ if !followLoads( at: path) &&
565585 // Except for begin_apply: it can yield an address value.
566586 !apply. isBeginApplyWithIndirectResults {
567587 return . continueWalk
@@ -622,7 +642,8 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
622642 // Continue at the destination of an arg-to-arg escape.
623643 let arg = argOp. value
624644
625- let p = Path ( projectionPath: toPath, followStores: false , knownType: nil )
645+ let p = Path ( projectionPath: toPath, followStores: false , addressIsStored: argPath. addressIsStored,
646+ knownType: nil )
626647 if walkUp ( addressOrValue: arg, path: p) == . abortWalk {
627648 return . abortWalk
628649 }
@@ -634,8 +655,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
634655 return isEscaping
635656 }
636657
637- let p = Path ( projectionPath: toPath, followStores: false , knownType: exclusive ? argPath. knownType : nil )
638-
658+ let p = Path ( projectionPath: toPath, followStores: false , addressIsStored: argPath. addressIsStored,
659+ knownType: exclusive ? argPath. knownType : nil )
660+
639661 if walkDownUses ( ofValue: result, path: p) == . abortWalk {
640662 return . abortWalk
641663 }
@@ -700,7 +722,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
700722 case let ap as ApplyInst :
701723 return walkUpApplyResult ( apply: ap, path: path. with ( knownType: nil ) )
702724 case is LoadInst , is LoadWeakInst , is LoadUnownedInst , is LoadBorrowInst :
703- if !followLoads( at: path. projectionPath ) {
725+ if !followLoads( at: path) {
704726 // When walking up we shouldn't end up at a load where followLoads is false,
705727 // because going from a (non-followLoads) address to a load always involves a class indirection.
706728 // There is one exception: loading a raw pointer, e.g.
@@ -743,7 +765,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
743765 case is AllocStackInst :
744766 return cachedWalkDown ( addressOrValue: def, path: path. with ( knownType: nil ) )
745767 case let arg as FunctionArgument :
746- if !followLoads( at: path. projectionPath ) && arg. convention. isExclusiveIndirect && !path. followStores {
768+ if !followLoads( at: path) && arg. convention. isExclusiveIndirect && !path. followStores {
747769 return cachedWalkDown ( addressOrValue: def, path: path. with ( knownType: nil ) )
748770 } else {
749771 return isEscaping
@@ -781,7 +803,8 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
781803 }
782804 let arg = argOp. value
783805
784- let p = Path ( projectionPath: effect. pathPattern, followStores: path. followStores, knownType: nil )
806+ let p = Path ( projectionPath: effect. pathPattern, followStores: path. followStores,
807+ addressIsStored: path. addressIsStored, knownType: nil )
785808 if walkUp ( addressOrValue: arg, path: p) == . abortWalk {
786809 return . abortWalk
787810 }
@@ -840,10 +863,11 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
840863 return false
841864 }
842865
843- private func followLoads( at path: SmallProjectionPath ) -> Bool {
866+ private func followLoads( at path: Path ) -> Bool {
844867 return visitor. followLoads ||
845868 // When part of a class field we have to follow loads.
846- path. mayHaveClassProjection
869+ path. projectionPath. mayHaveClassProjection ||
870+ path. addressIsStored
847871 }
848872
849873 private func pathForArgumentEscapeChecking( _ path: SmallProjectionPath ) -> SmallProjectionPath {
@@ -867,7 +891,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
867891
868892private extension SmallProjectionPath {
869893 var escapePath : EscapeUtilityTypes . EscapePath {
870- EscapeUtilityTypes . EscapePath ( projectionPath: self , followStores: false , knownType: nil )
894+ EscapeUtilityTypes . EscapePath ( projectionPath: self , followStores: false , addressIsStored : false , knownType: nil )
871895 }
872896}
873897
0 commit comments