diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 9106f6e5..4062d9a3 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -21,11 +21,9 @@ use crate::{ CompiledValue, }, interpreter::{ - BreakAction, BreakpointsSet, RunResult, SmallUInt, State, - parts::{ - StatePartIndex, StatePartKindBigSlots, StatePartKindMemories, - StatePartKindSmallSlots, TypeIndexRange, TypeLenSingle, - }, + BreakAction, BreakpointsSet, RunResult, SmallUInt, State, StatePartIndex, + StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, TypeIndexRange, + TypeLen, }, time::{SimDuration, SimInstant}, value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue}, @@ -1359,15 +1357,14 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBitFn { type Output = bool; fn call(self, state: &mut interpreter::State) -> Self::Output { - match self.compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { + match self.compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { state.small_slots[self.compiled_value.range.small_slots.start] != 0 } - Some(TypeLenSingle::BigSlot) => !state.big_slots - [self.compiled_value.range.big_slots.start] + TypeLen::A_BIG_SLOT => !state.big_slots[self.compiled_value.range.big_slots.start] .clone() .is_zero(), - None => unreachable!(), + _ => unreachable!(), } } } @@ -1382,13 +1379,13 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo fn call(self, state: &mut interpreter::State) -> Self::Output { let Self { compiled_value, io } = self; - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => Expr::ty(io) + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => Expr::ty(io) .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), - Some(TypeLenSingle::BigSlot) => Expr::ty(io).value_from_int_wrapping( + TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( state.big_slots[compiled_value.range.big_slots.start].clone(), ), - None => unreachable!(), + _ => unreachable!(), } } } @@ -2036,14 +2033,14 @@ impl SimulationImpl { .get_module_mut(which_module) .write_helper(io, which_module); self.state_ready_to_run = true; - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { self.state.small_slots[compiled_value.range.small_slots.start] = value as _; } - Some(TypeLenSingle::BigSlot) => { + TypeLen::A_BIG_SLOT => { self.state.big_slots[compiled_value.range.big_slots.start] = value.into() } - None => unreachable!(), + _ => unreachable!(), } } #[track_caller] @@ -2069,18 +2066,18 @@ impl SimulationImpl { .write_helper(Expr::canonical(io), which_module); self.state_ready_to_run = true; let value: BigInt = value.into(); - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { let mut small_value = value.iter_u64_digits().next().unwrap_or(0); if value.is_negative() { small_value = small_value.wrapping_neg(); } self.state.small_slots[compiled_value.range.small_slots.start] = small_value; } - Some(TypeLenSingle::BigSlot) => { + TypeLen::A_BIG_SLOT => { self.state.big_slots[compiled_value.range.big_slots.start] = value } - None => unreachable!(), + _ => unreachable!(), } } #[track_caller] @@ -2110,20 +2107,20 @@ impl SimulationImpl { }; let bit_indexes = start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => read_write_small_scalar( + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => read_write_small_scalar( signed, bit_indexes, bits, &mut state.small_slots[compiled_value.range.small_slots.start], ), - Some(TypeLenSingle::BigSlot) => read_write_big_scalar( + TypeLen::A_BIG_SLOT => read_write_big_scalar( signed, bit_indexes, bits, &mut state.big_slots[compiled_value.range.big_slots.start], ), - None => unreachable!(), + _ => unreachable!(), } } CompiledTypeLayoutBody::Array { element } => { diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index e58ca044..dd062675 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -32,18 +32,15 @@ use crate::{ TraceScope, TraceSyncReset, TraceUInt, TraceWire, interpreter::{ Insn, InsnField, InsnFieldKind, InsnFieldType, InsnOrLabel, Insns, InsnsBuilding, - InsnsBuildingDone, InsnsBuildingKind, Label, SmallUInt, StatePartArrayIndex, - StatePartArrayIndexed, - parts::{ - MemoryData, SlotDebugData, StatePartIndex, StatePartIndexRange, StatePartKind, - StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, - StatePartLayout, StatePartLen, TypeIndex, TypeIndexRange, TypeLayout, TypeLen, - TypeLenSingle, get_state_part_kinds, - }, + InsnsBuildingDone, InsnsBuildingKind, Label, MemoryData, SlotDebugData, SmallUInt, + StatePartArrayIndex, StatePartArrayIndexed, StatePartIndex, StatePartIndexRange, + StatePartKind, StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, + StatePartLayout, StatePartLen, StatePartsValue, TypeArrayIndex, TypeArrayIndexes, + TypeIndex, TypeIndexRange, TypeLayout, TypeLen, TypeParts, }, }, ty::StaticType, - util::{HashMap, chain}, + util::HashMap, }; use bitvec::vec::BitVec; use num_bigint::BigInt; @@ -54,7 +51,7 @@ use petgraph::{ IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable, }, }; -use std::{collections::BTreeSet, fmt, hash::Hash, mem}; +use std::{collections::BTreeSet, fmt, hash::Hash, marker::PhantomData, mem, ops::IndexMut}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] enum CondBody { @@ -302,177 +299,6 @@ impl CompiledValue { } } -macro_rules! make_type_array_indexes { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub(crate) struct TypeArrayIndexes { - $(pub(crate) $type_plural_field: Interned<[StatePartArrayIndex<$type_kind>]>,)* - } - - impl TypeArrayIndexes { - pub(crate) fn as_ref(&self) -> TypeArrayIndexesRef<'_> { - TypeArrayIndexesRef { - $($type_plural_field: &self.$type_plural_field,)* - } - } - #[must_use] - pub(crate) fn join(self, next: TypeArrayIndex) -> TypeArrayIndexes { - TypeArrayIndexes { - $($type_plural_field: Interned::from_iter(self.$type_plural_field.iter().copied().chain([next.$type_plural_field])),)* - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeArrayIndex { - $(pub(crate) $type_plural_field: StatePartArrayIndex<$type_kind>,)* - } - - impl TypeArrayIndex { - pub(crate) fn from_parts(index: StatePartIndex, len: usize, stride: TypeLen) -> Self { - Self { - $($type_plural_field: StatePartArrayIndex { - index, - len, - stride: stride.$type_plural_field, - },)* - } - } - pub(crate) fn len(self) -> usize { - let len = self.small_slots.len; - $(assert_eq!(self.$type_plural_field.len, len, "array length mismatch");)* - len - } - pub(crate) fn index(self) -> StatePartIndex { - let index = self.small_slots.index; - $(assert_eq!(self.$type_plural_field.index, index, "array index mismatch");)* - index - } - pub(crate) fn is_empty(self) -> bool { - self.len() == 0 - } - pub(crate) fn stride(self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.stride,)* - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub(crate) struct TypeArrayIndexesRef<'a> { - $(pub(crate) $type_plural_field: &'a [StatePartArrayIndex<$type_kind>],)* - } - - impl<'a> TypeArrayIndexesRef<'a> { - pub(crate) fn len(self) -> usize { - let len = self.small_slots.len(); - $(assert_eq!(self.$type_plural_field.len(), len, "indexes count mismatch");)* - len - } - pub(crate) fn is_empty(self) -> bool { - self.len() == 0 - } - pub(crate) fn iter(self) -> impl Iterator + 'a { - (0..self.len()).map(move |i| TypeArrayIndex { - $($type_plural_field: self.$type_plural_field[i],)* - }) - } - pub(crate) fn for_each_offset( - self, - mut f: impl FnMut(TypeIndex), - ) { - self.for_each_offset2(TypeIndex { - $($type_plural_field: StatePartIndex::new(0),)* - }, &mut f); - } - pub(crate) fn split_first(self) -> Option<(TypeArrayIndex, Self)> { - $(let $type_plural_field = self.$type_plural_field.split_first()?;)* - let next = TypeArrayIndex { - $($type_plural_field: *$type_plural_field.0,)* - }; - let rest = TypeArrayIndexesRef { - $($type_plural_field: $type_plural_field.1,)* - }; - Some((next, rest)) - } - pub(crate) fn for_each_offset2( - self, - base_offset: TypeIndex, - f: &mut (impl FnMut(TypeIndex) + ?Sized), - ) { - if let Some((next, rest)) = self.split_first() { - let stride = next.stride(); - for index in 0..next.len().try_into().expect("array too big") { - let mut offset = TypeIndex { - $($type_plural_field: StatePartIndex::new( - stride - .$type_plural_field - .value - .checked_mul(index) - .expect("array too big"), - ),)* - }; - $(offset.$type_plural_field.value = - base_offset - .$type_plural_field - .value - .checked_add(offset.$type_plural_field.value) - .expect("array too big");)* - rest.for_each_offset2(offset, f); - } - } else { - $(assert!(self.$type_plural_field.is_empty(), "indexes count mismatch");)* - f(base_offset); - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeArrayIndexed { - $(pub(crate) $type_plural_field: StatePartArrayIndexed<$type_kind>,)* - } - - impl TypeArrayIndexed { - pub(crate) fn from_parts(base: TypeIndex, indexes: TypeArrayIndexes) -> Self { - Self { - $($type_plural_field: StatePartArrayIndexed { - base: base.$type_plural_field, - indexes: indexes.$type_plural_field, - },)* - } - } - pub(crate) fn base(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.base,)* - } - } - pub(crate) fn indexes(self) -> TypeArrayIndexes { - TypeArrayIndexes { - $($type_plural_field: self.$type_plural_field.indexes,)* - } - } - } - - impl From for TypeArrayIndexed { - fn from(value: TypeIndex) -> Self { - TypeArrayIndexed { - $($type_plural_field: value.$type_plural_field.into(),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_type_array_indexes! { - type_plural_fields; - type_kinds; - } -} - #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] struct CompiledExpr { static_part: CompiledValue, @@ -565,965 +391,1145 @@ impl CompiledExpr { } } -macro_rules! make_assignment_graph { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - array_indexed_variants = [$($array_indexed_variant:ident,)*]; - input_variants = [$($input_variant:ident,)*]; - output_variants = [$($output_variant:ident,)*]; - ) => { - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentOrSlotIndex { - AssignmentIndex(usize), - $($type_singular_variant(StatePartIndex<$type_kind>),)* - } - - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentIO { - $($input_variant { - assignment_index: usize, - slot: StatePartIndex<$type_kind>, - },)* - $($output_variant { - assignment_index: usize, - slot: StatePartIndex<$type_kind>, - },)* - } - - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentsEdge { - IO(AssignmentIO), - AssignmentImmediatePredecessor { - predecessor_assignment_index: usize, - assignment_index: usize, - }, - } - - #[derive(Debug)] - enum Assignments { - Accumulating { - assignments: Vec, - }, - Finalized { - assignments: Box<[Assignment]>, - slots_layout: TypeLayout, - slot_readers: SlotToAssignmentIndexFullMap, - slot_writers: SlotToAssignmentIndexFullMap, - assignment_immediate_predecessors: Box<[Box<[usize]>]>, - assignment_immediate_successors: Box<[Box<[usize]>]>, - }, - } - - impl Default for Assignments { - fn default() -> Self { - Self::Accumulating { - assignments: Vec::new(), - } - } - } - - impl Assignments { - fn finalize(&mut self, slots_layout: TypeLayout) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - let assignments = mem::take(assignments).into_boxed_slice(); - let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()]; - let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()]; - for (assignment_index, assignment) in assignments.iter().enumerate() { - slot_readers - .keys_for_assignment(assignment_index) - .extend([&assignment.inputs]); - slot_readers - .keys_for_assignment(assignment_index) - .extend(&assignment.conditions); - $(for &slot in &assignment.outputs.$type_plural_field { - if let Some(&pred) = slot_writers[slot].last() { - assignment_immediate_predecessors[assignment_index].insert(pred); - assignment_immediate_successors[pred].insert(assignment_index); - } - slot_writers[slot].push(assignment_index); - })* - } - *self = Self::Finalized { - assignments, - slots_layout, - slot_readers, - slot_writers, - assignment_immediate_predecessors: assignment_immediate_predecessors - .into_iter() - .map(Box::from_iter) - .collect(), - assignment_immediate_successors: assignment_immediate_successors - .into_iter() - .map(Box::from_iter) - .collect(), - }; - } - fn push(&mut self, v: Assignment) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - assignments.push(v); - } - fn assignments(&self) -> &[Assignment] { - let Self::Finalized { assignments, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - assignments - } - fn slots_layout(&self) -> TypeLayout { - let Self::Finalized { slots_layout, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - *slots_layout - } - fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_readers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_readers - } - fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_writers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_writers - } - fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_predecessors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_predecessors - } - fn assignment_immediate_successors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_successors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_successors - } - fn elements(&self) -> AssignmentsElements<'_> { - let SlotToAssignmentIndexFullMap { - $($type_plural_field,)* - } = self.slot_readers(); - AssignmentsElements { - node_indexes: HashMap::with_capacity_and_hasher( - self.assignments().len() $(+ $type_plural_field.len())*, - Default::default(), - ), - nodes: self.node_references(), - edges: self.edge_references(), - } - } - } - - impl GraphBase for Assignments { - type EdgeId = AssignmentsEdge; - type NodeId = AssignmentOrSlotIndex; - } - - #[derive(Debug, Clone, Copy)] - enum AssignmentsNodeRef<'a> { - Assignment { - index: usize, - #[allow(dead_code, reason = "used in Debug impl")] - assignment: &'a Assignment, - }, - $($type_singular_variant( - StatePartIndex<$type_kind>, - #[allow(dead_code, reason = "used in Debug impl")] SlotDebugData, - ),)* - } - - impl<'a> NodeRef for AssignmentsNodeRef<'a> { - type NodeId = AssignmentOrSlotIndex; - type Weight = AssignmentsNodeRef<'a>; - - fn id(&self) -> Self::NodeId { - match *self { - AssignmentsNodeRef::Assignment { - index, - assignment: _, - } => AssignmentOrSlotIndex::AssignmentIndex(index), - $(AssignmentsNodeRef::$type_singular_variant(slot, _) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - } - } - - fn weight(&self) -> &Self::Weight { - self - } - } - - impl<'a> petgraph::visit::Data for &'a Assignments { - type NodeWeight = AssignmentsNodeRef<'a>; - type EdgeWeight = AssignmentsEdge; - } - - struct AssignmentsElements<'a> { - node_indexes: HashMap, - nodes: AssignmentsNodes<'a>, - edges: AssignmentsEdges<'a>, - } - - impl<'a> Iterator for AssignmentsElements<'a> { - type Item = petgraph::data::Element< - <&'a Assignments as petgraph::visit::Data>::NodeWeight, - <&'a Assignments as petgraph::visit::Data>::EdgeWeight, - >; - - fn next(&mut self) -> Option { - let Self { - node_indexes, - nodes, - edges, - } = self; - if let Some(node) = nodes.next() { - node_indexes.insert(node.id(), node_indexes.len()); - return Some(petgraph::data::Element::Node { weight: node }); - } - let edge = edges.next()?; - Some(petgraph::data::Element::Edge { - source: node_indexes[&edge.source()], - target: node_indexes[&edge.target()], - weight: *edge.weight(), - }) - } - } - - #[derive(Clone)] - struct AssignmentsNodeIdentifiers { - assignment_indexes: std::ops::Range, - $($type_plural_field: std::ops::Range,)* - } - - impl AssignmentsNodeIdentifiers { - fn internal_iter<'a>(&'a mut self) -> impl Iterator + 'a { - let Self { - assignment_indexes, - $($type_plural_field,)* - } = self; - assignment_indexes - .map(AssignmentOrSlotIndex::AssignmentIndex) - $(.chain($type_plural_field.map(|value| { - AssignmentOrSlotIndex::$type_singular_variant(StatePartIndex::new(value)) - })))* - } - } - - impl Iterator for AssignmentsNodeIdentifiers { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - self.internal_iter().next() - } - - fn nth(&mut self, n: usize) -> Option { - self.internal_iter().nth(n) - } - } - - impl<'a> IntoNodeIdentifiers for &'a Assignments { - type NodeIdentifiers = AssignmentsNodeIdentifiers; - - fn node_identifiers(self) -> Self::NodeIdentifiers { - let TypeLen { - $($type_plural_field,)* - } = self.slot_readers().len(); - AssignmentsNodeIdentifiers { - assignment_indexes: 0..self.assignments().len(), - $($type_plural_field: 0..$type_plural_field.value,)* - } - } - } - - struct AssignmentsNodes<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, - } - - impl<'a> Iterator for AssignmentsNodes<'a> { - type Item = AssignmentsNodeRef<'a>; - - fn next(&mut self) -> Option { - self.nodes.next().map(|node| match node { - AssignmentOrSlotIndex::AssignmentIndex(index) => AssignmentsNodeRef::Assignment { - index, - assignment: &self.assignments.assignments()[index], - }, - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => AssignmentsNodeRef::$type_singular_variant( - slot, - *self.assignments.slots_layout().$type_plural_field.debug_data(slot), - ),)* - }) - } - } - - impl<'a> IntoNodeReferences for &'a Assignments { - type NodeRef = AssignmentsNodeRef<'a>; - type NodeReferences = AssignmentsNodes<'a>; - - fn node_references(self) -> Self::NodeReferences { - AssignmentsNodes { - assignments: self, - nodes: self.node_identifiers(), - } - } - } - - struct AssignmentsNeighborsDirected<'a> { - assignment_indexes: std::slice::Iter<'a, usize>, - $($type_plural_field: std::collections::btree_set::Iter<'a, StatePartIndex<$type_kind>>,)* - } - - impl Iterator for AssignmentsNeighborsDirected<'_> { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - let Self { - assignment_indexes, - $($type_plural_field,)* - } = self; - if let retval @ Some(_) = assignment_indexes - .next() - .copied() - .map(AssignmentOrSlotIndex::AssignmentIndex) - { - retval - } $(else if let retval @ Some(_) = $type_plural_field - .next() - .copied() - .map(AssignmentOrSlotIndex::$type_singular_variant) - { - retval - })* else { - None - } - } - } - - impl<'a> IntoNeighbors for &'a Assignments { - type Neighbors = AssignmentsNeighborsDirected<'a>; - - fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { - self.neighbors_directed(n, petgraph::Direction::Outgoing) - } - } - - impl<'a> IntoNeighborsDirected for &'a Assignments { - type NeighborsDirected = AssignmentsNeighborsDirected<'a>; - - fn neighbors_directed( - self, - n: Self::NodeId, - d: petgraph::Direction, - ) -> Self::NeighborsDirected { - use petgraph::Direction::*; - let slot_map = match d { - Outgoing => self.slot_readers(), - Incoming => self.slot_writers(), - }; - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - let assignment = &self.assignments()[assignment_index]; - let ( - assignment_indexes, - SlotSet { - $($type_plural_field,)* - }, - ) = match d { - Outgoing => ( - &self.assignment_immediate_successors()[assignment_index], - &assignment.outputs, - ), - Incoming => ( - &self.assignment_immediate_predecessors()[assignment_index], - &assignment.inputs, - ), - }; - AssignmentsNeighborsDirected { - assignment_indexes: assignment_indexes.iter(), - $($type_plural_field: $type_plural_field.iter(),)* - } - } - AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNeighborsDirected { - assignment_indexes: slot_map[slot].iter(), - $($type_plural_field: Default::default(),)* - }, - AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNeighborsDirected { - assignment_indexes: slot_map[slot].iter(), - $($type_plural_field: Default::default(),)* - }, - } - } - } - - impl EdgeRef for AssignmentsEdge { - type NodeId = AssignmentOrSlotIndex; - type EdgeId = AssignmentsEdge; - type Weight = AssignmentsEdge; - - fn source(&self) -> Self::NodeId { - match *self { - $(AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - $(AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index),)* - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index: _, - } => AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - } - } - - fn target(&self) -> Self::NodeId { - match *self { - $(AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index),)* - $(AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index: _, - assignment_index, - } => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - } - } - - fn weight(&self) -> &Self::Weight { - self - } - - fn id(&self) -> Self::EdgeId { - *self - } - } - - struct AssignmentsEdges<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, - outgoing_neighbors: Option<(AssignmentOrSlotIndex, AssignmentsNeighborsDirected<'a>)>, - } - - impl Iterator for AssignmentsEdges<'_> { - type Item = AssignmentsEdge; - - fn next(&mut self) -> Option { - loop { - if let Some((node, outgoing_neighbors)) = &mut self.outgoing_neighbors { - if let Some(outgoing_neighbor) = outgoing_neighbors.next() { - return Some(match (*node, outgoing_neighbor) { - ( - $(AssignmentOrSlotIndex::$type_singular_variant(_))|*, - $(AssignmentOrSlotIndex::$type_singular_variant(_))|*, - ) => unreachable!(), - ( - AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index, - }, - $(( - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentOrSlotIndex::$type_singular_variant(slot), - ) => AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index, - slot, - }),)* - $(( - AssignmentOrSlotIndex::$type_singular_variant(slot), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index, - slot, - }),)* - }); - } - } - let node = self.nodes.next()?; - self.outgoing_neighbors = Some(( - node, - self.assignments - .neighbors_directed(node, petgraph::Direction::Outgoing), - )); - } - } - } - - impl<'a> IntoEdgeReferences for &'a Assignments { - type EdgeRef = AssignmentsEdge; - type EdgeReferences = AssignmentsEdges<'a>; - - fn edge_references(self) -> Self::EdgeReferences { - AssignmentsEdges { - assignments: self, - nodes: self.node_identifiers(), - outgoing_neighbors: None, - } - } - } - - struct AssignmentsVisitMap { - assignments: Vec, - slots: DenseSlotSet, - } - - impl VisitMap for AssignmentsVisitMap { - fn visit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - !mem::replace(&mut self.assignments[assignment_index], true) - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.insert(slot),)* - } - } - - fn is_visited(&self, n: &AssignmentOrSlotIndex) -> bool { - match *n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - self.assignments[assignment_index] - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.contains(slot),)* - } - } - - fn unvisit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - mem::replace(&mut self.assignments[assignment_index], false) - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.remove(slot),)* - } - } - } - - impl Visitable for Assignments { - type Map = AssignmentsVisitMap; - - fn visit_map(self: &Self) -> Self::Map { - AssignmentsVisitMap { - assignments: vec![false; self.assignments().len()], - slots: DenseSlotSet::new(self.slot_readers().len()), - } - } - - fn reset_map(self: &Self, map: &mut Self::Map) { - let AssignmentsVisitMap { assignments, slots } = map; - assignments.clear(); - assignments.resize(self.assignments().len(), false); - if slots.len() != self.slot_readers().len() { - *slots = DenseSlotSet::new(self.slot_readers().len()); - } else { - slots.clear(); - } - } - } - - #[derive(Debug)] - struct Assignment { - inputs: SlotSet, - outputs: SlotSet, - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, - } - - #[derive(Debug)] - struct SlotToAssignmentIndexFullMap { - $($type_plural_field: Box<[Vec]>,)* - } - - impl SlotToAssignmentIndexFullMap { - fn new(len: TypeLen) -> Self { - Self { - $($type_plural_field: vec![Vec::new(); len.$type_plural_field.value.try_into().expect("length too big")] - .into_boxed_slice(),)* - } - } - fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: StatePartLen::new(self.$type_plural_field.len() as _),)* - } - } - fn keys_for_assignment( - &mut self, - assignment_index: usize, - ) -> SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - SlotToAssignmentIndexFullMapKeysForAssignment { - map: self, - assignment_index, - } - } - fn for_each( - &self, - $(mut $type_plural_field: impl FnMut(StatePartIndex<$type_kind>, &[usize]),)* - ) { - $(self.$type_plural_field.iter().enumerate().for_each(|(k, v)| { - $type_plural_field(StatePartIndex::new(k as _), v) - });)* - } - } - - $(impl std::ops::Index> for SlotToAssignmentIndexFullMap { - type Output = Vec; - - fn index(&self, index: StatePartIndex<$type_kind>) -> &Self::Output { - &self.$type_plural_field[index.as_usize()] - } - } - - impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { - fn index_mut(&mut self, index: StatePartIndex<$type_kind>) -> &mut Self::Output { - &mut self.$type_plural_field[index.as_usize()] - } - })* - - struct SlotToAssignmentIndexFullMapKeysForAssignment<'a> { - map: &'a mut SlotToAssignmentIndexFullMap, - assignment_index: usize, - } - - $(impl<'a> Extend<&'a StatePartIndex<$type_kind>> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().copied()); - } - })* - - $(impl Extend> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>>(&mut self, iter: T) { - iter.into_iter() - .for_each(|slot| self.map[slot].push(self.assignment_index)); - } - })* - - impl<'a> Extend<&'a SlotSet> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |set| { - $(self.extend(&set.$type_plural_field);)* - }, - ); - } - } - - impl<'a> Extend<&'a Cond> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond| match cond.body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - let CompiledValue { - range, - layout: _, - write: _, - } = cond; - $(self.extend(range.$type_plural_field.iter());)* - } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }); - } - } - - impl Assignment { - fn new( - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, - ) -> Self { - let mut inputs = SlotSet::default(); - let mut outputs = SlotSet::default(); - for insn in &insns { - let insn = match insn { - InsnOrLabel::Insn(insn) => insn, - InsnOrLabel::Label(_) => continue, - }; - for InsnField { ty, kind } in insn.fields() { - match (kind, ty) { - $((InsnFieldKind::Input, InsnFieldType::$type_singular_variant(&slot)) => { - inputs.extend([slot]); - })* - $(( - InsnFieldKind::Input, - InsnFieldType::$array_indexed_variant(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| inputs.extend([slot])); - inputs.extend(array_indexed.indexes); - })* - $((InsnFieldKind::Output, InsnFieldType::$type_singular_variant(&slot)) => { - outputs.extend([slot]); - })* - $(( - InsnFieldKind::Output, - InsnFieldType::$array_indexed_variant(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| { - outputs.extend([slot]); - }); - inputs.extend(array_indexed.indexes); - })* - ( - _, - InsnFieldType::Memory(_) - | InsnFieldType::SmallUInt(_) - | InsnFieldType::SmallSInt(_) - | InsnFieldType::InternedBigInt(_) - | InsnFieldType::U8(_) - | InsnFieldType::USize(_) - | InsnFieldType::Empty(_), - ) - | ( - InsnFieldKind::Immediate - | InsnFieldKind::Memory - | InsnFieldKind::BranchTarget, - _, - ) => {} - } - } - } - Self { - inputs, - outputs, - conditions, - insns, - source_location, - } - } - } - }; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentOrSlotIndex { + AssignmentIndex(usize), + SmallSlot(StatePartIndex), + BigSlot(StatePartIndex), } -get_state_part_kinds! { - make_assignment_graph! { - type_plural_fields; - type_singular_variants; - type_kinds; - array_indexed_variants; - #[custom] input_variants = [small_slot = SmallInput, big_slot = BigInput,]; - #[custom] output_variants = [small_slot = SmallOutput, big_slot = BigOutput,]; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentIO { + BigInput { + assignment_index: usize, + slot: StatePartIndex, + }, + SmallInput { + assignment_index: usize, + slot: StatePartIndex, + }, + BigOutput { + assignment_index: usize, + slot: StatePartIndex, + }, + SmallOutput { + assignment_index: usize, + slot: StatePartIndex, + }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentsEdge { + IO(AssignmentIO), + AssignmentImmediatePredecessor { + predecessor_assignment_index: usize, + assignment_index: usize, + }, +} + +#[derive(Debug)] +enum Assignments { + Accumulating { + assignments: Vec, + }, + Finalized { + assignments: Box<[Assignment]>, + slots_layout: TypeLayout, + slot_readers: SlotToAssignmentIndexFullMap, + slot_writers: SlotToAssignmentIndexFullMap, + assignment_immediate_predecessors: Box<[Box<[usize]>]>, + assignment_immediate_successors: Box<[Box<[usize]>]>, + }, +} + +impl Default for Assignments { + fn default() -> Self { + Self::Accumulating { + assignments: Vec::new(), + } } } -macro_rules! make_dense_slot_set { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, PartialEq, Eq, Hash)] - struct DenseSlotSet { - $($type_plural_field: Box<[bool]>,)* - } - - impl DenseSlotSet { - fn new(len: TypeLen) -> Self { - Self { - $($type_plural_field: vec![false; len.$type_plural_field.value.try_into().expect("length too big")] - .into_boxed_slice(),)* +impl Assignments { + fn finalize(&mut self, slots_layout: TypeLayout) { + let Self::Accumulating { assignments } = self else { + unreachable!("already finalized"); + }; + let assignments = mem::take(assignments).into_boxed_slice(); + let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); + let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); + let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()]; + let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()]; + for (assignment_index, assignment) in assignments.iter().enumerate() { + slot_readers + .keys_for_assignment(assignment_index) + .extend([&assignment.inputs]); + slot_readers + .keys_for_assignment(assignment_index) + .extend(&assignment.conditions); + let SlotSet(TypeParts { + small_slots, + big_slots, + }) = &assignment.outputs; + for &slot in small_slots { + if let Some(&pred) = slot_writers[slot].last() { + assignment_immediate_predecessors[assignment_index].insert(pred); + assignment_immediate_successors[pred].insert(assignment_index); } + slot_writers[slot].push(assignment_index); } - fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: StatePartLen::new(self.$type_plural_field.len() as _),)* + for &slot in big_slots { + if let Some(&pred) = slot_writers[slot].last() { + assignment_immediate_predecessors[assignment_index].insert(pred); + assignment_immediate_successors[pred].insert(assignment_index); } - } - fn clear(&mut self) { - $(self.$type_plural_field.fill(false);)* + slot_writers[slot].push(assignment_index); } } - - trait DenseSlotSetMethods: Extend> { - fn contains(&self, k: StatePartIndex) -> bool; - fn remove(&mut self, k: StatePartIndex) -> bool { - self.take(k).is_some() - } - fn take(&mut self, k: StatePartIndex) -> Option>; - fn replace(&mut self, k: StatePartIndex) -> Option>; - fn insert(&mut self, k: StatePartIndex) -> bool { - self.replace(k).is_none() - } + *self = Self::Finalized { + assignments, + slots_layout, + slot_readers, + slot_writers, + assignment_immediate_predecessors: assignment_immediate_predecessors + .into_iter() + .map(Box::from_iter) + .collect(), + assignment_immediate_successors: assignment_immediate_successors + .into_iter() + .map(Box::from_iter) + .collect(), + }; + } + fn push(&mut self, v: Assignment) { + let Self::Accumulating { assignments } = self else { + unreachable!("already finalized"); + }; + assignments.push(v); + } + fn assignments(&self) -> &[Assignment] { + let Self::Finalized { assignments, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + assignments + } + fn slots_layout(&self) -> TypeLayout { + let Self::Finalized { slots_layout, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + *slots_layout + } + fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { + let Self::Finalized { slot_readers, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + slot_readers + } + fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { + let Self::Finalized { slot_writers, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + slot_writers + } + fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] { + let Self::Finalized { + assignment_immediate_predecessors, + .. + } = self + else { + unreachable!("Assignments::finalize should have been called"); + }; + assignment_immediate_predecessors + } + fn assignment_immediate_successors(&self) -> &[Box<[usize]>] { + let Self::Finalized { + assignment_immediate_successors, + .. + } = self + else { + unreachable!("Assignments::finalize should have been called"); + }; + assignment_immediate_successors + } + fn elements(&self) -> AssignmentsElements<'_> { + let SlotToAssignmentIndexFullMap(TypeParts { + small_slots, + big_slots, + }) = self.slot_readers(); + AssignmentsElements { + node_indexes: HashMap::with_capacity_and_hasher( + self.assignments().len() + small_slots.len() + big_slots.len(), + Default::default(), + ), + nodes: self.node_references(), + edges: self.edge_references(), } + } +} - impl Extend> for DenseSlotSet - where - Self: DenseSlotSetMethods, +impl GraphBase for Assignments { + type EdgeId = AssignmentsEdge; + type NodeId = AssignmentOrSlotIndex; +} + +#[derive(Debug, Clone, Copy)] +enum AssignmentsNodeRef<'a> { + Assignment { + index: usize, + #[allow(dead_code, reason = "used in Debug impl")] + assignment: &'a Assignment, + }, + SmallSlot( + StatePartIndex, + #[allow(dead_code, reason = "used in Debug impl")] SlotDebugData, + ), + BigSlot( + StatePartIndex, + #[allow(dead_code, reason = "used in Debug impl")] SlotDebugData, + ), +} + +impl<'a> NodeRef for AssignmentsNodeRef<'a> { + type NodeId = AssignmentOrSlotIndex; + type Weight = AssignmentsNodeRef<'a>; + + fn id(&self) -> Self::NodeId { + match *self { + AssignmentsNodeRef::Assignment { + index, + assignment: _, + } => AssignmentOrSlotIndex::AssignmentIndex(index), + AssignmentsNodeRef::SmallSlot(slot, _) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsNodeRef::BigSlot(slot, _) => AssignmentOrSlotIndex::BigSlot(slot), + } + } + + fn weight(&self) -> &Self::Weight { + self + } +} + +impl<'a> petgraph::visit::Data for &'a Assignments { + type NodeWeight = AssignmentsNodeRef<'a>; + type EdgeWeight = AssignmentsEdge; +} + +struct AssignmentsElements<'a> { + node_indexes: HashMap, + nodes: AssignmentsNodes<'a>, + edges: AssignmentsEdges<'a>, +} + +impl<'a> Iterator for AssignmentsElements<'a> { + type Item = petgraph::data::Element< + <&'a Assignments as petgraph::visit::Data>::NodeWeight, + <&'a Assignments as petgraph::visit::Data>::EdgeWeight, + >; + + fn next(&mut self) -> Option { + let Self { + node_indexes, + nodes, + edges, + } = self; + if let Some(node) = nodes.next() { + node_indexes.insert(node.id(), node_indexes.len()); + return Some(petgraph::data::Element::Node { weight: node }); + } + let edge = edges.next()?; + Some(petgraph::data::Element::Edge { + source: node_indexes[&edge.source()], + target: node_indexes[&edge.target()], + weight: *edge.weight(), + }) + } +} + +#[derive(Clone)] +struct AssignmentsNodeIdentifiers { + assignment_indexes: std::ops::Range, + small_slots: std::ops::Range, + big_slots: std::ops::Range, +} + +impl AssignmentsNodeIdentifiers { + fn internal_iter<'a>(&'a mut self) -> impl Iterator + 'a { + let Self { + assignment_indexes, + small_slots, + big_slots, + } = self; + assignment_indexes + .map(AssignmentOrSlotIndex::AssignmentIndex) + .chain(small_slots.map(|value| { + AssignmentOrSlotIndex::SmallSlot(StatePartIndex { + value, + _phantom: PhantomData, + }) + })) + .chain(big_slots.map(|value| { + AssignmentOrSlotIndex::BigSlot(StatePartIndex { + value, + _phantom: PhantomData, + }) + })) + } +} + +impl Iterator for AssignmentsNodeIdentifiers { + type Item = AssignmentOrSlotIndex; + fn next(&mut self) -> Option { + self.internal_iter().next() + } + + fn nth(&mut self, n: usize) -> Option { + self.internal_iter().nth(n) + } +} + +impl<'a> IntoNodeIdentifiers for &'a Assignments { + type NodeIdentifiers = AssignmentsNodeIdentifiers; + + fn node_identifiers(self) -> Self::NodeIdentifiers { + let TypeLen { + small_slots, + big_slots, + } = self.slot_readers().len(); + AssignmentsNodeIdentifiers { + assignment_indexes: 0..self.assignments().len(), + small_slots: 0..small_slots.value, + big_slots: 0..big_slots.value, + } + } +} + +struct AssignmentsNodes<'a> { + assignments: &'a Assignments, + nodes: AssignmentsNodeIdentifiers, +} + +impl<'a> Iterator for AssignmentsNodes<'a> { + type Item = AssignmentsNodeRef<'a>; + + fn next(&mut self) -> Option { + self.nodes.next().map(|node| match node { + AssignmentOrSlotIndex::AssignmentIndex(index) => AssignmentsNodeRef::Assignment { + index, + assignment: &self.assignments.assignments()[index], + }, + AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNodeRef::SmallSlot( + slot, + *self.assignments.slots_layout().small_slots.debug_data(slot), + ), + AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNodeRef::BigSlot( + slot, + *self.assignments.slots_layout().big_slots.debug_data(slot), + ), + }) + } +} + +impl<'a> IntoNodeReferences for &'a Assignments { + type NodeRef = AssignmentsNodeRef<'a>; + type NodeReferences = AssignmentsNodes<'a>; + + fn node_references(self) -> Self::NodeReferences { + AssignmentsNodes { + assignments: self, + nodes: self.node_identifiers(), + } + } +} + +struct AssignmentsNeighborsDirected<'a> { + assignment_indexes: std::slice::Iter<'a, usize>, + small_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, + big_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, +} + +impl Iterator for AssignmentsNeighborsDirected<'_> { + type Item = AssignmentOrSlotIndex; + fn next(&mut self) -> Option { + let Self { + assignment_indexes, + small_slots, + big_slots, + } = self; + if let retval @ Some(_) = assignment_indexes + .next() + .copied() + .map(AssignmentOrSlotIndex::AssignmentIndex) { - fn extend>>(&mut self, iter: T) { - iter.into_iter().for_each(|v| { - self.insert(v); - }); - } + retval + } else if let retval @ Some(_) = small_slots + .next() + .copied() + .map(AssignmentOrSlotIndex::SmallSlot) + { + retval + } else if let retval @ Some(_) = big_slots + .next() + .copied() + .map(AssignmentOrSlotIndex::BigSlot) + { + retval + } else { + None } - - $(impl DenseSlotSetMethods<$type_kind> for DenseSlotSet { - fn contains(&self, k: StatePartIndex<$type_kind>) -> bool { - self.$type_plural_field[k.as_usize()] - } - - fn take( - &mut self, - k: StatePartIndex<$type_kind>, - ) -> Option> { - mem::replace(self.$type_plural_field.get_mut(k.as_usize())?, false).then_some(k) - } - - fn replace( - &mut self, - k: StatePartIndex<$type_kind>, - ) -> Option> { - mem::replace(&mut self.$type_plural_field[k.as_usize()], true).then_some(k) - } - })* - }; -} - -get_state_part_kinds! { - make_dense_slot_set! { - type_plural_fields; - type_kinds; } } -macro_rules! make_slot_vec { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] - struct SlotVec { - $($type_plural_field: Vec>,)* - } +impl<'a> IntoNeighbors for &'a Assignments { + type Neighbors = AssignmentsNeighborsDirected<'a>; - impl SlotVec { - fn is_empty(&self) -> bool { - true $(&& self.$type_plural_field.is_empty())* - } - } - }; -} - -get_state_part_kinds! { - make_slot_vec! { - type_plural_fields; - type_kinds; + fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { + self.neighbors_directed(n, petgraph::Direction::Outgoing) } } -macro_rules! make_slot_set { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] - struct SlotSet { - $($type_plural_field: BTreeSet>,)* +impl<'a> IntoNeighborsDirected for &'a Assignments { + type NeighborsDirected = AssignmentsNeighborsDirected<'a>; + + fn neighbors_directed( + self, + n: Self::NodeId, + d: petgraph::Direction, + ) -> Self::NeighborsDirected { + use petgraph::Direction::*; + let slot_map = match d { + Outgoing => self.slot_readers(), + Incoming => self.slot_writers(), + }; + match n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + let assignment = &self.assignments()[assignment_index]; + let ( + assignment_indexes, + SlotSet(TypeParts { + small_slots, + big_slots, + }), + ) = match d { + Outgoing => ( + &self.assignment_immediate_successors()[assignment_index], + &assignment.outputs, + ), + Incoming => ( + &self.assignment_immediate_predecessors()[assignment_index], + &assignment.inputs, + ), + }; + AssignmentsNeighborsDirected { + assignment_indexes: assignment_indexes.iter(), + small_slots: small_slots.iter(), + big_slots: big_slots.iter(), + } + } + AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNeighborsDirected { + assignment_indexes: slot_map[slot].iter(), + small_slots: Default::default(), + big_slots: Default::default(), + }, + AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNeighborsDirected { + assignment_indexes: slot_map[slot].iter(), + small_slots: Default::default(), + big_slots: Default::default(), + }, } + } +} - impl SlotSet { - fn is_empty(&self) -> bool { - true $(&& self.$type_plural_field.is_empty())* - } - fn for_each( - &self, - $($type_plural_field: impl FnMut(StatePartIndex<$type_kind>),)* - ) { - $(self.$type_plural_field.iter().copied().for_each($type_plural_field);)* - } - fn all( - &self, - $($type_plural_field: impl FnMut(StatePartIndex<$type_kind>) -> bool,)* - small_slots_fn: impl FnMut(StatePartIndex) -> bool, - big_slots_fn: impl FnMut(StatePartIndex) -> bool, - ) -> bool { - true $(&& self.$type_plural_field.iter().copied().all($type_plural_field))* - } +impl EdgeRef for AssignmentsEdge { + type NodeId = AssignmentOrSlotIndex; + type EdgeId = AssignmentsEdge; + type Weight = AssignmentsEdge; + + fn source(&self) -> Self::NodeId { + match *self { + AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::BigSlot(slot), + AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index, + assignment_index: _, + } => AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), } + } - $(impl Extend> for SlotSet { - fn extend>>( - &mut self, - iter: T, - ) { - self.$type_plural_field.extend(iter); - } - })* - - $(impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().flat_map(|v| v.iter())); - } - })* - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |range| { - $(self.extend(range.$type_plural_field.iter());)* - }, - ) - } + fn target(&self) -> Self::NodeId { + match *self { + AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::BigSlot(slot), + AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index: _, + assignment_index, + } => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), } + } - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |v| { - $(self.extend([v.$type_plural_field]);)* - }, - ) + fn weight(&self) -> &Self::Weight { + self + } + + fn id(&self) -> Self::EdgeId { + *self + } +} + +struct AssignmentsEdges<'a> { + assignments: &'a Assignments, + nodes: AssignmentsNodeIdentifiers, + outgoing_neighbors: Option<(AssignmentOrSlotIndex, AssignmentsNeighborsDirected<'a>)>, +} + +impl Iterator for AssignmentsEdges<'_> { + type Item = AssignmentsEdge; + + fn next(&mut self) -> Option { + loop { + if let Some((node, outgoing_neighbors)) = &mut self.outgoing_neighbors { + if let Some(outgoing_neighbor) = outgoing_neighbors.next() { + return Some(match (*node, outgoing_neighbor) { + ( + AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), + AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), + ) => unreachable!(), + ( + AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index, + assignment_index, + }, + ( + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentOrSlotIndex::SmallSlot(slot), + ) => AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentOrSlotIndex::BigSlot(slot), + ) => AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::BigSlot(slot), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index, + slot, + }), + }); + } } + let node = self.nodes.next()?; + self.outgoing_neighbors = Some(( + node, + self.assignments + .neighbors_directed(node, petgraph::Direction::Outgoing), + )); } + } +} - $(impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.index)); +impl<'a> IntoEdgeReferences for &'a Assignments { + type EdgeRef = AssignmentsEdge; + type EdgeReferences = AssignmentsEdges<'a>; + + fn edge_references(self) -> Self::EdgeReferences { + AssignmentsEdges { + assignments: self, + nodes: self.node_identifiers(), + outgoing_neighbors: None, + } + } +} + +struct AssignmentsVisitMap { + assignments: Vec, + slots: DenseSlotSet, +} + +impl VisitMap for AssignmentsVisitMap { + fn visit(&mut self, n: AssignmentOrSlotIndex) -> bool { + match n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + !mem::replace(&mut self.assignments[assignment_index], true) } - })* + AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.insert(slot), + AssignmentOrSlotIndex::BigSlot(slot) => self.slots.insert(slot), + } + } - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond_body| match cond_body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - self.extend([cond.range]); + fn is_visited(&self, n: &AssignmentOrSlotIndex) -> bool { + match *n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + self.assignments[assignment_index] + } + AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.contains(slot), + AssignmentOrSlotIndex::BigSlot(slot) => self.slots.contains(slot), + } + } + + fn unvisit(&mut self, n: AssignmentOrSlotIndex) -> bool { + match n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + mem::replace(&mut self.assignments[assignment_index], false) + } + AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.remove(slot), + AssignmentOrSlotIndex::BigSlot(slot) => self.slots.remove(slot), + } + } +} + +impl Visitable for Assignments { + type Map = AssignmentsVisitMap; + + fn visit_map(self: &Self) -> Self::Map { + AssignmentsVisitMap { + assignments: vec![false; self.assignments().len()], + slots: DenseSlotSet::new(self.slot_readers().len()), + } + } + + fn reset_map(self: &Self, map: &mut Self::Map) { + let AssignmentsVisitMap { assignments, slots } = map; + assignments.clear(); + assignments.resize(self.assignments().len(), false); + if slots.len() != self.slot_readers().len() { + *slots = DenseSlotSet::new(self.slot_readers().len()); + } else { + slots.clear(); + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct DenseSlotSet(TypeParts); + +impl DenseSlotSet { + fn new(len: TypeLen) -> Self { + let TypeLen { + small_slots, + big_slots, + } = len; + Self(TypeParts { + small_slots: vec![false; small_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + big_slots: vec![false; big_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + }) + } + fn len(&self) -> TypeLen { + TypeLen { + small_slots: StatePartLen { + value: self.0.small_slots.len() as _, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: self.0.big_slots.len() as _, + _phantom: PhantomData, + }, + } + } + fn clear(&mut self) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.fill(false); + big_slots.fill(false); + } +} + +impl StatePartsValue for DenseSlotSet { + type Value = Box<[bool]>; +} + +trait DenseSlotSetMethods: Extend> { + fn contains(&self, k: StatePartIndex) -> bool; + fn remove(&mut self, k: StatePartIndex) -> bool { + self.take(k).is_some() + } + fn take(&mut self, k: StatePartIndex) -> Option>; + fn replace(&mut self, k: StatePartIndex) -> Option>; + fn insert(&mut self, k: StatePartIndex) -> bool { + self.replace(k).is_none() + } +} + +impl Extend> for DenseSlotSet +where + Self: DenseSlotSetMethods, +{ + fn extend>>(&mut self, iter: T) { + iter.into_iter().for_each(|v| { + self.insert(v); + }); + } +} + +impl DenseSlotSetMethods for DenseSlotSet { + fn contains(&self, k: StatePartIndex) -> bool { + self.0.small_slots[k.as_usize()] + } + + fn take( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(self.0.small_slots.get_mut(k.as_usize())?, false).then_some(k) + } + + fn replace( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(&mut self.0.small_slots[k.as_usize()], true).then_some(k) + } +} + +impl DenseSlotSetMethods for DenseSlotSet { + fn contains(&self, k: StatePartIndex) -> bool { + self.0.big_slots[k.as_usize()] + } + + fn take( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(self.0.big_slots.get_mut(k.as_usize())?, false).then_some(k) + } + + fn replace( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(&mut self.0.big_slots[k.as_usize()], true).then_some(k) + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +struct SlotVec(TypeParts); + +impl SlotVec { + fn is_empty(&self) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.is_empty() && big_slots.is_empty() + } +} + +impl StatePartsValue for SlotVec { + type Value = Vec>; +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +struct SlotSet(TypeParts); + +impl SlotSet { + fn is_empty(&self) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.is_empty() && big_slots.is_empty() + } + fn for_each( + &self, + small_slots_fn: impl FnMut(StatePartIndex), + big_slots_fn: impl FnMut(StatePartIndex), + ) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().copied().for_each(small_slots_fn); + big_slots.iter().copied().for_each(big_slots_fn); + } + fn all( + &self, + small_slots_fn: impl FnMut(StatePartIndex) -> bool, + big_slots_fn: impl FnMut(StatePartIndex) -> bool, + ) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().copied().all(small_slots_fn) + && big_slots.iter().copied().all(big_slots_fn) + } +} + +impl StatePartsValue for SlotSet { + type Value = BTreeSet>; +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.0.small_slots.extend(iter); + } +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.0.big_slots.extend(iter); + } +} + +impl Extend> for SlotSet +where + Self: Extend>, +{ + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().flat_map(|v| v.iter())); + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |TypeIndexRange { + small_slots, + big_slots, + }| { + self.extend(small_slots.iter()); + self.extend(big_slots.iter()); + }, + ) + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |TypeArrayIndex { + small_slots, + big_slots, + }| { + self.extend([small_slots]); + self.extend([big_slots]); + }, + ) + } +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|v| v.index)); + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cond_body| match cond_body { + CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { + self.extend([cond.range]); + } + CondBody::MatchArm { + discriminant, + variant_index: _, + } => self.extend([discriminant]), + }) + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|v| v.body)) + } +} + +#[derive(Debug)] +struct Assignment { + inputs: SlotSet, + outputs: SlotSet, + conditions: Interned<[Cond]>, + insns: Vec, + source_location: SourceLocation, +} + +#[derive(Debug)] +struct SlotToAssignmentIndexFullMap(TypeParts); + +impl StatePartsValue for SlotToAssignmentIndexFullMap { + type Value = Box<[Vec]>; +} + +impl SlotToAssignmentIndexFullMap { + fn new(len: TypeLen) -> Self { + let TypeLen { + small_slots, + big_slots, + } = len; + Self(TypeParts { + small_slots: vec![Vec::new(); small_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + big_slots: vec![Vec::new(); big_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + }) + } + fn len(&self) -> TypeLen { + TypeLen { + small_slots: StatePartLen { + value: self.0.small_slots.len() as _, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: self.0.big_slots.len() as _, + _phantom: PhantomData, + }, + } + } + fn keys_for_assignment( + &mut self, + assignment_index: usize, + ) -> SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + SlotToAssignmentIndexFullMapKeysForAssignment { + map: self, + assignment_index, + } + } + fn for_each( + &self, + mut small_slots_fn: impl FnMut(StatePartIndex, &[usize]), + mut big_slots_fn: impl FnMut(StatePartIndex, &[usize]), + ) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().enumerate().for_each(|(k, v)| { + small_slots_fn( + StatePartIndex { + value: k as _, + _phantom: PhantomData, + }, + v, + ) + }); + big_slots.iter().enumerate().for_each(|(k, v)| { + big_slots_fn( + StatePartIndex { + value: k as _, + _phantom: PhantomData, + }, + v, + ) + }); + } +} + +impl std::ops::Index> for SlotToAssignmentIndexFullMap { + type Output = Vec; + + fn index(&self, index: StatePartIndex) -> &Self::Output { + &self.0.small_slots[index.as_usize()] + } +} + +impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { + fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { + &mut self.0.small_slots[index.as_usize()] + } +} + +impl std::ops::Index> for SlotToAssignmentIndexFullMap { + type Output = Vec; + + fn index(&self, index: StatePartIndex) -> &Self::Output { + &self.0.big_slots[index.as_usize()] + } +} + +impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { + fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { + &mut self.0.big_slots[index.as_usize()] + } +} + +struct SlotToAssignmentIndexFullMapKeysForAssignment<'a> { + map: &'a mut SlotToAssignmentIndexFullMap, + assignment_index: usize, +} + +impl<'a, K: StatePartKind> Extend<&'a StatePartIndex> + for SlotToAssignmentIndexFullMapKeysForAssignment<'_> +where + Self: Extend>, +{ + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().copied()); + } +} + +impl Extend> + for SlotToAssignmentIndexFullMapKeysForAssignment<'_> +where + SlotToAssignmentIndexFullMap: IndexMut, Output = Vec>, +{ + fn extend>>(&mut self, iter: T) { + iter.into_iter() + .for_each(|slot| self.map[slot].push(self.assignment_index)); + } +} + +impl<'a> Extend<&'a SlotSet> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |SlotSet(TypeParts { + small_slots, + big_slots, + })| { + self.extend(small_slots); + self.extend(big_slots); + }, + ); + } +} + +impl<'a> Extend<&'a Cond> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cond| match cond.body { + CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { + let CompiledValue { + range: + TypeIndexRange { + small_slots, + big_slots, + }, + layout: _, + write: _, + } = cond; + self.extend(small_slots.iter()); + self.extend(big_slots.iter()); + } + CondBody::MatchArm { + discriminant, + variant_index: _, + } => self.extend([discriminant]), + }); + } +} + +impl Assignment { + fn new( + conditions: Interned<[Cond]>, + insns: Vec, + source_location: SourceLocation, + ) -> Self { + let mut inputs = SlotSet::default(); + let mut outputs = SlotSet::default(); + for insn in &insns { + let insn = match insn { + InsnOrLabel::Insn(insn) => insn, + InsnOrLabel::Label(_) => continue, + }; + for InsnField { ty, kind } in insn.fields() { + match (kind, ty) { + (InsnFieldKind::Input, InsnFieldType::SmallSlot(&slot)) => { + inputs.extend([slot]); } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }) + (InsnFieldKind::Input, InsnFieldType::BigSlot(&slot)) => { + inputs.extend([slot]); + } + ( + InsnFieldKind::Input, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Input, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::SmallSlot(&slot)) => { + outputs.extend([slot]); + } + (InsnFieldKind::Output, InsnFieldType::BigSlot(&slot)) => { + outputs.extend([slot]); + } + ( + InsnFieldKind::Output, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| { + outputs.extend([slot]); + }); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| { + outputs.extend([slot]); + }); + inputs.extend(array_indexed.indexes); + } + ( + _, + InsnFieldType::Memory(_) + | InsnFieldType::SmallUInt(_) + | InsnFieldType::SmallSInt(_) + | InsnFieldType::InternedBigInt(_) + | InsnFieldType::U8(_) + | InsnFieldType::USize(_) + | InsnFieldType::Empty(_), + ) + | ( + InsnFieldKind::Immediate + | InsnFieldKind::Memory + | InsnFieldKind::BranchTarget, + _, + ) => {} + } } } - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.body)) - } + Self { + inputs, + outputs, + conditions, + insns, + source_location, } - }; -} - -get_state_part_kinds! { - make_slot_set! { - type_plural_fields; - type_kinds; } } @@ -1657,395 +1663,6 @@ pub struct Compiler { dump_assignments_dot: Option>>, } -macro_rules! impl_compiler { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_singular_fields = [$($type_singular_field:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - copy_insns = [$($copy_insn:ident,)*]; - read_indexed_insns = [$($read_indexed_insn:ident,)*]; - write_indexed_insns = [$($write_indexed_insn:ident,)*]; - ) => { - impl Compiler { - fn make_trace_scalar_helper( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - source_location: SourceLocation, - $($type_singular_field: impl FnOnce(StatePartIndex<$type_kind>) -> SimTraceKind,)* - ) -> TraceLocation { - match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); - TraceLocation::Scalar(self.new_sim_trace(match compiled_value.range.len().as_single() { - $(Some(TypeLenSingle::$type_singular_variant) => { - $type_singular_field(compiled_value.range.$type_plural_field.start) - })* - None => unreachable!(), - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.bit_width(), - }), - } - } - fn make_trace_scalar( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - name: Interned, - source_location: SourceLocation, - ) -> TraceDecl { - let flow = target.flow(); - match target.ty() { - CanonicalType::UInt(ty) => TraceUInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallUInt { index, ty }, - |index| SimTraceKind::BigUInt { index, ty }, - ), - name, - ty, - flow, - } - .into(), - CanonicalType::SInt(ty) => TraceSInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSInt { index, ty }, - |index| SimTraceKind::BigSInt { index, ty }, - ), - name, - ty, - flow, - } - .into(), - CanonicalType::Bool(_) => TraceBool { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallBool { index }, - |index| SimTraceKind::BigBool { index }, - ), - name, - flow, - } - .into(), - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(ty) => { - assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); - let location = match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = - self.compiled_expr_to_value(compiled_value, source_location); - let discriminant = self.compile_enum_discriminant( - compiled_value.map_ty(Enum::from_canonical), - source_location, - ); - TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::EnumDiscriminant { - index: discriminant, - ty, - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.type_properties().bit_width, - }), - }; - TraceFieldlessEnum { - location, - name, - ty, - flow, - } - .into() - } - CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::AsyncReset(_) => TraceAsyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallAsyncReset { index }, - |index| SimTraceKind::BigAsyncReset { index }, - ), - name, - flow, - } - .into(), - CanonicalType::SyncReset(_) => TraceSyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSyncReset { index }, - |index| SimTraceKind::BigSyncReset { index }, - ), - name, - flow, - } - .into(), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(_) => TraceClock { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallClock { index }, - |index| SimTraceKind::BigClock { index }, - ), - name, - flow, - } - .into(), - } - } - fn compiled_expr_to_value( - &mut self, - expr: CompiledExpr, - source_location: SourceLocation, - ) -> CompiledValue { - if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { - return retval; - } - assert!( - expr.static_part.layout.ty.is_passive(), - "invalid expression passed to compiled_expr_to_value -- type must be passive", - ); - let CompiledExpr { - static_part, - indexes, - } = expr; - let retval = if indexes.as_ref().is_empty() { - CompiledValue { - layout: static_part.layout, - range: static_part.range, - write: None, - } - } else { - let layout = static_part.layout.with_anonymized_debug_info(); - let retval = CompiledValue { - layout, - range: self.insns.allocate_variable(&layout.layout), - write: None, - }; - let TypeIndexRange { - $($type_plural_field,)* - } = retval.range; - self.add_assignment( - Interned::default(), - chain!( - $($type_plural_field - .iter() - .zip(static_part.range.$type_plural_field.iter()) - .map(|(dest, base)| Insn::$read_indexed_insn { - dest, - src: StatePartArrayIndexed { - base, - indexes: indexes.$type_plural_field, - }, - }),)* - ), - source_location, - ); - retval - }; - self.compiled_exprs_to_values.insert(expr, retval); - retval - } - fn compile_simple_connect( - &mut self, - conditions: Interned<[Cond]>, - lhs: CompiledExpr, - rhs: CompiledValue, - source_location: SourceLocation, - ) { - let CompiledExpr { - static_part: lhs_static_part, - indexes, - } = lhs; - let (lhs_layout, lhs_range) = lhs_static_part.write(); - assert!( - lhs_layout.ty.is_passive(), - "invalid expression passed to compile_simple_connect -- type must be passive", - ); - self.add_assignment( - conditions, - chain!( - $(lhs_range.$type_plural_field - .iter() - .zip(rhs.range.$type_plural_field.iter()) - .map(|(base, src)| { - if indexes.$type_plural_field.is_empty() { - Insn::$copy_insn { dest: base, src } - } else { - Insn::$write_indexed_insn { - dest: StatePartArrayIndexed { - base, - indexes: indexes.$type_plural_field, - }, - src, - } - } - }),)* - ), - source_location, - ); - } - fn process_assignments(&mut self) { - self.assignments - .finalize(self.insns.state_layout().ty.clone().into()); - if let Some(DebugOpaque(dump_assignments_dot)) = &self.dump_assignments_dot { - let graph = - petgraph::graph::DiGraph::<_, _, usize>::from_elements(self.assignments.elements()); - dump_assignments_dot(&petgraph::dot::Dot::new(&graph)); - } - let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) { - Ok(nodes) => nodes - .into_iter() - .filter_map(|n| match n { - AssignmentOrSlotIndex::AssignmentIndex(v) => Some(v), - _ => None, - }) - .collect(), - Err(e) => match e.node_id() { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( - "combinatorial logic cycle detected at: {}", - self.assignments.assignments()[assignment_index].source_location, - ), - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => panic!( - "combinatorial logic cycle detected through: {}", - self.insns.state_layout().ty.$type_plural_field.debug_data[slot.as_usize()].name, - ),)* - }, - }; - struct CondStackEntry<'a> { - cond: &'a Cond, - end_label: Label, - } - let mut cond_stack = Vec::>::new(); - for assignment_index in assignments_order { - let Assignment { - inputs: _, - outputs: _, - conditions, - insns, - source_location, - } = &self.assignments.assignments()[assignment_index]; - let mut same_len = 0; - for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() { - if entry.cond != cond { - break; - } - same_len = index + 1; - } - while cond_stack.len() > same_len { - let CondStackEntry { cond: _, end_label } = - cond_stack.pop().expect("just checked len"); - self.insns.define_label_at_next_insn(end_label); - } - for cond in &conditions[cond_stack.len()..] { - let end_label = self.insns.new_label(); - match cond.body { - CondBody::IfTrue { cond: cond_value } - | CondBody::IfFalse { cond: cond_value } => { - let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => ( - Insn::BranchIfSmallZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - Insn::BranchIfSmallNonZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - ), - Some(TypeLenSingle::BigSlot) => ( - Insn::BranchIfZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - Insn::BranchIfNonZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - ), - None => unreachable!(), - }; - self.insns.push( - if let CondBody::IfTrue { .. } = cond.body { - branch_if_zero - } else { - branch_if_non_zero - }, - cond.source_location, - ); - } - CondBody::MatchArm { - discriminant, - variant_index, - } => { - self.insns.push( - Insn::BranchIfSmallNeImmediate { - target: end_label.0, - lhs: discriminant, - rhs: variant_index as _, - }, - cond.source_location, - ); - } - } - cond_stack.push(CondStackEntry { cond, end_label }); - } - self.insns.extend(insns.iter().copied(), *source_location); - } - for CondStackEntry { cond: _, end_label } in cond_stack { - self.insns.define_label_at_next_insn(end_label); - } - } - } - }; -} - -get_state_part_kinds! { - impl_compiler! { - type_plural_fields; - type_singular_fields; - type_singular_variants; - type_kinds; - copy_insns; - read_indexed_insns; - write_indexed_insns; - } -} - impl Compiler { pub fn new(base_module: Interned>) -> Self { let original_base_module = base_module; @@ -2087,6 +1704,165 @@ impl Compiler { }); id } + fn make_trace_scalar_helper( + &mut self, + instantiated_module: InstantiatedModule, + target: MakeTraceDeclTarget, + source_location: SourceLocation, + small_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, + big_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, + ) -> TraceLocation { + match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); + TraceLocation::Scalar(self.new_sim_trace(match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), + TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), + _ => unreachable!(), + })) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.bit_width(), + }), + } + } + fn make_trace_scalar( + &mut self, + instantiated_module: InstantiatedModule, + target: MakeTraceDeclTarget, + name: Interned, + source_location: SourceLocation, + ) -> TraceDecl { + let flow = target.flow(); + match target.ty() { + CanonicalType::UInt(ty) => TraceUInt { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallUInt { index, ty }, + |index| SimTraceKind::BigUInt { index, ty }, + ), + name, + ty, + flow, + } + .into(), + CanonicalType::SInt(ty) => TraceSInt { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallSInt { index, ty }, + |index| SimTraceKind::BigSInt { index, ty }, + ), + name, + ty, + flow, + } + .into(), + CanonicalType::Bool(_) => TraceBool { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallBool { index }, + |index| SimTraceKind::BigBool { index }, + ), + name, + flow, + } + .into(), + CanonicalType::Array(_) => unreachable!(), + CanonicalType::Enum(ty) => { + assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); + let location = match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = + self.compiled_expr_to_value(compiled_value, source_location); + let discriminant = self.compile_enum_discriminant( + compiled_value.map_ty(Enum::from_canonical), + source_location, + ); + TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::EnumDiscriminant { + index: discriminant, + ty, + })) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.type_properties().bit_width, + }), + }; + TraceFieldlessEnum { + location, + name, + ty, + flow, + } + .into() + } + CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) => unreachable!(), + CanonicalType::AsyncReset(_) => TraceAsyncReset { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallAsyncReset { index }, + |index| SimTraceKind::BigAsyncReset { index }, + ), + name, + flow, + } + .into(), + CanonicalType::SyncReset(_) => TraceSyncReset { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallSyncReset { index }, + |index| SimTraceKind::BigSyncReset { index }, + ), + name, + flow, + } + .into(), + CanonicalType::Reset(_) => unreachable!(), + CanonicalType::Clock(_) => TraceClock { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallClock { index }, + |index| SimTraceKind::BigClock { index }, + ), + name, + flow, + } + .into(), + } + } fn make_trace_decl_child( &mut self, instantiated_module: InstantiatedModule, @@ -2444,6 +2220,70 @@ impl Compiler { self.compiled_values.insert(target, retval); retval } + fn compiled_expr_to_value( + &mut self, + expr: CompiledExpr, + source_location: SourceLocation, + ) -> CompiledValue { + if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { + return retval; + } + assert!( + expr.static_part.layout.ty.is_passive(), + "invalid expression passed to compiled_expr_to_value -- type must be passive", + ); + let CompiledExpr { + static_part, + indexes, + } = expr; + let retval = if indexes.as_ref().is_empty() { + CompiledValue { + layout: static_part.layout, + range: static_part.range, + write: None, + } + } else { + let layout = static_part.layout.with_anonymized_debug_info(); + let retval = CompiledValue { + layout, + range: self.insns.allocate_variable(&layout.layout), + write: None, + }; + let TypeIndexRange { + small_slots, + big_slots, + } = retval.range; + self.add_assignment( + Interned::default(), + small_slots + .iter() + .zip(static_part.range.small_slots.iter()) + .map(|(dest, base)| Insn::ReadSmallIndexed { + dest, + src: StatePartArrayIndexed { + base, + indexes: indexes.small_slots, + }, + }) + .chain( + big_slots + .iter() + .zip(static_part.range.big_slots.iter()) + .map(|(dest, base)| Insn::ReadIndexed { + dest, + src: StatePartArrayIndexed { + base, + indexes: indexes.big_slots, + }, + }), + ), + source_location, + ); + retval + }; + self.compiled_exprs_to_values.insert(expr, retval); + retval + } fn add_assignment>( &mut self, conditions: Interned<[Cond]>, @@ -2462,7 +2302,7 @@ impl Compiler { let input = self.compile_expr(instantiated_module, input); let input = self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); - assert_eq!(input.range.len(), TypeLen::big_slot()); + assert_eq!(input.range.len(), TypeLen::A_BIG_SLOT); input.range.big_slots.start } fn compile_expr_helper( @@ -2493,7 +2333,7 @@ impl Compiler { make_insns: impl FnOnce(StatePartIndex) -> Vec, ) -> CompiledValue { self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { - assert_eq!(dest.len(), TypeLen::big_slot()); + assert_eq!(dest.len(), TypeLen::A_BIG_SLOT); make_insns(dest.big_slots.start) }) } @@ -2525,9 +2365,9 @@ impl Compiler { } let mut ty = compiled_value.layout.ty; ty.width = ty.width.min(SmallUInt::BITS as usize); - let retval = match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => compiled_value.range.small_slots.start, - Some(TypeLenSingle::BigSlot) => { + let retval = match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, + TypeLen::A_BIG_SLOT => { let debug_data = SlotDebugData { name: Interned::default(), ty: ty.canonical(), @@ -2550,7 +2390,7 @@ impl Compiler { ); dest } - None => unreachable!(), + _ => unreachable!(), }; self.compiled_values_to_dyn_array_indexes .insert(compiled_value, retval); @@ -2567,9 +2407,9 @@ impl Compiler { { return retval; } - let retval = match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => compiled_value.range.small_slots.start, - Some(TypeLenSingle::BigSlot) => { + let retval = match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, + TypeLen::A_BIG_SLOT => { let debug_data = SlotDebugData { name: Interned::default(), ty: Bool.canonical(), @@ -2578,7 +2418,7 @@ impl Compiler { .insns .allocate_variable(&TypeLayout { small_slots: StatePartLayout::scalar(debug_data, ()), - ..TypeLayout::empty() + big_slots: StatePartLayout::empty(), }) .small_slots .start; @@ -2592,7 +2432,7 @@ impl Compiler { ); dest } - None => unreachable!(), + _ => unreachable!(), }; self.compiled_value_bool_dest_is_small_map .insert(compiled_value, retval); @@ -3591,6 +3431,65 @@ impl Compiler { self.compiled_exprs.insert(expr, retval); retval } + fn compile_simple_connect( + &mut self, + conditions: Interned<[Cond]>, + lhs: CompiledExpr, + rhs: CompiledValue, + source_location: SourceLocation, + ) { + let CompiledExpr { + static_part: lhs_static_part, + indexes, + } = lhs; + let (lhs_layout, lhs_range) = lhs_static_part.write(); + assert!( + lhs_layout.ty.is_passive(), + "invalid expression passed to compile_simple_connect -- type must be passive", + ); + let TypeIndexRange { + small_slots, + big_slots, + } = lhs_range; + self.add_assignment( + conditions, + small_slots + .iter() + .zip(rhs.range.small_slots.iter()) + .map(|(base, src)| { + if indexes.small_slots.is_empty() { + Insn::CopySmall { dest: base, src } + } else { + Insn::WriteSmallIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.small_slots, + }, + src, + } + } + }) + .chain( + big_slots + .iter() + .zip(rhs.range.big_slots.iter()) + .map(|(base, src)| { + if indexes.big_slots.is_empty() { + Insn::Copy { dest: base, src } + } else { + Insn::WriteIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.big_slots, + }, + src, + } + } + }), + ), + source_location, + ); + } fn compile_connect( &mut self, lhs_instantiated_module: InstantiatedModule, @@ -3775,7 +3674,7 @@ impl Compiler { .collect(), ); let retval = if retval_ty == enum_value.layout.ty - && enum_value.range.len() == TypeLen::small_slot() + && enum_value.range.len() == TypeLen::A_SMALL_SLOT { enum_value.range.small_slots.start } else { @@ -3794,13 +3693,13 @@ impl Compiler { .start; let discriminant_bit_width = enum_value.layout.ty.discriminant_bit_width(); let discriminant_mask = !(!0u64 << discriminant_bit_width); - let insn = match enum_value.range.len().as_single() { - Some(TypeLenSingle::BigSlot) => Insn::AndBigWithSmallImmediate { + let insn = match enum_value.range.len() { + TypeLen::A_BIG_SLOT => Insn::AndBigWithSmallImmediate { dest: retval, lhs: enum_value.range.big_slots.start, rhs: discriminant_mask, }, - Some(TypeLenSingle::SmallSlot) => { + TypeLen::A_SMALL_SLOT => { if discriminant_bit_width == enum_value.layout.ty.type_properties().bit_width { Insn::CopySmall { dest: retval, @@ -3814,7 +3713,7 @@ impl Compiler { } } } - None => unreachable!(), + _ => unreachable!(), }; self.add_assignment(Interned::default(), [insn], source_location); retval @@ -4020,7 +3919,7 @@ impl Compiler { }, (), ), - ..TypeLayout::empty() + big_slots: StatePartLayout::empty(), }, first, last, @@ -4065,8 +3964,8 @@ impl Compiler { }) = read { insns.push( - match data.len().as_single() { - Some(TypeLenSingle::BigSlot) => { + match data.len() { + TypeLen::A_BIG_SLOT => { let dest = data.big_slots.start; if signed { Insn::MemoryReadSInt { @@ -4088,11 +3987,11 @@ impl Compiler { } } } - Some(TypeLenSingle::SmallSlot) => { + TypeLen::A_SMALL_SLOT => { let _dest = data.small_slots.start; todo!("memory ports' data are always big for now"); } - None => unreachable!(), + _ => unreachable!(), } .into(), ); @@ -4108,22 +4007,22 @@ impl Compiler { { let end_label = self.insns.new_label(); insns.push( - match mask.len().as_single() { - Some(TypeLenSingle::BigSlot) => Insn::BranchIfZero { + match mask.len() { + TypeLen::A_BIG_SLOT => Insn::BranchIfZero { target: end_label.0, value: mask.big_slots.start, }, - Some(TypeLenSingle::SmallSlot) => Insn::BranchIfSmallZero { + TypeLen::A_SMALL_SLOT => Insn::BranchIfSmallZero { target: end_label.0, value: mask.small_slots.start, }, - None => unreachable!(), + _ => unreachable!(), } .into(), ); insns.push( - match data.len().as_single() { - Some(TypeLenSingle::BigSlot) => { + match data.len() { + TypeLen::A_BIG_SLOT => { let value = data.big_slots.start; if signed { Insn::MemoryWriteSInt { @@ -4145,11 +4044,11 @@ impl Compiler { } } } - Some(TypeLenSingle::SmallSlot) => { + TypeLen::A_SMALL_SLOT => { let _value = data.small_slots.start; todo!("memory ports' data are always big for now"); } - None => unreachable!(), + _ => unreachable!(), } .into(), ); @@ -4834,6 +4733,121 @@ impl Compiler { }, }) } + fn process_assignments(&mut self) { + self.assignments + .finalize(self.insns.state_layout().ty.clone().into()); + if let Some(DebugOpaque(dump_assignments_dot)) = &self.dump_assignments_dot { + let graph = + petgraph::graph::DiGraph::<_, _, usize>::from_elements(self.assignments.elements()); + dump_assignments_dot(&petgraph::dot::Dot::new(&graph)); + } + let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) { + Ok(nodes) => nodes + .into_iter() + .filter_map(|n| match n { + AssignmentOrSlotIndex::AssignmentIndex(v) => Some(v), + _ => None, + }) + .collect(), + Err(e) => match e.node_id() { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( + "combinatorial logic cycle detected at: {}", + self.assignments.assignments()[assignment_index].source_location, + ), + AssignmentOrSlotIndex::SmallSlot(slot) => panic!( + "combinatorial logic cycle detected through: {}", + self.insns.state_layout().ty.small_slots.debug_data[slot.as_usize()].name, + ), + AssignmentOrSlotIndex::BigSlot(slot) => panic!( + "combinatorial logic cycle detected through: {}", + self.insns.state_layout().ty.big_slots.debug_data[slot.as_usize()].name, + ), + }, + }; + struct CondStackEntry<'a> { + cond: &'a Cond, + end_label: Label, + } + let mut cond_stack = Vec::>::new(); + for assignment_index in assignments_order { + let Assignment { + inputs: _, + outputs: _, + conditions, + insns, + source_location, + } = &self.assignments.assignments()[assignment_index]; + let mut same_len = 0; + for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() { + if entry.cond != cond { + break; + } + same_len = index + 1; + } + while cond_stack.len() > same_len { + let CondStackEntry { cond: _, end_label } = + cond_stack.pop().expect("just checked len"); + self.insns.define_label_at_next_insn(end_label); + } + for cond in &conditions[cond_stack.len()..] { + let end_label = self.insns.new_label(); + match cond.body { + CondBody::IfTrue { cond: cond_value } + | CondBody::IfFalse { cond: cond_value } => { + let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len() { + TypeLen::A_SMALL_SLOT => ( + Insn::BranchIfSmallZero { + target: end_label.0, + value: cond_value.range.small_slots.start, + }, + Insn::BranchIfSmallNonZero { + target: end_label.0, + value: cond_value.range.small_slots.start, + }, + ), + TypeLen::A_BIG_SLOT => ( + Insn::BranchIfZero { + target: end_label.0, + value: cond_value.range.big_slots.start, + }, + Insn::BranchIfNonZero { + target: end_label.0, + value: cond_value.range.big_slots.start, + }, + ), + _ => unreachable!(), + }; + self.insns.push( + if let CondBody::IfTrue { .. } = cond.body { + branch_if_zero + } else { + branch_if_non_zero + }, + cond.source_location, + ); + } + CondBody::MatchArm { + discriminant, + variant_index, + } => { + self.insns.push( + Insn::BranchIfSmallNeImmediate { + target: end_label.0, + lhs: discriminant, + rhs: variant_index as _, + }, + cond.source_location, + ); + } + } + cond_stack.push(CondStackEntry { cond, end_label }); + } + self.insns.extend(insns.iter().copied(), *source_location); + } + for CondStackEntry { cond: _, end_label } in cond_stack { + self.insns.define_label_at_next_insn(end_label); + } + } fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { mem::take(&mut self.clock_triggers) .into_iter() diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 7d412caa..35a25d0c 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -2,30 +2,27 @@ // See Notices.txt for copyright information use crate::{ + array::Array, int::{BoolOrIntType, SInt, UInt}, intern::{Intern, Interned, Memoize}, - sim::interpreter::parts::{ - StateLayout, StatePartIndex, StatePartKind, StatePartKindBigSlots, StatePartKindMemories, - StatePartKindSmallSlots, StatePartLen, TypeIndexRange, TypeLayout, get_state_part_kinds, - }, source_location::SourceLocation, + ty::CanonicalType, util::{HashMap, HashSet}, }; -use bitvec::slice::BitSlice; +use bitvec::{boxed::BitBox, slice::BitSlice}; use num_bigint::BigInt; use num_traits::{One, Signed, ToPrimitive, Zero}; use std::{ + any::TypeId, borrow::BorrowMut, convert::Infallible, fmt::{self, Write}, - hash::Hash, + hash::{Hash, Hasher}, marker::PhantomData, ops::{ControlFlow, Deref, DerefMut, Index, IndexMut}, }; use vec_map::VecMap; -pub(crate) mod parts; - pub(crate) type SmallUInt = u64; pub(crate) type SmallSInt = i64; pub(crate) const MIN_BITS_FOR_NEEDING_BIG: usize = SmallUInt::BITS as usize + 1; @@ -113,33 +110,19 @@ macro_rules! insn_field_enum { }; } -macro_rules! insn_field_enum2 { - ( - type_singular_variants = [$($type_singular_variant:ident,)*]; - array_indexed_variants = [$($array_indexed_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - insn_field_enum! { - pub(crate) enum InsnFieldType { - Memory(Transform::Type>), - $($type_singular_variant(Transform::Type>),)* - $($array_indexed_variant(Transform::Type>),)* - SmallUInt(Transform::Type), - SmallSInt(Transform::Type), - InternedBigInt(Transform::Type>), - U8(Transform::Type), - USize(Transform::Type), - Empty(Transform::Type<[(); 0]>), - } - } - }; -} - -get_state_part_kinds! { - insn_field_enum2! { - type_singular_variants; - array_indexed_variants; - type_kinds; +insn_field_enum! { + pub(crate) enum InsnFieldType { + Memory(Transform::Type>), + SmallSlot(Transform::Type>), + BigSlot(Transform::Type>), + SmallSlotArrayIndexed(Transform::Type>), + BigSlotArrayIndexed(Transform::Type>), + SmallUInt(Transform::Type), + SmallSInt(Transform::Type), + InternedBigInt(Transform::Type>), + U8(Transform::Type), + USize(Transform::Type), + Empty(Transform::Type<[(); 0]>), } } @@ -791,6 +774,911 @@ impl fmt::Debug for Insns { } } +pub(crate) trait StatePartKind: + Send + Sync + Ord + Hash + fmt::Debug + 'static + Copy + Default +{ + const NAME: &'static str; + type DebugData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; + type LayoutData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; + type State: fmt::Debug + 'static + Clone; + type BorrowedState<'a>: 'a; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State; + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>; + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData>; + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result; +} + +pub(crate) trait StatePartsValue { + type Value; +} + +macro_rules! impl_state_parts_traits { + ( + struct $Struct:ident<$V:ident: $StatePartsValue:ident> { + $(#[flatten] + $flattened_field:ident: $flattened_field_ty:ty, + $(#[field_in_flattened] + $field_in_flattened:ident: $field_in_flattened_ty:ty,)* + )? + $($field:ident: $field_ty:ty,)* + } + ) => { + impl<$V: $StatePartsValue> Copy for $Struct<$V> + where + $($flattened_field_ty: Copy,)? + $($field_ty: Copy,)* + { + } + + impl<$V: $StatePartsValue> Clone for $Struct<$V> + where + $($flattened_field_ty: Clone,)? + $($field_ty: Clone,)* + { + fn clone(&self) -> Self { + Self { + $($flattened_field: self.$flattened_field.clone(),)? + $($field: self.$field.clone(),)* + } + } + } + + impl<$V: $StatePartsValue> fmt::Debug for $Struct<$V> + where + $($($field_in_flattened_ty: fmt::Debug,)*)? + $($field_ty: fmt::Debug,)* + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($Struct)) + $($(.field(stringify!($field_in_flattened), &self.$flattened_field.$field_in_flattened))*)? + $(.field(stringify!($field), &self.$field))* + .finish() + } + } + + impl<$V: $StatePartsValue> PartialEq for $Struct<$V> + where + $($flattened_field_ty: PartialEq,)? + $($field_ty: PartialEq,)* + { + fn eq(&self, other: &Self) -> bool { + true $(&& self.$flattened_field == other.$flattened_field)? $(&& self.$field == other.$field)* + } + } + + impl<$V: $StatePartsValue> Eq for $Struct<$V> + where + $($flattened_field_ty: Eq,)? + $($field_ty: Eq,)* + { + } + + impl<$V: $StatePartsValue> Hash for $Struct<$V> + where + $($flattened_field_ty: Hash,)? + $($field_ty: Hash,)* + { + fn hash(&self, h: &mut H) { + $(self.$flattened_field.hash(h);)? + $(self.$field.hash(h);)* + } + } + + impl<$V: $StatePartsValue> Default for $Struct<$V> + where + $($flattened_field_ty: Default,)? + $($field_ty: Default,)* + { + fn default() -> Self { + Self { + $($flattened_field: Default::default(),)? + $($field: Default::default(),)* + } + } + } + }; +} + +macro_rules! make_state_part_kinds { + ( + $( + #[state, field = $state_field:ident] + impl $StateStatePartKind:ident for $StateKind:ident $state_impl_body:tt + )* + $( + #[type, field = $type_field:ident] + impl $TypeStatePartKind:ident for $TypeKind:ident $type_impl_body:tt + )* + ) => { + $( + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] + pub(crate) struct $StateKind; + + impl $StateStatePartKind for $StateKind $state_impl_body + )* + + $( + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] + pub(crate) struct $TypeKind; + + impl $TypeStatePartKind for $TypeKind $type_impl_body + )* + + pub(crate) struct StateParts { + pub(crate) ty: TypeParts, + $(pub(crate) $state_field: V::Value<$StateKind>,)* + } + + impl_state_parts_traits! { + struct StateParts { + #[flatten] + ty: TypeParts, + $(#[field_in_flattened] + $type_field: V::Value<$TypeKind>,)* + $($state_field: V::Value<$StateKind>,)* + } + } + + pub(crate) struct TypeParts { + $(pub(crate) $type_field: V::Value<$TypeKind>,)* + } + + impl_state_parts_traits! { + struct TypeParts { + $($type_field: V::Value<$TypeKind>,)* + } + } + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateLayout { + pub(crate) ty: TypeLayout, + $(pub(crate) $state_field: StatePartLayout<$StateKind, BK>,)* + } + + impl Copy for StateLayout {} + + impl StateLayout { + pub(crate) fn len(&self) -> StateLen { + StateLen { + ty: self.ty.len(), + $($state_field: self.$state_field.len(),)* + } + } + pub(crate) fn is_empty(&self) -> bool { + self.ty.is_empty() $(&& self.$state_field.is_empty())* + } + pub(crate) fn empty() -> Self { + Self { + ty: TypeLayout::empty(), + $($state_field: StatePartLayout::empty(),)* + } + } + } + + impl StateLayout { + pub(crate) fn next_index(&self) -> StateIndex { + StateIndex { + ty: self.ty.next_index(), + $($state_field: self.$state_field.next_index(),)* + } + } + pub(crate) fn allocate( + &mut self, + layout: &StateLayout, + ) -> StateIndexRange { + StateIndexRange { + ty: self.ty.allocate(&layout.ty), + $($state_field: self.$state_field.allocate(&layout.$state_field),)* + } + } + } + + impl From> for StateLayout { + fn from(v: StateLayout) -> Self { + Self { + ty: v.ty.into(), + $($state_field: v.$state_field.into(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateIndexRange { + pub(crate) ty: TypeIndexRange, + $(pub(crate) $state_field: StatePartIndexRange<$StateKind>,)* + } + + impl StateIndexRange { + pub(crate) fn start(self) -> StateIndex { + StateIndex { + ty: self.ty.start(), + $($state_field: self.$state_field.start(),)* + } + } + pub(crate) fn len(self) -> StateLen { + StateLen { + ty: self.ty.len(), + $($state_field: self.$state_field.len(),)* + } + } + pub(crate) fn is_empty(self) -> bool { + self.ty.is_empty() $(&& self.$state_field.is_empty())* + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateLen { + pub(crate) ty: TypeLen, + $(pub(crate) $state_field: StatePartLen<$StateKind>,)* + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateIndex { + pub(crate) ty: TypeIndex, + $(pub(crate) $state_field: StatePartIndex<$StateKind>,)* + } + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeLayout { + $(pub(crate) $type_field: StatePartLayout<$TypeKind, BK>,)* + } + + impl Copy for TypeLayout {} + + impl TypeLayout { + pub(crate) fn len(&self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.len(),)* + } + } + pub(crate) fn is_empty(&self) -> bool { + $(self.$type_field.is_empty())&&+ + } + pub(crate) fn empty() -> Self { + Self { + $($type_field: StatePartLayout::empty(),)* + } + } + } + + impl TypeLayout { + pub(crate) fn next_index(&self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.next_index(),)* + } + } + pub(crate) fn allocate( + &mut self, + layout: &TypeLayout, + ) -> TypeIndexRange { + TypeIndexRange { + $($type_field: self.$type_field.allocate(&layout.$type_field),)* + } + } + } + + impl From> for TypeLayout { + fn from(v: TypeLayout) -> Self { + Self { + $($type_field: v.$type_field.into(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeIndexRange { + $(pub(crate) $type_field: StatePartIndexRange<$TypeKind>,)* + } + + impl TypeIndexRange { + pub(crate) fn new(start: TypeIndex, len: TypeLen) -> Self { + Self { + $($type_field: StatePartIndexRange { + start: start.$type_field, + len: len.$type_field, + },)* + } + } + pub(crate) fn start(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.start(),)* + } + } + pub(crate) fn len(self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.len(),)* + } + } + pub(crate) fn is_empty(self) -> bool { + $(self.$type_field.is_empty()) &&+ + } + pub(crate) fn slice(self, index: TypeIndexRange) -> Self { + Self { + $($type_field: self.$type_field.slice(index.$type_field),)* + } + } + pub(crate) fn index_array(self, element_size: TypeLen, index: usize) -> Self { + Self { + $($type_field: self.$type_field.index_array(element_size.$type_field, index),)* + } + } + pub(crate) fn offset(self, offset: TypeIndex) -> Self { + Self { + $($type_field: self.$type_field.offset(offset.$type_field),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeLen { + $(pub(crate) $type_field: StatePartLen<$TypeKind>,)* + } + + impl TypeLen { + pub(crate) const fn as_index(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.as_index(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeIndex { + $(pub(crate) $type_field: StatePartIndex<$TypeKind>,)* + } + + impl TypeIndex { + pub(crate) const ZERO: Self = Self { + $($type_field: StatePartIndex::ZERO,)* + }; + pub(crate) fn offset(self, offset: TypeIndex) -> Self { + Self { + $($type_field: self.$type_field.offset(offset.$type_field),)* + } + } + } + + pub(crate) struct State { + pub(crate) insns: Interned>, + pub(crate) pc: usize, + pub(crate) memory_write_log: Vec<(StatePartIndex, usize)>, + $(pub(crate) $state_field: StatePart<$StateKind>,)* + $(pub(crate) $type_field: StatePart<$TypeKind>,)* + } + + impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + insns: _, + pc, + memory_write_log, + $($state_field,)* + $($type_field,)* + } = self; + f.debug_struct("State") + .field("insns", &InsnsOfState(self)) + .field("pc", pc) + .field("memory_write_log", memory_write_log) + $(.field(stringify!($state_field), $state_field))* + $(.field(stringify!($type_field), $type_field))* + .finish() + } + } + + impl State { + pub(crate) fn new(insns: Interned>) -> Self { + Self { + insns, + pc: 0, + memory_write_log: Vec::with_capacity(32), + $($state_field: StatePart::new(&insns.state_layout.$state_field.layout_data),)* + $($type_field: StatePart::new(&insns.state_layout.ty.$type_field.layout_data),)* + } + } + pub(crate) fn borrow(&mut self) -> BorrowedState<'_> { + BorrowedState { + orig_insns: self.insns, + insns: &self.insns.insns, + pc: self.pc, + orig_pc: &mut self.pc, + memory_write_log: &mut self.memory_write_log, + $($state_field: self.$state_field.borrow(),)* + $($type_field: self.$type_field.borrow(),)* + } + } + } + + #[derive(Debug)] + pub(crate) struct BorrowedState<'a> { + pub(crate) orig_insns: Interned>, + pub(crate) insns: &'a [Insn], + pub(crate) orig_pc: &'a mut usize, + pub(crate) pc: usize, + pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex, usize)>, + $(pub(crate) $state_field: BorrowedStatePart<'a, $StateKind>,)* + $(pub(crate) $type_field: BorrowedStatePart<'a, $TypeKind>,)* + } + + impl Drop for BorrowedState<'_> { + fn drop(&mut self) { + *self.orig_pc = self.pc; + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexes { + $(pub(crate) $type_field: Interned<[StatePartArrayIndex<$TypeKind>]>,)* + } + + impl TypeArrayIndexes { + pub(crate) fn as_ref(&self) -> TypeArrayIndexesRef<'_> { + TypeArrayIndexesRef { + $($type_field: &self.$type_field,)* + } + } + #[must_use] + pub(crate) fn join(self, next: TypeArrayIndex) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: Interned::from_iter(self.$type_field.iter().copied().chain([next.$type_field])),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndex { + $(pub(crate) $type_field: StatePartArrayIndex<$TypeKind>,)* + } + + impl TypeArrayIndex { + pub(crate) fn from_parts(index: StatePartIndex, len: usize, stride: TypeLen) -> Self { + Self { + $($type_field: StatePartArrayIndex { + index, + len, + stride: stride.$type_field, + },)* + } + } + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len; + $(assert_eq!(self.$type_field.len, len, "array length mismatch");)* + len + } + pub(crate) fn index(self) -> StatePartIndex { + let index = self.small_slots.index; + $(assert_eq!(self.$type_field.index, index, "array index mismatch");)* + index + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn stride(self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.stride,)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexesRef<'a> { + $(pub(crate) $type_field: &'a [StatePartArrayIndex<$TypeKind>],)* + } + + impl<'a> TypeArrayIndexesRef<'a> { + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len(); + $(assert_eq!(self.$type_field.len(), len, "indexes count mismatch");)* + len + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn iter(self) -> impl Iterator + 'a { + (0..self.len()).map(move |i| TypeArrayIndex { + $($type_field: self.$type_field[i],)* + }) + } + pub(crate) fn for_each_offset( + self, + mut f: impl FnMut(TypeIndex), + ) { + self.for_each_offset2(TypeIndex { + $($type_field: StatePartIndex { + value: 0, + _phantom: PhantomData, + },)* + }, &mut f); + } + pub(crate) fn split_first(self) -> Option<(TypeArrayIndex, Self)> { + $(let $type_field = self.$type_field.split_first()?;)* + let next = TypeArrayIndex { + $($type_field: *$type_field.0,)* + }; + let rest = TypeArrayIndexesRef { + $($type_field: $type_field.1,)* + }; + Some((next, rest)) + } + pub(crate) fn for_each_offset2( + self, + base_offset: TypeIndex, + f: &mut (impl FnMut(TypeIndex) + ?Sized), + ) { + if let Some((next, rest)) = self.split_first() { + let stride = next.stride(); + for index in 0..next.len().try_into().expect("array too big") { + let mut offset = TypeIndex { + $($type_field: StatePartIndex { + value: stride + .$type_field + .value + .checked_mul(index) + .expect("array too big"), + _phantom: PhantomData, + },)* + }; + $(offset.$type_field.value = + base_offset + .$type_field + .value + .checked_add(offset.$type_field.value) + .expect("array too big");)* + rest.for_each_offset2(offset, f); + } + } else { + $(assert!(self.$type_field.is_empty(), "indexes count mismatch");)* + f(base_offset); + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndexed { + $(pub(crate) $type_field: StatePartArrayIndexed<$TypeKind>,)* + } + + impl TypeArrayIndexed { + pub(crate) fn from_parts(base: TypeIndex, indexes: TypeArrayIndexes) -> Self { + Self { + $($type_field: StatePartArrayIndexed { + base: base.$type_field, + indexes: indexes.$type_field, + },)* + } + } + pub(crate) fn base(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.base,)* + } + } + pub(crate) fn indexes(self) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: self.$type_field.indexes,)* + } + } + } + + impl From for TypeArrayIndexed { + fn from(value: TypeIndex) -> Self { + TypeArrayIndexed { + $($type_field: value.$type_field.into(),)* + } + } + } + }; +} + +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub(crate) struct MemoryData> { + pub(crate) array_type: Array, + pub(crate) data: T, +} + +impl> fmt::Debug for MemoryData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { array_type, data } = self; + f.debug_struct("MemoryData") + .field("array_type", array_type) + .field( + "data", + &crate::memory::DebugMemoryData::from_bit_slice(*array_type, data), + ) + .finish() + } +} + +make_state_part_kinds! { + /*#[state, field = small_stack] + impl StatePartKind for StatePartKindSmallStack { + const NAME: &'static str = "SmallStack"; + type DebugData = (); + type LayoutData = (); + type State = Stack; + type BorrowedState<'a> = BorrowedStack<'a, SmallUInt>; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + Stack::new(layout_data.len()) + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state.borrow() + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.small_stack.debug_data.get(part_index.as_usize()) + } + } + #[state, field = big_stack] + impl StatePartKind for StatePartKindBigStack { + const NAME: &'static str = "BigStack"; + type DebugData = (); + type LayoutData = (); + type State = Stack; + type BorrowedState<'a> = BorrowedStack<'a, BigInt>; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + Stack::new(layout_data.len()) + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state.borrow() + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.big_stack.debug_data.get(part_index.as_usize()) + } + }*/ + #[state, field = memories] + impl StatePartKind for StatePartKindMemories { + const NAME: &'static str = "Memories"; + type DebugData = (); + type LayoutData = MemoryData>; + type State = Box<[MemoryData]>; + type BorrowedState<'a> = &'a mut [MemoryData]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + layout_data.iter().map(|MemoryData { array_type, data }| MemoryData { + array_type: *array_type, + data: BitBox::from_bitslice(data), + }).collect() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.memories.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + write!(f, "{:#?}", &state.memories[index]) + } + } + #[type, field = small_slots] + impl StatePartKind for StatePartKindSmallSlots { + const NAME: &'static str = "SmallSlots"; + type DebugData = SlotDebugData; + type LayoutData = (); + type State = Box<[SmallUInt]>; + type BorrowedState<'a> = &'a mut [SmallUInt]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + vec![0; layout_data.len()].into_boxed_slice() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.ty.small_slots.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + let value = state.small_slots[index]; + write!(f, "{value:#x} {}", value as SmallSInt)?; + Ok(()) + } + } + #[type, field = big_slots] + impl StatePartKind for StatePartKindBigSlots { + const NAME: &'static str = "BigSlots"; + type DebugData = SlotDebugData; + type LayoutData = (); + type State = Box<[BigInt]>; + type BorrowedState<'a> = &'a mut [BigInt]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + layout_data.iter().map(|_| BigInt::default()).collect() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.ty.big_slots.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + write!(f, "{:#x}", state.big_slots[index]) + } + } +} + +impl TypeLen { + pub(crate) fn only_small(self) -> Option> { + let Self { + small_slots, + big_slots: + StatePartLen { + value: 0, + _phantom: _, + }, + } = self + else { + return None; + }; + Some(small_slots) + } + pub(crate) const A_SMALL_SLOT: Self = TypeLen { + small_slots: StatePartLen { + value: 1, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: 0, + _phantom: PhantomData, + }, + }; + pub(crate) const A_BIG_SLOT: Self = TypeLen { + small_slots: StatePartLen { + value: 0, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: 1, + _phantom: PhantomData, + }, + }; +} + +#[derive(Debug, Clone)] +pub(crate) struct Stack { + storage: Box<[T]>, + cur_len: usize, +} + +impl Stack { + pub(crate) fn new(len: usize) -> Self + where + T: Default, + { + Self { + storage: std::iter::repeat_with(T::default).take(len).collect(), + cur_len: 0, + } + } + pub(crate) fn borrow(&mut self) -> BorrowedStack<'_, T> { + BorrowedStack { + storage: &mut self.storage, + cur_len: self.cur_len, + stack_cur_len: &mut self.cur_len, + } + } + pub(crate) fn clear(&mut self) { + self.cur_len = 0; + } +} + +#[derive(Debug)] +pub(crate) struct BorrowedStack<'a, T> { + storage: &'a mut [T], + cur_len: usize, + stack_cur_len: &'a mut usize, +} + +impl<'a, T> BorrowedStack<'a, T> { + pub(crate) fn push(&mut self, value: T) { + self.storage[self.cur_len] = value; + self.cur_len += 1; + } + pub(crate) fn pop(&mut self) -> T + where + T: Default, + { + self.cur_len -= 1; + std::mem::take(&mut self.storage[self.cur_len]) + } +} + +impl Drop for BorrowedStack<'_, T> { + fn drop(&mut self) { + *self.stack_cur_len = self.cur_len; + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub(crate) struct SlotDebugData { + pub(crate) name: Interned, + pub(crate) ty: CanonicalType, +} + +impl SlotDebugData { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + let mut name = String::with_capacity(self.name.len() + prefix.len()); + name.push_str(prefix); + name.push_str(&self.name); + Self { + name: Intern::intern_owned(name), + ty: self.ty, + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + name: Interned::default(), + ty: self.ty, + } + } +} + +impl, BK: InsnsBuildingKind> StatePartLayout { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + Self { + debug_data: self + .debug_data + .iter() + .map(|v| v.with_prefixed_debug_names(prefix)) + .collect(), + layout_data: self.layout_data.clone(), + _phantom: PhantomData, + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + debug_data: self + .debug_data + .iter() + .map(|v| v.with_anonymized_debug_info()) + .collect(), + layout_data: self.layout_data.clone(), + _phantom: PhantomData, + } + } +} + +impl TypeLayout { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + Self { + small_slots: self.small_slots.with_prefixed_debug_names(prefix), + big_slots: self.big_slots.with_prefixed_debug_names(prefix), + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + small_slots: self.small_slots.with_anonymized_debug_info(), + big_slots: self.big_slots.with_anonymized_debug_info(), + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct StatePartArrayIndex { pub(crate) index: StatePartIndex, @@ -862,11 +1750,13 @@ impl StatePartArrayIndexed { if let [next, rest @ ..] = indexes { for i in 0..next.len.try_into().expect("array too big") { Self::for_each_target2( - StatePartIndex::new( - base.value + StatePartIndex { + value: base + .value .checked_add(next.stride.value.checked_mul(i).expect("array too big")) .expect("array too big"), - ), + _phantom: PhantomData, + }, rest, f, ); @@ -880,6 +1770,285 @@ impl StatePartArrayIndexed { } } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct StatePartIndex { + pub(crate) value: u32, + pub(crate) _phantom: PhantomData, +} + +impl StatePartIndex { + pub(crate) const ZERO: Self = Self { + value: 0, + _phantom: PhantomData, + }; + pub(crate) fn as_usize(self) -> usize { + self.value.try_into().expect("index too big") + } + pub(crate) fn offset(self, offset: StatePartIndex) -> Self { + Self { + value: self + .value + .checked_add(offset.value) + .expect("offset too big"), + _phantom: PhantomData, + } + } + pub(crate) fn debug_fmt( + &self, + f: &mut impl fmt::Write, + before_debug_info_text: &str, + comment_start: &str, + comment_line_start: &str, + comment_end: &str, + state_layout: Option<&StateLayout>, + state: Option<&State>, + ) -> fmt::Result { + write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?; + f.write_str(before_debug_info_text)?; + let debug_data = + state_layout.and_then(|state_layout| K::part_debug_data(state_layout, *self)); + if state.is_some() || debug_data.is_some() { + f.write_str(comment_start)?; + } + let mut f = PrefixLinesWrapper { + writer: f, + at_beginning_of_line: false, + blank_line_prefix: comment_line_start.trim_end(), + line_prefix: comment_line_start, + }; + if let Some(state) = state { + f.write_str("(")?; + K::debug_fmt_state_value(state, *self, &mut f)?; + f.write_str(")")?; + } + if state.is_some() && debug_data.is_some() { + f.write_str(" ")?; + } + if let Some(debug_data) = debug_data { + write!(f, "{debug_data:?}")?; + } + if state.is_some() || debug_data.is_some() { + f.writer.write_str(comment_end)?; + } + Ok(()) + } +} + +impl fmt::Debug for StatePartIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug_fmt::(f, "", "", "", "", None, None) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct StatePartLen { + pub(crate) value: u32, + pub(crate) _phantom: PhantomData, +} + +impl StatePartLen { + pub(crate) const fn new(value: u32) -> Self { + Self { + value, + _phantom: PhantomData, + } + } + pub(crate) const fn as_index(self) -> StatePartIndex { + StatePartIndex { + value: self.value, + _phantom: PhantomData, + } + } +} + +impl fmt::Debug for StatePartLen { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "StatePartLen<{}>({})", K::NAME, self.value) + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct StatePartLayout { + pub(crate) debug_data: BK::Vec, + pub(crate) layout_data: BK::Vec, + pub(crate) _phantom: PhantomData, +} + +impl Copy for StatePartLayout {} + +impl StatePartLayout { + pub(crate) fn len(&self) -> StatePartLen { + StatePartLen::new( + self.debug_data + .len() + .try_into() + .expect("state part allocation layout is too big"), + ) + } + pub(crate) fn is_empty(&self) -> bool { + self.debug_data.is_empty() + } + pub(crate) fn empty() -> Self { + Self { + debug_data: Default::default(), + layout_data: Default::default(), + _phantom: PhantomData, + } + } + pub(crate) fn debug_data(&self, index: StatePartIndex) -> &K::DebugData { + &self.debug_data[index.as_usize()] + } +} + +impl From> + for StatePartLayout +{ + fn from(value: StatePartLayout) -> Self { + Self { + debug_data: Intern::intern_owned(value.debug_data), + layout_data: Intern::intern_owned(value.layout_data), + _phantom: PhantomData, + } + } +} + +impl StatePartLayout { + pub(crate) fn scalar(debug_data: K::DebugData, layout_data: K::LayoutData) -> Self { + Self { + debug_data: vec![debug_data], + layout_data: vec![layout_data], + _phantom: PhantomData, + } + } + pub(crate) fn next_index(&self) -> StatePartIndex { + StatePartIndex { + value: self.len().value, + _phantom: PhantomData, + } + } + pub(crate) fn allocate( + &mut self, + layout: &StatePartLayout, + ) -> StatePartIndexRange { + let start = self.next_index(); + let len = layout.len(); + let Self { + debug_data, + layout_data, + _phantom: _, + } = self; + debug_data.extend_from_slice(&layout.debug_data); + layout_data.extend_from_slice(&layout.layout_data); + StatePartIndexRange { start, len } + } +} + +impl fmt::Debug for StatePartLayout { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + debug_data, + layout_data, + _phantom: _, + } = self; + write!(f, "StatePartLayout<{}>", K::NAME)?; + let mut debug_struct = f.debug_struct(""); + debug_struct + .field("len", &debug_data.len()) + .field("debug_data", debug_data); + if TypeId::of::() != TypeId::of::<()>() { + debug_struct.field("layout_data", layout_data); + } + debug_struct.finish_non_exhaustive() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) struct StatePartIndexRange { + pub(crate) start: StatePartIndex, + pub(crate) len: StatePartLen, +} + +impl StatePartIndexRange { + pub(crate) fn start(self) -> StatePartIndex { + self.start + } + pub(crate) fn end(self) -> StatePartIndex { + StatePartIndex { + value: self + .start + .value + .checked_add(self.len.value) + .expect("state part allocation layout is too big"), + _phantom: PhantomData, + } + } + pub(crate) fn len(self) -> StatePartLen { + self.len + } + pub(crate) fn is_empty(self) -> bool { + self.len.value == 0 + } + pub(crate) fn iter(self) -> impl Iterator> { + (self.start.value..self.end().value).map(|value| StatePartIndex { + value, + _phantom: PhantomData, + }) + } + pub(crate) fn offset(self, offset: StatePartIndex) -> Self { + self.end().offset(offset); // check for overflow + Self { + start: self.start.offset(offset), + len: self.len, + } + } + pub(crate) fn slice(self, index: StatePartIndexRange) -> Self { + assert!(index.end().value <= self.len.value, "index out of range"); + Self { + start: StatePartIndex { + value: self.start.value + index.start.value, + _phantom: PhantomData, + }, + len: index.len, + } + } + pub(crate) fn index_array(self, element_size: StatePartLen, index: usize) -> Self { + if element_size.value == 0 { + assert_eq!( + self.len.value, 0, + "array with zero-sized element must also be zero-sized", + ); + return self; + } + assert!( + self.len.value % element_size.value == 0, + "array's size must be a multiple of its element size", + ); + self.slice(StatePartIndexRange { + start: StatePartIndex { + value: index + .try_into() + .ok() + .and_then(|index| element_size.value.checked_mul(index)) + .expect("index out of range"), + _phantom: PhantomData, + }, + len: element_size, + }) + } +} + +impl fmt::Debug for StatePartIndexRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "StatePartIndexRange<{}> {{ start: {}, len: {} }}", + K::NAME, + self.start.value, + self.len.value + ) + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct StatePart { pub(crate) value: K::State, @@ -956,84 +2125,17 @@ impl<'a, K: StatePartKind: DerefMut { - pub(crate) struct State { - pub(crate) insns: Interned>, - pub(crate) pc: usize, - pub(crate) memory_write_log: Vec<(StatePartIndex, usize)>, - $(pub(crate) $state_plural_field: StatePart<$state_kind>,)* - $(pub(crate) $type_plural_field: StatePart<$type_kind>,)* - } - - impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - insns: _, - pc, - memory_write_log, - $($state_plural_field,)* - $($type_plural_field,)* - } = self; - f.debug_struct("State") - .field("insns", &InsnsOfState(self)) - .field("pc", pc) - .field("memory_write_log", memory_write_log) - $(.field(stringify!($state_plural_field), $state_plural_field))* - $(.field(stringify!($type_plural_field), $type_plural_field))* - .finish() - } - } - - impl State { - pub(crate) fn new(insns: Interned>) -> Self { - Self { - insns, - pc: 0, - memory_write_log: Vec::with_capacity(32), - $($state_plural_field: StatePart::new(&insns.state_layout.$state_plural_field.layout_data),)* - $($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)* - } - } - pub(crate) fn borrow(&mut self) -> BorrowedState<'_> { - BorrowedState { - orig_insns: self.insns, - insns: &self.insns.insns, - pc: self.pc, - orig_pc: &mut self.pc, - memory_write_log: &mut self.memory_write_log, - $($state_plural_field: self.$state_plural_field.borrow(),)* - $($type_plural_field: self.$type_plural_field.borrow(),)* - } - } - } - - #[derive(Debug)] - pub(crate) struct BorrowedState<'a> { - pub(crate) orig_insns: Interned>, - pub(crate) insns: &'a [Insn], - pub(crate) orig_pc: &'a mut usize, - pub(crate) pc: usize, - pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex, usize)>, - $(pub(crate) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)* - $(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)* - } - - impl Drop for BorrowedState<'_> { - fn drop(&mut self) { - *self.orig_pc = self.pc; - } - } - }; -} - -get_state_part_kinds! { - make_state! { - state_plural_fields; - state_kinds; +impl<'a, K: StatePartKind = BorrowedStack<'a, T>>, T: 'a> + BorrowedStatePart<'a, K> +{ + pub(crate) fn push(&mut self, value: T) { + self.value.push(value) + } + pub(crate) fn pop(&mut self) -> T + where + T: Default, + { + self.value.pop() } } @@ -1070,7 +2172,10 @@ impl StatePartIndexMap { self.map.get_mut(key.as_usize()) } pub(crate) fn keys(&self) -> impl Iterator> + '_ { - self.map.keys().map(|v| StatePartIndex::new(v as _)) + self.map.keys().map(|k| StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }) } pub(crate) fn values(&self) -> vec_map::Values<'_, V> { self.map.values() @@ -1079,14 +2184,26 @@ impl StatePartIndexMap { self.map.values_mut() } pub(crate) fn iter(&self) -> impl Iterator, &V)> + '_ { - self.map - .iter() - .map(|(k, v)| (StatePartIndex::new(k as u32), v)) + self.map.iter().map(|(k, v)| { + ( + StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }, + v, + ) + }) } pub(crate) fn iter_mut(&mut self) -> impl Iterator, &mut V)> + '_ { - self.map - .iter_mut() - .map(|(k, v)| (StatePartIndex::new(k as u32), v)) + self.map.iter_mut().map(|(k, v)| { + ( + StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }, + v, + ) + }) } pub(crate) fn len(&self) -> usize { self.map.len() @@ -1313,6 +2430,31 @@ impl BorrowedState<'_> { } } +impl TypeIndexRange { + #[must_use] + pub(crate) fn insns_for_copy_to(self, dest: TypeIndexRange) -> impl Iterator { + assert_eq!(self.len(), dest.len()); + let Self { + small_slots, + big_slots, + } = self; + small_slots + .iter() + .zip(dest.small_slots.iter()) + .map(|(src, dest)| Insn::CopySmall { dest, src }) + .chain( + big_slots + .iter() + .zip(dest.big_slots.iter()) + .map(|(src, dest)| Insn::Copy { dest, src }), + ) + } + #[must_use] + pub(crate) fn insns_for_copy_from(self, src: TypeIndexRange) -> impl Iterator { + src.insns_for_copy_to(self) + } +} + fn bigint_pow2(width: usize) -> Interned { #[derive(Copy, Clone, PartialEq, Eq, Hash)] struct MyMemoize; diff --git a/crates/fayalite/src/sim/interpreter/parts.rs b/crates/fayalite/src/sim/interpreter/parts.rs deleted file mode 100644 index 2decd53d..00000000 --- a/crates/fayalite/src/sim/interpreter/parts.rs +++ /dev/null @@ -1,1012 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - array::Array, - intern::{Intern, Interned}, - sim::interpreter::{ - Insn, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, PrefixLinesWrapper, SmallSInt, - SmallUInt, State, - }, - ty::CanonicalType, - util::{chain, const_str_cmp}, -}; -use bitvec::{boxed::BitBox, slice::BitSlice}; -use num_bigint::BigInt; -use std::{ - any::TypeId, - fmt::{self, Write}, - hash::Hash, - marker::PhantomData, - ops::Deref, -}; - -#[rustfmt::skip] -macro_rules! make_get_state_part_kinds { - ( - #![dollar = $d:tt] - $(state_part! { - singular_field = $state_singular_fields:ident; - plural_field = $state_plural_fields:ident; - kind = $state_kinds:ident; - singular_variant = $state_singular_variants:ident; - plural_variant = $state_plural_variants:ident; - })* - $(type_part! { - singular_field = $type_singular_fields:ident; - plural_field = $type_plural_fields:ident; - kind = $type_kinds:ident; - singular_variant = $type_singular_variants:ident; - plural_variant = $type_plural_variants:ident; - copy_insn = $copy_insn:ident; - read_indexed_insn = $read_indexed_insn:ident; - write_indexed_insn = $write_indexed_insn:ident; - array_indexed_variant = $array_indexed_variants:ident; - })* - ) => { - make_get_state_part_kinds! { - #![dollar = $d] - parts! { - #![part_names = [$(#[state] $state_singular_fields,)* $(#[type] $type_singular_fields,)*]] - [$(state_singular_fields = (#[state] $state_singular_fields),)* $(state_singular_fields = (#[type] $type_singular_fields),)*]; - [$(type_singular_fields = ($type_singular_fields),)*]; - [$(state_plural_fields = (#[state] $state_plural_fields),)* $(state_plural_fields = (#[type] $type_plural_fields),)*]; - [$(type_plural_fields = ($type_plural_fields),)*]; - [$(state_kinds = (#[state] $state_kinds),)* $(state_kinds = (#[type] $type_kinds),)*]; - [$(type_kinds = ($type_kinds),)*]; - [$(state_singular_variants = (#[state] $state_singular_variants),)* $(state_singular_variants = (#[type] $type_singular_variants),)*]; - [$(type_singular_variants = ($type_singular_variants),)*]; - [$(state_plural_variants = (#[state] $state_plural_variants),)* $(state_plural_variants = (#[type] $type_plural_variants),)*]; - [$(type_plural_variants = ($type_plural_variants),)*]; - [$(copy_insns = ($copy_insn),)*]; - [$(read_indexed_insns = ($read_indexed_insn),)*]; - [$(write_indexed_insns = ($write_indexed_insn),)*]; - [$(array_indexed_variants = ($array_indexed_variants),)*]; - } - } - }; - ( - #![dollar = $d:tt] - parts! { - #![part_names = [$(#[state] $state_part_name:ident,)* $(#[type] $type_part_name:ident,)*]] - $([ - $first_name:ident = ($($first_value:tt)*), - $($name:ident = ($($value:tt)*),)* - ];)* - } - ) => { - const _: () = { - $($(assert!(const_str_cmp(stringify!($first_name), stringify!($name)).is_eq());)*)* - }; - macro_rules! get_state_part_kinds { - ($d macro_ident:ident! {$d ($d args:tt)*}) => { - get_state_part_kinds! { - @expand - $d macro_ident! {} - ($d ($d args)*) - () - } - }; - ($d macro_ident:ident!($d ($d args:tt)*)) => { - get_state_part_kinds! { - @expand - $d macro_ident!() - ($d ($d args)*) - () - } - }; - ( - @expand - $d macro_ident:ident! {} - () - ($d ($d args:tt)*) - ) => { - $d macro_ident! { - $d ($d args)* - } - }; - ( - @expand - $d macro_ident:ident!() - () - ($d ($d args:tt)*) - ) => { - $d macro_ident!( - $d ($d args)* - ) - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (, $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)*,) - } - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (; $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)*;) - } - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (#[custom] $d name:ident = [ - $d ($($state_part_name = $d $state_part_name:tt,)*)? - $($type_part_name = $d $type_part_name:tt,)* - ] - $d ($d rest:tt)* - ) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)* $d name = [ - $d ($($d $state_part_name,)*)? - $($d $type_part_name,)* - ]) - } - }; - $(( - @expand - $d macro_ident:ident! $d group:tt - ($first_name $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)* $first_name = [$($first_value)*, $($($value)*,)*]) - } - };)* - } - - pub(crate) use get_state_part_kinds; - }; -} - -make_get_state_part_kinds! { - #![dollar = $] - state_part! { - singular_field = memory; - plural_field = memories; - kind = StatePartKindMemories; - singular_variant = Memory; - plural_variant = Memories; - } - type_part! { - singular_field = small_slot; - plural_field = small_slots; - kind = StatePartKindSmallSlots; - singular_variant = SmallSlot; - plural_variant = SmallSlots; - copy_insn = CopySmall; - read_indexed_insn = ReadSmallIndexed; - write_indexed_insn = WriteSmallIndexed; - array_indexed_variant = SmallSlotArrayIndexed; - } - type_part! { - singular_field = big_slot; - plural_field = big_slots; - kind = StatePartKindBigSlots; - singular_variant = BigSlot; - plural_variant = BigSlots; - copy_insn = Copy; - read_indexed_insn = ReadIndexed; - write_indexed_insn = WriteIndexed; - array_indexed_variant = BigSlotArrayIndexed; - } -} - -pub(crate) trait StatePartKind: - Send + Sync + Ord + Hash + fmt::Debug + 'static + Copy + Default -{ - const NAME: &'static str; - type DebugData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; - type LayoutData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; - type State: fmt::Debug + 'static + Clone; - type BorrowedState<'a>: 'a; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State; - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>; - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData>; - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result; -} - -macro_rules! make_state_part_kinds { - ( - state_kinds = [$(#[$kind_attr:ident] $kind:ident,)*]; - ) => { - $( - #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] - pub(crate) struct $kind; - )* - }; -} - -get_state_part_kinds! { - make_state_part_kinds! { - state_kinds; - } -} - -impl StatePartKind for StatePartKindMemories { - const NAME: &'static str = "Memories"; - type DebugData = (); - type LayoutData = MemoryData>; - type State = Box<[MemoryData]>; - type BorrowedState<'a> = &'a mut [MemoryData]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - layout_data - .iter() - .map(|MemoryData { array_type, data }| MemoryData { - array_type: *array_type, - data: BitBox::from_bitslice(data), - }) - .collect() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout.memories.debug_data.get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - write!(f, "{:#?}", &state.memories[index]) - } -} - -impl StatePartKind for StatePartKindSmallSlots { - const NAME: &'static str = "SmallSlots"; - type DebugData = SlotDebugData; - type LayoutData = (); - type State = Box<[SmallUInt]>; - type BorrowedState<'a> = &'a mut [SmallUInt]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - vec![0; layout_data.len()].into_boxed_slice() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout - .ty - .small_slots - .debug_data - .get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - let value = state.small_slots[index]; - write!(f, "{value:#x} {}", value as SmallSInt)?; - Ok(()) - } -} - -impl StatePartKind for StatePartKindBigSlots { - const NAME: &'static str = "BigSlots"; - type DebugData = SlotDebugData; - type LayoutData = (); - type State = Box<[BigInt]>; - type BorrowedState<'a> = &'a mut [BigInt]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - layout_data.iter().map(|_| BigInt::default()).collect() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout - .ty - .big_slots - .debug_data - .get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - write!(f, "{:#x}", state.big_slots[index]) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct StatePartIndex { - pub(crate) value: u32, - pub(crate) _phantom: PhantomData, -} - -impl StatePartIndex { - pub(crate) const ZERO: Self = Self::new(0); - pub(crate) const fn new(value: u32) -> Self { - Self { - value, - _phantom: PhantomData, - } - } - pub(crate) fn as_usize(self) -> usize { - self.value.try_into().expect("index too big") - } - pub(crate) fn offset(self, offset: StatePartIndex) -> Self { - Self::new( - self.value - .checked_add(offset.value) - .expect("offset too big"), - ) - } - pub(crate) fn debug_fmt( - &self, - f: &mut impl fmt::Write, - before_debug_info_text: &str, - comment_start: &str, - comment_line_start: &str, - comment_end: &str, - state_layout: Option<&StateLayout>, - state: Option<&State>, - ) -> fmt::Result { - write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?; - f.write_str(before_debug_info_text)?; - let debug_data = - state_layout.and_then(|state_layout| K::part_debug_data(state_layout, *self)); - if state.is_some() || debug_data.is_some() { - f.write_str(comment_start)?; - } - let mut f = PrefixLinesWrapper { - writer: f, - at_beginning_of_line: false, - blank_line_prefix: comment_line_start.trim_end(), - line_prefix: comment_line_start, - }; - if let Some(state) = state { - f.write_str("(")?; - K::debug_fmt_state_value(state, *self, &mut f)?; - f.write_str(")")?; - } - if state.is_some() && debug_data.is_some() { - f.write_str(" ")?; - } - if let Some(debug_data) = debug_data { - write!(f, "{debug_data:?}")?; - } - if state.is_some() || debug_data.is_some() { - f.writer.write_str(comment_end)?; - } - Ok(()) - } -} - -impl fmt::Debug for StatePartIndex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt::(f, "", "", "", "", None, None) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub(crate) struct StatePartIndexRange { - pub(crate) start: StatePartIndex, - pub(crate) len: StatePartLen, -} - -impl StatePartIndexRange { - pub(crate) fn start(self) -> StatePartIndex { - self.start - } - pub(crate) fn end(self) -> StatePartIndex { - StatePartIndex::new( - self.start - .value - .checked_add(self.len.value) - .expect("state part allocation layout is too big"), - ) - } - pub(crate) fn len(self) -> StatePartLen { - self.len - } - pub(crate) fn is_empty(self) -> bool { - self.len.value == 0 - } - pub(crate) fn iter(self) -> impl Iterator> { - (self.start.value..self.end().value).map(StatePartIndex::new) - } - pub(crate) fn offset(self, offset: StatePartIndex) -> Self { - self.end().offset(offset); // check for overflow - Self { - start: self.start.offset(offset), - len: self.len, - } - } - pub(crate) fn slice(self, index: StatePartIndexRange) -> Self { - assert!(index.end().value <= self.len.value, "index out of range"); - Self { - start: StatePartIndex::new(self.start.value + index.start.value), - len: index.len, - } - } - pub(crate) fn index_array(self, element_size: StatePartLen, index: usize) -> Self { - if element_size.value == 0 { - assert_eq!( - self.len.value, 0, - "array with zero-sized element must also be zero-sized", - ); - return self; - } - assert!( - self.len.value % element_size.value == 0, - "array's size must be a multiple of its element size", - ); - self.slice(StatePartIndexRange { - start: StatePartIndex::new( - index - .try_into() - .ok() - .and_then(|index| element_size.value.checked_mul(index)) - .expect("index out of range"), - ), - len: element_size, - }) - } -} - -impl fmt::Debug for StatePartIndexRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "StatePartIndexRange<{}> {{ start: {}, len: {} }}", - K::NAME, - self.start.value, - self.len.value - ) - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub(crate) struct MemoryData> { - pub(crate) array_type: Array, - pub(crate) data: T, -} - -impl> fmt::Debug for MemoryData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { array_type, data } = self; - f.debug_struct("MemoryData") - .field("array_type", array_type) - .field( - "data", - &crate::memory::DebugMemoryData::from_bit_slice(*array_type, data), - ) - .finish() - } -} - -macro_rules! make_state_layout { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - ) => { - #[derive(Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateLayout { - pub(crate) ty: TypeLayout, - $(pub(crate) $state_plural_field: StatePartLayout<$state_kind, BK>,)* - } - - impl Copy for StateLayout {} - - impl StateLayout { - pub(crate) fn len(&self) -> StateLen { - StateLen { - ty: self.ty.len(), - $($state_plural_field: self.$state_plural_field.len(),)* - } - } - pub(crate) fn is_empty(&self) -> bool { - self.ty.is_empty() $(&& self.$state_plural_field.is_empty())* - } - pub(crate) fn empty() -> Self { - Self { - ty: TypeLayout::empty(), - $($state_plural_field: StatePartLayout::empty(),)* - } - } - } - - impl StateLayout { - pub(crate) fn next_index(&self) -> StateIndex { - StateIndex { - ty: self.ty.next_index(), - $($state_plural_field: self.$state_plural_field.next_index(),)* - } - } - pub(crate) fn allocate( - &mut self, - layout: &StateLayout, - ) -> StateIndexRange { - StateIndexRange { - ty: self.ty.allocate(&layout.ty), - $($state_plural_field: self.$state_plural_field.allocate(&layout.$state_plural_field),)* - } - } - } - - impl From> for StateLayout { - fn from(v: StateLayout) -> Self { - Self { - ty: v.ty.into(), - $($state_plural_field: v.$state_plural_field.into(),)* - } - } - } - - #[derive(Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeLayout { - $(pub(crate) $type_plural_field: StatePartLayout<$type_kind, BK>,)* - } - - impl Copy for TypeLayout {} - - impl TypeLayout { - pub(crate) fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.len(),)* - } - } - pub(crate) fn is_empty(&self) -> bool { - $(self.$type_plural_field.is_empty())&&+ - } - pub(crate) fn empty() -> Self { - Self { - $($type_plural_field: StatePartLayout::empty(),)* - } - } - } - - impl TypeLayout { - pub(crate) fn next_index(&self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.next_index(),)* - } - } - pub(crate) fn allocate( - &mut self, - layout: &TypeLayout, - ) -> TypeIndexRange { - TypeIndexRange { - $($type_plural_field: self.$type_plural_field.allocate(&layout.$type_plural_field),)* - } - } - } - - impl From> for TypeLayout { - fn from(v: TypeLayout) -> Self { - Self { - $($type_plural_field: v.$type_plural_field.into(),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_state_layout! { - state_plural_fields; - state_kinds; - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub(crate) struct StatePartLayout { - pub(crate) debug_data: BK::Vec, - pub(crate) layout_data: BK::Vec, - pub(crate) _phantom: PhantomData, -} - -impl Copy for StatePartLayout {} - -impl StatePartLayout { - pub(crate) fn len(&self) -> StatePartLen { - StatePartLen::new( - self.debug_data - .len() - .try_into() - .expect("state part allocation layout is too big"), - ) - } - pub(crate) fn is_empty(&self) -> bool { - self.debug_data.is_empty() - } - pub(crate) fn empty() -> Self { - Self { - debug_data: Default::default(), - layout_data: Default::default(), - _phantom: PhantomData, - } - } - pub(crate) fn debug_data(&self, index: StatePartIndex) -> &K::DebugData { - &self.debug_data[index.as_usize()] - } -} - -impl From> - for StatePartLayout -{ - fn from(value: StatePartLayout) -> Self { - Self { - debug_data: Intern::intern_owned(value.debug_data), - layout_data: Intern::intern_owned(value.layout_data), - _phantom: PhantomData, - } - } -} - -impl StatePartLayout { - pub(crate) fn scalar(debug_data: K::DebugData, layout_data: K::LayoutData) -> Self { - Self { - debug_data: vec![debug_data], - layout_data: vec![layout_data], - _phantom: PhantomData, - } - } - pub(crate) fn next_index(&self) -> StatePartIndex { - StatePartIndex::new(self.len().value) - } - pub(crate) fn allocate( - &mut self, - layout: &StatePartLayout, - ) -> StatePartIndexRange { - let start = self.next_index(); - let len = layout.len(); - let Self { - debug_data, - layout_data, - _phantom: _, - } = self; - debug_data.extend_from_slice(&layout.debug_data); - layout_data.extend_from_slice(&layout.layout_data); - StatePartIndexRange { start, len } - } -} - -impl fmt::Debug for StatePartLayout { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - debug_data, - layout_data, - _phantom: _, - } = self; - write!(f, "StatePartLayout<{}>", K::NAME)?; - let mut debug_struct = f.debug_struct(""); - debug_struct - .field("len", &debug_data.len()) - .field("debug_data", debug_data); - if TypeId::of::() != TypeId::of::<()>() { - debug_struct.field("layout_data", layout_data); - } - debug_struct.finish_non_exhaustive() - } -} - -impl, BK: InsnsBuildingKind> StatePartLayout { - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - Self { - debug_data: self - .debug_data - .iter() - .map(|v| v.with_prefixed_debug_names(prefix)) - .collect(), - layout_data: self.layout_data.clone(), - _phantom: PhantomData, - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - debug_data: self - .debug_data - .iter() - .map(|v| v.with_anonymized_debug_info()) - .collect(), - layout_data: self.layout_data.clone(), - _phantom: PhantomData, - } - } -} - -impl TypeLayout { - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - Self { - small_slots: self.small_slots.with_prefixed_debug_names(prefix), - big_slots: self.big_slots.with_prefixed_debug_names(prefix), - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - small_slots: self.small_slots.with_anonymized_debug_info(), - big_slots: self.big_slots.with_anonymized_debug_info(), - } - } -} - -macro_rules! make_state_len { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_singular_fields = [$($type_singular_field:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateLen { - pub(crate) ty: TypeLen, - $(pub(crate) $state_plural_field: StatePartLen<$state_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeLen { - $(pub(crate) $type_plural_field: StatePartLen<$type_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) enum TypeLenSingle { - $($type_singular_variant,)* - } - - impl TypeLen { - pub(crate) const fn as_index(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.as_index(),)* - } - } - pub(crate) const fn empty() -> Self { - Self { - $($type_plural_field: StatePartLen::new(0),)* - } - } - $(pub(crate) const fn $type_singular_field() -> Self { - let mut retval = Self::empty(); - retval.$type_plural_field.value = 1; - retval - })* - pub(crate) const fn as_single(self) -> Option { - $({ - const SINGLE: TypeLen = TypeLen::$type_singular_field(); - if let SINGLE = self { - return Some(TypeLenSingle::$type_singular_variant); - } - })* - None - } - pub(crate) const fn only_small(mut self) -> Option> { - const EMPTY: TypeLen = TypeLen::empty(); - let retval = self.small_slots; - self.small_slots.value = 0; - if let EMPTY = self { - Some(retval) - } else { - None - } - } - } - }; -} - -get_state_part_kinds! { - make_state_len! { - state_plural_fields; - state_kinds; - type_singular_variants; - type_singular_fields; - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct StatePartLen { - pub(crate) value: u32, - pub(crate) _phantom: PhantomData, -} - -impl StatePartLen { - pub(crate) const fn new(value: u32) -> Self { - Self { - value, - _phantom: PhantomData, - } - } - pub(crate) const fn as_index(self) -> StatePartIndex { - StatePartIndex::new(self.value) - } -} - -impl fmt::Debug for StatePartLen { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "StatePartLen<{}>({})", K::NAME, self.value) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub(crate) struct SlotDebugData { - pub(crate) name: Interned, - pub(crate) ty: CanonicalType, -} - -impl SlotDebugData { - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - let mut name = String::with_capacity(self.name.len() + prefix.len()); - name.push_str(prefix); - name.push_str(&self.name); - Self { - name: Intern::intern_owned(name), - ty: self.ty, - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - name: Interned::default(), - ty: self.ty, - } - } -} - -macro_rules! make_state_index { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateIndex { - pub(crate) ty: TypeIndex, - $(pub(crate) $state_plural_field: StatePartIndex<$state_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeIndex { - $(pub(crate) $type_plural_field: StatePartIndex<$type_kind>,)* - } - - impl TypeIndex { - pub(crate) const ZERO: Self = Self { - $($type_plural_field: StatePartIndex::ZERO,)* - }; - pub(crate) fn offset(self, offset: TypeIndex) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.offset(offset.$type_plural_field),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_state_index! { - state_plural_fields; - state_kinds; - } -} - -macro_rules! make_state_index_range { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - copy_insns = [$($copy_insn:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateIndexRange { - pub(crate) ty: TypeIndexRange, - $(pub(crate) $state_plural_field: StatePartIndexRange<$state_kind>,)* - } - - impl StateIndexRange { - pub(crate) fn start(self) -> StateIndex { - StateIndex { - ty: self.ty.start(), - $($state_plural_field: self.$state_plural_field.start(),)* - } - } - pub(crate) fn len(self) -> StateLen { - StateLen { - ty: self.ty.len(), - $($state_plural_field: self.$state_plural_field.len(),)* - } - } - pub(crate) fn is_empty(self) -> bool { - self.ty.is_empty() $(&& self.$state_plural_field.is_empty())* - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeIndexRange { - $(pub(crate) $type_plural_field: StatePartIndexRange<$type_kind>,)* - } - - impl TypeIndexRange { - pub(crate) fn new(start: TypeIndex, len: TypeLen) -> Self { - Self { - $($type_plural_field: StatePartIndexRange { - start: start.$type_plural_field, - len: len.$type_plural_field, - },)* - } - } - pub(crate) fn start(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.start(),)* - } - } - pub(crate) fn len(self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.len(),)* - } - } - pub(crate) fn is_empty(self) -> bool { - $(self.$type_plural_field.is_empty()) &&+ - } - pub(crate) fn slice(self, index: TypeIndexRange) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.slice(index.$type_plural_field),)* - } - } - pub(crate) fn index_array(self, element_size: TypeLen, index: usize) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.index_array(element_size.$type_plural_field, index),)* - } - } - pub(crate) fn offset(self, offset: TypeIndex) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.offset(offset.$type_plural_field),)* - } - } - #[must_use] - pub(crate) fn insns_for_copy_to(self, dest: TypeIndexRange) -> impl Iterator { - assert_eq!(self.len(), dest.len()); - chain!($(self.$type_plural_field.iter().zip(dest.$type_plural_field.iter()).map(|(src, dest)| Insn::$copy_insn { dest, src })),*) - } - #[must_use] - pub(crate) fn insns_for_copy_from(self, src: TypeIndexRange) -> impl Iterator { - src.insns_for_copy_to(self) - } - } - }; -} - -get_state_part_kinds! { - make_state_index_range! { - state_plural_fields; - state_kinds; - copy_insns; - } -} diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index e85bc9c1..f3d2c7c3 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -33,7 +33,6 @@ pub use const_cmp::{ #[doc(inline)] pub use scoped_ref::ScopedRef; -pub(crate) use misc::chain; #[doc(inline)] pub use misc::{ BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, diff --git a/crates/fayalite/src/util/misc.rs b/crates/fayalite/src/util/misc.rs index cebbceb5..d70605bf 100644 --- a/crates/fayalite/src/util/misc.rs +++ b/crates/fayalite/src/util/misc.rs @@ -211,21 +211,6 @@ impl std::io::Write for RcWriter { } } -macro_rules! chain { - () => { - std::iter::empty() - }; - ($first:expr $(, $rest:expr)* $(,)?) => { - { - let retval = IntoIterator::into_iter($first); - $(let retval = Iterator::chain(retval, $rest);)* - retval - } - }; -} - -pub(crate) use chain; - pub fn try_slice_range>(range: R, size: usize) -> Option> { let start = match range.start_bound() { Bound::Included(start) => *start,