2012-04-13 01:08:20 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Substitute constants and expressions in expr temp's
|
|
|
|
//
|
2019-11-08 03:33:59 +00:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2020-01-06 23:05:53 +00:00
|
|
|
// Copyright 2004-2020 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
// Version 2.0.
|
2006-08-26 11:35:28 +00:00
|
|
|
//
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
// V3Subst's Transformations:
|
2006-10-11 15:34:50 +00:00
|
|
|
//
|
2006-08-26 11:35:28 +00:00
|
|
|
// Each module:
|
2019-05-19 20:13:13 +00: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 11:35:28 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
2019-10-05 00:17:11 +00:00
|
|
|
|
2006-12-18 19:20:45 +00:00
|
|
|
#include "config_build.h"
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
#include "V3Subst.h"
|
|
|
|
#include "V3Const.h"
|
|
|
|
#include "V3Stats.h"
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
2018-10-14 17:43:24 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstdarg>
|
|
|
|
#include <vector>
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
//######################################################################
|
|
|
|
// Common debugging baseclass
|
|
|
|
|
|
|
|
class SubstBaseVisitor : public AstNVisitor {
|
|
|
|
public:
|
2018-05-14 10:50:47 +00:00
|
|
|
VL_DEBUG_FUNC; // Declare debug()
|
2006-08-26 11:35:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//######################################################################
|
2006-10-11 14:13:37 +00:00
|
|
|
// Class for each word of a multi-word variable
|
|
|
|
|
|
|
|
class SubstVarWord {
|
2006-10-11 15:34:50 +00:00
|
|
|
protected:
|
|
|
|
// MEMBERS
|
2019-05-19 20:13:13 +00: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 14:13:37 +00:00
|
|
|
friend class SubstVarEntry;
|
|
|
|
// METHODS
|
|
|
|
void clear() {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_assignp = NULL;
|
|
|
|
m_step = 0;
|
|
|
|
m_use = false;
|
|
|
|
m_complex = false;
|
2006-10-11 14:13:37 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
// Class for every variable we may process
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
class SubstVarEntry {
|
2006-10-11 15:34:50 +00:00
|
|
|
// MEMBERS
|
2019-05-19 20:13:13 +00:00
|
|
|
AstVar* m_varp; // Variable this tracks
|
|
|
|
bool m_wordAssign; // True if any word assignments
|
|
|
|
bool m_wordUse; // True if any individual word usage
|
|
|
|
SubstVarWord m_whole; // Data for whole vector used at once
|
2018-02-02 02:24:41 +00:00
|
|
|
std::vector<SubstVarWord> m_words; // Data for every word, if multi word variable
|
2006-08-26 11:35:28 +00:00
|
|
|
int debug() { return SubstBaseVisitor::debug(); }
|
2009-01-21 21:56:50 +00:00
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
public:
|
2006-10-11 15:34:50 +00:00
|
|
|
// CONSTRUCTORS
|
2018-08-25 13:52:45 +00:00
|
|
|
explicit SubstVarEntry(AstVar* varp) { // Construction for when a var is used
|
2019-05-19 20:13:13 +00:00
|
|
|
m_varp = varp;
|
|
|
|
m_wordAssign = false;
|
|
|
|
m_wordUse = false;
|
|
|
|
m_words.resize(varp->widthWords());
|
|
|
|
m_whole.clear();
|
|
|
|
for (int i=0; i<varp->widthWords(); i++) {
|
|
|
|
m_words[i].clear();
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2006-10-11 14:13:37 +00:00
|
|
|
~SubstVarEntry() {}
|
2006-10-11 15:34:50 +00:00
|
|
|
private:
|
|
|
|
// METHODS
|
|
|
|
bool wordNumOk(int word) const {
|
2019-05-19 20:13:13 +00:00
|
|
|
return word < m_varp->widthWords();
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2006-10-11 15:34:50 +00:00
|
|
|
AstNodeAssign* getWordAssignp(int word) const {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!wordNumOk(word)) return NULL;
|
|
|
|
else return m_words[word].m_assignp;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2006-10-11 15:34:50 +00:00
|
|
|
public:
|
2018-08-25 13:52:45 +00:00
|
|
|
void assignWhole(int step, AstNodeAssign* assp) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (m_whole.m_assignp) m_whole.m_complex = true;
|
|
|
|
m_whole.m_assignp = assp;
|
|
|
|
m_whole.m_step = step;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2018-08-25 13:52:45 +00:00
|
|
|
void assignWord(int step, int word, AstNodeAssign* assp) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!wordNumOk(word) || getWordAssignp(word)
|
|
|
|
|| m_words[word].m_complex) m_whole.m_complex = true;
|
|
|
|
m_wordAssign = true;
|
|
|
|
if (wordNumOk(word)) {
|
|
|
|
m_words[word].m_assignp = assp;
|
|
|
|
m_words[word].m_step = step;
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2018-10-14 22:39:33 +00:00
|
|
|
void assignWordComplex(int word) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!wordNumOk(word) || getWordAssignp(word)
|
|
|
|
|| m_words[word].m_complex) m_whole.m_complex = true;
|
|
|
|
m_words[word].m_complex = true;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2018-10-14 22:39:33 +00:00
|
|
|
void assignComplex() {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_whole.m_complex = true;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
void consumeWhole() { //==consumeComplex as we don't know the difference
|
2019-05-19 20:13:13 +00:00
|
|
|
m_whole.m_use = true;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
void consumeWord(int word) {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_words[word].m_use = true;
|
|
|
|
m_wordUse = true;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
// ACCESSORS
|
|
|
|
AstNode* substWhole(AstNode* errp) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!m_varp->isWide()
|
|
|
|
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
|
|
|
AstNodeAssign* assp = m_whole.m_assignp;
|
2019-07-06 16:57:50 +00:00
|
|
|
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
2019-05-19 20:13:13 +00:00
|
|
|
return (assp->rhsp());
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
|
|
|
|
AstNodeAssign* assp = getWordAssignp(word);
|
2019-07-06 16:57:50 +00:00
|
|
|
UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #");
|
2019-05-19 20:13:13 +00:00
|
|
|
return (assp->rhsp());
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2006-10-11 15:34:50 +00:00
|
|
|
int getWholeStep() const {
|
2019-05-19 20:13:13 +00:00
|
|
|
return m_whole.m_step;
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
|
|
|
int getWordStep(int word) const {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
2018-08-25 13:52:45 +00:00
|
|
|
void deleteAssign(AstNodeAssign* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
UINFO(5, "Delete "<<nodep<<endl);
|
2020-01-17 01:17:11 +00:00
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
void deleteUnusedAssign() {
|
2019-05-19 20:13:13 +00:00
|
|
|
// If there are unused assignments in this var, kill them
|
|
|
|
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
|
2020-01-18 15:29:49 +00:00
|
|
|
VL_DO_CLEAR(deleteAssign(m_whole.m_assignp), m_whole.m_assignp = NULL);
|
2019-05-19 20:13:13 +00: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-01-18 15:29:49 +00:00
|
|
|
VL_DO_CLEAR(deleteAssign(m_words[i].m_assignp), m_words[i].m_assignp = NULL);
|
2019-05-19 20:13:13 +00:00
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-10-11 15:34:50 +00:00
|
|
|
//######################################################################
|
2019-05-19 20:13:13 +00:00
|
|
|
// See if any variables have changed value since we determined subst value,
|
|
|
|
// as a visitor of each AstNode
|
2006-10-11 15:34:50 +00:00
|
|
|
|
|
|
|
class SubstUseVisitor : public SubstBaseVisitor {
|
|
|
|
private:
|
|
|
|
// NODE STATE
|
|
|
|
// See SubstVisitor
|
|
|
|
//
|
|
|
|
// STATE
|
2019-05-19 20:13:13 +00:00
|
|
|
int m_origStep; // Step number where subst was recorded
|
|
|
|
bool m_ok; // No misassignments found
|
2006-10-11 15:34:50 +00:00
|
|
|
|
|
|
|
// METHODS
|
|
|
|
SubstVarEntry* findEntryp(AstVarRef* nodep) {
|
2018-10-14 22:39:33 +00:00
|
|
|
return reinterpret_cast<SubstVarEntry*>(nodep->varp()->user1p()); // Might be NULL
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
|
|
|
// VISITORS
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
2018-08-25 13:52:45 +00:00
|
|
|
SubstVarEntry* entryp = findEntryp(nodep);
|
2019-05-19 20:13:13 +00: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()) {
|
|
|
|
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
|
|
|
|
m_ok = false;
|
|
|
|
}
|
|
|
|
}
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstConst* nodep) VL_OVERRIDE {} // Accelerate
|
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
|
|
|
public:
|
2019-09-12 11:22:22 +00:00
|
|
|
// CONSTRUCTORS
|
2006-10-11 15:34:50 +00:00
|
|
|
SubstUseVisitor(AstNode* nodep, int origStep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
|
|
|
|
m_ok = true;
|
|
|
|
m_origStep = origStep;
|
2018-05-11 00:55:37 +00:00
|
|
|
iterate(nodep);
|
2006-10-11 15:34:50 +00:00
|
|
|
}
|
|
|
|
virtual ~SubstUseVisitor() {}
|
|
|
|
// METHODS
|
|
|
|
bool ok() const { return m_ok; }
|
|
|
|
};
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
//######################################################################
|
2006-10-11 14:13:37 +00:00
|
|
|
// Subst state, as a visitor of each AstNode
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
class SubstVisitor : public SubstBaseVisitor {
|
|
|
|
private:
|
|
|
|
// NODE STATE
|
2006-10-11 15:34:50 +00:00
|
|
|
// Passed to SubstUseVisitor
|
2019-05-19 20:13:13 +00:00
|
|
|
// AstVar::user1p -> SubstVar* for usage var, 0=not set yet
|
|
|
|
// AstVar::user2 -> int step number for last assignment, 0=not set yet
|
|
|
|
AstUser1InUse m_inuser1;
|
|
|
|
AstUser2InUse m_inuser2;
|
2008-11-21 20:50:33 +00:00
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
// STATE
|
2018-02-02 02:24:41 +00:00
|
|
|
std::vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
|
2019-05-19 20:13:13 +00:00
|
|
|
int m_ops; // Number of operators on assign rhs
|
|
|
|
int m_assignStep; // Assignment number to determine var lifetime
|
2019-10-05 11:54:14 +00:00
|
|
|
VDouble0 m_statSubsts; // Statistic tracking
|
2006-08-26 11:35:28 +00:00
|
|
|
|
2019-05-19 20:13:13 +00: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 11:35:28 +00:00
|
|
|
|
|
|
|
// METHODS
|
|
|
|
SubstVarEntry* getEntryp(AstVarRef* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (!nodep->varp()->user1p()) {
|
2018-08-25 13:52:45 +00:00
|
|
|
SubstVarEntry* entryp = new SubstVarEntry(nodep->varp());
|
2019-05-19 20:13:13 +00:00
|
|
|
m_entryps.push_back(entryp);
|
|
|
|
nodep->varp()->user1p(entryp);
|
|
|
|
return entryp;
|
|
|
|
} else {
|
2018-10-14 22:39:33 +00:00
|
|
|
SubstVarEntry* entryp = reinterpret_cast<SubstVarEntry*>(nodep->varp()->user1p());
|
2019-05-19 20:13:13 +00:00
|
|
|
return entryp;
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2014-11-28 20:01:50 +00:00
|
|
|
inline bool isSubstVar(AstVar* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
return nodep->isStatementTemp() && !nodep->noSubst();
|
2014-11-28 20:01:50 +00:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
// VISITORS
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_ops = 0;
|
|
|
|
m_assignStep++;
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateAndNextNull(nodep->rhsp());
|
2019-05-19 20:13:13 +00:00
|
|
|
bool hit=false;
|
2018-02-02 02:32:58 +00:00
|
|
|
if (AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (isSubstVar(varrefp->varp())) {
|
|
|
|
SubstVarEntry* entryp = getEntryp(varrefp);
|
|
|
|
hit = true;
|
|
|
|
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
|
|
|
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
2018-10-14 22:39:33 +00:00
|
|
|
entryp->assignComplex();
|
2019-05-19 20:13:13 +00:00
|
|
|
} else {
|
|
|
|
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
|
|
|
|
entryp->assignWhole(m_assignStep, nodep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-02 02:32:58 +00:00
|
|
|
else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) {
|
|
|
|
if (AstVarRef* varrefp = VN_CAST(wordp->lhsp(), VarRef)) {
|
|
|
|
if (VN_IS(wordp->rhsp(), Const)
|
2019-05-19 20:13:13 +00:00
|
|
|
&& isSubstVar(varrefp->varp())) {
|
2018-02-02 02:32:58 +00:00
|
|
|
int word = VN_CAST(wordp->rhsp(), Const)->toUInt();
|
2019-05-19 20:13:13 +00:00
|
|
|
SubstVarEntry* entryp = getEntryp(varrefp);
|
|
|
|
hit = true;
|
|
|
|
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
|
|
|
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
2018-10-14 22:39:33 +00:00
|
|
|
entryp->assignWordComplex(word);
|
2019-05-19 20:13:13 +00:00
|
|
|
} else {
|
|
|
|
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
|
|
|
|
entryp->assignWord(m_assignStep, word, nodep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hit) {
|
2018-05-11 00:55:37 +00:00
|
|
|
iterate(nodep->lhsp());
|
2019-05-19 20:13:13 +00:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
void replaceSubstEtc(AstNode* nodep, AstNode* substp) {
|
2019-05-19 20:13:13 +00:00
|
|
|
if (debug()>5) nodep->dumpTree(cout, " substw_old: ");
|
|
|
|
AstNode* newp = substp->cloneTree(true);
|
|
|
|
if (!nodep->isQuad() && newp->isQuad()) {
|
2018-08-25 13:52:45 +00:00
|
|
|
newp = new AstCCast(newp->fileline(), newp, nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
}
|
|
|
|
if (debug()>5) newp->dumpTree(cout, " w_new: ");
|
|
|
|
nodep->replaceWith(newp);
|
2020-01-17 01:17:11 +00:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
++m_statSubsts;
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstWordSel* nodep) VL_OVERRIDE {
|
2018-05-11 00:55:37 +00:00
|
|
|
iterate(nodep->rhsp());
|
2018-02-02 02:32:58 +00:00
|
|
|
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
|
|
|
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
2019-05-19 20:13:13 +00:00
|
|
|
if (varrefp && isSubstVar(varrefp->varp())
|
|
|
|
&& !varrefp->lvalue()
|
|
|
|
&& constp) {
|
|
|
|
// Nicely formed lvalues handled in NodeAssign
|
|
|
|
// Other lvalues handled as unknown mess in AstVarRef
|
|
|
|
int word = constp->toUInt();
|
|
|
|
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
|
|
|
|
SubstVarEntry* entryp = getEntryp(varrefp);
|
|
|
|
if (AstNode* substp = entryp->substWord(nodep, word)) {
|
|
|
|
// Check that the RHS hasn't changed value since we recorded it.
|
|
|
|
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
|
|
|
|
if (visitor.ok()) {
|
2020-01-17 01:17:11 +00:00
|
|
|
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
} else {
|
|
|
|
entryp->consumeWord(word);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
entryp->consumeWord(word);
|
|
|
|
}
|
|
|
|
} else {
|
2018-05-11 00:55:37 +00:00
|
|
|
iterate(nodep->lhsp());
|
2019-05-19 20:13:13 +00:00
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
2019-05-19 20:13:13 +00:00
|
|
|
// Any variable
|
|
|
|
if (nodep->lvalue()) {
|
|
|
|
m_assignStep++;
|
|
|
|
nodep->varp()->user2(m_assignStep);
|
|
|
|
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
|
|
|
|
}
|
|
|
|
if (isSubstVar(nodep->varp())) {
|
2018-08-25 13:52:45 +00:00
|
|
|
SubstVarEntry* entryp = getEntryp(nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
if (nodep->lvalue()) {
|
|
|
|
UINFO(8," ASSIGNcpx "<<nodep<<endl);
|
2018-10-14 22:39:33 +00:00
|
|
|
entryp->assignComplex();
|
2019-05-19 20:13:13 +00:00
|
|
|
} else if (AstNode* substp = entryp->substWhole(nodep)) {
|
|
|
|
// Check that the RHS hasn't changed value since we recorded it.
|
|
|
|
SubstUseVisitor visitor (substp, entryp->getWholeStep());
|
|
|
|
if (visitor.ok()) {
|
|
|
|
UINFO(8," USEwhole "<<nodep<<endl);
|
2020-01-17 01:17:11 +00:00
|
|
|
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
2019-05-19 20:13:13 +00:00
|
|
|
} else {
|
|
|
|
UINFO(8," USEwholeButChg "<<nodep<<endl);
|
|
|
|
entryp->consumeWhole();
|
|
|
|
}
|
|
|
|
} else { // Consumed w/o substitute
|
|
|
|
UINFO(8," USEwtf "<<nodep<<endl);
|
|
|
|
entryp->consumeWhole();
|
|
|
|
}
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
2020-01-21 22:35:56 +00:00
|
|
|
virtual void visit(AstVar* nodep) VL_OVERRIDE {}
|
|
|
|
virtual void visit(AstConst* nodep) VL_OVERRIDE {}
|
|
|
|
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
2019-05-19 20:13:13 +00:00
|
|
|
m_ops++;
|
|
|
|
if (!nodep->isSubstOptimizable()) {
|
|
|
|
m_ops = SUBST_MAX_OPS_NA;
|
|
|
|
}
|
2018-05-11 00:55:37 +00:00
|
|
|
iterateChildren(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
public:
|
2019-09-12 11:22:22 +00:00
|
|
|
// CONSTRUCTORS
|
2015-10-04 02:33:06 +00:00
|
|
|
explicit SubstVisitor(AstNode* nodep) {
|
2019-05-19 20:13:13 +00:00
|
|
|
AstNode::user1ClearTree(); // user1p() used on entire tree
|
|
|
|
AstNode::user2ClearTree(); // user2p() used on entire tree
|
|
|
|
m_ops = 0;
|
|
|
|
m_assignStep = 0;
|
2018-05-11 00:55:37 +00:00
|
|
|
iterate(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
virtual ~SubstVisitor() {
|
2019-05-19 20:13:13 +00:00
|
|
|
V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts);
|
|
|
|
for (std::vector<SubstVarEntry*>::iterator it = m_entryps.begin();
|
|
|
|
it != m_entryps.end(); ++it) {
|
|
|
|
(*it)->deleteUnusedAssign();
|
|
|
|
delete (*it);
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
// Subst class functions
|
|
|
|
|
|
|
|
void V3Subst::substituteAll(AstNetlist* nodep) {
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2018-03-10 17:57:50 +00:00
|
|
|
{
|
|
|
|
SubstVisitor visitor (nodep);
|
|
|
|
} // Destruct before checking
|
2017-09-18 02:52:57 +00:00
|
|
|
V3Global::dumpCheckGlobalTree("subst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
2006-08-26 11:35:28 +00:00
|
|
|
}
|