sim: implement enums (except for connecting unequal enum types)
This commit is contained in:
parent
15bc304bb6
commit
42afd2da0e
|
@ -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…
Reference in a new issue