From f54e55a14330d1e10e2b6da13510d77e016850bc Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 13 Nov 2024 21:20:15 -0800 Subject: [PATCH] Simulation::settle_step() works for simple modules --- crates/fayalite/src/sim.rs | 485 +++++++++++++++-------- crates/fayalite/src/sim/interpreter.rs | 378 +++++++++++++++++- crates/fayalite/tests/sim.rs | 524 +++++++++++++++++++++++++ 3 files changed, 1221 insertions(+), 166 deletions(-) create mode 100644 crates/fayalite/tests/sim.rs diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index b647302..7793dce 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -40,13 +40,13 @@ mod interpreter; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] enum CondBody { IfTrue { - cond: CompiledExpr, + cond: CompiledValue, }, IfFalse { - cond: CompiledExpr, + cond: CompiledValue, }, MatchArm { - enum_expr: CompiledExpr, + enum_expr: CompiledValue, variant_index: usize, }, } @@ -267,8 +267,8 @@ impl CompiledValue { } impl CompiledValue { - 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 CompiledExpr { } } -impl CompiledExpr { - 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 { fn field_by_index(self, field_index: usize) -> CompiledExpr { CompiledExpr { @@ -446,48 +433,118 @@ enum AssignmentIO { }, } -#[derive(Debug, Default)] -struct Assignments { - assignments: Vec, - slot_readers: Option, - slot_writers: Option, +#[derive(Debug)] +enum Assignments { + Accumulating { + assignments: Vec, + }, + 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>, - big_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, - }, +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 { - 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 for SlotSet { fn extend>(&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 = 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 = 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::>::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 { 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 { } impl Compiled { - pub fn new(module: Module) -> Self { + pub fn new(module: Interned>) -> Self { Self::from_canonical(Compiler::new(module.canonical().intern()).compile()) } pub fn canonical(self) -> Compiled { @@ -2620,14 +2794,19 @@ impl Compiled { #[derive(Debug)] pub struct Simulation { state: interpreter::State, - compiled: Compiled, + base_module: CompiledModule, + base_module_io_ty: T, } impl Simulation { + pub fn new(module: Interned>) -> Self { + Self::from_compiled(Compiled::new(module)) + } pub fn from_compiled(compiled: Compiled) -> 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) { diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 5269131..e713300 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -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( retval } +impl fmt::Debug for Insn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug_fmt::(f, None, None) + } +} + +impl Insn { + fn debug_fmt( + &self, + f: &mut fmt::Formatter<'_>, + labels: Option<&Labels>, + state_layout: Option<&StateLayout>, + ) -> 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>), { $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>, { $Insn::MAX_FIELDS }> { match self { $( @@ -339,6 +439,8 @@ pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default { + Default + Deref + FromIterator; + 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 = 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 = Vec; + type Labels = Labels; + fn labels(labels: &Self::Labels) -> Option<&Labels> { + Some(labels) + } +} + +struct Label { + address: Option, +} + +#[derive(Default)] +pub(crate) struct Labels { + labels: Vec