Fix purity calculation during V3Const simplifying Ast

This commit is contained in:
Wilson Snyder 2023-10-15 06:25:42 -04:00
parent 46f8a659b3
commit 684aba0e90
9 changed files with 12 additions and 43 deletions

View File

@ -33,7 +33,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//======================================================================
// Statics
uint32_t VIsCached::s_cachedCntGbl = 1;
uint64_t VIsCached::s_cachedCntGbl = 1;
uint64_t AstNode::s_editCntLast = 0;
uint64_t AstNode::s_editCntGbl = 0; // Hot cache line

View File

@ -171,10 +171,9 @@ class VIsCached final {
// Used in some nodes to cache results of boolean methods
// If cachedCnt == 0, not cached
// else if cachedCnt == s_cachedCntGbl, then m_state is if cached
uint32_t m_cachedCnt : 31; // Mark of when cache was computed
uint32_t m_state : 1;
static uint32_t s_cachedCntGbl; // Global computed count
static constexpr uint32_t MAX_CNT = (1UL << 31) - 1; // Max for m_cachedCnt
uint64_t m_cachedCnt : 63; // Mark of when cache was computed
uint64_t m_state : 1;
static uint64_t s_cachedCntGbl; // Global computed count
public:
VIsCached()
@ -192,7 +191,8 @@ public:
}
static void clearCacheTree() {
++s_cachedCntGbl;
UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting");
// 64 bits so won't overflow
// UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting");
}
};
@ -1956,6 +1956,7 @@ public:
uint64_t editCount() const { return m_editCount; }
void editCountInc() {
m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##"
VIsCached::clearCacheTree(); // Any edit clears all caching
}
#else
void editCountInc() { ++s_editCntGbl; }

View File

@ -64,7 +64,6 @@ public:
// Wrap This expression into an AstStmtExpr to denote it occurs in statement position
inline AstStmtExpr* makeStmt();
virtual void clearCachedPurity(){}; // Most nodes don't cache their purity
};
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
// Binary expression
@ -98,7 +97,6 @@ public:
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
void clearCachedPurity() override;
private:
bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); }
@ -265,7 +263,6 @@ public:
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
string emitC() final override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
void clearCachedPurity() override;
private:
bool getPurityRecurse() const;
@ -296,7 +293,6 @@ public:
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
bool isPure() override;
const char* broken() const override;
void clearCachedPurity() override;
private:
bool getPurityRecurse() const {
@ -340,7 +336,6 @@ public:
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
void clearCachedPurity() override;
private:
bool getPurityRecurse() const {
@ -393,7 +388,6 @@ public:
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
void clearCachedPurity() override;
private:
bool getPurityRecurse() const {
@ -473,7 +467,6 @@ public:
bool same(const AstNode*) const override { return true; }
bool isPure() override;
const char* broken() const override;
void clearCachedPurity() override;
};
class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop {
public:

View File

@ -72,11 +72,6 @@ bool AstNodeFTaskRef::isPure() {
}
}
void AstNodeFTaskRef::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
bool AstNodeFTaskRef::getPurityRecurse() const {
AstNodeFTask* const taskp = this->taskp();
// Unlinked yet, so treat as impure
@ -152,11 +147,6 @@ const char* AstNodeUniop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure());
return nullptr;
}
void AstNodeUniop::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
bool AstNodeBiop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
@ -165,10 +155,6 @@ const char* AstNodeBiop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
void AstNodeBiop::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
bool AstNodeTriop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
@ -178,10 +164,6 @@ const char* AstNodeTriop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
void AstNodeTriop::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
bool AstNodePreSel::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
@ -191,10 +173,6 @@ const char* AstNodePreSel::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
void AstNodePreSel::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
bool AstNodeQuadop::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
@ -204,10 +182,6 @@ const char* AstNodeQuadop::broken() const {
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
return nullptr;
}
void AstNodeQuadop::clearCachedPurity() {
m_purity.clearCache();
if (AstNodeExpr* const exprp = VN_CAST(backp(), NodeExpr)) exprp->clearCachedPurity();
}
AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
AstNodeExpr* elsep)

View File

@ -174,7 +174,7 @@ private:
// MethodCalls not currently supported by inliner, so keep linked
if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) {
nodep->taskp(nullptr);
nodep->clearCachedPurity();
VIsCached::clearCacheTree();
}
iterateChildren(nodep);
}

View File

@ -3726,6 +3726,7 @@ public:
// Link class functions
void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
VIsCached::clearCacheTree(); // Avoid using any stale isPure
if (debug() >= 5 || dumpTreeLevel() >= 9) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
}

View File

@ -331,7 +331,7 @@ private:
// 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);
nodep->clearCachedPurity();
VIsCached::clearCacheTree();
}
checkNode(nodep);
}

View File

@ -396,7 +396,7 @@ private:
UINFO(9, " New pkg-taskref " << nodep << endl);
} else if (!VN_IS(nodep, MethodCall)) {
nodep->taskp(nullptr);
nodep->clearCachedPurity();
VIsCached::clearCacheTree();
UINFO(9, " New pkg-taskref " << nodep << endl);
}
iterateChildren(nodep);

View File

@ -1469,9 +1469,9 @@ private:
beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp};
// AstExprStmt is currently treated as impure, so clear the cached purity of its
// parents
nodep->clearCachedPurity();
nodep->replaceWith(beginp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
VIsCached::clearCacheTree();
} else {
insertBeforeStmt(nodep, beginp);
if (nodep->taskp()->isFunction()) {