Skip to main content

build_driver_graph

Function build_driver_graph 

Source
pub fn build_driver_graph<'d>(
    netlist: &Netlist<'d>,
    slang_analysis: &Analysis<'d>,
) -> DriverGraph
Expand description

Second load-bearing finding, TDD’d against real sv-lang output (verified this task): sv_lang::Analysis (slang::analysis:: AnalysisManager) tracks driver/procedure data per CANONICAL instance only — confirmed empirically against a fixture with two instances (i0, i1) of one shared module: slang_analysis.procedures(i0_body) .count() == 3 (i0 happened to be canonical) while slang_analysis.procedures(i1_body).count() == 0, even though Task 2’s own DisableInstanceCaching finding already established i0’s and i1’s own AST bodies are genuinely distinct Symbols (never pointer- shared). This is AnalysisManager.h’s own documented behavior (“driver state tracked PER CANONICAL INSTANCE”) — a SEPARATE, analysis-layer-only canonicalization from DisableInstanceCaching‘s elaboration-layer pointer-identity guarantee. Consequence: Analysis::drivers/ Analysis::procedures can only ever be queried against ONE representative instance per deduped Template — never a genuinely per-instance call — so this function computes the write/read STRUCTURAL PATTERN (as (SymbolKey, SymbolKey) pairs) once per Template, against its own canonical instance (found by [representative_instance_of], which — unlike populate_driver_kinds’ “any instance is correct, Decision 4 guarantees identical shape” reasoning — must specifically locate the one instance Analysis actually populated data for, not merely the lowest InstanceId), then FANS that pattern OUT onto every instance sharing the Template, using each instance’s own InstanceId. Clock-domain seeding stays genuinely per-instance regardless (NL-076: it never calls Analysis at all — it reads Template.processes, already derived directly from raw sv_lang in elaborate(), so i0’s and i1’s own distinct InstantiatedSignalIds for their clk port already differ correctly with no canonicalization pitfall).

Deviation from the plan’s literal “built by zipping Analysis::drivers()/Analysis::driver_handles()” wording: this implementation uses Analysis::drivers() (DriverInfo) alone — DriverInfo already exposes both .kind() (DriverEntry.driver_kind) and .containing_symbol() (the process-identity resolution this graph needs); Analysis::driver_handles()’s ValueDriver adds .source()/.is_unidirectional_port()/bit-range/override-range data no test in this task’s plan section exercises, so it is not fetched. Adapts minimally, keeps the specified edge set.