Compare commits
	
		
			2 commits
		
	
	
		
			4422157db8
			...
			42afd2da0e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 42afd2da0e | |||
| 15bc304bb6 | 
					 4 changed files with 486 additions and 120 deletions
				
			
		|  | @ -3,7 +3,7 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|     array::Array, |     array::Array, | ||||||
|     bundle::{Bundle, BundleField}, |     bundle::{Bundle, BundleField}, | ||||||
|     expr::Flow, |     expr::{Expr, Flow, ToExpr}, | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|     memory::{DynPortType, MemPort}, |     memory::{DynPortType, MemPort}, | ||||||
|     module::{Instance, ModuleIO, TargetName}, |     module::{Instance, ModuleIO, TargetName}, | ||||||
|  | @ -195,6 +195,16 @@ macro_rules! impl_target_base { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         impl ToExpr for $TargetBase { | ||||||
|  |             type Type = CanonicalType; | ||||||
|  | 
 | ||||||
|  |             fn to_expr(&self) -> Expr<Self::Type> { | ||||||
|  |                 match self { | ||||||
|  |                     $(Self::$Variant(v) => Expr::canonical(v.to_expr()),)* | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -59,7 +59,7 @@ enum CondBody { | ||||||
|         cond: CompiledValue<Bool>, |         cond: CompiledValue<Bool>, | ||||||
|     }, |     }, | ||||||
|     MatchArm { |     MatchArm { | ||||||
|         enum_expr: CompiledValue<Enum>, |         discriminant: StatePartIndex<StatePartKindSmallSlots>, | ||||||
|         variant_index: usize, |         variant_index: usize, | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
|  | @ -246,12 +246,6 @@ impl<T: Type> CompiledValue<T> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl CompiledValue<Enum> { |  | ||||||
|     fn add_discriminant_to_set(self, inputs: &mut SlotSet) { |  | ||||||
|         inputs.extend([self.range]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl CompiledValue<Bundle> { | impl CompiledValue<Bundle> { | ||||||
|     fn field_by_index(self, field_index: usize) -> CompiledValue<CanonicalType> { |     fn field_by_index(self, field_index: usize) -> CompiledValue<CanonicalType> { | ||||||
|         self.map(|layout, range| { |         self.map(|layout, range| { | ||||||
|  | @ -957,9 +951,9 @@ impl Extend<CondBody> for SlotSet { | ||||||
|                 self.extend([cond.range]); |                 self.extend([cond.range]); | ||||||
|             } |             } | ||||||
|             CondBody::MatchArm { |             CondBody::MatchArm { | ||||||
|                 enum_expr, |                 discriminant, | ||||||
|                 variant_index: _, |                 variant_index: _, | ||||||
|             } => enum_expr.add_discriminant_to_set(self), |             } => self.extend([discriminant]), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1271,11 +1265,14 @@ impl Compiler { | ||||||
|     } |     } | ||||||
|     fn make_trace_scalar_helper( |     fn make_trace_scalar_helper( | ||||||
|         &mut self, |         &mut self, | ||||||
|         target: TargetInInstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|  |         target: Expr<CanonicalType>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|         small_kind: impl FnOnce(StatePartIndex<StatePartKindSmallSlots>) -> SimTraceKind, |         small_kind: impl FnOnce(StatePartIndex<StatePartKindSmallSlots>) -> SimTraceKind, | ||||||
|         big_kind: impl FnOnce(StatePartIndex<StatePartKindBigSlots>) -> SimTraceKind, |         big_kind: impl FnOnce(StatePartIndex<StatePartKindBigSlots>) -> SimTraceKind, | ||||||
|     ) -> TraceScalarId { |     ) -> TraceScalarId { | ||||||
|         let compiled_value = self.compile_value(target); |         let compiled_value = self.compile_expr(instantiated_module, target); | ||||||
|  |         let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); | ||||||
|         self.new_sim_trace(match compiled_value.range.len() { |         self.new_sim_trace(match compiled_value.range.len() { | ||||||
|             TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), |             TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), | ||||||
|             TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), |             TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), | ||||||
|  | @ -1284,14 +1281,18 @@ impl Compiler { | ||||||
|     } |     } | ||||||
|     fn make_trace_scalar( |     fn make_trace_scalar( | ||||||
|         &mut self, |         &mut self, | ||||||
|         target: TargetInInstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|  |         target: Expr<CanonicalType>, | ||||||
|         name: Interned<str>, |         name: Interned<str>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|     ) -> TraceDecl { |     ) -> TraceDecl { | ||||||
|         let flow = target.target.flow(); |         let flow = Expr::flow(target); | ||||||
|         match target.target.canonical_ty() { |         match Expr::ty(target) { | ||||||
|             CanonicalType::UInt(ty) => TraceUInt { |             CanonicalType::UInt(ty) => TraceUInt { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallUInt { index, ty }, |                     |index| SimTraceKind::SmallUInt { index, ty }, | ||||||
|                     |index| SimTraceKind::BigUInt { index, ty }, |                     |index| SimTraceKind::BigUInt { index, ty }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1302,7 +1303,9 @@ impl Compiler { | ||||||
|             .into(), |             .into(), | ||||||
|             CanonicalType::SInt(ty) => TraceSInt { |             CanonicalType::SInt(ty) => TraceSInt { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallSInt { index, ty }, |                     |index| SimTraceKind::SmallSInt { index, ty }, | ||||||
|                     |index| SimTraceKind::BigSInt { index, ty }, |                     |index| SimTraceKind::BigSInt { index, ty }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1313,7 +1316,9 @@ impl Compiler { | ||||||
|             .into(), |             .into(), | ||||||
|             CanonicalType::Bool(_) => TraceBool { |             CanonicalType::Bool(_) => TraceBool { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallBool { index }, |                     |index| SimTraceKind::SmallBool { index }, | ||||||
|                     |index| SimTraceKind::BigBool { index }, |                     |index| SimTraceKind::BigBool { index }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1324,10 +1329,11 @@ impl Compiler { | ||||||
|             CanonicalType::Array(_) => unreachable!(), |             CanonicalType::Array(_) => unreachable!(), | ||||||
|             CanonicalType::Enum(ty) => { |             CanonicalType::Enum(ty) => { | ||||||
|                 assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); |                 assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); | ||||||
|                 let compiled_value = self.compile_value(target); |                 let compiled_value = self.compile_expr(instantiated_module, target); | ||||||
|  |                 let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); | ||||||
|                 let discriminant = self.compile_enum_discriminant( |                 let discriminant = self.compile_enum_discriminant( | ||||||
|                     compiled_value.map_ty(Enum::from_canonical), |                     compiled_value.map_ty(Enum::from_canonical), | ||||||
|                     target.target.base().source_location(), |                     source_location, | ||||||
|                 ); |                 ); | ||||||
|                 TraceFieldlessEnum { |                 TraceFieldlessEnum { | ||||||
|                     id: self.new_sim_trace(SimTraceKind::EnumDiscriminant { |                     id: self.new_sim_trace(SimTraceKind::EnumDiscriminant { | ||||||
|  | @ -1343,7 +1349,9 @@ impl Compiler { | ||||||
|             CanonicalType::Bundle(_) => unreachable!(), |             CanonicalType::Bundle(_) => unreachable!(), | ||||||
|             CanonicalType::AsyncReset(_) => TraceAsyncReset { |             CanonicalType::AsyncReset(_) => TraceAsyncReset { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallAsyncReset { index }, |                     |index| SimTraceKind::SmallAsyncReset { index }, | ||||||
|                     |index| SimTraceKind::BigAsyncReset { index }, |                     |index| SimTraceKind::BigAsyncReset { index }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1353,7 +1361,9 @@ impl Compiler { | ||||||
|             .into(), |             .into(), | ||||||
|             CanonicalType::SyncReset(_) => TraceSyncReset { |             CanonicalType::SyncReset(_) => TraceSyncReset { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallSyncReset { index }, |                     |index| SimTraceKind::SmallSyncReset { index }, | ||||||
|                     |index| SimTraceKind::BigSyncReset { index }, |                     |index| SimTraceKind::BigSyncReset { index }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1364,7 +1374,9 @@ impl Compiler { | ||||||
|             CanonicalType::Reset(_) => unreachable!(), |             CanonicalType::Reset(_) => unreachable!(), | ||||||
|             CanonicalType::Clock(_) => TraceClock { |             CanonicalType::Clock(_) => TraceClock { | ||||||
|                 id: self.make_trace_scalar_helper( |                 id: self.make_trace_scalar_helper( | ||||||
|  |                     instantiated_module, | ||||||
|                     target, |                     target, | ||||||
|  |                     source_location, | ||||||
|                     |index| SimTraceKind::SmallClock { index }, |                     |index| SimTraceKind::SmallClock { index }, | ||||||
|                     |index| SimTraceKind::BigClock { index }, |                     |index| SimTraceKind::BigClock { index }, | ||||||
|                 ), |                 ), | ||||||
|  | @ -1376,56 +1388,89 @@ impl Compiler { | ||||||
|     } |     } | ||||||
|     fn make_trace_decl_child( |     fn make_trace_decl_child( | ||||||
|         &mut self, |         &mut self, | ||||||
|         target: TargetInInstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|  |         target: Expr<CanonicalType>, | ||||||
|         name: Interned<str>, |         name: Interned<str>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|     ) -> TraceDecl { |     ) -> TraceDecl { | ||||||
|         match target.target.canonical_ty() { |         match Expr::ty(target) { | ||||||
|             CanonicalType::Array(ty) => { |             CanonicalType::Array(ty) => { | ||||||
|                 let elements = Interned::from_iter((0..ty.len()).map(|index| { |                 let elements = Interned::from_iter((0..ty.len()).map(|index| { | ||||||
|                     self.make_trace_decl_child( |                     self.make_trace_decl_child( | ||||||
|                         TargetInInstantiatedModule { |                         instantiated_module, | ||||||
|                             instantiated_module: target.instantiated_module, |                         Expr::<Array>::from_canonical(target)[index], | ||||||
|                             target: target.target.join( |  | ||||||
|                                 TargetPathElement::from(TargetPathArrayElement { index }) |  | ||||||
|                                     .intern_sized(), |  | ||||||
|                             ), |  | ||||||
|                         }, |  | ||||||
|                         Intern::intern_owned(format!("[{index}]")), |                         Intern::intern_owned(format!("[{index}]")), | ||||||
|  |                         source_location, | ||||||
|                     ) |                     ) | ||||||
|                 })); |                 })); | ||||||
|                 TraceArray { |                 TraceArray { | ||||||
|                     name, |                     name, | ||||||
|                     elements, |                     elements, | ||||||
|                     ty, |                     ty, | ||||||
|                     flow: target.target.flow(), |                     flow: Expr::flow(target), | ||||||
|                 } |                 } | ||||||
|                 .into() |                 .into() | ||||||
|             } |             } | ||||||
|             CanonicalType::Enum(ty) => { |             CanonicalType::Enum(ty) => { | ||||||
|                 if ty.variants().iter().all(|v| v.ty.is_none()) { |                 if ty.variants().iter().all(|v| v.ty.is_none()) { | ||||||
|                     self.make_trace_scalar(target, name) |                     self.make_trace_scalar(instantiated_module, target, name, source_location) | ||||||
|                 } else { |                 } else { | ||||||
|                     todo!() |                     let flow = Expr::flow(target); | ||||||
|  |                     let compiled_value = self.compile_expr(instantiated_module, target); | ||||||
|  |                     let compiled_value = | ||||||
|  |                         self.compiled_expr_to_value(compiled_value, source_location); | ||||||
|  |                     let discriminant = self.compile_enum_discriminant( | ||||||
|  |                         compiled_value.map_ty(Enum::from_canonical), | ||||||
|  |                         source_location, | ||||||
|  |                     ); | ||||||
|  |                     let discriminant = TraceEnumDiscriminant { | ||||||
|  |                         id: self.new_sim_trace(SimTraceKind::EnumDiscriminant { | ||||||
|  |                             index: discriminant, | ||||||
|  |                             ty, | ||||||
|  |                         }), | ||||||
|  |                         name, | ||||||
|  |                         ty, | ||||||
|  |                         flow, | ||||||
|  |                     }; | ||||||
|  |                     let base = Expr::<Enum>::from_canonical(target); | ||||||
|  |                     let non_empty_fields = | ||||||
|  |                         Interned::from_iter(ty.variants().into_iter().enumerate().flat_map( | ||||||
|  |                             |(variant_index, variant)| { | ||||||
|  |                                 variant.ty.map(|_| { | ||||||
|  |                                     self.make_trace_decl_child( | ||||||
|  |                                         instantiated_module, | ||||||
|  |                                         ops::VariantAccess::new_by_index(base, variant_index) | ||||||
|  |                                             .to_expr(), | ||||||
|  |                                         variant.name, | ||||||
|  |                                         source_location, | ||||||
|  |                                     ) | ||||||
|  |                                 }) | ||||||
|  |                             }, | ||||||
|  |                         )); | ||||||
|  |                     TraceEnumWithFields { | ||||||
|  |                         name, | ||||||
|  |                         discriminant, | ||||||
|  |                         non_empty_fields, | ||||||
|  |                         ty, | ||||||
|  |                         flow, | ||||||
|  |                     } | ||||||
|  |                     .into() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             CanonicalType::Bundle(ty) => { |             CanonicalType::Bundle(ty) => { | ||||||
|                 let fields = Interned::from_iter(ty.fields().iter().map(|field| { |                 let fields = Interned::from_iter(ty.fields().iter().map(|field| { | ||||||
|                     self.make_trace_decl_child( |                     self.make_trace_decl_child( | ||||||
|                         TargetInInstantiatedModule { |                         instantiated_module, | ||||||
|                             instantiated_module: target.instantiated_module, |                         Expr::field(Expr::<Bundle>::from_canonical(target), &field.name), | ||||||
|                             target: target.target.join( |  | ||||||
|                                 TargetPathElement::from(TargetPathBundleField { name: field.name }) |  | ||||||
|                                     .intern_sized(), |  | ||||||
|                             ), |  | ||||||
|                         }, |  | ||||||
|                         field.name, |                         field.name, | ||||||
|  |                         source_location, | ||||||
|                     ) |                     ) | ||||||
|                 })); |                 })); | ||||||
|                 TraceBundle { |                 TraceBundle { | ||||||
|                     name, |                     name, | ||||||
|                     fields, |                     fields, | ||||||
|                     ty, |                     ty, | ||||||
|                     flow: target.target.flow(), |                     flow: Expr::flow(target), | ||||||
|                 } |                 } | ||||||
|                 .into() |                 .into() | ||||||
|             } |             } | ||||||
|  | @ -1435,7 +1480,9 @@ impl Compiler { | ||||||
|             | CanonicalType::AsyncReset(_) |             | CanonicalType::AsyncReset(_) | ||||||
|             | CanonicalType::SyncReset(_) |             | CanonicalType::SyncReset(_) | ||||||
|             | CanonicalType::Reset(_) |             | CanonicalType::Reset(_) | ||||||
|             | CanonicalType::Clock(_) => self.make_trace_scalar(target, name), |             | CanonicalType::Clock(_) => { | ||||||
|  |                 self.make_trace_scalar(instantiated_module, target, name, source_location) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn make_trace_decl( |     fn make_trace_decl( | ||||||
|  | @ -1443,15 +1490,17 @@ impl Compiler { | ||||||
|         instantiated_module: InstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|         target_base: TargetBase, |         target_base: TargetBase, | ||||||
|     ) -> TraceDecl { |     ) -> TraceDecl { | ||||||
|         let target = TargetInInstantiatedModule { |         let target = target_base.to_expr(); | ||||||
|             instantiated_module, |  | ||||||
|             target: target_base.into(), |  | ||||||
|         }; |  | ||||||
|         match target_base { |         match target_base { | ||||||
|             TargetBase::ModuleIO(module_io) => TraceModuleIO { |             TargetBase::ModuleIO(module_io) => TraceModuleIO { | ||||||
|                 name: module_io.name(), |                 name: module_io.name(), | ||||||
|                 child: self |                 child: self | ||||||
|                     .make_trace_decl_child(target, module_io.name()) |                     .make_trace_decl_child( | ||||||
|  |                         instantiated_module, | ||||||
|  |                         target, | ||||||
|  |                         module_io.name(), | ||||||
|  |                         module_io.source_location(), | ||||||
|  |                     ) | ||||||
|                     .intern(), |                     .intern(), | ||||||
|                 ty: module_io.ty(), |                 ty: module_io.ty(), | ||||||
|                 flow: module_io.flow(), |                 flow: module_io.flow(), | ||||||
|  | @ -1459,9 +1508,12 @@ impl Compiler { | ||||||
|             .into(), |             .into(), | ||||||
|             TargetBase::MemPort(mem_port) => { |             TargetBase::MemPort(mem_port) => { | ||||||
|                 let name = Intern::intern_owned(mem_port.port_name().to_string()); |                 let name = Intern::intern_owned(mem_port.port_name().to_string()); | ||||||
|                 let TraceDecl::Scope(TraceScope::Bundle(bundle)) = |                 let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( | ||||||
|                     self.make_trace_decl_child(target, name) |                     instantiated_module, | ||||||
|                 else { |                     target, | ||||||
|  |                     name, | ||||||
|  |                     mem_port.source_location(), | ||||||
|  |                 ) else { | ||||||
|                     unreachable!() |                     unreachable!() | ||||||
|                 }; |                 }; | ||||||
|                 TraceMemPort { |                 TraceMemPort { | ||||||
|  | @ -1473,36 +1525,67 @@ impl Compiler { | ||||||
|             } |             } | ||||||
|             TargetBase::Reg(reg) => TraceReg { |             TargetBase::Reg(reg) => TraceReg { | ||||||
|                 name: reg.name(), |                 name: reg.name(), | ||||||
|                 child: self.make_trace_decl_child(target, reg.name()).intern(), |                 child: self | ||||||
|  |                     .make_trace_decl_child( | ||||||
|  |                         instantiated_module, | ||||||
|  |                         target, | ||||||
|  |                         reg.name(), | ||||||
|  |                         reg.source_location(), | ||||||
|  |                     ) | ||||||
|  |                     .intern(), | ||||||
|                 ty: reg.ty(), |                 ty: reg.ty(), | ||||||
|             } |             } | ||||||
|             .into(), |             .into(), | ||||||
|             TargetBase::RegSync(reg) => TraceReg { |             TargetBase::RegSync(reg) => TraceReg { | ||||||
|                 name: reg.name(), |                 name: reg.name(), | ||||||
|                 child: self.make_trace_decl_child(target, reg.name()).intern(), |                 child: self | ||||||
|  |                     .make_trace_decl_child( | ||||||
|  |                         instantiated_module, | ||||||
|  |                         target, | ||||||
|  |                         reg.name(), | ||||||
|  |                         reg.source_location(), | ||||||
|  |                     ) | ||||||
|  |                     .intern(), | ||||||
|                 ty: reg.ty(), |                 ty: reg.ty(), | ||||||
|             } |             } | ||||||
|             .into(), |             .into(), | ||||||
|             TargetBase::RegAsync(reg) => TraceReg { |             TargetBase::RegAsync(reg) => TraceReg { | ||||||
|                 name: reg.name(), |                 name: reg.name(), | ||||||
|                 child: self.make_trace_decl_child(target, reg.name()).intern(), |                 child: self | ||||||
|  |                     .make_trace_decl_child( | ||||||
|  |                         instantiated_module, | ||||||
|  |                         target, | ||||||
|  |                         reg.name(), | ||||||
|  |                         reg.source_location(), | ||||||
|  |                     ) | ||||||
|  |                     .intern(), | ||||||
|                 ty: reg.ty(), |                 ty: reg.ty(), | ||||||
|             } |             } | ||||||
|             .into(), |             .into(), | ||||||
|             TargetBase::Wire(wire) => TraceWire { |             TargetBase::Wire(wire) => TraceWire { | ||||||
|                 name: wire.name(), |                 name: wire.name(), | ||||||
|                 child: self.make_trace_decl_child(target, wire.name()).intern(), |                 child: self | ||||||
|  |                     .make_trace_decl_child( | ||||||
|  |                         instantiated_module, | ||||||
|  |                         target, | ||||||
|  |                         wire.name(), | ||||||
|  |                         wire.source_location(), | ||||||
|  |                     ) | ||||||
|  |                     .intern(), | ||||||
|                 ty: wire.ty(), |                 ty: wire.ty(), | ||||||
|             } |             } | ||||||
|             .into(), |             .into(), | ||||||
|             TargetBase::Instance(instance) => { |             TargetBase::Instance(instance) => { | ||||||
|                 let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = |                 let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( | ||||||
|                     self.make_trace_decl_child(target, instance.name()) |                     instantiated_module, | ||||||
|                 else { |                     target, | ||||||
|  |                     instance.name(), | ||||||
|  |                     instance.source_location(), | ||||||
|  |                 ) else { | ||||||
|                     unreachable!() |                     unreachable!() | ||||||
|                 }; |                 }; | ||||||
|                 let compiled_module = &self.modules[&InstantiatedModule::Child { |                 let compiled_module = &self.modules[&InstantiatedModule::Child { | ||||||
|                     parent: target.instantiated_module.intern(), |                     parent: instantiated_module.intern(), | ||||||
|                     instance: instance.intern(), |                     instance: instance.intern(), | ||||||
|                 }]; |                 }]; | ||||||
|                 TraceInstance { |                 TraceInstance { | ||||||
|  | @ -1647,6 +1730,49 @@ impl Compiler { | ||||||
|         self.assignments |         self.assignments | ||||||
|             .push(Assignment::new(conditions, insns, source_location)); |             .push(Assignment::new(conditions, insns, source_location)); | ||||||
|     } |     } | ||||||
|  |     fn simple_big_expr_input( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         input: Expr<CanonicalType>, | ||||||
|  |     ) -> StatePartIndex<StatePartKindBigSlots> { | ||||||
|  |         let input = self.compile_expr(instantiated_module, input); | ||||||
|  |         let input = | ||||||
|  |             self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); | ||||||
|  |         assert_eq!(input.range.len(), TypeLen::A_BIG_SLOT); | ||||||
|  |         input.range.big_slots.start | ||||||
|  |     } | ||||||
|  |     fn compile_expr_helper( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         dest_ty: CanonicalType, | ||||||
|  |         make_insns: impl FnOnce(&mut Self, TypeIndexRange) -> Vec<Insn>, | ||||||
|  |     ) -> CompiledValue<CanonicalType> { | ||||||
|  |         let layout = CompiledTypeLayout::get(dest_ty); | ||||||
|  |         let range = self.insns.allocate_variable(&layout.layout); | ||||||
|  |         let retval = CompiledValue { | ||||||
|  |             layout, | ||||||
|  |             range, | ||||||
|  |             write: None, | ||||||
|  |         }; | ||||||
|  |         let insns = make_insns(self, range); | ||||||
|  |         self.add_assignment( | ||||||
|  |             Interned::default(), | ||||||
|  |             insns, | ||||||
|  |             instantiated_module.leaf_module().source_location(), | ||||||
|  |         ); | ||||||
|  |         retval | ||||||
|  |     } | ||||||
|  |     fn simple_nary_big_expr_helper( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         dest_ty: CanonicalType, | ||||||
|  |         make_insns: impl FnOnce(StatePartIndex<StatePartKindBigSlots>) -> Vec<Insn>, | ||||||
|  |     ) -> CompiledValue<CanonicalType> { | ||||||
|  |         self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { | ||||||
|  |             assert_eq!(dest.len(), TypeLen::A_BIG_SLOT); | ||||||
|  |             make_insns(dest.big_slots.start) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|     fn simple_nary_big_expr<const N: usize>( |     fn simple_nary_big_expr<const N: usize>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         instantiated_module: InstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|  | @ -1657,37 +1783,10 @@ impl Compiler { | ||||||
|             [StatePartIndex<StatePartKindBigSlots>; N], |             [StatePartIndex<StatePartKindBigSlots>; N], | ||||||
|         ) -> Vec<Insn>, |         ) -> Vec<Insn>, | ||||||
|     ) -> CompiledValue<CanonicalType> { |     ) -> CompiledValue<CanonicalType> { | ||||||
|         let inputs = inputs.map(|input| { |         let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); | ||||||
|             let input = self.compile_expr(instantiated_module, input); |         self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { | ||||||
|             let input = self |             make_insns(dest, inputs) | ||||||
|                 .compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); |         }) | ||||||
|             let TypeIndexRange { |  | ||||||
|                 small_slots, |  | ||||||
|                 big_slots, |  | ||||||
|             } = input.range; |  | ||||||
|             assert_eq!(small_slots.len.value, 0); |  | ||||||
|             assert_eq!(big_slots.len.value, 1); |  | ||||||
|             big_slots.start |  | ||||||
|         }); |  | ||||||
|         let layout = CompiledTypeLayout::get(dest_ty); |  | ||||||
|         let range = self.insns.allocate_variable(&layout.layout); |  | ||||||
|         let TypeIndexRange { |  | ||||||
|             small_slots, |  | ||||||
|             big_slots, |  | ||||||
|         } = range; |  | ||||||
|         assert_eq!(small_slots.len.value, 0); |  | ||||||
|         assert_eq!(big_slots.len.value, 1); |  | ||||||
|         let retval = CompiledValue { |  | ||||||
|             layout, |  | ||||||
|             range, |  | ||||||
|             write: None, |  | ||||||
|         }; |  | ||||||
|         self.add_assignment( |  | ||||||
|             Interned::default(), |  | ||||||
|             make_insns(big_slots.start, inputs), |  | ||||||
|             instantiated_module.leaf_module().source_location(), |  | ||||||
|         ); |  | ||||||
|         retval |  | ||||||
|     } |     } | ||||||
|     fn compiled_value_to_dyn_array_index( |     fn compiled_value_to_dyn_array_index( | ||||||
|         &mut self, |         &mut self, | ||||||
|  | @ -1773,6 +1872,153 @@ impl Compiler { | ||||||
|             .insert(compiled_value, retval); |             .insert(compiled_value, retval); | ||||||
|         retval |         retval | ||||||
|     } |     } | ||||||
|  |     fn compile_cast_scalar_to_bits<T: Type>( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         arg: Expr<CanonicalType>, | ||||||
|  |         cast_fn: impl FnOnce(Expr<T>) -> Expr<UInt>, | ||||||
|  |     ) -> CompiledValue<UInt> { | ||||||
|  |         let arg = Expr::<T>::from_canonical(arg); | ||||||
|  |         let retval = cast_fn(arg); | ||||||
|  |         let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); | ||||||
|  |         let retval = self | ||||||
|  |             .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); | ||||||
|  |         retval.map_ty(UInt::from_canonical) | ||||||
|  |     } | ||||||
|  |     fn compile_cast_aggregate_to_bits( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         parts: impl IntoIterator<Item = Expr<CanonicalType>>, | ||||||
|  |     ) -> CompiledValue<UInt> { | ||||||
|  |         let retval = parts | ||||||
|  |             .into_iter() | ||||||
|  |             .map(|part| part.cast_to_bits()) | ||||||
|  |             .reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width)) | ||||||
|  |             .unwrap_or_else(|| UInt[0].zero().to_expr()); | ||||||
|  |         let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); | ||||||
|  |         let retval = self | ||||||
|  |             .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); | ||||||
|  |         retval.map_ty(UInt::from_canonical) | ||||||
|  |     } | ||||||
|  |     fn compile_cast_to_bits( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         expr: ops::CastToBits, | ||||||
|  |     ) -> CompiledValue<UInt> { | ||||||
|  |         match Expr::ty(expr.arg()) { | ||||||
|  |             CanonicalType::UInt(_) => { | ||||||
|  |                 self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) | ||||||
|  |             } | ||||||
|  |             CanonicalType::SInt(ty) => self.compile_cast_scalar_to_bits( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 expr.arg(), | ||||||
|  |                 |arg: Expr<SInt>| arg.cast_to(ty.as_same_width_uint()), | ||||||
|  |             ), | ||||||
|  |             CanonicalType::Bool(_) | ||||||
|  |             | CanonicalType::AsyncReset(_) | ||||||
|  |             | CanonicalType::SyncReset(_) | ||||||
|  |             | CanonicalType::Reset(_) | ||||||
|  |             | CanonicalType::Clock(_) => self.compile_cast_scalar_to_bits( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 expr.arg(), | ||||||
|  |                 |arg: Expr<Bool>| arg.cast_to(UInt[1]), | ||||||
|  |             ), | ||||||
|  |             CanonicalType::Array(ty) => self.compile_cast_aggregate_to_bits( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 (0..ty.len()).map(|index| Expr::<Array>::from_canonical(expr.arg())[index]), | ||||||
|  |             ), | ||||||
|  |             CanonicalType::Enum(ty) => self | ||||||
|  |                 .simple_nary_big_expr( | ||||||
|  |                     instantiated_module, | ||||||
|  |                     UInt[ty.type_properties().bit_width].canonical(), | ||||||
|  |                     [Expr::canonical(expr.arg())], | ||||||
|  |                     |dest, [src]| vec![Insn::Copy { dest, src }], | ||||||
|  |                 ) | ||||||
|  |                 .map_ty(UInt::from_canonical), | ||||||
|  |             CanonicalType::Bundle(ty) => self.compile_cast_aggregate_to_bits( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 ty.fields().iter().map(|field| { | ||||||
|  |                     Expr::field(Expr::<Bundle>::from_canonical(expr.arg()), &field.name) | ||||||
|  |                 }), | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn compile_cast_bits_to( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         expr: ops::CastBitsTo, | ||||||
|  |     ) -> CompiledValue<CanonicalType> { | ||||||
|  |         let retval = match expr.ty() { | ||||||
|  |             CanonicalType::UInt(_) => Expr::canonical(expr.arg()), | ||||||
|  |             CanonicalType::SInt(ty) => Expr::canonical(expr.arg().cast_to(ty)), | ||||||
|  |             CanonicalType::Bool(ty) => Expr::canonical(expr.arg().cast_to(ty)), | ||||||
|  |             CanonicalType::Array(ty) => { | ||||||
|  |                 let stride = ty.element().bit_width(); | ||||||
|  |                 Expr::<Array>::canonical( | ||||||
|  |                     ops::ArrayLiteral::new( | ||||||
|  |                         ty.element(), | ||||||
|  |                         Interned::from_iter((0..ty.len()).map(|index| { | ||||||
|  |                             let start = stride * index; | ||||||
|  |                             let end = start + stride; | ||||||
|  |                             expr.arg()[start..end].cast_bits_to(ty.element()) | ||||||
|  |                         })), | ||||||
|  |                     ) | ||||||
|  |                     .to_expr(), | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             ty @ CanonicalType::Enum(_) => { | ||||||
|  |                 return self.simple_nary_big_expr( | ||||||
|  |                     instantiated_module, | ||||||
|  |                     ty, | ||||||
|  |                     [Expr::canonical(expr.arg())], | ||||||
|  |                     |dest, [src]| vec![Insn::Copy { dest, src }], | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             CanonicalType::Bundle(ty) => Expr::canonical( | ||||||
|  |                 ops::BundleLiteral::new( | ||||||
|  |                     ty, | ||||||
|  |                     Interned::from_iter(ty.field_offsets().iter().zip(&ty.fields()).map( | ||||||
|  |                         |(&offset, &field)| { | ||||||
|  |                             let end = offset + field.ty.bit_width(); | ||||||
|  |                             expr.arg()[offset..end].cast_bits_to(field.ty) | ||||||
|  |                         }, | ||||||
|  |                     )), | ||||||
|  |                 ) | ||||||
|  |                 .to_expr(), | ||||||
|  |             ), | ||||||
|  |             CanonicalType::AsyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), | ||||||
|  |             CanonicalType::SyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), | ||||||
|  |             CanonicalType::Reset(_) => unreachable!(), | ||||||
|  |             CanonicalType::Clock(ty) => Expr::canonical(expr.arg().cast_to(ty)), | ||||||
|  |         }; | ||||||
|  |         let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); | ||||||
|  |         self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) | ||||||
|  |     } | ||||||
|  |     fn compile_aggregate_literal( | ||||||
|  |         &mut self, | ||||||
|  |         instantiated_module: InstantiatedModule, | ||||||
|  |         dest_ty: CanonicalType, | ||||||
|  |         inputs: Interned<[Expr<CanonicalType>]>, | ||||||
|  |     ) -> CompiledValue<CanonicalType> { | ||||||
|  |         self.compile_expr_helper(instantiated_module, dest_ty, |this, dest| { | ||||||
|  |             let mut insns = Vec::new(); | ||||||
|  |             let mut offset = TypeIndex::ZERO; | ||||||
|  |             for input in inputs { | ||||||
|  |                 let input = this.compile_expr(instantiated_module, input); | ||||||
|  |                 let input = this | ||||||
|  |                     .compiled_expr_to_value( | ||||||
|  |                         input, | ||||||
|  |                         instantiated_module.leaf_module().source_location(), | ||||||
|  |                     ) | ||||||
|  |                     .range; | ||||||
|  |                 insns.extend( | ||||||
|  |                     input.insns_for_copy_to(dest.slice(TypeIndexRange::new(offset, input.len()))), | ||||||
|  |                 ); | ||||||
|  |                 offset = offset.offset(input.len().as_index()); | ||||||
|  |             } | ||||||
|  |             insns | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|     fn compile_expr( |     fn compile_expr( | ||||||
|         &mut self, |         &mut self, | ||||||
|         instantiated_module: InstantiatedModule, |         instantiated_module: InstantiatedModule, | ||||||
|  | @ -1860,10 +2106,44 @@ impl Compiler { | ||||||
|                     }] |                     }] | ||||||
|                 }) |                 }) | ||||||
|                 .into(), |                 .into(), | ||||||
|             ExprEnum::BundleLiteral(expr) => todo!(), |             ExprEnum::BundleLiteral(literal) => self | ||||||
|             ExprEnum::ArrayLiteral(expr) => todo!(), |                 .compile_aggregate_literal( | ||||||
|             ExprEnum::EnumLiteral(expr) => todo!(), |                     instantiated_module, | ||||||
|             ExprEnum::Uninit(expr) => todo!(), |                     Expr::ty(expr), | ||||||
|  |                     literal.field_values(), | ||||||
|  |                 ) | ||||||
|  |                 .into(), | ||||||
|  |             ExprEnum::ArrayLiteral(literal) => self | ||||||
|  |                 .compile_aggregate_literal( | ||||||
|  |                     instantiated_module, | ||||||
|  |                     Expr::ty(expr), | ||||||
|  |                     literal.element_values(), | ||||||
|  |                 ) | ||||||
|  |                 .into(), | ||||||
|  |             ExprEnum::EnumLiteral(expr) => { | ||||||
|  |                 let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; | ||||||
|  |                 let enum_bits = if let Some(variant_value) = expr.variant_value() { | ||||||
|  |                     ( | ||||||
|  |                         UInt[expr.ty().discriminant_bit_width()] | ||||||
|  |                             .from_int_wrapping(expr.variant_index()), | ||||||
|  |                         variant_value, | ||||||
|  |                     ) | ||||||
|  |                         .cast_to_bits() | ||||||
|  |                         .cast_to(enum_bits_ty) | ||||||
|  |                 } else { | ||||||
|  |                     enum_bits_ty | ||||||
|  |                         .from_int_wrapping(expr.variant_index()) | ||||||
|  |                         .to_expr() | ||||||
|  |                 }; | ||||||
|  |                 self.compile_expr( | ||||||
|  |                     instantiated_module, | ||||||
|  |                     enum_bits.cast_bits_to(expr.ty().canonical()), | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             ExprEnum::Uninit(expr) => self.compile_expr( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 UInt[expr.ty().bit_width()].zero().cast_bits_to(expr.ty()), | ||||||
|  |             ), | ||||||
|             ExprEnum::NotU(expr) => self |             ExprEnum::NotU(expr) => self | ||||||
|                 .simple_nary_big_expr( |                 .simple_nary_big_expr( | ||||||
|                     instantiated_module, |                     instantiated_module, | ||||||
|  | @ -2392,7 +2672,12 @@ impl Compiler { | ||||||
|                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) |                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) | ||||||
|                 .map_ty(Bundle::from_canonical) |                 .map_ty(Bundle::from_canonical) | ||||||
|                 .field_by_index(expr.field_index()), |                 .field_by_index(expr.field_index()), | ||||||
|             ExprEnum::VariantAccess(expr) => todo!(), |             ExprEnum::VariantAccess(variant_access) => self.compile_expr( | ||||||
|  |                 instantiated_module, | ||||||
|  |                 variant_access.base().cast_to_bits() | ||||||
|  |                     [Expr::ty(variant_access.base()).discriminant_bit_width()..] | ||||||
|  |                     .cast_bits_to(Expr::ty(expr)), | ||||||
|  |             ), | ||||||
|             ExprEnum::ArrayIndex(expr) => self |             ExprEnum::ArrayIndex(expr) => self | ||||||
|                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) |                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) | ||||||
|                 .map_ty(Array::from_canonical) |                 .map_ty(Array::from_canonical) | ||||||
|  | @ -2512,8 +2797,13 @@ impl Compiler { | ||||||
|                     }, |                     }, | ||||||
|                 ) |                 ) | ||||||
|                 .into(), |                 .into(), | ||||||
|             ExprEnum::CastToBits(expr) => todo!(), |             ExprEnum::CastToBits(expr) => self | ||||||
|             ExprEnum::CastBitsTo(expr) => todo!(), |                 .compile_cast_to_bits(instantiated_module, expr) | ||||||
|  |                 .map_ty(CanonicalType::UInt) | ||||||
|  |                 .into(), | ||||||
|  |             ExprEnum::CastBitsTo(expr) => { | ||||||
|  |                 self.compile_cast_bits_to(instantiated_module, expr).into() | ||||||
|  |             } | ||||||
|             ExprEnum::ModuleIO(expr) => self |             ExprEnum::ModuleIO(expr) => self | ||||||
|                 .compile_value(TargetInInstantiatedModule { |                 .compile_value(TargetInInstantiatedModule { | ||||||
|                     instantiated_module, |                     instantiated_module, | ||||||
|  | @ -3061,13 +3351,14 @@ impl Compiler { | ||||||
|                     let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr)); |                     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 = self.compiled_expr_to_value(enum_expr, source_location); | ||||||
|                     let enum_expr = enum_expr.map_ty(Enum::from_canonical); |                     let enum_expr = enum_expr.map_ty(Enum::from_canonical); | ||||||
|  |                     let discriminant = self.compile_enum_discriminant(enum_expr, source_location); | ||||||
|                     for (variant_index, block) in blocks.into_iter().enumerate() { |                     for (variant_index, block) in blocks.into_iter().enumerate() { | ||||||
|                         self.compile_block( |                         self.compile_block( | ||||||
|                             parent_module, |                             parent_module, | ||||||
|                             block, |                             block, | ||||||
|                             Interned::from_iter(conditions.iter().copied().chain([Cond { |                             Interned::from_iter(conditions.iter().copied().chain([Cond { | ||||||
|                                 body: CondBody::MatchArm { |                                 body: CondBody::MatchArm { | ||||||
|                                     enum_expr, |                                     discriminant, | ||||||
|                                     variant_index, |                                     variant_index, | ||||||
|                                 }, |                                 }, | ||||||
|                                 source_location, |                                 source_location, | ||||||
|  | @ -3217,9 +3508,18 @@ impl Compiler { | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
|                     CondBody::MatchArm { |                     CondBody::MatchArm { | ||||||
|                         enum_expr, |                         discriminant, | ||||||
|                         variant_index, |                         variant_index, | ||||||
|                     } => todo!(), |                     } => { | ||||||
|  |                         self.insns.push( | ||||||
|  |                             Insn::BranchIfSmallNeImmediate { | ||||||
|  |                                 target: end_label_index, | ||||||
|  |                                 lhs: discriminant, | ||||||
|  |                                 rhs: variant_index as _, | ||||||
|  |                             }, | ||||||
|  |                             cond.source_location, | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 cond_stack.push(CondStackEntry { |                 cond_stack.push(CondStackEntry { | ||||||
|                     cond, |                     cond, | ||||||
|  | @ -3261,22 +3561,6 @@ impl Compiler { | ||||||
|             source_location, |             source_location, | ||||||
|         } in mem::take(&mut self.registers) |         } in mem::take(&mut self.registers) | ||||||
|         { |         { | ||||||
|             let write_to_current_value = |value_to_write: CompiledValue<CanonicalType>| { |  | ||||||
|                 let TypeIndexRange { |  | ||||||
|                     small_slots, |  | ||||||
|                     big_slots, |  | ||||||
|                 } = value.range; |  | ||||||
|                 small_slots |  | ||||||
|                     .iter() |  | ||||||
|                     .zip(value_to_write.range.small_slots.iter()) |  | ||||||
|                     .map(|(base, src)| Insn::CopySmall { dest: base, src }) |  | ||||||
|                     .chain( |  | ||||||
|                         big_slots |  | ||||||
|                             .iter() |  | ||||||
|                             .zip(value_to_write.range.big_slots.iter()) |  | ||||||
|                             .map(|(base, src)| Insn::Copy { dest: base, src }), |  | ||||||
|                     ) |  | ||||||
|             }; |  | ||||||
|             match reset { |             match reset { | ||||||
|                 Some(RegisterReset { |                 Some(RegisterReset { | ||||||
|                     is_async, |                     is_async, | ||||||
|  | @ -3300,15 +3584,15 @@ impl Compiler { | ||||||
|                         self.insns.push(branch_if_not_triggered, source_location); |                         self.insns.push(branch_if_not_triggered, source_location); | ||||||
|                         self.insns.push(branch_if_reset, source_location); |                         self.insns.push(branch_if_reset, source_location); | ||||||
|                     } |                     } | ||||||
|                     for insn in write_to_current_value(value.write_value()) { |                     self.insns.extend( | ||||||
|                         self.insns.push(insn, source_location); |                         value.range.insns_for_copy_from(value.write_value().range), | ||||||
|                     } |                         source_location, | ||||||
|  |                     ); | ||||||
|                     self.insns |                     self.insns | ||||||
|                         .push(Insn::Branch { target: reg_end }, source_location); |                         .push(Insn::Branch { target: reg_end }, source_location); | ||||||
|                     self.insns.define_label_at_next_insn(reg_reset); |                     self.insns.define_label_at_next_insn(reg_reset); | ||||||
|                     for insn in write_to_current_value(init) { |                     self.insns | ||||||
|                         self.insns.push(insn, source_location); |                         .extend(value.range.insns_for_copy_from(init.range), source_location); | ||||||
|                     } |  | ||||||
|                     self.insns.define_label_at_next_insn(reg_end); |                     self.insns.define_label_at_next_insn(reg_end); | ||||||
|                 } |                 } | ||||||
|                 None => { |                 None => { | ||||||
|  | @ -3320,9 +3604,10 @@ impl Compiler { | ||||||
|                         }, |                         }, | ||||||
|                         source_location, |                         source_location, | ||||||
|                     ); |                     ); | ||||||
|                     for insn in write_to_current_value(value.write_value()) { |                     self.insns.extend( | ||||||
|                         self.insns.push(insn, source_location); |                         value.range.insns_for_copy_from(value.write_value().range), | ||||||
|                     } |                         source_location, | ||||||
|  |                     ); | ||||||
|                     self.insns.define_label_at_next_insn(reg_end); |                     self.insns.define_label_at_next_insn(reg_end); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -913,12 +913,23 @@ macro_rules! make_state_part_kinds { | ||||||
|             $(pub(crate) $type_field: StatePartLen<$TypeKind>,)* |             $(pub(crate) $type_field: StatePartLen<$TypeKind>,)* | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         impl TypeLen { | ||||||
|  |             pub(crate) const fn as_index(self) -> TypeIndex { | ||||||
|  |                 TypeIndex { | ||||||
|  |                     $($type_field: self.$type_field.as_index(),)* | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |         #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||||||
|         pub(crate) struct TypeIndex { |         pub(crate) struct TypeIndex { | ||||||
|             $(pub(crate) $type_field: StatePartIndex<$TypeKind>,)* |             $(pub(crate) $type_field: StatePartIndex<$TypeKind>,)* | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl TypeIndex { |         impl TypeIndex { | ||||||
|  |             pub(crate) const ZERO: Self = Self { | ||||||
|  |                 $($type_field: StatePartIndex::ZERO,)* | ||||||
|  |             }; | ||||||
|             pub(crate) fn offset(self, offset: TypeIndex) -> Self { |             pub(crate) fn offset(self, offset: TypeIndex) -> Self { | ||||||
|                 Self { |                 Self { | ||||||
|                     $($type_field: self.$type_field.offset(offset.$type_field),)* |                     $($type_field: self.$type_field.offset(offset.$type_field),)* | ||||||
|  | @ -1470,6 +1481,10 @@ pub(crate) struct StatePartIndex<K: StatePartKind> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<K: StatePartKind> StatePartIndex<K> { | impl<K: StatePartKind> StatePartIndex<K> { | ||||||
|  |     pub(crate) const ZERO: Self = Self { | ||||||
|  |         value: 0, | ||||||
|  |         _phantom: PhantomData, | ||||||
|  |     }; | ||||||
|     pub(crate) fn as_usize(self) -> usize { |     pub(crate) fn as_usize(self) -> usize { | ||||||
|         self.value.try_into().expect("index too big") |         self.value.try_into().expect("index too big") | ||||||
|     } |     } | ||||||
|  | @ -1520,6 +1535,12 @@ impl<K: StatePartKind> StatePartLen<K> { | ||||||
|             _phantom: PhantomData, |             _phantom: PhantomData, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     pub(crate) const fn as_index(self) -> StatePartIndex<K> { | ||||||
|  |         StatePartIndex { | ||||||
|  |             value: self.value, | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<K: StatePartKind> fmt::Debug for StatePartLen<K> { | impl<K: StatePartKind> fmt::Debug for StatePartLen<K> { | ||||||
|  | @ -1948,6 +1969,15 @@ impl Insns<InsnsBuilding> { | ||||||
|         self.insns.push(insn); |         self.insns.push(insn); | ||||||
|         self.insn_source_locations.push(source_location); |         self.insn_source_locations.push(source_location); | ||||||
|     } |     } | ||||||
|  |     pub(crate) fn extend( | ||||||
|  |         &mut self, | ||||||
|  |         insns: impl IntoIterator<Item = Insn>, | ||||||
|  |         source_location: SourceLocation, | ||||||
|  |     ) { | ||||||
|  |         self.insns.extend(insns); | ||||||
|  |         self.insn_source_locations | ||||||
|  |             .resize(self.insns.len(), source_location); | ||||||
|  |     } | ||||||
|     pub(crate) fn allocate_variable<BK: InsnsBuildingKind>( |     pub(crate) fn allocate_variable<BK: InsnsBuildingKind>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         layout: &TypeLayout<BK>, |         layout: &TypeLayout<BK>, | ||||||
|  | @ -2047,6 +2077,31 @@ impl BorrowedState<'_> { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl TypeIndexRange { | ||||||
|  |     #[must_use] | ||||||
|  |     pub(crate) fn insns_for_copy_to(self, dest: TypeIndexRange) -> impl Iterator<Item = Insn> { | ||||||
|  |         assert_eq!(self.len(), dest.len()); | ||||||
|  |         let Self { | ||||||
|  |             small_slots, | ||||||
|  |             big_slots, | ||||||
|  |         } = self; | ||||||
|  |         small_slots | ||||||
|  |             .iter() | ||||||
|  |             .zip(dest.small_slots.iter()) | ||||||
|  |             .map(|(src, dest)| Insn::CopySmall { dest, src }) | ||||||
|  |             .chain( | ||||||
|  |                 big_slots | ||||||
|  |                     .iter() | ||||||
|  |                     .zip(dest.big_slots.iter()) | ||||||
|  |                     .map(|(src, dest)| Insn::Copy { dest, src }), | ||||||
|  |             ) | ||||||
|  |     } | ||||||
|  |     #[must_use] | ||||||
|  |     pub(crate) fn insns_for_copy_from(self, src: TypeIndexRange) -> impl Iterator<Item = Insn> { | ||||||
|  |         src.insns_for_copy_to(self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn bigint_pow2(width: usize) -> Interned<BigInt> { | fn bigint_pow2(width: usize) -> Interned<BigInt> { | ||||||
|     #[derive(Copy, Clone, PartialEq, Eq, Hash)] |     #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||||||
|     struct MyMemoize; |     struct MyMemoize; | ||||||
|  | @ -2633,6 +2688,20 @@ impl_insns! { | ||||||
|             branch!(target); |             branch!(target); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     BranchIfSmallNeImmediate { | ||||||
|  |         #[kind = BranchTarget] | ||||||
|  |         target: usize, | ||||||
|  |         #[kind = Input] | ||||||
|  |         lhs: StatePartIndex<StatePartKindSmallSlots>, | ||||||
|  |         #[kind = Immediate] | ||||||
|  |         rhs: SmallUInt, | ||||||
|  |     } => { | ||||||
|  |         if state.small_slots[lhs] != rhs { | ||||||
|  |             branch!(target); | ||||||
|  |         } else { | ||||||
|  |             next!(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     Return => { |     Return => { | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -3793,3 +3793,5 @@ $end | ||||||
|         panic!(); |         panic!(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // TODO: add tests for enums
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue