@@ -73,7 +73,11 @@ enum AccessBase : CustomStringConvertible, Hashable {
73
73
/// An address which is derived from a `Builtin.RawPointer`.
74
74
case pointer( PointerToAddressInst )
75
75
76
- init ? ( baseAddress: Value ) {
76
+ /// The access base is some SIL pattern which does not fit into any other case.
77
+ /// This should be a very rare situation.
78
+ case unidentified
79
+
80
+ init ( baseAddress: Value ) {
77
81
switch baseAddress {
78
82
case let rea as RefElementAddrInst : self = . class( rea)
79
83
case let rta as RefTailAddrInst : self = . tail( rta)
@@ -85,15 +89,16 @@ enum AccessBase : CustomStringConvertible, Hashable {
85
89
if let ba = mvr. instruction as? BeginApplyInst , baseAddress. type. isAddress {
86
90
self = . yield( ba)
87
91
} else {
88
- return nil
92
+ self = . unidentified
89
93
}
90
94
default :
91
- return nil
95
+ self = . unidentified
92
96
}
93
97
}
94
98
95
99
var description : String {
96
100
switch self {
101
+ case . unidentified: return " ? "
97
102
case . box( let pbi) : return " box - \( pbi) "
98
103
case . stack( let asi) : return " stack - \( asi) "
99
104
case . global( let gl) : return " global - @ \( gl. name) "
@@ -110,7 +115,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
110
115
switch self {
111
116
case . class, . tail:
112
117
return true
113
- case . box, . stack, . global, . argument, . yield, . pointer:
118
+ case . box, . stack, . global, . argument, . yield, . pointer, . unidentified :
114
119
return false
115
120
}
116
121
}
@@ -121,7 +126,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
121
126
case . box( let pbi) : return pbi. operand
122
127
case . class( let rea) : return rea. operand
123
128
case . tail( let rta) : return rta. operand
124
- case . stack, . global, . argument, . yield, . pointer:
129
+ case . stack, . global, . argument, . yield, . pointer, . unidentified :
125
130
return nil
126
131
}
127
132
}
@@ -130,7 +135,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
130
135
switch self {
131
136
case . class( let rea) : return rea. fieldIsLet
132
137
case . global( let g) : return g. isLet
133
- case . box, . stack, . tail, . argument, . yield, . pointer:
138
+ case . box, . stack, . tail, . argument, . yield, . pointer, . unidentified :
134
139
return false
135
140
}
136
141
}
@@ -142,7 +147,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
142
147
case . class( let rea) : return rea. operand is AllocRefInstBase
143
148
case . tail( let rta) : return rta. operand is AllocRefInstBase
144
149
case . stack: return true
145
- case . global, . argument, . yield, . pointer:
150
+ case . global, . argument, . yield, . pointer, . unidentified :
146
151
return false
147
152
}
148
153
}
@@ -152,7 +157,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
152
157
switch self {
153
158
case . box, . class, . tail, . stack, . global:
154
159
return true
155
- case . argument, . yield, . pointer:
160
+ case . argument, . yield, . pointer, . unidentified :
156
161
return false
157
162
}
158
163
}
@@ -174,7 +179,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
174
179
}
175
180
176
181
func argIsDistinct( _ arg: FunctionArgument , from other: AccessBase ) -> Bool {
177
- if arg. isExclusiveIndirectParameter {
182
+ if arg. convention . isExclusiveIndirect {
178
183
// Exclusive indirect arguments cannot alias with an address for which we know that it
179
184
// is not derived from that argument (which might be the case for `pointer` and `yield`).
180
185
return other. hasKnownStorageKind
@@ -199,7 +204,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
199
204
case ( . tail( let rta) , . tail( let otherRta) ) :
200
205
return isDifferentAllocation ( rta. operand, otherRta. operand)
201
206
case ( . argument( let arg) , . argument( let otherArg) ) :
202
- return ( arg. isExclusiveIndirectParameter || otherArg. isExclusiveIndirectParameter ) && arg != otherArg
207
+ return ( arg. convention . isExclusiveIndirect || otherArg. convention . isExclusiveIndirect ) && arg != otherArg
203
208
204
209
// Handle arguments vs non-arguments
205
210
case ( . argument( let arg) , _) :
@@ -224,6 +229,10 @@ struct AccessPath : CustomStringConvertible {
224
229
/// address projections only
225
230
let projectionPath : SmallProjectionPath
226
231
232
+ static func unidentified( ) -> AccessPath {
233
+ return AccessPath ( base: . unidentified, projectionPath: SmallProjectionPath ( ) )
234
+ }
235
+
227
236
var description : String {
228
237
" \( projectionPath) : \( base) "
229
238
}
@@ -362,46 +371,46 @@ enum EnclosingScope {
362
371
/// of the access (the base address and the address projections to the accessed fields) and
363
372
/// the innermost enclosing scope (`begin_access`).
364
373
struct AccessPathWalker {
365
- mutating func getAccessPath( of address: Value ) -> AccessPath ? {
374
+ mutating func getAccessPath( of address: Value ) -> AccessPath {
366
375
assert ( address. type. isAddress, " Expected address " )
367
376
walker. start ( )
368
377
if walker. walkUp ( address: address, path: Walker . Path ( ) ) == . abortWalk {
369
- return nil
378
+ assert ( walker. result. base == . unidentified,
379
+ " shouldn't have set an access base in an aborted walk " )
370
380
}
371
381
return walker. result
372
382
}
373
383
374
- mutating func getAccessPathWithScope( of address: Value ) -> ( AccessPath ? , EnclosingScope ? ) {
384
+ mutating func getAccessPathWithScope( of address: Value ) -> ( AccessPath , EnclosingScope ) {
375
385
let ap = getAccessPath ( of: address)
376
386
return ( ap, walker. scope)
377
387
}
378
388
379
- mutating func getAccessBase( of address: Value ) -> AccessBase ? {
380
- getAccessPath ( of: address) ? . base
389
+ mutating func getAccessBase( of address: Value ) -> AccessBase {
390
+ getAccessPath ( of: address) . base
381
391
}
382
392
383
- mutating func getAccessScope( of address: Value ) -> EnclosingScope ? {
393
+ mutating func getAccessScope( of address: Value ) -> EnclosingScope {
384
394
getAccessPathWithScope ( of: address) . 1
385
395
}
386
396
387
397
private var walker = Walker ( )
388
398
389
399
private struct Walker : AddressUseDefWalker {
390
- private( set) var result : AccessPath ? = nil
400
+ private( set) var result = AccessPath . unidentified ( )
391
401
private var foundBeginAccess : BeginAccessInst ? = nil
392
402
private var pointerId = PointerIdentification ( )
393
403
394
- var scope : EnclosingScope ? {
404
+ var scope : EnclosingScope {
395
405
if let ba = foundBeginAccess {
396
406
return . scope( ba)
397
407
} else {
398
- guard let accessPath = result else { return nil }
399
- return . base( accessPath. base)
408
+ return . base( result. base)
400
409
}
401
410
}
402
411
403
412
mutating func start( ) {
404
- result = nil
413
+ result = . unidentified ( )
405
414
foundBeginAccess = nil
406
415
}
407
416
@@ -435,7 +444,7 @@ struct AccessPathWalker {
435
444
}
436
445
437
446
mutating func rootDef( address: Value , path: Path ) -> WalkResult {
438
- assert ( result == nil , " rootDef should only called once " )
447
+ assert ( result. base == . unidentified , " rootDef should only called once " )
439
448
// Try identifying the address a pointer originates from
440
449
if let p2ai = address as? PointerToAddressInst {
441
450
if let originatingAddr = pointerId. getOriginatingAddress ( of: p2ai) {
@@ -446,15 +455,9 @@ struct AccessPathWalker {
446
455
}
447
456
}
448
457
449
- // If this is a base then we're done
450
- if let base = AccessBase ( baseAddress: address) {
451
- self . result = AccessPath ( base: base, projectionPath: path. projectionPath)
452
- return . continueWalk
453
- }
454
-
455
- // The base is unidentified
456
- self . result = nil
457
- return . abortWalk
458
+ let base = AccessBase ( baseAddress: address)
459
+ self . result = AccessPath ( base: base, projectionPath: path. projectionPath)
460
+ return . continueWalk
458
461
}
459
462
460
463
mutating func walkUp( address: Value , path: Path ) -> WalkResult {
@@ -464,7 +467,6 @@ struct AccessPathWalker {
464
467
} else if path. indexAddr && !canBeOperandOfIndexAddr( address) {
465
468
// An `index_addr` instruction cannot be derived from an address
466
469
// projection. Bail out
467
- self . result = nil
468
470
return . abortWalk
469
471
} else if let ba = address as? BeginAccessInst , foundBeginAccess == nil {
470
472
foundBeginAccess = ba
@@ -474,6 +476,27 @@ struct AccessPathWalker {
474
476
}
475
477
}
476
478
479
+ extension Value {
480
+ // Convenient properties to avoid instantiating an explicit AccessPathWalker.
481
+ //
482
+ // Although an AccessPathWalker is created for each call of these properties,
483
+ // it's very unlikely that this will end up in memory allocations.
484
+ // Only in the rare case of `pointer_to_address` -> `address_to_pointer` pairs, which
485
+ // go through phi-arguments, the AccessPathWalker will allocate memnory in its cache.
486
+
487
+ /// Computes the access base of this address value.
488
+ var accessBase : AccessBase {
489
+ var apWalker = AccessPathWalker ( )
490
+ return apWalker. getAccessBase ( of: self )
491
+ }
492
+
493
+ /// Computes the enclosing access scope of this address value.
494
+ var accessScope : EnclosingScope {
495
+ var apWalker = AccessPathWalker ( )
496
+ return apWalker. getAccessScope ( of: self )
497
+ }
498
+ }
499
+
477
500
/// A ValueUseDef walker that identifies which values a reference of an access path might
478
501
/// originate from.
479
502
protocol AccessStoragePathWalker : ValueUseDefWalker where Path == SmallProjectionPath {
@@ -496,7 +519,7 @@ extension AccessStoragePathWalker {
496
519
return walkUp ( value: rea. operand, path: path. push ( . classField, index: rea. fieldIndex) ) != . abortWalk
497
520
case . tail( let rta) :
498
521
return walkUp ( value: rta. operand, path: path. push ( . tailElements, index: 0 ) ) != . abortWalk
499
- case . stack, . global, . argument, . yield, . pointer:
522
+ case . stack, . global, . argument, . yield, . pointer, . unidentified :
500
523
return false
501
524
}
502
525
}
0 commit comments