@@ -201,25 +201,49 @@ extension AddressUseVisitor {
201
201
}
202
202
203
203
extension AccessBase {
204
- /// If this access base has a single initializer, return it, along
205
- /// with the initialized address. This does not guarantee that all
206
- /// uses of that address are dominated by the store or even that the
207
- /// store is a direct use of `address`.
208
- func findSingleInitializer( _ context: some Context ) -> ( initialAddress: Value , initializingStore: Instruction ) ? {
204
+ enum Initializer {
205
+ // An @in or @inout argument that is never modified inside the function. Handling an unmodified @inout like an @in
206
+ // allows clients to ignore access scopes for the purpose of reaching definitions and lifetimes.
207
+ case argument( FunctionArgument )
208
+ // A yielded @in argument.
209
+ case yield( MultipleValueInstructionResult )
210
+ // A local variable or @out argument that is assigned once.
211
+ // 'initialAddress' is the first point at which address may be used. Typically the allocation.
212
+ case store( initializingStore: Instruction , initialAddress: Value )
213
+
214
+ var initialAddress : Value {
215
+ let address : Value
216
+ switch self {
217
+ case let . argument( arg) :
218
+ address = arg
219
+ case let . yield( result) :
220
+ address = result
221
+ case let . store( _, initialAddress) :
222
+ address = initialAddress
223
+ }
224
+ assert ( address. type. isAddress)
225
+ return address
226
+ }
227
+ }
228
+
229
+ /// If this access base has a single initializer, return it, along with the initialized address. This does not
230
+ /// guarantee that all uses of that address are dominated by the store or even that the store is a direct use of
231
+ /// `address`.
232
+ func findSingleInitializer( _ context: some Context ) -> Initializer ? {
209
233
let baseAddr : Value
210
234
switch self {
211
235
case let . stack( allocStack) :
212
236
baseAddr = allocStack
213
237
case let . argument( arg) :
214
- guard arg. convention. isIndirectOut else {
215
- return nil
238
+ if arg. convention. isIndirectIn {
239
+ return . argument ( arg )
216
240
}
217
241
baseAddr = arg
218
242
case let . storeBorrow( sbi) :
219
243
guard case let . stack( allocStack) = sbi. destinationOperand. value. accessBase else {
220
244
return nil
221
245
}
222
- return ( initialAddress : allocStack , initializingStore : sbi )
246
+ return . store ( initializingStore : sbi , initialAddress : allocStack )
223
247
default :
224
248
return nil
225
249
}
@@ -254,33 +278,43 @@ extension AccessBase {
254
278
// distinguishes between `mayWriteToMemory` for dependence vs. actual
255
279
// modification of memory.
256
280
struct AddressInitializationWalker : AddressDefUseWalker , AddressUseVisitor {
281
+ let baseAddress : Value
257
282
let context : any Context
258
283
259
284
var walkDownCache = WalkerCache < SmallProjectionPath > ( )
260
285
261
286
var isProjected = false
262
- var initializingStore : Instruction ?
287
+ var initializer : AccessBase . Initializer ?
263
288
264
289
static func findSingleInitializer( ofAddress baseAddr: Value , context: some Context )
265
- -> ( initialAddress : Value , initializingStore : Instruction ) ? {
290
+ -> AccessBase . Initializer ? {
266
291
267
- var walker = AddressInitializationWalker ( context : context)
292
+ var walker = AddressInitializationWalker ( baseAddress : baseAddr , context)
268
293
if walker. walkDownUses ( ofAddress: baseAddr, path: SmallProjectionPath ( ) ) == . abortWalk {
269
294
return nil
270
295
}
271
- guard let initializingStore = walker. initializingStore else {
272
- return nil
296
+ return walker. initializer
297
+ }
298
+
299
+ private init ( baseAddress: Value , _ context: some Context ) {
300
+ self . baseAddress = baseAddress
301
+ self . context = context
302
+ if let arg = baseAddress as? FunctionArgument {
303
+ assert ( !arg. convention. isIndirectIn, " @in arguments cannot be initialized " )
304
+ if arg. convention. isInout {
305
+ initializer = . argument( arg)
306
+ }
307
+ // @out arguments are initialized normally via stores.
273
308
}
274
- return ( initialAddress: baseAddr, initializingStore: initializingStore)
275
309
}
276
310
277
311
private mutating func setInitializer( instruction: Instruction ) -> WalkResult {
278
312
// An initializer must be unique and store the full value.
279
- if initializingStore != nil || isProjected {
280
- initializingStore = nil
313
+ if initializer != nil || isProjected {
314
+ initializer = nil
281
315
return . abortWalk
282
316
}
283
- initializingStore = instruction
317
+ initializer = . store ( initializingStore : instruction, initialAddress : baseAddress )
284
318
return . continueWalk
285
319
}
286
320
}
0 commit comments