From 90017695bf546519e3559f3d2539e8850b15534d Mon Sep 17 00:00:00 2001 From: Szymon Gizler Date: Tue, 21 Nov 2023 15:28:47 +0100 Subject: [PATCH 1/7] Add --dump-json-tree --- src/V3Ast.cpp | 26 +++ src/V3Ast.h | 7 + src/V3AstNodeDType.h | 9 + src/V3AstNodeExpr.h | 28 +++ src/V3AstNodeOther.h | 49 +++++ src/V3AstNodes.cpp | 508 +++++++++++++++++++++++++++++++++++++++++-- src/V3Global.cpp | 3 + src/V3Options.cpp | 11 + src/V3Options.h | 3 + 9 files changed, 629 insertions(+), 15 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 139aeb0de8..09489cf316 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -22,6 +22,7 @@ #include #include +#include VL_DEFINE_DEBUG_FUNCTIONS; @@ -1170,6 +1171,22 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { } } +// cppcheck-suppress unusedFunction // Debug only +std::string AstNode::dumpJsonTreeGdb(const AstNode* nodep) { + if (!nodep) return "\n"; + std::stringstream nodepStream; + nodep->dumpTreeJson(nodepStream); + return nodepStream.rdbuf()->str(); +} +// cppcheck-suppress unusedFunction // Debug only +// identity func to allow for passing already done dumps to jtree +const char* AstNode::dumpJsonTreeGdb(const char* str) { return str; } +// cppcheck-suppress unusedFunction // Debug only +// allow for passing pointer literals like 0x42.. without manual cast +std::string AstNode::dumpJsonTreeGdb(intptr_t nodep) { + if (!nodep) return "\n"; + return dumpJsonTreeGdb((const AstNode*)nodep); +} // cppcheck-suppress unusedFunction // Debug only void AstNode::dumpGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_LINE if (!nodep) { @@ -1328,6 +1345,15 @@ void AstNode::dumpTreeDot(std::ostream& os) const { drawChildren(os, this, m_op4p, "op4"); } +void AstNode::dumpTreeJsonFile(const string& filename, bool append, bool doDump) { + if (!doDump) return; + UINFO(2, "Dumping " << filename << endl); + const std::unique_ptr treejsonp{V3File::new_ofstream(filename, append)}; + if (treejsonp->fail()) v3fatal("Can't write " << filename); + dumpTreeJson(*treejsonp); + *treejsonp << "\n"; +} + void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump) { if (doDump) { UINFO(2, "Dumping " << filename << endl); diff --git a/src/V3Ast.h b/src/V3Ast.h index fc255d933a..288b6717be 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -31,6 +31,7 @@ #include "V3Ast__gen_forward_class_decls.h" // From ./astgen #include +#include #include #include #include @@ -2161,6 +2162,9 @@ class AstNode VL_NOT_FINAL { string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); } virtual void dump(std::ostream& str = std::cout) const; + static std::string dumpJsonTreeGdb(const AstNode* nodep); // For GDB only + static const char* dumpJsonTreeGdb(const char* str); // For GDB only + static std::string dumpJsonTreeGdb(intptr_t nodep); // For GDB only static void dumpGdb(const AstNode* nodep); // For GDB only void dumpGdbHeader() const; @@ -2216,6 +2220,9 @@ class AstNode VL_NOT_FINAL { static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr); void dumpTreeDot(std::ostream& os = std::cout) const; void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true); + virtual void dumpExtraJson(std::ostream& os) const {}; // node specific fields + void dumpTreeJson(std::ostream& os) const; + void dumpTreeJsonFile(const string& filename, bool append = false, bool doDump = true); // METHODS - static advancement static AstNode* afterCommentp(AstNode* nodep) { diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 32679819c1..85f52c811b 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -52,6 +52,7 @@ class AstNodeDType VL_NOT_FINAL : public AstNode { ASTGEN_MEMBERS_AstNodeDType; // ACCESSORS void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; virtual void dumpSmall(std::ostream& str) const; bool hasDType() const override { return true; } /// Require VlUnpacked, instead of [] for POD elements. @@ -148,6 +149,7 @@ class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { public: ASTGEN_MEMBERS_AstNodeArrayDType; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; void dumpSmall(std::ostream& str) const override; const char* broken() const override { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) @@ -217,6 +219,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { int uniqueNum() const { return m_uniqueNum; } const char* broken() const override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool isCompound() const override { return !packed(); } // For basicp() we reuse the size to indicate a "fake" basic type of same size AstBasicDType* basicp() const override { @@ -387,6 +390,7 @@ class AstBasicDType final : public AstNodeDType { public: ASTGEN_MEMBERS_AstBasicDType; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; // width/widthMin/numeric compared elsewhere bool same(const AstNode* samep) const override; bool similarDType(const AstNodeDType* samep) const override { @@ -548,6 +552,7 @@ class AstClassRefDType final : public AstNodeDType { return this == samep || (type() == samep->type() && same(samep)); } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; string name() const override VL_MT_STABLE; AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } @@ -813,6 +818,7 @@ class AstEnumDType final : public AstNodeDType { string name() const override VL_MT_STABLE { return m_name; } void name(const string& flag) override { m_name = flag; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; // METHODS AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } @@ -867,6 +873,7 @@ class AstIfaceRefDType final : public AstNodeDType { // METHODS const char* broken() const override; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; void cloneRelink() override; AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } @@ -982,6 +989,7 @@ class AstParamTypeDType final : public AstNodeDType { } ASTGEN_MEMBERS_AstParamTypeDType; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* subDTypep() const override VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); @@ -1135,6 +1143,7 @@ class AstRefDType final : public AstNodeDType { return skipRefp()->similarDType(samep->skipRefp()); } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } string prettyDTypeName() const override { diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 37309f7adc..6516f54dff 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -50,6 +50,7 @@ class AstNodeExpr VL_NOT_FINAL : public AstNode { ASTGEN_MEMBERS_AstNodeExpr; // METHODS void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; // TODO: The only AstNodeExpr without dtype is AstArg. Otherwise this could be final. bool hasDType() const override { return true; } virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV @@ -195,6 +196,7 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr { public: ASTGEN_MEMBERS_AstNodeCCall; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void cloneRelink() override; const char* broken() const override; int instrCount() const override { return INSTR_COUNT_CALL; } @@ -248,6 +250,7 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool isGateOptimizable() const override; string dotted() const { return m_dotted; } // * = Scope name or "" @@ -357,6 +360,7 @@ class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr { // cppcheck-suppress functionConst void iterateChildren(VNVisitorConst& v) {} void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; }; class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { // Ternary expression @@ -377,6 +381,7 @@ class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { ASTGEN_MEMBERS_AstNodeTriop; // METHODS void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; // Set out to evaluation of a AstConst'ed virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) @@ -458,6 +463,7 @@ class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr { ASTGEN_MEMBERS_AstNodeUniop; // METHODS void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; // Set out to evaluation of a AstConst'ed lhs virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; virtual bool cleanLhs() const = 0; @@ -509,6 +515,7 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr { public: ASTGEN_MEMBERS_AstNodeVarRef; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; int instrCount() const override { return widthInstrs(); } void cloneRelink() override; @@ -594,6 +601,7 @@ class AstAttrOf final : public AstNodeExpr { ASTGEN_MEMBERS_AstAttrOf; VAttrType attrType() const { return m_attrType; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -777,6 +785,7 @@ class AstClassOrPackageRef final : public AstNodeExpr { == VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep); } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } @@ -1131,6 +1140,7 @@ class AstDot final : public AstNodeExpr { return new AstDot{fl, true, packageOrClassp, rhsp}; } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool colon() const { return m_colon; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } @@ -1159,6 +1169,7 @@ class AstEnumItemRef final : public AstNodeExpr { } ASTGEN_MEMBERS_AstEnumItemRef; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return itemp()->name(); } int instrCount() const override { return 0; } const char* broken() const override; @@ -1438,6 +1449,9 @@ class AstInitArray final : public AstNodeExpr { private: KeyItemMap m_map; // Node value for each array index + // METHODS + void dumpInitList(std::ostream& str) const; + public: AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNodeExpr* defaultp) : ASTGEN_SUPER_InitArray(fl) { @@ -1446,6 +1460,7 @@ class AstInitArray final : public AstNodeExpr { } ASTGEN_MEMBERS_AstInitArray; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; void cloneRelink() override; bool same(const AstNode* samep) const override { @@ -1538,6 +1553,7 @@ class AstMemberSel final : public AstNodeExpr { void cloneRelink() override; const char* broken() const override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } void name(const string& name) override { m_name = name; } VAccess access() const { return m_access; } @@ -1605,6 +1621,7 @@ class AstParseRef final : public AstNodeExpr { } ASTGEN_MEMBERS_AstParseRef; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool same(const AstNode* samep) const override { const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef); @@ -1661,6 +1678,7 @@ class AstPatMember final : public AstNodeExpr { bool cleanOut() const override { V3ERROR_NA_RETURN(""); } int instrCount() const override { return widthInstrs() * 2; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; bool isDefault() const { return m_default; } void isDefault(bool flag) { m_default = flag; } }; @@ -1891,6 +1909,7 @@ class AstScopeName final : public AstNodeExpr { string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string scopeSymName() const { // Name for __Vscope variable including children return scopeNameFormatter(scopeAttrp()); } @@ -4374,6 +4393,7 @@ class AstTime final : public AstNodeTermop { int instrCount() const override { return INSTR_COUNT_TIME; } bool same(const AstNode* /*samep*/) const override { return true; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } }; @@ -4394,6 +4414,7 @@ class AstTimeD final : public AstNodeTermop { int instrCount() const override { return INSTR_COUNT_TIME; } bool same(const AstNode* /*samep*/) const override { return true; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } }; @@ -4542,6 +4563,7 @@ class AstSel final : public AstNodeTriop { } ASTGEN_MEMBERS_AstSel; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) override { out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); @@ -4582,6 +4604,7 @@ class AstSliceSel final : public AstNodeTriop { , m_declRange{declRange} {} ASTGEN_MEMBERS_AstSliceSel; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, const V3Number& width) override { V3ERROR_NA; @@ -4745,6 +4768,7 @@ class AstCAwait final : public AstNodeUniop { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; AstSenTree* sensesp() const { return m_sensesp; } void clearSensesp() { m_sensesp = nullptr; } void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } @@ -4783,6 +4807,7 @@ class AstCCast final : public AstNodeUniop { return size() == VN_DBG_AS(samep, CCast)->size(); } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; // int size() const { return m_size; } }; @@ -5275,6 +5300,7 @@ class AstTimeImport final : public AstNodeUniop { bool cleanLhs() const override { return false; } bool sizeMattersLhs() const override { return false; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } }; @@ -5541,6 +5567,7 @@ class AstVarRef final : public AstNodeVarRef { ASTGEN_MEMBERS_AstVarRef; inline string name() const override; // * = Var name void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; bool same(const AstNode* samep) const override; inline bool same(const AstVarRef* samep) const; @@ -5565,6 +5592,7 @@ class AstVarXRef final : public AstNodeVarRef { ASTGEN_MEMBERS_AstVarXRef; string name() const override VL_MT_STABLE { return m_name; } // * = Var name void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string dotted() const { return m_dotted; } void dotted(const string& dotted) { m_dotted = dotted; } string inlinedDots() const { return m_inlinedDots; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index ff37277bc8..77e2586711 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -47,6 +47,7 @@ class AstNodeBlock VL_NOT_FINAL : public AstNode { public: ASTGEN_MEMBERS_AstNodeBlock; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Block name void name(const string& name) override { m_name = name; } bool unnamed() const { return m_unnamed; } @@ -123,6 +124,7 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode { ASTGEN_MEMBERS_AstNodeFTask; virtual AstNodeFTask* cloneType(const string& name) = 0; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool maybePointedTo() const override { return true; } bool isGateOptimizable() const override { @@ -210,6 +212,7 @@ class AstNodeFile VL_NOT_FINAL : public AstNode { , m_name{name} {} ASTGEN_MEMBERS_AstNodeFile; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -258,6 +261,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode { public: ASTGEN_MEMBERS_AstNodeModule; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool maybePointedTo() const override { return true; } string name() const override VL_MT_STABLE { return m_name; } virtual bool timescaleMatters() const = 0; @@ -313,6 +317,7 @@ class AstNodeProcedure VL_NOT_FINAL : public AstNode { ASTGEN_MEMBERS_AstNodeProcedure; // METHODS void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); } bool isSuspendable() const { return m_suspendable; } void setSuspendable() { m_suspendable = true; } @@ -328,6 +333,7 @@ class AstNodeRange VL_NOT_FINAL : public AstNode { public: ASTGEN_MEMBERS_AstNodeRange; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; }; class AstNodeStmt VL_NOT_FINAL : public AstNode { // Procedural statement @@ -341,6 +347,7 @@ class AstNodeStmt VL_NOT_FINAL : public AstNode { void addNextStmt(AstNode* newp, AstNode* belowp) override; // Stop statement searchback here void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; }; class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { // Iteration is in order, and we want rhsp to be visited first (which is the execution order) @@ -407,6 +414,7 @@ class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { bool same(const AstNode* samep) const override { return samep->name() == name(); } void name(const string& name) override { m_name = name; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; bool immediate() const { return m_immediate; } }; class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { @@ -505,6 +513,8 @@ class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { }; class AstNodeText VL_NOT_FINAL : public AstNode { string m_text; + // METHODS + string shortText() const; protected: // Node that puts text into the output stream @@ -515,6 +525,7 @@ class AstNodeText VL_NOT_FINAL : public AstNode { public: ASTGEN_MEMBERS_AstNodeText; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; bool same(const AstNode* samep) const override { const AstNodeText* asamep = VN_DBG_AS(samep, NodeText); return text() == asamep->text(); @@ -553,6 +564,7 @@ class AstActive final : public AstNode { } ASTGEN_MEMBERS_AstActive; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } const char* broken() const override; void cloneRelink() override; @@ -655,6 +667,7 @@ class AstCFunc final : public AstNode { void cloneRelink() override; bool maybePointedTo() const override { return true; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; bool same(const AstNode* samep) const override { const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc); return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) @@ -758,6 +771,7 @@ class AstCUse final : public AstNode { , m_useType{useType} {} ASTGEN_MEMBERS_AstCUse; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } VUseType useType() const { return m_useType; } }; @@ -810,6 +824,7 @@ class AstCell final : public AstNode { ASTGEN_MEMBERS_AstCell; // No cloneRelink, we presume cloneee's want the same module linkages void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; bool maybePointedTo() const override { return true; } // ACCESSORS @@ -851,6 +866,7 @@ class AstCellInline final : public AstNode { , m_timeunit{timeunit} {} ASTGEN_MEMBERS_AstCellInline; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; // ACCESSORS string name() const override VL_MT_STABLE { return m_name; } // * = Cell name @@ -878,6 +894,7 @@ class AstClassExtends final : public AstNode { } ASTGEN_MEMBERS_AstClassExtends; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool hasDType() const override { return true; } string verilogKwd() const override { return isImplements() ? "implements" : "extends"; } // Class being extended (after link and instantiation if needed) @@ -910,6 +927,7 @@ class AstClocking final : public AstNode { } ASTGEN_MEMBERS_AstClocking; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; std::string name() const override VL_MT_STABLE { return m_name; } bool isDefault() const { return m_isDefault; } bool isGlobal() const { return m_isGlobal; } @@ -1173,6 +1191,7 @@ class AstMTaskBody final : public AstNode { ExecMTask* execMTaskp() const { return m_execMTaskp; } void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; } void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; }; class AstModport final : public AstNode { // A modport in an interface @@ -1205,6 +1224,7 @@ class AstModportFTaskRef final : public AstNode { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } bool isImport() const { return !m_export; } bool isExport() const { return m_export; } @@ -1227,6 +1247,7 @@ class AstModportVarRef final : public AstNode { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } void direction(const VDirection& flag) { m_direction = flag; } VDirection direction() const { return m_direction; } @@ -1265,6 +1286,7 @@ class AstNetlist final : public AstNode { void cloneRelink() override { V3ERROR_NA; } string name() const override VL_MT_STABLE { return "$root"; } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy return modulesp(); // First one in the list, for now } @@ -1315,6 +1337,7 @@ class AstPackageExport final : public AstNode { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } @@ -1340,6 +1363,7 @@ class AstPackageImport final : public AstNode { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } @@ -1364,6 +1388,7 @@ class AstPin final : public AstNode { inline AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp); ASTGEN_MEMBERS_AstPin; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number void name(const string& name) override { m_name = name; } @@ -1474,6 +1499,7 @@ class AstScope final : public AstNode { string name() const override VL_MT_STABLE { return m_name; } // * = Scope name void name(const string& name) override { m_name = name; } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool same(const AstNode* samep) const override; string nameDotless() const; AstNodeModule* modp() const { return m_modp; } @@ -1522,6 +1548,7 @@ class AstSenItem final : public AstNode { , m_edgeType{VEdgeType::ET_NEVER} {} ASTGEN_MEMBERS_AstSenItem; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool same(const AstNode* samep) const override { return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType(); } @@ -1552,6 +1579,7 @@ class AstSenTree final : public AstNode { } ASTGEN_MEMBERS_AstSenTree; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool maybePointedTo() const override { return true; } bool isMulti() const { return m_multi; } void multi(bool flag) { m_multi = true; } @@ -1584,6 +1612,7 @@ class AstStrengthSpec final : public AstNode { VStrength strength0() { return m_s0; } VStrength strength1() { return m_s1; } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; }; class AstTopScope final : public AstNode { // A singleton, held under the top level AstModule. Holds the top level @@ -1641,6 +1670,7 @@ class AstTypeTable final : public AstNode { void clearCache(); void repairCache(); void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; }; class AstTypedef final : public AstNode { // @astgen op1 := childDTypep : Optional[AstNodeDType] @@ -1661,6 +1691,7 @@ class AstTypedef final : public AstNode { } ASTGEN_MEMBERS_AstTypedef; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); @@ -1867,6 +1898,7 @@ class AstVar final : public AstNode { } ASTGEN_MEMBERS_AstVar; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool same(const AstNode* samep) const override; string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name bool hasDType() const override { return true; } @@ -2122,6 +2154,7 @@ class AstVarScope final : public AstNode { bool maybePointedTo() const override { return true; } string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool same(const AstNode* samep) const override; bool hasDType() const override { return true; } AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable @@ -2150,6 +2183,7 @@ class AstBegin final : public AstNodeBlock { , m_implied{implied} {} ASTGEN_MEMBERS_AstBegin; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } void setNeedProcess() { m_needProcess = true; } @@ -2169,6 +2203,7 @@ class AstFork final : public AstNodeBlock { ASTGEN_MEMBERS_AstFork; bool isTimingControl() const override { return !joinType().joinNone(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; VJoinType joinType() const { return m_joinType; } void joinType(const VJoinType& flag) { m_joinType = flag; } }; @@ -2239,6 +2274,7 @@ class AstCFile final : public AstNodeFile { , m_support{false} {} ASTGEN_MEMBERS_AstCFile; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; bool slow() const { return m_slow; } void slow(bool flag) { m_slow = flag; } bool source() const { return m_source; } @@ -2254,6 +2290,7 @@ class AstVFile final : public AstNodeFile { : ASTGEN_SUPER_VFile(fl, name) {} ASTGEN_MEMBERS_AstVFile; void dump(std::ostream& str = std::cout) const override; + void dumpExtraJson(std::ostream& str = std::cout) const override; }; // === AstNodeModule === @@ -2274,6 +2311,7 @@ class AstClass final : public AstNodeModule { string verilogKwd() const override { return "class"; } bool maybePointedTo() const override { return true; } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override; void cloneRelink() override; bool timescaleMatters() const override { return false; } @@ -2379,6 +2417,7 @@ class AstAlways final : public AstNodeProcedure { ASTGEN_MEMBERS_AstAlways; // void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; VAlwaysKwd keyword() const { return m_keyword; } }; class AstAlwaysObserved final : public AstNodeProcedure { @@ -2496,6 +2535,7 @@ class AstRange final : public AstNodeRange { int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; } bool ascending() const { return leftConst() < rightConst(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -2673,6 +2713,7 @@ class AstCoverDecl final : public AstNodeStmt { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } bool maybePointedTo() const override { return true; } void binNum(int flag) { m_binNum = flag; } @@ -2712,6 +2753,7 @@ class AstCoverInc final : public AstNodeStmt { if (m_declp->clonep()) m_declp = m_declp->clonep(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } bool same(const AstNode* samep) const override { return declp() == VN_DBG_AS(samep, CoverInc)->declp(); @@ -2759,6 +2801,7 @@ class AstDelay final : public AstNodeStmt { } ASTGEN_MEMBERS_AstDelay; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; bool isTimingControl() const override { return true; } bool isCycleDelay() const { return m_isCycle; } bool same(const AstNode* /*samep*/) const override { return true; } @@ -2806,6 +2849,7 @@ class AstDisplay final : public AstNodeStmt { } ASTGEN_MEMBERS_AstDisplay; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; const char* broken() const override { BROKEN_RTN(!fmtp()); return nullptr; @@ -2978,6 +3022,7 @@ class AstJumpGo final : public AstNodeStmt { const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return INSTR_COUNT_BRANCH; } bool same(const AstNode* samep) const override { return labelp() == VN_DBG_AS(samep, JumpGo)->labelp(); @@ -3008,6 +3053,7 @@ class AstJumpLabel final : public AstNodeStmt { if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return 0; } bool same(const AstNode* samep) const override { return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp(); @@ -3044,6 +3090,7 @@ class AstPrintTimeScale final : public AstNodeStmt { void name(const string& name) override { m_name = name; } string name() const override VL_MT_STABLE { return m_name; } // * = Var name void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; string verilogKwd() const override { return "$printtimescale"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } @@ -3257,6 +3304,7 @@ class AstTraceDecl final : public AstNodeStmt { this->valuep(valuep); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return 100; } // Large... ASTGEN_MEMBERS_AstTraceDecl; string name() const override VL_MT_STABLE { return m_showname; } @@ -3303,6 +3351,7 @@ class AstTraceInc final : public AstNodeStmt { if (m_declp->clonep()) m_declp = m_declp->clonep(); } void dump(std::ostream& str) const override; + void dumpExtraJson(std::ostream& str) const override; int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } bool hasDType() const override { return true; } bool same(const AstNode* samep) const override { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5b717f5132..466001a0ed 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2,7 +2,7 @@ //************************************************************************* // DESCRIPTION: Verilator: Ast node structures // -// Code available from: https://verilator.org + // Code available from: https://verilator.org // //************************************************************************* // @@ -27,8 +27,46 @@ #include #include +#include +#include #include +// Render node address for dumps. By default this is just the address +// printed as hex, but with --dump-tree-addrids we map addresses to short +// strings with a bijection to aid human readability. Observe that this might +// not actually be a unique identifier as the address can get reused after a +// node has been freed. +static std::string nodeAddr(const AstNode* nodep) { + return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep); +} + +// Shorthands for dumping JSON. + +// SQOUT - stream quote - print x surrounded with quotes. Example: cout << SQUOT("something") +#define SQUOT(x) '"' << (x) << '"' + +// Routines for dumping dict fields (NOTE: due to leading ',' they can't be used for first field in +// dict) +static void dumpJsonNum(std::ostream& os, const std::string& name, int64_t val) { + os << "," << SQUOT(name) << ":" << val; +} +static void dumpJsonBool(std::ostream& os, const std::string& name, bool val) { + os << "," << SQUOT(name) << ":" << (val ? "true" : "false"); +} +static void dumpJsonStr(std::ostream& os, const std::string& name, const std::string& val) { + os << "," << SQUOT(name) << ":" << SQUOT(V3OutFormatter::quoteNameControls(val)); +} +static void dumpJsonPtr(std::ostream& os, const std::string& name, const AstNode* const valp, + const std::string& unlink_msg = "UNLINKED") { + os << "," << SQUOT(name) << ":" << SQUOT(valp ? nodeAddr(valp) : unlink_msg); +} + +// Shorthands for dumping fields that use func name as key +#define dumpJsonNumFunc(os, func) dumpJsonNum(os, #func, func()) +#define dumpJsonBoolFunc(os, func) dumpJsonBool(os, #func, func()) +#define dumpJsonStrFunc(os, func) dumpJsonStr(os, #func, func()) +#define dumpJsonPtrFunc(os, func) dumpJsonPtr(os, #func, func()) + //====================================================================== // Special methods @@ -118,6 +156,7 @@ const char* AstNodeUOrStructDType::broken() const { } void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeStmt::dumpExtraJson(std::ostream& str) const { AstNode::dumpExtraJson(str); } void AstNodeCCall::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); @@ -128,6 +167,12 @@ void AstNodeCCall::dump(std::ostream& str) const { str << " " << name(); } } +void AstNodeCCall::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + if (funcp()) dumpJsonStr(str, "funcName", funcp()->name()); + dumpJsonPtrFunc(str, funcp); + // WARN: I'm not sure about this dump +} void AstNodeCCall::cloneRelink() { if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep(); } @@ -1364,15 +1409,6 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) { //====================================================================== // Per-type Debugging -// Render node address for dumps. By default this is just the address -// printed as hex, but with --dump-tree-addrids we map addresses to short -// strings with a bijection to aid human readability. Observe that this might -// not actually be a unique identifier as the address can get reused after a -// node has been freed. -static std::string nodeAddr(const AstNode* nodep) { - return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep); -} - void AstNode::dump(std::ostream& str) const { str << typeName() << " " << nodeAddr(this) #ifdef VL_DEBUG @@ -1404,26 +1440,78 @@ void AstNode::dump(std::ostream& str) const { } } +static void dumpNodeListJson(std::ostream& os, const AstNode* nodep, const std::string& listName) { + os << "," << SQUOT(listName) << ": ["; + bool comma = false; + for (; nodep; nodep = nodep->nextp()) { + if (comma) os << ", "; + comma = true; + nodep->dumpTreeJson(os); + } + os << "]"; +} + +void AstNode::dumpTreeJson(std::ostream& os) const { + // TODO: + // - dumping dtype + os << "{" << SQUOT("type") << ":" << SQUOT(typeName()); + dumpJsonStr(os, "name", V3OutFormatter::quoteNameControls(name())); + dumpJsonPtr(os, "addr", this); + dumpJsonStr(os, "file", + fileline()->filename() + ":" + std::to_string(fileline()->lastLineno()) + ":" + + std::to_string(fileline()->firstColumn())); +#ifdef VL_DEBUG + dumpJsonNum(os, "editNum", editCount()); +#endif + dumpExtraJson(os); + dumpNodeListJson(os, op1p(), "op1"); + dumpNodeListJson(os, op2p(), "op2"); + dumpNodeListJson(os, op3p(), "op3"); + dumpNodeListJson(os, op4p(), "op4"); + os << "}"; +} + void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); if (isSuspendable()) str << " [SUSP]"; if (needProcess()) str << " [NPRC]"; } +void AstNodeProcedure::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isSuspendable); + dumpJsonBoolFunc(str, needProcess); +} + void AstAlways::dump(std::ostream& str) const { this->AstNodeProcedure::dump(str); if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]"; } +void AstAlways::dumpExtraJson(std::ostream& str) const { + AstNodeProcedure::dumpExtraJson(str); + dumpJsonStr(str, "keyword", keyword().ascii()); +} void AstAttrOf::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << attrType().ascii() << "]"; } +void AstAttrOf::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "attrType", attrType().ascii()); +} void AstBasicDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); str << " kwd=" << keyword().ascii(); if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]"; } +void AstBasicDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonStr(str, "keyword", keyword().ascii()); + if (isRanged() && !rangep()) { + dumpJsonStr(str, "range", std::to_string(left()) + ":" + std::to_string(right())); + } +} string AstBasicDType::prettyDTypeName() const { std::ostringstream os; os << keyword().ascii(); @@ -1434,12 +1522,18 @@ string AstBasicDType::prettyDTypeName() const { } void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeExpr::dumpExtraJson(std::ostream& str) const { AstNode::dumpExtraJson(str); } void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } +void AstNodeUniop::dumpExtraJson(std::ostream& str) const { AstNodeExpr::dumpExtraJson(str); } void AstCCast::dump(std::ostream& str) const { this->AstNodeUniop::dump(str); str << " sz" << size(); } +void AstCCast::dumpExtraJson(std::ostream& str) const { + AstNodeUniop::dumpExtraJson(str); + dumpJsonNumFunc(str, size); +} void AstCell::dump(std::ostream& str) const { this->AstNode::dump(str); if (recursive()) str << " [RECURSIVE]"; @@ -1450,6 +1544,11 @@ void AstCell::dump(std::ostream& str) const { str << " ->UNLINKED:" << modName(); } } +void AstCell::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, recursive); + dumpJsonPtr(str, "modp", modp(), "UNLINKED:" + modName()); +} const char* AstCell::broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return nullptr; @@ -1459,6 +1558,12 @@ void AstCellInline::dump(std::ostream& str) const { str << " -> " << origModName(); str << " [scopep=" << nodeAddr(scopep()) << "]"; } +void AstCellInline::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStrFunc(str, origModName); + // NOTE: I don't know why, but normal dump() doesn't use nodeAddr() for scopep + dumpJsonPtrFunc(str, scopep); +} const char* AstCellInline::broken() const { BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return nullptr; @@ -1496,6 +1601,12 @@ void AstClass::dump(std::ostream& str) const { if (isInterfaceClass()) str << " [IFCCLS]"; if (isVirtual()) str << " [VIRT]"; } +void AstClass::dumpExtraJson(std::ostream& str) const { + AstNodeModule::dumpExtraJson(str); + dumpJsonBoolFunc(str, isExtended); + dumpJsonBoolFunc(str, isInterfaceClass); + dumpJsonBoolFunc(str, isVirtual); +} const char* AstClass::broken() const { BROKEN_BASE_RTN(AstNodeModule::broken()); BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); @@ -1511,6 +1622,10 @@ void AstClassExtends::dump(std::ostream& str) const { this->AstNode::dump(str); if (isImplements()) str << " [IMPLEMENTS]"; } +void AstClassExtends::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isImplements); +} AstClass* AstClassExtends::classOrNullp() const { const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep(); const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType); @@ -1536,6 +1651,11 @@ void AstClassRefDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstClassRefDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonPtr(str, "cpkgp", classOrPackagep()); + dumpJsonPtrFunc(str, classp); +} void AstClassRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "class:" << name(); @@ -1556,19 +1676,33 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (immediate()) str << " [IMMEDIATE]"; } +void AstNodeCoverOrAssert::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonBoolFunc(str, immediate); +} void AstClocking::dump(std::ostream& str) const { this->AstNode::dump(str); if (isDefault()) str << " [DEFAULT]"; if (isGlobal()) str << " [GLOBAL]"; } +void AstClocking::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isDefault); + dumpJsonBoolFunc(str, isGlobal); +} void AstDisplay::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); // str << " " << displayType().ascii(); } +void AstDisplay::dumpExtraJson(std::ostream& str) const { AstNodeStmt::dumpExtraJson(str); } void AstEnumDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); str << " enum"; } +void AstEnumDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonBool(str, "enum", 1); +} void AstEnumDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "enum"; @@ -1590,6 +1724,10 @@ const char* AstEnumDType::broken() const { return nullptr; } +void AstEnumItemRef::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + dumpJsonPtrFunc(str, itemp); +} const char* AstEnumItemRef::broken() const { BROKEN_RTN(m_itemp && !m_itemp->brokeExists()); BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); @@ -1616,6 +1754,14 @@ void AstIfaceRefDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstIfaceRefDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + if (cellName() != "") dumpJsonStr(str, "cell", cellName()); + if (ifaceName() != "") dumpJsonStr(str, "if", ifaceName()); + if (modportName() != "") dumpJsonStr(str, "mp", modportName()); + dumpJsonPtrFunc(str, cellp); + dumpJsonPtrFunc(str, ifacep); +} void AstIfaceRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "iface"; @@ -1625,8 +1771,7 @@ void AstIfaceRefDType::cloneRelink() { if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); } -void AstInitArray::dump(std::ostream& str) const { - this->AstNode::dump(str); +void AstInitArray::dumpInitList(std::ostream& str) const { int n = 0; const auto& mapr = map(); for (const auto& itr : mapr) { @@ -1637,6 +1782,16 @@ void AstInitArray::dump(std::ostream& str) const { str << " [" << itr.first << "]=" << nodeAddr(itr.second); } } +void AstInitArray::dump(std::ostream& str) const { + this->AstNode::dump(str); + dumpInitList(str); +} +void AstInitArray::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + str << ',' << SQUOT("initList") << ':' << '"'; + dumpInitList(str); + str << '"'; +} const char* AstInitArray::broken() const { for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { BROKEN_RTN(!it->second); @@ -1682,6 +1837,10 @@ void AstJumpGo::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstJumpGo::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonPtr(str, "labelp", labelp(), "%Error:UNLINKED"); +} const char* AstJumpGo::broken() const { BROKEN_RTN(!labelp()->brokeExistsBelow()); return nullptr; @@ -1698,6 +1857,10 @@ void AstJumpLabel::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstJumpLabel::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonPtr(str, "blockp", blockp(), "%Error:UNLINKED"); +} void AstMemberDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); @@ -1726,6 +1889,11 @@ void AstMemberSel::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstMemberSel::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + dumpJsonPtr(str, "varp", varp(), "%Error:UNLINKED"); +} + void AstMemberSel::cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); } @@ -1744,6 +1912,12 @@ void AstModportFTaskRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstModportFTaskRef::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isExport); + dumpJsonBoolFunc(str, isImport); + dumpJsonPtrFunc(str, ftaskp); +} const char* AstModportFTaskRef::broken() const { BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); return nullptr; @@ -1761,6 +1935,11 @@ void AstModportVarRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstModportVarRef::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "direction", direction().ascii()); + dumpJsonPtrFunc(str, varp); +} const char* AstModportVarRef::broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return nullptr; @@ -1779,6 +1958,13 @@ void AstPin::dump(std::ostream& str) const { if (svDotName()) str << " [.n]"; if (svImplicit()) str << " [.SV]"; } + +void AstPin::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtrFunc(str, modVarp); + dumpJsonBoolFunc(str, svDotName); + dumpJsonBoolFunc(str, svImplicit); +} const char* AstPin::broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); @@ -1794,20 +1980,37 @@ void AstPrintTimeScale::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " " << timeunit(); } +void AstPrintTimeScale::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonStr(str, "timeunit", timeunit().ascii()); +} void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } +void AstNodeTermop::dumpExtraJson(std::ostream& str) const { AstNodeExpr::dumpExtraJson(str); } void AstTime::dump(std::ostream& str) const { this->AstNodeTermop::dump(str); str << " " << timeunit(); } +void AstTime::dumpExtraJson(std::ostream& str) const { + AstNodeTermop::dumpExtraJson(str); + dumpJsonStr(str, "timeunit", timeunit().ascii()); +} void AstTimeD::dump(std::ostream& str) const { this->AstNodeTermop::dump(str); str << " " << timeunit(); } +void AstTimeD::dumpExtraJson(std::ostream& str) const { + AstNodeTermop::dumpExtraJson(str); + dumpJsonStr(str, "timeunit", timeunit().ascii()); +} void AstTimeImport::dump(std::ostream& str) const { this->AstNodeUniop::dump(str); str << " " << timeunit(); } +void AstTimeImport::dumpExtraJson(std::ostream& str) const { + AstNodeUniop::dumpExtraJson(str); + dumpJsonStr(str, "timeunit", timeunit().ascii()); +} void AstTypedef::dump(std::ostream& str) const { this->AstNode::dump(str); if (attrPublic()) str << " [PUBLIC]"; @@ -1816,11 +2019,21 @@ void AstTypedef::dump(std::ostream& str) const { subDTypep()->dump(str); } } +void AstTypedef::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBool(str, "public", attrPublic()); + dumpJsonPtrFunc(str, subDTypep); +} void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeRange::dumpExtraJson(std::ostream& str) const { AstNode::dumpExtraJson(str); } void AstRange::dump(std::ostream& str) const { this->AstNodeRange::dump(str); if (ascending()) str << " [ASCENDING]"; } +void AstRange::dumpExtraJson(std::ostream& str) const { + AstNodeRange::dumpExtraJson(str); + dumpJsonBoolFunc(str, ascending); +} void AstParamTypeDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (subDTypep()) { @@ -1830,6 +2043,10 @@ void AstParamTypeDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstParamTypeDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonPtrFunc(str, subDTypep); +} void AstRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (typedefp() || subDTypep()) { @@ -1848,6 +2065,11 @@ void AstRefDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +void AstRefDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonPtrFunc(str, typedefp); + dumpJsonPtrFunc(str, subDTypep); +} void AstRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "ref"; @@ -1875,6 +2097,12 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const { if (isFourstate()) str << " [4STATE]"; if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); } +void AstNodeUOrStructDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonBoolFunc(str, packed); + dumpJsonBoolFunc(str, isFourstate); + dumpJsonPtr(str, "pkgp", classOrPackagep()); +} void AstNodeDType::dump(std::ostream& str) const { this->AstNode::dump(str); if (generic()) str << " [GENERIC]"; @@ -1883,6 +2111,13 @@ void AstNodeDType::dump(std::ostream& str) const { dtp->dumpSmall(str); } } +void AstNodeDType::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, generic); + if (AstNodeDType* const dtp = virtRefDTypep()) { + dumpJsonPtr(str, "dtp", dtp); // WARN + } +} void AstNodeDType::dumpSmall(std::ostream& str) const { str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "") << (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : ""); @@ -1905,6 +2140,13 @@ void AstNodeArrayDType::dump(std::ostream& str) const { if (isCompound()) str << " [COMPOUND]"; str << " " << declRange(); } +void AstNodeArrayDType::dumpExtraJson(std::ostream& str) const { + AstNodeDType::dumpExtraJson(str); + dumpJsonBoolFunc(str, isCompound); + std::stringstream declRangeStream; + declRange().dump(declRangeStream); + dumpJsonStr(str, "declRange", declRangeStream.rdbuf()->str()); +} string AstPackArrayDType::prettyDTypeName() const { std::ostringstream os; if (const auto subp = subDTypep()) os << subp->prettyDTypeName(); @@ -1940,6 +2182,11 @@ void AstNetlist::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << timeunit() << "/" << timeprecision() << "]"; } +void AstNetlist::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "timeunit", timeunit().ascii()); + dumpJsonStr(str, "timeprecision", timeprecision().ascii()); +} const char* AstNetlist::broken() const { BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists()); BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists()); @@ -1982,10 +2229,24 @@ void AstNodeModule::dump(std::ostream& str) const { } str << " [" << timeunit() << "]"; } +void AstNodeModule::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonNumFunc(str, level); + dumpJsonBoolFunc(str, modPublic); + dumpJsonBoolFunc(str, inLibrary); + dumpJsonBoolFunc(str, dead); + dumpJsonBoolFunc(str, recursiveClone); + dumpJsonBoolFunc(str, recursive); + dumpJsonStr(str, "timeunit", timeunit().ascii()); +} void AstPackageExport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +void AstPackageExport::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtrFunc(str, packagep); +} const char* AstPackageExport::broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return nullptr; @@ -1997,6 +2258,10 @@ void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +void AstPackageImport::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtrFunc(str, packagep); +} const char* AstPackageImport::broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return nullptr; @@ -2008,7 +2273,12 @@ void AstPatMember::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (isDefault()) str << " [DEFAULT]"; } +void AstPatMember::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + if (isDefault()) dumpJsonBoolFunc(str, isDefault); +} void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } +void AstNodeTriop::dumpExtraJson(std::ostream& str) const { AstNodeExpr::dumpExtraJson(str); } void AstSel::dump(std::ostream& str) const { this->AstNodeTriop::dump(str); if (declRange().ranged()) { @@ -2016,15 +2286,38 @@ void AstSel::dump(std::ostream& str) const { if (declElWidth() != 1) str << "/" << declElWidth(); } } +void AstSel::dumpExtraJson(std::ostream& str) const { + AstNodeTriop::dumpExtraJson(str); + if (declRange().ranged()) { + std::stringstream declRangeStream; + declRange().dump(declRangeStream); + dumpJsonStr(str, "declRange", declRangeStream.rdbuf()->str()); + dumpJsonNumFunc(str, declElWidth); + } +} void AstSliceSel::dump(std::ostream& str) const { this->AstNodeTriop::dump(str); if (declRange().ranged()) str << " decl" << declRange(); } +void AstSliceSel::dumpExtraJson(std::ostream& str) const { + AstNodeTriop::dumpExtraJson(str); + if (declRange().ranged()) { + std::stringstream declRangeStream; + declRange().dump(declRangeStream); + dumpJsonStr(str, "declRange", declRangeStream.rdbuf()->str()); + } +} void AstMTaskBody::dump(std::ostream& str) const { this->AstNode::dump(str); str << " "; m_execMTaskp->dump(str); } +void AstMTaskBody::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + str << ',' << SQUOT("execMTask") << ':' << '"'; + m_execMTaskp->dump(str); // WARN: I'm unsure about this dump + str << '"'; +} void AstTypeTable::dump(std::ostream& str) const { this->AstNode::dump(str); for (int i = 0; i < static_cast(VBasicDTypeKwd::_ENUM_MAX); ++i) { @@ -2046,6 +2339,10 @@ void AstTypeTable::dump(std::ostream& str) const { } // Note get newline from caller too. } +void AstTypeTable::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + // WARN: Unimplemented +} void AstAssocArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "[assoc-" << nodeAddr(keyDTypep()) << "]"; @@ -2124,6 +2421,12 @@ void AstVarScope::dump(std::ostream& str) const { str << " ->UNLINKED"; } } +void AstVarScope::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isTrace); + dumpJsonPtrFunc(str, varp); + dumpJsonPtrFunc(str, scopep); +} bool AstVarScope::same(const AstNode* samep) const { const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope); return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep()); @@ -2133,6 +2436,11 @@ void AstNodeVarRef::dump(std::ostream& str) const { if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); str << " " << access().arrow() << " "; } +void AstNodeVarRef::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + dumpJsonPtr(str, "pkgp", classOrPackagep()); + dumpJsonStr(str, "access", access().ascii()); +} void AstVarXRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); str << ".=" << dotted() << " "; @@ -2145,6 +2453,13 @@ void AstVarXRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +void AstVarXRef::dumpExtraJson(std::ostream& str) const { + AstNodeVarRef::dumpExtraJson(str); + dumpJsonStr(str, "dot", dotted()); + dumpJsonStr(str, "inlineDot", inlinedDots()); + dumpJsonPtrFunc(str, varp); + dumpJsonPtrFunc(str, varScopep); +} void AstVarRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); if (varScopep()) { @@ -2155,6 +2470,11 @@ void AstVarRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +void AstVarRef::dumpExtraJson(std::ostream& str) const { + AstNodeVarRef::dumpExtraJson(str); + dumpJsonPtrFunc(str, varp); + dumpJsonPtrFunc(str, varScopep); +} const char* AstVarRef::broken() const { BROKEN_RTN(!varp()); return AstNodeVarRef::broken(); @@ -2199,6 +2519,31 @@ void AstVar::dump(std::ostream& str) const { if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; str << " " << varType(); } +void AstVar::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isSc); + // if (isPrimaryIO()) str << (isInoutish() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]")); + // WARN: I'm not sure how I should dump this. I think that dumping just ioDirection may be + // sufficient + dumpJsonStr(str, "ioDirection", direction().ascii()); + dumpJsonBoolFunc(str, isConst); + dumpJsonBoolFunc(str, isPullup); + dumpJsonBoolFunc(str, isPulldown); + dumpJsonBoolFunc(str, isUsedClock); + dumpJsonBoolFunc(str, isSigPublic); + dumpJsonBoolFunc(str, isLatched); + dumpJsonBoolFunc(str, isUsedLoopIdx); + dumpJsonBoolFunc(str, noReset); + dumpJsonBoolFunc(str, attrIsolateAssign); + dumpJsonBoolFunc(str, attrFileDescr); + dumpJsonBoolFunc(str, isDpiOpenArray); + dumpJsonBoolFunc(str, isFuncReturn); + dumpJsonBoolFunc(str, isFuncLocal); + dumpJsonStr(str, "attrClocker", (attrClocker().unknown() ? "UNKNOWN" : attrClocker().ascii())); + dumpJsonStr(str, "lifetime", lifetime().ascii()); + dumpJsonStr(str, "varType", varType().ascii()); + // TODO: maybe try to shorten these flags somehow +} bool AstVar::same(const AstNode* samep) const { const AstVar* const asamep = VN_DBG_AS(samep, Var); return name() == asamep->name() && varType() == asamep->varType(); @@ -2209,6 +2554,12 @@ void AstScope::dump(std::ostream& str) const { str << " [cellp=" << nodeAddr(aboveCellp()) << "]"; str << " [modp=" << nodeAddr(modp()) << "]"; } +void AstScope::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtr(str, "abovep", aboveScopep()); + dumpJsonPtr(str, "cellp", aboveCellp()); + dumpJsonPtr(str, "modp", modp()); +} bool AstScope::same(const AstNode* samep) const { const AstScope* const asamep = VN_DBG_AS(samep, Scope); return name() == asamep->name() @@ -2221,22 +2572,44 @@ void AstScopeName::dump(std::ostream& str) const { if (dpiExport()) str << " [DPIEX]"; if (forFormat()) str << " [FMT]"; } +void AstScopeName::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + dumpJsonBoolFunc(str, dpiExport); + dumpJsonBoolFunc(str, forFormat); +} void AstSenTree::dump(std::ostream& str) const { this->AstNode::dump(str); if (isMulti()) str << " [MULTI]"; } +void AstSenTree::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, isMulti); +} void AstSenItem::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << edgeType().ascii() << "]"; } +void AstSenItem::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "edgeType", edgeType().ascii()); +} void AstStrengthSpec::dump(std::ostream& str) const { this->AstNode::dump(str); str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")"; } +void AstStrengthSpec::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "strength0", m_s0.ascii()); + dumpJsonStr(str, "strength1", m_s1.ascii()); +} void AstParseRef::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << expect().ascii() << "]"; } +void AstParseRef::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "expect", expect().ascii()); +} void AstClassOrPackageRef::dump(std::ostream& str) const { this->AstNode::dump(str); if (classOrPackageNodep()) str << " cpkg=" << nodeAddr(classOrPackageNodep()); @@ -2247,6 +2620,10 @@ void AstClassOrPackageRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +void AstClassOrPackageRef::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtrFunc(str, classOrPackageNodep); +} AstNodeModule* AstClassOrPackageRef::classOrPackagep() const { AstNode* foundp = m_classOrPackageNodep; if (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); @@ -2259,6 +2636,10 @@ void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); if (colon()) str << " [::]"; } +void AstDot::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, colon); +} void AstActive::dump(std::ostream& str) const { this->AstNode::dump(str); str << " => "; @@ -2268,6 +2649,10 @@ void AstActive::dump(std::ostream& str) const { str << "UNLINKED"; } } +void AstActive::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonPtrFunc(str, sensesp); +} const char* AstActive::broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return nullptr; @@ -2286,6 +2671,12 @@ void AstNodeFTaskRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +void AstNodeFTaskRef::dumpExtraJson(std::ostream& str) const { + AstNodeExpr::dumpExtraJson(str); + dumpJsonPtr(str, "pkgp", classOrPackagep()); + dumpJsonPtrFunc(str, taskp); + dumpJsonStr(str, "dot", dotted()); +} void AstNodeFTask::dump(std::ostream& str) const { this->AstNode::dump(str); if (classMethod()) str << " [METHOD]"; @@ -2323,10 +2714,28 @@ bool AstNodeFTask::getPurityRecurse() const { } return true; } +void AstNodeFTask::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBool(str, "method", classMethod()); + dumpJsonBoolFunc(str, dpiExport); + dumpJsonBoolFunc(str, dpiImport); + dumpJsonBoolFunc(str, dpiOpenChild); + dumpJsonBoolFunc(str, dpiOpenParent); + dumpJsonBoolFunc(str, prototype); + dumpJsonBoolFunc(str, recursive); + dumpJsonBoolFunc(str, taskPublic); + if ((dpiImport() || dpiExport()) && cname() != name()) { + dumpJsonStrFunc(str, cname); // WARN: not sure about this + } +} void AstNodeBlock::dump(std::ostream& str) const { this->AstNode::dump(str); if (unnamed()) str << " [UNNAMED]"; } +void AstNodeBlock::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, unnamed); +} void AstBegin::dump(std::ostream& str) const { this->AstNodeBlock::dump(str); if (generate()) str << " [GEN]"; @@ -2334,6 +2743,12 @@ void AstBegin::dump(std::ostream& str) const { if (implied()) str << " [IMPLIED]"; if (needProcess()) str << " [NPRC]"; } +void AstBegin::dumpExtraJson(std::ostream& str) const { + AstNodeBlock::dumpExtraJson(str); + dumpJsonBoolFunc(str, generate); + dumpJsonBool(str, "genfor", bool(genforp())); + dumpJsonBoolFunc(str, implied); +} void AstCoverDecl::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (!page().empty()) str << " page=" << page(); @@ -2345,6 +2760,10 @@ void AstCoverDecl::dump(std::ostream& str) const { if (binNum()) str << " bin" << std::dec << binNum(); } } +void AstCoverDecl::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + // WARN: Unimplemented +} void AstCoverInc::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -2354,14 +2773,26 @@ void AstCoverInc::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstCoverInc::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonPtr(str, "declp", declp(), "%Error:UNLINKED"); +} void AstFork::dump(std::ostream& str) const { this->AstNodeBlock::dump(str); if (!joinType().join()) str << " [" << joinType() << "]"; } +void AstFork::dumpExtraJson(std::ostream& str) const { + AstNodeBlock::dumpExtraJson(str); + dumpJsonStr(str, "joinType", joinType().ascii()); +} void AstTraceDecl::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (code()) str << " [code=" << code() << "]"; } +void AstTraceDecl::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonNumFunc(str, code); +} void AstTraceInc::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -2371,25 +2802,44 @@ void AstTraceInc::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } -void AstNodeText::dump(std::ostream& str) const { - this->AstNode::dump(str); +void AstTraceInc::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonPtr(str, "declp", declp(), "%Error:UNLINKED"); +} +string AstNodeText::shortText() const { string out = text(); string::size_type pos; if ((pos = out.find('\n')) != string::npos) { out.erase(pos, out.length() - pos); out += "..."; } - str << " \"" << out << "\""; + return out; +} +void AstNodeText::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " \"" << shortText() << "\""; +} +void AstNodeText::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "text", shortText()); } void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeFile::dumpExtraJson(std::ostream& str) const { AstNode::dumpExtraJson(str); } void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); } +void AstVFile::dumpExtraJson(std::ostream& str) const { AstNodeFile::dumpExtraJson(str); } void AstCFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); if (source()) str << " [SRC]"; if (slow()) str << " [SLOW]"; } + +void AstCFile::dumpExtraJson(std::ostream& str) const { + AstNodeFile::dumpExtraJson(str); + dumpJsonBoolFunc(str, source); + dumpJsonBoolFunc(str, slow); +} void AstCFunc::dump(std::ostream& str) const { this->AstNode::dump(str); if (slow()) str << " [SLOW]"; @@ -2407,6 +2857,22 @@ void AstCFunc::dump(std::ostream& str) const { if (needProcess()) str << " [NPRC]"; if (entryPoint()) str << " [ENTRY]"; } +void AstCFunc::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonBoolFunc(str, slow); + dumpJsonBoolFunc(str, isStatic); + dumpJsonBoolFunc(str, dpiExportDispatcher); + dumpJsonBoolFunc(str, dpiExportImpl); + dumpJsonBoolFunc(str, dpiImportPrototype); + dumpJsonBoolFunc(str, dpiImportWrapper); + dumpJsonBoolFunc(str, dpiContext); + dumpJsonBoolFunc(str, isConstructor); + dumpJsonBoolFunc(str, isDestructor); + dumpJsonBoolFunc(str, isVirtual); + dumpJsonBoolFunc(str, isCoroutine); + dumpJsonBoolFunc(str, needProcess); + // TODO: maybe try to shorten these flags somehow +} const char* AstCAwait::broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return nullptr; @@ -2421,6 +2887,10 @@ void AstCAwait::dump(std::ostream& str) const { sensesp()->dump(str); } } +void AstCAwait::dumpExtraJson(std::ostream& str) const { + AstNodeUniop::dumpExtraJson(str); + dumpJsonPtrFunc(str, sensesp); +} int AstCMethodHard::instrCount() const { if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) { // TODO: add a more structured description of library methods, rather than using string @@ -2514,6 +2984,10 @@ void AstCUse::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << useType() << "]"; } +void AstCUse::dumpExtraJson(std::ostream& str) const { + AstNode::dumpExtraJson(str); + dumpJsonStr(str, "useType", useType().ascii()); +} AstAlways* AstAssignW::convertToAlways() { const bool hasTimingControl = isTimingControl(); @@ -2538,3 +3012,7 @@ void AstDelay::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (isCycleDelay()) str << " [CYCLE]"; } +void AstDelay::dumpExtraJson(std::ostream& str) const { + AstNodeStmt::dumpExtraJson(str); + dumpJsonBoolFunc(str, isCycleDelay); +} diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 454787fe9c..a594d9442e 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -107,6 +107,9 @@ string V3Global::digitsFilename(int number) { void V3Global::dumpCheckGlobalTree(const string& stagename, int newNumber, bool doDump) { const string treeFilename = v3Global.debugFilename(stagename + ".tree", newNumber); v3Global.rootp()->dumpTreeFile(treeFilename, false, doDump); + if (v3Global.opt.dumpTreeJson()) { + v3Global.rootp()->dumpTreeJsonFile(treeFilename + ".json", false, doDump); + } if (v3Global.opt.dumpTreeDot()) { v3Global.rootp()->dumpTreeDotFile(treeFilename + ".dot", false, doDump); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 919aefd96a..1d97eb4d47 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -898,11 +898,22 @@ void V3Options::notify() VL_MT_DISABLED { // Mark options as available m_available = true; + // --dump-json-tree will serve as alias to --dump-tree-json. Rationale is that: + // - It is easy typo to make (after all tool used for pretty printing is called jsontree) + // - Parsing of dump* options is very "forgiving" and does not report error when non-existing + // option is used + if (m_dumpLevel.count("json-tree")) m_dumpLevel["tree-json"] = m_dumpLevel["json-tree"]; + // --dump-tree-dot will turn on tree dumping. if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) { m_dumpLevel["tree"] = m_dumpLevel["tree-dot"]; } + // --dump-tree-json will turn on tree dumping. + if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-json")) { + m_dumpLevel["tree"] = m_dumpLevel["tree-json"]; + } + // Sanity check of expected configuration UASSERT(threads() >= 1, "'threads()' must return a value >= 1"); diff --git a/src/V3Options.h b/src/V3Options.h index 259462fe84..0b04be6f07 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -472,6 +472,9 @@ class V3Options final { bool decoration() const VL_MT_SAFE { return m_decoration; } bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); } + bool dumpTreeJson() const { + return m_dumpLevel.count("tree-json") && m_dumpLevel.at("tree-json"); + } bool dumpTreeDot() const { return m_dumpLevel.count("tree-dot") && m_dumpLevel.at("tree-dot"); } From a46b6e20ff3a7f1b375e5d081a738797b03d1bd7 Mon Sep 17 00:00:00 2001 From: Szymon Gizler Date: Tue, 21 Nov 2023 15:29:45 +0100 Subject: [PATCH 2/7] Improve .gdbinit --- Makefile.in | 1 + src/.gdbinit | 20 +++++++++++++++ src/.gdbinit.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/.gdbinit.py diff --git a/Makefile.in b/Makefile.in index 8eb581f1e0..85af9395ee 100644 --- a/Makefile.in +++ b/Makefile.in @@ -410,6 +410,7 @@ PY_PROGRAMS = \ src/cppcheck_filtered \ src/flexfix \ src/vlcovgen \ + src/.gdbinit.py \ test_regress/t/*.pf \ nodist/clang_check_attributes \ nodist/code_coverage \ diff --git a/src/.gdbinit b/src/.gdbinit index b6c6c40a32..7c29624a61 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -20,6 +20,26 @@ document pnt Verilator: Print AstNode NODEP's tree end +# source python-based gdb config with jshow/jdiff definitions +# (we store it in separate file, so it can be highlighted/linted/formatted as python) +python +import os +if "VERILATOR_ROOT" in os.environ: + gdbinit_py = os.environ["VERILATOR_ROOT"] + "/src/.gdbinit.py" + gdb.execute("source" + gdbinit_py) +end + +define jstash + call (char*) &(AstNode::dumpJsonTreeGdb($arg0)[0]) +end +document jstash +Verilator: Do json dump of the given nodep and save it in value history (e.g. $1) for later +inspection using jtree. nodep can be actual pointer or adress literal (like 0x55555613dca0). +end + +alias -a js=jstash +alias -a jt=jtree + define dtf call AstNode::dumpTreeFileGdb($arg0, 0) end diff --git a/src/.gdbinit.py b/src/.gdbinit.py new file mode 100644 index 0000000000..40d528800e --- /dev/null +++ b/src/.gdbinit.py @@ -0,0 +1,68 @@ +# pylint: disable=line-too-long,invalid-name,multiple-statements,missing-function-docstring,missing-class-docstring,missing-module-docstring,no-else-return,too-few-public-methods,unused-argument +import os +import sys +import tempfile + +import gdb # pylint: disable=import-error + +# add dir with verilator_jsontree to import path +sys.path.append(os.environ["VERILATOR_ROOT"] + "/bin") + + +def _get_dump(node): + return gdb.execute(f'printf "%s", &(AstNode::dumpJsonTreeGdb({node})[0])', + to_string=True) + + +def _tmpfile(): + return tempfile.NamedTemporaryFile(mode="wt") # write, text mode + + +def _fwrite(file, s): + """write to file and flush buf to make sure that data is written before passing file to jsontree""" + file.write(s) + file.flush() + + +class JsonTreeCmd(gdb.Command): + """Verilator: Pretty print or diff node(s) using jsontree. Node is allowed to be: + * an actual pointer, + * an address literal (like 0x55555613dca0), + * a gdb value (like $1) that stores a dump previously done by the jstash command. + Besides not taking input from file, it works exactly like `verilator_jsontree`: + * passing one node gives you a pretty print, + * passing two nodes gives you a diff, + * flags like -d work like expected. + """ + + def __init__(self): + super().__init__("jtree", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION) + + def _null_check(self, old, new): + err = "" + if old == "\n": err += "old == \n" + if new == "\n": err += "new == " + if err: raise gdb.GdbError(err.strip("\n")) + + def invoke(self, arg_str, from_tty): + import verilator_jsontree as jsontree # pylint: disable=wrong-import-position + # jsontree import may fail so we do it here rather than in outer scope + + # We abuse verilator_jsontree's arg parser to find arguments with nodes + # After finding them, we replace them with proper files + jsontree_args = jsontree.parser.parse_args(gdb.string_to_argv(arg_str)) + self._null_check(jsontree_args.file, jsontree_args.newfile) + with _tmpfile() as oldfile, _tmpfile() as newfile: + if jsontree_args.file: + _fwrite(oldfile, _get_dump(jsontree_args.file)) + jsontree_args.file = oldfile.name + if jsontree_args.newfile: + _fwrite(newfile, _get_dump(jsontree_args.newfile)) + jsontree_args.newfile = newfile.name + try: + jsontree.main(jsontree_args) + except SystemExit: # jsontree prints nice errmsgs on exit(), so we just catch it to suppress cryptic python trace + return + + +JsonTreeCmd() From d5d109db0433952b4953450f06491b8feaa13388 Mon Sep 17 00:00:00 2001 From: Szymon Gizler Date: Tue, 21 Nov 2023 15:30:53 +0100 Subject: [PATCH 3/7] Update CONTRIBUTORS list --- docs/CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 0cf083ae63..154db7aa8e 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -157,6 +157,7 @@ Srinivasan Venkataramanan Stefan Wallentowitz Stephen Henry Steven Hugg +Szymon Gizler Sören Tempel Teng Huang Tim Hutt From 2a3c4cc7de4c923b71b0f6ffd7f959743a93e58e Mon Sep 17 00:00:00 2001 From: Szymon Gizler Date: Tue, 21 Nov 2023 15:38:21 +0100 Subject: [PATCH 4/7] Add docs --- docs/internals.rst | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/docs/internals.rst b/docs/internals.rst index 30a27bb5e9..60cf6b626f 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1696,6 +1696,76 @@ Similarly, the ``NETLIST`` has a list of modules referred to by its ``op1p()`` pointer. +.tree.json Output +----------------- + +``.tree.json``` is alternative dump format (enabled with ``--dump-tree-json``) +that is meant for programatic processing (see e.g. `verilator_jsontree` tool) + +Structure (note: plain output is unformatted): +:: + + { + /* here go atributes that are common to all types of nodes */ + "type": "VAR", + "name": "out_wide", + "addr": "0x91a780", + "file": "t_do_while.v:18:4", /* :: */ + "editNum": 634, + /* here go fields that are specific to VAR nodes: */ + "isSc": false, + "ioDirection": "NONE", + "isConst": false, + "isPullup": false, + "isPulldown": false, + "isUsedClock": false, + "isSigPublic": false, + "isLatched": false, + "isUsedLoopIdx": false, + "noReset": false, + "attrIsolateAssign": false, + "attrFileDescr": false, + "isDpiOpenArray": false, + "isFuncReturn": false, + "isFuncLocal": false, + "attrClocker": "UNKNOWN", + "lifetime": "NONE", + "varType": "VAR", + /* here go lists of child nodes (which use similar structure as their parrent): */ + op1: [ /* ... */ ], + op2: [ /* ... */ ], + op3: [ /* ... */ ], + op4: [ /* ... */ ] + } + +verilator_jsontree +------------------ +``verilator_jsontree`` is tool that pretty prints, filters and diffs ``.tree.json`` files. +The "pretty-print format" looks like this + +Structure: +:: + + ... + MODULE "t" t_do_while.v:16:8 0x558a88b8ae90 timeunit:1ps + op2: + VAR "a" t_do_while.v:17:8 0x558a88b8b370 attrClocker:UNKNOWN, ioDirection:NONE, lifetime:NONE, varType:VAR + op1: + BASICDTYPE "int" t_do_while.v:17:4 0x558a88b8b2a0 keyword:int, range:31:0 + INITIAL "" t_do_while.v:18:4 0x558a88b96420 + ... + +* Order of fields: ``type``, ``name``, ``file``, ``addr``, ``editNum``, , ``op1``, ``op2``, ``op3``, ``op4``. +* For the sake of brevity, names of common fields (type, name, file, addr and editNum) are omitted. +* Unless ``--verbose`` is used, node-specific fields with the value of false are omitted. +* If there are no children in a given ``op*`` array then it is skipped. +* ``name`` is often an empty string, so it is enclosed in quotes to make this case apparent. +* Unwanted fields can be filtered out using the ``-d``` flag, for example ``-d '.file, .editNum'``. +* In diffs, removed/added lines are colored, and replacements of inline fields are signaled with the ``->`` marker. +* Unless ``--verbose`` is used, chunks of unmodified nodes are replaced with a ``...`` in diff + +To use jsontree, ``jq`` (a CLI utility) and ``DeepDiff`` (a Python library) have to be installed. + .tree.dot Output ---------------- @@ -1768,6 +1838,18 @@ To print a node: pnt nodep # or: call dumpTreeGdb(nodep) # aliased to "pnt" in src/.gdbinit +``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utils for working with +JSON dumps. For example + +* ``jstash nodep`` - Do an unformatted JSON dump and save it into value history (e.g. ``$1``) +* ``jtree nodep`` - Do a JSON dump and pretty print it using ``verilator_jsontree``. +* ``jtree $1`` - Pretty print a dump that was previously saved by ``jstash``. +* ``jtree nodep -d '.file, .timeunit'`` - Do a JSON dump, filter out some fields and pretty print it. +* ``jtree 0x55555613dca0`` - Pretty print using address literal (rather than actual pointer). +* ``jtree $1 nodep`` - Diff ``nodep`` against its older dump. + +A detailed description of ``jstash`` and ``jtree`` can be displayed using ``gdb``'s ``help`` command. + When GDB halts, it is useful to understand that the backtrace will commonly show the iterator functions between each invocation of ``visit`` in the backtrace. You will typically see a frame sequence something like: From 0c2b6ec45df3cfa080d8b04d72db7bb0d19b1e45 Mon Sep 17 00:00:00 2001 From: github action Date: Tue, 21 Nov 2023 15:58:51 +0000 Subject: [PATCH 5/7] Apply 'make format' --- src/V3AstNodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 466001a0ed..5c3f2ae45e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2,7 +2,7 @@ //************************************************************************* // DESCRIPTION: Verilator: Ast node structures // - // Code available from: https://verilator.org +// Code available from: https://verilator.org // //************************************************************************* // From 0be18bdc9ce330f6423ced0f0ea424c8aca05c03 Mon Sep 17 00:00:00 2001 From: Szymon Gizler <151655464+sgizler@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:37:15 +0100 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: Krzysztof Bieganski --- docs/internals.rst | 47 ++++++++++------------------------------------ src/.gdbinit | 4 ++-- src/.gdbinit.py | 14 +++++++------- 3 files changed, 19 insertions(+), 46 deletions(-) diff --git a/docs/internals.rst b/docs/internals.rst index 60cf6b626f..03966e0269 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1699,10 +1699,9 @@ Similarly, the ``NETLIST`` has a list of modules referred to by its .tree.json Output ----------------- -``.tree.json``` is alternative dump format (enabled with ``--dump-tree-json``) -that is meant for programatic processing (see e.g. `verilator_jsontree` tool) +``.tree.json``` is an alternative dump format to ``.tree`` that is meant for programmatic processing (e.g. with `astsee _`]). To enable this dump format, use ``--dump-tree-json``) -Structure (note: plain output is unformatted): +Structure: :: { @@ -1738,34 +1737,6 @@ Structure (note: plain output is unformatted): op4: [ /* ... */ ] } -verilator_jsontree ------------------- -``verilator_jsontree`` is tool that pretty prints, filters and diffs ``.tree.json`` files. -The "pretty-print format" looks like this - -Structure: -:: - - ... - MODULE "t" t_do_while.v:16:8 0x558a88b8ae90 timeunit:1ps - op2: - VAR "a" t_do_while.v:17:8 0x558a88b8b370 attrClocker:UNKNOWN, ioDirection:NONE, lifetime:NONE, varType:VAR - op1: - BASICDTYPE "int" t_do_while.v:17:4 0x558a88b8b2a0 keyword:int, range:31:0 - INITIAL "" t_do_while.v:18:4 0x558a88b96420 - ... - -* Order of fields: ``type``, ``name``, ``file``, ``addr``, ``editNum``, , ``op1``, ``op2``, ``op3``, ``op4``. -* For the sake of brevity, names of common fields (type, name, file, addr and editNum) are omitted. -* Unless ``--verbose`` is used, node-specific fields with the value of false are omitted. -* If there are no children in a given ``op*`` array then it is skipped. -* ``name`` is often an empty string, so it is enclosed in quotes to make this case apparent. -* Unwanted fields can be filtered out using the ``-d``` flag, for example ``-d '.file, .editNum'``. -* In diffs, removed/added lines are colored, and replacements of inline fields are signaled with the ``->`` marker. -* Unless ``--verbose`` is used, chunks of unmodified nodes are replaced with a ``...`` in diff - -To use jsontree, ``jq`` (a CLI utility) and ``DeepDiff`` (a Python library) have to be installed. - .tree.dot Output ---------------- @@ -1838,18 +1809,20 @@ To print a node: pnt nodep # or: call dumpTreeGdb(nodep) # aliased to "pnt" in src/.gdbinit -``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utils for working with -JSON dumps. For example +``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utilities for working with +JSON AST dumps. For example -* ``jstash nodep`` - Do an unformatted JSON dump and save it into value history (e.g. ``$1``) -* ``jtree nodep`` - Do a JSON dump and pretty print it using ``verilator_jsontree``. +* ``jstash nodep`` - Perform a JSON AST dump and save it into GDB value history (e.g. ``$1``) +* ``jtree nodep`` - Perform a JSON AST dump and pretty print it using ``astsee_verilator``. * ``jtree $1`` - Pretty print a dump that was previously saved by ``jstash``. -* ``jtree nodep -d '.file, .timeunit'`` - Do a JSON dump, filter out some fields and pretty print it. +* ``jtree nodep -d '.file, .timeunit'`` - Perform a JSON AST dump, filter out some fields and pretty print it. * ``jtree 0x55555613dca0`` - Pretty print using address literal (rather than actual pointer). -* ``jtree $1 nodep`` - Diff ``nodep`` against its older dump. +* ``jtree $1 nodep`` - Diff ``nodep`` against an older dump. A detailed description of ``jstash`` and ``jtree`` can be displayed using ``gdb``'s ``help`` command. +These commands require `astsee _` to be installed. + When GDB halts, it is useful to understand that the backtrace will commonly show the iterator functions between each invocation of ``visit`` in the backtrace. You will typically see a frame sequence something like: diff --git a/src/.gdbinit b/src/.gdbinit index 7c29624a61..c165254ff6 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -33,8 +33,8 @@ define jstash call (char*) &(AstNode::dumpJsonTreeGdb($arg0)[0]) end document jstash -Verilator: Do json dump of the given nodep and save it in value history (e.g. $1) for later -inspection using jtree. nodep can be actual pointer or adress literal (like 0x55555613dca0). +Verilator: Perform a JSON dump of the given AST node and save it in value history (e.g. $1) for later +inspection using jtree. The node can be a pointer identifier or an address literal. end alias -a js=jstash diff --git a/src/.gdbinit.py b/src/.gdbinit.py index 40d528800e..c690e77afa 100644 --- a/src/.gdbinit.py +++ b/src/.gdbinit.py @@ -19,20 +19,20 @@ def _tmpfile(): def _fwrite(file, s): - """write to file and flush buf to make sure that data is written before passing file to jsontree""" + """Write to file and flush buffer before passing the file to astsee""" file.write(s) file.flush() class JsonTreeCmd(gdb.Command): - """Verilator: Pretty print or diff node(s) using jsontree. Node is allowed to be: - * an actual pointer, - * an address literal (like 0x55555613dca0), - * a gdb value (like $1) that stores a dump previously done by the jstash command. - Besides not taking input from file, it works exactly like `verilator_jsontree`: + """Verilator: Pretty print or diff nodes using `astsee`. A node can be: + * an pointer identifier, + * an address literal, + * a GDB value (like `$1`) that stores a dump previously done by the `jstash` command. + Apart from not taking input from a file, it works exactly like `astsee`: * passing one node gives you a pretty print, * passing two nodes gives you a diff, - * flags like -d work like expected. + * for more options see `astsee` readme/help. """ def __init__(self): From 8429caa7c24e8f537077b9114346461db1f163ce Mon Sep 17 00:00:00 2001 From: Szymon Gizler <151655464+sgizler@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:38:15 +0100 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Krzysztof Bieganski --- src/.gdbinit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.gdbinit.py b/src/.gdbinit.py index c690e77afa..c7735a3b3f 100644 --- a/src/.gdbinit.py +++ b/src/.gdbinit.py @@ -48,7 +48,7 @@ def invoke(self, arg_str, from_tty): import verilator_jsontree as jsontree # pylint: disable=wrong-import-position # jsontree import may fail so we do it here rather than in outer scope - # We abuse verilator_jsontree's arg parser to find arguments with nodes + # We hack `astsee_verilator`'s arg parser to find arguments with nodes # After finding them, we replace them with proper files jsontree_args = jsontree.parser.parse_args(gdb.string_to_argv(arg_str)) self._null_check(jsontree_args.file, jsontree_args.newfile)