use crate::{
analysis::{DominatorTree, PredecessorTable, TemporalRegionGraph},
ir::{
layout::BlockNode, prelude::*, BlockData, ControlFlowGraph, DataFlowGraph, ExtUnit,
ExtUnitData, FunctionLayout, InstBuilder, InstData, UnitId, ValueData,
},
table::TableKey,
verifier::Verifier,
void_ty, Type,
};
use std::{
collections::HashSet,
ops::{Deref, Index, IndexMut},
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum UnitName {
Anonymous(u32),
Local(String),
Global(String),
}
impl UnitName {
pub fn anonymous(id: u32) -> Self {
UnitName::Anonymous(id)
}
pub fn local(name: impl Into<String>) -> Self {
UnitName::Local(name.into())
}
pub fn global(name: impl Into<String>) -> Self {
UnitName::Global(name.into())
}
pub fn is_local(&self) -> bool {
match self {
UnitName::Anonymous(..) | UnitName::Local(..) => true,
_ => false,
}
}
pub fn is_global(&self) -> bool {
match self {
UnitName::Global(..) => true,
_ => false,
}
}
pub fn get_name(&self) -> Option<&str> {
match self {
UnitName::Global(n) | UnitName::Local(n) => Some(n.as_str()),
_ => None,
}
}
}
impl std::fmt::Display for UnitName {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
UnitName::Anonymous(id) => write!(f, "%{}", id),
UnitName::Local(n) => write!(f, "%{}", n),
UnitName::Global(n) => write!(f, "@{}", n),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnitKind {
Function,
Process,
Entity,
}
impl std::fmt::Display for UnitKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
UnitKind::Function => write!(f, "func"),
UnitKind::Process => write!(f, "proc"),
UnitKind::Entity => write!(f, "entity"),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct UnitData {
pub kind: UnitKind,
pub name: UnitName,
pub(super) sig: Signature,
pub(super) dfg: DataFlowGraph,
pub(super) cfg: ControlFlowGraph,
pub(super) layout: FunctionLayout,
}
impl UnitData {
pub fn new(kind: UnitKind, name: UnitName, sig: Signature) -> Self {
match kind {
UnitKind::Function => {
assert!(!sig.has_outputs());
assert!(sig.has_return_type());
}
UnitKind::Process | UnitKind::Entity => {
assert!(!sig.has_return_type());
}
}
let mut data = Self {
kind,
name,
sig,
dfg: Default::default(),
cfg: Default::default(),
layout: Default::default(),
};
let mut unit = UnitBuilder::new_anonymous(&mut data);
if kind == UnitKind::Entity {
unit.block();
unit.insert_at_end();
unit.ins().halt();
}
unit.make_args_for_signature(&unit.sig().clone());
data
}
}
#[derive(Clone, Copy)]
pub struct Unit<'a> {
unit: UnitId,
data: &'a UnitData,
}
impl<'a> Unit<'a> {
pub fn new(unit: UnitId, data: &'a UnitData) -> Self {
Self { unit, data }
}
pub fn new_anonymous(data: &'a UnitData) -> Self {
Self::new(UnitId::invalid(), data)
}
#[inline(always)]
pub fn id(self) -> UnitId {
self.unit
}
#[inline(always)]
pub fn data(self) -> &'a UnitData {
self.data
}
pub fn kind(&self) -> UnitKind {
self.data.kind
}
pub fn sig(self) -> &'a Signature {
&self.data.sig
}
pub fn name(self) -> &'a UnitName {
&self.data.name
}
#[deprecated(since = "0.13.0", note = "simply drop the dump()")]
pub fn dump(self) -> Self {
self
}
pub fn verify(self) {
let mut verifier = Verifier::new();
verifier.verify_unit(self);
match verifier.finish() {
Ok(()) => (),
Err(errs) => {
eprintln!("");
eprintln!("Verified {}:", self.data.kind);
eprintln!("{}", self);
eprintln!("");
eprintln!("Verification errors:");
eprintln!("{}", errs);
panic!("verification failed");
}
}
}
pub fn is_function(self) -> bool {
self.kind() == UnitKind::Function
}
pub fn is_process(self) -> bool {
self.kind() == UnitKind::Process
}
pub fn is_entity(self) -> bool {
self.kind() == UnitKind::Entity
}
pub fn input_args(self) -> impl Iterator<Item = Value> + 'a {
self.sig().inputs().map(move |arg| self.arg_value(arg))
}
pub fn output_args(self) -> impl Iterator<Item = Value> + 'a {
self.sig().outputs().map(move |arg| self.arg_value(arg))
}
pub fn args(self) -> impl Iterator<Item = Value> + 'a {
self.sig().args().map(move |arg| self.arg_value(arg))
}
pub fn input_arg(self, pos: usize) -> Value {
self.arg_value(
self.sig()
.inputs()
.nth(pos)
.expect("input argument position out of bounds"),
)
}
pub fn output_arg(self, pos: usize) -> Value {
self.arg_value(
self.sig()
.outputs()
.nth(pos)
.expect("output argument position out of bounds"),
)
}
pub fn extern_name(self, ext: ExtUnit) -> &'a UnitName {
&self.data.dfg[ext].name
}
pub fn extern_sig(self, ext: ExtUnit) -> &'a Signature {
&self.data.dfg[ext].sig
}
pub fn extern_units(self) -> impl Iterator<Item = (ExtUnit, &'a ExtUnitData)> + 'a {
self.data.dfg.ext_units.iter()
}
}
impl<'a> Unit<'a> {
pub fn trg(self) -> TemporalRegionGraph {
#[allow(deprecated)]
TemporalRegionGraph::new(&self)
}
pub fn predtbl(self) -> PredecessorTable {
#[allow(deprecated)]
PredecessorTable::new(&self)
}
pub fn temporal_predtbl(self) -> PredecessorTable {
#[allow(deprecated)]
PredecessorTable::new_temporal(&self)
}
pub fn domtree(self) -> DominatorTree {
self.domtree_with_predtbl(&self.predtbl())
}
pub fn temporal_domtree(self) -> DominatorTree {
self.domtree_with_predtbl(&self.temporal_predtbl())
}
pub fn domtree_with_predtbl(self, pt: &PredecessorTable) -> DominatorTree {
#[allow(deprecated)]
DominatorTree::new(&self, pt)
}
}
impl<'a> Unit<'a> {
pub fn get_block_name(self, bb: Block) -> Option<&'a str> {
self.data.cfg[bb].name.as_ref().map(AsRef::as_ref)
}
pub fn get_anonymous_block_hint(self, bb: Block) -> Option<u32> {
self.data.cfg.anonymous_hints.get(&bb).cloned()
}
}
impl<'a> Unit<'a> {
pub fn is_placeholder(self, value: Value) -> bool {
self[value].is_placeholder()
}
pub fn has_result(self, inst: Inst) -> bool {
self.data.dfg.results.storage.contains_key(&inst.index())
}
pub fn inst_result(self, inst: Inst) -> Value {
self.data.dfg.results[inst]
}
pub fn get_inst_result(self, inst: Inst) -> Option<Value> {
self.data.dfg.results.get(inst).cloned()
}
pub fn arg_value(self, arg: Arg) -> Value {
self.data.dfg.args[arg]
}
pub fn value_type(self, value: Value) -> Type {
match &self[value] {
ValueData::Invalid => panic!("invalid value"),
ValueData::Inst { ty, .. } => ty.clone(),
ValueData::Arg { ty, .. } => ty.clone(),
ValueData::Placeholder { ty, .. } => ty.clone(),
}
}
pub fn inst_type(self, inst: Inst) -> Type {
if self.has_result(inst) {
self.value_type(self.inst_result(inst))
} else {
void_ty()
}
}
pub fn get_value_arg(self, value: Value) -> Option<Arg> {
match self[value] {
ValueData::Arg { arg, .. } => Some(arg),
_ => None,
}
}
pub fn value_arg(self, value: Value) -> Arg {
match self.get_value_arg(value) {
Some(arg) => arg,
None => panic!("value {} not an argument", value),
}
}
pub fn get_value_inst(self, value: Value) -> Option<Inst> {
match self[value] {
ValueData::Inst { inst, .. } => Some(inst),
_ => None,
}
}
pub fn value_inst(self, value: Value) -> Inst {
match self.get_value_inst(value) {
Some(inst) => inst,
None => panic!("value {} not the result of an instruction", value),
}
}
pub fn get_name(self, value: Value) -> Option<&'a str> {
self.data.dfg.names.get(&value).map(AsRef::as_ref)
}
pub fn get_anonymous_hint(self, value: Value) -> Option<u32> {
self.data.dfg.anonymous_hints.get(&value).cloned()
}
pub fn uses(self, value: Value) -> &'a HashSet<Inst> {
&self.data.dfg.value_uses[&value]
}
pub fn has_uses(self, value: Value) -> bool {
!self.uses(value).is_empty()
}
pub fn has_one_use(self, value: Value) -> bool {
self.uses(value).len() == 1
}
pub fn get_const(self, value: Value) -> Option<crate::Value> {
let inst = self.get_value_inst(value)?;
match self[inst].opcode() {
Opcode::ConstInt => self.get_const_int(value).cloned().map(Into::into),
Opcode::ConstTime => self.get_const_time(value).cloned().map(Into::into),
Opcode::Array | Opcode::ArrayUniform => self.get_const_array(value).map(Into::into),
Opcode::Struct => self.get_const_struct(value).map(Into::into),
_ => None,
}
}
pub fn get_const_time(self, value: Value) -> Option<&'a crate::TimeValue> {
let inst = self.get_value_inst(value)?;
self.data.dfg[inst].get_const_time()
}
pub fn get_const_int(self, value: Value) -> Option<&'a crate::IntValue> {
let inst = self.get_value_inst(value)?;
self.data.dfg[inst].get_const_int()
}
pub fn get_const_array(self, value: Value) -> Option<crate::ArrayValue> {
let inst = self.get_value_inst(value)?;
match self[inst].opcode() {
Opcode::Array => {
let args: Option<Vec<_>> = self[inst]
.args()
.iter()
.map(|&a| self.get_const(a))
.collect();
Some(crate::ArrayValue::new(args?))
}
Opcode::ArrayUniform => Some(crate::ArrayValue::new_uniform(
self[inst].imms()[0],
self.get_const(self[inst].args()[0])?,
)),
_ => None,
}
}
pub fn get_const_struct(self, value: Value) -> Option<crate::StructValue> {
let inst = self.get_value_inst(value)?;
match self[inst].opcode() {
Opcode::Struct => {
let args: Option<Vec<_>> = self[inst]
.args()
.iter()
.map(|&a| self.get_const(a))
.collect();
Some(crate::StructValue::new(args?))
}
_ => None,
}
}
pub fn location_hint(self, inst: Inst) -> Option<usize> {
self.data.dfg.location_hints.get(&inst).cloned()
}
pub fn block_id_bound(self) -> usize {
self.data.cfg.blocks.capacity()
}
}
impl<'a> Unit<'a> {
pub fn blocks(self) -> impl Iterator<Item = Block> + 'a {
let layout = &self.data.layout;
std::iter::successors(layout.first_bb, move |&bb| self.next_block(bb))
}
pub fn is_block_inserted(self, bb: Block) -> bool {
self.data.layout.bbs.contains(bb)
}
pub fn first_block(self) -> Option<Block> {
let layout = &self.data.layout;
layout.first_bb
}
pub fn last_block(self) -> Option<Block> {
let layout = &self.data.layout;
layout.last_bb
}
pub fn prev_block(self, bb: Block) -> Option<Block> {
let layout = &self.data.layout;
layout.bbs[bb].prev
}
pub fn next_block(self, bb: Block) -> Option<Block> {
let layout = &self.data.layout;
layout.bbs[bb].next
}
pub fn entry(self) -> Block {
self.first_block().expect("entry block is required")
}
}
impl<'a> Unit<'a> {
pub fn inst_block(self, inst: Inst) -> Option<Block> {
self.data.layout.inst_map.get(&inst).cloned()
}
pub fn insts(self, bb: Block) -> impl Iterator<Item = Inst> + 'a {
self.data.layout.bbs[bb].layout.insts()
}
pub fn all_insts(self) -> impl Iterator<Item = Inst> + 'a {
self.blocks().flat_map(move |bb| self.insts(bb))
}
pub fn is_inst_inserted(self, inst: Inst) -> bool {
self.data.layout.inst_map.contains_key(&inst)
}
pub fn first_inst(self, bb: Block) -> Option<Inst> {
self.data.layout.bbs[bb].layout.first_inst()
}
pub fn last_inst(self, bb: Block) -> Option<Inst> {
self.data.layout.bbs[bb].layout.last_inst()
}
pub fn prev_inst(self, inst: Inst) -> Option<Inst> {
let bb = self.inst_block(inst).unwrap();
self.data.layout.bbs[bb].layout.prev_inst(inst)
}
pub fn next_inst(self, inst: Inst) -> Option<Inst> {
let bb = self.inst_block(inst).unwrap();
self.data.layout.bbs[bb].layout.next_inst(inst)
}
pub fn terminator(self, bb: Block) -> Inst {
match self.last_inst(bb) {
Some(term) => term,
None => panic!("block {} must have a terminator", bb.dump(&self)),
}
}
}
impl std::fmt::Display for Unit<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{} {} {} {{\n",
self.data.kind,
self.data.name,
self.data.sig.dump(self)
)?;
for bb in self.blocks() {
write!(f, "{}:\n", bb.dump(self))?;
for inst in self.insts(bb) {
if self[inst].opcode().is_terminator() && self.is_entity() {
continue;
}
write!(f, " {}\n", inst.dump(self))?;
}
}
write!(f, "}}")?;
Ok(())
}
}
pub struct UnitBuilder<'a> {
unit: Unit<'a>,
data: &'a mut UnitData,
pos: InsertPos,
}
impl<'a> Deref for UnitBuilder<'a> {
type Target = Unit<'a>;
fn deref(&self) -> &Unit<'a> {
&self.unit
}
}
impl<'a> UnitBuilder<'a> {
pub fn new(unit: UnitId, data: &'a mut UnitData) -> Self {
let pos = {
let unit = Unit::new(unit, data);
match data.kind {
UnitKind::Entity => match unit.first_block() {
Some(bb) => InsertPos::Before(unit.terminator(bb)),
None => InsertPos::None,
},
_ => InsertPos::None,
}
};
Self {
unit: Unit::new(unit, unsafe { &*(data as *const _) }),
data: data,
pos,
}
}
pub fn new_anonymous(data: &'a mut UnitData) -> Self {
Self::new(UnitId::invalid(), data)
}
pub fn finish(self) -> Unit<'a> {
self.unit
}
#[inline(always)]
pub fn data(&mut self) -> &mut UnitData {
self.data
}
pub fn unit(&'a self) -> Unit<'a> {
self.unit
}
pub fn ins(&mut self) -> InstBuilder<'a, '_> {
InstBuilder::new(self)
}
pub fn build_inst(&mut self, data: InstData, ty: Type) -> Inst {
let inst = self.add_inst_dfg(data, ty);
match self.pos {
InsertPos::None => panic!("no block selected to insert instruction"),
InsertPos::Append(bb) => self.append_inst(inst, bb),
InsertPos::Prepend(bb) => {
self.prepend_inst(inst, bb);
self.pos = InsertPos::After(inst);
}
InsertPos::After(other) => {
self.insert_inst_after(inst, other);
self.pos = InsertPos::After(inst);
}
InsertPos::Before(other) => self.insert_inst_before(inst, other),
}
inst
}
pub fn delete_inst(&mut self, inst: Inst) {
self.remove_inst_dfg(inst);
match self.pos {
InsertPos::After(i) if i == inst => {
self.pos = self
.next_inst(i)
.map(InsertPos::Before)
.unwrap_or(InsertPos::Append(self.inst_block(i).unwrap()))
}
InsertPos::Before(i) if i == inst => {
self.pos = self
.prev_inst(i)
.map(InsertPos::After)
.unwrap_or(InsertPos::Prepend(self.inst_block(i).unwrap()))
}
_ => (),
}
self.remove_inst(inst);
}
pub fn block(&mut self) -> Block {
let bb = self.data.cfg.blocks.add(BlockData { name: None });
self.append_block(bb);
bb
}
pub fn named_block(&mut self, name: impl Into<String>) -> Block {
let bb = self.block();
self.set_block_name(bb, name.into());
bb
}
pub fn delete_block(&mut self, bb: Block) {
let insts: Vec<_> = self.insts(bb).collect();
self.remove_block_use(bb);
self.remove_block(bb);
self.data.cfg.blocks.remove(bb);
for inst in insts {
if self.has_result(inst) {
let value = self.inst_result(inst);
self.replace_use(value, Value::invalid());
}
self.remove_inst_dfg(inst);
}
}
pub fn insert_at_end(&mut self) {
self.pos = InsertPos::Append(self.entry());
}
pub fn insert_at_beginning(&mut self) {
self.pos = InsertPos::Prepend(self.entry());
}
pub fn append_to(&mut self, bb: Block) {
self.pos = InsertPos::Append(bb);
}
pub fn prepend_to(&mut self, bb: Block) {
self.pos = InsertPos::Prepend(bb);
}
pub fn insert_after(&mut self, inst: Inst) {
self.pos = InsertPos::After(inst);
}
pub fn insert_before(&mut self, inst: Inst) {
self.pos = InsertPos::Before(inst);
}
pub fn add_extern(&mut self, name: UnitName, sig: Signature) -> ExtUnit {
self.data.dfg.ext_units.add(ExtUnitData { sig, name })
}
pub fn prune_if_unused(&mut self, inst: Inst) -> bool {
if self.has_result(inst) && !self.has_uses(self.inst_result(inst)) {
#[allow(unreachable_patterns)]
let inst_args: Vec<_> = self[inst]
.args()
.iter()
.cloned()
.flat_map(|arg| self.get_value_inst(arg))
.collect();
self.delete_inst(inst);
for inst in inst_args {
self.prune_if_unused(inst);
}
true
} else {
false
}
}
}
impl<'a> UnitBuilder<'a> {
pub fn set_block_name(&mut self, bb: Block, name: String) {
self.data.cfg[bb].name = Some(name);
}
pub fn clear_block_name(&mut self, bb: Block) -> Option<String> {
std::mem::replace(&mut self.data.cfg[bb].name, None)
}
pub fn set_anonymous_block_hint(&mut self, bb: Block, hint: u32) {
self.data.cfg.anonymous_hints.insert(bb, hint);
}
pub fn clear_anonymous_block_hint(&mut self, bb: Block) -> Option<u32> {
self.data.cfg.anonymous_hints.remove(&bb)
}
}
impl<'a> UnitBuilder<'a> {
pub fn add_placeholder(&mut self, ty: Type) -> Value {
self.add_value(ValueData::Placeholder { ty })
}
pub fn remove_placeholder(&mut self, value: Value) {
assert!(!self.has_uses(value));
assert!(self[value].is_placeholder());
self.remove_value(value);
}
fn add_value(&mut self, data: ValueData) -> Value {
let v = self.data.dfg.values.add(data);
self.data.dfg.value_uses.insert(v, Default::default());
v
}
fn remove_value(&mut self, value: Value) -> ValueData {
let data = self.data.dfg.values.remove(value);
self.data.dfg.value_uses.remove(&value);
data
}
fn update_uses(&mut self, inst: Inst) {
for value in self[inst].args().to_vec() {
self.data
.dfg
.value_uses
.entry(value)
.or_default()
.insert(inst);
}
for block in self[inst].blocks().to_vec() {
self.data
.dfg
.block_uses
.entry(block)
.or_default()
.insert(inst);
}
}
fn remove_uses(&mut self, inst: Inst, data: InstData) {
for value in data.args() {
self.data
.dfg
.value_uses
.get_mut(value)
.unwrap()
.remove(&inst);
}
for block in data.blocks() {
self.data
.dfg
.block_uses
.get_mut(block)
.unwrap()
.remove(&inst);
}
}
fn add_inst_dfg(&mut self, data: InstData, ty: Type) -> Inst {
let inst = self.data.dfg.insts.add(data);
if !ty.is_void() {
let result = self.add_value(ValueData::Inst { ty, inst });
self.data.dfg.results.add(inst, result);
}
self.update_uses(inst);
inst
}
fn remove_inst_dfg(&mut self, inst: Inst) {
if self.has_result(inst) {
let value = self.inst_result(inst);
assert!(!self.has_uses(value));
self.remove_value(value);
}
let data = self.data.dfg.insts.remove(inst);
self.remove_uses(inst, data);
self.data.dfg.results.remove(inst);
}
pub(crate) fn make_args_for_signature(&mut self, sig: &Signature) {
for arg in sig.args() {
let value = self.add_value(ValueData::Arg {
ty: sig.arg_type(arg),
arg: arg,
});
self.data.dfg.args.add(arg, value);
}
}
pub fn set_name(&mut self, value: Value, name: String) {
self.data.dfg.names.insert(value, name);
}
pub fn clear_name(&mut self, value: Value) -> Option<String> {
self.data.dfg.names.remove(&value)
}
pub fn set_anonymous_hint(&mut self, value: Value, hint: u32) {
self.data.dfg.anonymous_hints.insert(value, hint);
}
pub fn clear_anonymous_hint(&mut self, value: Value) -> Option<u32> {
self.data.dfg.anonymous_hints.remove(&value)
}
pub fn replace_use(&mut self, from: Value, to: Value) -> usize {
let mut count = 0;
for inst in self
.data
.dfg
.value_uses
.get(&from)
.cloned()
.unwrap_or_else(Default::default)
{
count += self.replace_value_within_inst(from, to, inst);
}
count
}
pub fn replace_value_within_inst(&mut self, from: Value, to: Value, inst: Inst) -> usize {
#[allow(deprecated)]
let count = self[inst].replace_value(from, to);
self.data
.dfg
.value_uses
.entry(from)
.or_default()
.remove(&inst);
self.update_uses(inst);
count
}
pub fn replace_block_use(&mut self, from: Block, to: Block) -> usize {
let mut count = 0;
for inst in self
.data
.dfg
.block_uses
.get(&from)
.cloned()
.unwrap_or_else(Default::default)
{
count += self.replace_block_within_inst(from, to, inst);
}
count
}
pub fn replace_block_within_inst(&mut self, from: Block, to: Block, inst: Inst) -> usize {
#[allow(deprecated)]
let count = self[inst].replace_block(from, to);
self.data
.dfg
.block_uses
.entry(from)
.or_default()
.remove(&inst);
self.update_uses(inst);
count
}
pub fn remove_block_use(&mut self, block: Block) -> usize {
let mut count = 0;
for inst in self
.data
.dfg
.block_uses
.get(&block)
.cloned()
.unwrap_or_else(Default::default)
{
count += self.remove_block_from_inst(block, inst);
}
count
}
pub fn remove_block_from_inst(&mut self, block: Block, inst: Inst) -> usize {
#[allow(deprecated)]
let count = self[inst].remove_block(block);
self.data
.dfg
.block_uses
.entry(block)
.or_default()
.remove(&inst);
self.update_uses(inst);
count
}
pub fn set_location_hint(&mut self, inst: Inst, loc: usize) {
self.data.dfg.location_hints.insert(inst, loc);
}
}
impl<'a> UnitBuilder<'a> {
pub fn append_block(&mut self, bb: Block) {
let layout = &mut self.data.layout;
layout.bbs.add(
bb,
BlockNode {
prev: layout.last_bb,
next: None,
layout: Default::default(),
},
);
if let Some(prev) = layout.last_bb {
layout.bbs[prev].next = Some(bb);
}
if layout.first_bb.is_none() {
layout.first_bb = Some(bb);
}
layout.last_bb = Some(bb);
}
pub fn prepend_block(&mut self, bb: Block) {
let layout = &mut self.data.layout;
layout.bbs.add(
bb,
BlockNode {
prev: None,
next: layout.first_bb,
layout: Default::default(),
},
);
if let Some(next) = layout.first_bb {
layout.bbs[next].prev = Some(bb);
}
if layout.last_bb.is_none() {
layout.last_bb = Some(bb);
}
layout.first_bb = Some(bb);
}
pub fn insert_block_after(&mut self, bb: Block, after: Block) {
let layout = &mut self.data.layout;
layout.bbs.add(
bb,
BlockNode {
prev: Some(after),
next: layout.bbs[after].next,
layout: Default::default(),
},
);
if let Some(next) = layout.bbs[after].next {
layout.bbs[next].prev = Some(bb);
}
layout.bbs[after].next = Some(bb);
if layout.last_bb == Some(after) {
layout.last_bb = Some(bb);
}
}
pub fn insert_block_before(&mut self, bb: Block, before: Block) {
let layout = &mut self.data.layout;
layout.bbs.add(
bb,
BlockNode {
prev: layout.bbs[before].prev,
next: Some(before),
layout: Default::default(),
},
);
if let Some(prev) = layout.bbs[before].prev {
layout.bbs[prev].next = Some(bb);
}
layout.bbs[before].prev = Some(bb);
if layout.first_bb == Some(before) {
layout.first_bb = Some(bb);
}
}
pub fn remove_block(&mut self, bb: Block) {
let layout = &mut self.data.layout;
let node = layout.bbs.remove(bb).unwrap();
if let Some(next) = node.next {
layout.bbs[next].prev = node.prev;
}
if let Some(prev) = node.prev {
layout.bbs[prev].next = node.next;
}
if layout.first_bb == Some(bb) {
layout.first_bb = node.next;
}
if layout.last_bb == Some(bb) {
layout.last_bb = node.prev;
}
}
pub fn swap_blocks(&mut self, bb0: Block, bb1: Block) {
let layout = &mut self.data.layout;
if bb0 == bb1 {
return;
}
let mut bb0_next = layout.bbs[bb0].next;
let mut bb0_prev = layout.bbs[bb0].prev;
let mut bb1_next = layout.bbs[bb1].next;
let mut bb1_prev = layout.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);
}
layout.bbs[bb0].next = bb1_next;
layout.bbs[bb0].prev = bb1_prev;
layout.bbs[bb1].next = bb0_next;
layout.bbs[bb1].prev = bb0_prev;
if let Some(next) = bb0_next {
layout.bbs[next].prev = Some(bb1);
}
if let Some(prev) = bb0_prev {
layout.bbs[prev].next = Some(bb1);
}
if let Some(next) = bb1_next {
layout.bbs[next].prev = Some(bb0);
}
if let Some(prev) = bb1_prev {
layout.bbs[prev].next = Some(bb0);
}
if layout.first_bb == Some(bb0) {
layout.first_bb = Some(bb1);
} else if layout.first_bb == Some(bb1) {
layout.first_bb = Some(bb0);
}
if layout.last_bb == Some(bb0) {
layout.last_bb = Some(bb1);
} else if layout.last_bb == Some(bb1) {
layout.last_bb = Some(bb0);
}
}
}
impl<'a> UnitBuilder<'a> {
pub fn append_inst(&mut self, inst: Inst, bb: Block) {
self.data.layout.bbs[bb].layout.append_inst(inst);
self.data.layout.inst_map.insert(inst, bb);
}
pub fn prepend_inst(&mut self, inst: Inst, bb: Block) {
self.data.layout.bbs[bb].layout.prepend_inst(inst);
self.data.layout.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.data.layout.bbs[bb]
.layout
.insert_inst_after(inst, after);
self.data.layout.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.data.layout.bbs[bb]
.layout
.insert_inst_before(inst, before);
self.data.layout.inst_map.insert(inst, bb);
}
pub fn remove_inst(&mut self, inst: Inst) {
let bb = self.inst_block(inst).expect("`inst` not inserted");
self.data.layout.bbs[bb].layout.remove_inst(inst);
self.data.layout.inst_map.remove(&inst);
}
}
impl<'a> std::borrow::Borrow<Unit<'a>> for UnitBuilder<'a> {
fn borrow(&self) -> &Unit<'a> {
&self.unit
}
}
impl Index<Value> for Unit<'_> {
type Output = ValueData;
fn index(&self, idx: Value) -> &ValueData {
self.data.dfg.index(idx)
}
}
impl Index<Inst> for Unit<'_> {
type Output = InstData;
fn index(&self, idx: Inst) -> &InstData {
self.data.dfg.index(idx)
}
}
impl Index<ExtUnit> for Unit<'_> {
type Output = ExtUnitData;
fn index(&self, idx: ExtUnit) -> &ExtUnitData {
self.data.dfg.index(idx)
}
}
impl Index<Block> for Unit<'_> {
type Output = BlockData;
fn index(&self, idx: Block) -> &BlockData {
self.data.cfg.index(idx)
}
}
impl Index<Value> for UnitBuilder<'_> {
type Output = ValueData;
fn index(&self, idx: Value) -> &ValueData {
self.data.dfg.index(idx)
}
}
impl Index<Inst> for UnitBuilder<'_> {
type Output = InstData;
fn index(&self, idx: Inst) -> &InstData {
self.data.dfg.index(idx)
}
}
impl Index<ExtUnit> for UnitBuilder<'_> {
type Output = ExtUnitData;
fn index(&self, idx: ExtUnit) -> &ExtUnitData {
self.data.dfg.index(idx)
}
}
impl Index<Block> for UnitBuilder<'_> {
type Output = BlockData;
fn index(&self, idx: Block) -> &BlockData {
self.data.cfg.index(idx)
}
}
impl IndexMut<Value> for UnitBuilder<'_> {
fn index_mut(&mut self, idx: Value) -> &mut ValueData {
self.data.dfg.index_mut(idx)
}
}
impl IndexMut<Inst> for UnitBuilder<'_> {
fn index_mut(&mut self, idx: Inst) -> &mut InstData {
self.data.dfg.index_mut(idx)
}
}
impl IndexMut<ExtUnit> for UnitBuilder<'_> {
fn index_mut(&mut self, idx: ExtUnit) -> &mut ExtUnitData {
self.data.dfg.index_mut(idx)
}
}
impl IndexMut<Block> for UnitBuilder<'_> {
fn index_mut(&mut self, idx: Block) -> &mut BlockData {
self.data.cfg.index_mut(idx)
}
}
#[derive(Clone, Copy)]
enum InsertPos {
None,
Append(Block),
Prepend(Block),
After(Inst),
Before(Inst),
}
#[allow(dead_code)]
mod static_checks {
use super::*;
pub fn ensure_send<'a>(u: Unit<'a>, ub: UnitBuilder<'a>) -> impl Send + 'a {
(u, ub)
}
}