From de3095e3b4c459306b57f1ba0976a0d177a4fbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Mon, 22 May 2023 14:29:01 +0200 Subject: [PATCH] Fix missing class forward declarations (#4151) --- src/V3CUse.cpp | 35 +++++++++++++++++++++++----- src/V3EmitCBase.cpp | 21 +++++------------ src/V3EmitCBase.h | 15 ++++++++++++ src/V3EmitCHeaders.cpp | 16 +++++++++++-- test_regress/t/t_cuse_forward.pl | 17 ++++++++++++++ test_regress/t/t_cuse_forward.v | 39 ++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 23 deletions(-) create mode 100755 test_regress/t/t_cuse_forward.pl create mode 100644 test_regress/t/t_cuse_forward.v diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index d9de9a10d..0bbab0886 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -45,12 +45,16 @@ class CUseVisitor final : public VNVisitor { const VNUser1InUse m_inuser1; // MEMBERS - bool m_impOnly = false; // In details needed only for implementation AstNodeModule* const m_modp; // Current module std::set> m_didUse; // What we already used + bool m_dtypesImplOnly = false; // METHODS void addNewUse(AstNode* nodep, VUseType useType, const string& name) { + if (m_dtypesImplOnly + && (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS)) + return; + if (m_didUse.emplace(useType, name).second) { AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name}; m_modp->addStmtsp(newp); @@ -61,12 +65,29 @@ class CUseVisitor final : public VNVisitor { // VISITORS void visit(AstClassRefDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once - if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); - // Need to include extends() when we implement, but no need for pointers to know - VL_RESTORER(m_impOnly); + addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); + } + void visit(AstCFunc* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + iterateAndNextNull(nodep->argsp()); + { - m_impOnly = true; - iterateChildren(nodep->classp()); // This also gets all extend classes + VL_RESTORER(m_dtypesImplOnly); + m_dtypesImplOnly = true; + + iterateAndNextNull(nodep->initsp()); + iterateAndNextNull(nodep->stmtsp()); + iterateAndNextNull(nodep->finalsp()); + } + } + void visit(AstCReturn* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + if (m_dtypesImplOnly) { + for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) { + if (exprp->dtypep()) iterate(exprp->dtypep()); + } + } else { + iterateChildren(nodep); } } void visit(AstNodeDType* nodep) override { @@ -79,6 +100,8 @@ class CUseVisitor final : public VNVisitor { if (stypep && stypep->classOrPackagep()) { addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name()); iterateChildren(stypep); + } else if (AstClassRefDType* const classp = VN_CAST(nodep->skipRefp(), ClassRefDType)) { + addNewUse(nodep, VUseType::INT_FWD_CLASS, classp->name()); } } void visit(AstNode* nodep) override { diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 1bec37b9c..a7779be62 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -224,21 +224,12 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { } void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) { - string nl; - for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { - if (AstCUse* const usep = VN_CAST(itemp, CUse)) { - if (usep->useType() == useType) { - if (usep->useType().isInclude()) { - puts("#include \"" + prefixNameProtect(usep) + ".h\"\n"); - } - if (usep->useType().isFwdClass()) { - puts("class " + prefixNameProtect(usep) + ";\n"); - } - nl = "\n"; - } - } - } - puts(nl); + bool nl = false; + forModCUse(modp, useType, [&](string entry) { + puts(entry); + nl = true; + }); + if (nl) puts("\n"); } void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) { diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 5ae0074c4..4be6b7b91 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -113,6 +113,21 @@ public: void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); void emitVarDecl(const AstVar* nodep, bool asRef = false); + template + static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) { + for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { + if (AstCUse* const usep = VN_CAST(itemp, CUse)) { + if (usep->useType() == useType) { + if (usep->useType().isInclude()) { + action("#include \"" + prefixNameProtect(usep) + ".h\"\n"); + } + if (usep->useType().isFwdClass()) { + action("class " + prefixNameProtect(usep) + ";\n"); + } + } + } + } + } void emitModCUse(const AstNodeModule* modp, VUseType useType); void emitTextSection(const AstNodeModule* modp, VNType type); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 04eac47d7..4d2a77d60 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -22,6 +22,7 @@ #include "V3Global.h" #include +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -287,11 +288,9 @@ class EmitCHeader final : public EmitCConstInit { + ".h\"\n"); } } - emitModCUse(modp, VUseType::INT_INCLUDE); // Forward declarations required by this AstNodeModule puts("\nclass " + symClassName() + ";\n"); - emitModCUse(modp, VUseType::INT_FWD_CLASS); // From `systemc_header emitTextSection(modp, VNType::atScHdr); @@ -361,6 +360,19 @@ class EmitCHeader final : public EmitCConstInit { if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); if (v3Global.usesTiming()) puts("#include \"verilated_timing.h\"\n"); + std::set cuse_set; + auto add_to_cuse_set = [&](string s) { cuse_set.insert(s); }; + + forModCUse(modp, VUseType::INT_INCLUDE, add_to_cuse_set); + forModCUse(modp, VUseType::INT_FWD_CLASS, add_to_cuse_set); + if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) { + forModCUse(packagep->classp(), VUseType::INT_INCLUDE, add_to_cuse_set); + forModCUse(packagep->classp(), VUseType::INT_FWD_CLASS, add_to_cuse_set); + } + + for (const string& s : cuse_set) puts(s); + puts("\n"); + emitAll(modp); if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) { diff --git a/test_regress/t/t_cuse_forward.pl b/test_regress/t/t_cuse_forward.pl new file mode 100755 index 000000000..f17d7f547 --- /dev/null +++ b/test_regress/t/t_cuse_forward.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_cuse_forward.v b/test_regress/t/t_cuse_forward.v new file mode 100644 index 000000000..c1178a2d7 --- /dev/null +++ b/test_regress/t/t_cuse_forward.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Baz; +endclass + +class Bar#(type T) extends T; +endclass + +class Foo; + typedef struct { + int field; + } Zee; + + task t1(); + // Refer to Baz CLASSREFDTYPE node in implementation (via CLASSEXTENDS) + Bar#(Baz) b = new; + endtask + // Refer to the very same Baz CLASSREFDTYPE node again, this time within interface + task t2(Bar#(Baz)::T b); + endtask +endclass + +class Moo; + // Use Foo::Zee to cause inclusion of Foo's header file + Foo::Zee z; +endclass + +module t(); + initial begin + // Use Moo in top module to add Moo to root, causing inclusion of Foo header into + // root header. + Moo moo; + moo = new; + end +endmodule