From 3106a6fff6db72ab44bfccc62383c305ab79e492 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 12 Nov 2024 22:11:12 -0800 Subject: [PATCH] working on simulator... --- crates/fayalite/src/sim.rs | 1045 ++++++++++++++++-------- crates/fayalite/src/sim/interpreter.rs | 335 ++++++++ 2 files changed, 1044 insertions(+), 336 deletions(-) diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index dbcb88a..8dc087b 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -6,10 +6,12 @@ use crate::{ bundle::{BundleField, BundleType}, expr::{ + ops, target::{ - Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, + GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, + TargetPathElement, }, - ExprEnum, + ExprEnum, Flow, }, intern::{Intern, Interned, Memoize}, module::{ @@ -19,15 +21,16 @@ use crate::{ prelude::*, sim::interpreter::{ Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone, - SlotDebugData, SmallUInt, StatePartIndex, StatePartIndexMap, StatePartIndexRange, - StatePartKind, StatePartKindBigSlots, StatePartKindSmallSlots, StatePartLayout, - StatePartLen, StatePartsValue, TypeIndex, TypeIndexRange, TypeLayout, TypeLen, TypeParts, - MIN_BITS_FOR_NEEDING_BIG, + SlotDebugData, StatePartArrayIndex, StatePartArrayIndexed, StatePartIndex, + StatePartIndexMap, StatePartIndexRange, StatePartKind, StatePartKindBigSlots, + StatePartKindSmallSlots, StatePartLayout, StatePartsValue, TypeArrayIndex, + TypeArrayIndexes, TypeIndex, TypeIndexRange, TypeLayout, TypeParts, }, + ty::StaticType, }; use hashbrown::HashMap; use num_bigint::BigInt; -use std::{collections::BTreeSet, fmt, marker::PhantomData, mem}; +use std::{collections::BTreeSet, fmt}; mod interpreter; @@ -127,6 +130,14 @@ impl CompiledTypeLayout { body, } } + fn with_anonymized_debug_info(self) -> Self { + let Self { ty, layout, body } = self; + Self { + ty, + layout: layout.with_anonymized_debug_info(), + body, + } + } fn get(ty: T) -> Self { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] struct MyMemoize; @@ -221,6 +232,9 @@ struct CompiledValue { } impl CompiledValue { + fn write(self) -> (CompiledTypeLayout, TypeIndexRange) { + self.write.unwrap_or((self.layout, self.range)) + } fn map( self, mut f: impl FnMut( @@ -235,6 +249,18 @@ impl CompiledValue { write: self.write.map(|(layout, range)| f(layout, range)), } } + fn map_ty(self, mut f: impl FnMut(T) -> U) -> CompiledValue { + self.map(|CompiledTypeLayout { ty, layout, body }, range| { + ( + CompiledTypeLayout { + ty: f(ty), + layout, + body, + }, + range, + ) + }) + } } impl CompiledValue { @@ -243,139 +269,90 @@ impl CompiledValue { } } -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -struct CompiledExprDynIndex { - index_slot: StatePartIndex, - len: usize, - stride: TypeLen, -} - -impl CompiledExprDynIndex { - fn offsets(self) -> impl Iterator { - (0..self.len.try_into().unwrap()).map(move |index| TypeIndex { - small_slots: StatePartIndex { - value: self - .stride - .small_slots - .value - .checked_mul(index) - .expect("array too big"), - _phantom: PhantomData, - }, - big_slots: StatePartIndex { - value: self - .stride - .big_slots - .value - .checked_mul(index) - .expect("array too big"), - _phantom: PhantomData, - }, +impl CompiledValue { + fn field_by_index(self, field_index: usize) -> CompiledValue { + self.map(|layout, range| { + let CompiledTypeLayout { + ty: _, + layout: _, + body: CompiledTypeLayoutBody::Bundle { fields }, + } = layout + else { + unreachable!(); + }; + ( + fields[field_index].ty, + range.slice(TypeIndexRange::new( + fields[field_index].offset, + fields[field_index].ty.layout.len(), + )), + ) }) } - fn for_each_offset(dyn_indexes: &[CompiledExprDynIndex], mut f: impl FnMut(TypeIndex)) { - fn helper( - dyn_indexes: &[CompiledExprDynIndex], - offset: TypeIndex, - f: &mut impl FnMut(TypeIndex), - ) { - if let [next, rest @ ..] = dyn_indexes { - for next_offset in next.offsets() { - helper( - rest, - TypeIndex { - small_slots: StatePartIndex { - value: next_offset - .small_slots - .value - .checked_add(offset.small_slots.value) - .expect("array too big"), - _phantom: PhantomData, - }, - big_slots: StatePartIndex { - value: next_offset - .big_slots - .value - .checked_add(offset.big_slots.value) - .expect("array too big"), - _phantom: PhantomData, - }, - }, - f, - ); - } - } else { - f(offset); - } - } - helper( - dyn_indexes, - TypeIndex { - small_slots: StatePartIndex { - value: 0, - _phantom: PhantomData, - }, - big_slots: StatePartIndex { - value: 0, - _phantom: PhantomData, - }, - }, - &mut f, - ); + fn field_by_name(self, name: Interned) -> CompiledValue { + self.field_by_index(self.layout.ty.name_indexes()[&name]) + } +} + +impl CompiledValue { + fn element(self, index: usize) -> CompiledValue { + self.map(|layout, range| { + let CompiledTypeLayoutBody::Array { element } = layout.body else { + unreachable!(); + }; + (*element, range.index_array(element.layout.len(), index)) + }) + } + fn element_dyn( + self, + index_slot: StatePartIndex, + ) -> CompiledExpr { + CompiledExpr::from(self).element_dyn(index_slot) } } #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] struct CompiledExpr { static_part: CompiledValue, - dyn_indexes: Interned<[CompiledExprDynIndex]>, + indexes: TypeArrayIndexes, } impl From> for CompiledExpr { fn from(static_part: CompiledValue) -> Self { Self { static_part, - dyn_indexes: Interned::default(), + indexes: TypeArrayIndexes::default(), } } } impl CompiledExpr { - fn map_ty(self, mut f: impl FnMut(T) -> U) -> CompiledExpr { + fn map_ty(self, f: impl FnMut(T) -> U) -> CompiledExpr { let Self { static_part, - dyn_indexes, + indexes, } = self; CompiledExpr { - static_part: static_part.map(|CompiledTypeLayout { ty, layout, body }, range| { - ( - CompiledTypeLayout { - ty: f(ty), - layout, - body, - }, - range, - ) - }), - dyn_indexes, + static_part: static_part.map_ty(f), + indexes, } } fn add_target_without_indexes_to_set(self, inputs: &mut SlotSet) { let Self { static_part, - dyn_indexes, + indexes, } = self; - CompiledExprDynIndex::for_each_offset(&dyn_indexes, |offset| { + indexes.as_ref().for_each_offset(|offset| { inputs.extend([static_part.range.offset(offset)]); }); } fn add_target_and_indexes_to_set(self, inputs: &mut SlotSet) { let Self { static_part: _, - dyn_indexes, + indexes, } = self; self.add_target_without_indexes_to_set(inputs); - inputs.extend(dyn_indexes); + inputs.extend(indexes.as_ref().iter()); } } @@ -383,12 +360,59 @@ impl CompiledExpr { fn add_discriminant_and_indexes_to_set(self, inputs: &mut SlotSet) { let Self { static_part, - dyn_indexes, + indexes, } = self; - CompiledExprDynIndex::for_each_offset(&dyn_indexes, |offset| { + indexes.as_ref().for_each_offset(|offset| { static_part.add_discriminant_to_set(offset, inputs); }); - inputs.extend(dyn_indexes); + inputs.extend(indexes.as_ref().iter()); + } +} + +impl CompiledExpr { + fn field_by_index(self, field_index: usize) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.field_by_index(field_index), + indexes: self.indexes, + } + } + fn field_by_name(self, name: Interned) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.field_by_name(name), + indexes: self.indexes, + } + } +} + +impl CompiledExpr { + fn element(self, index: usize) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.element(index), + indexes: self.indexes, + } + } + fn element_dyn( + self, + index_slot: StatePartIndex, + ) -> CompiledExpr { + let CompiledTypeLayoutBody::Array { element } = self.static_part.layout.body else { + unreachable!(); + }; + let stride = element.layout.len(); + let indexes = self.indexes.join(TypeArrayIndex::from_parts( + index_slot, + self.static_part.layout.ty.len(), + stride, + )); + CompiledExpr { + static_part: self.static_part.map(|layout, range| { + let CompiledTypeLayoutBody::Array { element } = layout.body else { + unreachable!(); + }; + (*element, range.index_array(stride, 0)) + }), + indexes, + } } } @@ -444,9 +468,23 @@ impl Extend for SlotSet { } } -impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.index_slot)); +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |TypeArrayIndex { + small_slots, + big_slots, + }| { + self.extend([small_slots]); + self.extend([big_slots]); + }, + ) + } +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|v| v.index)); } } @@ -475,6 +513,7 @@ struct Assignment { inputs: SlotSet, conditions: Interned<[Cond]>, insns: Vec, + source_location: SourceLocation, } #[derive(Debug, Default)] @@ -488,19 +527,59 @@ struct SlotAssignments { parts: TypeParts, } +impl SlotAssignments { + fn for_assignment(&mut self, assignment_index: usize) -> SlotAssignmentsForAssignment<'_> { + SlotAssignmentsForAssignment { + parts: &mut self.parts, + assignment_index, + } + } +} + impl StatePartsValue for SlotAssignments { type Value = StatePartAssignments; } +struct SlotAssignmentsForAssignment<'a> { + parts: &'a mut TypeParts, + assignment_index: usize, +} + +impl Extend> for SlotAssignmentsForAssignment<'_> { + fn extend>>(&mut self, iter: T) { + iter.into_iter().for_each(|slot| { + self.parts + .small_slots + .written_slot_to_assignment_indexes_map + .entry(slot) + .or_insert_with(Vec::new) + .push(self.assignment_index) + }); + } +} + +impl Extend> for SlotAssignmentsForAssignment<'_> { + fn extend>>(&mut self, iter: T) { + iter.into_iter().for_each(|slot| { + self.parts + .big_slots + .written_slot_to_assignment_indexes_map + .entry(slot) + .or_insert_with(Vec::new) + .push(self.assignment_index) + }); + } +} + #[derive(Debug)] pub struct Compiler { insns: Insns, base_module: Interned>, modules: HashMap, compiled_values: HashMap>, - compiled_exprs: HashMap<(Interned<[Cond]>, Expr), CompiledExpr>, - compiled_exprs_to_values: - HashMap<(Interned<[Cond]>, CompiledExpr), CompiledValue>, + compiled_exprs: HashMap, CompiledExpr>, + compiled_exprs_to_values: HashMap, CompiledValue>, + decl_conditions: HashMap>, slots_assignments: SlotAssignments, } @@ -513,6 +592,7 @@ impl Compiler { compiled_values: HashMap::new(), compiled_exprs: HashMap::new(), compiled_exprs_to_values: HashMap::new(), + decl_conditions: HashMap::new(), slots_assignments: SlotAssignments::default(), } } @@ -562,32 +642,11 @@ impl Compiler { }); match *target_child.path_element() { TargetPathElement::BundleField(TargetPathBundleField { name }) => { - parent.map(|layout, range| { - let CompiledTypeLayout { - ty: CanonicalType::Bundle(bundle), - layout: _, - body: CompiledTypeLayoutBody::Bundle { fields }, - } = layout - else { - unreachable!(); - }; - let field_index = bundle.name_indexes()[&name]; - ( - fields[field_index].ty, - range.slice(TypeIndexRange::new( - fields[field_index].offset, - fields[field_index].ty.layout.len(), - )), - ) - }) + parent.map_ty(Bundle::from_canonical).field_by_name(name) + } + TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => { + parent.map_ty(Array::from_canonical).element(index) } - TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => parent - .map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { - unreachable!(); - }; - (*element, range.index_array(element.layout.len(), index)) - }), TargetPathElement::DynArrayElement(_) => unreachable!(), } } @@ -597,32 +656,76 @@ impl Compiler { } fn compiled_expr_to_value( &mut self, - conditions: Interned<[Cond]>, expr: CompiledExpr, + source_location: SourceLocation, ) -> CompiledValue { - if let Some(&retval) = self.compiled_exprs_to_values.get(&(conditions, expr)) { + if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { return retval; } + assert!( + expr.static_part.layout.ty.is_passive(), + "invalid expression passed to compiled_expr_to_value -- type must be passive", + ); let CompiledExpr { - static_part: mut retval, - dyn_indexes, + static_part, + indexes, } = expr; - for CompiledExprDynIndex { - index_slot, - len, - stride, - } in dyn_indexes - { - todo!(); - } - self.compiled_exprs_to_values - .insert((conditions, expr), retval); + 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)| { + 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 } fn add_assignment( &mut self, conditions: Interned<[Cond]>, insns: impl IntoIterator, + source_location: SourceLocation, ) { let insns = Vec::from_iter(insns); let assignment_index = self.slots_assignments.assignments.len(); @@ -630,28 +733,50 @@ impl Compiler { for insn in &insns { for InsnField { ty, kind } in insn.fields() { match (kind, ty) { - (InsnFieldKind::Input, InsnFieldType::SmallSlot(&small_slot)) => { - inputs.0.small_slots.insert(small_slot); + (InsnFieldKind::Input, InsnFieldType::SmallSlot(&slot)) => { + inputs.extend([slot]); } - (InsnFieldKind::Input, InsnFieldType::BigSlot(&big_slot)) => { - inputs.0.big_slots.insert(big_slot); + (InsnFieldKind::Input, InsnFieldType::BigSlot(&slot)) => { + inputs.extend([slot]); } - (InsnFieldKind::Output, InsnFieldType::SmallSlot(&small_slot)) => self + ( + InsnFieldKind::Input, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Input, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::SmallSlot(&slot)) => self .slots_assignments - .parts - .small_slots - .written_slot_to_assignment_indexes_map - .entry(small_slot) - .or_insert_with(Vec::new) - .push(assignment_index), - (InsnFieldKind::Output, InsnFieldType::BigSlot(&big_slot)) => self + .for_assignment(assignment_index) + .extend([slot]), + (InsnFieldKind::Output, InsnFieldType::BigSlot(&slot)) => self .slots_assignments - .parts - .big_slots - .written_slot_to_assignment_indexes_map - .entry(big_slot) - .or_insert_with(Vec::new) - .push(assignment_index), + .for_assignment(assignment_index) + .extend([slot]), + ( + InsnFieldKind::Output, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| { + self.slots_assignments + .for_assignment(assignment_index) + .extend([slot]) + }); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| { + self.slots_assignments + .for_assignment(assignment_index) + .extend([slot]) + }); + inputs.extend(array_indexed.indexes); + } ( _, InsnFieldType::SmallUInt(_) @@ -669,11 +794,12 @@ impl Compiler { inputs, conditions, insns, + source_location, }); } fn simple_nary_big_expr( &mut self, - conditions: Interned<[Cond]>, + instantiated_module: InstantiatedModule, dest_ty: CanonicalType, inputs: [Expr; N], make_insns: impl FnOnce( @@ -682,8 +808,9 @@ impl Compiler { ) -> Vec, ) -> CompiledValue { let inputs = inputs.map(|input| { - let input = self.compile_expr(conditions, input); - let input = self.compiled_expr_to_value(conditions, input); + let input = self.compile_expr(instantiated_module, input); + let input = self + .compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); let TypeIndexRange { small_slots, big_slots, @@ -705,15 +832,19 @@ impl Compiler { range, write: None, }; - self.add_assignment(conditions, make_insns(big_slots.start, inputs)); + self.add_assignment( + Interned::default(), + make_insns(big_slots.start, inputs), + instantiated_module.leaf_module().source_location(), + ); retval } fn compile_expr( &mut self, - conditions: Interned<[Cond]>, + instantiated_module: InstantiatedModule, expr: Expr, ) -> CompiledExpr { - if let Some(&retval) = self.compiled_exprs.get(&(conditions, expr)) { + if let Some(&retval) = self.compiled_exprs.get(&expr) { return retval; } let mut cast_bit = |arg: Expr| { @@ -741,7 +872,7 @@ impl Compiler { CanonicalType::Reset(_) => false, CanonicalType::Clock(_) => false, }; - self.simple_nary_big_expr(conditions, Expr::ty(expr), [arg], |dest, [src]| { + self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| { match (src_signed, dest_signed) { (false, false) | (true, true) => { vec![Insn::Copy { dest, src }] @@ -762,23 +893,33 @@ impl Compiler { }; let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) { ExprEnum::UIntLiteral(expr) => self - .simple_nary_big_expr(conditions, expr.ty().canonical(), [], |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }) + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: expr.to_bigint().intern_sized(), + }] + }, + ) .into(), ExprEnum::SIntLiteral(expr) => self - .simple_nary_big_expr(conditions, expr.ty().canonical(), [], |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }) + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: expr.to_bigint().intern_sized(), + }] + }, + ) .into(), ExprEnum::BoolLiteral(expr) => self - .simple_nary_big_expr(conditions, Bool.canonical(), [], |dest, []| { + .simple_nary_big_expr(instantiated_module, Bool.canonical(), [], |dest, []| { vec![Insn::Const { dest, value: BigInt::from(expr).intern_sized(), @@ -791,7 +932,7 @@ impl Compiler { ExprEnum::Uninit(expr) => todo!(), ExprEnum::NotU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Expr::ty(expr.arg()).canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -805,7 +946,7 @@ impl Compiler { .into(), ExprEnum::NotS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Expr::ty(expr.arg()).canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::NotS { dest, src }], @@ -813,7 +954,7 @@ impl Compiler { .into(), ExprEnum::NotB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Expr::ty(expr.arg()).canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -827,7 +968,7 @@ impl Compiler { .into(), ExprEnum::Neg(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::Neg { dest, src }], @@ -835,7 +976,7 @@ impl Compiler { .into(), ExprEnum::BitAndU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -843,7 +984,7 @@ impl Compiler { .into(), ExprEnum::BitAndS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -851,7 +992,7 @@ impl Compiler { .into(), ExprEnum::BitAndB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], @@ -859,7 +1000,7 @@ impl Compiler { .into(), ExprEnum::BitOrU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -867,7 +1008,7 @@ impl Compiler { .into(), ExprEnum::BitOrS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -875,7 +1016,7 @@ impl Compiler { .into(), ExprEnum::BitOrB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], @@ -883,7 +1024,7 @@ impl Compiler { .into(), ExprEnum::BitXorU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -891,7 +1032,7 @@ impl Compiler { .into(), ExprEnum::BitXorS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -899,7 +1040,7 @@ impl Compiler { .into(), ExprEnum::BitXorB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], @@ -907,7 +1048,7 @@ impl Compiler { .into(), ExprEnum::AddU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], @@ -915,7 +1056,7 @@ impl Compiler { .into(), ExprEnum::AddS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], @@ -923,7 +1064,7 @@ impl Compiler { .into(), ExprEnum::SubU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| { @@ -938,7 +1079,7 @@ impl Compiler { .into(), ExprEnum::SubS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::SubS { dest, lhs, rhs }], @@ -946,7 +1087,7 @@ impl Compiler { .into(), ExprEnum::MulU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], @@ -954,7 +1095,7 @@ impl Compiler { .into(), ExprEnum::MulS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], @@ -962,7 +1103,7 @@ impl Compiler { .into(), ExprEnum::DivU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], @@ -970,7 +1111,7 @@ impl Compiler { .into(), ExprEnum::DivS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], @@ -978,7 +1119,7 @@ impl Compiler { .into(), ExprEnum::RemU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], @@ -986,7 +1127,7 @@ impl Compiler { .into(), ExprEnum::RemS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], @@ -994,7 +1135,7 @@ impl Compiler { .into(), ExprEnum::DynShlU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], @@ -1002,7 +1143,7 @@ impl Compiler { .into(), ExprEnum::DynShlS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], @@ -1010,7 +1151,7 @@ impl Compiler { .into(), ExprEnum::DynShrU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], @@ -1018,7 +1159,7 @@ impl Compiler { .into(), ExprEnum::DynShrS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], @@ -1026,7 +1167,7 @@ impl Compiler { .into(), ExprEnum::FixedShlU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -1040,7 +1181,7 @@ impl Compiler { .into(), ExprEnum::FixedShlS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -1054,7 +1195,7 @@ impl Compiler { .into(), ExprEnum::FixedShrU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -1068,7 +1209,7 @@ impl Compiler { .into(), ExprEnum::FixedShrS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.lhs())], |dest, [lhs]| { @@ -1082,7 +1223,7 @@ impl Compiler { .into(), ExprEnum::CmpLtB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -1090,7 +1231,7 @@ impl Compiler { .into(), ExprEnum::CmpLeB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -1098,7 +1239,7 @@ impl Compiler { .into(), ExprEnum::CmpGtB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1107,7 +1248,7 @@ impl Compiler { .into(), ExprEnum::CmpGeB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1116,7 +1257,7 @@ impl Compiler { .into(), ExprEnum::CmpEqB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -1124,7 +1265,7 @@ impl Compiler { .into(), ExprEnum::CmpNeB(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -1132,7 +1273,7 @@ impl Compiler { .into(), ExprEnum::CmpLtU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -1140,7 +1281,7 @@ impl Compiler { .into(), ExprEnum::CmpLeU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -1148,7 +1289,7 @@ impl Compiler { .into(), ExprEnum::CmpGtU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1157,7 +1298,7 @@ impl Compiler { .into(), ExprEnum::CmpGeU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1166,7 +1307,7 @@ impl Compiler { .into(), ExprEnum::CmpEqU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -1174,7 +1315,7 @@ impl Compiler { .into(), ExprEnum::CmpNeU(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -1182,7 +1323,7 @@ impl Compiler { .into(), ExprEnum::CmpLtS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], @@ -1190,7 +1331,7 @@ impl Compiler { .into(), ExprEnum::CmpLeS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], @@ -1198,7 +1339,7 @@ impl Compiler { .into(), ExprEnum::CmpGtS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1207,7 +1348,7 @@ impl Compiler { .into(), ExprEnum::CmpGeS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), // swap both comparison direction and lhs/rhs [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], @@ -1216,7 +1357,7 @@ impl Compiler { .into(), ExprEnum::CmpEqS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], @@ -1224,7 +1365,7 @@ impl Compiler { .into(), ExprEnum::CmpNeS(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, Bool.canonical(), [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], @@ -1232,7 +1373,7 @@ impl Compiler { .into(), ExprEnum::CastUIntToUInt(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -1244,10 +1385,23 @@ impl Compiler { }, ) .into(), - ExprEnum::CastUIntToSInt(expr) => todo!(), + ExprEnum::CastUIntToSInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToSInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), ExprEnum::CastSIntToUInt(expr) => self .simple_nary_big_expr( - conditions, + instantiated_module, expr.ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { @@ -1259,7 +1413,20 @@ impl Compiler { }, ) .into(), - ExprEnum::CastSIntToSInt(expr) => todo!(), + ExprEnum::CastSIntToSInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToSInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), ExprEnum::CastBoolToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::CastBoolToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::CastUIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), @@ -1287,34 +1454,190 @@ impl Compiler { ExprEnum::CastClockToBool(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::CastClockToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), ExprEnum::CastClockToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::FieldAccess(expr) => todo!(), + ExprEnum::FieldAccess(expr) => self + .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .map_ty(Bundle::from_canonical) + .field_by_index(expr.field_index()), ExprEnum::VariantAccess(expr) => todo!(), - ExprEnum::ArrayIndex(expr) => todo!(), + ExprEnum::ArrayIndex(expr) => self + .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .map_ty(Array::from_canonical) + .element(expr.element_index()), ExprEnum::DynArrayIndex(expr) => todo!(), - ExprEnum::ReduceBitAndU(expr) => todo!(), - ExprEnum::ReduceBitAndS(expr) => todo!(), - ExprEnum::ReduceBitOrU(expr) => todo!(), - ExprEnum::ReduceBitOrS(expr) => todo!(), - ExprEnum::ReduceBitXorU(expr) => todo!(), - ExprEnum::ReduceBitXorS(expr) => todo!(), + ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical( + expr.arg() + .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), + ), + ) + } + .into(), + ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical( + expr.arg() + .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), + ), + ) + } + .into(), + ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + ) + } + .into(), + ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + ) + } + .into(), + ExprEnum::ReduceBitXorU(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::<1>::TYPE.canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::ReduceBitXor { + dest, + src, + input_width: Expr::ty(expr.arg()).width(), + }] + }, + ) + .into(), + ExprEnum::ReduceBitXorS(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::<1>::TYPE.canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::ReduceBitXor { + dest, + src, + input_width: Expr::ty(expr.arg()).width(), + }] + }, + ) + .into(), ExprEnum::SliceUInt(expr) => todo!(), ExprEnum::SliceSInt(expr) => todo!(), ExprEnum::CastToBits(expr) => todo!(), ExprEnum::CastBitsTo(expr) => todo!(), - ExprEnum::ModuleIO(expr) => todo!(), - ExprEnum::Instance(expr) => todo!(), - ExprEnum::Wire(expr) => todo!(), - ExprEnum::Reg(expr) => todo!(), - ExprEnum::MemPort(expr) => todo!(), + ExprEnum::ModuleIO(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Instance(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Wire(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Reg(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::MemPort(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), }; - self.compiled_exprs.insert((conditions, expr), retval); + self.compiled_exprs.insert(expr, retval); retval } + fn compile_simple_connect( + &mut self, + conditions: Interned<[Cond]>, + lhs: CompiledExpr, + rhs: CompiledValue, + source_location: SourceLocation, + ) { + let CompiledExpr { + static_part: lhs_static_part, + indexes, + } = lhs; + let (lhs_layout, lhs_range) = lhs_static_part.write(); + assert!( + lhs_layout.ty.is_passive(), + "invalid expression passed to compile_simple_connect -- type must be passive", + ); + let TypeIndexRange { + small_slots, + big_slots, + } = lhs_range; + self.add_assignment( + conditions, + small_slots + .iter() + .zip(rhs.range.small_slots.iter()) + .map(|(base, src)| { + if indexes.small_slots.is_empty() { + Insn::CopySmall { dest: base, src } + } else { + Insn::WriteSmallIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.small_slots, + }, + src, + } + } + }) + .chain( + big_slots + .iter() + .zip(rhs.range.big_slots.iter()) + .map(|(base, src)| { + if indexes.big_slots.is_empty() { + Insn::Copy { dest: base, src } + } else { + Insn::WriteIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.big_slots, + }, + src, + } + } + }), + ), + source_location, + ); + } fn compile_connect( &mut self, - parent_module: Interned, - conditions: Interned<[Cond]>, + lhs_instantiated_module: InstantiatedModule, + lhs_conditions: Interned<[Cond]>, lhs: Expr, + rhs_instantiated_module: InstantiatedModule, + rhs_conditions: Interned<[Cond]>, mut rhs: Expr, source_location: SourceLocation, ) { @@ -1336,9 +1659,11 @@ impl Compiler { let rhs = Expr::::from_canonical(rhs); for index in 0..lhs_ty.len() { self.compile_connect( - parent_module, - conditions, + lhs_instantiated_module, + lhs_conditions, lhs[index], + rhs_instantiated_module, + rhs_conditions, rhs[index], source_location, ); @@ -1372,20 +1697,30 @@ impl Compiler { { assert_eq!(name, rhs_field.name); assert_eq!(flipped, rhs_field.flipped); - let mut lhs_expr = - crate::expr::ops::FieldAccess::new_by_index(lhs, field_index).to_expr(); - let mut rhs_expr = - crate::expr::ops::FieldAccess::new_by_index(rhs, field_index).to_expr(); + let lhs_expr = ops::FieldAccess::new_by_index(lhs, field_index).to_expr(); + let rhs_expr = ops::FieldAccess::new_by_index(rhs, field_index).to_expr(); if flipped { - mem::swap(&mut lhs_expr, &mut rhs_expr); + // swap lhs/rhs + self.compile_connect( + rhs_instantiated_module, + rhs_conditions, + rhs_expr, + lhs_instantiated_module, + lhs_conditions, + lhs_expr, + source_location, + ); + } else { + self.compile_connect( + lhs_instantiated_module, + lhs_conditions, + lhs_expr, + rhs_instantiated_module, + rhs_conditions, + rhs_expr, + source_location, + ); } - self.compile_connect( - parent_module, - conditions, - lhs_expr, - rhs_expr, - source_location, - ); } return; } @@ -1395,10 +1730,93 @@ impl Compiler { CanonicalType::Clock(_) => unreachable!(), } } - let lhs = self.compile_expr(conditions, lhs); - let rhs = self.compile_expr(conditions, rhs); - let rhs = self.compiled_expr_to_value(conditions, rhs); - todo!(); + let Some(target) = lhs.target() else { + unreachable!("connect lhs must have target"); + }; + let lhs_decl_conditions = self.decl_conditions[&TargetInInstantiatedModule { + instantiated_module: lhs_instantiated_module, + target: target.base().into(), + }]; + let lhs = self.compile_expr(lhs_instantiated_module, lhs); + let rhs = self.compile_expr(rhs_instantiated_module, rhs); + let rhs = self.compiled_expr_to_value(rhs, source_location); + self.compile_simple_connect( + lhs_conditions[lhs_decl_conditions.len()..].intern(), + lhs, + rhs, + source_location, + ); + } + fn compile_declaration( + &mut self, + declaration: StmtDeclaration, + parent_module: Interned, + conditions: Interned<[Cond]>, + ) { + let target_base: TargetBase = match &declaration { + StmtDeclaration::Wire(v) => v.wire.into(), + StmtDeclaration::Reg(v) => v.reg.into(), + StmtDeclaration::Instance(v) => v.instance.into(), + }; + let target = TargetInInstantiatedModule { + instantiated_module: *parent_module, + target: target_base.into(), + }; + self.decl_conditions.insert(target, conditions); + self.compile_value(target); + match declaration { + StmtDeclaration::Wire(StmtWire { annotations, wire }) => {} + StmtDeclaration::Reg(StmtReg { annotations, reg }) => { + todo!(); + } + StmtDeclaration::Instance(StmtInstance { + annotations, + instance, + }) => { + let inner_instantiated_module = InstantiatedModule::Child { + parent: parent_module, + instance: instance.intern_sized(), + } + .intern_sized(); + let instance_expr = instance.to_expr(); + self.compile_module(inner_instantiated_module); + for (field_index, module_io) in + instance.instantiated().module_io().into_iter().enumerate() + { + let instance_field = + ops::FieldAccess::new_by_index(instance_expr, field_index).to_expr(); + match Expr::flow(instance_field) { + Flow::Source => { + // we need to supply the value to the instance since the + // parent module expects to read from the instance + self.compile_connect( + *parent_module, + conditions, + instance_field, + *inner_instantiated_module, + Interned::default(), + module_io.module_io.to_expr(), + instance.source_location(), + ); + } + Flow::Sink => { + // we need to take the value from the instance since the + // parent module expects to write to the instance + self.compile_connect( + *inner_instantiated_module, + Interned::default(), + module_io.module_io.to_expr(), + *parent_module, + conditions, + instance_field, + instance.source_location(), + ); + } + Flow::Duplex => unreachable!(), + } + } + } + } } fn compile_block( &mut self, @@ -1416,22 +1834,23 @@ impl Compiler { lhs, rhs, source_location, - }) => self.compile_connect(parent_module, conditions, lhs, rhs, source_location), - Stmt::Formal(StmtFormal { - kind, - clk, - pred, - en, - text, + }) => self.compile_connect( + *parent_module, + conditions, + lhs, + *parent_module, + conditions, + rhs, source_location, - }) => todo!("implement simulating formal statements"), + ), + Stmt::Formal(StmtFormal { .. }) => todo!("implement simulating formal statements"), Stmt::If(StmtIf { cond, source_location, blocks: [then_block, else_block], }) => { let cond = self - .compile_expr(conditions, Expr::canonical(cond)) + .compile_expr(*parent_module, Expr::canonical(cond)) .map_ty(Bool::from_canonical); self.compile_block( parent_module, @@ -1456,7 +1875,7 @@ impl Compiler { blocks, }) => { let enum_expr = self - .compile_expr(conditions, Expr::canonical(expr)) + .compile_expr(*parent_module, Expr::canonical(expr)) .map_ty(Enum::from_canonical); for (variant_index, block) in blocks.into_iter().enumerate() { self.compile_block( @@ -1472,55 +1891,9 @@ impl Compiler { ); } } - Stmt::Declaration(declaration) => match declaration { - StmtDeclaration::Wire(StmtWire { annotations, wire }) => { - self.compile_value(TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: wire.into(), - }); - } - StmtDeclaration::Reg(StmtReg { annotations, reg }) => { - self.compile_value(TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: reg.into(), - }); - todo!(); - } - StmtDeclaration::Instance(StmtInstance { - annotations, - instance, - }) => { - let CompiledValue { - layout: - CompiledTypeLayout { - ty: value_ty, - layout: ty_layout, - body: CompiledTypeLayoutBody::Bundle { fields }, - }, - range: value_range, - write: None, - } = self.compile_value(TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: instance.into(), - }) - else { - unreachable!(); - }; - let CompiledModule { module_io } = *self.compile_module( - InstantiatedModule::Child { - parent: parent_module, - instance: instance.intern_sized(), - } - .intern_sized(), - ); - for (module_io, CompiledBundleField { offset, ty }) in - module_io.into_iter().zip(fields) - { - todo!(); - } - todo!() - } - }, + Stmt::Declaration(declaration) => { + self.compile_declaration(declaration, parent_module, conditions); + } } } } @@ -1556,7 +1929,7 @@ impl Compiler { } pub fn compile(mut self) -> Compiled { self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); - + todo!("handle self.slots_assignments"); Compiled { insns: Insns::from(self.insns).intern_sized(), modules: self.modules, diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 8fc9038..e89628c 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -109,6 +109,8 @@ insn_field_enum! { pub(crate) enum InsnFieldType { SmallSlot(Transform::Type>), BigSlot(Transform::Type>), + SmallSlotArrayIndexed(Transform::Type>), + BigSlotArrayIndexed(Transform::Type>), SmallUInt(Transform::Type), SmallSInt(Transform::Type), InternedBigInt(Transform::Type>), @@ -787,6 +789,167 @@ macro_rules! make_state_part_kinds { *self.orig_pc = self.pc; } } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexes { + $(pub(crate) $type_field: Interned<[StatePartArrayIndex<$TypeKind>]>,)* + } + + impl TypeArrayIndexes { + pub(crate) fn as_ref(&self) -> TypeArrayIndexesRef<'_> { + TypeArrayIndexesRef { + $($type_field: &self.$type_field,)* + } + } + #[must_use] + pub(crate) fn join(self, next: TypeArrayIndex) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: Interned::from_iter(self.$type_field.iter().copied().chain([next.$type_field])),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndex { + $(pub(crate) $type_field: StatePartArrayIndex<$TypeKind>,)* + } + + impl TypeArrayIndex { + pub(crate) fn from_parts(index: StatePartIndex, len: usize, stride: TypeLen) -> Self { + Self { + $($type_field: StatePartArrayIndex { + index, + len, + stride: stride.$type_field, + },)* + } + } + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len; + $(assert_eq!(self.$type_field.len, len, "array length mismatch");)* + len + } + pub(crate) fn index(self) -> StatePartIndex { + let index = self.small_slots.index; + $(assert_eq!(self.$type_field.index, index, "array index mismatch");)* + index + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn stride(self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.stride,)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexesRef<'a> { + $(pub(crate) $type_field: &'a [StatePartArrayIndex<$TypeKind>],)* + } + + impl<'a> TypeArrayIndexesRef<'a> { + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len(); + $(assert_eq!(self.$type_field.len(), len, "indexes count mismatch");)* + len + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn iter(self) -> impl Iterator + 'a { + (0..self.len()).map(move |i| TypeArrayIndex { + $($type_field: self.$type_field[i],)* + }) + } + pub(crate) fn for_each_offset( + self, + mut f: impl FnMut(TypeIndex), + ) { + self.for_each_offset2(TypeIndex { + $($type_field: StatePartIndex { + value: 0, + _phantom: PhantomData, + },)* + }, &mut f); + } + pub(crate) fn split_first(self) -> Option<(TypeArrayIndex, Self)> { + $(let $type_field = self.$type_field.split_first()?;)* + let next = TypeArrayIndex { + $($type_field: *$type_field.0,)* + }; + let rest = TypeArrayIndexesRef { + $($type_field: $type_field.1,)* + }; + Some((next, rest)) + } + pub(crate) fn for_each_offset2( + self, + base_offset: TypeIndex, + f: &mut (impl FnMut(TypeIndex) + ?Sized), + ) { + if let Some((next, rest)) = self.split_first() { + let stride = next.stride(); + for index in 0..next.len().try_into().expect("array too big") { + let mut offset = TypeIndex { + $($type_field: StatePartIndex { + value: stride + .$type_field + .value + .checked_mul(index) + .expect("array too big"), + _phantom: PhantomData, + },)* + }; + $(offset.$type_field.value = + base_offset + .$type_field + .value + .checked_add(offset.$type_field.value) + .expect("array too big");)* + rest.for_each_offset2(offset, f); + } + } else { + $(assert!(self.$type_field.is_empty(), "indexes count mismatch");)* + f(base_offset); + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndexed { + $(pub(crate) $type_field: StatePartArrayIndexed<$TypeKind>,)* + } + + impl TypeArrayIndexed { + pub(crate) fn from_parts(base: TypeIndex, indexes: TypeArrayIndexes) -> Self { + Self { + $($type_field: StatePartArrayIndexed { + base: base.$type_field, + indexes: indexes.$type_field, + },)* + } + } + pub(crate) fn base(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.base,)* + } + } + pub(crate) fn indexes(self) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: self.$type_field.indexes,)* + } + } + } + + impl From for TypeArrayIndexed { + fn from(value: TypeIndex) -> Self { + TypeArrayIndexed { + $($type_field: value.$type_field.into(),)* + } + } + } }; } @@ -933,6 +1096,12 @@ impl SlotDebugData { ty: self.ty, } } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + name: Interned::default(), + ty: self.ty, + } + } } impl, BK: InsnsBuildingKind> StatePartLayout { @@ -946,6 +1115,16 @@ impl, BK: InsnsBuildingKind> StatePa _phantom: PhantomData, } } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + debug_data: self + .debug_data + .iter() + .map(|v| v.with_anonymized_debug_info()) + .collect(), + _phantom: PhantomData, + } + } } impl TypeLayout { @@ -955,6 +1134,63 @@ impl TypeLayout { big_slots: self.big_slots.with_prefixed_debug_names(prefix), } } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + small_slots: self.small_slots.with_anonymized_debug_info(), + big_slots: self.big_slots.with_anonymized_debug_info(), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct StatePartArrayIndex { + pub(crate) index: StatePartIndex, + pub(crate) len: usize, + pub(crate) stride: StatePartLen, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub(crate) struct StatePartArrayIndexed { + pub(crate) base: StatePartIndex, + pub(crate) indexes: Interned<[StatePartArrayIndex]>, +} + +impl From> for StatePartArrayIndexed { + fn from(base: StatePartIndex) -> Self { + Self { + base, + indexes: Interned::default(), + } + } +} + +impl StatePartArrayIndexed { + pub(crate) fn for_each_target2( + base: StatePartIndex, + indexes: &[StatePartArrayIndex], + f: &mut (impl FnMut(StatePartIndex) + ?Sized), + ) { + if let [next, rest @ ..] = indexes { + for i in 0..next.len.try_into().expect("array too big") { + Self::for_each_target2( + StatePartIndex { + value: base + .value + .checked_add(next.stride.value.checked_mul(i).expect("array too big")) + .expect("array too big"), + _phantom: PhantomData, + }, + rest, + f, + ); + } + } else { + f(base); + } + } + pub(crate) fn for_each_target(self, mut f: impl FnMut(StatePartIndex)) { + Self::for_each_target2(self.base, &self.indexes, &mut f); + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1435,6 +1671,26 @@ impl State { } } +impl BorrowedState<'_> { + fn eval_array_indexed( + &self, + array_indexed: StatePartArrayIndexed, + ) -> Option> { + let StatePartArrayIndexed { + base: mut retval, + indexes, + } = array_indexed; + for StatePartArrayIndex { index, len, stride } in indexes { + let index = self.small_slots[index]; + if index >= len as SmallUInt { + return None; + } + retval.value += stride.value * index as u32; + } + Some(retval) + } +} + fn bigint_pow2(width: usize) -> Interned { #[derive(Copy, Clone, PartialEq, Eq, Hash)] struct MyMemoize; @@ -1515,6 +1771,69 @@ impl_insns! { } next!(); } + CopySmall { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartIndex, + } => { + state.small_slots[dest] = state.small_slots[src]; + next!(); + } + ReadIndexed { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartArrayIndexed, + } => { + if let Some(src) = state.eval_array_indexed(src) { + if dest != src { + let [dest, src] = state.big_slots.get_many_mut([dest, src]); + dest.clone_from(src); + } + } else { + state.big_slots[dest] = BigInt::ZERO; + } + next!(); + } + ReadSmallIndexed { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartArrayIndexed, + } => { + if let Some(src) = state.eval_array_indexed(src) { + state.small_slots[dest] = state.small_slots[src]; + } else { + state.small_slots[dest] = 0; + } + next!(); + } + WriteIndexed { + #[kind = Output] + dest: StatePartArrayIndexed, + #[kind = Input] + src: StatePartIndex, + } => { + if let Some(dest) = state.eval_array_indexed(dest) { + if dest != src { + let [dest, src] = state.big_slots.get_many_mut([dest, src]); + dest.clone_from(src); + } + } + next!(); + } + WriteSmallIndexed { + #[kind = Output] + dest: StatePartArrayIndexed, + #[kind = Input] + src: StatePartIndex, + } => { + if let Some(dest) = state.eval_array_indexed(dest) { + state.small_slots[dest] = state.small_slots[src]; + } + next!(); + } CastToSInt { #[kind = Output] dest: StatePartIndex, @@ -1792,6 +2111,22 @@ impl_insns! { state.big_slots[dest] = value; next!(); } + ReduceBitXor { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartIndex, + #[kind = Immediate] + input_width: usize, + } => { + let src = &state.big_slots[src]; + let src = src & &*bigint_mask(input_width); + let value = BigInt::from( + src.to_biguint().expect("known to be non-negative").count_ones() % 2, + ); + state.big_slots[dest] = value; + next!(); + } Const { #[kind = Output] dest: StatePartIndex,