diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 5ba270934..06aee97a0 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -3057,6 +3057,7 @@ class AstJumpBlock final : public AstNodeStmt { // // @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment + VIsCached m_purity; // Pure state public: // After construction must call ->labelp to associate with appropriate label AstJumpBlock(FileLine* fl, AstNode* stmtsp) @@ -3072,6 +3073,10 @@ public: void labelNum(int flag) { m_labelNum = flag; } AstJumpLabel* labelp() const { return m_labelp; } void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } + bool isPure() override; + +private: + bool getPurityRecurse() const; }; class AstJumpGo final : public AstNodeStmt { // Jump point; branch down to a JumpLabel @@ -3263,6 +3268,7 @@ public: this->exprp(exprp); } ASTGEN_MEMBERS_AstStmtExpr; + bool isPure() override { return exprp()->isPure(); } }; class AstStop final : public AstNodeStmt { public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b146d984a..7fe45a45f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1002,6 +1002,16 @@ const char* AstJumpBlock::broken() const { BROKEN_RTN(!labelp()->brokeExistsBelow()); return nullptr; } +bool AstJumpBlock::isPure() { + if (!m_purity.isCached()) m_purity.set(getPurityRecurse()); + return m_purity.get(); +} +bool AstJumpBlock::getPurityRecurse() const { + for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (!stmtp->isPure()) return false; + } + return true; +} string AstScope::nameDotless() const { string result = shortName(); diff --git a/test_regress/t/t_impure_cond_empty_if.pl b/test_regress/t/t_impure_cond_empty_if.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_impure_cond_empty_if.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_impure_cond_empty_if.v b/test_regress/t/t_impure_cond_empty_if.v new file mode 100644 index 000000000..6cf409ea6 --- /dev/null +++ b/test_regress/t/t_impure_cond_empty_if.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class uvm_component; + int x; + function void set_x(); + x = 1; + endfunction + function new(); + if(call_set_return_false()); + endfunction + function bit call_set_return_false; + set_x(); + return 0; + endfunction +endclass + +module t; + initial begin + automatic uvm_component a = new; + if (a.x != 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule