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

View file

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

View file

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