mirror of
https://github.com/verilator/verilator.git
synced 2025-01-03 21:27:35 +00:00
Dump DFG patterns with --stats (#4889)
With --stats, we will print DFG pattern combinations, one per line, as S-expressions to new stat files, together with their frequency, to aid discovery of new peephole patterns.
This commit is contained in:
parent
d667b73e8d
commit
cbc76a7816
@ -1267,6 +1267,8 @@ Summary:
|
||||
|
||||
Creates a dump file with statistics on the design in
|
||||
:file:`<prefix>__stats.txt`.
|
||||
Also dumps DFG patterns to
|
||||
:file:`<prefix>__stats_dfg_patterns__*.txt`.
|
||||
|
||||
.. option:: --stats-vars
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "V3AstUserAllocator.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3DfgPatternStats.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
@ -252,6 +254,8 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
|
||||
|
||||
V3DfgOptimizationContext ctx{label};
|
||||
|
||||
V3DfgPatternStats patternStats;
|
||||
|
||||
// Run the optimization phase
|
||||
for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) {
|
||||
// Only optimize proper modules
|
||||
@ -295,10 +299,34 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
|
||||
dfg->addGraph(*component);
|
||||
}
|
||||
|
||||
// Accumulate patterns from the optimized graph for reporting
|
||||
if (v3Global.opt.stats()) patternStats.accumulate(*dfg);
|
||||
|
||||
// Convert back to Ast
|
||||
if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized");
|
||||
AstModule* const resultModp = V3DfgPasses::dfgToAst(*dfg, ctx);
|
||||
UASSERT_OBJ(resultModp == modp, modp, "Should be the same module");
|
||||
}
|
||||
|
||||
// Print the collected patterns
|
||||
if (v3Global.opt.stats()) {
|
||||
// Label to lowercase, without spaces
|
||||
std::string ident = label;
|
||||
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
|
||||
return c == ' ' ? '_' : std::tolower(c);
|
||||
});
|
||||
|
||||
// File to dump to
|
||||
const std::string filename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
|
||||
+ "__stats_dfg_patterns__" + ident + ".txt";
|
||||
|
||||
// Open, write, close
|
||||
std::ofstream* const ofp = V3File::new_ofstream(filename);
|
||||
if (ofp->fail()) v3fatal("Can't write " << filename);
|
||||
patternStats.dump(label, *ofp);
|
||||
ofp->close();
|
||||
VL_DO_DANGLING(delete ofp, ofp);
|
||||
}
|
||||
|
||||
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
197
src/V3DfgPatternStats.h
Normal file
197
src/V3DfgPatternStats.h
Normal file
@ -0,0 +1,197 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Implementations of simple passes over DfgGraph
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "V3PchAstNoMT.h"
|
||||
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
class V3DfgPatternStats final {
|
||||
static constexpr uint32_t MIN_PATTERN_DEPTH = 1;
|
||||
static constexpr uint32_t MAX_PATTERN_DEPTH = 4;
|
||||
|
||||
std::map<std::string, std::string> m_internedConsts; // Interned constants
|
||||
std::map<const AstVar*, std::string> m_internedVars; // Interned variables
|
||||
std::map<uint32_t, std::string> m_internedSelLsbs; // Interned lsb value for selects
|
||||
std::map<uint32_t, std::string> m_internedWordWidths; // Interned widths
|
||||
std::map<uint32_t, std::string> m_internedWideWidths; // Interned widths
|
||||
std::map<const DfgVertex*, std::string> m_internedVertices; // Interned vertices
|
||||
|
||||
// Maps from pattern to the number of times it appears, for each pattern depth
|
||||
std::vector<std::unordered_map<std::string, size_t>> m_patterCounts{MAX_PATTERN_DEPTH + 1};
|
||||
|
||||
static std::string toLetters(size_t value, bool lowerCase = false) {
|
||||
const char base = lowerCase ? 'a' : 'A';
|
||||
std::string s;
|
||||
do { s += static_cast<char>(base + value % 26); } while (value /= 26);
|
||||
return s;
|
||||
}
|
||||
|
||||
const std::string& internConst(const DfgConst& vtx) {
|
||||
const auto pair = m_internedConsts.emplace(vtx.num().ascii(false), "c");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedConsts.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
const std::string& internVar(const DfgVertexVar& vtx) {
|
||||
const auto pair = m_internedVars.emplace(vtx.varp(), "v");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedVars.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
const std::string& internSelLsb(uint32_t value) {
|
||||
const auto pair = m_internedSelLsbs.emplace(value, "");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedSelLsbs.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
const std::string& internWordWidth(uint32_t 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(uint32_t value) {
|
||||
const auto pair = m_internedWideWidths.emplace(value, "");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedWideWidths.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
const std::string& internVertex(const DfgVertex& vtx) {
|
||||
const auto pair = m_internedVertices.emplace(&vtx, "_");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedVertices.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
// Render the vertx into ss, and return true if the recursion reached the given depth,
|
||||
// meaning an S-expression with that nesting level has been rendered.
|
||||
bool render(std::ostringstream& ss, const DfgVertex& vtx, uint32_t depth) {
|
||||
bool deep = depth == 0;
|
||||
|
||||
if (const DfgConst* const constp = vtx.cast<DfgConst>()) {
|
||||
// Base case 1: constant
|
||||
if (constp->isZero()) {
|
||||
ss << "'0";
|
||||
} else if (constp->isOnes()) {
|
||||
ss << "'1";
|
||||
} else {
|
||||
ss << internConst(*constp);
|
||||
}
|
||||
} else if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
||||
// Base case 2: variable
|
||||
ss << internVar(*varp);
|
||||
} else if (depth == 0) {
|
||||
// Base case 3: deep vertex
|
||||
ss << internVertex(vtx);
|
||||
} else {
|
||||
// Recursively print an S-expression for the vertex
|
||||
|
||||
// S-expression begin
|
||||
ss << '(';
|
||||
// Name
|
||||
ss << vtx.typeName();
|
||||
// Specials
|
||||
if (const DfgSel* const selp = vtx.cast<DfgSel>()) {
|
||||
ss << '@';
|
||||
if (selp->lsb() == 0) {
|
||||
ss << '0';
|
||||
} else {
|
||||
ss << internSelLsb(selp->lsb());
|
||||
}
|
||||
}
|
||||
|
||||
// Operands
|
||||
vtx.forEachSource([&](const DfgVertex& src) {
|
||||
ss << ' ';
|
||||
if (render(ss, src, depth - 1)) deep = true;
|
||||
});
|
||||
// S-expression end
|
||||
ss << ')';
|
||||
|
||||
// Mark it if it has multiple sinks
|
||||
if (vtx.hasMultipleSinks()) ss << '*';
|
||||
}
|
||||
|
||||
// Annotate type
|
||||
ss << ':';
|
||||
const AstNodeDType* const dtypep = vtx.dtypep();
|
||||
if (!VN_IS(dtypep, BasicDType)) {
|
||||
dtypep->dumpSmall(ss);
|
||||
} else {
|
||||
const uint32_t width = dtypep->width();
|
||||
if (width == 1) {
|
||||
ss << '1';
|
||||
} else if (width <= VL_QUADSIZE) {
|
||||
ss << internWordWidth(width);
|
||||
} else {
|
||||
ss << internWideWidth(width);
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
return deep;
|
||||
}
|
||||
|
||||
public:
|
||||
V3DfgPatternStats() = default;
|
||||
|
||||
void accumulate(const DfgGraph& dfg) {
|
||||
dfg.forEachVertex([&](const DfgVertex& vtx) {
|
||||
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
|
||||
std::ostringstream ss;
|
||||
if (render(ss, vtx, i)) m_patterCounts[i][ss.str()] += 1;
|
||||
m_internedConsts.clear();
|
||||
m_internedVars.clear();
|
||||
m_internedSelLsbs.clear();
|
||||
m_internedWordWidths.clear();
|
||||
m_internedWideWidths.clear();
|
||||
m_internedVertices.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void dump(const std::string& stage, std::ostream& os) {
|
||||
using Line = std::pair<std::string, size_t>;
|
||||
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
|
||||
os << "DFG '" << stage << "' patterns with depth " << i << '\n';
|
||||
|
||||
// Pick up pattern accumulators with given depth
|
||||
const auto& patternCounts = m_patterCounts[i];
|
||||
|
||||
// Sort patterns, first by descending frequency, then lexically
|
||||
std::vector<Line> 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';
|
||||
}
|
||||
}
|
||||
};
|
@ -279,7 +279,7 @@ static void process() {
|
||||
|
||||
if (v3Global.opt.fDfgPreInline()) {
|
||||
// Pre inline DFG optimization
|
||||
V3DfgOptimizer::optimize(v3Global.rootp(), " pre inline");
|
||||
V3DfgOptimizer::optimize(v3Global.rootp(), "pre inline");
|
||||
}
|
||||
|
||||
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
||||
|
37
test_regress/t/t_dfg_stats_patterns.v
Normal file
37
test_regress/t/t_dfg_stats_patterns.v
Normal file
@ -0,0 +1,37 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by 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 [3:0] x,
|
||||
output wire [3:0] y,
|
||||
output wire [3:0] z,
|
||||
output wire [ 0:0] w1,
|
||||
output wire [ 7:0] w8,
|
||||
output wire [15:0] w16,
|
||||
output wire [31:0] w32,
|
||||
output wire [63:0] w64a,
|
||||
output wire [63:0] w64b,
|
||||
output wire [62:0] w63,
|
||||
output wire [95:0] w96
|
||||
);
|
||||
|
||||
assign x = ~a & ~b;
|
||||
assign y = ~b & ~c;
|
||||
assign z = ~c & ~a;
|
||||
assign w1 = x[0];
|
||||
assign w8 = {8{x[1]}};
|
||||
assign w16 = {2{w8}};
|
||||
assign w32 = {2{w16}};
|
||||
assign w64a = {2{w32}};
|
||||
assign w64b = {2{~w32}};
|
||||
assign w63 = 63'({2{~w32}});
|
||||
assign w96 = 96'(w64a);
|
||||
|
||||
endmodule
|
50
test_regress/t/t_dfg_stats_patterns_post_inline.out
Normal file
50
test_regress/t/t_dfg_stats_patterns_post_inline.out
Normal file
@ -0,0 +1,50 @@
|
||||
DFG 'post inline' patterns with depth 1
|
||||
3 (NOT vA:a)*:a
|
||||
2 (AND _A:a _B:a):a
|
||||
2 (REPLICATE _A:a cA:a)*:b
|
||||
1 (AND _A:a _B:a)*:a
|
||||
1 (CONCAT '0:a _A:b):A
|
||||
1 (NOT _A:a):a
|
||||
1 (REPLICATE _A:1 cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:c
|
||||
1 (SEL@0 _A:a):1
|
||||
1 (SEL@0 _A:a):b
|
||||
1 (SEL@A _A:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 2
|
||||
2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||
1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a
|
||||
1 (CONCAT '0:a (REPLICATE _A:a cA:a)*:b):A
|
||||
1 (NOT (REPLICATE _A:a cA:b)*:b):b
|
||||
1 (REPLICATE (NOT _A:a):a cA:a)*:b
|
||||
1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b
|
||||
1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND _A:a _B:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c
|
||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 3
|
||||
1 (CONCAT '0:a (REPLICATE (REPLICATE _A:b cA:a)*:a cA:a)*:c):A
|
||||
1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b
|
||||
1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 4
|
||||
1 (CONCAT '0:a (REPLICATE (REPLICATE (REPLICATE _A:b cA:a)*:c cA:a)*:a cA:a)*:d):A
|
||||
1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a
|
||||
1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b
|
||||
1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d
|
||||
|
23
test_regress/t/t_dfg_stats_patterns_post_inline.pl
Executable file
23
test_regress/t/t_dfg_stats_patterns_post_inline.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
top_filename("t/t_dfg_stats_patterns.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["--stats --no-skip-identical -fno-dfg-pre-inline"],
|
||||
);
|
||||
|
||||
my $f = glob_one("$Self->{obj_dir}/$Self->{vm_prefix}__stats_dfg_patterns*");
|
||||
files_identical($f, $Self->{golden_filename});
|
||||
|
||||
ok(1);
|
||||
1;
|
50
test_regress/t/t_dfg_stats_patterns_pre_inline.out
Normal file
50
test_regress/t/t_dfg_stats_patterns_pre_inline.out
Normal file
@ -0,0 +1,50 @@
|
||||
DFG 'pre inline' patterns with depth 1
|
||||
3 (NOT vA:a)*:a
|
||||
2 (AND _A:a _B:a):a
|
||||
2 (REPLICATE _A:a cA:a)*:b
|
||||
1 (AND _A:a _B:a)*:a
|
||||
1 (CONCAT '0:a _A:b):A
|
||||
1 (NOT _A:a):a
|
||||
1 (REPLICATE _A:1 cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:c
|
||||
1 (SEL@0 _A:a):1
|
||||
1 (SEL@0 _A:a):b
|
||||
1 (SEL@A _A:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 2
|
||||
2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||
1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a
|
||||
1 (CONCAT '0:a (REPLICATE _A:a cA:a)*:b):A
|
||||
1 (NOT (REPLICATE _A:a cA:b)*:b):b
|
||||
1 (REPLICATE (NOT _A:a):a cA:a)*:b
|
||||
1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b
|
||||
1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND _A:a _B:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c
|
||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 3
|
||||
1 (CONCAT '0:a (REPLICATE (REPLICATE _A:b cA:a)*:a cA:a)*:c):A
|
||||
1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b
|
||||
1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 4
|
||||
1 (CONCAT '0:a (REPLICATE (REPLICATE (REPLICATE _A:b cA:a)*:c cA:a)*:a cA:a)*:d):A
|
||||
1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a
|
||||
1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b
|
||||
1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d
|
||||
|
23
test_regress/t/t_dfg_stats_patterns_pre_inline.pl
Executable file
23
test_regress/t/t_dfg_stats_patterns_pre_inline.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(vlt => 1);
|
||||
|
||||
top_filename("t/t_dfg_stats_patterns.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["--stats --no-skip-identical -fno-dfg-post-inline"],
|
||||
);
|
||||
|
||||
my $f = glob_one("$Self->{obj_dir}/$Self->{vm_prefix}__stats_dfg_patterns*");
|
||||
files_identical($f, $Self->{golden_filename});
|
||||
|
||||
ok(1);
|
||||
1;
|
@ -14,7 +14,7 @@ compile(
|
||||
verilator_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
file_grep($Self->{stats}, qr/Optimizations, DFG pre inline Ast2Dfg, non-representable \(impure\)\s+(\d+)/i, 1);
|
||||
file_grep($Self->{stats}, qr/Optimizations, DFG pre inline Ast2Dfg, non-representable \(impure\)\s+(\d+)/i, 1);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user