From 8b663f9c84c8ec504c9fa4581273700188dc2b96 Mon Sep 17 00:00:00 2001 From: Deanyone Su Date: Fri, 25 Sep 2026 13:38:18 -0500 Subject: [PATCH] Optimize modport resolution with many interface instances (#8496) (#8497) --- docs/CONTRIBUTORS | 1 + src/V3LinkDot.cpp | 6 +++ test_regress/t/t_interface_modport_many.py | 16 ++++++++ test_regress/t/t_interface_modport_many.v | 43 ++++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100755 test_regress/t/t_interface_modport_many.py create mode 100644 test_regress/t/t_interface_modport_many.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b10d19e5c..7c1f043f6 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -69,6 +69,7 @@ David Ledger David Metz David Stanford David Turner +Deanyone Su dependabot[bot] Dercury Demin Han diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 8ef3a6ad2..906565144 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3130,6 +3130,10 @@ class LinkDotIfaceVisitor final : public VNVisitor { nodep->v3error("Modport item is not a clocking block: " << nodep->prettyNameQ()); } } + void visit(AstScope* nodep) override { // IfaceVisitor:: + if (nodep->user3SetOnce()) return; + iterateChildren(nodep); + } void visit(AstNode* nodep) override { iterateChildren(nodep); } // IfaceVisitor:: public: @@ -3144,6 +3148,8 @@ public: }; void LinkDotState::computeIfaceModSyms() { + // AstScope::user3() // bool. Already iterated by a LinkDotIfaceVisitor + const VNUser3InUse user3InUse; for (const auto& itr : m_ifaceModSyms) { AstIface* const nodep = itr.first; VSymEnt* const symp = itr.second; diff --git a/test_regress/t/t_interface_modport_many.py b/test_regress/t/t_interface_modport_many.py new file mode 100755 index 000000000..d583fe5fd --- /dev/null +++ b/test_regress/t/t_interface_modport_many.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=['--stats']) + +test.passes() diff --git a/test_regress/t/t_interface_modport_many.v b/test_regress/t/t_interface_modport_many.v new file mode 100644 index 000000000..001074018 --- /dev/null +++ b/test_regress/t/t_interface_modport_many.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Deanyone Su +// SPDX-License-Identifier: CC0-1.0 + +// Many instances of one interface, each with modports and some logic +// (performance test for modport resolution after scoping) + +interface ctrl_if; + logic [31:0] data; + logic valid; + logic ready; + logic [31:0] data_q; + always_comb ready = !valid || data[0]; + assign data_q = data ^ 32'h5a5a5a5a; + modport master_mp(output data, output valid, input ready); + modport slave_mp(input data, input valid, output ready); +endinterface + +module sink ( + ctrl_if.slave_mp s, + output logic o +); + assign o = s.valid & s.data[3]; +endmodule + +module t #( + parameter int N = 4000 +) ( + input logic [31:0] in, + output logic [N-1:0] out +); + ctrl_if intfs[N] (); + for (genvar i = 0; i < N; i++) begin : g + assign intfs[i].data = in + i; + assign intfs[i].valid = in[i%32]; + sink u_sink ( + .s(intfs[i]), + .o(out[i]) + ); + end +endmodule