2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-02-14 16:01:21 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Replace return/continue with jumps
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2010-02-14 16:01:21 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2023-01-01 16:18:39 +01:00
|
|
|
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2010-02-14 16:01:21 +01:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2010-02-14 16:01:21 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3LinkJump's Transformations:
|
|
|
|
|
//
|
|
|
|
|
// Each module:
|
2020-05-06 02:42:19 +02:00
|
|
|
// Look for BEGINs
|
|
|
|
|
// BEGIN(VAR...) -> VAR ... {renamed}
|
|
|
|
|
// FOR -> WHILEs
|
|
|
|
|
//
|
|
|
|
|
// Add JumpLabel which branches to after statements within JumpLabel
|
2020-05-07 03:33:05 +02:00
|
|
|
// RETURN -> JUMPBLOCK(statements with RETURN changed to JUMPGO, ..., JUMPLABEL)
|
|
|
|
|
// WHILE(... BREAK) -> JUMPBLOCK(WHILE(... statements with BREAK changed to JUMPGO),
|
|
|
|
|
// ... JUMPLABEL)
|
|
|
|
|
// WHILE(... CONTINUE) -> WHILE(JUMPBLOCK(... statements with CONTINUE changed to JUMPGO,
|
|
|
|
|
// ... JUMPPABEL))
|
2010-02-14 16:01:21 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2010-02-14 16:01:21 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
|
|
#include "V3LinkJump.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2010-02-14 16:01:21 +01:00
|
|
|
#include "V3Ast.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
2010-02-14 16:01:21 +01:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2010-02-14 16:01:21 +01:00
|
|
|
//######################################################################
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class LinkJumpVisitor final : public VNVisitor {
|
2010-02-14 16:01:21 +01:00
|
|
|
private:
|
|
|
|
|
// STATE
|
2020-08-16 15:55:36 +02:00
|
|
|
AstNodeModule* m_modp = nullptr; // Current module
|
|
|
|
|
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
2021-12-11 21:06:33 +01:00
|
|
|
AstNode* m_loopp = nullptr; // Current loop
|
2020-08-16 15:55:36 +02:00
|
|
|
bool m_loopInc = false; // In loop increment
|
|
|
|
|
bool m_inFork = false; // Under fork
|
|
|
|
|
int m_modRepeatNum = 0; // Repeat counter
|
2021-03-12 23:26:53 +01:00
|
|
|
std::vector<AstNodeBlock*> m_blockStack; // All begin blocks above current node
|
2012-03-20 21:01:53 +01:00
|
|
|
|
2010-02-14 16:01:21 +01:00
|
|
|
// METHODS
|
|
|
|
|
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Put label under given node, and if WHILE optionally at end of iteration
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Create label for " << nodep << endl);
|
2021-10-22 14:56:48 +02:00
|
|
|
if (VN_IS(nodep, JumpLabel)) return VN_AS(nodep, JumpLabel); // Done
|
2010-02-14 16:01:21 +01:00
|
|
|
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNode* underp = nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
bool under_and_next = true;
|
2020-04-23 03:31:40 +02:00
|
|
|
if (VN_IS(nodep, NodeBlock)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
underp = VN_AS(nodep, NodeBlock)->stmtsp();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(nodep, NodeFTask)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
underp = VN_AS(nodep, NodeFTask)->stmtsp();
|
2021-12-11 21:06:33 +01:00
|
|
|
} else if (VN_IS(nodep, Foreach)) {
|
|
|
|
|
if (endOfIter) {
|
2022-09-15 20:43:56 +02:00
|
|
|
underp = VN_AS(nodep, Foreach)->stmtsp();
|
2021-12-11 21:06:33 +01:00
|
|
|
} else {
|
|
|
|
|
underp = nodep;
|
|
|
|
|
under_and_next = false; // IE we skip the entire foreach
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(nodep, While)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (endOfIter) {
|
|
|
|
|
// Note we jump to end of bodysp; a FOR loop has its
|
|
|
|
|
// increment under incsp() which we don't skip
|
2022-09-15 20:43:56 +02:00
|
|
|
underp = VN_AS(nodep, While)->stmtsp();
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
underp = nodep;
|
|
|
|
|
under_and_next = false; // IE we skip the entire while
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-09 02:01:08 +01:00
|
|
|
} else if (AstDoWhile* const dowhilep = VN_CAST(nodep, DoWhile)) {
|
|
|
|
|
// Handle it the same as AstWhile, because it will be converted to it
|
|
|
|
|
if (endOfIter) {
|
|
|
|
|
underp = dowhilep->stmtsp();
|
|
|
|
|
} else {
|
|
|
|
|
underp = nodep;
|
|
|
|
|
under_and_next = false;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2019-09-09 13:50:21 +02:00
|
|
|
// Skip over variables as we'll just move them in a moment
|
2019-05-19 22:13:13 +02:00
|
|
|
// Also this would otherwise prevent us from using a label twice
|
|
|
|
|
// see t_func_return test.
|
2018-02-02 03:32:58 +01:00
|
|
|
while (underp && VN_IS(underp, Var)) underp = underp->nextp();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement");
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(5, " Underpoint is " << underp << endl);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
2019-07-06 18:57:50 +02:00
|
|
|
if (VN_IS(underp, JumpLabel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
return VN_AS(underp, JumpLabel);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // Move underp stuff to be under a new label
|
2022-11-20 21:06:49 +01:00
|
|
|
AstJumpBlock* const blockp = new AstJumpBlock{nodep->fileline(), nullptr};
|
|
|
|
|
AstJumpLabel* const labelp = new AstJumpLabel{nodep->fileline(), blockp};
|
2020-05-07 03:33:05 +02:00
|
|
|
blockp->labelp(labelp);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
2022-01-02 16:32:35 +01:00
|
|
|
VNRelinker repHandle;
|
2020-04-15 13:58:34 +02:00
|
|
|
if (under_and_next) {
|
|
|
|
|
underp->unlinkFrBackWithNext(&repHandle);
|
|
|
|
|
} else {
|
|
|
|
|
underp->unlinkFrBack(&repHandle);
|
|
|
|
|
}
|
2020-05-07 03:33:05 +02:00
|
|
|
repHandle.relink(blockp);
|
2010-02-14 16:01:21 +01:00
|
|
|
|
2020-05-07 03:33:05 +02:00
|
|
|
blockp->addStmtsp(underp);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Keep any AstVars under the function not under the new JumpLabel
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nextp = varp->nextp();
|
2022-11-09 02:01:08 +01:00
|
|
|
if (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-05-07 03:33:05 +02:00
|
|
|
// Label goes last
|
|
|
|
|
blockp->addEndStmtsp(labelp);
|
2019-05-19 22:13:13 +02:00
|
|
|
return labelp;
|
|
|
|
|
}
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->dead()) return;
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modp);
|
|
|
|
|
VL_RESTORER(m_modRepeatNum);
|
2020-01-20 19:27:27 +01:00
|
|
|
{
|
|
|
|
|
m_modp = nodep;
|
|
|
|
|
m_modRepeatNum = 0;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeFTask* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ftaskp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
m_ftaskp = nullptr;
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBlock* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " " << nodep << endl);
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_inFork);
|
2020-04-23 03:31:40 +02:00
|
|
|
m_blockStack.push_back(nodep);
|
2020-05-10 21:01:43 +02:00
|
|
|
{
|
|
|
|
|
m_inFork = m_inFork || VN_IS(nodep, Fork);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2020-04-23 03:31:40 +02:00
|
|
|
m_blockStack.pop_back();
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRepeat* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// So later optimizations don't need to deal with them,
|
|
|
|
|
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
|
|
|
|
// Note var can be signed or unsigned based on original number.
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext();
|
2021-06-21 00:32:57 +02:00
|
|
|
const string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Spec says value is integral, if negative is ignored
|
2022-01-02 19:56:40 +01:00
|
|
|
AstVar* const varp
|
2022-11-20 21:06:49 +01:00
|
|
|
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()};
|
2019-05-19 22:13:13 +02:00
|
|
|
varp->usedLoopIdx(true);
|
2022-09-15 20:43:56 +02:00
|
|
|
m_modp->addStmtsp(varp);
|
2022-11-20 21:06:49 +01:00
|
|
|
AstNode* initsp = new AstAssign{
|
|
|
|
|
nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::WRITE}, countp};
|
|
|
|
|
AstNode* const decp = new AstAssign{
|
|
|
|
|
nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::WRITE},
|
|
|
|
|
new AstSub{nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::READ},
|
|
|
|
|
new AstConst{nodep->fileline(), 1}}};
|
|
|
|
|
AstNodeExpr* const zerosp = new AstConst{nodep->fileline(), AstConst::Signed32{}, 0};
|
|
|
|
|
AstNodeExpr* const condp = new AstGtS{
|
|
|
|
|
nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::READ}, zerosp};
|
2022-09-15 20:43:56 +02:00
|
|
|
AstNode* const bodysp = nodep->stmtsp();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (bodysp) bodysp->unlinkFrBackWithNext();
|
2022-11-20 21:06:49 +01:00
|
|
|
AstNode* newp = new AstWhile{nodep->fileline(), condp, bodysp, decp};
|
2019-05-19 22:13:13 +02:00
|
|
|
initsp = initsp->addNext(newp);
|
|
|
|
|
newp = initsp;
|
|
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWhile* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Don't need to track AstRepeat/AstFor as they have already been converted
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_loopp);
|
|
|
|
|
VL_RESTORER(m_loopInc);
|
|
|
|
|
{
|
|
|
|
|
m_loopp = nodep;
|
|
|
|
|
m_loopInc = false;
|
|
|
|
|
iterateAndNextNull(nodep->precondsp());
|
|
|
|
|
iterateAndNextNull(nodep->condp());
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextNull(nodep->stmtsp());
|
2020-08-25 03:10:43 +02:00
|
|
|
m_loopInc = true;
|
|
|
|
|
iterateAndNextNull(nodep->incsp());
|
|
|
|
|
}
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-11-09 02:01:08 +01:00
|
|
|
void visit(AstDoWhile* nodep) override {
|
|
|
|
|
// It is converted to AstWhile in this visit method
|
|
|
|
|
VL_RESTORER(m_loopp);
|
|
|
|
|
VL_RESTORER(m_loopInc);
|
|
|
|
|
{
|
|
|
|
|
m_loopp = nodep;
|
|
|
|
|
m_loopInc = false;
|
|
|
|
|
iterateAndNextNull(nodep->precondsp());
|
|
|
|
|
iterateAndNextNull(nodep->condp());
|
|
|
|
|
iterateAndNextNull(nodep->stmtsp());
|
|
|
|
|
m_loopInc = true;
|
|
|
|
|
iterateAndNextNull(nodep->incsp());
|
|
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr;
|
2022-11-09 02:01:08 +01:00
|
|
|
AstNode* const bodyp = nodep->stmtsp() ? nodep->stmtsp()->unlinkFrBack() : nullptr;
|
|
|
|
|
AstNode* const incsp = nodep->incsp() ? nodep->incsp()->unlinkFrBack() : nullptr;
|
|
|
|
|
AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp, incsp};
|
|
|
|
|
nodep->replaceWith(whilep);
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
|
|
|
if (bodyp) whilep->addHereThisAsNext(bodyp->cloneTree(false));
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstForeach* nodep) override {
|
2021-12-11 21:06:33 +01:00
|
|
|
VL_RESTORER(m_loopp);
|
|
|
|
|
{
|
|
|
|
|
m_loopp = nodep;
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextNull(nodep->stmtsp());
|
2021-12-11 21:06:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstReturn* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstFunc* const funcp = VN_CAST(m_ftaskp, Func);
|
2020-05-10 21:01:43 +02:00
|
|
|
if (m_inFork) {
|
|
|
|
|
nodep->v3error("Return isn't legal under fork (IEEE 1800-2017 9.2.3)");
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
|
|
|
|
return;
|
|
|
|
|
} else if (!m_ftaskp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Return isn't underneath a task or function");
|
2022-11-09 12:32:22 +01:00
|
|
|
} else if (funcp && !nodep->lhsp() && !funcp->isConstructor()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Return underneath a function should have return value");
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (!funcp && nodep->lhsp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->v3error("Return underneath a task shouldn't have return value");
|
|
|
|
|
} else {
|
|
|
|
|
if (funcp && nodep->lhsp()) {
|
|
|
|
|
// Set output variable to return value
|
2022-11-20 21:06:49 +01:00
|
|
|
nodep->addHereThisAsNext(new AstAssign{
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->fileline(),
|
2022-11-20 21:06:49 +01:00
|
|
|
new AstVarRef{nodep->fileline(), VN_AS(funcp->fvarp(), Var), VAccess::WRITE},
|
|
|
|
|
nodep->lhsp()->unlinkFrBackWithNext()});
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
// Jump to the end of the function call
|
2021-11-13 19:50:44 +01:00
|
|
|
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
|
2022-11-20 21:06:49 +01:00
|
|
|
nodep->addHereThisAsNext(new AstJumpGo{nodep->fileline(), labelp});
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstBreak* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!m_loopp) {
|
|
|
|
|
nodep->v3error("break isn't underneath a loop");
|
|
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Jump to the end of the loop
|
2021-11-13 19:50:44 +01:00
|
|
|
AstJumpLabel* const labelp = findAddLabel(m_loopp, false);
|
2022-11-20 21:06:49 +01:00
|
|
|
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstContinue* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!m_loopp) {
|
|
|
|
|
nodep->v3error("continue isn't underneath a loop");
|
|
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Jump to the end of this iteration
|
|
|
|
|
// If a "for" loop then need to still do the post-loop increment
|
2021-11-13 19:50:44 +01:00
|
|
|
AstJumpLabel* const labelp = findAddLabel(m_loopp, true);
|
2022-11-20 21:06:49 +01:00
|
|
|
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDisable* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(8, " DISABLE " << nodep << endl);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNodeBlock* blockp = nullptr;
|
2022-04-18 19:03:56 +02:00
|
|
|
for (AstNodeBlock* const stackp : vlstd::reverse_view(m_blockStack)) {
|
|
|
|
|
UINFO(9, " UNDERBLK " << stackp << endl);
|
|
|
|
|
if (stackp->name() == nodep->name()) {
|
|
|
|
|
blockp = stackp;
|
2019-05-19 22:13:13 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) { UINFO(0, "\n"); blockp->dumpTree("- labeli: "); }
|
2020-04-23 03:31:40 +02:00
|
|
|
if (!blockp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ());
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstBegin* const beginp = VN_CAST(blockp, Begin)) {
|
2020-04-23 03:31:40 +02:00
|
|
|
// Jump to the end of the named block
|
2021-11-13 19:50:44 +01:00
|
|
|
AstJumpLabel* const labelp = findAddLabel(beginp, false);
|
2022-11-20 21:06:49 +01:00
|
|
|
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
2020-04-23 03:31:40 +02:00
|
|
|
} else {
|
2020-06-10 01:20:16 +02:00
|
|
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->unlinkFrBack();
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2022-11-27 14:31:22 +01:00
|
|
|
// if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree("- labelo: "); }
|
2011-06-29 03:26:49 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true);
|
2011-01-06 12:46:19 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConst*) override {}
|
|
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2010-02-14 16:01:21 +01:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-16 15:55:36 +02:00
|
|
|
explicit LinkJumpVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-09-16 12:22:11 +02:00
|
|
|
~LinkJumpVisitor() override = default;
|
2010-02-14 16:01:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Task class functions
|
|
|
|
|
|
|
|
|
|
void V3LinkJump::linkJump(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 16:52:36 +01:00
|
|
|
{ LinkJumpVisitor{nodep}; } // Destruct before checking
|
2022-09-18 21:53:42 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTree() >= 3);
|
2010-02-14 16:01:21 +01:00
|
|
|
}
|