@@ -281,7 +281,8 @@ struct LocalVariableAccessMap: Collection, CustomStringConvertible {
281281 let context : Context
282282 let allocation : Value
283283
284- let liveInAccess : LocalVariableAccess ?
284+ let isLiveIn : Bool
285+ let isLiveOut : Bool
285286
286287 // All mapped accesses have a valid instruction.
287288 //
@@ -306,12 +307,19 @@ struct LocalVariableAccessMap: Collection, CustomStringConvertible {
306307 init ? ( allocation: Value , _ context: Context ) {
307308 switch allocation {
308309 case is AllocBoxInst , is AllocStackInst :
309- self . liveInAccess = nil
310- break
310+ self . isLiveIn = false
311+ self . isLiveOut = false
311312 case let arg as FunctionArgument :
312313 switch arg. convention {
313- case . indirectIn, . indirectInout, . indirectInoutAliasable:
314- self . liveInAccess = LocalVariableAccess ( . incomingArgument, nil )
314+ case . indirectIn:
315+ self . isLiveIn = true
316+ self . isLiveOut = false
317+ case . indirectInout, . indirectInoutAliasable:
318+ self . isLiveIn = true
319+ self . isLiveOut = true
320+ case . indirectOut:
321+ self . isLiveIn = false
322+ self . isLiveOut = true
315323 default :
316324 return nil
317325 }
@@ -779,7 +787,8 @@ extension LocalVariableReachableAccess {
779787 if block != accessMap. allocation. parentBlock {
780788 for predecessor in block. predecessors { blockList. pushIfNotVisited ( predecessor) }
781789 } else if block == accessMap. function. entryBlock {
782- accessStack. push ( accessMap. liveInAccess!)
790+ assert ( accessMap. isLiveIn)
791+ accessStack. push ( LocalVariableAccess ( . incomingArgument, nil ) )
783792 }
784793 case . assignValue:
785794 break
@@ -829,7 +838,7 @@ extension LocalVariableReachableAccess {
829838 /// This performs a forward CFG walk to find known reachable uses from the function entry that guarantee liveness and
830839 /// may safely enclose dependent uses.
831840 private func gatherKnownLivenessUsesFromEntry( in accessStack: inout Stack < LocalVariableAccess > ) {
832- assert ( accessMap. liveInAccess! . kind == . incomingArgument , " only an argument access is live in to the function " )
841+ assert ( accessMap. isLiveIn , " only an argument access is live in to the function " )
833842 let firstInst = accessMap. function. entryBlock. instructions. first!
834843 _ = gatherReachableUses ( onOrAfter: firstInst, in: & accessStack, mode: . livenessUses)
835844 }
@@ -906,7 +915,7 @@ extension LocalVariableReachableAccess {
906915 return false
907916 }
908917 forwardPropagateEffect ( in: initialBlock, blockInfo: blockMap [ initialBlock] , effect: initialEffect,
909- blockList: & blockList, accessStack: & accessStack)
918+ blockList: & blockList, accessStack: & accessStack, mode : mode )
910919 while let block = blockList. pop ( ) {
911920 let blockInfo = blockMap [ block]
912921 var currentEffect : ForwardDataFlowEffect ?
@@ -933,7 +942,7 @@ extension LocalVariableReachableAccess {
933942 return false
934943 }
935944 forwardPropagateEffect ( in: block, blockInfo: blockInfo, effect: currentEffect, blockList: & blockList,
936- accessStack: & accessStack)
945+ accessStack: & accessStack, mode : mode )
937946 }
938947 log ( " \n \( accessMap) " )
939948 log ( prefix: false , " Reachable access: \n \( accessStack. map ( { String ( describing: $0) } ) . joined ( separator: " \n " ) ) " )
@@ -945,16 +954,18 @@ extension LocalVariableReachableAccess {
945954
946955 private func forwardPropagateEffect( in block: BasicBlock , blockInfo: BlockInfo ? , effect: ForwardDataFlowEffect ? ,
947956 blockList: inout BasicBlockWorklist ,
948- accessStack: inout Stack < LocalVariableAccess > ) {
957+ accessStack: inout Stack < LocalVariableAccess > ,
958+ mode: DataFlowMode ) {
949959 switch effect {
950960 case . none, . read, . modify, . escape:
951961 if let blockInfo, blockInfo. hasDealloc {
952962 break
953963 }
954- if block. terminator. isFunctionExiting {
955- // Record any reachable function exit as .outgoingArgument.
964+ // Assume that only a ReturnInst can return a live-out value.
965+ // All other function exits are considered dead-ends.
966+ if block. terminator is ReturnInstruction , accessMap. isLiveOut {
956967 accessStack. push ( LocalVariableAccess ( . outgoingArgument, block. terminator) )
957- } else if block. successors. isEmpty {
968+ } else if block. successors. isEmpty, mode == . livenessUses {
958969 accessStack. push ( LocalVariableAccess ( . deadEnd, block. terminator) )
959970 } else {
960971 for successor in block. successors { blockList. pushIfNotVisited ( successor) }
0 commit comments