From eafe9636cf58a74a6a90b6127821b2f4fab8940f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 21 Jun 2026 22:17:36 +0100 Subject: [PATCH] Internals: Dump Ast expression pattern statistics like Dfg (#7818) Remove the expression combination counts from the default stats file, and add a new `--dump-ast-patterns` option, which will dump new `*_ast_patterns_*.txt` files. These contain the expression combinations in a similar S-expression format as Dfg already produces with `--dump-dfg-stats`. These dumps are not produced by just `--stats` as they are fairly expensive to compute. Currently the new option will dump at two points: just before we change to C types via widthMin usage, and just before emit. --- bin/verilator | 1 + docs/guide/exe_verilator.rst | 4 + src/CMakeLists.txt | 3 +- src/Makefile_obj.in | 2 +- src/V3Ast.cpp | 150 +++++++++++++++ src/V3AstNodeExpr.h | 3 + src/V3AstPatterns.h | 34 ++++ src/V3Dfg.cpp | 3 + src/V3DfgDumpPatterns.cpp | 92 --------- src/V3DfgPasses.h | 3 +- src/V3Options.h | 3 + src/V3PatternStats.cpp | 129 +++++++++++++ src/V3Stats.cpp | 20 -- src/Verilator.cpp | 5 + test_regress/t/t_ast_dump_patterns.out | 251 +++++++++++++++++++++++++ test_regress/t/t_ast_dump_patterns.py | 19 ++ test_regress/t/t_ast_dump_patterns.v | 26 +++ 17 files changed, 633 insertions(+), 115 deletions(-) create mode 100644 src/V3AstPatterns.h delete mode 100644 src/V3DfgDumpPatterns.cpp create mode 100644 src/V3PatternStats.cpp create mode 100644 test_regress/t/t_ast_dump_patterns.out create mode 100755 test_regress/t/t_ast_dump_patterns.py create mode 100644 test_regress/t/t_ast_dump_patterns.v diff --git a/bin/verilator b/bin/verilator index 10176f45c..57fd60507 100755 --- a/bin/verilator +++ b/bin/verilator @@ -438,6 +438,7 @@ detailed descriptions of these arguments. --diagnostics-sarif-output Set SARIF diagnostics output file --dpi-hdr-only Only produce the DPI header file --dump- Enable dumping everything in source file + --dump-ast-patterns Enable dumping Ast pattern statistics --dump-defines Show preprocessor defines with -E --dump-dfg Enable dumping DfgGraphs to .dot files --dump-dfg-patterns Enable dumping Dfg pattern statistics diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index c35cd3e57..952500400 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -491,6 +491,10 @@ Summary: Rarely needed - for developer use. Enable all dumping in the given source file at level 3. +.. option:: --dump-ast-patterns + + Rarely needed. Enable dumping AstNodeExpr pattern statistics. + .. option:: --dump-defines With :vlopt:`-E`, suppress normal output, and instead print a list of diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 469456b45..90a0d3ab4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,7 @@ set(HEADERS V3AstNodeExpr.h V3AstNodeOther.h V3AstNodeStmt.h + V3AstPatterns.h V3AstUserAllocator.h V3Begin.h V3Branch.h @@ -250,7 +251,6 @@ set(COMMON_SOURCES V3DfgDataType.cpp V3DfgDecomposition.cpp V3DfgDfgToAst.cpp - V3DfgDumpPatterns.cpp V3DfgOptimizer.cpp V3DfgPasses.cpp V3DfgPeephole.cpp @@ -327,6 +327,7 @@ set(COMMON_SOURCES V3ParseGrammar.cpp V3ParseImp.cpp V3ParseLex.cpp + V3PatternStats.cpp V3PreProc.cpp V3PreShell.cpp V3Premit.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index eb3b1d50a..f5a728063 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -264,7 +264,6 @@ RAW_OBJS_PCH_ASTNOMT = \ V3DfgDataType.o \ V3DfgDecomposition.o \ V3DfgDfgToAst.o \ - V3DfgDumpPatterns.o \ V3DfgOptimizer.o \ V3DfgPasses.o \ V3DfgPeephole.o \ @@ -314,6 +313,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3OrderProcessDomains.o \ V3OrderSerial.o \ V3Param.o \ + V3PatternStats.o \ V3Premit.o \ V3ProtectLib.o \ V3RandSequence.o \ diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 9fe36df38..8c9d6198e 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1745,6 +1745,156 @@ AstNodeDType* AstNode::getCommonClassTypep(AstNode* node1p, AstNode* node2p) { return nullptr; } +//###################################################################### +// Renders the canonical pattern S-expression for a single AstNode + +class VNPatternString final { + std::ostream& m_os; + + std::map m_internedConsts; // Interned constants + std::map m_internedWordWidths; // Interned widths + std::map m_internedWideWidths; // Interned widths + + // Whether to dump the widhtMin as well + const bool m_dumpWidthMin = v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH; + + static std::string toLetters(size_t value, bool lowerCase = false) { + const char base = lowerCase ? 'a' : 'A'; + std::string s; + do { s += static_cast(base + value % 26); } while (value /= 26); + return s; + } + + const std::string& internConst(const AstConst& nodep) { + const auto pair = m_internedConsts.emplace(nodep.num().ascii(false), ""); + if (pair.second) pair.first->second += toLetters(m_internedConsts.size() - 1); + return pair.first->second; + } + + const std::string& internWordWidth(int value) { + const auto pair = m_internedWordWidths.emplace(value, ""); + if (pair.second) pair.first->second += toLetters(m_internedWordWidths.size() - 1, true); + return pair.first->second; + } + + const std::string& internWideWidth(int value) { + const auto pair = m_internedWideWidths.emplace(value, ""); + if (pair.second) pair.first->second += toLetters(m_internedWideWidths.size() - 1); + return pair.first->second; + } + + // True if the node has no operands (e.g. a VarRef or Const) + static bool isLeaf(const AstNode* nodep) { + const VNTypeInfo& typeInfo = VNType::typeInfo(nodep->type()); + for (const VNTypeInfo::OpEn& opType : typeInfo.m_opType) { + if (opType != VNTypeInfo::OP_UNUSED) return false; + } + return true; + } + + // Render operand, return true if not unused + void renderOperand(VNTypeInfo::OpEn opType, const AstNode* const opp, uint32_t depth) { + switch (opType) { + case VNTypeInfo::OP_UNUSED: // + break; + case VNTypeInfo::OP_USED: // + m_os << ' '; + render(opp, depth); + break; + case VNTypeInfo::OP_LIST: + m_os << " ["; + for (const AstNode* nodep = opp; nodep; nodep = nodep->nextp()) { + if (nodep != opp) m_os << ", "; + render(opp, depth); + } + m_os << ']'; + break; + case VNTypeInfo::OP_OPTIONAL: + if (opp) { + m_os << " "; + render(opp, depth); + } else { + m_os << " nil"; + } + break; + } + } + + // Render the node into the stream. + void render(const AstNode* nodep, uint32_t depth) { + if (const AstConst* const constp = VN_CAST(nodep, Const)) { + // Base case 1: constant + if (constp->isZero()) { + m_os << "(CONST ZERO)"; + } else if (constp->isEqAllOnes()) { + m_os << "(CONST ONES)"; + } else { + m_os << "(CONST #" << internConst(*constp) << ')'; + } + } else if (isLeaf(nodep)) { + // Base case 2: expression with no operands (e.g. a variable reference) + m_os << '(' << nodep->typeName() << ')'; + } else if (depth == 0) { + // Base case 3: deep expression + m_os << '_'; + } else { + // Recursively print an S-expression for the expression + m_os << '('; + // Name + m_os << nodep->typeName(); + // Operands + const VNTypeInfo& typeInfo = VNType::typeInfo(nodep->type()); + renderOperand(typeInfo.m_opType[0], nodep->op1p(), depth - 1); + renderOperand(typeInfo.m_opType[1], nodep->op2p(), depth - 1); + renderOperand(typeInfo.m_opType[2], nodep->op3p(), depth - 1); + renderOperand(typeInfo.m_opType[3], nodep->op4p(), depth - 1); + // S-expression end + m_os << ')'; + } + + // Annotate type + m_os << ':'; + const AstNodeDType* const dtypep = nodep->dtypep() ? nodep->dtypep()->skipRefp() : nullptr; + if (!dtypep) { + m_os << '?'; + } else if (dtypep->isCompound() || VN_IS(dtypep, UnpackArrayDType)) { + dtypep->dumpSmall(m_os); + } else { + const int width = nodep->width(); + if (width == 1) { + m_os << '1'; + } else if (width <= VL_QUADSIZE) { + m_os << internWordWidth(width); + } else { + m_os << internWideWidth(width); + } + if (m_dumpWidthMin) { + m_os << '/'; + const int widthMin = nodep->widthMin(); + if (widthMin == 1) { + m_os << '1'; + } else if (widthMin <= VL_QUADSIZE) { + m_os << internWordWidth(widthMin); + } else { + m_os << internWideWidth(widthMin); + } + } + } + } + +public: + VNPatternString(std::ostream& os, const AstNode* nodep, uint32_t depth) + : m_os{os} { + render(nodep, depth); + } +}; + +std::string AstNodeExpr::patternString(uint32_t depth) const { + std::ostringstream oss; + VNPatternString{oss, this, depth}; + return oss.str(); +} + //###################################################################### // VNDeleter diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 91d689227..85c5b0892 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -73,6 +73,9 @@ public: // Returns an error message if widthMin() is not correct otherwise returns nullptr like // broken() virtual const char* widthMismatch() const VL_MT_STABLE { return nullptr; } + + // S-expression inspired dump of node and operands for debugging + std::string patternString(uint32_t depth = 0) const; }; class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr { // Binary expression diff --git a/src/V3AstPatterns.h b/src/V3AstPatterns.h new file mode 100644 index 000000000..451a518d4 --- /dev/null +++ b/src/V3AstPatterns.h @@ -0,0 +1,34 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Dump AstNodeExpr patterns for analysis +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of either the GNU Lesser General Public License Version 3 +// or the Perl Artistic License Version 2.0. +// SPDX-FileCopyrightText: 2003-2026 Wilson Snyder +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTPATTERNS_H_ +#define VERILATOR_V3ASTPATTERNS_H_ + +#include "config_build.h" +#include "verilatedos.h" + +class AstNetlist; + +//============================================================================ + +class V3AstPatterns final { +public: + // Accumulate the patterns in the netlist, and dump the collected + // statistics to '__ast_patterns_.txt'. + static void dumpAll(const AstNetlist* nodep, const std::string& suffix) VL_MT_DISABLED; +}; + +#endif // Guard diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index cb18ba704..fc6be54ce 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -959,6 +959,9 @@ void DfgVertex::unlinkDelete(DfgGraph& dfg) { delete this; } +//###################################################################### +// Renders the canonical pattern S-expression for a single DfgVertex + class DfgPatternString final { std::ostream& m_os; diff --git a/src/V3DfgDumpPatterns.cpp b/src/V3DfgDumpPatterns.cpp deleted file mode 100644 index 18611f180..000000000 --- a/src/V3DfgDumpPatterns.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Implementations of simple passes over DfgGraph -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of either the GNU Lesser General Public License Version 3 -// or the Perl Artistic License Version 2.0. -// SPDX-FileCopyrightText: 2003-2026 Wilson Snyder -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* - -#ifndef VERILATOR_V3DFGPATTERNSTATS_H_ -#define VERILATOR_V3DFGPATTERNSTATS_H_ - -#include "V3Dfg.h" -#include "V3DfgPasses.h" -#include "V3File.h" - -#include - -class V3DfgPatternStats final { - static constexpr uint32_t MIN_PATTERN_DEPTH = 1; - static constexpr uint32_t MAX_PATTERN_DEPTH = 4; - - // Maps from pattern to the number of times it appears, for each pattern depth - std::vector> m_patterCounts{MAX_PATTERN_DEPTH + 1}; - - void dump(std::ostream& os) { - using Line = std::pair; - for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) { - os << "DFG patterns with depth " << i << '\n'; - - // Pick up pattern accumulators with given depth - auto& patternCounts = m_patterCounts[i]; - - // Remove patterns also present at shallower depths - for (uint32_t j = MIN_PATTERN_DEPTH; j < i; ++j) { - for (const auto& pair : m_patterCounts[j]) patternCounts.erase(pair.first); - } - - // Sort patterns, first by descending frequency, then lexically - std::vector lines; - lines.reserve(patternCounts.size()); - for (const auto& pair : patternCounts) lines.emplace_back(pair); - std::sort(lines.begin(), lines.end(), [](const Line& a, const Line& b) { - if (a.second != b.second) return a.second > b.second; - return a.first < b.first; - }); - - // Print each pattern - for (const auto& line : lines) { - os << ' ' << std::setw(12) << std::right << line.second; - os << ' ' << std::left << line.first << '\n'; - } - - // Trailing new-line to separate sections - os << '\n'; - } - } - -public: - V3DfgPatternStats() = default; - ~V3DfgPatternStats() { - // File to dump to - const std::string filename - = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__dfg_patterns.txt"; - // Open, write, close - const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write file: " << filename); - dump(*ofp); - } - - void accumulate(const DfgGraph& dfg) { - dfg.forEachVertex([&](const DfgVertex& vtx) { - for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) { - m_patterCounts[i][vtx.patternString(i)] += 1; - } - }); - } -}; - -void V3DfgPasses::dumpPatterns(const std::vector>& graphs) { - V3DfgPatternStats patternStats; - for (auto& cp : graphs) patternStats.accumulate(*cp); -} - -#endif diff --git a/src/V3DfgPasses.h b/src/V3DfgPasses.h index 2984c6bd7..d0d8e62d8 100644 --- a/src/V3DfgPasses.h +++ b/src/V3DfgPasses.h @@ -67,7 +67,8 @@ void regularize(DfgGraph&, V3DfgRegularizeContext&) VL_MT_DISABLED; // Convert DfgGraph back into Ast, and insert converted graph back into the Ast. void dfgToAst(DfgGraph&, V3DfgContext&) VL_MT_DISABLED; // Dump the patterns in the given graphs -void dumpPatterns(const std::vector>&) VL_MT_DISABLED; +void dumpPatterns(const std::vector>&, + const std::string& suffix = "") VL_MT_DISABLED; //=========================================================================== // Intermediate/internal operations diff --git a/src/V3Options.h b/src/V3Options.h index 6894f8312..f3dd59863 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -552,6 +552,9 @@ public: bool decorationNodes() const VL_MT_SAFE { return m_decorationNodes; } bool diagnosticsSarif() const VL_MT_SAFE { return m_diagnosticsSarif; } bool dpiHdrOnly() const { return m_dpiHdrOnly; } + bool dumpAstPatterns() const { + return m_dumpLevel.count("ast-patterns") && m_dumpLevel.at("ast-patterns"); + } bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); } bool dumpDfgPatterns() const { return m_dumpLevel.count("dfg-patterns") && m_dumpLevel.at("dfg-patterns"); diff --git a/src/V3PatternStats.cpp b/src/V3PatternStats.cpp new file mode 100644 index 000000000..8d4d5a63d --- /dev/null +++ b/src/V3PatternStats.cpp @@ -0,0 +1,129 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Dump data structure pattern frequencies for analysis +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of either the GNU Lesser General Public License Version 3 +// or the Perl Artistic License Version 2.0. +// SPDX-FileCopyrightText: 2003-2026 Wilson Snyder +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "V3PchAstNoMT.h" + +#include "V3Ast.h" +#include "V3AstPatterns.h" +#include "V3Dfg.h" +#include "V3DfgPasses.h" +#include "V3File.h" + +#include +#include +#include + +VL_DEFINE_DEBUG_FUNCTIONS; + +//============================================================================ +// Accumulates and dumps the pattern statistics + +class V3PatternStats VL_NOT_FINAL { +public: + static constexpr uint32_t MIN_PATTERN_DEPTH = 1; + static constexpr uint32_t MAX_PATTERN_DEPTH = 4; + +private: + const std::string m_what; // Description of what is being dumped + // Maps from pattern to the number of times it appears, for each pattern depth + std::vector> m_patternCounts{MAX_PATTERN_DEPTH + 1}; + + void dump(std::ostream& os) { + using Line = std::pair; + for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) { + os << m_what << " patterns with depth " << i << '\n'; + + // Pick up pattern accumulators with given depth + auto& patternCounts = m_patternCounts[i]; + + // Remove patterns also present at shallower depths + for (uint32_t j = MIN_PATTERN_DEPTH; j < i; ++j) { + for (const auto& pair : m_patternCounts[j]) patternCounts.erase(pair.first); + } + + // Sort patterns, first by descending frequency, then lexically + std::vector lines; + lines.reserve(patternCounts.size()); + for (const auto& pair : patternCounts) lines.emplace_back(pair); + std::sort(lines.begin(), lines.end(), [](const Line& a, const Line& b) { + if (a.second != b.second) return a.second > b.second; + return a.first < b.first; + }); + + // Print each pattern + for (const auto& line : lines) { + os << ' ' << std::setw(12) << std::right << line.second; + os << ' ' << std::left << line.first << '\n'; + } + + // Trailing new-line to separate sections + os << '\n'; + } + } + +public: + V3PatternStats(const std::string& what) + : m_what{what} {} + ~V3PatternStats() = default; + + void accumulate(const std::string& pattern, uint32_t depth) { + m_patternCounts[depth][pattern] += 1; + } + + void dumpToFile(const std::string& filename) { + // Open, write, close + const std::unique_ptr ofp{V3File::new_ofstream(filename)}; + if (ofp->fail()) v3fatal("Can't write file: " << filename); + dump(*ofp); + } +}; + +//============================================================================ +// V3AstPatterns top level + +void V3AstPatterns::dumpAll(const AstNetlist* nodep, const std::string& suffix) { + UINFO(2, __FUNCTION__ << ":"); + V3PatternStats patternStats{"AST"}; + nodep->foreach([&](const AstNodeExpr* exprp) { + for (uint32_t i = V3PatternStats::MIN_PATTERN_DEPTH; + i <= V3PatternStats::MAX_PATTERN_DEPTH; ++i) { + patternStats.accumulate(exprp->patternString(i), i); + } + }); + const std::string fileName = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + + "__ast_patterns_" + suffix + ".txt"; + patternStats.dumpToFile(fileName); + V3Global::dumpCheckGlobalTree("astpatterns", 0, false, false); +} + +//============================================================================ +// V3DfgPasses top level + +void V3DfgPasses::dumpPatterns(const std::vector>& graphs, + const std::string& suffix) { + V3PatternStats patternStats{"DFG"}; + for (auto& cp : graphs) { + cp->forEachVertex([&](const DfgVertex& vtx) { + for (uint32_t i = V3PatternStats::MIN_PATTERN_DEPTH; + i <= V3PatternStats::MAX_PATTERN_DEPTH; ++i) { + patternStats.accumulate(vtx.patternString(i), i); + } + }); + } + const std::string fileName = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + + "__dfg_patterns" + suffix + ".txt"; + patternStats.dumpToFile(fileName); +} diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index e1cd949ae..8abe9254b 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -35,15 +35,12 @@ class StatsVisitor final : public VNVisitorConst { struct Counters final { // Nodes of given type std::array m_statTypeCount{}; - // Nodes of given type with given type immediate child - std::array, VNType::NUM_TYPES()> m_statAbove{}; // Prediction of given type std::array m_statPred{}; }; // STATE const bool m_fastOnly; // When true, consider only fast functions - const AstNodeExpr* m_parentExprp = nullptr; // Parent expression Counters m_counters; // The actual counts we will display Counters m_dumpster; // Alternate buffer to make discarding parts of the tree easier Counters* m_accump; // The currently active accumulator @@ -75,14 +72,6 @@ class StatsVisitor final : public VNVisitorConst { countThenIterateChildren(nodep); } - void visit(AstNodeExpr* nodep) override { - // Count expression combinations - if (m_parentExprp) ++m_accump->m_statAbove[m_parentExprp->type()][nodep->type()]; - VL_RESTORER(m_parentExprp); - m_parentExprp = nodep; - countThenIterateChildren(nodep); - } - void visit(AstNodeIf* nodep) override { // Track prediction ++m_accump->m_statPred[nodep->branchPred()]; @@ -148,15 +137,6 @@ public: } } - // Expression combinations - for (size_t t1 = 0; t1 < VNType::NUM_TYPES(); ++t1) { - for (size_t t2 = 0; t2 < VNType::NUM_TYPES(); ++t2) { - if (const uint64_t c = m_counters.m_statAbove[t1][t2]) { - addStat("Expr combination, " + typeName(t1) + " over " + typeName(t2), c); - } - } - } - // Branch predictions for (int t = 0; t < VBranchPred::_ENUM_END; ++t) { if (const uint64_t c = m_counters.m_statPred[t]) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 21fe83b5e..b1f0a9af0 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -22,6 +22,7 @@ #include "V3AssertNfa.h" #include "V3AssertPre.h" #include "V3Ast.h" +#include "V3AstPatterns.h" #include "V3Begin.h" #include "V3Branch.h" #include "V3Broken.h" @@ -541,6 +542,8 @@ static void process() { V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyAll(v3Global.rootp()); + if (v3Global.opt.dumpAstPatterns()) V3AstPatterns::dumpAll(v3Global.rootp(), "prec"); + // Here down, widthMin() is the Verilog width, and width() is the C++ width // Bits between widthMin() and width() are irrelevant, but may be non-zero. v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH); @@ -635,6 +638,8 @@ static void process() { } } + if (v3Global.opt.dumpAstPatterns()) V3AstPatterns::dumpAll(v3Global.rootp(), "emit"); + // Output the text if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() && !v3Global.opt.dpiHdrOnly()) { diff --git a/test_regress/t/t_ast_dump_patterns.out b/test_regress/t/t_ast_dump_patterns.out new file mode 100644 index 000000000..4d2ea4bb2 --- /dev/null +++ b/test_regress/t/t_ast_dump_patterns.out @@ -0,0 +1,251 @@ +AST patterns with depth 1 + 126 (CONST #A):a/a + 54 (VARREF):a/b + 36 (CCAST (VARREF):a/b):a/b + 34 (AND (CONST #A):a/a _:a/1):a/1 + 29 (VARREF):a/a + 23 (CONST ZERO):a/a + 21 (VARREF):(w64)u[1:0] + 20 (CCAST _:a/1):a/1 + 18 (AND (CONST #A):a/a _:a/a):a/a + 18 (SHIFTR _:a/b (CONST #A):a/a):a/1 + 17 (VARREF):a/1 + 15 (SHIFTL _:a/1 (CONST #A):a/a):a/a + 14 (NEGATE _:a/1):a/a + 12 (AND (CONST #A):a/a _:a/b):a/b + 12 (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b + 12 (NOT _:a/b):a/b + 12 (VARREF):(w64)u[0:0] + 11 (OR _:a/a _:a/b):a/c + 9 (OR _:a/a _:a/1):a/b + 9 (VARREF):(G/str) + 8 (CCAST _:a/a):a/a + 8 (CCAST _:a/a):b/b + 8 (CRESET):a/a + 8 (NOT _:a/a):a/a + 8 (REDXOR _:a/b):a/1 + 7 (SHIFTL _:a/b (CONST #A):a/a):a/a + 6 (AND _:a/b _:a/b):a/b + 6 (REDXOR _:a/a):b/1 + 5 (CCAST _:a/a):b/1 + 5 (OR _:a/a _:a/a):a/a + 4 (ADD _:a/a (VARREF):a/a):a/a + 4 (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):a/a):b/b + 4 (CCAST (CONST #A):a/a):a/a + 4 (CCAST (VARREF):a/1):a/1 + 4 (CCAST _:a/1):b/1 + 4 (CONST #A):(G/str) + 4 (CONST #A):a/1 + 4 (NEGATE _:a/1):a/b + 4 (SHIFTL _:a/a (CONST #A):b/b):a/a + 3 (AND (VARREF):a/a (CONST #A):b/b):a/a + 3 (CONST ZERO):a/1 + 3 (CRESET):(w64)u[0:0] + 3 (CRESET):(w64)u[1:0] + 3 (NOT _:a/1):a/1 + 3 (OR (CONST #A):a/a _:a/a):a/a + 2 (CCALL [(VARREF):(w64)u[0:0], (VARREF):(w64)u[0:0]]):a/a + 2 (CCALL [(VARREF):(w64)u[0:0]]):a/1 + 2 (CCALL [(VARREF):(w64)u[1:0], (VARREF):(w64)u[1:0]]):a/a + 2 (CCALL [(VARREF):(w64)u[1:0]]):a/1 + 2 (CCALL []):a/1 + 2 (CRESET):(G/str) + 2 (GT (CONST #A):a/a (VARREF):a/a):a/1 + 2 (LT (CONST #A):a/a (VARREF):a/a):a/1 + 2 (NEQ _:a/b _:a/b):a/1 + 2 (OR _:a/a _:a/a):a/b + 2 (REDXOR (VARREF):a/b):a/1 + 2 (REDXOR _:a/a):a/1 + 2 (REDXOR _:a/b):c/1 + 2 (SHIFTR _:a/a (CONST #A):b/b):a/a + 1 (ARRAYSEL (VARREF):(w64)u[0:0] (VARREF):a/a):b/b + 1 (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b + 1 (ARRAYSEL (VARREF):(w64)u[1:0] (VARREF):a/a):b/b + 1 (CCAST _:a/1):b/b + 1 (CCAST _:a/b):a/b + 1 (CCAST _:a/b):c/c + 1 (CRESET):1/1 + 1 (NEQ _:a/b _:a/b):a/c + 1 (VARREF):1/1 + +AST patterns with depth 2 + 18 (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1 + 18 (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1 + 18 (SHIFTR (CCAST (VARREF):a/b):a/b (CONST #A):a/a):a/1 + 14 (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a + 12 (NOT (CCAST (VARREF):a/b):a/b):a/b + 10 (NEGATE (CCAST _:a/1):a/1):a/a + 8 (CCAST (CCAST _:a/a):a/a):b/b + 8 (CCAST (NOT _:a/a):a/a):a/a + 8 (NOT (NEGATE _:a/1):a/a):a/a + 8 (OR (AND (CONST #A):a/a _:a/a):a/a (AND (CONST #B):a/a _:a/1):a/1):a/b + 8 (REDXOR (AND (CONST #A):a/a _:a/b):a/b):a/1 + 6 (AND (CONST #A):a/a (AND _:a/b _:a/b):a/b):a/b + 6 (AND (NOT _:a/b):a/b (NOT _:a/b):a/b):a/b + 6 (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c + 6 (SHIFTL (OR _:a/a _:a/b):a/c (CONST #A):a/a):a/a + 5 (AND (CONST #A):a/a (CCAST _:b/b):a/1):a/1 + 4 (ADD (CCAST (CONST #A):a/a):a/a (VARREF):a/a):a/a + 4 (AND (CONST #A):a/a (NEGATE _:a/1):a/b):a/b + 4 (AND (CONST #A):a/a (REDXOR _:a/b):a/1):a/1 + 4 (AND (CONST #A):a/a (REDXOR _:b/b):a/1):a/1 + 4 (CCAST (CCAST _:a/1):a/1):b/1 + 4 (NEGATE (CCAST _:a/1):a/1):a/b + 4 (NEGATE (CCAST _:a/1):b/1):b/b + 4 (REDXOR (NEGATE _:a/1):a/a):b/1 + 4 (SHIFTL (CCAST _:a/a):b/b (CONST #A):a/a):b/b + 4 (SHIFTL (REDXOR _:a/b):a/1 (CONST #A):a/a):a/a + 3 (AND (CONST #A):a/a (NOT _:a/1):a/1):a/1 + 3 (OR (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):b/b):a/a):a/a + 2 (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):b/b):a/a):a/a + 2 (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):b/b):a/a):a/a + 2 (AND (CONST #A):a/a (OR _:a/a _:a/a):a/b):a/b + 2 (CCAST (SHIFTR _:a/a (CONST #A):b/b):a/a):b/1 + 2 (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1 + 2 (NOT (CCAST _:a/1):a/1):a/1 + 2 (OR (OR _:a/a _:a/a):a/a (OR _:a/a _:a/b):a/c):a/d + 2 (OR (SHIFTL _:a/a (CONST #A):b/b):a/a (CCAST _:b/b):a/a):a/a + 2 (OR (SHIFTL _:a/a (CONST #A):b/b):a/a (CCAST _:b/b):a/a):a/c + 2 (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (OR _:a/a _:a/1):a/c):a/d + 2 (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (SHIFTL _:a/b (CONST #B):a/a):a/a):a/a + 2 (REDXOR (AND (CONST #A):a/a _:a/b):a/b):c/1 + 2 (REDXOR (NEGATE _:a/1):a/a):a/1 + 2 (REDXOR (OR _:a/a _:a/a):a/a):b/1 + 2 (SHIFTL (CCAST (VARREF):a/1):a/1 (CONST #A):a/a):a/a + 2 (SHIFTL (REDXOR (VARREF):a/b):a/1 (CONST #A):a/a):a/a + 2 (SHIFTL (REDXOR _:a/a):a/1 (CONST #A):a/a):a/a + 2 (SHIFTL (REDXOR _:a/a):b/1 (CONST #A):b/b):b/b + 2 (SHIFTL (REDXOR _:a/b):c/1 (CONST #A):c/c):c/c + 2 (SHIFTR (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b (CONST #A):a/a):b/b + 1 (CCAST (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):a/a):b/b):a/1 + 1 (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b):a/1 + 1 (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b):a/1 + 1 (CCAST (CCALL [(VARREF):(w64)u[0:0]]):a/1):a/1 + 1 (CCAST (CCALL [(VARREF):(w64)u[1:0]]):a/1):a/1 + 1 (CCAST (CCAST (VARREF):a/1):a/1):b/b + 1 (CCAST (CCAST _:a/b):a/b):c/c + 1 (CCAST (OR _:a/a _:a/b):a/c):a/c + 1 (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/c + 1 (NOT (CCAST (VARREF):a/1):a/1):a/1 + 1 (OR (AND (CONST #A):a/a _:a/a):a/a (CCAST _:b/1):a/a):a/a + 1 (OR (SHIFTL _:a/1 (CONST #A):a/a):a/a (NEQ _:a/b _:a/b):a/1):a/c + 1 (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (OR _:a/a _:a/1):a/b):a/c + 1 (SHIFTL (NEQ _:a/b _:a/b):a/1 (CONST #A):a/a):a/a + 1 (SHIFTL (NEQ _:a/b _:a/b):a/c (CONST #A):a/a):a/a + +AST patterns with depth 3 + 18 (AND (CONST #A):a/a (SHIFTR (CCAST (VARREF):a/b):a/b (CONST #A):a/a):a/1):a/1 + 18 (CCAST (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1):a/1 + 10 (NEGATE (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):a/a + 8 (CCAST (CCAST (NOT _:a/a):a/a):a/a):b/b + 8 (CCAST (NOT (NEGATE _:a/1):a/a):a/a):a/a + 8 (NOT (NEGATE (CCAST _:a/1):a/1):a/a):a/a + 6 (AND (CONST #A):a/a (AND (NOT _:a/b):a/b (NOT _:a/b):a/b):a/b):a/b + 6 (AND (NOT (CCAST (VARREF):a/b):a/b):a/b (NOT (CCAST (VARREF):a/b):a/b):a/b):a/b + 6 (OR (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a _:a/a):a/a (AND (CONST #C):a/a _:a/1):a/1):a/b):a/c + 6 (SHIFTL (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c (CONST #B):a/a):a/a + 4 (AND (CONST #A):a/a (NEGATE (CCAST _:a/1):a/1):a/b):a/b + 4 (AND (CONST #A):a/a (REDXOR (AND (CONST #B):a/a _:a/b):a/b):a/1):a/1 + 4 (AND (CONST #A):a/a (SHIFTL (REDXOR _:a/b):a/1 (CONST #B):a/a):a/a):a/a + 4 (CCAST (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):b/1 + 4 (NEGATE (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):a/b + 4 (NEGATE (CCAST (CCAST _:a/1):a/1):b/1):b/b + 4 (OR (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR _:a/b):a/1):a/1):a/c + 4 (OR (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR _:b/b):a/1):a/1):a/c + 4 (REDXOR (AND (CONST #A):a/a (AND _:a/b _:a/b):a/b):a/b):a/1 + 4 (REDXOR (AND (CONST #A):a/a (NEGATE _:a/1):a/b):a/b):a/1 + 4 (REDXOR (NEGATE (CCAST _:a/1):b/1):b/b):a/1 + 4 (SHIFTL (CCAST (CCAST _:a/a):a/a):b/b (CONST #A):a/a):b/b + 4 (SHIFTL (REDXOR (AND (CONST #A):a/a _:a/b):a/b):a/1 (CONST #B):a/a):a/a + 2 (AND (CONST #A):a/a (NOT (CCAST _:a/1):a/1):a/1):a/1 + 2 (AND (CONST #A):a/a (OR (SHIFTL _:a/a (CONST #B):b/b):a/a (CCAST _:b/b):a/a):a/c):a/c + 2 (AND (CONST #A):a/a (REDXOR (NEGATE _:b/1):b/b):a/1):a/1 + 2 (AND (CONST #A):a/a (REDXOR (OR _:b/b _:b/b):b/b):a/1):a/1 + 2 (AND (CONST #A):a/a (SHIFTL (CCAST (VARREF):a/1):a/1 (CONST #B):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR (VARREF):a/b):a/1 (CONST #B):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR _:a/a):a/1 (CONST #B):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR _:b/b):a/1 (CONST #B):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR _:b/c):a/1 (CONST #B):a/a):a/a):a/a + 2 (CCAST (SHIFTR (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b (CONST #A):a/a):b/b):a/1 + 2 (OR (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (SHIFTL _:a/b (CONST #B):a/a):a/a):a/a (OR (SHIFTL _:a/b (CONST #C):a/a):a/a (OR _:a/a _:a/1):a/c):a/d):a/e + 2 (OR (SHIFTL (CCAST _:a/a):b/b (CONST #A):a/a):b/b (CCAST (CCAST _:a/a):a/a):b/b):b/b + 2 (OR (SHIFTL (CCAST _:a/a):b/b (CONST #A):a/a):b/b (CCAST (CCAST _:a/a):a/a):b/b):b/c + 2 (OR (SHIFTL (OR _:a/a _:a/b):a/c (CONST #A):a/a):a/a (OR (AND (CONST #A):a/a _:a/a):a/a (AND (CONST #B):a/a _:a/1):a/1):a/b):a/d + 2 (OR (SHIFTL (OR _:a/a _:a/b):a/c (CONST #A):a/a):a/a (SHIFTL (OR _:a/a _:a/b):a/c (CONST #B):a/a):a/a):a/a + 2 (REDXOR (AND (CONST #A):a/a (OR _:a/a _:a/a):a/b):a/b):c/1 + 2 (REDXOR (NEGATE (CCAST _:a/1):a/1):a/a):a/1 + 2 (REDXOR (OR (SHIFTL _:a/a (CONST #A):b/b):a/a (CCAST _:b/b):a/a):a/a):b/1 + 2 (SHIFTL (REDXOR (AND (CONST #A):a/a _:a/b):a/b):c/1 (CONST #B):c/c):c/c + 2 (SHIFTL (REDXOR (NEGATE _:a/1):a/a):a/1 (CONST #A):a/a):a/a + 2 (SHIFTL (REDXOR (NEGATE _:a/1):a/a):b/1 (CONST #A):b/b):b/b + 1 (AND (CONST #A):a/a (CCAST (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST #A):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (CCAST (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (CCAST (SHIFTR _:b/b (CONST #A):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (CCAST (SHIFTR _:b/b (CONST #B):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (NOT (CCAST (VARREF):a/1):a/1):a/1):a/1 + 1 (CCAST (CCAST (OR _:a/a _:a/b):a/c):a/c):d/d + 1 (CCAST (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (OR _:a/a _:a/1):a/b):a/c):a/c + 1 (NOT (CCAST (CCALL [(VARREF):(w64)u[0:0]]):a/1):a/1):a/1 + 1 (NOT (CCAST (CCALL [(VARREF):(w64)u[1:0]]):a/1):a/1):a/1 + 1 (OR (AND (CONST #A):a/a (ARRAYSEL (VARREF):(w64)u[0:0] (CONST ZERO):b/b):a/a):a/a (CCAST (CCAST (VARREF):b/1):b/1):a/a):a/a + 1 (OR (SHIFTL (NEQ _:a/b _:a/b):a/1 (CONST #A):a/a):a/a (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1):a/c + 1 (OR (SHIFTL (NEQ _:a/b _:a/b):a/c (CONST #A):a/a):a/a (OR (SHIFTL _:a/1 (CONST #B):a/a):a/a (NEQ _:a/b _:a/b):a/1):a/c):a/b + 1 (SHIFTL (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1 (CONST #A):a/a):a/a + 1 (SHIFTL (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/c (CONST #A):a/a):a/a + +AST patterns with depth 4 + 18 (CCAST (AND (CONST #A):a/a (SHIFTR (CCAST (VARREF):a/b):a/b (CONST #A):a/a):a/1):a/1):a/1 + 10 (NEGATE (CCAST (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1):a/1):a/a + 8 (CCAST (CCAST (NOT (NEGATE _:a/1):a/a):a/a):a/a):b/b + 8 (CCAST (NOT (NEGATE (CCAST _:a/1):a/1):a/a):a/a):a/a + 8 (NOT (NEGATE (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):a/a):a/a + 6 (AND (CONST #A):a/a (AND (NOT (CCAST (VARREF):a/b):a/b):a/b (NOT (CCAST (VARREF):a/b):a/b):a/b):a/b):a/b + 4 (AND (CONST #A):a/a (NEGATE (CCAST (AND (CONST #B):a/a _:a/1):a/1):a/1):a/b):a/b + 4 (AND (CONST #A):a/a (SHIFTL (REDXOR (AND (CONST #B):a/a _:a/b):a/b):a/1 (CONST #C):a/a):a/a):a/a + 4 (CCAST (CCAST (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1):a/1):c/1 + 4 (NEGATE (CCAST (AND (CONST #A):a/a (SHIFTR _:a/b (CONST #A):a/a):a/1):a/1):a/1):a/c + 4 (NEGATE (CCAST (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):b/1):b/b + 4 (REDXOR (AND (CONST #A):a/a (AND (NOT _:a/b):a/b (NOT _:a/b):a/b):a/b):a/b):a/1 + 4 (REDXOR (AND (CONST #A):a/a (NEGATE (CCAST _:a/1):a/1):a/b):a/b):a/1 + 4 (REDXOR (NEGATE (CCAST (CCAST _:a/1):a/1):b/1):b/b):a/1 + 4 (SHIFTL (CCAST (CCAST (NOT _:a/a):a/a):a/a):b/b (CONST #A):a/a):b/b + 4 (SHIFTL (OR (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a _:a/a):a/a (AND (CONST #C):a/a _:a/1):a/1):a/b):a/c (CONST #D):a/a):a/a + 2 (AND (CONST #A):a/a (OR (SHIFTL (CCAST _:b/b):a/a (CONST #B):b/b):a/a (CCAST (CCAST _:b/b):b/b):a/a):a/c):a/c + 2 (AND (CONST #A):a/a (REDXOR (AND (CONST #B):a/a (AND _:a/b _:a/b):a/b):a/b):a/1):a/1 + 2 (AND (CONST #A):a/a (REDXOR (AND (CONST #B):a/a (NEGATE _:a/1):a/b):a/b):a/1):a/1 + 2 (AND (CONST #A):a/a (REDXOR (NEGATE (CCAST _:a/1):b/1):b/b):a/1):a/1 + 2 (AND (CONST #A):a/a (REDXOR (OR (SHIFTL _:b/b (CONST #B):a/a):b/b (CCAST _:a/a):b/b):b/b):a/1):a/1 + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR (AND (CONST #B):b/b _:b/c):b/c):a/1 (CONST #C):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR (NEGATE _:a/1):a/a):a/1 (CONST #B):a/a):a/a):a/a + 2 (AND (CONST #A):a/a (SHIFTL (REDXOR (NEGATE _:b/1):b/b):a/1 (CONST #B):a/a):a/a):a/a + 2 (OR (AND (CONST #A):a/a (SHIFTL (CCAST (VARREF):a/1):a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a (SHIFTL _:a/1 (CONST #C):a/a):a/a):a/a (AND (CONST #C):a/a (REDXOR _:a/b):a/1):a/1):a/c):a/d + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR (VARREF):a/b):a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a (SHIFTL _:a/1 (CONST #C):a/a):a/a):a/a (AND (CONST #C):a/a (REDXOR _:a/b):a/1):a/1):a/c):a/d + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR _:a/a):a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a (SHIFTL _:a/1 (CONST #C):a/a):a/a):a/a (AND (CONST #C):a/a (REDXOR _:b/b):a/1):a/1):a/c):a/d + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR _:a/b):a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR (AND (CONST #C):a/a _:a/b):a/b):a/1):a/1):a/c + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR _:a/b):a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR (AND (CONST #C):a/a _:a/c):a/c):a/1):a/1):a/d + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR _:b/b):a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR (OR _:b/b _:b/b):b/b):a/1):a/1):a/c + 2 (OR (AND (CONST #A):a/a (SHIFTL (REDXOR _:b/c):a/1 (CONST #B):a/a):a/a):a/a (AND (CONST #B):a/a (REDXOR (NEGATE _:b/1):b/b):a/1):a/1):a/d + 2 (OR (OR (SHIFTL (OR _:a/a _:a/b):a/c (CONST #A):a/a):a/a (SHIFTL (OR _:a/a _:a/b):a/c (CONST #B):a/a):a/a):a/a (OR (SHIFTL (OR _:a/a _:a/b):a/c (CONST #C):a/a):a/a (OR (AND (CONST #C):a/a _:a/a):a/a (AND (CONST #D):a/a _:a/1):a/1):a/b):a/d):a/e + 2 (OR (SHIFTL (CCAST (CCAST _:a/a):a/a):b/b (CONST #A):a/a):b/b (CCAST (CCAST (NOT _:a/a):a/a):a/a):b/b):b/b + 2 (OR (SHIFTL (CCAST (CCAST _:a/a):a/a):b/b (CONST #A):a/a):b/b (CCAST (CCAST (NOT _:a/a):a/a):a/a):b/b):b/c + 2 (OR (SHIFTL (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c (CONST #B):a/a):a/a (OR (AND (CONST #B):a/a (SHIFTL _:a/1 (CONST #C):a/a):a/a):a/a (AND (CONST #C):a/a (REDXOR _:d/d):a/1):a/1):a/b):a/e + 2 (OR (SHIFTL (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c (CONST #B):a/a):a/a (SHIFTL (OR (AND (CONST #A):a/a _:a/a):a/a (OR _:a/a _:a/1):a/b):a/c (CONST #C):a/a):a/a):a/a + 2 (REDXOR (AND (CONST #A):a/a (OR (SHIFTL _:a/a (CONST #B):b/b):a/a (CCAST _:b/b):a/a):a/c):a/c):b/1 + 2 (REDXOR (NEGATE (CCAST (AND (CONST #A):a/a _:a/1):a/1):a/1):a/a):a/1 + 2 (REDXOR (OR (SHIFTL (CCAST _:a/a):b/b (CONST #A):a/a):b/b (CCAST (CCAST _:a/a):a/a):b/b):b/b):a/1 + 2 (SHIFTL (OR (AND (CONST #A):a/a (SHIFTL _:a/1 (CONST #B):a/a):a/a):a/a (OR (AND (CONST #B):a/a _:a/a):a/a (AND (CONST #C):a/a _:a/1):a/1):a/b):a/c (CONST #B):a/a):a/a + 2 (SHIFTL (REDXOR (AND (CONST #A):a/a (AND _:a/b _:a/b):a/b):a/b):a/1 (CONST #B):a/a):a/a + 2 (SHIFTL (REDXOR (AND (CONST #A):a/a (NEGATE _:a/1):a/b):a/b):a/1 (CONST #B):a/a):a/a + 2 (SHIFTL (REDXOR (AND (CONST #A):a/a (OR _:a/a _:a/a):a/b):a/b):c/1 (CONST #B):c/c):c/c + 2 (SHIFTL (REDXOR (NEGATE (CCAST _:a/1):a/1):a/a):a/1 (CONST #A):a/a):a/a + 2 (SHIFTL (REDXOR (NEGATE (CCAST _:a/1):b/1):b/b):a/1 (CONST #A):a/a):a/a + 1 (AND (CONST #A):a/a (CCAST (SHIFTR (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b (CONST #A):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (CCAST (SHIFTR (ARRAYSEL (VARREF):(w64)u[1:0] (CONST ZERO):a/a):b/b (CONST #B):a/a):b/b):a/1):a/1 + 1 (AND (CONST #A):a/a (NOT (CCAST (CCALL [(VARREF):(w64)u[0:0]]):a/1):a/1):a/1):a/1 + 1 (AND (CONST #A):a/a (NOT (CCAST (CCALL [(VARREF):(w64)u[1:0]]):a/1):a/1):a/1):a/1 + 1 (CCAST (CCAST (OR (SHIFTL _:a/b (CONST #A):a/a):a/a (OR _:a/a _:a/1):a/b):a/c):a/c):d/d + 1 (CCAST (OR (SHIFTL (NEQ _:a/b _:a/b):a/c (CONST #A):a/a):a/a (OR (SHIFTL _:a/1 (CONST #B):a/a):a/a (NEQ _:a/b _:a/b):a/1):a/c):a/b):a/b + 1 (OR (SHIFTL (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1 (CONST #A):a/a):a/a (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1):a/c + 1 (OR (SHIFTL (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/c (CONST #A):a/a):a/a (OR (SHIFTL (NEQ _:a/b _:a/b):a/1 (CONST #B):a/a):a/a (NEQ (CCAST (VARREF):a/b):a/b (CCAST (VARREF):a/b):a/b):a/1):a/c):a/b + diff --git a/test_regress/t/t_ast_dump_patterns.py b/test_regress/t/t_ast_dump_patterns.py new file mode 100755 index 000000000..d1bf14b33 --- /dev/null +++ b/test_regress/t/t_ast_dump_patterns.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.compile(verilator_flags2=["--dump-ast-patterns", "--no-skip-identical"]) + +test.files_identical(test.obj_dir + "/" + test.vm_prefix + "__ast_patterns_emit.txt", + test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_ast_dump_patterns.v b/test_regress/t/t_ast_dump_patterns.v new file mode 100644 index 000000000..dc96474fb --- /dev/null +++ b/test_regress/t/t_ast_dump_patterns.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +module t ( + input wire [3:0] a, + input wire [3:0] b, + input wire [3:0] c, + output wire [10:0] o +); + wire [3:0] x = ~a & ~b; + wire [3:0] y = ~b & ~c; + wire [3:0] z = ~c & ~a; + wire [0:0] w1 = x[0]; + wire [7:0] w8 = {8{x[1]}}; + wire [15:0] w16 = {2{w8}}; + wire [31:0] w32 = {2{w16}}; + wire [63:0] w64a = {2{w32}}; + wire [63:0] w64b = {2{~w32}}; + wire [62:0] w63 = 63'({2{~w32}}); + wire [95:0] w96 = 96'(w64a); + + assign o = {^x, ^y, ^z, ^w1, ^w8, ^w16, ^w32, ^w64a, ^w64b, ^w63, ^w96}; +endmodule