diff --git a/src/libcretonne/layout.rs b/src/libcretonne/layout.rs index 15748eda6a..d803858d0a 100644 --- a/src/libcretonne/layout.rs +++ b/src/libcretonne/layout.rs @@ -139,32 +139,53 @@ impl Layout { /// Get the EBB containing `inst`, or `None` if `inst` is not inserted in the layout. pub fn inst_ebb(&self, inst: Inst) -> Option { if self.insts.is_valid(inst) { - let ebb = self.insts[inst].ebb; - if ebb == NO_EBB { - None - } else { - Some(ebb) - } + self.insts[inst].ebb.wrap() } else { None } } /// Append `inst` to the end of `ebb`. - pub fn append_inst(&self, inst: Inst, ebb: Ebb) { + pub fn append_inst(&mut self, inst: Inst, ebb: Ebb) { assert_eq!(self.inst_ebb(inst), None); assert!(self.is_ebb_inserted(ebb), "Cannot append instructions to EBB not in layout"); - unimplemented!(); + let ebb_node = &mut self.ebbs[ebb]; + let inst_node = &mut self.insts[inst]; + inst_node.ebb = ebb; + inst_node.prev = ebb_node.last_inst; + assert_eq!(inst_node.next, NO_INST); + if ebb_node.first_inst == NO_INST { + ebb_node.first_inst = inst; + } } /// Insert `inst` before the instruction `before` in the same EBB. - pub fn insert_inst(&self, inst: Inst, before: Inst) { + pub fn insert_inst(&mut self, inst: Inst, before: Inst) { assert_eq!(self.inst_ebb(inst), None); let ebb = self.inst_ebb(before) .expect("Instruction before insertion point not in the layout"); - assert!(ebb != NO_EBB); - unimplemented!(); + let after = self.insts[before].prev; + { + let inst_node = &mut self.insts[inst]; + inst_node.ebb = ebb; + inst_node.next = before; + inst_node.prev = after; + } + self.insts[before].prev = inst; + if after == NO_INST { + self.ebbs[ebb].first_inst = inst; + } else { + self.insts[after].next = inst; + } + } + + /// Iterate over the instructions in `ebb` in layout order. + pub fn ebb_insts<'a>(&'a self, ebb: Ebb) -> Insts<'a> { + Insts { + layout: self, + next: self.ebbs[ebb].first_inst.wrap(), + } } } @@ -175,11 +196,31 @@ struct InstNode { next: Inst, } +/// Iterate over instructions in an EBB in layout order. See `Layout::ebb_insts()`. +pub struct Insts<'a> { + layout: &'a Layout, + next: Option, +} + +impl<'a> Iterator for Insts<'a> { + type Item = Inst; + + fn next(&mut self) -> Option { + match self.next { + Some(inst) => { + self.next = self.layout.insts[inst].next.wrap(); + Some(inst) + } + None => None, + } + } +} + #[cfg(test)] mod tests { use super::Layout; use entity_map::EntityRef; - use entities::Ebb; + use entities::{Ebb, Inst}; #[test] fn insert_ebb() { @@ -218,4 +259,43 @@ mod tests { let v: Vec = layout.ebbs().collect(); assert_eq!(v, [e2, e0, e1]); } + + #[test] + fn insert_inst() { + let mut layout = Layout::new(); + let e1 = Ebb::new(1); + + layout.append_ebb(e1); + let v: Vec = layout.ebb_insts(e1).collect(); + assert_eq!(v, []); + + let i0 = Inst::new(0); + let i1 = Inst::new(1); + let i2 = Inst::new(2); + + assert_eq!(layout.inst_ebb(i0), None); + assert_eq!(layout.inst_ebb(i1), None); + assert_eq!(layout.inst_ebb(i2), None); + + layout.append_inst(i1, e1); + assert_eq!(layout.inst_ebb(i0), None); + assert_eq!(layout.inst_ebb(i1), Some(e1)); + assert_eq!(layout.inst_ebb(i2), None); + let v: Vec = layout.ebb_insts(e1).collect(); + assert_eq!(v, [i1]); + + layout.insert_inst(i2, i1); + assert_eq!(layout.inst_ebb(i0), None); + assert_eq!(layout.inst_ebb(i1), Some(e1)); + assert_eq!(layout.inst_ebb(i2), Some(e1)); + let v: Vec = layout.ebb_insts(e1).collect(); + assert_eq!(v, [i2, i1]); + + layout.insert_inst(i0, i1); + assert_eq!(layout.inst_ebb(i0), Some(e1)); + assert_eq!(layout.inst_ebb(i1), Some(e1)); + assert_eq!(layout.inst_ebb(i2), Some(e1)); + let v: Vec = layout.ebb_insts(e1).collect(); + assert_eq!(v, [i2, i0, i1]); + } }