@@ -38,51 +38,18 @@ let tempRValueElimination = FunctionPass(name: "temp-rvalue-elimination") {
38
38
( function: Function , context: FunctionPassContext ) in
39
39
40
40
for inst in function. instructions {
41
- switch inst {
42
- case let copy as CopyAddrInst :
43
- if copy. source == copy. destination {
44
- // Remove identity copies which may have been created by an earlier iteration, where another `copy_addr`
45
- // copied the `alloc_stack` back to the source location.
46
- context. erase ( instruction: copy)
47
- } else {
48
- tryEliminate ( copy: copy, context)
49
- }
50
- case let store as StoreInst :
51
- // Also handle `load`-`store` pairs which are basically the same thing as a `copy_addr`.
52
- if let load = store. source as? LoadInst , load. uses. isSingleUse, load. parentBlock == store. parentBlock {
53
- tryEliminate ( copy: store, context)
54
- }
55
- default :
56
- break
41
+ if let copyAddr = inst as? CopyAddrInst {
42
+ tryEliminate ( copy: copyAddr, context)
57
43
}
58
44
}
59
45
}
60
46
61
- private protocol CopyLikeInstruction : Instruction {
62
- var sourceAddress : Value { get }
63
- var destinationAddress : Value { get }
64
- var isTakeOfSource : Bool { get }
65
- var isInitializationOfDestination : Bool { get }
66
- var loadingInstruction : Instruction { get }
67
- }
68
-
69
- extension CopyAddrInst : CopyLikeInstruction {
70
- var sourceAddress : Value { source }
71
- var destinationAddress : Value { destination }
72
- var loadingInstruction : Instruction { self }
73
- }
74
-
75
- // A `store` which has a `load` as source operand. This is basically the same as a `copy_addr`.
76
- extension StoreInst : CopyLikeInstruction {
77
- var sourceAddress : Value { load. address }
78
- var destinationAddress : Value { destination }
79
- var isTakeOfSource : Bool { load. loadOwnership == . take }
80
- var isInitializationOfDestination : Bool { storeOwnership != . assign }
81
- var loadingInstruction : Instruction { load }
82
- private var load : LoadInst { source as! LoadInst }
83
- }
84
-
85
- private func tryEliminate( copy: CopyLikeInstruction , _ context: FunctionPassContext ) {
47
+ private func tryEliminate( copy: CopyAddrInst , _ context: FunctionPassContext ) {
48
+ // Remove identity copies which may have been created by an earlier iteration, where another `copy_addr`
49
+ // copied the `alloc_stack` back to the source location.
50
+ if copy. source == copy. destination {
51
+ context. erase ( instruction: copy)
52
+ }
86
53
87
54
guard let ( allocStack, lastUseOfAllocStack) = getRemovableAllocStackDestination ( of: copy, context) else {
88
55
return
@@ -94,7 +61,7 @@ private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassCont
94
61
95
62
if needToInsertDestroy ( copy: copy, lastUseOfAllocStack: lastUseOfAllocStack) {
96
63
Builder . insert ( after: lastUseOfAllocStack, context) { builder in
97
- builder. createDestroyAddr ( address: copy. sourceAddress )
64
+ builder. createDestroyAddr ( address: copy. source )
98
65
}
99
66
}
100
67
@@ -109,25 +76,25 @@ private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassCont
109
76
assert ( cai == lastUseOfAllocStack && cai. source == allocStack)
110
77
cai. set ( isTakeOfSource: false , context)
111
78
}
112
- use. set ( to: copy. sourceAddress , context)
79
+ use. set ( to: copy. source , context)
113
80
case let load as LoadInst :
114
81
if load. loadOwnership == . take, !copy. isTakeOfSource {
115
82
// If the original copy is not taking its source, a `load` from the `allocStack` must
116
83
// not take its source either.
117
84
assert ( load == lastUseOfAllocStack)
118
85
load. set ( ownership: . copy, context)
119
86
}
120
- use. set ( to: copy. sourceAddress , context) ;
87
+ use. set ( to: copy. source , context) ;
121
88
122
89
default :
123
90
// Note that no operations that may be handled by this default clause can destroy the `allocStack`.
124
91
// This includes operations that load the value from memory and release it or cast the address
125
92
// before destroying it.
126
- use. set ( to: copy. sourceAddress , context) ;
93
+ use. set ( to: copy. source , context) ;
127
94
}
128
95
}
129
96
context. erase ( instruction: allocStack)
130
- context. erase ( instructionIncludingAllUsers : copy. loadingInstruction )
97
+ context. erase ( instruction : copy)
131
98
}
132
99
133
100
/// Checks if the `copy` is copying into an `alloc_stack` which is removable:
@@ -138,17 +105,17 @@ private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassCont
138
105
/// %lastUseOfAllocStack = load %allocStack
139
106
/// ```
140
107
private func getRemovableAllocStackDestination(
141
- of copy: CopyLikeInstruction , _ context: FunctionPassContext
108
+ of copy: CopyAddrInst , _ context: FunctionPassContext
142
109
) -> ( allocStack: AllocStackInst , lastUseOfAllocStack: Instruction ) ? {
143
110
guard copy. isInitializationOfDestination,
144
- let allocStack = copy. destinationAddress as? AllocStackInst
111
+ let allocStack = copy. destination as? AllocStackInst
145
112
else {
146
113
return nil
147
114
}
148
115
149
116
// If the `allocStack` is lexical we can eliminate it if the source of the copy is lexical and
150
117
// it is live for longer than the `allocStack`.
151
- if allocStack. isLexical && !copy. sourceAddress . accessBase. storageIsLexical {
118
+ if allocStack. isLexical && !copy. source . accessBase. storageIsLexical {
152
119
return nil
153
120
}
154
121
@@ -182,7 +149,7 @@ private func getRemovableAllocStackDestination(
182
149
if copy. isTakeOfSource,
183
150
lastUseOfAllocStack != copy,
184
151
!( lastUseOfAllocStack is DestroyAddrInst ) ,
185
- lastUseOfAllocStack. mayWrite ( toAddress: copy. sourceAddress , context. aliasAnalysis)
152
+ lastUseOfAllocStack. mayWrite ( toAddress: copy. source , context. aliasAnalysis)
186
153
{
187
154
return nil
188
155
}
@@ -201,7 +168,7 @@ private func getRemovableAllocStackDestination(
201
168
202
169
/// We need to insert a final destroy if the original `copy` is taking the source but the
203
170
/// `lastUseOfAllocStack` is not taking the `alloc_stack`.
204
- private func needToInsertDestroy( copy: CopyLikeInstruction , lastUseOfAllocStack: Instruction ) -> Bool {
171
+ private func needToInsertDestroy( copy: CopyAddrInst , lastUseOfAllocStack: Instruction ) -> Bool {
205
172
if !copy. isTakeOfSource {
206
173
return false
207
174
}
@@ -210,13 +177,13 @@ private func needToInsertDestroy(copy: CopyLikeInstruction, lastUseOfAllocStack:
210
177
return true
211
178
case let cai as CopyAddrInst :
212
179
if cai. isTakeOfSource {
213
- assert ( cai. source == copy. destinationAddress , " copy_addr must be not take a projected address " )
180
+ assert ( cai. source == copy. destination , " copy_addr must be not take a projected address " )
214
181
return false
215
182
}
216
183
return true
217
184
case let li as LoadInst :
218
185
if li. loadOwnership == . take {
219
- assert ( li. address == copy. destinationAddress , " load must be not take a projected address " )
186
+ assert ( li. address == copy. destination , " load must be not take a projected address " )
220
187
return false
221
188
}
222
189
return true
@@ -280,9 +247,7 @@ private extension AllocStackInst {
280
247
/// ```
281
248
/// We must not replace %temp with %a after the `end_access`. Instead we try to move the `end_access`
282
249
/// after the last use.
283
- private func extendAccessScopes( beyond lastUse: Instruction , copy: CopyLikeInstruction ,
284
- _ context: FunctionPassContext ) -> Bool
285
- {
250
+ private func extendAccessScopes( beyond lastUse: Instruction , copy: CopyAddrInst , _ context: FunctionPassContext ) -> Bool {
286
251
var endAccessToMove : EndAccessInst ? = nil
287
252
288
253
for inst in InstructionList ( first: copy. next) {
@@ -292,7 +257,7 @@ private func extendAccessScopes(beyond lastUse: Instruction, copy: CopyLikeInstr
292
257
if endAccessToMove != nil {
293
258
return false
294
259
}
295
- if context. aliasAnalysis. mayAlias ( copy. sourceAddress , endAccess. beginAccess. address) ,
260
+ if context. aliasAnalysis. mayAlias ( copy. source , endAccess. beginAccess. address) ,
296
261
// There cannot be any aliasing modifying accesses within the liverange of the `alloc_stack`,
297
262
// because we would have cought this in `getLastUseWhileSourceIsNotModified`.
298
263
// But there are cases where `aliasAnalysis.mayAlias` is less precise than `Instruction.mayWrite`.
@@ -336,7 +301,7 @@ private func extendAccessScopes(beyond lastUse: Instruction, copy: CopyLikeInstr
336
301
///
337
302
/// Unfortunately, we cannot simply use the destroy points as the lifetime end, because they can be in a
338
303
/// different basic block. Instead we look for the last non-destroy, non-dealloc use.
339
- private func getLastUseWhileSourceIsNotModified( of copy: CopyLikeInstruction ,
304
+ private func getLastUseWhileSourceIsNotModified( of copy: CopyAddrInst ,
340
305
uses: InstructionSetWithCount ,
341
306
_ context: FunctionPassContext ) -> Instruction ?
342
307
{
@@ -348,7 +313,7 @@ private func getLastUseWhileSourceIsNotModified(of copy: CopyLikeInstruction,
348
313
349
314
// We already checked that the useful lifetime of the `alloc_stack` ends in the same block as the `copy`.
350
315
// Therefore we can limit our search to the instructions of this block.
351
- for inst in InstructionList ( first: copy. loadingInstruction . next) {
316
+ for inst in InstructionList ( first: copy. next) {
352
317
if uses. contains ( inst) {
353
318
numUsesFound += 1
354
319
}
@@ -362,7 +327,7 @@ private func getLastUseWhileSourceIsNotModified(of copy: CopyLikeInstruction,
362
327
// could occur _before_ the read of the `alloc_stack`.
363
328
switch inst {
364
329
case is FullApplySite , is YieldInst :
365
- if inst. mayWrite ( toAddress: copy. sourceAddress , aliasAnalysis) {
330
+ if inst. mayWrite ( toAddress: copy. source , aliasAnalysis) {
366
331
return nil
367
332
}
368
333
return inst
@@ -371,7 +336,7 @@ private func getLastUseWhileSourceIsNotModified(of copy: CopyLikeInstruction,
371
336
}
372
337
}
373
338
374
- if inst. mayWrite ( toAddress: copy. sourceAddress , aliasAnalysis) {
339
+ if inst. mayWrite ( toAddress: copy. source , aliasAnalysis) {
375
340
return nil
376
341
}
377
342
}
@@ -383,9 +348,9 @@ private func getLastUseWhileSourceIsNotModified(of copy: CopyLikeInstruction,
383
348
/// Collects all uses of the `alloc_stack`.
384
349
private struct UseCollector : AddressDefUseWalker {
385
350
private( set) var uses : InstructionSetWithCount
386
- private let copy : CopyLikeInstruction
351
+ private let copy : CopyAddrInst
387
352
388
- init ( copy: CopyLikeInstruction , _ context: FunctionPassContext ) {
353
+ init ( copy: CopyAddrInst , _ context: FunctionPassContext ) {
389
354
self . uses = InstructionSetWithCount ( context)
390
355
self . copy = copy
391
356
}
@@ -502,7 +467,7 @@ private struct UseCollector : AddressDefUseWalker {
502
467
if load. loadOwnership == . take,
503
468
// Only accept `load [take]` if it takes the whole `alloc_stack`. A `load [take]` from
504
469
// a projection would destroy only a part of the `alloc_stack` and we don't handle this.
505
- load. address != copy. destinationAddress
470
+ load. address != copy. destination
506
471
{
507
472
return . abortWalk
508
473
}
@@ -529,7 +494,7 @@ private struct UseCollector : AddressDefUseWalker {
529
494
return . abortWalk
530
495
}
531
496
// As with `load [take]`, only accept `copy_addr [take]` if it takes the whole `alloc_stack`.
532
- if copyFromStack. isTakeOfSource && copyFromStack. source != copy. destinationAddress {
497
+ if copyFromStack. isTakeOfSource && copyFromStack. source != copy. destination {
533
498
return . abortWalk
534
499
}
535
500
uses. insert ( copyFromStack)
0 commit comments