use crate::ir::entities::{BasicBlock, Value};
use key_node_list::{KeyNodeList, Map, impl_node};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::{HashMap, hash_map::Entry};
use std::hash::Hash;
use std::rc::{Rc, Weak};
pub struct Layout {
bbs: BasicBlockList,
inst_bb: Rc<RefCell<HashMap<Value, BasicBlock>>>,
}
impl Layout {
pub fn new() -> Self {
Self::default()
}
pub fn bbs(&self) -> &BasicBlockList {
&self.bbs
}
pub fn bbs_mut(&mut self) -> &mut BasicBlockList {
&mut self.bbs
}
pub fn bb_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockNode {
self.bbs.node_mut(&bb).expect("`bb` does not exist")
}
pub fn entry_bb(&self) -> Option<BasicBlock> {
self.bbs.front_key().copied()
}
pub fn parent_bb(&self, inst: Value) -> Option<BasicBlock> {
self.inst_bb.as_ref().borrow().get(&inst).copied()
}
}
impl Default for Layout {
fn default() -> Self {
let inst_bb = Rc::new(RefCell::new(HashMap::new()));
Self {
bbs: BasicBlockList::with_map(BasicBlockMap::new(Rc::downgrade(&inst_bb))),
inst_bb,
}
}
}
pub type BasicBlockList = KeyNodeList<BasicBlock, BasicBlockNode, BasicBlockMap>;
type InstBBCell = Weak<RefCell<HashMap<Value, BasicBlock>>>;
pub struct BasicBlockMap {
inst_bb: InstBBCell,
map: HashMap<BasicBlock, BasicBlockNode>,
}
impl BasicBlockMap {
fn new(inst_bb: InstBBCell) -> Self {
Self {
inst_bb,
map: HashMap::new(),
}
}
}
impl Map<BasicBlock, BasicBlockNode> for BasicBlockMap {
fn len(&self) -> usize {
self.map.len()
}
fn clear(&mut self) {
self.map.clear()
}
fn get<Q>(&self, k: &Q) -> Option<&BasicBlockNode>
where
BasicBlock: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get(k)
}
fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut BasicBlockNode>
where
BasicBlock: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get_mut(k)
}
fn insert<T>(&mut self, k: BasicBlock, v: T) -> Result<(), (BasicBlock, T)>
where
T: Into<BasicBlockNode>,
{
if let Entry::Vacant(e) = self.map.entry(k) {
let node = BasicBlockNode::new(k, self.inst_bb.clone());
e.insert(node);
Ok(())
} else {
Err((k, v))
}
}
fn remove_entry<Q>(&mut self, k: &Q) -> Option<(BasicBlock, BasicBlockNode)>
where
BasicBlock: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.remove_entry(k)
}
}
pub struct BasicBlockNode {
insts: InstList,
prev: Option<BasicBlock>,
next: Option<BasicBlock>,
}
impl_node!(BasicBlockNode { Key = BasicBlock, prev = prev, next = next });
impl BasicBlockNode {
fn new(bb: BasicBlock, inst_bb: InstBBCell) -> Self {
Self {
insts: InstList::with_map(InstMap::new(bb, inst_bb)),
prev: None,
next: None,
}
}
pub fn insts(&self) -> &InstList {
&self.insts
}
pub fn insts_mut(&mut self) -> &mut InstList {
&mut self.insts
}
}
impl From<()> for BasicBlockNode {
fn from(_: ()) -> Self {
panic!("shound not be called")
}
}
pub type InstList = KeyNodeList<Value, InstNode, InstMap>;
pub struct InstMap {
bb: BasicBlock,
inst_bb: InstBBCell,
map: HashMap<Value, InstNode>,
}
impl InstMap {
fn new(bb: BasicBlock, inst_bb: InstBBCell) -> Self {
Self {
bb,
inst_bb,
map: HashMap::new(),
}
}
}
impl Map<Value, InstNode> for InstMap {
fn len(&self) -> usize {
self.map.len()
}
fn clear(&mut self) {
self.map.clear()
}
fn get<Q>(&self, k: &Q) -> Option<&InstNode>
where
Value: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get(k)
}
fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut InstNode>
where
Value: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get_mut(k)
}
fn insert<T>(&mut self, k: Value, v: T) -> Result<(), (Value, T)>
where
T: Into<InstNode>,
{
if self.contains_key(&k) {
Err((k, v))
} else {
self
.inst_bb
.upgrade()
.unwrap()
.as_ref()
.borrow_mut()
.insert(k, self.bb);
self.map.insert(k, v.into());
Ok(())
}
}
fn remove_entry<Q>(&mut self, k: &Q) -> Option<(Value, InstNode)>
where
Value: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
let kv = self.map.remove_entry(k);
if kv.is_some() {
self
.inst_bb
.upgrade()
.unwrap()
.as_ref()
.borrow_mut()
.remove(k);
}
kv
}
}
pub struct InstNode {
prev: Option<Value>,
next: Option<Value>,
}
impl_node!(InstNode { Key = Value, prev = prev, next = next });
impl From<()> for InstNode {
fn from(_: ()) -> Self {
Self {
prev: None,
next: None,
}
}
}