@@ -4604,6 +4604,63 @@ impl Function {
46044604 self . infer_types ( ) ;
46054605 }
46064606
4607+ fn optimize_load_store ( & mut self ) {
4608+ // TODO: Add specific tests for load_store
4609+ // TODO: Add dead store elimination
4610+ // The key for the hashmap should be type and offset, with a value of value
4611+ // This lets us to index in with both load and store fields since insn_ids are probably always going to be different and we can't easily match on that
4612+ // So... how do we match against and store the enum label without all the data?? not sure yet :/
4613+ let mut compile_time_heap: HashMap < ( InsnId , i32 ) , InsnId > = HashMap :: new ( ) ;
4614+ for block in self . rpo ( ) {
4615+ let old_insns = std:: mem:: take ( & mut self . blocks [ block. 0 ] . insns ) ;
4616+ let mut new_insns = vec ! [ ] ;
4617+ for insn_id in old_insns {
4618+ let replacement_insn: InsnId = match self . find ( insn_id) {
4619+ Insn :: StoreField { recv, offset, val, .. } => {
4620+ let key = ( recv, offset) ;
4621+
4622+ let heap_entry = compile_time_heap. get ( & key) . copied ( ) ;
4623+ // TODO(Jacob): Switch from actual to partial equality
4624+ if Some ( val) == heap_entry {
4625+ // TODO(Jacob): Add TBAA to avoid removing so many entries
4626+ compile_time_heap. retain ( |( _, off) , _| * off == offset) ;
4627+ // If the value is already stored, short circuit and don't add an instruction to the block
4628+ continue
4629+ }
4630+ // TODO(Jacob): Add TBAA to avoid removing so many entries
4631+ compile_time_heap. retain ( |( _, off) , _| * off == offset) ;
4632+ compile_time_heap. insert ( key, val) ;
4633+ insn_id
4634+ } ,
4635+ Insn :: LoadField { recv, offset, .. } => {
4636+ let key = ( recv, offset) ;
4637+ match compile_time_heap. entry ( key) {
4638+ std:: collections:: hash_map:: Entry :: Occupied ( entry) => {
4639+ // If the value is already saved, we can't short circuit like we can with a store.
4640+ // However, we can avoid the load with a reference to the representative to the union from SSA.
4641+ self . make_equal_to ( insn_id, * entry. get ( ) ) ;
4642+ }
4643+ std:: collections:: hash_map:: Entry :: Vacant ( _) => {
4644+ // TODO(Jacob): Make sure this is correct, could be wrong?
4645+ compile_time_heap. insert ( key, insn_id) ;
4646+ }
4647+ }
4648+ insn_id
4649+ } ,
4650+ insn => {
4651+ // If an instruction affects memory and we haven't modeled it, the compile_time_heap is invalidated
4652+ if insn. effects_of ( ) . includes ( Effect :: write ( abstract_heaps:: Memory ) ) {
4653+ compile_time_heap. clear ( ) ;
4654+ }
4655+ insn_id
4656+ }
4657+ } ;
4658+ new_insns. push ( replacement_insn) ;
4659+ }
4660+ self . blocks [ block. 0 ] . insns = new_insns;
4661+ }
4662+ }
4663+
46074664 /// Fold a binary operator on fixnums.
46084665 fn fold_fixnum_bop ( & mut self , insn_id : InsnId , left : InsnId , right : InsnId , f : impl FnOnce ( Option < i64 > , Option < i64 > ) -> Option < i64 > ) -> InsnId {
46094666 f ( self . type_of ( left) . fixnum_value ( ) , self . type_of ( right) . fixnum_value ( ) )
@@ -5450,6 +5507,7 @@ impl Function {
54505507 run_pass ! ( inline) ;
54515508 run_pass ! ( optimize_getivar) ;
54525509 run_pass ! ( optimize_c_calls) ;
5510+ run_pass ! ( optimize_load_store) ;
54535511 run_pass ! ( fold_constants) ;
54545512 run_pass ! ( clean_cfg) ;
54555513 run_pass ! ( remove_redundant_patch_points) ;
0 commit comments