use crate::block::*;
use crate::inst::*;
use crate::util::IndirectMapIter;
use crate::value::{BlockRef, InstRef};
use std;
use std::collections::HashMap;
pub struct SeqBody {
blocks: HashMap<BlockRef, Block>,
block_seq: Vec<BlockRef>,
block_of_inst: HashMap<InstRef, BlockRef>,
insts: HashMap<InstRef, Inst>,
}
impl SeqBody {
pub fn new() -> SeqBody {
SeqBody {
blocks: HashMap::new(),
block_seq: Vec::new(),
block_of_inst: HashMap::new(),
insts: HashMap::new(),
}
}
pub fn add_block(&mut self, block: Block, pos: BlockPosition) -> BlockRef {
let br = block.as_ref();
self.blocks.insert(br, block);
self.insert_block(br, pos, false);
br
}
pub fn move_block(&mut self, block: BlockRef, pos: BlockPosition) {
self.detach_block(block, true);
self.insert_block(block, pos, true);
}
pub fn remove_block(&mut self, block: BlockRef) {
self.detach_block(block, false);
self.blocks.remove(&block);
}
fn insert_block(&mut self, block: BlockRef, pos: BlockPosition, just_move: bool) {
let index = match pos {
BlockPosition::Begin => 0,
BlockPosition::End => self.block_seq.len(),
BlockPosition::Before(b) => self.block_pos(b),
BlockPosition::After(b) => self.block_pos(b) + 1,
};
self.block_seq.insert(index, block);
if !just_move {
let insts: Vec<InstRef> = self.blocks[&block].inst_refs().map(|r| *r).collect();
self.block_of_inst.extend(insts.iter().map(|r| (*r, block)));
}
}
fn detach_block(&mut self, block: BlockRef, just_move: bool) {
let pos = self.block_pos(block);
self.block_seq.remove(pos);
if !just_move {
let insts: Vec<InstRef> = self.blocks[&block].inst_refs().map(|r| *r).collect();
for inst in insts {
self.block_of_inst.remove(&inst);
}
}
}
fn block_pos(&self, block: BlockRef) -> usize {
self.block_seq
.iter()
.position(|&b| b == block)
.expect("body does not contain basic block")
}
pub fn add_inst(&mut self, inst: Inst, pos: InstPosition) -> InstRef {
let ir = inst.as_ref();
self.insts.insert(ir, inst);
self.insert_inst(ir, pos);
ir
}
pub fn move_inst(&mut self, inst: InstRef, pos: InstPosition) {
self.detach_inst(inst);
self.insert_inst(inst, pos);
}
pub fn remove_inst(&mut self, inst: InstRef) {
self.detach_inst(inst);
self.insts.remove(&inst);
}
fn insert_inst(&mut self, inst: InstRef, pos: InstPosition) {
let block = match pos {
InstPosition::Begin => self
.blocks
.get_mut(self.block_seq.first().unwrap())
.unwrap(),
InstPosition::End => self.blocks.get_mut(self.block_seq.last().unwrap()).unwrap(),
InstPosition::BlockBegin(b) | InstPosition::BlockEnd(b) => {
self.blocks.get_mut(&b).unwrap()
}
InstPosition::Before(i) | InstPosition::After(i) => {
self.blocks.get_mut(&self.block_of_inst[&i]).unwrap()
}
};
block.insert_inst(inst, pos);
self.block_of_inst.insert(inst, block.as_ref());
}
fn detach_inst(&mut self, inst: InstRef) {
self.block_of_inst.remove(&inst);
self.blocks
.get_mut(&self.block_of_inst[&inst])
.unwrap()
.detach_inst(inst)
}
pub fn blocks(&self) -> IndirectMapIter<std::slice::Iter<BlockRef>, Block> {
IndirectMapIter::new(self.block_seq.iter(), &self.blocks)
}
pub fn block(&self, block: BlockRef) -> &Block {
self.blocks.get(&block).unwrap()
}
pub fn block_mut(&mut self, block: BlockRef) -> &mut Block {
self.blocks.get_mut(&block).unwrap()
}
pub fn inst(&self, inst: InstRef) -> &Inst {
self.insts.get(&inst).unwrap()
}
pub fn inst_mut(&mut self, inst: InstRef) -> &mut Inst {
self.insts.get_mut(&inst).unwrap()
}
}