sim: implement enums (except for connecting unequal enum types)
This commit is contained in:
		
							parent
							
								
									15bc304bb6
								
							
						
					
					
						commit
						42afd2da0e
					
				
					 3 changed files with 475 additions and 119 deletions
				
			
		|  | @ -59,7 +59,7 @@ enum CondBody { | |||
|         cond: CompiledValue<Bool>, | ||||
|     }, | ||||
|     MatchArm { | ||||
|         enum_expr: CompiledValue<Enum>, | ||||
|         discriminant: StatePartIndex<StatePartKindSmallSlots>, | ||||
|         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> { | ||||
|     fn field_by_index(self, field_index: usize) -> CompiledValue<CanonicalType> { | ||||
|         self.map(|layout, range| { | ||||
|  | @ -957,9 +951,9 @@ impl Extend<CondBody> for SlotSet { | |||
|                 self.extend([cond.range]); | ||||
|             } | ||||
|             CondBody::MatchArm { | ||||
|                 enum_expr, | ||||
|                 discriminant, | ||||
|                 variant_index: _, | ||||
|             } => enum_expr.add_discriminant_to_set(self), | ||||
|             } => self.extend([discriminant]), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | @ -1271,11 +1265,14 @@ impl Compiler { | |||
|     } | ||||
|     fn make_trace_scalar_helper( | ||||
|         &mut self, | ||||
|         target: TargetInInstantiatedModule, | ||||
|         instantiated_module: InstantiatedModule, | ||||
|         target: Expr<CanonicalType>, | ||||
|         source_location: SourceLocation, | ||||
|         small_kind: impl FnOnce(StatePartIndex<StatePartKindSmallSlots>) -> SimTraceKind, | ||||
|         big_kind: impl FnOnce(StatePartIndex<StatePartKindBigSlots>) -> SimTraceKind, | ||||
|     ) -> 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() { | ||||
|             TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), | ||||
|             TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), | ||||
|  | @ -1284,14 +1281,18 @@ impl Compiler { | |||
|     } | ||||
|     fn make_trace_scalar( | ||||
|         &mut self, | ||||
|         target: TargetInInstantiatedModule, | ||||
|         instantiated_module: InstantiatedModule, | ||||
|         target: Expr<CanonicalType>, | ||||
|         name: Interned<str>, | ||||
|         source_location: SourceLocation, | ||||
|     ) -> TraceDecl { | ||||
|         let flow = target.target.flow(); | ||||
|         match target.target.canonical_ty() { | ||||
|         let flow = Expr::flow(target); | ||||
|         match Expr::ty(target) { | ||||
|             CanonicalType::UInt(ty) => TraceUInt { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallUInt { index, ty }, | ||||
|                     |index| SimTraceKind::BigUInt { index, ty }, | ||||
|                 ), | ||||
|  | @ -1302,7 +1303,9 @@ impl Compiler { | |||
|             .into(), | ||||
|             CanonicalType::SInt(ty) => TraceSInt { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallSInt { index, ty }, | ||||
|                     |index| SimTraceKind::BigSInt { index, ty }, | ||||
|                 ), | ||||
|  | @ -1313,7 +1316,9 @@ impl Compiler { | |||
|             .into(), | ||||
|             CanonicalType::Bool(_) => TraceBool { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallBool { index }, | ||||
|                     |index| SimTraceKind::BigBool { index }, | ||||
|                 ), | ||||
|  | @ -1324,10 +1329,11 @@ impl Compiler { | |||
|             CanonicalType::Array(_) => unreachable!(), | ||||
|             CanonicalType::Enum(ty) => { | ||||
|                 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( | ||||
|                     compiled_value.map_ty(Enum::from_canonical), | ||||
|                     target.target.base().source_location(), | ||||
|                     source_location, | ||||
|                 ); | ||||
|                 TraceFieldlessEnum { | ||||
|                     id: self.new_sim_trace(SimTraceKind::EnumDiscriminant { | ||||
|  | @ -1343,7 +1349,9 @@ impl Compiler { | |||
|             CanonicalType::Bundle(_) => unreachable!(), | ||||
|             CanonicalType::AsyncReset(_) => TraceAsyncReset { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallAsyncReset { index }, | ||||
|                     |index| SimTraceKind::BigAsyncReset { index }, | ||||
|                 ), | ||||
|  | @ -1353,7 +1361,9 @@ impl Compiler { | |||
|             .into(), | ||||
|             CanonicalType::SyncReset(_) => TraceSyncReset { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallSyncReset { index }, | ||||
|                     |index| SimTraceKind::BigSyncReset { index }, | ||||
|                 ), | ||||
|  | @ -1364,7 +1374,9 @@ impl Compiler { | |||
|             CanonicalType::Reset(_) => unreachable!(), | ||||
|             CanonicalType::Clock(_) => TraceClock { | ||||
|                 id: self.make_trace_scalar_helper( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     source_location, | ||||
|                     |index| SimTraceKind::SmallClock { index }, | ||||
|                     |index| SimTraceKind::BigClock { index }, | ||||
|                 ), | ||||
|  | @ -1376,56 +1388,89 @@ impl Compiler { | |||
|     } | ||||
|     fn make_trace_decl_child( | ||||
|         &mut self, | ||||
|         target: TargetInInstantiatedModule, | ||||
|         instantiated_module: InstantiatedModule, | ||||
|         target: Expr<CanonicalType>, | ||||
|         name: Interned<str>, | ||||
|         source_location: SourceLocation, | ||||
|     ) -> TraceDecl { | ||||
|         match target.target.canonical_ty() { | ||||
|         match Expr::ty(target) { | ||||
|             CanonicalType::Array(ty) => { | ||||
|                 let elements = Interned::from_iter((0..ty.len()).map(|index| { | ||||
|                     self.make_trace_decl_child( | ||||
|                         TargetInInstantiatedModule { | ||||
|                             instantiated_module: target.instantiated_module, | ||||
|                             target: target.target.join( | ||||
|                                 TargetPathElement::from(TargetPathArrayElement { index }) | ||||
|                                     .intern_sized(), | ||||
|                             ), | ||||
|                         }, | ||||
|                         instantiated_module, | ||||
|                         Expr::<Array>::from_canonical(target)[index], | ||||
|                         Intern::intern_owned(format!("[{index}]")), | ||||
|                         source_location, | ||||
|                     ) | ||||
|                 })); | ||||
|                 TraceArray { | ||||
|                     name, | ||||
|                     elements, | ||||
|                     ty, | ||||
|                     flow: target.target.flow(), | ||||
|                     flow: Expr::flow(target), | ||||
|                 } | ||||
|                 .into() | ||||
|             } | ||||
|             CanonicalType::Enum(ty) => { | ||||
|                 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 { | ||||
|                     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) => { | ||||
|                 let fields = Interned::from_iter(ty.fields().iter().map(|field| { | ||||
|                     self.make_trace_decl_child( | ||||
|                         TargetInInstantiatedModule { | ||||
|                             instantiated_module: target.instantiated_module, | ||||
|                             target: target.target.join( | ||||
|                                 TargetPathElement::from(TargetPathBundleField { name: field.name }) | ||||
|                                     .intern_sized(), | ||||
|                             ), | ||||
|                         }, | ||||
|                         instantiated_module, | ||||
|                         Expr::field(Expr::<Bundle>::from_canonical(target), &field.name), | ||||
|                         field.name, | ||||
|                         source_location, | ||||
|                     ) | ||||
|                 })); | ||||
|                 TraceBundle { | ||||
|                     name, | ||||
|                     fields, | ||||
|                     ty, | ||||
|                     flow: target.target.flow(), | ||||
|                     flow: Expr::flow(target), | ||||
|                 } | ||||
|                 .into() | ||||
|             } | ||||
|  | @ -1435,7 +1480,9 @@ impl Compiler { | |||
|             | CanonicalType::AsyncReset(_) | ||||
|             | CanonicalType::SyncReset(_) | ||||
|             | 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( | ||||
|  | @ -1443,15 +1490,17 @@ impl Compiler { | |||
|         instantiated_module: InstantiatedModule, | ||||
|         target_base: TargetBase, | ||||
|     ) -> TraceDecl { | ||||
|         let target = TargetInInstantiatedModule { | ||||
|             instantiated_module, | ||||
|             target: target_base.into(), | ||||
|         }; | ||||
|         let target = target_base.to_expr(); | ||||
|         match target_base { | ||||
|             TargetBase::ModuleIO(module_io) => TraceModuleIO { | ||||
|                 name: module_io.name(), | ||||
|                 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(), | ||||
|                 ty: module_io.ty(), | ||||
|                 flow: module_io.flow(), | ||||
|  | @ -1459,9 +1508,12 @@ impl Compiler { | |||
|             .into(), | ||||
|             TargetBase::MemPort(mem_port) => { | ||||
|                 let name = Intern::intern_owned(mem_port.port_name().to_string()); | ||||
|                 let TraceDecl::Scope(TraceScope::Bundle(bundle)) = | ||||
|                     self.make_trace_decl_child(target, name) | ||||
|                 else { | ||||
|                 let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     name, | ||||
|                     mem_port.source_location(), | ||||
|                 ) else { | ||||
|                     unreachable!() | ||||
|                 }; | ||||
|                 TraceMemPort { | ||||
|  | @ -1473,36 +1525,67 @@ impl Compiler { | |||
|             } | ||||
|             TargetBase::Reg(reg) => TraceReg { | ||||
|                 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(), | ||||
|             } | ||||
|             .into(), | ||||
|             TargetBase::RegSync(reg) => TraceReg { | ||||
|                 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(), | ||||
|             } | ||||
|             .into(), | ||||
|             TargetBase::RegAsync(reg) => TraceReg { | ||||
|                 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(), | ||||
|             } | ||||
|             .into(), | ||||
|             TargetBase::Wire(wire) => TraceWire { | ||||
|                 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(), | ||||
|             } | ||||
|             .into(), | ||||
|             TargetBase::Instance(instance) => { | ||||
|                 let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = | ||||
|                     self.make_trace_decl_child(target, instance.name()) | ||||
|                 else { | ||||
|                 let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( | ||||
|                     instantiated_module, | ||||
|                     target, | ||||
|                     instance.name(), | ||||
|                     instance.source_location(), | ||||
|                 ) else { | ||||
|                     unreachable!() | ||||
|                 }; | ||||
|                 let compiled_module = &self.modules[&InstantiatedModule::Child { | ||||
|                     parent: target.instantiated_module.intern(), | ||||
|                     parent: instantiated_module.intern(), | ||||
|                     instance: instance.intern(), | ||||
|                 }]; | ||||
|                 TraceInstance { | ||||
|  | @ -1647,6 +1730,49 @@ impl Compiler { | |||
|         self.assignments | ||||
|             .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>( | ||||
|         &mut self, | ||||
|         instantiated_module: InstantiatedModule, | ||||
|  | @ -1657,37 +1783,10 @@ impl Compiler { | |||
|             [StatePartIndex<StatePartKindBigSlots>; N], | ||||
|         ) -> Vec<Insn>, | ||||
|     ) -> CompiledValue<CanonicalType> { | ||||
|         let inputs = inputs.map(|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, | ||||
|             } = 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 | ||||
|         let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); | ||||
|         self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { | ||||
|             make_insns(dest, inputs) | ||||
|         }) | ||||
|     } | ||||
|     fn compiled_value_to_dyn_array_index( | ||||
|         &mut self, | ||||
|  | @ -1773,6 +1872,153 @@ impl Compiler { | |||
|             .insert(compiled_value, 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( | ||||
|         &mut self, | ||||
|         instantiated_module: InstantiatedModule, | ||||
|  | @ -1860,10 +2106,44 @@ impl Compiler { | |||
|                     }] | ||||
|                 }) | ||||
|                 .into(), | ||||
|             ExprEnum::BundleLiteral(expr) => todo!(), | ||||
|             ExprEnum::ArrayLiteral(expr) => todo!(), | ||||
|             ExprEnum::EnumLiteral(expr) => todo!(), | ||||
|             ExprEnum::Uninit(expr) => todo!(), | ||||
|             ExprEnum::BundleLiteral(literal) => self | ||||
|                 .compile_aggregate_literal( | ||||
|                     instantiated_module, | ||||
|                     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 | ||||
|                 .simple_nary_big_expr( | ||||
|                     instantiated_module, | ||||
|  | @ -2392,7 +2672,12 @@ impl Compiler { | |||
|                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) | ||||
|                 .map_ty(Bundle::from_canonical) | ||||
|                 .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 | ||||
|                 .compile_expr(instantiated_module, Expr::canonical(expr.base())) | ||||
|                 .map_ty(Array::from_canonical) | ||||
|  | @ -2512,8 +2797,13 @@ impl Compiler { | |||
|                     }, | ||||
|                 ) | ||||
|                 .into(), | ||||
|             ExprEnum::CastToBits(expr) => todo!(), | ||||
|             ExprEnum::CastBitsTo(expr) => todo!(), | ||||
|             ExprEnum::CastToBits(expr) => self | ||||
|                 .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 | ||||
|                 .compile_value(TargetInInstantiatedModule { | ||||
|                     instantiated_module, | ||||
|  | @ -3061,13 +3351,14 @@ impl Compiler { | |||
|                     let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr)); | ||||
|                     let enum_expr = self.compiled_expr_to_value(enum_expr, source_location); | ||||
|                     let enum_expr = enum_expr.map_ty(Enum::from_canonical); | ||||
|                     let discriminant = self.compile_enum_discriminant(enum_expr, source_location); | ||||
|                     for (variant_index, block) in blocks.into_iter().enumerate() { | ||||
|                         self.compile_block( | ||||
|                             parent_module, | ||||
|                             block, | ||||
|                             Interned::from_iter(conditions.iter().copied().chain([Cond { | ||||
|                                 body: CondBody::MatchArm { | ||||
|                                     enum_expr, | ||||
|                                     discriminant, | ||||
|                                     variant_index, | ||||
|                                 }, | ||||
|                                 source_location, | ||||
|  | @ -3217,9 +3508,18 @@ impl Compiler { | |||
|                         ); | ||||
|                     } | ||||
|                     CondBody::MatchArm { | ||||
|                         enum_expr, | ||||
|                         discriminant, | ||||
|                         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, | ||||
|  | @ -3261,22 +3561,6 @@ impl Compiler { | |||
|             source_location, | ||||
|         } 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 { | ||||
|                 Some(RegisterReset { | ||||
|                     is_async, | ||||
|  | @ -3300,15 +3584,15 @@ impl Compiler { | |||
|                         self.insns.push(branch_if_not_triggered, source_location); | ||||
|                         self.insns.push(branch_if_reset, source_location); | ||||
|                     } | ||||
|                     for insn in write_to_current_value(value.write_value()) { | ||||
|                         self.insns.push(insn, source_location); | ||||
|                     } | ||||
|                     self.insns.extend( | ||||
|                         value.range.insns_for_copy_from(value.write_value().range), | ||||
|                         source_location, | ||||
|                     ); | ||||
|                     self.insns | ||||
|                         .push(Insn::Branch { target: reg_end }, source_location); | ||||
|                     self.insns.define_label_at_next_insn(reg_reset); | ||||
|                     for insn in write_to_current_value(init) { | ||||
|                         self.insns.push(insn, source_location); | ||||
|                     } | ||||
|                     self.insns | ||||
|                         .extend(value.range.insns_for_copy_from(init.range), source_location); | ||||
|                     self.insns.define_label_at_next_insn(reg_end); | ||||
|                 } | ||||
|                 None => { | ||||
|  | @ -3320,9 +3604,10 @@ impl Compiler { | |||
|                         }, | ||||
|                         source_location, | ||||
|                     ); | ||||
|                     for insn in write_to_current_value(value.write_value()) { | ||||
|                         self.insns.push(insn, source_location); | ||||
|                     } | ||||
|                     self.insns.extend( | ||||
|                         value.range.insns_for_copy_from(value.write_value().range), | ||||
|                         source_location, | ||||
|                     ); | ||||
|                     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>,)* | ||||
|         } | ||||
| 
 | ||||
|         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)] | ||||
|         pub(crate) struct TypeIndex { | ||||
|             $(pub(crate) $type_field: StatePartIndex<$TypeKind>,)* | ||||
|         } | ||||
| 
 | ||||
|         impl TypeIndex { | ||||
|             pub(crate) const ZERO: Self = Self { | ||||
|                 $($type_field: StatePartIndex::ZERO,)* | ||||
|             }; | ||||
|             pub(crate) fn offset(self, offset: TypeIndex) -> Self { | ||||
|                 Self { | ||||
|                     $($type_field: self.$type_field.offset(offset.$type_field),)* | ||||
|  | @ -1470,6 +1481,10 @@ pub(crate) struct StatePartIndex<K: StatePartKind> { | |||
| } | ||||
| 
 | ||||
| impl<K: StatePartKind> StatePartIndex<K> { | ||||
|     pub(crate) const ZERO: Self = Self { | ||||
|         value: 0, | ||||
|         _phantom: PhantomData, | ||||
|     }; | ||||
|     pub(crate) fn as_usize(self) -> usize { | ||||
|         self.value.try_into().expect("index too big") | ||||
|     } | ||||
|  | @ -1520,6 +1535,12 @@ impl<K: StatePartKind> StatePartLen<K> { | |||
|             _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> { | ||||
|  | @ -1948,6 +1969,15 @@ impl Insns<InsnsBuilding> { | |||
|         self.insns.push(insn); | ||||
|         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>( | ||||
|         &mut self, | ||||
|         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> { | ||||
|     #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||||
|     struct MyMemoize; | ||||
|  | @ -2633,6 +2688,20 @@ impl_insns! { | |||
|             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 => { | ||||
|         break; | ||||
|     } | ||||
|  |  | |||
|  | @ -3793,3 +3793,5 @@ $end | |||
|         panic!(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // TODO: add tests for enums
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue