@@ -990,3 +990,146 @@ private extension PartialApplyInst {
990990 }
991991 }
992992}
993+
994+ //===--------------------------------------------------------------------===//
995+ // Tests
996+ //===--------------------------------------------------------------------===//
997+
998+ let escapeInfoTest = FunctionTest ( " escape_info " ) {
999+ function, arguments, context in
1000+
1001+ print ( " Escape information for \( function. name) : " )
1002+
1003+ struct Visitor : EscapeVisitorWithResult {
1004+ var result : Set < String > = Set ( )
1005+
1006+ mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
1007+ if operand. instruction is ReturnInstruction {
1008+ result. insert ( " return[ \( path. projectionPath) ] " )
1009+ return . ignore
1010+ }
1011+ return . continueWalk
1012+ }
1013+
1014+ mutating func visitDef( def: Value , path: EscapePath ) -> DefResult {
1015+ guard let arg = def as? FunctionArgument else {
1016+ return . continueWalkUp
1017+ }
1018+ result. insert ( " arg \( arg. index) [ \( path. projectionPath) ] " )
1019+ return . walkDown
1020+ }
1021+ }
1022+
1023+ // Dump the EscapeInfo query results for all `alloc_ref` instructions in the function.
1024+ //
1025+ for inst in function. instructions {
1026+ if let allocRef = inst as? AllocRefInst {
1027+
1028+ let resultStr : String
1029+ if let result = allocRef. visit ( using: Visitor ( ) , context) {
1030+ if result. isEmpty {
1031+ resultStr = " - "
1032+ } else {
1033+ resultStr = Array ( result) . sorted ( ) . joined ( separator: " , " )
1034+ }
1035+ } else {
1036+ resultStr = " global "
1037+ }
1038+ print ( " \( resultStr) : \( allocRef) " )
1039+ }
1040+ }
1041+ print ( " End function \( function. name) \n " )
1042+ }
1043+
1044+ let addressEscapeInfoTest = FunctionTest ( " address_escape_info " ) {
1045+ function, arguments, context in
1046+
1047+ // Dumps the EscapeInfo query results for addresses escaping to function calls.
1048+ // The `fix_lifetime` instruction is used as marker for addresses and values to query.
1049+
1050+ print ( " Address escape information for \( function. name) : " )
1051+
1052+ var valuesToCheck = [ Value] ( )
1053+ var applies = [ Instruction] ( )
1054+
1055+ for inst in function. instructions {
1056+ switch inst {
1057+ case let fli as FixLifetimeInst :
1058+ valuesToCheck. append ( fli. operand. value)
1059+ case is FullApplySite :
1060+ applies. append ( inst)
1061+ default :
1062+ break
1063+ }
1064+ }
1065+
1066+ struct Visitor : EscapeVisitor {
1067+ let apply : Instruction
1068+ mutating func visitUse( operand: Operand , path: EscapePath ) -> UseResult {
1069+ let user = operand. instruction
1070+ if user == apply {
1071+ return . abort
1072+ }
1073+ if user is ReturnInstruction {
1074+ // Anything which is returned cannot escape to an instruction inside the function.
1075+ return . ignore
1076+ }
1077+ return . continueWalk
1078+ }
1079+
1080+ var followTrivialTypes : Bool { true }
1081+ var followLoads : Bool { false }
1082+ }
1083+
1084+ // test `isEscaping(addressesOf:)`
1085+ for value in valuesToCheck {
1086+ print ( " value: \( value) " )
1087+ for apply in applies {
1088+ if value. allContainedAddresses. isEscaping ( using: Visitor ( apply: apply) , context) {
1089+ print ( " ==> \( apply) " )
1090+ } else {
1091+ print ( " - \( apply) " )
1092+ }
1093+ }
1094+ }
1095+
1096+ // test `canReferenceSameField` for each pair of `fix_lifetime`.
1097+ if !valuesToCheck. isEmpty {
1098+ for lhsIdx in 0 ..< ( valuesToCheck. count - 1 ) {
1099+ for rhsIdx in ( lhsIdx + 1 ) ..< valuesToCheck. count {
1100+ print ( " pair \( lhsIdx) - \( rhsIdx) " )
1101+ let lhs = valuesToCheck [ lhsIdx]
1102+ let rhs = valuesToCheck [ rhsIdx]
1103+ print ( lhs)
1104+ print ( rhs)
1105+
1106+ let projLhs = lhs. allContainedAddresses
1107+ let projRhs = rhs. allContainedAddresses
1108+ let mayAlias = projLhs. canAddressAlias ( with: projRhs, context)
1109+ if mayAlias != projRhs. canAddressAlias ( with: projLhs, context) {
1110+ fatalError ( " canAddressAlias(with:) must be symmetric " )
1111+ }
1112+
1113+ let addrReachable : Bool
1114+ if lhs. type. isAddress && !rhs. type. isAddress {
1115+ let anythingReachableFromRhs = rhs. at ( SmallProjectionPath ( . anything) )
1116+ addrReachable = projLhs. canAddressAlias ( with: anythingReachableFromRhs, context)
1117+ if mayAlias && !addrReachable {
1118+ fatalError ( " mayAlias implies addrReachable " )
1119+ }
1120+ } else {
1121+ addrReachable = false
1122+ }
1123+ if mayAlias {
1124+ print ( " may alias " )
1125+ } else if addrReachable {
1126+ print ( " address reachable but no alias " )
1127+ } else {
1128+ print ( " no alias " )
1129+ }
1130+ }
1131+ }
1132+ }
1133+
1134+ print ( " End function \( function. name) \n " )
1135+ }
0 commit comments