Skip to content

Commit 4d40f85

Browse files
committed
Also report what module poisoned a latency inference
1 parent bc46d91 commit 4d40f85

File tree

10 files changed

+267
-95
lines changed

10 files changed

+267
-95
lines changed

src/codegen/system_verilog.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::prelude::*;
1313

1414
use crate::flattening::{Direction, Module, PartSelectDirection, Port};
1515
use crate::instantiation::{
16-
InstantiatedModule, MultiplexerSource, RealWire, RealWireDataSource, RealWirePathElem,
16+
InstantiatedModule, IsPort, MultiplexerSource, RealWire, RealWireDataSource, RealWirePathElem,
1717
};
1818
use crate::to_string::{join_string_iter, trim_known_prefix};
1919
use crate::typing::concrete_type::{ConcreteGlobalReference, ConcreteTemplateArg, IntBounds};
@@ -387,7 +387,7 @@ impl<'g> CodeGenerationContext<'g> {
387387
)
388388
.unwrap();
389389
for (_id, port_wire) in &self.instance.wires {
390-
let Some(direction) = port_wire.is_port else {
390+
let IsPort::Port(_, direction) = port_wire.is_port else {
391391
continue;
392392
};
393393
let wire_doc = port_wire.source.wire_or_reg();
@@ -400,7 +400,7 @@ impl<'g> CodeGenerationContext<'g> {
400400
// Add latency registers for the interface declarations
401401
// Should not appear in the program text for extern modules
402402
for (port_wire_id, port_wire) in &self.instance.wires {
403-
if port_wire.is_port.is_some() {
403+
if matches!(port_wire.is_port, IsPort::Port(_, _)) {
404404
self.add_latency_registers(port_wire_id, port_wire).unwrap();
405405
}
406406
}
@@ -582,7 +582,7 @@ impl<'g> CodeGenerationContext<'g> {
582582
continue;
583583
}
584584

585-
if w.is_port.is_some() {
585+
if matches!(w.is_port, IsPort::Port(_, _)) {
586586
continue;
587587
}
588588
let wire_or_reg = w.source.wire_or_reg();

src/dev_aid/dot_graphs.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fs::{self, File};
33
use std::io::Write;
44

55
use crate::alloc::UUID;
6+
use crate::instantiation::IsPort;
67
use crate::to_string::{FmtWrapper, join_string_iter_formatter};
78
use crate::{
89
alloc::FlatAlloc,
@@ -91,9 +92,9 @@ fn custom_render_hardware_structure<'a>(
9192
let abs_lat = wire.absolute_latency;
9293
let label = format!("{}'{}", name, abs_lat);
9394
let (style, color) = match wire.is_port {
94-
Some(Direction::Input) => ("bold", "red"),
95-
Some(Direction::Output) => ("bold", "blue"),
96-
None => ("", "black"),
95+
IsPort::Port(_, Direction::Input) => ("bold", "red"),
96+
IsPort::Port(_, Direction::Output) => ("bold", "blue"),
97+
_ => ("", "black"),
9798
};
9899
writeln!(
99100
f,
@@ -237,16 +238,16 @@ fn custom_render_latency_count_graph(
237238
}
238239
write!(f, " {id} [label=\"{label}\"")?;
239240
match wire.is_port {
240-
Some(Direction::Input) => {
241+
IsPort::Port(_, Direction::Input) => {
241242
node_ids[idx].id = format!("{id}:e");
242243
// Makes the nice rightwards arrow-ey shape
243244
writeln!(f, ",shape=cds,style=filled,fillcolor=darkolivegreen3];")
244245
}
245-
Some(Direction::Output) => {
246+
IsPort::Port(_, Direction::Output) => {
246247
node_ids[idx].id = format!("{id}:w");
247248
writeln!(f, ",shape=cds,style=filled,fillcolor=skyblue];")
248249
}
249-
None => writeln!(f, ",style=filled,fillcolor=bisque];"),
250+
_ => writeln!(f, ",style=filled,fillcolor=bisque];"),
250251
}
251252
};
252253
for (sm_id, sm) in submodules {

src/dev_aid/lsp/hover_info.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ impl HoverCollector<'_> {
7575
for (_id, sm) in &inst.submodules {
7676
if sm.original_instruction == submodule_instr {
7777
self.sus_code(sm.display_interface(self.linker).to_string());
78-
self.monospace(display_all_infer_params(self.linker, sm).to_string());
78+
self.monospace(
79+
display_all_infer_params(self.linker, &inst.submodules, sm).to_string(),
80+
);
7981
}
8082
}
8183
}

src/instantiation/concrete_typecheck.rs

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::typing::set_unifier::{DelayedErrorCollector, FullySubstitutable, Unif
1414
use crate::typing::template::TemplateKind;
1515
use crate::typing::value_unifier::{ValueErrorReporter, ValueUnifierStore};
1616
use crate::typing::{concrete_type::ConcreteType, value_unifier::ValueUnifier};
17-
use crate::util::{ceil_div, floor_div};
17+
use crate::util::{all_equal, ceil_div, floor_div};
1818

1919
use super::*;
2020

@@ -563,7 +563,37 @@ impl<'inst, 'l: 'inst> ModuleTypingContext<'l> {
563563
};
564564
match latency_infer_problem.infer(from.maps_to_wire, to.maps_to_wire) {
565565
Ok(result) => InferenceResult::Found(IBig::from(result)),
566-
Err(err) => InferenceResult::LatencyError(err),
566+
Err(InferenceFailure::BadProblem) => InferenceResult::LatencyBadProblem,
567+
Err(InferenceFailure::NotReached) => InferenceResult::LatencyNotReached,
568+
Err(InferenceFailure::Poison { edge_from, edge_to }) => {
569+
let from_wire_id = latency_infer_problem
570+
.latency_count_problem
571+
.map_latency_node_to_wire[edge_from];
572+
let to_wire_id = latency_infer_problem
573+
.latency_count_problem
574+
.map_latency_node_to_wire[edge_to];
575+
576+
let w_from = &self.wires[from_wire_id];
577+
let w_to = &self.wires[to_wire_id];
578+
579+
let_unwrap!(
580+
IsPort::SubmodulePort(in_submod_id, port_from, Direction::Input),
581+
w_from.is_port
582+
);
583+
let_unwrap!(
584+
IsPort::SubmodulePort(out_submod_id, port_to, Direction::Output),
585+
w_to.is_port
586+
);
587+
let submod = all_equal([in_submod_id, out_submod_id]);
588+
589+
//w_from.is_port
590+
591+
InferenceResult::LatencyPoison {
592+
submod,
593+
port_from,
594+
port_to,
595+
}
596+
}
567597
}
568598
}
569599
}
@@ -632,7 +662,10 @@ impl<'inst, 'l: 'inst> ModuleTypingContext<'l> {
632662
for (info, last) in value_iter {
633663
match last {
634664
InferenceResult::PortNotUsed => continue,
635-
InferenceResult::NotFound | InferenceResult::LatencyError(_) => {
665+
InferenceResult::NotFound
666+
| InferenceResult::LatencyBadProblem
667+
| InferenceResult::LatencyNotReached
668+
| InferenceResult::LatencyPoison { .. } => {
636669
continue;
637670
}
638671
InferenceResult::Found(v) => {
@@ -657,7 +690,10 @@ impl<'inst, 'l: 'inst> ModuleTypingContext<'l> {
657690
for (info, last) in value_iter {
658691
match last {
659692
InferenceResult::PortNotUsed => continue, // Missing ports are okay, just skip their inference value
660-
InferenceResult::NotFound | InferenceResult::LatencyError(_) => {
693+
InferenceResult::NotFound
694+
| InferenceResult::LatencyBadProblem
695+
| InferenceResult::LatencyNotReached
696+
| InferenceResult::LatencyPoison { .. } => {
661697
total = None;
662698
break; // Missing value means failed inference
663699
}
@@ -683,7 +719,10 @@ impl<'inst, 'l: 'inst> ModuleTypingContext<'l> {
683719
for (info, last) in value_iter {
684720
match last {
685721
InferenceResult::PortNotUsed => continue, // Missing ports are okay, just skip their inference value
686-
InferenceResult::NotFound | InferenceResult::LatencyError(_) => {
722+
InferenceResult::NotFound
723+
| InferenceResult::LatencyBadProblem
724+
| InferenceResult::LatencyNotReached
725+
| InferenceResult::LatencyPoison { .. } => {
687726
total = None;
688727
break; // Missing value means failed inference
689728
}
@@ -852,18 +891,56 @@ impl<'inst, 'l: 'inst> ModuleTypingContext<'l> {
852891
Self::finalize_partial_bounds(path, &root.typ);
853892
}
854893

855-
for (_, sm) in &mut self.submodules {
894+
for sm_id in self.submodules.id_range() {
895+
let sm = &mut self.submodules[sm_id];
856896
let failed_to_substitute = !sm.refers_to.template_args.fully_substitute(substitutor);
897+
let sm = &self.submodules[sm_id]; // Immutable reborrow so we can use self.submodules
857898
if !did_already_error {
858899
if failed_to_substitute {
859-
self.errors.error(
900+
let sm_name = &sm.name;
901+
let mut err = self.errors.error(
860902
sm.get_span(self.link_info),
861903
format!(
862-
"Some submodule parameters were still unknown: {}\n{}",
904+
"Some submodule parameters of {sm_name} were still unknown: {}\n{}",
863905
sm.refers_to.display(self.linker),
864-
display_all_infer_params(self.linker, sm)
906+
display_all_infer_params(self.linker, &self.submodules, sm)
865907
),
866908
);
909+
for (template_id, known_values) in sm.last_infer_values.borrow().iter() {
910+
for known_v in known_values {
911+
match known_v {
912+
InferenceResult::LatencyPoison {
913+
submod,
914+
port_from,
915+
port_to,
916+
} => {
917+
let sm_md = &self.linker.modules[sm.refers_to.id];
918+
let template_name =
919+
&sm_md.link_info.parameters[template_id].name;
920+
921+
let poison_sm = &self.submodules[*submod];
922+
let poison_submod_md =
923+
&self.linker.modules[poison_sm.refers_to.id];
924+
925+
let sm_name = &sm.name;
926+
let poison_sm_name = &poison_sm.name;
927+
let poison_sm_refer_to =
928+
poison_sm.refers_to.display(&self.linker.globals);
929+
let from_port_name = &poison_submod_md.ports[*port_from].name;
930+
let to_port_name = &poison_submod_md.ports[*port_to].name;
931+
err = err.info_same_file(
932+
poison_sm.get_span(self.link_info),
933+
format!("{poison_sm_refer_to} {poison_sm_name} isn't resolved, in turn the unknown latency from {from_port_name} to {to_port_name} prevented {sm_name}.{template_name} from resolving"),
934+
);
935+
}
936+
InferenceResult::PortNotUsed
937+
| InferenceResult::NotFound
938+
| InferenceResult::LatencyBadProblem
939+
| InferenceResult::LatencyNotReached
940+
| InferenceResult::Found(_) => {}
941+
}
942+
}
943+
}
867944
} else if let Err(reason) = sm.refers_to.report_if_errors(
868945
self.linker,
869946
"Invalid arguments found in a submodule's template arguments",

src/instantiation/execute.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ impl<'l> ExecutionContext<'l> {
10161016
name: self.unique_name_producer.get_unique_name(""),
10171017
specified_latency: AbsLat::UNKNOWN,
10181018
absolute_latency: AbsLat::UNKNOWN,
1019-
is_port: None,
1019+
is_port: IsPort::PlainWire,
10201020
}))
10211021
}
10221022
fn alloc_bool(&mut self, v: bool, original_instruction: FlatID, domain: DomainID) -> WireID {
@@ -1030,7 +1030,7 @@ impl<'l> ExecutionContext<'l> {
10301030
name: self.unique_name_producer.get_unique_name(""),
10311031
specified_latency: AbsLat::UNKNOWN,
10321032
absolute_latency: AbsLat::UNKNOWN,
1033-
is_port: None,
1033+
is_port: IsPort::PlainWire,
10341034
})
10351035
}
10361036

@@ -1126,7 +1126,7 @@ impl<'l> ExecutionContext<'l> {
11261126
name,
11271127
specified_latency: AbsLat::UNKNOWN,
11281128
absolute_latency: AbsLat::UNKNOWN,
1129-
is_port: None,
1129+
is_port: IsPort::SubmodulePort(sub_module_id, port_id, port_data.direction),
11301130
});
11311131

11321132
if is_condition && port_data.direction == Direction::Input {
@@ -1378,7 +1378,7 @@ impl<'l> ExecutionContext<'l> {
13781378
source,
13791379
specified_latency: AbsLat::UNKNOWN,
13801380
absolute_latency: AbsLat::UNKNOWN,
1381-
is_port: None,
1381+
is_port: IsPort::PlainWire,
13821382
})])
13831383
}
13841384

@@ -1427,10 +1427,13 @@ impl<'l> ExecutionContext<'l> {
14271427

14281428
let specified_latency = self.get_specified_latency(wire_decl.latency_specifier)?;
14291429

1430-
let is_port = if let DeclarationKind::Port { direction, .. } = &wire_decl.decl_kind {
1431-
Some(*direction)
1430+
let is_port = if let DeclarationKind::Port {
1431+
direction, port_id, ..
1432+
} = &wire_decl.decl_kind
1433+
{
1434+
IsPort::Port(*port_id, *direction)
14321435
} else {
1433-
None
1436+
IsPort::PlainWire
14341437
};
14351438

14361439
let wire_id = self.wires.alloc(RealWire {
@@ -1769,16 +1772,21 @@ impl<'l> ExecutionContext<'l> {
17691772

17701773
let is_port = match interface.interface_kind {
17711774
InterfaceKind::RegularInterface => unreachable!(),
1772-
InterfaceKind::Action(_) => Some(Direction::Input),
1773-
InterfaceKind::Trigger(_) => Some(Direction::Output),
1775+
InterfaceKind::Action(port_id) => {
1776+
IsPort::Port(port_id, Direction::Input)
1777+
}
1778+
InterfaceKind::Trigger(port_id) => {
1779+
IsPort::Port(port_id, Direction::Output)
1780+
}
17741781
};
17751782

17761783
let source = match is_port {
1777-
Some(Direction::Input) => RealWireDataSource::ReadOnly,
1778-
Some(Direction::Output) | None => RealWireDataSource::Multiplexer {
1784+
IsPort::Port(_, Direction::Input) => RealWireDataSource::ReadOnly,
1785+
IsPort::Port(_, Direction::Output) => RealWireDataSource::Multiplexer {
17791786
is_state: None,
17801787
sources: Vec::new(),
17811788
},
1789+
_ => unreachable!(),
17821790
};
17831791
let domain = interface.domain.unwrap_physical();
17841792
let condition_wire = self.wires.alloc(RealWire {

src/instantiation/mod.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ pub enum RealWireDataSource {
119119
},
120120
}
121121

122+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123+
pub enum IsPort {
124+
PlainWire,
125+
Port(PortID, Direction),
126+
SubmodulePort(SubModuleID, PortID, Direction),
127+
}
128+
122129
/// An actual instantiated wire of an [InstantiatedModule] (See [InstantiatedModule::wires])
123130
///
124131
/// It can have a latency count and domain. All wires have a name, either the name they were given by the user, or a generated name like _1, _13
@@ -136,7 +143,7 @@ pub struct RealWire {
136143
pub specified_latency: AbsLat,
137144
/// The computed latencies after latency counting
138145
pub absolute_latency: AbsLat,
139-
pub is_port: Option<Direction>,
146+
pub is_port: IsPort,
140147
}
141148
impl RealWire {
142149
fn get_span(&self, link_info: &LinkInfo) -> Span {
@@ -401,8 +408,18 @@ pub enum InferenceResult {
401408
PortNotUsed,
402409
/// Means the port is valid, but the target couldn't be computed. Invalidates [ValueInferStrategy::Min] and [ValueInferStrategy::Max]
403410
NotFound,
404-
/// Latency Error
405-
LatencyError(InferenceFailure),
411+
/// See [InferenceFailure::BadProblem]
412+
LatencyBadProblem,
413+
/// See [InferenceFailure::NotReached]
414+
LatencyNotReached,
415+
/// See [InferenceFailure::Poison]
416+
LatencyPoison {
417+
submod: SubModuleID,
418+
/// Input port
419+
port_from: PortID,
420+
/// Output port
421+
port_to: PortID,
422+
},
406423
/// Valid value! Can be used for inferring
407424
Found(IBig),
408425
}
@@ -439,13 +456,13 @@ impl<'l> ModuleTypingContext<'l> {
439456
}
440457
}
441458

442-
let interface_ports = self.md.ports.map(|(_, port)| {
459+
let interface_ports = self.md.ports.map(|(port_id, port)| {
443460
let port_decl_id = port.declaration_instruction;
444461
let SubModuleOrWire::Wire(wire_id) = &self.generation_state[port_decl_id] else {
445462
return None;
446463
};
447464
let wire = &self.wires[*wire_id];
448-
assert_eq!(wire.is_port.unwrap(), port.direction);
465+
assert_eq!(wire.is_port, IsPort::Port(port_id, port.direction));
449466
Some(InstantiatedPort {
450467
wire: *wire_id,
451468
direction: port.direction,
@@ -634,7 +651,7 @@ impl ModuleTypingContext<'_> {
634651
},
635652
) in &self.wires
636653
{
637-
let is_port_str = if let Some(direction) = is_port {
654+
let is_port_str = if let IsPort::Port(_, direction) = is_port {
638655
format!("{direction} ").purple()
639656
} else {
640657
"".purple()

0 commit comments

Comments
 (0)