@@ -127,20 +127,24 @@ where
127127 }
128128
129129 pub ( super ) fn merge ( & mut self , states : & [ BranchState < K > ] ) {
130- let mut keys = HashSet :: default ( ) ;
130+ let mut inputs_by_key : HashMap < K , ( Vec < VersionId > , usize ) > = HashMap :: default ( ) ;
131131 for state in states {
132- keys. extend ( state. bindings . keys ( ) . copied ( ) ) ;
132+ for ( & key, & version) in & state. bindings {
133+ let ( inputs, bound_branches) =
134+ inputs_by_key. entry ( key) . or_insert_with ( || ( Vec :: new ( ) , 0 ) ) ;
135+ inputs. push ( version) ;
136+ * bound_branches += 1 ;
137+ }
133138 }
134- for key in keys {
139+ for ( key, ( mut inputs , bound_branches ) ) in inputs_by_key {
135140 let fallback = self
136141 . current
137142 . get ( & key)
138143 . copied ( )
139144 . unwrap_or_else ( || self . entry ( key) ) ;
140- let inputs = states
141- . iter ( )
142- . map ( |state| state. bindings . get ( & key) . copied ( ) . unwrap_or ( fallback) )
143- . collect ( ) ;
145+ if bound_branches < states. len ( ) {
146+ inputs. push ( fallback) ;
147+ }
144148 let version = self . phi ( inputs) ;
145149 self . bind ( key, version) ;
146150 }
@@ -298,4 +302,20 @@ mod tests {
298302 assert_eq ! ( outer_state. bindings[ "outer" ] , outer_definition) ;
299303 assert_eq ! ( outer_state. bindings[ "inner" ] , merged_inner) ;
300304 }
305+
306+ #[ test]
307+ fn merge_cost_tracks_sparse_bindings_not_branch_key_product ( ) {
308+ let mut ssa = SsaStore :: default ( ) ;
309+ let mut states = Vec :: new ( ) ;
310+ for key in 0 ..10_000 {
311+ let version = ssa. definition ( Vec :: new ( ) ) ;
312+ let mut bindings = HashMap :: default ( ) ;
313+ bindings. insert ( key, version) ;
314+ states. push ( BranchState { bindings } ) ;
315+ }
316+
317+ ssa. merge ( & states) ;
318+
319+ assert_eq ! ( ssa. current. len( ) , states. len( ) ) ;
320+ }
301321}
0 commit comments