use crate::{
ir::{Block, Inst},
table::SecondaryTable,
};
use std::collections::HashMap;
#[derive(Default)]
pub struct FunctionLayout {
bbs: SecondaryTable<Block, BlockNode>,
first_bb: Option<Block>,
last_bb: Option<Block>,
inst_map: HashMap<Inst, Block>,
}
#[derive(Default)]
struct BlockNode {
prev: Option<Block>,
next: Option<Block>,
layout: InstLayout,
}
impl FunctionLayout {
pub fn new() -> Self {
Default::default()
}
}
impl FunctionLayout {
pub fn is_block_inserted(&self, bb: Block) -> bool {
self.bbs.contains(bb)
}
pub fn append_block(&mut self, bb: Block) {
self.bbs.add(
bb,
BlockNode {
prev: self.last_bb,
next: None,
layout: Default::default(),
},
);
if let Some(prev) = self.last_bb {
self.bbs[prev].next = Some(bb);
}
if self.first_bb.is_none() {
self.first_bb = Some(bb);
}
self.last_bb = Some(bb);
}
pub fn prepend_block(&mut self, bb: Block) {
self.bbs.add(
bb,
BlockNode {
prev: None,
next: self.first_bb,
layout: Default::default(),
},
);
if let Some(next) = self.first_bb {
self.bbs[next].prev = Some(bb);
}
if self.last_bb.is_none() {
self.last_bb = Some(bb);
}
self.first_bb = Some(bb);
}
pub fn insert_block_after(&mut self, bb: Block, after: Block) {
self.bbs.add(
bb,
BlockNode {
prev: Some(after),
next: self.bbs[after].next,
layout: Default::default(),
},
);
if let Some(next) = self.bbs[after].next {
self.bbs[next].prev = Some(bb);
}
self.bbs[after].next = Some(bb);
if self.last_bb == Some(after) {
self.last_bb = Some(bb);
}
}
pub fn insert_block_before(&mut self, bb: Block, before: Block) {
self.bbs.add(
bb,
BlockNode {
prev: self.bbs[before].prev,
next: Some(before),
layout: Default::default(),
},
);
if let Some(prev) = self.bbs[before].prev {
self.bbs[prev].next = Some(bb);
}
self.bbs[before].prev = Some(bb);
if self.first_bb == Some(before) {
self.first_bb = Some(bb);
}
}
pub fn remove_block(&mut self, bb: Block) {
let node = self.bbs.remove(bb).unwrap();
if let Some(next) = node.next {
self.bbs[next].prev = node.prev;
}
if let Some(prev) = node.prev {
self.bbs[prev].next = node.next;
}
if self.first_bb == Some(bb) {
self.first_bb = node.next;
}
if self.last_bb == Some(bb) {
self.last_bb = node.prev;
}
}
pub fn swap_blocks(&mut self, bb0: Block, bb1: Block) {
if bb0 == bb1 {
return;
}
let mut bb0_next = self.bbs[bb0].next;
let mut bb0_prev = self.bbs[bb0].prev;
let mut bb1_next = self.bbs[bb1].next;
let mut bb1_prev = self.bbs[bb1].prev;
if bb0_next == Some(bb1) {
bb0_next = Some(bb0);
}
if bb0_prev == Some(bb1) {
bb0_prev = Some(bb0);
}
if bb1_next == Some(bb0) {
bb1_next = Some(bb1);
}
if bb1_prev == Some(bb0) {
bb1_prev = Some(bb1);
}
self.bbs[bb0].next = bb1_next;
self.bbs[bb0].prev = bb1_prev;
self.bbs[bb1].next = bb0_next;
self.bbs[bb1].prev = bb0_prev;
if let Some(next) = bb0_next {
self.bbs[next].prev = Some(bb1);
}
if let Some(prev) = bb0_prev {
self.bbs[prev].next = Some(bb1);
}
if let Some(next) = bb1_next {
self.bbs[next].prev = Some(bb0);
}
if let Some(prev) = bb1_prev {
self.bbs[prev].next = Some(bb0);
}
if self.first_bb == Some(bb0) {
self.first_bb = Some(bb1);
} else if self.first_bb == Some(bb1) {
self.first_bb = Some(bb0);
}
if self.last_bb == Some(bb0) {
self.last_bb = Some(bb1);
} else if self.last_bb == Some(bb1) {
self.last_bb = Some(bb0);
}
}
pub fn blocks<'a>(&'a self) -> impl Iterator<Item = Block> + 'a {
std::iter::successors(self.first_bb, move |&bb| self.next_block(bb))
}
pub fn first_block(&self) -> Option<Block> {
self.first_bb
}
pub fn last_block(&self) -> Option<Block> {
self.last_bb
}
pub fn prev_block(&self, bb: Block) -> Option<Block> {
self.bbs[bb].prev
}
pub fn next_block(&self, bb: Block) -> Option<Block> {
self.bbs[bb].next
}
}
#[derive(Default)]
pub struct InstLayout {
insts: SecondaryTable<Inst, InstNode>,
first_inst: Option<Inst>,
last_inst: Option<Inst>,
}
#[derive(Default)]
struct InstNode {
prev: Option<Inst>,
next: Option<Inst>,
}
impl InstLayout {
pub fn new() -> Self {
Default::default()
}
pub fn is_inst_inserted(&self, inst: Inst) -> bool {
self.insts.contains(inst)
}
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),
},
);
self.insts[before].prev = Some(inst);
if let Some(prev) = self.insts[before].prev {
self.insts[prev].next = 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
}
}
impl FunctionLayout {
pub fn inst_block(&self, inst: Inst) -> Option<Block> {
self.inst_map.get(&inst).cloned()
}
pub fn append_inst(&mut self, inst: Inst, bb: Block) {
self.bbs[bb].layout.append_inst(inst);
self.inst_map.insert(inst, bb);
}
pub fn prepend_inst(&mut self, inst: Inst, bb: Block) {
self.bbs[bb].layout.prepend_inst(inst);
self.inst_map.insert(inst, bb);
}
pub fn insert_inst_after(&mut self, inst: Inst, after: Inst) {
let bb = self.inst_block(after).expect("`after` not inserted");
self.bbs[bb].layout.insert_inst_after(inst, after);
self.inst_map.insert(inst, bb);
}
pub fn insert_inst_before(&mut self, inst: Inst, before: Inst) {
let bb = self.inst_block(before).expect("`before` not inserted");
self.bbs[bb].layout.insert_inst_before(inst, before);
self.inst_map.insert(inst, bb);
}
pub fn remove_inst(&mut self, inst: Inst) {
let bb = self.inst_block(inst).expect("`inst` not inserted");
self.bbs[bb].layout.remove_inst(inst);
self.inst_map.remove(&inst);
}
pub fn insts<'a>(&'a self, bb: Block) -> impl Iterator<Item = Inst> + 'a {
self.bbs[bb].layout.insts()
}
pub fn first_inst(&self, bb: Block) -> Option<Inst> {
self.bbs[bb].layout.first_inst()
}
pub fn last_inst(&self, bb: Block) -> Option<Inst> {
self.bbs[bb].layout.last_inst()
}
pub fn prev_inst(&self, inst: Inst) -> Option<Inst> {
let bb = self.inst_block(inst).unwrap();
self.bbs[bb].layout.prev_inst(inst)
}
pub fn next_inst(&self, inst: Inst) -> Option<Inst> {
let bb = self.inst_block(inst).unwrap();
self.bbs[bb].layout.next_inst(inst)
}
}