use std::{
collections::{btree_map, BTreeMap, BTreeSet},
mem,
- ops::Index,
+ ops::{Index, IndexMut},
};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
_ => None,
}
}
+ pub fn block_term_mut(&mut self) -> Option<&mut BlockTermInstKind> {
+ match self {
+ InstKind::BlockTerm(v) => Some(v),
+ _ => None,
+ }
+ }
pub fn copy(&self) -> Option<&CopyInstKind> {
match self {
InstKind::Copy(v) => Some(v),
.get(idx.get())
.ok_or(Error::InstIdxOutOfRange { idx })
}
+ pub fn try_get_inst_mut(&mut self, idx: InstIdx) -> Result<&mut Inst> {
+ self.insts
+ .get_mut(idx.get())
+ .ok_or(Error::InstIdxOutOfRange { idx })
+ }
pub fn try_get_operand(&self, inst: InstIdx, operand_idx: usize) -> Result<&Operand> {
self.try_get_inst(inst)?.try_get_operand(inst, operand_idx)
}
.ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
Ok((term_idx, term_kind))
}
+ pub fn try_get_block_term_inst_and_kind_mut(
+ &mut self,
+ block: BlockIdx,
+ ) -> Result<(InstIdx, &mut BlockTermInstKind)> {
+ let term_idx = self.try_get_block_term_inst_idx(block)?;
+ let term_kind = self
+ .try_get_inst_mut(term_idx)?
+ .kind
+ .block_term_mut()
+ .ok_or(Error::BlocksLastInstMustBeTerm { term_idx })?;
+ Ok((term_idx, term_kind))
+ }
pub fn try_get_branch_target_params(
&self,
branch_inst: InstIdx,
}
}
+impl IndexMut<SSAValIdx> for Vec<SSAVal> {
+ fn index_mut(&mut self, index: SSAValIdx) -> &mut Self::Output {
+ &mut self[index.get()]
+ }
+}
+
impl Index<InstIdx> for Vec<Inst> {
type Output = Inst;
}
}
+impl IndexMut<InstIdx> for Vec<Inst> {
+ fn index_mut(&mut self, index: InstIdx) -> &mut Self::Output {
+ &mut self[index.get()]
+ }
+}
+
impl Index<BlockIdx> for Vec<Block> {
type Output = Block;
}
}
+impl IndexMut<BlockIdx> for Vec<Block> {
+ fn index_mut(&mut self, index: BlockIdx) -> &mut Self::Output {
+ &mut self[index.get()]
+ }
+}
+
impl GraphBase for FnFields {
type EdgeId = (BlockIdx, BlockIdx);
type NodeId = BlockIdx;
+use std::{collections::BTreeMap, num::NonZeroUsize};
+
use crate::{
- function::{Block, FnFields, SSAVal, SSAValDef},
- index::{BlockIdx, SSAValIdx},
+ function::{Block, BlockTermInstKind, FnFields, Inst, InstKind, Operand, SSAVal, SSAValDef},
+ index::{BlockIdx, InstIdx, InstRange, SSAValIdx},
+ interned::{GlobalState, Intern},
loc::Ty,
+ loc_set::LocSet,
};
use arbitrary::{Arbitrary, Error, Unstructured};
+use petgraph::algo::dominators;
-struct FnBuilder<'a, 'b> {
+struct FnBuilder<'a, 'b, 'g> {
+ global_state: &'g GlobalState,
u: &'a mut Unstructured<'b>,
func: FnFields,
}
-impl FnBuilder<'_, '_> {
+impl FnBuilder<'_, '_, '_> {
fn new_ssa_val(&mut self, ty: Ty, def: SSAValDef) -> SSAValIdx {
let retval = SSAValIdx::new(self.func.ssa_vals.len());
self.func.ssa_vals.push(SSAVal {
});
retval
}
+ fn new_inst_in_last_block(
+ &mut self,
+ kind: InstKind,
+ operands: Vec<Operand>,
+ clobbers: LocSet,
+ ) -> InstIdx {
+ let block = self.func.blocks.last_mut().expect("no block");
+ let inst_idx = block.insts.end;
+ assert_eq!(inst_idx.get(), self.func.insts.len());
+ block.insts.end = block.insts.end.next();
+ self.func.insts.push(Inst {
+ kind,
+ operands,
+ clobbers: clobbers.into_interned(self.global_state),
+ });
+ inst_idx
+ }
+ fn make_ssa_val_use(&mut self) -> Result<SSAValIdx, Error> {
+ todo!()
+ }
fn run(&mut self) -> Result<(), Error> {
- for block_idx in 0..self.u.int_in_range(1..=10)? {
+ let block_count = self.u.int_in_range(1..=10u16)?;
+ for block_idx in 0..block_count as usize {
let block_idx = BlockIdx::new(block_idx);
let mut params = Vec::new();
for param_idx in 0..self.u.int_in_range(0..=10)? {
},
));
}
- let insts = todo!();
+ let end = InstIdx::new(self.func.insts.len());
self.func.blocks.push(Block {
params,
- insts,
+ insts: InstRange { start: end, end },
preds: Default::default(),
immediate_dominator: Default::default(),
});
+ for _ in 0..self.u.int_in_range(0..=10)? {
+ self.new_inst_in_last_block(InstKind::Normal, vec![], self.u.arbitrary()?);
+ }
+ let mut succs_and_params = BTreeMap::default();
+ let succ_range = BlockIdx::ENTRY_BLOCK.get() as u16..=(block_count - 1);
+ if !succ_range.is_empty() {
+ for i in 0..self.u.int_in_range(0..=3usize)? {
+ if i > succ_range.len() {
+ break;
+ }
+ let succ = BlockIdx::new(self.u.int_in_range(succ_range)?.into());
+ succs_and_params.insert(succ, vec![]);
+ }
+ }
+ let mut operands = vec![];
+ for _ in 0..self.u.int_in_range(0..=5)? {
+ operands.push(Operand {
+ ssa_val: todo!(),
+ kind_and_constraint: todo!(),
+ stage: todo!(),
+ });
+ }
+ self.new_inst_in_last_block(
+ InstKind::BlockTerm(BlockTermInstKind { succs_and_params }),
+ operands,
+ self.u.arbitrary()?,
+ );
+ }
+ let dominators = dominators::simple_fast(&self.func, BlockIdx::ENTRY_BLOCK);
+ for block_idx in 0..self.func.blocks.len() {
+ let block_idx = BlockIdx::new(block_idx);
+ self.func.blocks[block_idx].immediate_dominator =
+ dominators.immediate_dominator(block_idx);
+ let term_idx = self
+ .func
+ .try_get_block_term_inst_idx(block_idx)
+ .expect("known to have block term inst");
+ let successors = self.func.insts[term_idx]
+ .kind
+ .block_term()
+ .expect("known to have block term inst")
+ .succs_and_params
+ .keys()
+ .copied();
+ for succ in successors {
+ self.func.blocks[succ].preds.insert(block_idx);
+ }
+ for inst_idx in self.func.blocks[block_idx].insts {
+ let inst = &mut self.func.insts[inst_idx];
+ match &mut inst.kind {
+ InstKind::Normal => {
+ let _;
+ todo!()
+ }
+ InstKind::Copy(_) => unreachable!(),
+ InstKind::BlockTerm(block_term_inst_kind) => {
+ for (&succ, params) in &mut block_term_inst_kind.succs_and_params {}
+ }
+ }
+ }
}
Ok(())
}
impl<'a> Arbitrary<'a> for FnFields {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
- let mut builder = FnBuilder {
- u,
- func: Self {
- ssa_vals: Vec::new(),
- insts: Vec::new(),
- blocks: Vec::new(),
- start_inst_to_block_map: Default::default(),
- },
- };
- builder.run()?;
- Ok(builder.func)
+ GlobalState::get(|global_state| {
+ let mut builder = FnBuilder {
+ global_state,
+ u,
+ func: Self {
+ ssa_vals: Vec::new(),
+ insts: Vec::new(),
+ blocks: Vec::new(),
+ start_inst_to_block_map: Default::default(),
+ },
+ };
+ builder.run()?;
+ Ok(builder.func)
+ })
}
}
use std::{
borrow::{Borrow, Cow},
cell::Cell,
+ collections::BTreeMap,
fmt,
hash::Hash,
iter::{FusedIterator, Peekable},
#[derive(Deserialize)]
struct LocSetSerialized {
- starts: EnumMap<LocKind, BigUint>,
- ty: Option<Ty>,
+ reg_len_to_starts_map: BTreeMap<NonZeroU32, EnumMap<LocKind, BigUint>>,
}
impl TryFrom<LocSetSerialized> for LocSet {
type Error = Error;
fn try_from(value: LocSetSerialized) -> Result<Self, Self::Error> {
- Self::from_parts(value.starts, value.ty)
+ Self::from_reg_len_to_starts_map(value.reg_len_to_starts_map)
}
}
#[derive(Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(try_from = "LocSetSerialized")]
pub struct LocSet {
- starts: EnumMap<LocKind, BigUint>,
- ty: Option<Ty>,
+ reg_len_to_starts_map: BTreeMap<NonZeroU32, EnumMap<LocKind, BigUint>>,
}
/// computes same value as `a & !b`, but more efficiently