diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 1a421e928..828bb4d11 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -600,6 +600,7 @@ public: , m_name{name} { this->fromp(fromp); this->addPinsp(pinsp); + setPurity(); } ASTGEN_MEMBERS_AstCMethodHard; string name() const override VL_MT_STABLE { return m_name; } // * = Var name @@ -609,11 +610,13 @@ public: return (m_name == asamep->m_name); } bool isPure() const override { return m_pure; } - void pure(bool flag) { m_pure = flag; } int instrCount() const override; string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } + +private: + void setPurity(); }; class AstCast final : public AstNodeExpr { // Cast to appropriate data type diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5a411d606..a2caf2621 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2326,6 +2326,74 @@ int AstCMethodHard::instrCount() const { } return 0; } +void AstCMethodHard::setPurity() { + static const std::map isPureMethod{{"andNot", false}, + {"any", true}, + {"assign", false}, + {"at", true}, + {"atBack", true}, + {"awaitingCurrentTime", true}, + {"clear", false}, + {"clearFired", false}, + {"commit", false}, + {"delay", false}, + {"done", false}, + {"erase", false}, + {"evaluate", false}, + {"evaluation", false}, + {"exists", true}, + {"find", true}, + {"find_first", true}, + {"find_first_index", true}, + {"find_index", true}, + {"find_last", true}, + {"find_last_index", true}, + {"fire", false}, + {"first", false}, + {"init", false}, + {"insert", false}, + {"isFired", true}, + {"isTriggered", true}, + {"join", false}, + {"last", false}, + {"max", true}, + {"min", true}, + {"neq", true}, + {"next", false}, + {"pop", false}, + {"pop_back", false}, + {"pop_front", false}, + {"prev", false}, + {"push", false}, + {"push_back", false}, + {"push_front", false}, + {"r_and", true}, + {"r_or", true}, + {"r_product", true}, + {"r_sum", true}, + {"r_xor", true}, + {"renew", false}, + {"renew_copy", false}, + {"resume", false}, + {"reverse", false}, + {"rsort", false}, + {"set", false}, + {"shuffle", false}, + {"size", true}, + {"slice", true}, + {"sliceBackBack", true}, + {"sliceFrontBack", true}, + {"sort", false}, + {"thisOr", false}, + {"trigger", false}, + {"unique", true}, + {"unique_index", true}, + {"word", true}}; + + auto isPureIt = isPureMethod.find(name()); + UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name()); + m_pure = isPureIt->second; +} const char* AstCFunc::broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return nullptr; diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 8948730bf..897cb6343 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -393,7 +393,6 @@ AstSenTree* createTriggerSenTree(AstNetlist* netlistp, AstVarScope* const vscp, AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; callp->dtypeSetUInt64(); - callp->pure(true); AstNodeExpr* const termp = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, termp}; @@ -479,7 +478,6 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; callp->dtypeSetUInt64(); - callp->pure(true); AstNodeExpr* const termp = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; return termp; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ebc770fc3..e428c072a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3107,7 +3107,6 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists", index_exprp->unlinkFrBack()}; newp->dtypeSetSigned32(); - newp->pure(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -3192,7 +3191,6 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists", index_exprp->unlinkFrBack()}; newp->dtypeSetSigned32(); - newp->pure(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -3657,7 +3655,6 @@ private: AstCMethodHard* const callp = new AstCMethodHard{ nodep->fileline(), nodep->fromp()->unlinkFrBack(), "isTriggered"}; callp->dtypeSetBit(); - callp->pure(true); nodep->replaceWith(callp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else {