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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 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-10-18 12:37:46 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3Premit.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
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
|
|
|
|
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
|
|
|
// 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
|
2025-07-23 11:48:55 +02:00
|
|
|
VDouble0 m_temporaryVarsCreated; // Statistic tracking
|
2023-05-27 15:43:23 +02:00
|
|
|
|
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-12-06 15:42:46 +01:00
|
|
|
size_t 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
|
|
|
|
|
bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
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.
|
2023-12-06 15:42:46 +01:00
|
|
|
if (!m_stmtp) return; // Not under a statement
|
|
|
|
|
if (nodep->user1SetOnce()) return; // Already processed
|
|
|
|
|
if (!nodep->isWide()) return; // Not wide
|
|
|
|
|
if (m_assignLhs) return; // This is an lvalue!
|
|
|
|
|
UASSERT_OBJ(!VN_IS(nodep->firstAbovep(), ArraySel), nodep, "Should have been ignored");
|
2025-07-23 11:48:55 +02:00
|
|
|
createTemp(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-23 11:48:55 +02:00
|
|
|
AstVar* createTemp(AstNodeExpr* nodep) {
|
2023-12-06 15:42:46 +01:00
|
|
|
UASSERT_OBJ(m_stmtp, nodep, "Attempting to create temporary with no insertion point");
|
2025-07-23 11:48:55 +02:00
|
|
|
UINFO(4, "createTemp: " << nodep);
|
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
|
|
|
|
2023-12-06 15:42:46 +01:00
|
|
|
FileLine* const flp = nodep->fileline();
|
2021-05-08 21:04:56 +02:00
|
|
|
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
|
2023-12-06 15:42:46 +01:00
|
|
|
|
|
|
|
|
AstVar* varp = nullptr;
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
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();
|
2024-05-08 14:36:24 +02:00
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2021-06-13 16:05:55 +02:00
|
|
|
++m_extractedToConstPool;
|
2021-05-08 21:04:56 +02:00
|
|
|
} else {
|
2023-12-06 15:42:46 +01:00
|
|
|
// Keep as local temporary.
|
|
|
|
|
const std::string name = "__Vtemp_" + std::to_string(++m_tmpVarCnt);
|
|
|
|
|
varp = new AstVar{flp, VVarType::STMTTEMP, name, nodep->dtypep()};
|
2025-10-21 17:37:32 +02:00
|
|
|
m_cfuncp->addVarsp(varp);
|
2025-07-23 11:48:55 +02:00
|
|
|
++m_temporaryVarsCreated;
|
2023-12-06 15:42:46 +01:00
|
|
|
|
2025-07-23 14:50:39 +02:00
|
|
|
// Assignment to put before the referencing statement
|
|
|
|
|
AstAssign* const assignp
|
|
|
|
|
= new AstAssign{flp, new AstVarRef{flp, varp, VAccess::WRITE}, nodep};
|
|
|
|
|
// Insert before the statement
|
|
|
|
|
m_stmtp->addHereThisAsNext(assignp);
|
2021-05-08 21:04:56 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
// Replace node with VarRef to new Var
|
2023-12-06 15:42:46 +01:00
|
|
|
relinker.relink(new AstVarRef{flp, varp, VAccess::READ});
|
2023-05-21 18:03:13 +02:00
|
|
|
|
2023-12-06 15:42:46 +01:00
|
|
|
// Return the temporary variable
|
|
|
|
|
return varp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-05-21 18:03:13 +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
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(4, " ShiftFix " << nodep);
|
2023-10-15 04:34:37 +02:00
|
|
|
const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
|
|
|
|
|
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
|
2025-09-20 14:19:42 +02:00
|
|
|
shiftp->v3warn(
|
|
|
|
|
E_UNSUPPORTED,
|
2023-10-15 04:34:37 +02:00
|
|
|
"Unsupported: Shifting of by over 32-bit number isn't supported."
|
2025-09-20 14:19:42 +02:00
|
|
|
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
2023-10-15 04:34:37 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2025-05-05 12:31:06 +02:00
|
|
|
nodep->replaceWithKeepDType(newp);
|
2023-10-15 04:34:37 +02:00
|
|
|
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
|
|
|
}
|
2023-12-06 15:42:46 +01:00
|
|
|
|
2025-08-21 10:43:37 +02:00
|
|
|
static bool rhsReadsLhs(const AstNodeAssign* nodep) {
|
2023-12-06 15:42:46 +01:00
|
|
|
const VNUser3InUse user3InUse;
|
|
|
|
|
nodep->lhsp()->foreach([](const AstVarRef* refp) {
|
|
|
|
|
if (refp->access().isWriteOrRW()) refp->varp()->user3(true);
|
|
|
|
|
});
|
|
|
|
|
return nodep->rhsp()->exists([](const AstVarRef* refp) {
|
|
|
|
|
return refp->access().isReadOnly() && refp->varp()->user3();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS
|
|
|
|
|
void visit(AstCFunc* nodep) override {
|
|
|
|
|
UASSERT_OBJ(!m_cfuncp, nodep, "Should not nest");
|
|
|
|
|
VL_RESTORER(m_cfuncp);
|
|
|
|
|
VL_RESTORER(m_tmpVarCnt);
|
|
|
|
|
m_cfuncp = nodep;
|
|
|
|
|
m_tmpVarCnt = 0;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VISITORS - Statements
|
|
|
|
|
#define START_STATEMENT_OR_RETURN(stmtp) \
|
|
|
|
|
if (!m_cfuncp) return; \
|
|
|
|
|
if (stmtp->user1SetOnce()) return; \
|
|
|
|
|
VL_RESTORER(m_assignLhs); \
|
|
|
|
|
VL_RESTORER(m_stmtp); \
|
|
|
|
|
m_assignLhs = false; \
|
2025-09-29 16:25:25 +02:00
|
|
|
m_stmtp = stmtp;
|
|
|
|
|
|
2023-12-06 15:42:46 +01:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
|
|
|
|
START_STATEMENT_OR_RETURN(nodep);
|
|
|
|
|
|
2025-03-13 13:56:29 +01:00
|
|
|
if (AstCvtArrayToPacked* const packedp = VN_CAST(nodep->lhsp(), CvtArrayToPacked)) {
|
|
|
|
|
// AstCvtArrayToPacked is converted to VL_PACK, which returns rvalue,
|
|
|
|
|
// so it shouldn't be on the LHS. It is now replaced with unpacking of RHS.
|
|
|
|
|
AstNodeExpr* const exprLhsp = packedp->fromp()->unlinkFrBack();
|
|
|
|
|
packedp->replaceWith(exprLhsp);
|
|
|
|
|
VL_DO_DANGLING(pushDeletep(packedp), packedp);
|
|
|
|
|
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
|
|
|
|
nodep->rhsp(new AstCvtPackedToArray{rhsp->fileline(), rhsp, exprLhsp->dtypep()});
|
|
|
|
|
nodep->dtypeFrom(exprLhsp);
|
|
|
|
|
}
|
2023-12-06 15:42:46 +01:00
|
|
|
// Direct assignment to a simple variable
|
|
|
|
|
if (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())) {
|
|
|
|
|
AstNode* const rhsp = nodep->rhsp();
|
|
|
|
|
// Rhs is already a var ref, so nothing to so
|
|
|
|
|
if (VN_IS(rhsp, VarRef) && !AstVar::scVarRecurse(rhsp)) return;
|
|
|
|
|
if (!VN_IS(rhsp, Const)) {
|
|
|
|
|
// Don't replace the rhs, it's already a simple assignment
|
|
|
|
|
rhsp->user1(true);
|
|
|
|
|
} else if (rhsp->width() < STATIC_CONST_MIN_WIDTH) {
|
|
|
|
|
// It's a small constant, so nothing to do, otherwise will be put to const pool
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-23 11:48:55 +02:00
|
|
|
// If the RHS reads the LHS, we need a temporary unless the update is atomic
|
|
|
|
|
const bool isAtomic = VN_IS(nodep->lhsp(), VarRef) && !nodep->lhsp()->isWide();
|
|
|
|
|
if (!isAtomic && rhsReadsLhs(nodep)) {
|
|
|
|
|
createTemp(nodep->rhsp());
|
2023-12-06 15:42:46 +01:00
|
|
|
} else {
|
|
|
|
|
iterateAndNextNull(nodep->rhsp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_assignLhs = true; // Restored by VL_RESTORER in START_STATEMENT_OR_RETURN
|
|
|
|
|
iterateAndNextNull(nodep->lhsp());
|
|
|
|
|
}
|
|
|
|
|
void visit(AstDisplay* nodep) override {
|
|
|
|
|
START_STATEMENT_OR_RETURN(nodep);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
if (v3Global.opt.autoflush()) {
|
|
|
|
|
const AstNode* searchp = nodep->nextp();
|
|
|
|
|
while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp();
|
|
|
|
|
if (searchp && VN_IS(searchp, Display)
|
|
|
|
|
&& nodep->filep()->sameGateTree(VN_AS(searchp, Display)->filep())) {
|
|
|
|
|
// There's another display next; we can just wait to flush
|
|
|
|
|
} else {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(4, "Autoflush " << nodep);
|
2023-12-06 15:42:46 +01:00
|
|
|
nodep->addNextHere(
|
|
|
|
|
new AstFFlush{nodep->fileline(),
|
|
|
|
|
nodep->filep() ? nodep->filep()->cloneTreePure(true) : nullptr});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void visit(AstNodeStmt* nodep) override {
|
|
|
|
|
START_STATEMENT_OR_RETURN(nodep);
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef START_STATEMENT_OR_RETURN
|
|
|
|
|
|
|
|
|
|
// VISITORS - Expressions
|
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); }
|
2023-12-06 15:42:46 +01:00
|
|
|
|
|
|
|
|
void visit(AstConst* nodep) override { checkNode(nodep); }
|
2006-08-26 13:35:28 +02:00
|
|
|
// Operators
|
2023-12-06 15:42:46 +01:00
|
|
|
void visit(AstNodeTermop* nodep) override { checkNode(nodep); }
|
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);
|
|
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void visit(AstCExprUser* nodep) override {
|
2020-04-15 13:58:34 +02:00
|
|
|
iterateChildren(nodep);
|
2024-08-06 14:48:46 +02:00
|
|
|
checkNode(nodep);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstCvtArrayToPacked* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
2025-04-15 03:40:17 +02:00
|
|
|
checkNode(nodep);
|
|
|
|
|
}
|
2025-04-15 17:50:43 +02:00
|
|
|
void visit(AstCvtPackedToArray* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
checkNode(nodep);
|
2025-07-23 11:48:55 +02:00
|
|
|
if (!VN_IS(nodep->backp(), NodeAssign)) createTemp(nodep);
|
2025-04-15 17:50:43 +02:00
|
|
|
}
|
2025-04-15 03:40:17 +02:00
|
|
|
void visit(AstCvtUnpackedToQueue* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
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());
|
2023-12-06 15:42:46 +01:00
|
|
|
// AstSel::widthp() must remain a constant, so not iterating
|
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 {
|
2025-04-15 17:50:43 +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;
|
2025-04-15 17:50:43 +02:00
|
|
|
iterateAndNextNull(nodep->bitp());
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2023-12-06 15:42:46 +01:00
|
|
|
// ArraySel are just pointer arithmetic and should never be replaced
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
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
|
|
|
}
|
2025-08-16 00:49:06 +02:00
|
|
|
void visit(AstCond* 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
|
2025-07-23 11:48:55 +02:00
|
|
|
createTemp(nodep->condp());
|
2023-10-15 12:25:42 +02:00
|
|
|
VIsCached::clearCacheTree();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
checkNode(nodep);
|
2006-08-26 13:35:28 +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.
|
2023-12-06 15:42:46 +01:00
|
|
|
for (AstNodeExpr *expp = nodep->exprsp(), *nextp; expp; expp = nextp) {
|
|
|
|
|
nextp = VN_AS(expp->nextp(), NodeExpr);
|
|
|
|
|
if (expp->isString() && !VN_IS(expp, VarRef)) {
|
2025-07-23 11:48:55 +02:00
|
|
|
AstVar* const varp = createTemp(expp);
|
2023-12-06 15:42:46 +01:00
|
|
|
// Do not remove VarRefs to this in V3Const
|
|
|
|
|
varp->noSubst(true);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
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);
|
2025-07-23 11:48:55 +02:00
|
|
|
V3Stats::addStat("Optimizations, Prelim temporary variables created",
|
|
|
|
|
m_temporaryVarsCreated);
|
2021-05-08 21:04:56 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Premit class functions
|
|
|
|
|
|
|
|
|
|
void V3Premit::premitAll(AstNetlist* nodep) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2021-11-26 16:52:36 +01:00
|
|
|
{ PremitVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("premit", 0, dumpTreeEitherLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|