Compare commits
No commits in common. "6b31e6d515e6e30c44d56bd5432a3e3e50042f39" and "e4cf66adf8e50cfe0b2d5ac95ba220878aa295ba" have entirely different histories.
6b31e6d515
...
e4cf66adf8
6 changed files with 45 additions and 559 deletions
|
|
@ -42,12 +42,8 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::{Signed, ToPrimitive, Zero};
|
use num_traits::{Signed, ToPrimitive, Zero};
|
||||||
use petgraph::{
|
use petgraph::visit::{
|
||||||
data::FromElements,
|
GraphBase, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, VisitMap, Visitable,
|
||||||
visit::{
|
|
||||||
EdgeRef, GraphBase, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected,
|
|
||||||
IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut};
|
use std::{borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut};
|
||||||
|
|
||||||
|
|
@ -388,8 +384,8 @@ impl CompiledExpr<Array> {
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
enum AssignmentOrSlotIndex {
|
enum AssignmentOrSlotIndex {
|
||||||
AssignmentIndex(usize),
|
AssignmentIndex(usize),
|
||||||
SmallSlot(StatePartIndex<StatePartKindSmallSlots>),
|
SmallSlots(StatePartIndex<StatePartKindSmallSlots>),
|
||||||
BigSlot(StatePartIndex<StatePartKindBigSlots>),
|
BigSlots(StatePartIndex<StatePartKindBigSlots>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -412,15 +408,6 @@ enum AssignmentIO {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
enum AssignmentsEdge {
|
|
||||||
IO(AssignmentIO),
|
|
||||||
AssignmentImmediatePredecessor {
|
|
||||||
predecessor_assignment_index: usize,
|
|
||||||
assignment_index: usize,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Assignments {
|
enum Assignments {
|
||||||
Accumulating {
|
Accumulating {
|
||||||
|
|
@ -428,7 +415,6 @@ enum Assignments {
|
||||||
},
|
},
|
||||||
Finalized {
|
Finalized {
|
||||||
assignments: Box<[Assignment]>,
|
assignments: Box<[Assignment]>,
|
||||||
slots_layout: TypeLayout<InsnsBuildingDone>,
|
|
||||||
slot_readers: SlotToAssignmentIndexFullMap,
|
slot_readers: SlotToAssignmentIndexFullMap,
|
||||||
slot_writers: SlotToAssignmentIndexFullMap,
|
slot_writers: SlotToAssignmentIndexFullMap,
|
||||||
assignment_immediate_predecessors: Box<[Box<[usize]>]>,
|
assignment_immediate_predecessors: Box<[Box<[usize]>]>,
|
||||||
|
|
@ -445,13 +431,13 @@ impl Default for Assignments {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Assignments {
|
impl Assignments {
|
||||||
fn finalize(&mut self, slots_layout: TypeLayout<InsnsBuildingDone>) {
|
fn finalize(&mut self, slots_len: TypeLen) {
|
||||||
let Self::Accumulating { assignments } = self else {
|
let Self::Accumulating { assignments } = self else {
|
||||||
unreachable!("already finalized");
|
unreachable!("already finalized");
|
||||||
};
|
};
|
||||||
let assignments = mem::take(assignments).into_boxed_slice();
|
let assignments = mem::take(assignments).into_boxed_slice();
|
||||||
let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len());
|
let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_len);
|
||||||
let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len());
|
let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_len);
|
||||||
let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()];
|
let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()];
|
||||||
let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()];
|
let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()];
|
||||||
for (assignment_index, assignment) in assignments.iter().enumerate() {
|
for (assignment_index, assignment) in assignments.iter().enumerate() {
|
||||||
|
|
@ -479,7 +465,6 @@ impl Assignments {
|
||||||
}
|
}
|
||||||
*self = Self::Finalized {
|
*self = Self::Finalized {
|
||||||
assignments,
|
assignments,
|
||||||
slots_layout,
|
|
||||||
slot_readers,
|
slot_readers,
|
||||||
slot_writers,
|
slot_writers,
|
||||||
assignment_immediate_predecessors: assignment_immediate_predecessors
|
assignment_immediate_predecessors: assignment_immediate_predecessors
|
||||||
|
|
@ -504,12 +489,6 @@ impl Assignments {
|
||||||
};
|
};
|
||||||
assignments
|
assignments
|
||||||
}
|
}
|
||||||
fn slots_layout(&self) -> TypeLayout<InsnsBuildingDone> {
|
|
||||||
let Self::Finalized { slots_layout, .. } = self else {
|
|
||||||
unreachable!("Assignments::finalize should have been called");
|
|
||||||
};
|
|
||||||
*slots_layout
|
|
||||||
}
|
|
||||||
fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap {
|
fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap {
|
||||||
let Self::Finalized { slot_readers, .. } = self else {
|
let Self::Finalized { slot_readers, .. } = self else {
|
||||||
unreachable!("Assignments::finalize should have been called");
|
unreachable!("Assignments::finalize should have been called");
|
||||||
|
|
@ -542,131 +521,46 @@ impl Assignments {
|
||||||
};
|
};
|
||||||
assignment_immediate_successors
|
assignment_immediate_successors
|
||||||
}
|
}
|
||||||
fn elements(&self) -> AssignmentsElements<'_> {
|
|
||||||
let SlotToAssignmentIndexFullMap(TypeParts {
|
|
||||||
small_slots,
|
|
||||||
big_slots,
|
|
||||||
}) = self.slot_readers();
|
|
||||||
AssignmentsElements {
|
|
||||||
node_indexes: HashMap::with_capacity(
|
|
||||||
self.assignments().len() + small_slots.len() + big_slots.len(),
|
|
||||||
),
|
|
||||||
nodes: self.node_references(),
|
|
||||||
edges: self.edge_references(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphBase for Assignments {
|
impl GraphBase for Assignments {
|
||||||
type EdgeId = AssignmentsEdge;
|
type EdgeId = AssignmentIO;
|
||||||
type NodeId = AssignmentOrSlotIndex;
|
type NodeId = AssignmentOrSlotIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum AssignmentsNodeRef<'a> {
|
|
||||||
Assignment {
|
|
||||||
index: usize,
|
|
||||||
assignment: &'a Assignment,
|
|
||||||
},
|
|
||||||
SmallSlot(StatePartIndex<StatePartKindSmallSlots>, SlotDebugData),
|
|
||||||
BigSlot(StatePartIndex<StatePartKindBigSlots>, 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<AssignmentOrSlotIndex, usize>,
|
|
||||||
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<Self::Item> {
|
|
||||||
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 {
|
struct AssignmentsNodeIdentifiers {
|
||||||
assignment_indexes: std::ops::Range<usize>,
|
assignment_indexes: std::ops::Range<usize>,
|
||||||
small_slots: std::ops::Range<u32>,
|
small_slots: std::ops::Range<u32>,
|
||||||
big_slots: std::ops::Range<u32>,
|
big_slots: std::ops::Range<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssignmentsNodeIdentifiers {
|
impl Iterator for AssignmentsNodeIdentifiers {
|
||||||
fn internal_iter<'a>(&'a mut self) -> impl Iterator<Item = AssignmentOrSlotIndex> + 'a {
|
type Item = AssignmentOrSlotIndex;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let Self {
|
let Self {
|
||||||
assignment_indexes,
|
assignment_indexes,
|
||||||
small_slots,
|
small_slots,
|
||||||
big_slots,
|
big_slots,
|
||||||
} = self;
|
} = self;
|
||||||
assignment_indexes
|
assignment_indexes
|
||||||
|
.next()
|
||||||
.map(AssignmentOrSlotIndex::AssignmentIndex)
|
.map(AssignmentOrSlotIndex::AssignmentIndex)
|
||||||
.chain(small_slots.map(|value| {
|
.or_else(|| {
|
||||||
AssignmentOrSlotIndex::SmallSlot(StatePartIndex {
|
small_slots.next().map(|value| {
|
||||||
value,
|
AssignmentOrSlotIndex::SmallSlots(StatePartIndex {
|
||||||
_phantom: PhantomData,
|
value,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}))
|
})
|
||||||
.chain(big_slots.map(|value| {
|
.or_else(|| {
|
||||||
AssignmentOrSlotIndex::BigSlot(StatePartIndex {
|
big_slots.next().map(|value| {
|
||||||
value,
|
AssignmentOrSlotIndex::BigSlots(StatePartIndex {
|
||||||
_phantom: PhantomData,
|
value,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}))
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for AssignmentsNodeIdentifiers {
|
|
||||||
type Item = AssignmentOrSlotIndex;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.internal_iter().next()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
|
||||||
self.internal_iter().nth(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -686,44 +580,6 @@ impl<'a> IntoNodeIdentifiers for &'a Assignments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssignmentsNodes<'a> {
|
|
||||||
assignments: &'a Assignments,
|
|
||||||
nodes: AssignmentsNodeIdentifiers,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for AssignmentsNodes<'a> {
|
|
||||||
type Item = AssignmentsNodeRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
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> {
|
struct AssignmentsNeighborsDirected<'a> {
|
||||||
assignment_indexes: std::slice::Iter<'a, usize>,
|
assignment_indexes: std::slice::Iter<'a, usize>,
|
||||||
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
|
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
|
||||||
|
|
@ -747,13 +603,13 @@ impl Iterator for AssignmentsNeighborsDirected<'_> {
|
||||||
} else if let retval @ Some(_) = small_slots
|
} else if let retval @ Some(_) = small_slots
|
||||||
.next()
|
.next()
|
||||||
.copied()
|
.copied()
|
||||||
.map(AssignmentOrSlotIndex::SmallSlot)
|
.map(AssignmentOrSlotIndex::SmallSlots)
|
||||||
{
|
{
|
||||||
retval
|
retval
|
||||||
} else if let retval @ Some(_) = big_slots
|
} else if let retval @ Some(_) = big_slots
|
||||||
.next()
|
.next()
|
||||||
.copied()
|
.copied()
|
||||||
.map(AssignmentOrSlotIndex::BigSlot)
|
.map(AssignmentOrSlotIndex::BigSlots)
|
||||||
{
|
{
|
||||||
retval
|
retval
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -808,12 +664,12 @@ impl<'a> IntoNeighborsDirected for &'a Assignments {
|
||||||
big_slots: big_slots.iter(),
|
big_slots: big_slots.iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNeighborsDirected {
|
AssignmentOrSlotIndex::SmallSlots(slot) => AssignmentsNeighborsDirected {
|
||||||
assignment_indexes: slot_map[slot].iter(),
|
assignment_indexes: slot_map[slot].iter(),
|
||||||
small_slots: Default::default(),
|
small_slots: Default::default(),
|
||||||
big_slots: Default::default(),
|
big_slots: Default::default(),
|
||||||
},
|
},
|
||||||
AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNeighborsDirected {
|
AssignmentOrSlotIndex::BigSlots(slot) => AssignmentsNeighborsDirected {
|
||||||
assignment_indexes: slot_map[slot].iter(),
|
assignment_indexes: slot_map[slot].iter(),
|
||||||
small_slots: Default::default(),
|
small_slots: Default::default(),
|
||||||
big_slots: Default::default(),
|
big_slots: Default::default(),
|
||||||
|
|
@ -822,149 +678,6 @@ impl<'a> IntoNeighborsDirected for &'a Assignments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Self::Item> {
|
|
||||||
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<'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 {
|
struct AssignmentsVisitMap {
|
||||||
assignments: Vec<bool>,
|
assignments: Vec<bool>,
|
||||||
slots: DenseSlotSet,
|
slots: DenseSlotSet,
|
||||||
|
|
@ -976,8 +689,8 @@ impl VisitMap<AssignmentOrSlotIndex> for AssignmentsVisitMap {
|
||||||
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
|
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
|
||||||
!mem::replace(&mut self.assignments[assignment_index], true)
|
!mem::replace(&mut self.assignments[assignment_index], true)
|
||||||
}
|
}
|
||||||
AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.insert(slot),
|
AssignmentOrSlotIndex::SmallSlots(slot) => self.slots.insert(slot),
|
||||||
AssignmentOrSlotIndex::BigSlot(slot) => self.slots.insert(slot),
|
AssignmentOrSlotIndex::BigSlots(slot) => self.slots.insert(slot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -986,8 +699,8 @@ impl VisitMap<AssignmentOrSlotIndex> for AssignmentsVisitMap {
|
||||||
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
|
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
|
||||||
self.assignments[assignment_index]
|
self.assignments[assignment_index]
|
||||||
}
|
}
|
||||||
AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.contains(slot),
|
AssignmentOrSlotIndex::SmallSlots(slot) => self.slots.contains(slot),
|
||||||
AssignmentOrSlotIndex::BigSlot(slot) => self.slots.contains(slot),
|
AssignmentOrSlotIndex::BigSlots(slot) => self.slots.contains(slot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3012,15 +2725,12 @@ impl Compiler {
|
||||||
.compile_expr(instantiated_module, Expr::canonical(expr.base()))
|
.compile_expr(instantiated_module, Expr::canonical(expr.base()))
|
||||||
.map_ty(Bundle::from_canonical)
|
.map_ty(Bundle::from_canonical)
|
||||||
.field_by_index(expr.field_index()),
|
.field_by_index(expr.field_index()),
|
||||||
ExprEnum::VariantAccess(variant_access) => {
|
ExprEnum::VariantAccess(variant_access) => self.compile_expr(
|
||||||
let start = Expr::ty(variant_access.base()).discriminant_bit_width();
|
instantiated_module,
|
||||||
let len = Expr::ty(expr).bit_width();
|
variant_access.base().cast_to_bits()
|
||||||
self.compile_expr(
|
[Expr::ty(variant_access.base()).discriminant_bit_width()..]
|
||||||
instantiated_module,
|
.cast_bits_to(Expr::ty(expr)),
|
||||||
variant_access.base().cast_to_bits()[start..start + len]
|
),
|
||||||
.cast_bits_to(Expr::ty(expr)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExprEnum::ArrayIndex(expr) => self
|
ExprEnum::ArrayIndex(expr) => self
|
||||||
.compile_expr(instantiated_module, Expr::canonical(expr.base()))
|
.compile_expr(instantiated_module, Expr::canonical(expr.base()))
|
||||||
.map_ty(Array::from_canonical)
|
.map_ty(Array::from_canonical)
|
||||||
|
|
@ -4436,13 +4146,7 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
fn process_assignments(&mut self) {
|
fn process_assignments(&mut self) {
|
||||||
self.assignments
|
self.assignments
|
||||||
.finalize(self.insns.state_layout().ty.clone().into());
|
.finalize(self.insns.state_layout().len().ty);
|
||||||
println!(
|
|
||||||
"{:#?}",
|
|
||||||
petgraph::dot::Dot::new(&petgraph::graph::DiGraph::<_, _, usize>::from_elements(
|
|
||||||
self.assignments.elements()
|
|
||||||
))
|
|
||||||
);
|
|
||||||
let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) {
|
let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) {
|
||||||
Ok(nodes) => nodes
|
Ok(nodes) => nodes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -4456,11 +4160,11 @@ impl Compiler {
|
||||||
"combinatorial logic cycle detected at: {}",
|
"combinatorial logic cycle detected at: {}",
|
||||||
self.assignments.assignments()[assignment_index].source_location,
|
self.assignments.assignments()[assignment_index].source_location,
|
||||||
),
|
),
|
||||||
AssignmentOrSlotIndex::SmallSlot(slot) => panic!(
|
AssignmentOrSlotIndex::SmallSlots(slot) => panic!(
|
||||||
"combinatorial logic cycle detected through: {}",
|
"combinatorial logic cycle detected through: {}",
|
||||||
self.insns.state_layout().ty.small_slots.debug_data[slot.as_usize()].name,
|
self.insns.state_layout().ty.small_slots.debug_data[slot.as_usize()].name,
|
||||||
),
|
),
|
||||||
AssignmentOrSlotIndex::BigSlot(slot) => panic!(
|
AssignmentOrSlotIndex::BigSlots(slot) => panic!(
|
||||||
"combinatorial logic cycle detected through: {}",
|
"combinatorial logic cycle detected through: {}",
|
||||||
self.insns.state_layout().ty.big_slots.debug_data[slot.as_usize()].name,
|
self.insns.state_layout().ty.big_slots.debug_data[slot.as_usize()].name,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1652,9 +1652,6 @@ impl<K: StatePartKind, BK: InsnsBuildingKind> StatePartLayout<K, BK> {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn debug_data(&self, index: StatePartIndex<K>) -> &K::DebugData {
|
|
||||||
&self.debug_data[index.as_usize()]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: StatePartKind> From<StatePartLayout<K, InsnsBuilding>>
|
impl<K: StatePartKind> From<StatePartLayout<K, InsnsBuilding>>
|
||||||
|
|
|
||||||
|
|
@ -235,17 +235,6 @@ fn write_escaped<W: io::Write>(writer: &mut W, value: impl Display) -> io::Resul
|
||||||
write!(Wrapper(writer), "{value}")
|
write!(Wrapper(writer), "{value}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_unescaped_verilog_identifier(ident: &str) -> bool {
|
|
||||||
// we only allow ascii, so we can just check bytes
|
|
||||||
let Some((&first, rest)) = ident.as_bytes().split_first() else {
|
|
||||||
return false; // empty string is not an identifier
|
|
||||||
};
|
|
||||||
(first.is_ascii_alphabetic() || first == b'_')
|
|
||||||
&& rest
|
|
||||||
.iter()
|
|
||||||
.all(|&ch| ch.is_ascii_alphanumeric() || ch == b'_' || ch == b'$')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_vcd_var<W: io::Write>(
|
fn write_vcd_var<W: io::Write>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
var_type: &str,
|
var_type: &str,
|
||||||
|
|
@ -255,12 +244,7 @@ fn write_vcd_var<W: io::Write>(
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
write!(writer, "$var {var_type} {size} ")?;
|
write!(writer, "$var {var_type} {size} ")?;
|
||||||
write_scalar_id(writer, id)?;
|
write_scalar_id(writer, id)?;
|
||||||
writer.write_all(b" ")?;
|
writeln!(writer, " {name} $end")
|
||||||
if !is_unescaped_verilog_identifier(name) {
|
|
||||||
writer.write_all(b"\\")?;
|
|
||||||
}
|
|
||||||
write_escaped(writer, name)?;
|
|
||||||
writer.write_all(b" $end\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteTrace for TraceUInt {
|
impl WriteTrace for TraceUInt {
|
||||||
|
|
|
||||||
|
|
@ -293,204 +293,5 @@ fn test_shift_register() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl_module(outline_generated)]
|
// TODO: add tests for enums
|
||||||
pub fn enums() {
|
|
||||||
#[hdl]
|
|
||||||
let cd: ClockDomain<SyncReset> = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let en: Bool = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let which_in: UInt<2> = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let data_in: UInt<4> = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let which_out: UInt<2> = m.output();
|
|
||||||
#[hdl]
|
|
||||||
let data_out: UInt<4> = m.output();
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
struct MyStruct<T> {
|
|
||||||
a: T,
|
|
||||||
b: SInt<2>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
enum MyEnum {
|
|
||||||
A,
|
|
||||||
B((UInt<1>, Bool)),
|
|
||||||
C(MyStruct<Array<UInt<1>, 2>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
let the_reg = reg_builder().clock_domain(cd).reset(MyEnum.A());
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
if en {
|
|
||||||
#[hdl]
|
|
||||||
if which_in.cmp_eq(0_hdl_u2) {
|
|
||||||
connect(the_reg, MyEnum.A());
|
|
||||||
} else if which_in.cmp_eq(1_hdl_u2) {
|
|
||||||
connect(the_reg, MyEnum.B((data_in[0].cast_to_static(), data_in[1])));
|
|
||||||
} else {
|
|
||||||
connect(
|
|
||||||
the_reg,
|
|
||||||
MyEnum.C(
|
|
||||||
#[hdl]
|
|
||||||
MyStruct {
|
|
||||||
a: #[hdl]
|
|
||||||
[data_in[0].cast_to_static(), data_in[1].cast_to_static()],
|
|
||||||
b: data_in[2..4].cast_to_static(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
match the_reg {
|
|
||||||
MyEnum::A => {
|
|
||||||
connect(which_out, 0_hdl_u2);
|
|
||||||
connect(data_out, 0_hdl_u4);
|
|
||||||
}
|
|
||||||
MyEnum::B(v) => {
|
|
||||||
connect(which_out, 1_hdl_u2);
|
|
||||||
connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1));
|
|
||||||
}
|
|
||||||
MyEnum::C(v) => {
|
|
||||||
connect(which_out, 2_hdl_u2);
|
|
||||||
connect_any(data_out, v.cast_to_bits());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(todo)] // FIXME: enum lowering currently broken
|
|
||||||
#[hdl]
|
|
||||||
#[test]
|
|
||||||
fn test_enums() {
|
|
||||||
let _n = SourceLocation::normalize_files_for_tests();
|
|
||||||
let mut sim = Simulation::new(enums());
|
|
||||||
let mut writer = RcWriter::default();
|
|
||||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
|
||||||
sim.write_clock(sim.io().cd.clk, false);
|
|
||||||
sim.write_reset(sim.io().cd.rst, true);
|
|
||||||
sim.write_bool(sim.io().en, false);
|
|
||||||
sim.write_bool_or_int(sim.io().which_in, 0_hdl_u2);
|
|
||||||
sim.write_bool_or_int(sim.io().data_in, 0_hdl_u4);
|
|
||||||
sim.advance_time(SimDuration::from_micros(1));
|
|
||||||
sim.write_clock(sim.io().cd.clk, true);
|
|
||||||
sim.advance_time(SimDuration::from_nanos(100));
|
|
||||||
sim.write_reset(sim.io().cd.rst, false);
|
|
||||||
sim.advance_time(SimDuration::from_nanos(900));
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
struct IO {
|
|
||||||
en: bool,
|
|
||||||
which_in: u8,
|
|
||||||
data_in: u8,
|
|
||||||
which_out: u8,
|
|
||||||
data_out: u8,
|
|
||||||
}
|
|
||||||
let io_cycles = [
|
|
||||||
IO {
|
|
||||||
en: false,
|
|
||||||
which_in: 0,
|
|
||||||
data_in: 0,
|
|
||||||
which_out: 0,
|
|
||||||
data_out: 0,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: true,
|
|
||||||
which_in: 1,
|
|
||||||
data_in: 0,
|
|
||||||
which_out: 0,
|
|
||||||
data_out: 0,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: false,
|
|
||||||
which_in: 0,
|
|
||||||
data_in: 0,
|
|
||||||
which_out: 1,
|
|
||||||
data_out: 0,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: true,
|
|
||||||
which_in: 1,
|
|
||||||
data_in: 0xF,
|
|
||||||
which_out: 1,
|
|
||||||
data_out: 0,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: true,
|
|
||||||
which_in: 1,
|
|
||||||
data_in: 0xF,
|
|
||||||
which_out: 1,
|
|
||||||
data_out: 0x3,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: true,
|
|
||||||
which_in: 2,
|
|
||||||
data_in: 0xF,
|
|
||||||
which_out: 1,
|
|
||||||
data_out: 0x3,
|
|
||||||
},
|
|
||||||
IO {
|
|
||||||
en: true,
|
|
||||||
which_in: 2,
|
|
||||||
data_in: 0xF,
|
|
||||||
which_out: 2,
|
|
||||||
data_out: 0xF,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
for (
|
|
||||||
cycle,
|
|
||||||
expected @ IO {
|
|
||||||
en,
|
|
||||||
which_in,
|
|
||||||
data_in,
|
|
||||||
which_out: _,
|
|
||||||
data_out: _,
|
|
||||||
},
|
|
||||||
) in io_cycles.into_iter().enumerate()
|
|
||||||
{
|
|
||||||
sim.write_bool(sim.io().en, en);
|
|
||||||
sim.write_bool_or_int(sim.io().which_in, which_in.cast_to_static());
|
|
||||||
sim.write_bool_or_int(sim.io().data_in, data_in.cast_to_static());
|
|
||||||
let io = IO {
|
|
||||||
en,
|
|
||||||
which_in,
|
|
||||||
data_in,
|
|
||||||
which_out: sim
|
|
||||||
.read_bool_or_int(sim.io().which_out)
|
|
||||||
.to_bigint()
|
|
||||||
.try_into()
|
|
||||||
.expect("known to be in range"),
|
|
||||||
data_out: sim
|
|
||||||
.read_bool_or_int(sim.io().data_out)
|
|
||||||
.to_bigint()
|
|
||||||
.try_into()
|
|
||||||
.expect("known to be in range"),
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
expected,
|
|
||||||
io,
|
|
||||||
"cycle: {cycle}\nvcd:\n{}",
|
|
||||||
String::from_utf8(writer.take()).unwrap(),
|
|
||||||
);
|
|
||||||
sim.write_clock(sim.io().cd.clk, false);
|
|
||||||
sim.advance_time(SimDuration::from_micros(1));
|
|
||||||
sim.write_clock(sim.io().cd.clk, true);
|
|
||||||
sim.advance_time(SimDuration::from_micros(1));
|
|
||||||
}
|
|
||||||
sim.flush_traces().unwrap();
|
|
||||||
let vcd = String::from_utf8(writer.take()).unwrap();
|
|
||||||
println!("####### VCD:\n{vcd}\n#######");
|
|
||||||
if vcd != include_str!("sim/expected/enums.vcd") {
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
let sim_debug = format!("{sim:#?}");
|
|
||||||
println!("#######\n{sim_debug}\n#######");
|
|
||||||
if sim_debug != include_str!("sim/expected/enums.txt") {
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add tests for memories
|
// TODO: add tests for memories
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue