Simulation::settle_step() works for simple modules
This commit is contained in:
parent
d7d8e2e7ce
commit
2e9d5c1835
|
@ -40,13 +40,13 @@ mod interpreter;
|
|||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
enum CondBody {
|
||||
IfTrue {
|
||||
cond: CompiledExpr<Bool>,
|
||||
cond: CompiledValue<Bool>,
|
||||
},
|
||||
IfFalse {
|
||||
cond: CompiledExpr<Bool>,
|
||||
cond: CompiledValue<Bool>,
|
||||
},
|
||||
MatchArm {
|
||||
enum_expr: CompiledExpr<Enum>,
|
||||
enum_expr: CompiledValue<Enum>,
|
||||
variant_index: usize,
|
||||
},
|
||||
}
|
||||
|
@ -267,8 +267,8 @@ impl<T: Type> CompiledValue<T> {
|
|||
}
|
||||
|
||||
impl CompiledValue<Enum> {
|
||||
fn add_discriminant_to_set(self, offset: TypeIndex, inputs: &mut SlotSet) {
|
||||
inputs.extend([self.range.offset(offset)]);
|
||||
fn add_discriminant_to_set(self, inputs: &mut SlotSet) {
|
||||
inputs.extend([self.range]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,19 +359,6 @@ impl<T: Type> CompiledExpr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl CompiledExpr<Enum> {
|
||||
fn add_discriminant_and_indexes_to_set(self, inputs: &mut SlotSet) {
|
||||
let Self {
|
||||
static_part,
|
||||
indexes,
|
||||
} = self;
|
||||
indexes.as_ref().for_each_offset(|offset| {
|
||||
static_part.add_discriminant_to_set(offset, inputs);
|
||||
});
|
||||
inputs.extend(indexes.as_ref().iter());
|
||||
}
|
||||
}
|
||||
|
||||
impl CompiledExpr<Bundle> {
|
||||
fn field_by_index(self, field_index: usize) -> CompiledExpr<CanonicalType> {
|
||||
CompiledExpr {
|
||||
|
@ -446,48 +433,118 @@ enum AssignmentIO {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Assignments {
|
||||
assignments: Vec<Assignment>,
|
||||
slot_readers: Option<SlotToAssignmentIndexFullMap>,
|
||||
slot_writers: Option<SlotToAssignmentIndexFullMap>,
|
||||
#[derive(Debug)]
|
||||
enum Assignments {
|
||||
Accumulating {
|
||||
assignments: Vec<Assignment>,
|
||||
},
|
||||
Finalized {
|
||||
assignments: Box<[Assignment]>,
|
||||
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_len: TypeLen) {
|
||||
assert!(
|
||||
self.slot_readers.is_none() && self.slot_writers.is_none(),
|
||||
"already finalized"
|
||||
);
|
||||
let Self::Accumulating { assignments } = self else {
|
||||
unreachable!("already finalized");
|
||||
};
|
||||
let assignments = mem::take(assignments).into_boxed_slice();
|
||||
let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_len);
|
||||
let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_len);
|
||||
for (assignment_index, assignment) in self.assignments.iter().enumerate() {
|
||||
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_writers
|
||||
.keys_for_assignment(assignment_index)
|
||||
.extend([&assignment.outputs]);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
slot_writers[slot].push(assignment_index);
|
||||
}
|
||||
}
|
||||
self.slot_readers = Some(slot_readers);
|
||||
self.slot_writers = Some(slot_writers);
|
||||
*self = Self::Finalized {
|
||||
assignments,
|
||||
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) {
|
||||
assert!(
|
||||
self.slot_readers.is_none() && self.slot_writers.is_none(),
|
||||
"already finalized"
|
||||
);
|
||||
self.assignments.push(v);
|
||||
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 slot_readers(&self) -> &SlotToAssignmentIndexFullMap {
|
||||
self.slot_readers
|
||||
.as_ref()
|
||||
.expect("Assignments::finalize should have been called")
|
||||
let Self::Finalized { slot_readers, .. } = self else {
|
||||
unreachable!("Assignments::finalize should have been called");
|
||||
};
|
||||
slot_readers
|
||||
}
|
||||
fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap {
|
||||
self.slot_writers
|
||||
.as_ref()
|
||||
.expect("Assignments::finalize should have been called")
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,42 +598,47 @@ impl<'a> IntoNodeIdentifiers for &'a Assignments {
|
|||
big_slots,
|
||||
} = self.slot_readers().len();
|
||||
AssignmentsNodeIdentifiers {
|
||||
assignment_indexes: 0..self.assignments.len(),
|
||||
assignment_indexes: 0..self.assignments().len(),
|
||||
small_slots: 0..small_slots.value,
|
||||
big_slots: 0..big_slots.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AssignmentsNeighborsDirected<'a> {
|
||||
AssignmentIndexes(std::slice::Iter<'a, usize>),
|
||||
Slots {
|
||||
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
|
||||
big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
|
||||
},
|
||||
struct AssignmentsNeighborsDirected<'a> {
|
||||
assignment_indexes: std::slice::Iter<'a, usize>,
|
||||
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
|
||||
big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
|
||||
}
|
||||
|
||||
impl Iterator for AssignmentsNeighborsDirected<'_> {
|
||||
type Item = AssignmentOrSlotIndex;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
AssignmentsNeighborsDirected::AssignmentIndexes(iter) => iter
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::AssignmentIndex),
|
||||
AssignmentsNeighborsDirected::Slots {
|
||||
small_slots,
|
||||
big_slots,
|
||||
} => small_slots
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::SmallSlots)
|
||||
.or_else(|| {
|
||||
big_slots
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::BigSlots)
|
||||
}),
|
||||
let Self {
|
||||
assignment_indexes,
|
||||
small_slots,
|
||||
big_slots,
|
||||
} = self;
|
||||
if let retval @ Some(_) = assignment_indexes
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::AssignmentIndex)
|
||||
{
|
||||
retval
|
||||
} else if let retval @ Some(_) = small_slots
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::SmallSlots)
|
||||
{
|
||||
retval
|
||||
} else if let retval @ Some(_) = big_slots
|
||||
.next()
|
||||
.copied()
|
||||
.map(AssignmentOrSlotIndex::BigSlots)
|
||||
{
|
||||
retval
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -604,25 +666,39 @@ impl<'a> IntoNeighborsDirected for &'a Assignments {
|
|||
};
|
||||
match n {
|
||||
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
|
||||
let assignment = &self.assignments[assignment_index];
|
||||
let SlotSet(TypeParts {
|
||||
small_slots,
|
||||
big_slots,
|
||||
}) = match d {
|
||||
Outgoing => &assignment.outputs,
|
||||
Incoming => &assignment.inputs,
|
||||
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::Slots {
|
||||
AssignmentsNeighborsDirected {
|
||||
assignment_indexes: assignment_indexes.iter(),
|
||||
small_slots: small_slots.iter(),
|
||||
big_slots: big_slots.iter(),
|
||||
}
|
||||
}
|
||||
AssignmentOrSlotIndex::SmallSlots(slot) => {
|
||||
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter())
|
||||
}
|
||||
AssignmentOrSlotIndex::BigSlots(slot) => {
|
||||
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter())
|
||||
}
|
||||
AssignmentOrSlotIndex::SmallSlots(slot) => AssignmentsNeighborsDirected {
|
||||
assignment_indexes: slot_map[slot].iter(),
|
||||
small_slots: Default::default(),
|
||||
big_slots: Default::default(),
|
||||
},
|
||||
AssignmentOrSlotIndex::BigSlots(slot) => AssignmentsNeighborsDirected {
|
||||
assignment_indexes: slot_map[slot].iter(),
|
||||
small_slots: Default::default(),
|
||||
big_slots: Default::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -659,7 +735,7 @@ impl Visitable for Assignments {
|
|||
|
||||
fn visit_map(self: &Self) -> Self::Map {
|
||||
AssignmentsVisitMap {
|
||||
assignments: vec![false; self.assignments.len()],
|
||||
assignments: vec![false; self.assignments().len()],
|
||||
slots: DenseSlotSet::new(self.slot_readers().len()),
|
||||
}
|
||||
}
|
||||
|
@ -667,7 +743,7 @@ impl Visitable for Assignments {
|
|||
fn reset_map(self: &Self, map: &mut Self::Map) {
|
||||
let AssignmentsVisitMap { assignments, slots } = map;
|
||||
assignments.clear();
|
||||
assignments.resize(self.assignments.len(), false);
|
||||
assignments.resize(self.assignments().len(), false);
|
||||
if slots.len() != self.slot_readers().len() {
|
||||
*slots = DenseSlotSet::new(self.slot_readers().len());
|
||||
} else {
|
||||
|
@ -898,12 +974,12 @@ impl Extend<CondBody> for SlotSet {
|
|||
fn extend<T: IntoIterator<Item = CondBody>>(&mut self, iter: T) {
|
||||
iter.into_iter().for_each(|cond_body| match cond_body {
|
||||
CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => {
|
||||
cond.add_target_and_indexes_to_set(self);
|
||||
self.extend([cond.range]);
|
||||
}
|
||||
CondBody::MatchArm {
|
||||
enum_expr,
|
||||
variant_index,
|
||||
} => enum_expr.add_discriminant_and_indexes_to_set(self),
|
||||
variant_index: _,
|
||||
} => enum_expr.add_discriminant_to_set(self),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -936,11 +1012,10 @@ impl SlotToAssignmentIndexFullMap {
|
|||
small_slots,
|
||||
big_slots,
|
||||
} = len;
|
||||
const VEC_NEW: Vec<usize> = Vec::new();
|
||||
Self(TypeParts {
|
||||
small_slots: vec![VEC_NEW; small_slots.value.try_into().expect("length too big")]
|
||||
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")]
|
||||
big_slots: vec![Vec::new(); big_slots.value.try_into().expect("length too big")]
|
||||
.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
|
@ -1237,54 +1312,51 @@ impl Compiler {
|
|||
static_part,
|
||||
indexes,
|
||||
} = expr;
|
||||
let layout = static_part.layout.with_anonymized_debug_info();
|
||||
let retval = CompiledValue {
|
||||
layout,
|
||||
range: self.insns.allocate_variable(&layout.layout),
|
||||
write: None,
|
||||
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
|
||||
};
|
||||
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)| {
|
||||
if indexes.small_slots.is_empty() {
|
||||
Insn::CopySmall { dest, src: base }
|
||||
} else {
|
||||
Insn::ReadSmallIndexed {
|
||||
dest,
|
||||
src: StatePartArrayIndexed {
|
||||
base,
|
||||
indexes: indexes.small_slots,
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
.chain(
|
||||
big_slots
|
||||
.iter()
|
||||
.zip(static_part.range.big_slots.iter())
|
||||
.map(|(dest, base)| {
|
||||
if indexes.big_slots.is_empty() {
|
||||
Insn::Copy { dest, src: base }
|
||||
} else {
|
||||
Insn::ReadIndexed {
|
||||
dest,
|
||||
src: StatePartArrayIndexed {
|
||||
base,
|
||||
indexes: indexes.big_slots,
|
||||
},
|
||||
}
|
||||
}
|
||||
}),
|
||||
),
|
||||
source_location,
|
||||
);
|
||||
self.compiled_exprs_to_values.insert(expr, retval);
|
||||
retval
|
||||
}
|
||||
|
@ -2456,9 +2528,9 @@ impl Compiler {
|
|||
source_location,
|
||||
blocks: [then_block, else_block],
|
||||
}) => {
|
||||
let cond = self
|
||||
.compile_expr(*parent_module, Expr::canonical(cond))
|
||||
.map_ty(Bool::from_canonical);
|
||||
let cond = self.compile_expr(*parent_module, Expr::canonical(cond));
|
||||
let cond = self.compiled_expr_to_value(cond, source_location);
|
||||
let cond = cond.map_ty(Bool::from_canonical);
|
||||
self.compile_block(
|
||||
parent_module,
|
||||
then_block,
|
||||
|
@ -2481,9 +2553,9 @@ impl Compiler {
|
|||
source_location,
|
||||
blocks,
|
||||
}) => {
|
||||
let enum_expr = self
|
||||
.compile_expr(*parent_module, Expr::canonical(expr))
|
||||
.map_ty(Enum::from_canonical);
|
||||
let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr));
|
||||
let enum_expr = self.compiled_expr_to_value(enum_expr, source_location);
|
||||
let enum_expr = enum_expr.map_ty(Enum::from_canonical);
|
||||
for (variant_index, block) in blocks.into_iter().enumerate() {
|
||||
self.compile_block(
|
||||
parent_module,
|
||||
|
@ -2514,10 +2586,12 @@ impl Compiler {
|
|||
annotations: _,
|
||||
module_io,
|
||||
}| {
|
||||
self.compile_value(TargetInInstantiatedModule {
|
||||
let target = TargetInInstantiatedModule {
|
||||
instantiated_module: *module,
|
||||
target: Target::from(module_io),
|
||||
})
|
||||
};
|
||||
self.decl_conditions.insert(target, Interned::default());
|
||||
self.compile_value(target)
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
@ -2537,8 +2611,7 @@ impl Compiler {
|
|||
fn process_assignments(&mut self) {
|
||||
self.assignments
|
||||
.finalize(self.insns.state_layout().len().ty);
|
||||
let assignments_queue: Vec<usize> = match petgraph::algo::toposort(&self.assignments, None)
|
||||
{
|
||||
let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) {
|
||||
Ok(nodes) => nodes
|
||||
.into_iter()
|
||||
.filter_map(|n| match n {
|
||||
|
@ -2549,7 +2622,7 @@ impl Compiler {
|
|||
Err(e) => match e.node_id() {
|
||||
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!(
|
||||
"combinatorial logic cycle detected at: {}",
|
||||
self.assignments.assignments[assignment_index].source_location,
|
||||
self.assignments.assignments()[assignment_index].source_location,
|
||||
),
|
||||
AssignmentOrSlotIndex::SmallSlots(slot) => panic!(
|
||||
"combinatorial logic cycle detected through: {}",
|
||||
|
@ -2561,12 +2634,113 @@ impl Compiler {
|
|||
),
|
||||
},
|
||||
};
|
||||
todo!();
|
||||
struct CondStackEntry<'a> {
|
||||
cond: &'a Cond,
|
||||
end_label_index: usize,
|
||||
}
|
||||
let mut cond_stack = Vec::<CondStackEntry<'_>>::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_index,
|
||||
} = cond_stack.pop().expect("just checked len");
|
||||
self.insns.define_label_at_next_insn(end_label_index);
|
||||
}
|
||||
for cond in &conditions[cond_stack.len()..] {
|
||||
let end_label_index = 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 {
|
||||
small_slots:
|
||||
StatePartLen {
|
||||
value: 1,
|
||||
_phantom: _,
|
||||
},
|
||||
big_slots:
|
||||
StatePartLen {
|
||||
value: 0,
|
||||
_phantom: _,
|
||||
},
|
||||
} => (
|
||||
Insn::BranchIfSmallZero {
|
||||
target: end_label_index,
|
||||
value: cond_value.range.small_slots.start,
|
||||
},
|
||||
Insn::BranchIfSmallNonZero {
|
||||
target: end_label_index,
|
||||
value: cond_value.range.small_slots.start,
|
||||
},
|
||||
),
|
||||
TypeLen {
|
||||
small_slots:
|
||||
StatePartLen {
|
||||
value: 0,
|
||||
_phantom: _,
|
||||
},
|
||||
big_slots:
|
||||
StatePartLen {
|
||||
value: 1,
|
||||
_phantom: _,
|
||||
},
|
||||
} => (
|
||||
Insn::BranchIfZero {
|
||||
target: end_label_index,
|
||||
value: cond_value.range.big_slots.start,
|
||||
},
|
||||
Insn::BranchIfNonZero {
|
||||
target: end_label_index,
|
||||
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 {
|
||||
enum_expr,
|
||||
variant_index,
|
||||
} => todo!(),
|
||||
}
|
||||
cond_stack.push(CondStackEntry {
|
||||
cond,
|
||||
end_label_index,
|
||||
});
|
||||
}
|
||||
for insn in insns {
|
||||
self.insns.push(*insn, *source_location);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn compile(mut self) -> Compiled<Bundle> {
|
||||
let base_module =
|
||||
*self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized());
|
||||
self.process_assignments();
|
||||
self.insns
|
||||
.push(Insn::Return, self.base_module.source_location());
|
||||
Compiled {
|
||||
insns: Insns::from(self.insns).intern_sized(),
|
||||
base_module,
|
||||
|
@ -2588,7 +2762,7 @@ pub struct Compiled<T: BundleType> {
|
|||
}
|
||||
|
||||
impl<T: BundleType> Compiled<T> {
|
||||
pub fn new(module: Module<T>) -> Self {
|
||||
pub fn new(module: Interned<Module<T>>) -> Self {
|
||||
Self::from_canonical(Compiler::new(module.canonical().intern()).compile())
|
||||
}
|
||||
pub fn canonical(self) -> Compiled<Bundle> {
|
||||
|
@ -2620,14 +2794,19 @@ impl<T: BundleType> Compiled<T> {
|
|||
#[derive(Debug)]
|
||||
pub struct Simulation<T: BundleType> {
|
||||
state: interpreter::State,
|
||||
compiled: Compiled<T>,
|
||||
base_module: CompiledModule,
|
||||
base_module_io_ty: T,
|
||||
}
|
||||
|
||||
impl<T: BundleType> Simulation<T> {
|
||||
pub fn new(module: Interned<Module<T>>) -> Self {
|
||||
Self::from_compiled(Compiled::new(module))
|
||||
}
|
||||
pub fn from_compiled(compiled: Compiled<T>) -> Self {
|
||||
Self {
|
||||
state: interpreter::State::new(compiled.insns),
|
||||
compiled,
|
||||
base_module: compiled.base_module,
|
||||
base_module_io_ty: compiled.base_module_io_ty,
|
||||
}
|
||||
}
|
||||
pub fn settle_step(&mut self) {
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
ty::CanonicalType,
|
||||
util::get_many_mut,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||
use std::{
|
||||
|
@ -166,6 +167,83 @@ fn make_array_into_iter<T, const I: usize, const N: usize>(
|
|||
retval
|
||||
}
|
||||
|
||||
impl fmt::Debug for Insn {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.debug_fmt::<InsnsBuildingDone>(f, None, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Insn {
|
||||
fn debug_fmt<BK: InsnsBuildingKind>(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
labels: Option<&Labels>,
|
||||
state_layout: Option<&StateLayout<BK>>,
|
||||
) -> fmt::Result {
|
||||
let (insn_name, fields) = self.fields_with_names();
|
||||
write!(f, "{insn_name}")?;
|
||||
if fields.len() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
writeln!(f, " {{")?;
|
||||
for (field_name, field) in fields {
|
||||
write!(f, " {field_name}: ")?;
|
||||
match field.kind {
|
||||
InsnFieldKind::BranchTarget => match field.ty {
|
||||
InsnFieldType::USize(&label_index) => {
|
||||
if let Some(labels) = labels {
|
||||
write!(f, "L{label_index}")?;
|
||||
if let Some(label) = labels.labels.get(label_index) {
|
||||
if let Some(address) = label.address {
|
||||
write!(f, " (at {address})")?;
|
||||
} else {
|
||||
write!(f, " (not yet defined)")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, " (invalid)")?;
|
||||
}
|
||||
writeln!(f, ",")?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
InsnFieldType::SmallSlot(_)
|
||||
| InsnFieldType::BigSlot(_)
|
||||
| InsnFieldType::SmallSlotArrayIndexed(_)
|
||||
| InsnFieldType::BigSlotArrayIndexed(_)
|
||||
| InsnFieldType::SmallUInt(_)
|
||||
| InsnFieldType::SmallSInt(_)
|
||||
| InsnFieldType::InternedBigInt(_)
|
||||
| InsnFieldType::U8(_)
|
||||
| InsnFieldType::Empty(_) => {}
|
||||
},
|
||||
InsnFieldKind::Input | InsnFieldKind::Output | InsnFieldKind::Immediate => {}
|
||||
}
|
||||
match field.ty {
|
||||
InsnFieldType::SmallSlot(v) => {
|
||||
v.debug_fmt(f, ",", " // ", "", state_layout)?;
|
||||
}
|
||||
InsnFieldType::BigSlot(v) => {
|
||||
v.debug_fmt(f, ",", " // ", "", state_layout)?;
|
||||
}
|
||||
InsnFieldType::SmallSlotArrayIndexed(v) => {
|
||||
v.debug_fmt(f, ",", " // ", "", state_layout)?;
|
||||
}
|
||||
InsnFieldType::BigSlotArrayIndexed(v) => {
|
||||
v.debug_fmt(f, ",", " // ", "", state_layout)?;
|
||||
}
|
||||
InsnFieldType::SmallUInt(v) => fmt::Debug::fmt(v, f)?,
|
||||
InsnFieldType::SmallSInt(v) => fmt::Debug::fmt(v, f)?,
|
||||
InsnFieldType::InternedBigInt(v) => fmt::Debug::fmt(v, f)?,
|
||||
InsnFieldType::U8(v) => fmt::Debug::fmt(v, f)?,
|
||||
InsnFieldType::USize(v) => fmt::Debug::fmt(v, f)?,
|
||||
InsnFieldType::Empty(v) => fmt::Debug::fmt(v, f)?,
|
||||
}
|
||||
writeln!(f, ",")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_insns {
|
||||
(
|
||||
#[insn = $Insn:ident, next_macro = $next_macro:ident, branch_macro = $branch_macro:ident]
|
||||
|
@ -191,7 +269,7 @@ macro_rules! impl_insns {
|
|||
})? => $block:block
|
||||
)*
|
||||
) => {
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
$vis enum $Insn {
|
||||
$(
|
||||
$(#[$insn_meta])*
|
||||
|
@ -249,6 +327,28 @@ macro_rules! impl_insns {
|
|||
)*
|
||||
}
|
||||
}
|
||||
$vis fn fields_with_names<'a>(&'a self) -> (&'static str, std::array::IntoIter<(&'static str, InsnField<InsnFieldTypeTransformRef<'a>>), { $Insn::MAX_FIELDS }>) {
|
||||
match self {
|
||||
$(
|
||||
$Insn::$insn_name $({
|
||||
$($field_name,)*
|
||||
})? => (
|
||||
stringify!($insn_name),
|
||||
make_array_into_iter([
|
||||
$($((stringify!($field_name), InsnField {
|
||||
ty: <$field_ty as InsnFieldTrait>::variant($field_name),
|
||||
kind: InsnFieldKind::$field_kind,
|
||||
}),)*)?
|
||||
],
|
||||
|| ("", InsnField {
|
||||
ty: InsnFieldType::empty(),
|
||||
kind: InsnFieldKind::Immediate,
|
||||
}),
|
||||
),
|
||||
),
|
||||
)*
|
||||
}
|
||||
}
|
||||
$vis fn fields_mut<'a>(&'a mut self) -> std::array::IntoIter<InsnField<InsnFieldTypeTransformRefMut<'a>>, { $Insn::MAX_FIELDS }> {
|
||||
match self {
|
||||
$(
|
||||
|
@ -339,6 +439,8 @@ pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default {
|
|||
+ Default
|
||||
+ Deref<Target = [T]>
|
||||
+ FromIterator<T>;
|
||||
type Labels: Default;
|
||||
fn labels(labels: &Self::Labels) -> Option<&Labels>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
||||
|
@ -346,6 +448,10 @@ pub(crate) struct InsnsBuildingDone;
|
|||
|
||||
impl InsnsBuildingKind for InsnsBuildingDone {
|
||||
type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Interned<[T]>;
|
||||
type Labels = ();
|
||||
fn labels(_labels: &Self::Labels) -> Option<&Labels> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
||||
|
@ -353,12 +459,27 @@ pub(crate) struct InsnsBuilding;
|
|||
|
||||
impl InsnsBuildingKind for InsnsBuilding {
|
||||
type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Vec<T>;
|
||||
type Labels = Labels;
|
||||
fn labels(labels: &Self::Labels) -> Option<&Labels> {
|
||||
Some(labels)
|
||||
}
|
||||
}
|
||||
|
||||
struct Label {
|
||||
address: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Labels {
|
||||
labels: Vec<Label>,
|
||||
address_to_label_indexes_map: HashMap<usize, Vec<usize>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct Insns<BK: InsnsBuildingKind> {
|
||||
insns: BK::Vec<Insn>,
|
||||
insn_source_locations: BK::Vec<SourceLocation>,
|
||||
labels: BK::Labels,
|
||||
state_layout: StateLayout<BK>,
|
||||
}
|
||||
|
||||
|
@ -368,21 +489,60 @@ impl<BK: InsnsBuildingKind> Insns<BK> {
|
|||
}
|
||||
}
|
||||
|
||||
struct InsnsDebug<'a> {
|
||||
struct InsnsDebug<'a, BK: InsnsBuildingKind> {
|
||||
insns: &'a [Insn],
|
||||
insn_source_locations: &'a [SourceLocation],
|
||||
labels: &'a BK::Labels,
|
||||
state_layout: &'a StateLayout<BK>,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for InsnsDebug<'a> {
|
||||
struct InsnDebug<'a, BK: InsnsBuildingKind> {
|
||||
address: usize,
|
||||
source_location: Option<SourceLocation>,
|
||||
insn: &'a Insn,
|
||||
labels: Option<&'a Labels>,
|
||||
state_layout: &'a StateLayout<BK>,
|
||||
}
|
||||
|
||||
impl<BK: InsnsBuildingKind> fmt::Debug for InsnDebug<'_, BK> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(label_indexes) = self
|
||||
.labels
|
||||
.and_then(|labels| labels.address_to_label_indexes_map.get(&self.address))
|
||||
{
|
||||
for &label_index in label_indexes {
|
||||
writeln!(f, "L{label_index}:")?;
|
||||
}
|
||||
}
|
||||
if let Some(source_location) = self.source_location {
|
||||
writeln!(f, "// at: {source_location}")?;
|
||||
}
|
||||
self.insn.debug_fmt(f, self.labels, Some(self.state_layout))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, BK: InsnsBuildingKind> fmt::Debug for InsnsDebug<'a, BK> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let labels = BK::labels(&self.labels);
|
||||
let mut debug_list = f.debug_list();
|
||||
let mut last_source_location = None;
|
||||
for (insn, source_location) in self.insns.iter().zip(self.insn_source_locations) {
|
||||
if Some(source_location) != last_source_location {
|
||||
debug_list.entry(&format_args!("// at: {source_location}\n{insn:?}"));
|
||||
} else {
|
||||
debug_list.entry(insn);
|
||||
}
|
||||
for (address, (insn, &source_location)) in self
|
||||
.insns
|
||||
.iter()
|
||||
.zip(self.insn_source_locations)
|
||||
.enumerate()
|
||||
{
|
||||
debug_list.entry(&InsnDebug {
|
||||
address,
|
||||
source_location: if Some(source_location) != last_source_location {
|
||||
Some(source_location)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
insn,
|
||||
labels,
|
||||
state_layout: self.state_layout,
|
||||
});
|
||||
last_source_location = Some(source_location);
|
||||
}
|
||||
debug_list.finish()
|
||||
|
@ -394,15 +554,18 @@ impl<BK: InsnsBuildingKind> fmt::Debug for Insns<BK> {
|
|||
let Self {
|
||||
insns,
|
||||
insn_source_locations,
|
||||
labels,
|
||||
state_layout,
|
||||
} = self;
|
||||
f.debug_struct("Insns")
|
||||
.field("state_layout", state_layout)
|
||||
.field(
|
||||
"insns",
|
||||
&InsnsDebug {
|
||||
&InsnsDebug::<BK> {
|
||||
insns,
|
||||
insn_source_locations,
|
||||
labels,
|
||||
state_layout,
|
||||
},
|
||||
)
|
||||
.finish_non_exhaustive()
|
||||
|
@ -418,6 +581,10 @@ pub(crate) trait StatePartKind:
|
|||
type BorrowedState<'a>: 'a;
|
||||
fn new_state(len: StatePartLen<Self>) -> Self::State;
|
||||
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>;
|
||||
fn part_debug_data<BK: InsnsBuildingKind>(
|
||||
state_layout: &StateLayout<BK>,
|
||||
part_index: StatePartIndex<Self>,
|
||||
) -> Option<&Self::DebugData>;
|
||||
}
|
||||
|
||||
pub(crate) trait StatePartsValue {
|
||||
|
@ -980,6 +1147,12 @@ make_state_part_kinds! {
|
|||
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
|
||||
state.borrow()
|
||||
}
|
||||
fn part_debug_data<BK: InsnsBuildingKind>(
|
||||
state_layout: &StateLayout<BK>,
|
||||
part_index: StatePartIndex<Self>,
|
||||
) -> Option<&Self::DebugData> {
|
||||
state_layout.small_stack.debug_data.get(part_index.as_usize())
|
||||
}
|
||||
}
|
||||
#[state, field = big_stack]
|
||||
impl StatePartKind for StatePartKindBigStack {
|
||||
|
@ -993,6 +1166,12 @@ make_state_part_kinds! {
|
|||
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
|
||||
state.borrow()
|
||||
}
|
||||
fn part_debug_data<BK: InsnsBuildingKind>(
|
||||
state_layout: &StateLayout<BK>,
|
||||
part_index: StatePartIndex<Self>,
|
||||
) -> Option<&Self::DebugData> {
|
||||
state_layout.big_stack.debug_data.get(part_index.as_usize())
|
||||
}
|
||||
}*/
|
||||
#[type, field = small_slots]
|
||||
impl StatePartKind for StatePartKindSmallSlots {
|
||||
|
@ -1006,6 +1185,12 @@ make_state_part_kinds! {
|
|||
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
|
||||
state
|
||||
}
|
||||
fn part_debug_data<BK: InsnsBuildingKind>(
|
||||
state_layout: &StateLayout<BK>,
|
||||
part_index: StatePartIndex<Self>,
|
||||
) -> Option<&Self::DebugData> {
|
||||
state_layout.ty.small_slots.debug_data.get(part_index.as_usize())
|
||||
}
|
||||
}
|
||||
#[type, field = big_slots]
|
||||
impl StatePartKind for StatePartKindBigSlots {
|
||||
|
@ -1019,6 +1204,12 @@ make_state_part_kinds! {
|
|||
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
|
||||
state
|
||||
}
|
||||
fn part_debug_data<BK: InsnsBuildingKind>(
|
||||
state_layout: &StateLayout<BK>,
|
||||
part_index: StatePartIndex<Self>,
|
||||
) -> Option<&Self::DebugData> {
|
||||
state_layout.ty.big_slots.debug_data.get(part_index.as_usize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,12 +1354,57 @@ pub(crate) struct StatePartArrayIndex<K: StatePartKind> {
|
|||
pub(crate) stride: StatePartLen<K>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct StatePartArrayIndexed<K: StatePartKind> {
|
||||
pub(crate) base: StatePartIndex<K>,
|
||||
pub(crate) indexes: Interned<[StatePartArrayIndex<K>]>,
|
||||
}
|
||||
|
||||
impl<K: StatePartKind> StatePartArrayIndexed<K> {
|
||||
pub(crate) fn debug_fmt<BK: InsnsBuildingKind>(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
before_debug_info_text: &str,
|
||||
comment_start: &str,
|
||||
comment_end: &str,
|
||||
state_layout: Option<&StateLayout<BK>>,
|
||||
) -> fmt::Result {
|
||||
if let Some(state_layout) = state_layout {
|
||||
let Self { base, indexes } = *self;
|
||||
if indexes.is_empty() {
|
||||
base.debug_fmt(
|
||||
f,
|
||||
before_debug_info_text,
|
||||
comment_start,
|
||||
comment_end,
|
||||
Some(state_layout),
|
||||
)
|
||||
} else {
|
||||
base.debug_fmt(f, "", " /* ", " */ ", Some(state_layout))?;
|
||||
for StatePartArrayIndex { index, len, stride } in indexes {
|
||||
f.write_str("[")?;
|
||||
index.debug_fmt(f, "", " /* ", " */ ", Some(state_layout))?;
|
||||
write!(f, ", len={len}, stride={}]", stride.value)?;
|
||||
}
|
||||
f.write_str(before_debug_info_text)
|
||||
}
|
||||
} else {
|
||||
let Self { base, indexes } = self;
|
||||
f.debug_struct("StatePartArrayIndexed")
|
||||
.field("base", base)
|
||||
.field("indexes", indexes)
|
||||
.finish()?;
|
||||
f.write_str(before_debug_info_text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: StatePartKind + fmt::Debug> fmt::Debug for StatePartArrayIndexed<K> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.debug_fmt::<InsnsBuildingDone>(f, "", "", "", None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: StatePartKind> From<StatePartIndex<K>> for StatePartArrayIndexed<K> {
|
||||
fn from(base: StatePartIndex<K>) -> Self {
|
||||
Self {
|
||||
|
@ -1226,11 +1462,28 @@ impl<K: StatePartKind> StatePartIndex<K> {
|
|||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
pub(crate) fn debug_fmt<BK: InsnsBuildingKind>(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
before_debug_info_text: &str,
|
||||
comment_start: &str,
|
||||
comment_end: &str,
|
||||
state_layout: Option<&StateLayout<BK>>,
|
||||
) -> fmt::Result {
|
||||
write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?;
|
||||
f.write_str(before_debug_info_text)?;
|
||||
if let Some(state_layout) = state_layout {
|
||||
if let Some(debug_data) = K::part_debug_data(state_layout, *self) {
|
||||
write!(f, "{comment_start}{debug_data:?}{comment_end}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: StatePartKind> fmt::Debug for StatePartIndex<K> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)
|
||||
self.debug_fmt::<InsnsBuildingDone>(f, "", "", "", None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1641,6 +1894,7 @@ impl Insns<InsnsBuilding> {
|
|||
Self {
|
||||
insns: Vec::new(),
|
||||
insn_source_locations: Vec::new(),
|
||||
labels: Labels::default(),
|
||||
state_layout: StateLayout::empty(),
|
||||
}
|
||||
}
|
||||
|
@ -1663,18 +1917,62 @@ impl Insns<InsnsBuilding> {
|
|||
) -> TypeIndexRange {
|
||||
self.state_layout.ty.allocate(layout)
|
||||
}
|
||||
pub(crate) fn new_label(&mut self) -> usize {
|
||||
let retval = self.labels.labels.len();
|
||||
self.labels.labels.push(Label { address: None });
|
||||
retval
|
||||
}
|
||||
#[track_caller]
|
||||
pub(crate) fn define_label_at_next_insn(&mut self, label_index: usize) {
|
||||
let address = self.next_insn_pc();
|
||||
let label = &mut self.labels.labels[label_index];
|
||||
assert!(label.address.is_none(), "label already defined");
|
||||
label.address = Some(address);
|
||||
self.labels
|
||||
.address_to_label_indexes_map
|
||||
.entry(address)
|
||||
.or_default()
|
||||
.push(label_index);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Insns<InsnsBuilding>> for Insns<InsnsBuildingDone> {
|
||||
fn from(input: Insns<InsnsBuilding>) -> Self {
|
||||
let Insns {
|
||||
insns,
|
||||
mut insns,
|
||||
insn_source_locations,
|
||||
labels,
|
||||
state_layout,
|
||||
} = input;
|
||||
for insn in &mut insns {
|
||||
for field in insn.fields_mut() {
|
||||
match field.kind {
|
||||
InsnFieldKind::BranchTarget => match field.ty {
|
||||
InsnFieldType::USize(value) => {
|
||||
*value = labels.labels[*value]
|
||||
.address
|
||||
.expect("label address not set");
|
||||
}
|
||||
InsnFieldType::SmallSlot(_)
|
||||
| InsnFieldType::BigSlot(_)
|
||||
| InsnFieldType::SmallSlotArrayIndexed(_)
|
||||
| InsnFieldType::BigSlotArrayIndexed(_)
|
||||
| InsnFieldType::SmallUInt(_)
|
||||
| InsnFieldType::SmallSInt(_)
|
||||
| InsnFieldType::InternedBigInt(_)
|
||||
| InsnFieldType::U8(_)
|
||||
| InsnFieldType::Empty(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
InsnFieldKind::Input | InsnFieldKind::Output | InsnFieldKind::Immediate => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Insns {
|
||||
insns: Intern::intern_owned(insns),
|
||||
insn_source_locations: Intern::intern_owned(insn_source_locations),
|
||||
labels: (),
|
||||
state_layout: state_layout.into(),
|
||||
}
|
||||
}
|
||||
|
@ -2182,6 +2480,60 @@ impl_insns! {
|
|||
state.big_slots[dest].clone_from(&value);
|
||||
next!();
|
||||
}
|
||||
Branch {
|
||||
#[kind = BranchTarget]
|
||||
target: usize,
|
||||
} => {
|
||||
branch!(target);
|
||||
}
|
||||
BranchIfZero {
|
||||
#[kind = BranchTarget]
|
||||
target: usize,
|
||||
#[kind = Input]
|
||||
value: StatePartIndex<StatePartKindBigSlots>,
|
||||
} => {
|
||||
if state.big_slots[value].is_zero() {
|
||||
branch!(target);
|
||||
} else {
|
||||
next!();
|
||||
}
|
||||
}
|
||||
BranchIfNonZero {
|
||||
#[kind = BranchTarget]
|
||||
target: usize,
|
||||
#[kind = Input]
|
||||
value: StatePartIndex<StatePartKindBigSlots>,
|
||||
} => {
|
||||
if state.big_slots[value].is_zero() {
|
||||
next!();
|
||||
} else {
|
||||
branch!(target);
|
||||
}
|
||||
}
|
||||
BranchIfSmallZero {
|
||||
#[kind = BranchTarget]
|
||||
target: usize,
|
||||
#[kind = Input]
|
||||
value: StatePartIndex<StatePartKindSmallSlots>,
|
||||
} => {
|
||||
if state.small_slots[value] == 0 {
|
||||
branch!(target);
|
||||
} else {
|
||||
next!();
|
||||
}
|
||||
}
|
||||
BranchIfSmallNonZero {
|
||||
#[kind = BranchTarget]
|
||||
target: usize,
|
||||
#[kind = Input]
|
||||
value: StatePartIndex<StatePartKindSmallSlots>,
|
||||
} => {
|
||||
if state.small_slots[value] == 0 {
|
||||
next!();
|
||||
} else {
|
||||
branch!(target);
|
||||
}
|
||||
}
|
||||
Return => {
|
||||
break;
|
||||
}
|
||||
|
|
524
crates/fayalite/tests/sim.rs
Normal file
524
crates/fayalite/tests/sim.rs
Normal file
|
@ -0,0 +1,524 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use fayalite::{prelude::*, sim::Simulation};
|
||||
|
||||
#[hdl_module(outline_generated)]
|
||||
pub fn connect_const() {
|
||||
#[hdl]
|
||||
let o: UInt<8> = m.output();
|
||||
connect(o, 5u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_connect_const() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let mut sim = Simulation::new(connect_const());
|
||||
sim.settle_step();
|
||||
let sim_debug = format!("{sim:#?}");
|
||||
println!("#######\n{sim_debug}\n#######");
|
||||
if sim_debug
|
||||
!= r#"Simulation {
|
||||
state: State {
|
||||
insns: Insns {
|
||||
state_layout: StateLayout {
|
||||
ty: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 2,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
|
||||
ty: UInt<8>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<8>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
},
|
||||
insns: [
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
Const {
|
||||
dest: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "", ty: UInt<8> },
|
||||
value: 5,
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:3:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(0), // SlotDebugData { name: "InstantiatedModule(connect_const: connect_const).connect_const::o", ty: UInt<8> },
|
||||
src: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "", ty: UInt<8> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
Return,
|
||||
],
|
||||
..
|
||||
},
|
||||
pc: 2,
|
||||
small_slots: StatePart {
|
||||
value: [],
|
||||
},
|
||||
big_slots: StatePart {
|
||||
value: [
|
||||
5,
|
||||
5,
|
||||
],
|
||||
},
|
||||
},
|
||||
base_module: CompiledModule {
|
||||
module_io: [
|
||||
CompiledValue {
|
||||
layout: CompiledTypeLayout {
|
||||
ty: UInt<8>,
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 1,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
|
||||
ty: UInt<8>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Scalar,
|
||||
},
|
||||
range: TypeIndexRange {
|
||||
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
|
||||
},
|
||||
write: None,
|
||||
},
|
||||
],
|
||||
},
|
||||
base_module_io_ty: connect_const {
|
||||
o: UInt<8>,
|
||||
},
|
||||
}"# {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module(outline_generated)]
|
||||
pub fn mod1_child() {
|
||||
#[hdl]
|
||||
let i: UInt<4> = m.input();
|
||||
#[hdl]
|
||||
let o: SInt<2> = m.output();
|
||||
#[hdl]
|
||||
let i2: SInt<2> = m.input();
|
||||
#[hdl]
|
||||
let o2: UInt<4> = m.output();
|
||||
connect(o, i.cast_to_static());
|
||||
connect(o2, i2.cast_to_static());
|
||||
#[hdl]
|
||||
if i.cmp_gt(5_hdl_u4) {
|
||||
connect(o2, 0xF_hdl_u4);
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module(outline_generated)]
|
||||
pub fn mod1() {
|
||||
#[hdl]
|
||||
let child = instance(mod1_child());
|
||||
#[hdl]
|
||||
let o: mod1_child = m.output(Expr::ty(child));
|
||||
connect(o, child);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mod1() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let mut sim = Simulation::new(mod1());
|
||||
sim.settle_step();
|
||||
let sim_debug = format!("{sim:#?}");
|
||||
println!("#######\n{sim_debug}\n#######");
|
||||
if sim_debug
|
||||
!= r#"Simulation {
|
||||
state: State {
|
||||
insns: Insns {
|
||||
state_layout: StateLayout {
|
||||
ty: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 17,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::child.i",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::child.o",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::child.i2",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::child.o2",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Bool,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
},
|
||||
insns: [
|
||||
// at: module-XXXXXXXXXX.rs:4:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(6), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(2), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i2", ty: SInt<2> },
|
||||
},
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(4), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(0), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:2:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(10), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(6), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
|
||||
},
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(4), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:1:1
|
||||
Const {
|
||||
dest: StatePartIndex<BigSlots>(16), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
value: 15,
|
||||
},
|
||||
Const {
|
||||
dest: StatePartIndex<BigSlots>(14), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
value: 5,
|
||||
},
|
||||
CmpLt {
|
||||
dest: StatePartIndex<BigSlots>(15), // SlotDebugData { name: "", ty: Bool },
|
||||
lhs: StatePartIndex<BigSlots>(14), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
rhs: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||
},
|
||||
CastToUInt {
|
||||
dest: StatePartIndex<BigSlots>(13), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(10), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
|
||||
dest_width: 4,
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:7:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(13), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:8:1
|
||||
BranchIfZero {
|
||||
target: 11,
|
||||
value: StatePartIndex<BigSlots>(15), // SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:9:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(16), // SlotDebugData { name: "", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:2:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(7), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:4:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(3), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o2", ty: UInt<4> },
|
||||
src: StatePartIndex<BigSlots>(7), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:1:1
|
||||
CastToSInt {
|
||||
dest: StatePartIndex<BigSlots>(12), // SlotDebugData { name: "", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
|
||||
dest_width: 2,
|
||||
},
|
||||
// at: module-XXXXXXXXXX-2.rs:6:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(9), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(12), // SlotDebugData { name: "", ty: SInt<2> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:2:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(5), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(9), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:4:1
|
||||
Copy {
|
||||
dest: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o", ty: SInt<2> },
|
||||
src: StatePartIndex<BigSlots>(5), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
Return,
|
||||
],
|
||||
..
|
||||
},
|
||||
pc: 17,
|
||||
small_slots: StatePart {
|
||||
value: [],
|
||||
},
|
||||
big_slots: StatePart {
|
||||
value: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
15,
|
||||
],
|
||||
},
|
||||
},
|
||||
base_module: CompiledModule {
|
||||
module_io: [
|
||||
CompiledValue {
|
||||
layout: CompiledTypeLayout {
|
||||
ty: Bundle {
|
||||
#[hdl(flip)] /* offset = 0 */
|
||||
i: UInt<4>,
|
||||
/* offset = 4 */
|
||||
o: SInt<2>,
|
||||
#[hdl(flip)] /* offset = 6 */
|
||||
i2: SInt<2>,
|
||||
/* offset = 8 */
|
||||
o2: UInt<4>,
|
||||
},
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 4,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Bundle {
|
||||
fields: [
|
||||
CompiledBundleField {
|
||||
offset: TypeIndex {
|
||||
small_slots: StatePartIndex<SmallSlots>(0),
|
||||
big_slots: StatePartIndex<BigSlots>(0),
|
||||
},
|
||||
ty: CompiledTypeLayout {
|
||||
ty: UInt<4>,
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 1,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Scalar,
|
||||
},
|
||||
},
|
||||
CompiledBundleField {
|
||||
offset: TypeIndex {
|
||||
small_slots: StatePartIndex<SmallSlots>(0),
|
||||
big_slots: StatePartIndex<BigSlots>(1),
|
||||
},
|
||||
ty: CompiledTypeLayout {
|
||||
ty: SInt<2>,
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 1,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Scalar,
|
||||
},
|
||||
},
|
||||
CompiledBundleField {
|
||||
offset: TypeIndex {
|
||||
small_slots: StatePartIndex<SmallSlots>(0),
|
||||
big_slots: StatePartIndex<BigSlots>(2),
|
||||
},
|
||||
ty: CompiledTypeLayout {
|
||||
ty: SInt<2>,
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 1,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: SInt<2>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Scalar,
|
||||
},
|
||||
},
|
||||
CompiledBundleField {
|
||||
offset: TypeIndex {
|
||||
small_slots: StatePartIndex<SmallSlots>(0),
|
||||
big_slots: StatePartIndex<BigSlots>(3),
|
||||
},
|
||||
ty: CompiledTypeLayout {
|
||||
ty: UInt<4>,
|
||||
layout: TypeLayout {
|
||||
small_slots: StatePartAllocationLayout<SmallSlots> {
|
||||
len: 0,
|
||||
debug_data: [],
|
||||
..
|
||||
},
|
||||
big_slots: StatePartAllocationLayout<BigSlots> {
|
||||
len: 1,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: UInt<4>,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
},
|
||||
body: Scalar,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
range: TypeIndexRange {
|
||||
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
|
||||
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 4 },
|
||||
},
|
||||
write: None,
|
||||
},
|
||||
],
|
||||
},
|
||||
base_module_io_ty: mod1 {
|
||||
o: mod1_child {
|
||||
i: UInt<4>,
|
||||
o: SInt<2>,
|
||||
i2: SInt<2>,
|
||||
o2: UInt<4>,
|
||||
},
|
||||
},
|
||||
}"# {
|
||||
panic!();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue