10824abbaSChris Fallin //! Alias analysis, consisting of a "last store" pass and a "memory
20824abbaSChris Fallin //! values" pass. These two passes operate as one fused pass, and so
30824abbaSChris Fallin //! are implemented together here.
40824abbaSChris Fallin //!
50824abbaSChris Fallin //! We partition memory state into several *disjoint pieces* of
60824abbaSChris Fallin //! "abstract state". There are a finite number of such pieces:
70824abbaSChris Fallin //! currently, we call them "heap", "table", "vmctx", and "other".Any
80824abbaSChris Fallin //! given address in memory belongs to exactly one disjoint piece.
90824abbaSChris Fallin //!
100824abbaSChris Fallin //! One never tracks which piece a concrete address belongs to at
110824abbaSChris Fallin //! runtime; this is a purely static concept. Instead, all
120824abbaSChris Fallin //! memory-accessing instructions (loads and stores) are labeled with
130824abbaSChris Fallin //! one of these four categories in the `MemFlags`. It is forbidden
140824abbaSChris Fallin //! for a load or store to access memory under one category and a
150824abbaSChris Fallin //! later load or store to access the same memory under a different
160824abbaSChris Fallin //! category. This is ensured to be true by construction during
170824abbaSChris Fallin //! frontend translation into CLIF and during legalization.
180824abbaSChris Fallin //!
190824abbaSChris Fallin //! Given that this non-aliasing property is ensured by the producer
200824abbaSChris Fallin //! of CLIF, we can compute a *may-alias* property: one load or store
210824abbaSChris Fallin //! may-alias another load or store if both access the same category
220824abbaSChris Fallin //! of abstract state.
230824abbaSChris Fallin //!
240824abbaSChris Fallin //! The "last store" pass helps to compute this aliasing: it scans the
250824abbaSChris Fallin //! code, finding at each program point the last instruction that
260824abbaSChris Fallin //! *might have* written to a given part of abstract state.
270824abbaSChris Fallin //!
280824abbaSChris Fallin //! We can't say for sure that the "last store" *did* actually write
290824abbaSChris Fallin //! that state, but we know for sure that no instruction *later* than
300824abbaSChris Fallin //! it (up to the current instruction) did. However, we can get a
310824abbaSChris Fallin //! must-alias property from this: if at a given load or store, we
320824abbaSChris Fallin //! look backward to the "last store", *AND* we find that it has
330824abbaSChris Fallin //! exactly the same address expression and type, then we know that
340824abbaSChris Fallin //! the current instruction's access *must* be to the same memory
350824abbaSChris Fallin //! location.
360824abbaSChris Fallin //!
370824abbaSChris Fallin //! To get this must-alias property, we compute a sparse table of
380824abbaSChris Fallin //! "memory values": these are known equivalences between SSA `Value`s
390824abbaSChris Fallin //! and particular locations in memory. The memory-values table is a
400824abbaSChris Fallin //! mapping from (last store, address expression, type) to SSA
410824abbaSChris Fallin //! value. At a store, we can insert into this table directly. At a
420824abbaSChris Fallin //! load, we can also insert, if we don't already have a value (from
430824abbaSChris Fallin //! the store that produced the load's value).
440824abbaSChris Fallin //!
450824abbaSChris Fallin //! Then we can do two optimizations at once given this table. If a
460824abbaSChris Fallin //! load accesses a location identified by a (last store, address,
470824abbaSChris Fallin //! type) key already in the table, we replace it with the SSA value
480824abbaSChris Fallin //! for that memory location. This is usually known as "redundant load
490824abbaSChris Fallin //! elimination" if the value came from an earlier load of the same
500824abbaSChris Fallin //! location, or "store-to-load forwarding" if the value came from an
510824abbaSChris Fallin //! earlier store to the same location.
520824abbaSChris Fallin //!
530824abbaSChris Fallin //! In theory we could also do *dead-store elimination*, where if a
540824abbaSChris Fallin //! store overwrites a key in the table, *and* if no other load/store
550824abbaSChris Fallin //! to the abstract state category occurred, *and* no other trapping
560824abbaSChris Fallin //! instruction occurred (at which point we need an up-to-date memory
570824abbaSChris Fallin //! state because post-trap-termination memory state can be observed),
580824abbaSChris Fallin //! *and* we can prove the original store could not have trapped, then
590824abbaSChris Fallin //! we can eliminate the original store. Because this is so complex,
600824abbaSChris Fallin //! and the conditions for doing it correctly when post-trap state
610824abbaSChris Fallin //! must be correct likely reduce the potential benefit, we don't yet
620824abbaSChris Fallin //! do this.
630824abbaSChris Fallin 
64*76911c29SSSD use crate::{FxHashMap, FxHashSet};
650824abbaSChris Fallin use crate::{
660824abbaSChris Fallin     cursor::{Cursor, FuncCursor},
673a14fa39SPaul Nodet     dominator_tree::DominatorTree,
680824abbaSChris Fallin     inst_predicates::{
690824abbaSChris Fallin         has_memory_fence_semantics, inst_addr_offset_type, inst_store_data, visit_block_succs,
700824abbaSChris Fallin     },
7190ac295eSAlex Crichton     ir::{AliasRegion, Block, Function, Inst, Opcode, Type, Value, immediates::Offset32},
728d022434SBenjamin Bouvier     trace,
730824abbaSChris Fallin };
7490ac295eSAlex Crichton use cranelift_entity::{EntityRef, packed_option::PackedOption};
750824abbaSChris Fallin 
760824abbaSChris Fallin /// For a given program point, the vector of last-store instruction
770824abbaSChris Fallin /// indices for each disjoint category of abstract state.
780824abbaSChris Fallin #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
79feaa7ca7SChris Fallin pub struct LastStores {
800824abbaSChris Fallin     heap: PackedOption<Inst>,
810824abbaSChris Fallin     table: PackedOption<Inst>,
820824abbaSChris Fallin     vmctx: PackedOption<Inst>,
830824abbaSChris Fallin     other: PackedOption<Inst>,
840824abbaSChris Fallin }
850824abbaSChris Fallin 
860824abbaSChris Fallin impl LastStores {
update(&mut self, func: &Function, inst: Inst)870824abbaSChris Fallin     fn update(&mut self, func: &Function, inst: Inst) {
8825bf8e0eSTrevor Elliott         let opcode = func.dfg.insts[inst].opcode();
890824abbaSChris Fallin         if has_memory_fence_semantics(opcode) {
900824abbaSChris Fallin             self.heap = inst.into();
910824abbaSChris Fallin             self.table = inst.into();
920824abbaSChris Fallin             self.vmctx = inst.into();
930824abbaSChris Fallin             self.other = inst.into();
940824abbaSChris Fallin         } else if opcode.can_store() {
9525bf8e0eSTrevor Elliott             if let Some(memflags) = func.dfg.insts[inst].memflags() {
96b651c441SAlex Crichton                 match memflags.alias_region() {
97b651c441SAlex Crichton                     None => self.other = inst.into(),
98b651c441SAlex Crichton                     Some(AliasRegion::Heap) => self.heap = inst.into(),
99b651c441SAlex Crichton                     Some(AliasRegion::Table) => self.table = inst.into(),
100b651c441SAlex Crichton                     Some(AliasRegion::Vmctx) => self.vmctx = inst.into(),
1010824abbaSChris Fallin                 }
1020824abbaSChris Fallin             } else {
1030824abbaSChris Fallin                 self.heap = inst.into();
1040824abbaSChris Fallin                 self.table = inst.into();
1050824abbaSChris Fallin                 self.vmctx = inst.into();
1060824abbaSChris Fallin                 self.other = inst.into();
1070824abbaSChris Fallin             }
1080824abbaSChris Fallin         }
1090824abbaSChris Fallin     }
1100824abbaSChris Fallin 
get_last_store(&self, func: &Function, inst: Inst) -> PackedOption<Inst>1110824abbaSChris Fallin     fn get_last_store(&self, func: &Function, inst: Inst) -> PackedOption<Inst> {
11225bf8e0eSTrevor Elliott         if let Some(memflags) = func.dfg.insts[inst].memflags() {
113b651c441SAlex Crichton             match memflags.alias_region() {
114b651c441SAlex Crichton                 None => self.other,
115b651c441SAlex Crichton                 Some(AliasRegion::Heap) => self.heap,
116b651c441SAlex Crichton                 Some(AliasRegion::Table) => self.table,
117b651c441SAlex Crichton                 Some(AliasRegion::Vmctx) => self.vmctx,
1180824abbaSChris Fallin             }
11925bf8e0eSTrevor Elliott         } else if func.dfg.insts[inst].opcode().can_load()
12025bf8e0eSTrevor Elliott             || func.dfg.insts[inst].opcode().can_store()
12125bf8e0eSTrevor Elliott         {
1220824abbaSChris Fallin             inst.into()
1230824abbaSChris Fallin         } else {
1240824abbaSChris Fallin             PackedOption::default()
1250824abbaSChris Fallin         }
1260824abbaSChris Fallin     }
1270824abbaSChris Fallin 
meet_from(&mut self, other: &LastStores, loc: Inst)1280824abbaSChris Fallin     fn meet_from(&mut self, other: &LastStores, loc: Inst) {
1290824abbaSChris Fallin         let meet = |a: PackedOption<Inst>, b: PackedOption<Inst>| -> PackedOption<Inst> {
1300824abbaSChris Fallin             match (a.into(), b.into()) {
1310824abbaSChris Fallin                 (None, None) => None.into(),
1320824abbaSChris Fallin                 (Some(a), None) => a,
1330824abbaSChris Fallin                 (None, Some(b)) => b,
1340824abbaSChris Fallin                 (Some(a), Some(b)) if a == b => a,
1350824abbaSChris Fallin                 _ => loc.into(),
1360824abbaSChris Fallin             }
1370824abbaSChris Fallin         };
1380824abbaSChris Fallin 
1390824abbaSChris Fallin         self.heap = meet(self.heap, other.heap);
1400824abbaSChris Fallin         self.table = meet(self.table, other.table);
1410824abbaSChris Fallin         self.vmctx = meet(self.vmctx, other.vmctx);
1420824abbaSChris Fallin         self.other = meet(self.other, other.other);
1430824abbaSChris Fallin     }
1440824abbaSChris Fallin }
1450824abbaSChris Fallin 
1460824abbaSChris Fallin /// A key identifying a unique memory location.
1470824abbaSChris Fallin ///
1480824abbaSChris Fallin /// For the result of a load to be equivalent to the result of another
1490824abbaSChris Fallin /// load, or the store data from a store, we need for (i) the
1500824abbaSChris Fallin /// "version" of memory (here ensured by having the same last store
1510824abbaSChris Fallin /// instruction to touch the disjoint category of abstract state we're
1520824abbaSChris Fallin /// accessing); (ii) the address must be the same (here ensured by
1530824abbaSChris Fallin /// having the same SSA value, which doesn't change after computed);
1540824abbaSChris Fallin /// (iii) the offset must be the same; and (iv) the accessed type and
1550824abbaSChris Fallin /// extension mode (e.g., 8-to-32, signed) must be the same.
1560824abbaSChris Fallin #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1570824abbaSChris Fallin struct MemoryLoc {
1580824abbaSChris Fallin     last_store: PackedOption<Inst>,
1590824abbaSChris Fallin     address: Value,
1600824abbaSChris Fallin     offset: Offset32,
1610824abbaSChris Fallin     ty: Type,
1620824abbaSChris Fallin     /// We keep the *opcode* of the instruction that produced the
1630824abbaSChris Fallin     /// value we record at this key if the opcode is anything other
1640824abbaSChris Fallin     /// than an ordinary load or store. This is needed when we
1650824abbaSChris Fallin     /// consider loads that extend the value: e.g., an 8-to-32
1660824abbaSChris Fallin     /// sign-extending load will produce a 32-bit value from an 8-bit
1670824abbaSChris Fallin     /// value in memory, so we can only reuse that (as part of RLE)
1680824abbaSChris Fallin     /// for another load with the same extending opcode.
1690824abbaSChris Fallin     ///
1700824abbaSChris Fallin     /// We could improve the transform to insert explicit extend ops
1710824abbaSChris Fallin     /// in place of extending loads when we know the memory value, but
1720824abbaSChris Fallin     /// we haven't yet done this.
1730824abbaSChris Fallin     extending_opcode: Option<Opcode>,
1740824abbaSChris Fallin }
1750824abbaSChris Fallin 
1760824abbaSChris Fallin /// An alias-analysis pass.
1770824abbaSChris Fallin pub struct AliasAnalysis<'a> {
1780824abbaSChris Fallin     /// The domtree for the function.
1793a14fa39SPaul Nodet     domtree: &'a DominatorTree,
1800824abbaSChris Fallin 
1810824abbaSChris Fallin     /// Input state to a basic block.
1820824abbaSChris Fallin     block_input: FxHashMap<Block, LastStores>,
1830824abbaSChris Fallin 
1840824abbaSChris Fallin     /// Known memory-value equivalences. This is the result of the
1850824abbaSChris Fallin     /// analysis. This is a mapping from (last store, address
1860824abbaSChris Fallin     /// expression, offset, type) to SSA `Value`.
1870824abbaSChris Fallin     ///
1880824abbaSChris Fallin     /// We keep the defining inst around for quick dominance checks.
1890824abbaSChris Fallin     mem_values: FxHashMap<MemoryLoc, (Inst, Value)>,
1900824abbaSChris Fallin }
1910824abbaSChris Fallin 
1920824abbaSChris Fallin impl<'a> AliasAnalysis<'a> {
1930824abbaSChris Fallin     /// Perform an alias analysis pass.
new(func: &Function, domtree: &'a DominatorTree) -> AliasAnalysis<'a>1943a14fa39SPaul Nodet     pub fn new(func: &Function, domtree: &'a DominatorTree) -> AliasAnalysis<'a> {
1958d022434SBenjamin Bouvier         trace!("alias analysis: input is:\n{:?}", func);
1960824abbaSChris Fallin         let mut analysis = AliasAnalysis {
1970824abbaSChris Fallin             domtree,
1980824abbaSChris Fallin             block_input: FxHashMap::default(),
1990824abbaSChris Fallin             mem_values: FxHashMap::default(),
2000824abbaSChris Fallin         };
2010824abbaSChris Fallin 
202feaa7ca7SChris Fallin         analysis.compute_block_input_states(func);
2030824abbaSChris Fallin         analysis
2040824abbaSChris Fallin     }
2050824abbaSChris Fallin 
compute_block_input_states(&mut self, func: &Function)206feaa7ca7SChris Fallin     fn compute_block_input_states(&mut self, func: &Function) {
2070824abbaSChris Fallin         let mut queue = vec![];
2080824abbaSChris Fallin         let mut queue_set = FxHashSet::default();
209feaa7ca7SChris Fallin         let entry = func.layout.entry_block().unwrap();
2100824abbaSChris Fallin         queue.push(entry);
2110824abbaSChris Fallin         queue_set.insert(entry);
2120824abbaSChris Fallin 
2130824abbaSChris Fallin         while let Some(block) = queue.pop() {
2140824abbaSChris Fallin             queue_set.remove(&block);
2150c0153c1SNick Fitzgerald             let mut state = *self
2160824abbaSChris Fallin                 .block_input
2170824abbaSChris Fallin                 .entry(block)
2180c0153c1SNick Fitzgerald                 .or_insert_with(|| LastStores::default());
2190824abbaSChris Fallin 
2208d022434SBenjamin Bouvier             trace!(
2210824abbaSChris Fallin                 "alias analysis: input to block{} is {:?}",
2220824abbaSChris Fallin                 block.index(),
2230824abbaSChris Fallin                 state
2240824abbaSChris Fallin             );
2250824abbaSChris Fallin 
226feaa7ca7SChris Fallin             for inst in func.layout.block_insts(block) {
227feaa7ca7SChris Fallin                 state.update(func, inst);
2288d022434SBenjamin Bouvier                 trace!("after inst{}: state is {:?}", inst.index(), state);
2290824abbaSChris Fallin             }
2300824abbaSChris Fallin 
231feaa7ca7SChris Fallin             visit_block_succs(func, block, |_inst, succ, _from_table| {
232703871a2SAlex Crichton                 let succ_first_inst = func.layout.block_insts(succ).next().unwrap();
2330824abbaSChris Fallin                 let updated = match self.block_input.get_mut(&succ) {
2340824abbaSChris Fallin                     Some(succ_state) => {
2350c0153c1SNick Fitzgerald                         let old = *succ_state;
2360824abbaSChris Fallin                         succ_state.meet_from(&state, succ_first_inst);
2370824abbaSChris Fallin                         *succ_state != old
2380824abbaSChris Fallin                     }
2390824abbaSChris Fallin                     None => {
2400c0153c1SNick Fitzgerald                         self.block_input.insert(succ, state);
2410824abbaSChris Fallin                         true
2420824abbaSChris Fallin                     }
2430824abbaSChris Fallin                 };
2440824abbaSChris Fallin 
2450824abbaSChris Fallin                 if updated && queue_set.insert(succ) {
2460824abbaSChris Fallin                     queue.push(succ);
2470824abbaSChris Fallin                 }
2480824abbaSChris Fallin             });
2490824abbaSChris Fallin         }
2500824abbaSChris Fallin     }
2510824abbaSChris Fallin 
252feaa7ca7SChris Fallin     /// Get the starting state for a block.
block_starting_state(&self, block: Block) -> LastStores253feaa7ca7SChris Fallin     pub fn block_starting_state(&self, block: Block) -> LastStores {
254feaa7ca7SChris Fallin         self.block_input
2550824abbaSChris Fallin             .get(&block)
2560824abbaSChris Fallin             .cloned()
257feaa7ca7SChris Fallin             .unwrap_or_else(|| LastStores::default())
258feaa7ca7SChris Fallin     }
2590824abbaSChris Fallin 
260feaa7ca7SChris Fallin     /// Process one instruction. Meant to be invoked in program order
261feaa7ca7SChris Fallin     /// within a block, and ideally in RPO or at least some domtree
262feaa7ca7SChris Fallin     /// preorder for maximal reuse.
263feaa7ca7SChris Fallin     ///
264feaa7ca7SChris Fallin     /// Returns `true` if instruction was removed.
process_inst( &mut self, func: &mut Function, state: &mut LastStores, inst: Inst, ) -> Option<Value>265feaa7ca7SChris Fallin     pub fn process_inst(
266feaa7ca7SChris Fallin         &mut self,
267feaa7ca7SChris Fallin         func: &mut Function,
268feaa7ca7SChris Fallin         state: &mut LastStores,
269feaa7ca7SChris Fallin         inst: Inst,
270feaa7ca7SChris Fallin     ) -> Option<Value> {
2718d022434SBenjamin Bouvier         trace!(
2720824abbaSChris Fallin             "alias analysis: scanning at inst{} with state {:?} ({:?})",
2730824abbaSChris Fallin             inst.index(),
2740824abbaSChris Fallin             state,
27525bf8e0eSTrevor Elliott             func.dfg.insts[inst],
2760824abbaSChris Fallin         );
2770824abbaSChris Fallin 
278feaa7ca7SChris Fallin         let replacing_value = if let Some((address, offset, ty)) = inst_addr_offset_type(func, inst)
279feaa7ca7SChris Fallin         {
280feaa7ca7SChris Fallin             let address = func.dfg.resolve_aliases(address);
28125bf8e0eSTrevor Elliott             let opcode = func.dfg.insts[inst].opcode();
2820824abbaSChris Fallin 
2830824abbaSChris Fallin             if opcode.can_store() {
284feaa7ca7SChris Fallin                 let store_data = inst_store_data(func, inst).unwrap();
285feaa7ca7SChris Fallin                 let store_data = func.dfg.resolve_aliases(store_data);
2860824abbaSChris Fallin                 let mem_loc = MemoryLoc {
2870824abbaSChris Fallin                     last_store: inst.into(),
2880824abbaSChris Fallin                     address,
2890824abbaSChris Fallin                     offset,
2900824abbaSChris Fallin                     ty,
2910824abbaSChris Fallin                     extending_opcode: get_ext_opcode(opcode),
2920824abbaSChris Fallin                 };
2938d022434SBenjamin Bouvier                 trace!(
2940824abbaSChris Fallin                     "alias analysis: at inst{}: store with data v{} at loc {:?}",
2950824abbaSChris Fallin                     inst.index(),
2960824abbaSChris Fallin                     store_data.index(),
2970824abbaSChris Fallin                     mem_loc
2980824abbaSChris Fallin                 );
2990824abbaSChris Fallin                 self.mem_values.insert(mem_loc, (inst, store_data));
300feaa7ca7SChris Fallin 
301feaa7ca7SChris Fallin                 None
3020824abbaSChris Fallin             } else if opcode.can_load() {
303feaa7ca7SChris Fallin                 let last_store = state.get_last_store(func, inst);
304feaa7ca7SChris Fallin                 let load_result = func.dfg.inst_results(inst)[0];
3050824abbaSChris Fallin                 let mem_loc = MemoryLoc {
3060824abbaSChris Fallin                     last_store,
3070824abbaSChris Fallin                     address,
3080824abbaSChris Fallin                     offset,
3090824abbaSChris Fallin                     ty,
3100824abbaSChris Fallin                     extending_opcode: get_ext_opcode(opcode),
3110824abbaSChris Fallin                 };
3128d022434SBenjamin Bouvier                 trace!(
3130824abbaSChris Fallin                     "alias analysis: at inst{}: load with last_store inst{} at loc {:?}",
3140824abbaSChris Fallin                     inst.index(),
3150824abbaSChris Fallin                     last_store.map(|inst| inst.index()).unwrap_or(usize::MAX),
3160824abbaSChris Fallin                     mem_loc
3170824abbaSChris Fallin                 );
3180824abbaSChris Fallin 
3190824abbaSChris Fallin                 // Is there a Value already known to be stored
3200824abbaSChris Fallin                 // at this specific memory location?  If so,
3210824abbaSChris Fallin                 // we can alias the load result to this
3220824abbaSChris Fallin                 // already-known Value.
3230824abbaSChris Fallin                 //
3240824abbaSChris Fallin                 // Check if the definition dominates this
3250824abbaSChris Fallin                 // location; it might not, if it comes from a
3260824abbaSChris Fallin                 // load (stores will always dominate though if
3270824abbaSChris Fallin                 // their `last_store` survives through
3280824abbaSChris Fallin                 // meet-points to this use-site).
329feaa7ca7SChris Fallin                 let aliased =
330feaa7ca7SChris Fallin                     if let Some((def_inst, value)) = self.mem_values.get(&mem_loc).cloned() {
3318d022434SBenjamin Bouvier                         trace!(
3320824abbaSChris Fallin                             " -> sees known value v{} from inst{}",
3330824abbaSChris Fallin                             value.index(),
3340824abbaSChris Fallin                             def_inst.index()
3350824abbaSChris Fallin                         );
3363a14fa39SPaul Nodet                         if self.domtree.dominates(def_inst, inst, &func.layout) {
3378d022434SBenjamin Bouvier                             trace!(
3380824abbaSChris Fallin                                 " -> dominates; value equiv from v{} to v{} inserted",
3390824abbaSChris Fallin                                 load_result.index(),
3400824abbaSChris Fallin                                 value.index()
3410824abbaSChris Fallin                             );
342feaa7ca7SChris Fallin                             Some(value)
3430824abbaSChris Fallin                         } else {
344feaa7ca7SChris Fallin                             None
3450824abbaSChris Fallin                         }
3460824abbaSChris Fallin                     } else {
347feaa7ca7SChris Fallin                         None
3480824abbaSChris Fallin                     };
3490824abbaSChris Fallin 
3500824abbaSChris Fallin                 // Otherwise, we can keep *this* load around
3510824abbaSChris Fallin                 // as a new equivalent value.
352feaa7ca7SChris Fallin                 if aliased.is_none() {
3538d022434SBenjamin Bouvier                     trace!(
3540824abbaSChris Fallin                         " -> inserting load result v{} at loc {:?}",
3550824abbaSChris Fallin                         load_result.index(),
3560824abbaSChris Fallin                         mem_loc
3570824abbaSChris Fallin                     );
3580824abbaSChris Fallin                     self.mem_values.insert(mem_loc, (inst, load_result));
3590824abbaSChris Fallin                 }
360feaa7ca7SChris Fallin 
361feaa7ca7SChris Fallin                 aliased
362feaa7ca7SChris Fallin             } else {
363feaa7ca7SChris Fallin                 None
3640824abbaSChris Fallin             }
365feaa7ca7SChris Fallin         } else {
366feaa7ca7SChris Fallin             None
367feaa7ca7SChris Fallin         };
368feaa7ca7SChris Fallin 
369feaa7ca7SChris Fallin         state.update(func, inst);
370feaa7ca7SChris Fallin 
371feaa7ca7SChris Fallin         replacing_value
3720824abbaSChris Fallin     }
3730824abbaSChris Fallin 
374feaa7ca7SChris Fallin     /// Make a pass and update known-redundant loads to aliased
375feaa7ca7SChris Fallin     /// values. We interleave the updates with the memory-location
376feaa7ca7SChris Fallin     /// tracking because resolving some aliases may expose others
377feaa7ca7SChris Fallin     /// (e.g. in cases of double-indirection with two separate chains
378feaa7ca7SChris Fallin     /// of loads).
compute_and_update_aliases(&mut self, func: &mut Function)379feaa7ca7SChris Fallin     pub fn compute_and_update_aliases(&mut self, func: &mut Function) {
380feaa7ca7SChris Fallin         let mut pos = FuncCursor::new(func);
381feaa7ca7SChris Fallin 
382feaa7ca7SChris Fallin         while let Some(block) = pos.next_block() {
383feaa7ca7SChris Fallin             let mut state = self.block_starting_state(block);
384feaa7ca7SChris Fallin             while let Some(inst) = pos.next_inst() {
385feaa7ca7SChris Fallin                 if let Some(replaced_result) = self.process_inst(pos.func, &mut state, inst) {
386feaa7ca7SChris Fallin                     let result = pos.func.dfg.inst_results(inst)[0];
387d02f895fSJamey Sharp                     pos.func.dfg.clear_results(inst);
388feaa7ca7SChris Fallin                     pos.func.dfg.change_to_alias(result, replaced_result);
389feaa7ca7SChris Fallin                     pos.remove_inst_and_step_back();
390feaa7ca7SChris Fallin                 }
3910824abbaSChris Fallin             }
3920824abbaSChris Fallin         }
3930824abbaSChris Fallin     }
3940824abbaSChris Fallin }
3950824abbaSChris Fallin 
get_ext_opcode(op: Opcode) -> Option<Opcode>3960824abbaSChris Fallin fn get_ext_opcode(op: Opcode) -> Option<Opcode> {
3970824abbaSChris Fallin     debug_assert!(op.can_load() || op.can_store());
3980824abbaSChris Fallin     match op {
3990824abbaSChris Fallin         Opcode::Load | Opcode::Store => None,
4000824abbaSChris Fallin         _ => Some(op),
4010824abbaSChris Fallin     }
4020824abbaSChris Fallin }
403