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