@@ -54,24 +54,6 @@ private extension Instruction {
54
54
}
55
55
}
56
56
57
- private extension Argument {
58
- func verify( _ context: FunctionPassContext ) {
59
- if let phi = Phi ( self ) , phi. value. ownership == . guaranteed {
60
- var forwardingBorrowedFromFound = false
61
- for use in phi. value. uses {
62
- require ( use. instruction is BorrowedFromInst ,
63
- " guaranteed phi: \( self ) \n has non borrowed-from use: \( use) " )
64
- if use. index == 0 {
65
- require ( !forwardingBorrowedFromFound, " phi \( self ) has multiple forwarding borrowed-from uses " )
66
- forwardingBorrowedFromFound = true
67
- }
68
- }
69
- require ( forwardingBorrowedFromFound,
70
- " missing forwarding borrowed-from user of guaranteed phi \( phi) " )
71
- }
72
- }
73
- }
74
-
75
57
extension BorrowedFromInst : VerifiableInstruction {
76
58
func verify( _ context: FunctionPassContext ) {
77
59
var computedEVs = Stack < Value > ( context)
@@ -92,121 +74,20 @@ extension BorrowedFromInst : VerifiableInstruction {
92
74
}
93
75
}
94
76
95
- extension LoadBorrowInst : VerifiableInstruction {
77
+ private extension Argument {
96
78
func verify( _ context: FunctionPassContext ) {
97
- if isUnchecked {
98
- return
99
- }
100
-
101
- var mutatingInstructions = MutatingUsesWalker ( context)
102
- defer { mutatingInstructions. deinitialize ( ) }
103
-
104
- mutatingInstructions. findMutatingUses ( of: self . address)
105
- mutatingInstructions. verifyNoMutatingUsesInLiverange ( of: self )
106
- }
107
- }
108
-
109
- // Used to check if any instruction is mutating the memory location within the liverange of a `load_borrow`.
110
- // Note that it is not checking if an instruction _may_ mutate the memory, but it's checking if any instruction
111
- // _definitely_ will mutate the memory.
112
- // Otherwise the risk would be too big for false alarms. It also means that this verification is not perfect and
113
- // might miss some subtle violations.
114
- private struct MutatingUsesWalker : AddressDefUseWalker {
115
- let context : FunctionPassContext
116
- var mutatingInstructions : InstructionSet
117
-
118
- init ( _ context: FunctionPassContext ) {
119
- self . context = context
120
- self . mutatingInstructions = InstructionSet ( context)
121
- }
122
-
123
- mutating func deinitialize( ) {
124
- self . mutatingInstructions. deinitialize ( )
125
- }
126
-
127
- mutating func findMutatingUses( of address: Value ) {
128
- _ = walkDownUses ( ofAddress: address, path: UnusedWalkingPath ( ) )
129
- }
130
-
131
- mutating func verifyNoMutatingUsesInLiverange( of load: LoadBorrowInst ) {
132
- // The liverange of a `load_borrow` can end in a branch instruction. In such cases we handle the re-borrow liveranges
133
- // (starting at the `borrowed_from` in the successor block) separately.
134
- // This worklist contains the starts of the individual linear liveranges,
135
- // i.e. `load_borrow` and `borrowed_from` instructions.
136
- var linearLiveranges = SpecificInstructionWorklist < SingleValueInstruction > ( context)
137
- defer { linearLiveranges. deinitialize ( ) }
138
-
139
- linearLiveranges. pushIfNotVisited ( load)
140
- while let startInst = linearLiveranges. pop ( ) {
141
- verifyNoMutatingUsesInLinearLiverange ( of: startInst)
142
-
143
- for use in startInst. uses {
144
- if let phi = Phi ( using: use) {
145
- linearLiveranges. pushIfNotVisited ( phi. borrowedFrom!)
146
- }
147
- }
148
- }
149
- }
150
-
151
- private mutating func verifyNoMutatingUsesInLinearLiverange( of startInst: SingleValueInstruction ) {
152
- assert ( startInst is LoadBorrowInst || startInst is BorrowedFromInst )
153
-
154
- var instWorklist = InstructionWorklist ( context)
155
- defer { instWorklist. deinitialize ( ) }
156
-
157
- // It would be good enough to only consider `end_borrow`s (and branches), but adding all users doesn't harm.
158
- for use in startInst. uses {
159
- instWorklist. pushPredecessors ( of: use. instruction, ignoring: startInst)
160
- }
161
-
162
- while let inst = instWorklist. pop ( ) {
163
- require ( !mutatingInstructions. contains ( inst) ,
164
- " Load borrow invalidated by a local write " , atInstruction: inst)
165
- instWorklist. pushPredecessors ( of: inst, ignoring: startInst)
166
- }
167
- }
168
-
169
- mutating func leafUse( address: Operand , path: UnusedWalkingPath ) -> WalkResult {
170
- if address. isMutatedAddress {
171
- mutatingInstructions. insert ( address. instruction)
172
- }
173
- return . continueWalk
174
- }
175
- }
176
-
177
- private extension Operand {
178
- // Returns true if the operand's instruction is definitely writing to the operand's address value.
179
- var isMutatedAddress : Bool {
180
- assert ( value. type. isAddress)
181
- switch instruction {
182
- case let store as StoringInstruction :
183
- return self == store. destinationOperand
184
- case let copy as SourceDestAddrInstruction :
185
- if self == copy. destinationOperand {
186
- return true
187
- } else if self == copy. sourceOperand && copy. isTakeOfSrc {
188
- return true
189
- }
190
- return false
191
- case let load as LoadInst :
192
- return load. loadOwnership == . take
193
- case let partialApply as PartialApplyInst :
194
- if !partialApply. isOnStack,
195
- let convention = partialApply. convention ( of: self )
196
- {
197
- switch convention {
198
- case . indirectIn, . indirectInGuaranteed:
199
- // Such operands are consumed by the `partial_apply` and therefore cound as "written".
200
- return true
201
- default :
202
- return false
79
+ if let phi = Phi ( self ) , phi. value. ownership == . guaranteed {
80
+ var forwardingBorrowedFromFound = false
81
+ for use in phi. value. uses {
82
+ require ( use. instruction is BorrowedFromInst ,
83
+ " guaranteed phi: \( self ) \n has non borrowed-from use: \( use) " )
84
+ if use. index == 0 {
85
+ require ( !forwardingBorrowedFromFound, " phi \( self ) has multiple forwarding borrowed-from uses " )
86
+ forwardingBorrowedFromFound = true
203
87
}
204
88
}
205
- return false
206
- case is DestroyAddrInst , is IsUniqueInst :
207
- return true
208
- default :
209
- return false
89
+ require ( forwardingBorrowedFromFound,
90
+ " missing forwarding borrowed-from user of guaranteed phi \( phi) " )
210
91
}
211
92
}
212
93
}
0 commit comments