use crate::{
ir::{Block, Inst},
table::SecondaryTable,
};
use std::collections::HashMap;
#[derive(Default, Serialize, Deserialize)]
pub(super) struct FunctionLayout {
pub(super) bbs: SecondaryTable<Block, BlockNode>,
pub(super) first_bb: Option<Block>,
pub(super) last_bb: Option<Block>,
pub(super) inst_map: HashMap<Inst, Block>,
}
#[derive(Default, Serialize, Deserialize)]
pub(super) struct BlockNode {
pub(super) prev: Option<Block>,
pub(super) next: Option<Block>,
pub(super) layout: InstLayout,
}
#[derive(Default, Serialize, Deserialize)]
pub(super) struct InstLayout {
insts: SecondaryTable<Inst, InstNode>,
first_inst: Option<Inst>,
last_inst: Option<Inst>,
}
#[derive(Default, Serialize, Deserialize)]
struct InstNode {
prev: Option<Inst>,
next: Option<Inst>,
}
impl FunctionLayout {
pub(super) fn map_inst(&mut self, inst: Inst, bb: Block) {
match self.inst_map.insert(inst, bb) {
Some(old_bb) => panic!(
"inst {} already inserted in {}, now being inserted into {}",
inst, old_bb, bb
),
None => (),
}
}
pub(super) fn unmap_inst(&mut self, inst: Inst) {
match self.inst_map.remove(&inst) {
Some(_) => (),
None => panic!("inst {} was not inserted"),
}
}
}
impl InstLayout {
pub fn append_inst(&mut self, inst: Inst) {
self.insts.add(
inst,
InstNode {
prev: self.last_inst,
next: None,
},
);
if let Some(prev) = self.last_inst {
self.insts[prev].next = Some(inst);
}
if self.first_inst.is_none() {
self.first_inst = Some(inst);
}
self.last_inst = Some(inst);
}
pub fn prepend_inst(&mut self, inst: Inst) {
self.insts.add(
inst,
InstNode {
prev: None,
next: self.first_inst,
},
);
if let Some(next) = self.first_inst {
self.insts[next].prev = Some(inst);
}
if self.last_inst.is_none() {
self.last_inst = Some(inst);
}
self.first_inst = Some(inst);
}
pub fn insert_inst_after(&mut self, inst: Inst, after: Inst) {
self.insts.add(
inst,
InstNode {
prev: Some(after),
next: self.insts[after].next,
},
);
if let Some(next) = self.insts[after].next {
self.insts[next].prev = Some(inst);
}
self.insts[after].next = Some(inst);
if self.last_inst == Some(after) {
self.last_inst = Some(inst);
}
}
pub fn insert_inst_before(&mut self, inst: Inst, before: Inst) {
self.insts.add(
inst,
InstNode {
prev: self.insts[before].prev,
next: Some(before),
},
);
if let Some(prev) = self.insts[before].prev {
self.insts[prev].next = Some(inst);
}
self.insts[before].prev = Some(inst);
if self.first_inst == Some(before) {
self.first_inst = Some(inst);
}
}
pub fn remove_inst(&mut self, inst: Inst) {
let node = self.insts.remove(inst).unwrap();
if let Some(next) = node.next {
self.insts[next].prev = node.prev;
}
if let Some(prev) = node.prev {
self.insts[prev].next = node.next;
}
if self.first_inst == Some(inst) {
self.first_inst = node.next;
}
if self.last_inst == Some(inst) {
self.last_inst = node.prev;
}
}
pub fn insts<'a>(&'a self) -> impl Iterator<Item = Inst> + 'a {
std::iter::successors(self.first_inst, move |&inst| self.next_inst(inst))
}
pub fn first_inst(&self) -> Option<Inst> {
self.first_inst
}
pub fn last_inst(&self) -> Option<Inst> {
self.last_inst
}
pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
self.insts[inst].prev
}
pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
self.insts[inst].next
}
}