diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index f61dd2303..43cc60555 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -45,6 +45,9 @@ class LocalizeVisitor final : public VNVisitor { // AstVarScope::user3p() -> Set of CFuncs referencing this VarScope. (via m_accessors) // AstCFunc::user4p() -> Multimap of 'VarScope -> VarRefs that reference that VarScope' // in this function. (via m_references) + // AstVarScope::user4() -> Bool indicating VarScope cannot be optimized + // - compared to AstVarScope::user1 this guarantees that this + // scope won't be optimized. const VNUser1InUse m_user1InUse; const VNUser3InUse m_user3InUse; const VNUser4InUse m_user4InUse; @@ -60,11 +63,15 @@ class LocalizeVisitor final : public VNVisitor { // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current active function uint32_t m_nodeDepth = 0; // Node depth under m_cfuncp + bool m_inSuperConstructorCallStmt = false; // If under super constructor call statement // METHODS bool isOptimizable(AstVarScope* nodep) { // Don't want to malloc/free the backing store all the time if (VN_IS(nodep->dtypep(), NBACommitQueueDType)) return false; + // Variables used in super constructor call can't be localized, because + // in C++ there is no way to declare them before base class constructor call + if (nodep->user4()) return false; return ((!nodep->user1() // Not marked as not optimizable, or ... // .. a block temp used in a single CFunc || (nodep->varp()->varType() == VVarType::BLOCKTEMP @@ -147,6 +154,14 @@ class LocalizeVisitor final : public VNVisitor { iterateChildrenConst(nodep); } + void visit(AstCNew* nodep) override { + VL_RESTORER(m_inSuperConstructorCallStmt); + m_inSuperConstructorCallStmt + = m_cfuncp->isConstructor() && VN_IS(nodep->backp(), StmtExpr); + m_cfuncp->user1(true); // Mark caller as not a leaf function + iterateChildren(nodep); + } + void visit(AstCCall* nodep) override { m_cfuncp->user1(true); // Mark caller as not a leaf function iterateChildrenConst(nodep); @@ -195,8 +210,11 @@ class LocalizeVisitor final : public VNVisitor { // Remember the reference so we can fix it up later (we always need this as well) m_references(m_cfuncp).emplace(varScopep, nodep); - // Check if already marked as not optimizable - if (!varScopep->user1()) { + if (m_inSuperConstructorCallStmt) { + // Variable used in super constructor call can't be localized + varScopep->user1(true); + varScopep->user4(true); + } else if (!varScopep->user1()) { // Check if already marked as not optimizable // Note: we only check read variables, as it's ok to localize (and in fact discard) // any variables that are only written but never read. if (nodep->access().isReadOrRW() && !varScopep->user2()) { diff --git a/test_regress/t/t_class_super_new3.py b/test_regress/t/t_class_super_new3.py new file mode 100755 index 000000000..f989a35fb --- /dev/null +++ b/test_regress/t/t_class_super_new3.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_super_new3.v b/test_regress/t/t_class_super_new3.v new file mode 100644 index 000000000..c216e91a9 --- /dev/null +++ b/test_regress/t/t_class_super_new3.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class Base; + int j; + function new(int x); + j = x; + endfunction + static function int get_default(); + return 8; + endfunction +endclass +class Derived extends Base; + function new(); + super.new(get_default()); + endfunction +endclass + +module t; + initial begin + Derived d = new; + if (d.j != 8) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule