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: Substitute constants and expressions in expr temp's
|
|
|
|
|
//
|
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 2004-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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Subst's Transformations:
|
2006-10-11 17:34:50 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Each module:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Search all ASSIGN(WORDSEL(...)) and build what it's assigned to
|
|
|
|
|
// Later usages of that word may then be replaced as long as
|
|
|
|
|
// the RHS hasn't changed value.
|
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 "V3Subst.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
2025-06-23 23:58:26 +02:00
|
|
|
#include "V3Const.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Stats.h"
|
2006-08-26 13:35:28 +02: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;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
2006-10-11 16:13:37 +02:00
|
|
|
// Class for each word of a multi-word variable
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class SubstVarWord final {
|
2006-10-11 17:34:50 +02:00
|
|
|
protected:
|
|
|
|
|
// MEMBERS
|
2020-04-15 13:58:34 +02:00
|
|
|
AstNodeAssign* m_assignp; // Last assignment to each word of this var
|
|
|
|
|
int m_step; // Step number of last assignment
|
|
|
|
|
bool m_use; // True if each word was consumed
|
|
|
|
|
bool m_complex; // True if each word is complex
|
2006-10-11 16:13:37 +02:00
|
|
|
friend class SubstVarEntry;
|
|
|
|
|
// METHODS
|
|
|
|
|
void clear() {
|
2020-08-15 16:12:55 +02:00
|
|
|
m_assignp = nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
m_step = 0;
|
|
|
|
|
m_use = false;
|
|
|
|
|
m_complex = false;
|
2006-10-11 16:13:37 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Class for every variable we may process
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class SubstVarEntry final {
|
2006-10-11 17:34:50 +02:00
|
|
|
// MEMBERS
|
2021-11-13 19:50:44 +01:00
|
|
|
AstVar* const m_varp; // Variable this tracks
|
2020-08-16 15:55:36 +02:00
|
|
|
bool m_wordAssign = false; // True if any word assignments
|
|
|
|
|
bool m_wordUse = false; // True if any individual word usage
|
2020-04-15 13:58:34 +02:00
|
|
|
SubstVarWord m_whole; // Data for whole vector used at once
|
2018-02-02 03:24:41 +01:00
|
|
|
std::vector<SubstVarWord> m_words; // Data for every word, if multi word variable
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2006-10-11 17:34:50 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-16 15:55:36 +02:00
|
|
|
explicit SubstVarEntry(AstVar* varp)
|
|
|
|
|
: m_varp{varp} { // Construction for when a var is used
|
2019-05-19 22:13:13 +02:00
|
|
|
m_words.resize(varp->widthWords());
|
|
|
|
|
m_whole.clear();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int i = 0; i < varp->widthWords(); i++) m_words[i].clear();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
~SubstVarEntry() = default;
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2006-10-11 17:34:50 +02:00
|
|
|
private:
|
|
|
|
|
// METHODS
|
2020-04-15 13:58:34 +02:00
|
|
|
bool wordNumOk(int word) const { return word < m_varp->widthWords(); }
|
2006-10-11 17:34:50 +02:00
|
|
|
AstNodeAssign* getWordAssignp(int word) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!wordNumOk(word)) {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
return m_words[word].m_assignp;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2006-10-11 17:34:50 +02:00
|
|
|
public:
|
2018-08-25 15:52:45 +02:00
|
|
|
void assignWhole(int step, AstNodeAssign* assp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_whole.m_assignp) m_whole.m_complex = true;
|
|
|
|
|
m_whole.m_assignp = assp;
|
|
|
|
|
m_whole.m_step = step;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
void assignWord(int step, int word, AstNodeAssign* assp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
|
|
|
|
|
m_whole.m_complex = true;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_wordAssign = true;
|
|
|
|
|
if (wordNumOk(word)) {
|
|
|
|
|
m_words[word].m_assignp = assp;
|
|
|
|
|
m_words[word].m_step = step;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-10-15 00:39:33 +02:00
|
|
|
void assignWordComplex(int word) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
|
|
|
|
|
m_whole.m_complex = true;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_words[word].m_complex = true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
void assignComplex() { m_whole.m_complex = true; }
|
2022-01-08 18:01:39 +01:00
|
|
|
void consumeWhole() { // ==consumeComplex as we don't know the difference
|
2019-05-19 22:13:13 +02:00
|
|
|
m_whole.m_use = true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void consumeWord(int word) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_words[word].m_use = true;
|
|
|
|
|
m_wordUse = true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
// ACCESSORS
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* substWhole(AstNode* errp) {
|
2025-08-30 16:34:39 +02:00
|
|
|
if (m_varp->isWide()) return nullptr;
|
|
|
|
|
if (m_whole.m_complex) return nullptr;
|
|
|
|
|
if (!m_whole.m_assignp) return nullptr;
|
|
|
|
|
if (m_wordAssign) return nullptr;
|
|
|
|
|
|
|
|
|
|
const AstNodeAssign* const assp = m_whole.m_assignp;
|
|
|
|
|
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
|
|
|
|
AstNodeExpr* const rhsp = assp->rhsp();
|
|
|
|
|
|
|
|
|
|
// AstCvtPackedToArray can't be anywhere else than on the RHS of assignment
|
|
|
|
|
if (VN_IS(rhsp, CvtPackedToArray)) return nullptr;
|
|
|
|
|
// Check if only substitute if constant
|
|
|
|
|
if (m_varp->substConstOnly() && !VN_IS(rhsp, Const)) return nullptr;
|
|
|
|
|
// Substitute it
|
|
|
|
|
return rhsp;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
// Return what to substitute given word number for
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* substWord(AstNode* errp, int word) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstNodeAssign* const assp = getWordAssignp(word);
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #");
|
2023-09-09 03:51:59 +02:00
|
|
|
return assp->rhsp();
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
int getWholeStep() const { return m_whole.m_step; }
|
2006-10-11 17:34:50 +02:00
|
|
|
int getWordStep(int word) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!wordNumOk(word)) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
return m_words[word].m_step;
|
|
|
|
|
}
|
2006-10-11 17:34:50 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
void deleteAssign(AstNodeAssign* nodep) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(5, "Delete " << nodep);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void deleteUnusedAssign() {
|
2019-05-19 22:13:13 +02:00
|
|
|
// If there are unused assignments in this var, kill them
|
|
|
|
|
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
|
2020-08-15 16:12:55 +02:00
|
|
|
VL_DO_CLEAR(deleteAssign(m_whole.m_assignp), m_whole.m_assignp = nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
for (unsigned i = 0; i < m_words.size(); i++) {
|
|
|
|
|
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp
|
|
|
|
|
&& !m_words[i].m_complex) {
|
2020-08-15 16:12:55 +02:00
|
|
|
VL_DO_CLEAR(deleteAssign(m_words[i].m_assignp), m_words[i].m_assignp = nullptr);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2006-10-11 17:34:50 +02:00
|
|
|
//######################################################################
|
2019-05-19 22:13:13 +02:00
|
|
|
// See if any variables have changed value since we determined subst value,
|
|
|
|
|
// as a visitor of each AstNode
|
2006-10-11 17:34:50 +02:00
|
|
|
|
2023-11-13 00:26:29 +01:00
|
|
|
class SubstUseVisitor final : public VNVisitorConst {
|
2006-10-11 17:34:50 +02:00
|
|
|
// NODE STATE
|
|
|
|
|
// See SubstVisitor
|
2025-04-27 20:17:24 +02:00
|
|
|
|
|
|
|
|
// STATE - across all visitors
|
2021-11-26 23:55:36 +01:00
|
|
|
const int m_origStep; // Step number where subst was recorded
|
2020-08-15 19:11:27 +02:00
|
|
|
bool m_ok = true; // No misassignments found
|
2006-10-11 17:34:50 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
SubstVarEntry* findEntryp(AstVarRef* nodep) {
|
2020-08-15 16:12:55 +02:00
|
|
|
return reinterpret_cast<SubstVarEntry*>(nodep->varp()->user1p()); // Might be nullptr
|
2006-10-11 17:34:50 +02:00
|
|
|
}
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2021-11-13 19:50:44 +01:00
|
|
|
const SubstVarEntry* const entryp = findEntryp(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (entryp) {
|
|
|
|
|
// Don't sweat it. We assign a new temp variable for every new assignment,
|
|
|
|
|
// so there's no way we'd ever replace a old value.
|
|
|
|
|
} else {
|
|
|
|
|
// A simple variable; needs checking.
|
|
|
|
|
if (m_origStep < nodep->varp()->user2()) {
|
2025-05-23 02:29:32 +02:00
|
|
|
if (m_ok) { UINFO(9, " RHS variable changed since subst recorded: " << nodep); }
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ok = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-10-11 17:34:50 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstConst*) override {} // Accelerate
|
2023-09-09 03:52:33 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
|
|
|
|
if (!nodep->isPure()) m_ok = false;
|
2023-11-13 00:26:29 +01:00
|
|
|
iterateChildrenConst(nodep);
|
2023-09-09 03:52:33 +02:00
|
|
|
}
|
2020-04-04 14:31:14 +02:00
|
|
|
|
2006-10-11 17:34:50 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 19:11:27 +02:00
|
|
|
SubstUseVisitor(AstNode* nodep, int origStep)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_origStep{origStep} {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(9, " SubstUseVisitor " << origStep << " " << nodep);
|
2023-11-13 00:26:29 +01:00
|
|
|
iterateConst(nodep);
|
2006-10-11 17:34:50 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
~SubstUseVisitor() override = default;
|
2006-10-11 17:34:50 +02:00
|
|
|
// METHODS
|
|
|
|
|
bool ok() const { return m_ok; }
|
|
|
|
|
};
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
2006-10-11 16:13:37 +02:00
|
|
|
// Subst state, as a visitor of each AstNode
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
class SubstVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
// NODE STATE
|
2006-10-11 17:34:50 +02:00
|
|
|
// Passed to SubstUseVisitor
|
2023-11-12 17:01:07 +01:00
|
|
|
// AstVar::user1p -> SubstVar* for usage var, 0=not set yet. Only under CFunc.
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstVar::user2 -> int step number for last assignment, 0=not set yet
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser2InUse m_inuser2;
|
2008-11-21 21:50:33 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// STATE
|
2023-11-12 17:01:07 +01:00
|
|
|
std::deque<SubstVarEntry> m_entries; // Nodes to delete when we are finished
|
2020-08-16 15:55:36 +02:00
|
|
|
int m_ops = 0; // Number of operators on assign rhs
|
|
|
|
|
int m_assignStep = 0; // Assignment number to determine var lifetime
|
2023-11-12 17:01:07 +01:00
|
|
|
const AstCFunc* m_funcp = nullptr; // Current function we are under
|
2025-08-30 16:34:39 +02:00
|
|
|
size_t m_nSubst = 0; // Number of substitutions performed
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
enum {
|
|
|
|
|
SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
|
|
|
|
SUBST_MAX_OPS_NA = 9999
|
|
|
|
|
}; // Not allowed to substitute
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
SubstVarEntry* getEntryp(AstVarRef* nodep) {
|
2023-11-12 17:01:07 +01:00
|
|
|
AstVar* const varp = nodep->varp();
|
|
|
|
|
if (!varp->user1p()) {
|
|
|
|
|
m_entries.emplace_back(varp);
|
|
|
|
|
varp->user1p(&m_entries.back());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2023-11-12 17:01:07 +01:00
|
|
|
return varp->user1u().to<SubstVarEntry*>();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 14:17:38 +02:00
|
|
|
bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
2023-11-12 17:01:07 +01:00
|
|
|
if (!m_funcp) return;
|
2022-11-19 21:23:37 +01:00
|
|
|
VL_RESTORER(m_ops);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_ops = 0;
|
|
|
|
|
m_assignStep++;
|
2025-08-30 16:34:39 +02:00
|
|
|
const size_t nSubstBefore = m_nSubst;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateAndNextNull(nodep->rhsp());
|
2025-08-30 16:34:39 +02:00
|
|
|
if (nSubstBefore != m_nSubst) V3Const::constifyEditCpp(nodep->rhsp());
|
|
|
|
|
if (VN_IS(nodep->rhsp(), Const)) m_ops = 0;
|
2020-04-15 13:58:34 +02:00
|
|
|
bool hit = false;
|
2021-11-13 19:50:44 +01:00
|
|
|
if (AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (isSubstVar(varrefp->varp())) {
|
2021-11-13 19:50:44 +01:00
|
|
|
SubstVarEntry* const entryp = getEntryp(varrefp);
|
2019-05-19 22:13:13 +02:00
|
|
|
hit = true;
|
|
|
|
|
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " ASSIGNtooDeep " << varrefp);
|
2018-10-15 00:39:33 +02:00
|
|
|
entryp->assignComplex();
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " ASSIGNwhole " << varrefp);
|
2019-05-19 22:13:13 +02:00
|
|
|
entryp->assignWhole(m_assignStep, nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstWordSel* const wordp = VN_CAST(nodep->lhsp(), WordSel)) {
|
2023-11-12 19:30:48 +01:00
|
|
|
if (AstVarRef* const varrefp = VN_CAST(wordp->fromp(), VarRef)) {
|
|
|
|
|
if (VN_IS(wordp->bitp(), Const) && isSubstVar(varrefp->varp())) {
|
|
|
|
|
const int word = VN_AS(wordp->bitp(), Const)->toUInt();
|
2021-11-13 19:50:44 +01:00
|
|
|
SubstVarEntry* const entryp = getEntryp(varrefp);
|
2019-05-19 22:13:13 +02:00
|
|
|
hit = true;
|
|
|
|
|
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " ASSIGNtooDeep " << varrefp);
|
2018-10-15 00:39:33 +02:00
|
|
|
entryp->assignWordComplex(word);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " ASSIGNword" << word << " " << varrefp);
|
2019-05-19 22:13:13 +02:00
|
|
|
entryp->assignWord(m_assignStep, word, nodep);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!hit) iterate(nodep->lhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
void replaceSubstEtc(AstNode* nodep, AstNodeExpr* substp) {
|
2025-08-02 19:44:40 +02:00
|
|
|
UINFOTREE(6, nodep, "", "substw_old");
|
2023-09-17 04:50:54 +02:00
|
|
|
AstNodeExpr* newp = substp->cloneTreePure(true);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->isQuad() && newp->isQuad()) {
|
2022-11-19 20:45:33 +01:00
|
|
|
newp = new AstCCast{newp->fileline(), newp, nodep};
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2025-08-02 19:44:40 +02:00
|
|
|
UINFOTREE(6, newp, "", "w_new");
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->replaceWith(newp);
|
2023-11-12 17:01:07 +01:00
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
2025-08-30 16:34:39 +02:00
|
|
|
++m_nSubst;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWordSel* nodep) override {
|
2023-11-12 17:01:07 +01:00
|
|
|
if (!m_funcp) return;
|
2025-08-30 16:34:39 +02:00
|
|
|
const size_t nSubstBefore = m_nSubst;
|
2023-11-12 19:30:48 +01:00
|
|
|
iterate(nodep->bitp());
|
2025-08-30 16:34:39 +02:00
|
|
|
// Simplify in case it was substituted and became constant
|
|
|
|
|
if (nSubstBefore != m_nSubst) V3Const::constifyEditCpp(nodep->bitp());
|
2023-11-12 19:30:48 +01:00
|
|
|
AstVarRef* const varrefp = VN_CAST(nodep->fromp(), VarRef);
|
|
|
|
|
const AstConst* const constp = VN_CAST(nodep->bitp(), Const);
|
2020-10-31 03:28:51 +01:00
|
|
|
if (varrefp && isSubstVar(varrefp->varp()) && varrefp->access().isReadOnly() && constp) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Nicely formed lvalues handled in NodeAssign
|
|
|
|
|
// Other lvalues handled as unknown mess in AstVarRef
|
2021-06-21 00:32:57 +02:00
|
|
|
const int word = constp->toUInt();
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " USEword" << word << " " << varrefp);
|
2021-11-13 19:50:44 +01:00
|
|
|
SubstVarEntry* const entryp = getEntryp(varrefp);
|
2022-11-13 21:33:11 +01:00
|
|
|
if (AstNodeExpr* const substp = entryp->substWord(nodep, word)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Check that the RHS hasn't changed value since we recorded it.
|
2021-11-26 23:55:36 +01:00
|
|
|
const SubstUseVisitor visitor{substp, entryp->getWordStep(word)};
|
2019-05-19 22:13:13 +02:00
|
|
|
if (visitor.ok()) {
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
|
|
|
|
entryp->consumeWord(word);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
entryp->consumeWord(word);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-11-12 19:30:48 +01:00
|
|
|
iterate(nodep->fromp());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVarRef* nodep) override {
|
2023-11-12 17:01:07 +01:00
|
|
|
if (!m_funcp) return;
|
2019-05-19 22:13:13 +02:00
|
|
|
// Any variable
|
2020-11-07 16:37:55 +01:00
|
|
|
if (nodep->access().isWriteOrRW()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignStep++;
|
|
|
|
|
nodep->varp()->user2(m_assignStep);
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (isSubstVar(nodep->varp())) {
|
2021-11-13 19:50:44 +01:00
|
|
|
SubstVarEntry* const entryp = getEntryp(nodep);
|
2020-11-07 16:37:55 +01:00
|
|
|
if (nodep->access().isWriteOrRW()) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " ASSIGNcpx " << nodep);
|
2018-10-15 00:39:33 +02:00
|
|
|
entryp->assignComplex();
|
2022-11-13 21:33:11 +01:00
|
|
|
} else if (AstNodeExpr* const substp = entryp->substWhole(nodep)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Check that the RHS hasn't changed value since we recorded it.
|
2021-11-26 23:55:36 +01:00
|
|
|
const SubstUseVisitor visitor{substp, entryp->getWholeStep()};
|
2019-05-19 22:13:13 +02:00
|
|
|
if (visitor.ok()) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " USEwhole " << nodep);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " USEwholeButChg " << nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
entryp->consumeWhole();
|
|
|
|
|
}
|
|
|
|
|
} else { // Consumed w/o substitute
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(8, " USEwtf " << nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
entryp->consumeWhole();
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstVar*) override {}
|
|
|
|
|
void visit(AstConst*) override {}
|
2023-11-12 17:01:07 +01:00
|
|
|
|
|
|
|
|
void visit(AstCFunc* nodep) override {
|
|
|
|
|
UASSERT_OBJ(!m_funcp, nodep, "Should not nest");
|
|
|
|
|
UASSERT_OBJ(m_entries.empty(), nodep, "References outside functions");
|
|
|
|
|
VL_RESTORER(m_funcp);
|
|
|
|
|
m_funcp = nodep;
|
|
|
|
|
|
|
|
|
|
const VNUser1InUse m_inuser1;
|
2022-09-14 13:37:51 +02:00
|
|
|
iterateChildren(nodep);
|
2023-11-12 17:01:07 +01:00
|
|
|
for (SubstVarEntry& ip : m_entries) ip.deleteUnusedAssign();
|
|
|
|
|
m_entries.clear();
|
2025-06-23 23:58:26 +02:00
|
|
|
|
|
|
|
|
// Constant fold here, as Ast size can likely be reduced
|
|
|
|
|
if (v3Global.opt.fConstEager()) {
|
|
|
|
|
AstNode* const editedp = V3Const::constifyEditCpp(nodep);
|
|
|
|
|
UASSERT_OBJ(editedp == nodep, editedp, "Should not have replaced CFunc");
|
|
|
|
|
}
|
2022-09-14 13:37:51 +02:00
|
|
|
}
|
2023-11-12 17:01:07 +01:00
|
|
|
|
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
|
|
|
// Do not optimzie across user $c input
|
|
|
|
|
void visit(AstCExprUser* nodep) override {
|
|
|
|
|
m_ops = SUBST_MAX_OPS_NA;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstCStmtUser* nodep) override {
|
|
|
|
|
m_ops = SUBST_MAX_OPS_NA;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
2022-11-19 21:23:37 +01:00
|
|
|
++m_ops;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-10-08 01:39:59 +02:00
|
|
|
explicit SubstVisitor(AstNode* nodep) { iterate(nodep); }
|
2022-09-16 12:22:11 +02:00
|
|
|
~SubstVisitor() override {
|
2025-08-30 16:34:39 +02:00
|
|
|
V3Stats::addStat("Optimizations, Substituted temps", m_nSubst);
|
2023-11-12 17:01:07 +01:00
|
|
|
UASSERT(m_entries.empty(), "References outside functions");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Subst class functions
|
|
|
|
|
|
|
|
|
|
void V3Subst::substituteAll(AstNetlist* nodep) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2021-11-26 16:52:36 +01:00
|
|
|
{ SubstVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("subst", 0, dumpTreeEitherLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|