sim: implement enums (except for connecting unequal enum types)
Some checks failed
/ deps (push) Successful in 18s
/ test (push) Has been cancelled
/ deps (pull_request) Successful in 14s
/ test (pull_request) Successful in 5m24s

This commit is contained in:
Jacob Lifshay 2024-12-04 20:58:39 -08:00
parent 15bc304bb6
commit 42afd2da0e
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
3 changed files with 475 additions and 119 deletions

View file

@ -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);
} }
} }

View file

@ -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;
} }

View file

@ -3793,3 +3793,5 @@ $end
panic!(); panic!();
} }
} }
// TODO: add tests for enums