@@ -152,13 +152,100 @@ private func addEnclosingValues(
152152 return true
153153}
154154
155+ /// Replaces a phi with the unique incoming value if all incoming values are the same:
156+ /// ```
157+ /// bb1:
158+ /// br bb3(%1)
159+ /// bb2:
160+ /// br bb3(%1)
161+ /// bb3(%2 : $T): // Predecessors: bb1, bb2
162+ /// use(%2)
163+ /// ```
164+ /// ->
165+ /// ```
166+ /// bb1:
167+ /// br bb3
168+ /// bb2:
169+ /// br bb3
170+ /// bb3:
171+ /// use(%1)
172+ /// ```
173+ ///
174+ func replacePhiWithIncomingValue( phi: Phi , _ context: some MutatingContext ) -> Bool {
175+ if phi. predecessors. isEmpty {
176+ return false
177+ }
178+ let uniqueIncomingValue = phi. incomingValues. first!
179+ if !uniqueIncomingValue. parentFunction. hasOwnership {
180+ // For the SSAUpdater it's only required to simplify phis in OSSA.
181+ // This avoids that we need to handle cond_br instructions below.
182+ return false
183+ }
184+ if phi. incomingValues. contains ( where: { $0 != uniqueIncomingValue } ) {
185+ return false
186+ }
187+ if let borrowedFrom = phi. borrowedFrom {
188+ borrowedFrom. uses. replaceAll ( with: uniqueIncomingValue, context)
189+ context. erase ( instruction: borrowedFrom)
190+ } else {
191+ phi. value. uses. replaceAll ( with: uniqueIncomingValue, context)
192+ }
193+
194+ let block = phi. value. parentBlock
195+ for incomingOp in phi. incomingOperands {
196+ let existingBranch = incomingOp. instruction as! BranchInst
197+ let argsWithRemovedPhiOp = existingBranch. operands. filter { $0 != incomingOp } . map { $0. value }
198+ Builder ( before: existingBranch, context) . createBranch ( to: block, arguments: argsWithRemovedPhiOp)
199+ context. erase ( instruction: existingBranch)
200+ }
201+ block. eraseArgument ( at: phi. value. index, context)
202+ return true
203+ }
204+
205+ /// Replaces phis with the unique incoming values if all incoming values are the same.
206+ /// This is needed after running the SSAUpdater for an existing OSSA value, because the updater can
207+ /// insert unnecessary phis in the middle of the original liverange which breaks up the original
208+ /// liverange into smaller ones:
209+ /// ```
210+ /// %1 = def_of_owned_value
211+ /// %2 = begin_borrow %1
212+ /// ...
213+ /// br bb2(%1)
214+ /// bb2(%3 : @owned $T): // inserted by SSAUpdater
215+ /// ...
216+ /// end_borrow %2 // use after end-of-lifetime!
217+ /// destroy_value %3
218+ /// ```
219+ ///
220+ /// It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange.
221+ ///
222+ func replacePhisWithIncomingValues( phis: [ Phi ] , _ context: some MutatingContext ) {
223+ var currentPhis = phis
224+ // Do this in a loop because replacing one phi might open up the opportunity for another phi
225+ // and the order of phis in the array can be arbitrary.
226+ while true {
227+ var newPhis = [ Phi] ( )
228+ for phi in currentPhis {
229+ if !replacePhiWithIncomingValue( phi: phi, context) {
230+ newPhis. append ( phi)
231+ }
232+ }
233+ if newPhis. count == currentPhis. count {
234+ return
235+ }
236+ currentPhis = newPhis
237+ }
238+ }
239+
155240func registerGuaranteedPhiUpdater( ) {
156241 BridgedUtilities . registerGuaranteedPhiUpdater (
242+ // updateAllGuaranteedPhis
157243 { ( bridgedCtxt: BridgedPassContext , bridgedFunction: BridgedFunction ) in
158244 let context = FunctionPassContext ( _bridged: bridgedCtxt)
159245 let function = bridgedFunction. function;
160246 updateGuaranteedPhis ( in: function, context)
161247 } ,
248+ // updateGuaranteedPhis
162249 { ( bridgedCtxt: BridgedPassContext , bridgedPhiArray: BridgedArrayRef ) in
163250 let context = FunctionPassContext ( _bridged: bridgedCtxt)
164251 var guaranteedPhis = Stack < Phi > ( context)
@@ -172,6 +259,15 @@ func registerGuaranteedPhiUpdater() {
172259 }
173260 }
174261 updateGuaranteedPhis ( phis: guaranteedPhis, context)
262+ } ,
263+ // replacePhisWithIncomingValues
264+ { ( bridgedCtxt: BridgedPassContext , bridgedPhiArray: BridgedArrayRef ) in
265+ let context = FunctionPassContext ( _bridged: bridgedCtxt)
266+ var phis = [ Phi] ( )
267+ bridgedPhiArray. withElements ( ofType: BridgedValue . self) {
268+ phis = $0. map { Phi ( $0. value) ! }
269+ }
270+ replacePhisWithIncomingValues ( phis: phis, context)
175271 }
176272 )
177273}
0 commit comments