2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Add temporaries, such as for premit nodes
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02: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
|
2009-05-04 23:07:57 +02: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
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Premit's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Each module:
|
2019-05-19 22:13:13 +02:00
|
|
|
// For each wide OP, make a a temporary variable with the wide value
|
|
|
|
|
// For each deep expression, assign expression to temporary.
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
2019-09-09 13:50:21 +02:00
|
|
|
// Each display (independent transformation; here as Premit is a good point)
|
2019-05-19 22:13:13 +02:00
|
|
|
// If autoflush, insert a flush
|
2008-07-16 20:06:08 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-09-25 04:12:23 +02:00
|
|
|
#define VL_MT_DISABLED_CODE_UNIT 1
|
|
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3Premit.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Ast.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
2021-05-08 21:04:56 +02:00
|
|
|
#include "V3Stats.h"
|
2021-08-11 15:30:00 +02:00
|
|
|
#include "V3UniqueNames.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <algorithm>
|
2014-07-04 15:13:59 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2021-05-08 21:04:56 +02:00
|
|
|
constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to static constant
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Premit state, as a visitor of each AstNode
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class PremitVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
2022-10-12 11:19:21 +02:00
|
|
|
// AstNodeExpr::user() -> bool. True if iterated already
|
2022-01-09 23:34:10 +01:00
|
|
|
// *::user3() -> Used when visiting AstNodeAssign
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser1InUse m_inuser1;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2023-05-27 15:43:23 +02:00
|
|
|
// STATE - across all visitors
|
|
|
|
|
VDouble0 m_extractedToConstPool; // Statistic tracking
|
|
|
|
|
|
2023-05-21 20:06:39 +02:00
|
|
|
// STATE - for current visit position (use VL_RESTORER)
|
2020-10-31 13:59:35 +01:00
|
|
|
AstCFunc* m_cfuncp = nullptr; // Current block
|
2023-08-28 15:44:41 +02:00
|
|
|
int m_tmpVarCnt = 0; // Number of temporary variables created inside a function
|
2020-08-16 15:55:36 +02:00
|
|
|
AstNode* m_stmtp = nullptr; // Current statement
|
2022-10-12 11:19:21 +02:00
|
|
|
AstCCall* m_callp = nullptr; // Current AstCCall
|
2020-08-16 15:55:36 +02:00
|
|
|
AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions
|
|
|
|
|
AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions
|
|
|
|
|
bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
bool assignNoTemp(AstNodeAssign* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())
|
2018-02-02 03:32:58 +01:00
|
|
|
&& VN_IS(nodep->rhsp(), Const));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
void checkNode(AstNodeExpr* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Consider adding a temp for this expression.
|
|
|
|
|
// We need to avoid adding temps to the following:
|
|
|
|
|
// ASSIGN(x, *here*)
|
|
|
|
|
// ASSIGN(CONST*here*, VARREF(!sc))
|
|
|
|
|
// ARRAYSEL(*here*, ...) (No wides can be in any argument but first,
|
|
|
|
|
// so we don't check which arg is wide)
|
|
|
|
|
// ASSIGN(x, SEL*HERE*(ARRAYSEL()...) (m_assignLhs==true handles this.)
|
2020-04-15 13:58:34 +02:00
|
|
|
// UINFO(9, " Check: " << nodep << endl);
|
|
|
|
|
// UINFO(9, " Detail stmtp=" << (m_stmtp?"Y":"N") << " U=" << (nodep->user1()?"Y":"N")
|
|
|
|
|
// << " IW=" << (nodep->isWide()?"Y":"N") << endl);
|
|
|
|
|
if (m_stmtp && !nodep->user1()) { // Not already done
|
2019-05-19 22:13:13 +02:00
|
|
|
if (nodep->isWide()) {
|
|
|
|
|
if (m_assignLhs) {
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), NodeAssign)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& assignNoTemp(VN_AS(nodep->firstAbovep(), NodeAssign))) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Not much point if it's just a direct assignment to a constant
|
2018-02-02 03:32:58 +01:00
|
|
|
} else if (VN_IS(nodep->backp(), Sel)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& VN_AS(nodep->backp(), Sel)->widthp() == nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstSel::width must remain a constant
|
2020-11-19 14:02:58 +01:00
|
|
|
} else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel))
|
2022-10-12 11:19:21 +02:00
|
|
|
|| ((m_callp || VN_IS(m_stmtp, CStmt)) && VN_IS(nodep, ArraySel))) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// ArraySel's are pointer refs, ignore
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Cre Temp: " << nodep << endl);
|
2019-05-19 22:13:13 +02:00
|
|
|
createDeepTemp(nodep, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void insertBeforeStmt(AstNode* newp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Insert newp before m_stmtp
|
|
|
|
|
if (m_inWhilep) {
|
|
|
|
|
// Statements that are needed for the 'condition' in a while
|
|
|
|
|
// actually have to be put before & after the loop, since we
|
|
|
|
|
// can't do any statements in a while's (cond).
|
|
|
|
|
m_inWhilep->addPrecondsp(newp);
|
|
|
|
|
} else if (m_inTracep) {
|
|
|
|
|
m_inTracep->addPrecondsp(newp);
|
|
|
|
|
} else if (m_stmtp) {
|
2022-07-13 14:55:40 +02:00
|
|
|
m_stmtp->addHereThisAsNext(newp);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
newp->v3fatalSrc("No statement insertion point.");
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:33:11 +01:00
|
|
|
void createDeepTemp(AstNodeExpr* nodep, bool noSubst) {
|
2021-06-13 16:05:55 +02:00
|
|
|
if (nodep->user1SetOnce()) return; // Only add another assignment for this node
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-01-02 16:32:35 +01:00
|
|
|
VNRelinker relinker;
|
2021-06-13 16:05:55 +02:00
|
|
|
nodep->unlinkFrBack(&relinker);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
FileLine* const fl = nodep->fileline();
|
2021-05-08 21:04:56 +02:00
|
|
|
AstVar* varp = nullptr;
|
|
|
|
|
AstConst* const constp = VN_CAST(nodep, Const);
|
2021-06-13 16:05:55 +02:00
|
|
|
const bool useConstPool = constp // Is a constant
|
|
|
|
|
&& (constp->width() >= STATIC_CONST_MIN_WIDTH) // Large enough
|
|
|
|
|
&& !constp->num().isFourState() // Not four state
|
|
|
|
|
&& !constp->num().isString(); // Not a string
|
|
|
|
|
if (useConstPool) {
|
|
|
|
|
// Extract into constant pool.
|
2022-06-04 01:41:59 +02:00
|
|
|
const bool merge = v3Global.opt.fMergeConstPool();
|
2021-06-13 16:05:55 +02:00
|
|
|
varp = v3Global.rootp()->constPoolp()->findConst(constp, merge)->varp();
|
|
|
|
|
nodep->deleteTree();
|
|
|
|
|
++m_extractedToConstPool;
|
2021-05-08 21:04:56 +02:00
|
|
|
} else {
|
2021-08-11 15:30:00 +02:00
|
|
|
// Keep as local temporary. Name based on hash of node for output stability.
|
2023-08-28 15:44:41 +02:00
|
|
|
varp = new AstVar{fl, VVarType::STMTTEMP, "__Vtemp_" + cvtToStr(++m_tmpVarCnt),
|
|
|
|
|
nodep->dtypep()};
|
2021-05-08 21:04:56 +02:00
|
|
|
m_cfuncp->addInitsp(varp);
|
|
|
|
|
// Put assignment before the referencing statement
|
2022-11-20 21:06:49 +01:00
|
|
|
insertBeforeStmt(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, nodep});
|
2021-05-08 21:04:56 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
// Do not remove VarRefs to this in V3Const
|
|
|
|
|
if (noSubst) varp->noSubst(true);
|
|
|
|
|
|
|
|
|
|
// Replace node with VarRef to new Var
|
2022-11-20 21:06:49 +01:00
|
|
|
relinker.relink(new AstVarRef{fl, varp, VAccess::READ});
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " MOD " << nodep << endl);
|
2021-05-08 21:04:56 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCFunc* nodep) override {
|
2020-10-31 13:59:35 +01:00
|
|
|
VL_RESTORER(m_cfuncp);
|
2023-08-28 15:44:41 +02:00
|
|
|
VL_RESTORER(m_tmpVarCnt);
|
2023-05-21 18:03:13 +02:00
|
|
|
m_cfuncp = nodep;
|
2023-08-28 15:44:41 +02:00
|
|
|
m_tmpVarCnt = 0;
|
2023-05-21 18:03:13 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-05-21 18:03:13 +02:00
|
|
|
|
|
|
|
|
#define RESTORER_START_STATEMENT() \
|
|
|
|
|
VL_RESTORER(m_assignLhs); \
|
|
|
|
|
VL_RESTORER(m_stmtp);
|
|
|
|
|
|
|
|
|
|
// Must use RESTORER_START_STATEMENT() in visitors using this
|
2006-08-26 13:35:28 +02:00
|
|
|
void startStatement(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignLhs = false;
|
2020-10-31 13:59:35 +01:00
|
|
|
if (m_cfuncp) m_stmtp = nodep;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-05-21 18:03:13 +02:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWhile* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " WHILE " << nodep << endl);
|
2023-05-21 18:03:13 +02:00
|
|
|
RESTORER_START_STATEMENT();
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->precondsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
2023-05-21 18:03:13 +02:00
|
|
|
{
|
|
|
|
|
VL_RESTORER(m_inWhilep);
|
|
|
|
|
m_inWhilep = nodep;
|
|
|
|
|
iterateAndNextNull(nodep->condp());
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
2022-09-15 20:43:56 +02:00
|
|
|
iterateAndNextNull(nodep->stmtsp());
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->incsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
2023-05-21 18:03:13 +02:00
|
|
|
RESTORER_START_STATEMENT();
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
|
|
|
|
{
|
2022-01-09 23:34:10 +01:00
|
|
|
bool noopt = false;
|
|
|
|
|
{
|
|
|
|
|
const VNUser3InUse user3InUse;
|
2022-10-20 14:48:44 +02:00
|
|
|
nodep->lhsp()->foreach([](const AstVarRef* refp) {
|
2022-01-09 23:34:10 +01:00
|
|
|
if (refp->access().isWriteOrRW()) refp->varp()->user3(true);
|
|
|
|
|
});
|
2022-10-20 14:48:44 +02:00
|
|
|
nodep->rhsp()->foreach([&noopt](const AstVarRef* refp) {
|
2022-01-09 23:34:10 +01:00
|
|
|
if (refp->access().isReadOnly() && refp->varp()->user3()) noopt = true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
if (noopt && !nodep->user1()) {
|
2021-04-21 15:21:06 +02:00
|
|
|
nodep->user1(true);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Need to do this even if not wide, as e.g. a select may be on a wide operator
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Deep temp for LHS/RHS\n");
|
2019-05-19 22:13:13 +02:00
|
|
|
createDeepTemp(nodep->rhsp(), false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->rhsp());
|
2023-05-21 18:03:13 +02:00
|
|
|
{
|
2023-09-01 00:29:58 +02:00
|
|
|
// VL_RESTORER(m_assignLhs); // Not needed; part of RESTORER_START_STATEMENT()
|
2023-05-21 18:03:13 +02:00
|
|
|
m_assignLhs = true;
|
|
|
|
|
iterateAndNextNull(nodep->lhsp());
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeStmt* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, " STMT " << nodep << endl);
|
2023-05-21 18:03:13 +02:00
|
|
|
RESTORER_START_STATEMENT();
|
2019-01-06 23:38:27 +01:00
|
|
|
startStatement(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTraceInc* nodep) override {
|
2023-05-21 18:03:13 +02:00
|
|
|
RESTORER_START_STATEMENT();
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
2023-05-21 18:03:13 +02:00
|
|
|
VL_RESTORER(m_inTracep);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_inTracep = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
void visitShift(AstNodeBiop* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
2023-10-15 04:34:37 +02:00
|
|
|
UINFO(4, " ShiftFix " << nodep << endl);
|
|
|
|
|
const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
|
|
|
|
|
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
|
|
|
|
|
shiftp->v3error(
|
|
|
|
|
"Unsupported: Shifting of by over 32-bit number isn't supported."
|
|
|
|
|
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
|
|
|
|
}
|
|
|
|
|
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
|
|
|
|
|
// C operator's width must be < maximum shift which is
|
|
|
|
|
// based on Verilog width
|
|
|
|
|
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
|
|
|
|
AstNode* newp;
|
|
|
|
|
if (VN_IS(nodep, ShiftL)) {
|
|
|
|
|
newp = new AstShiftLOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
|
|
|
|
nodep->rhsp()->unlinkFrBack()};
|
|
|
|
|
} else if (VN_IS(nodep, ShiftR)) {
|
|
|
|
|
newp = new AstShiftROvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
|
|
|
|
nodep->rhsp()->unlinkFrBack()};
|
|
|
|
|
} else {
|
|
|
|
|
UASSERT_OBJ(VN_IS(nodep, ShiftRS), nodep, "Bad case");
|
|
|
|
|
newp = new AstShiftRSOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
|
|
|
|
nodep->rhsp()->unlinkFrBack()};
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2023-10-15 04:34:37 +02:00
|
|
|
newp->dtypeFrom(nodep);
|
|
|
|
|
nodep->replaceWith(newp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
|
|
|
return;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstShiftL* nodep) override { visitShift(nodep); }
|
|
|
|
|
void visit(AstShiftR* nodep) override { visitShift(nodep); }
|
|
|
|
|
void visit(AstShiftRS* nodep) override { visitShift(nodep); }
|
2006-08-26 13:35:28 +02:00
|
|
|
// Operators
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeTermop* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeUniop* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBiop* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstRand* nodep) override {
|
2021-08-24 02:13:09 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
|
|
|
|
}
|
2023-04-01 16:50:27 +02:00
|
|
|
void visit(AstRandRNG* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstUCFunc* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSel* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2020-04-15 13:58:34 +02:00
|
|
|
{ // Only the 'from' is part of the assignment LHS
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_assignLhs);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignLhs = false;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->lsbp());
|
|
|
|
|
iterateAndNextNull(nodep->widthp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstArraySel* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2020-04-15 13:58:34 +02:00
|
|
|
{ // Only the 'from' is part of the assignment LHS
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_assignLhs);
|
2019-12-01 17:52:48 +01:00
|
|
|
m_assignLhs = false;
|
|
|
|
|
iterateAndNextNull(nodep->bitp());
|
|
|
|
|
}
|
|
|
|
|
checkNode(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAssocSel* nodep) override {
|
2019-12-01 17:52:48 +01:00
|
|
|
iterateAndNextNull(nodep->fromp());
|
2020-04-15 13:58:34 +02:00
|
|
|
{ // Only the 'from' is part of the assignment LHS
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_assignLhs);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignLhs = false;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->bitp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConst* nodep) override {
|
2020-04-04 14:31:14 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2017-09-20 02:04:45 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeCond* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2022-09-15 20:43:56 +02:00
|
|
|
if (nodep->thenp()->isWide() && !VN_IS(nodep->condp(), Const)
|
2018-02-02 03:32:58 +01:00
|
|
|
&& !VN_IS(nodep->condp(), VarRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// We're going to need the expression several times in the expanded code,
|
|
|
|
|
// so might as well make it a common expression
|
|
|
|
|
createDeepTemp(nodep->condp(), false);
|
2023-09-18 15:21:30 +02:00
|
|
|
nodep->clearCachedPurity();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
checkNode(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
void visit(AstCCall* nodep) override {
|
|
|
|
|
VL_RESTORER(m_callp);
|
|
|
|
|
m_callp = nodep;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2008-07-16 20:06:08 +02:00
|
|
|
// Autoflush
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstDisplay* nodep) override {
|
2023-05-21 18:03:13 +02:00
|
|
|
RESTORER_START_STATEMENT();
|
2019-05-19 22:13:13 +02:00
|
|
|
startStatement(nodep);
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (v3Global.opt.autoflush()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNode* searchp = nodep->nextp();
|
2018-02-02 03:32:58 +01:00
|
|
|
while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (searchp && VN_IS(searchp, Display)
|
2021-10-22 14:56:48 +02:00
|
|
|
&& nodep->filep()->sameGateTree(VN_AS(searchp, Display)->filep())) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// There's another display next; we can just wait to flush
|
|
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(4, "Autoflush " << nodep << endl);
|
2022-11-13 21:33:11 +01:00
|
|
|
nodep->addNextHere(
|
|
|
|
|
new AstFFlush{nodep->fileline(),
|
2023-09-17 04:50:54 +02:00
|
|
|
nodep->filep() ? nodep->filep()->cloneTreePure(true) : nullptr});
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2008-07-16 20:06:08 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSFormatF* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
// Any strings sent to a display must be var of string data type,
|
|
|
|
|
// to avoid passing a pointer to a temporary.
|
2022-11-13 21:33:11 +01:00
|
|
|
for (AstNodeExpr* expp = nodep->exprsp(); expp; expp = VN_AS(expp->nextp(), NodeExpr)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (expp->dtypep()->basicp() && expp->dtypep()->basicp()->isString()
|
2018-02-02 03:32:58 +01:00
|
|
|
&& !VN_IS(expp, VarRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
createDeepTemp(expp, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-28 21:01:50 +01:00
|
|
|
}
|
2008-07-16 20:06:08 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//--------------------
|
|
|
|
|
// Default: Just iterate
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar*) override {} // Don't hit varrefs under vars
|
|
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2023-08-28 15:44:41 +02:00
|
|
|
explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-07-30 16:01:25 +02:00
|
|
|
~PremitVisitor() override {
|
2021-06-13 16:05:55 +02:00
|
|
|
V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool",
|
|
|
|
|
m_extractedToConstPool);
|
2021-05-08 21:04:56 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Premit class functions
|
|
|
|
|
|
|
|
|
|
void V3Premit::premitAll(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 16:52:36 +01:00
|
|
|
{ PremitVisitor{nodep}; } // Destruct before checking
|
2023-05-04 00:04:10 +02:00
|
|
|
V3Global::dumpCheckGlobalTree("premit", 0, dumpTreeLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|