From 692306ef4425bed9aab5f808747e36bf975bcfa5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 28 Nov 2021 14:17:28 -0500 Subject: [PATCH] Optimize $random concatenates/selects (#3114). --- Changes | 1 + include/verilated.cpp | 5 --- include/verilated_funcs.h | 2 - src/V3AstNodes.h | 4 ++ src/V3Const.cpp | 25 ++++++++++++ test_regress/t/t_sys_rand_concat.pl | 23 +++++++++++ test_regress/t/t_sys_rand_concat.v | 60 +++++++++++++++++++++++++++++ 7 files changed, 113 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_sys_rand_concat.pl create mode 100644 test_regress/t/t_sys_rand_concat.v diff --git a/Changes b/Changes index 3362d93e7..467fb4ea0 100644 --- a/Changes +++ b/Changes @@ -22,6 +22,7 @@ Verilator 4.215 devel * Improve --thread verilation-time performance. * Support task name in $display %m (#3211). [Julie Schwartz] * Make 'bit', 'logic' and 'time' types unsigned by default. [Geza Lore] +* Optimize $random concatenates/selects (#3114). * Fix array method names with parenthesis (#3181) (#3183). [Teng Huang] * Fix split_var assign merging (#3177) (#3179). [Yutetsu TAKATSUKASA] * Fix wrong bit op tree optimization (#3185). [Yutetsu TAKATSUKASA] diff --git a/include/verilated.cpp b/include/verilated.cpp index 96ad788e4..40c51f000 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -308,16 +308,11 @@ vluint64_t vl_rand64() VL_MT_SAFE { return result; } -#ifndef VL_NO_LEGACY -// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility -// LCOV_EXCL_START WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = vl_rand64(); // Last word is unclean return outwp; } -// LCOV_EXCL_STOP -#endif IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE { Verilated::threadContextp()->randSeed(static_cast(seed)); diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 5442260cf..bd1369421 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -76,9 +76,7 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; // EMIT_RULE: VL_RANDOM: oclean=dirty inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); } inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); } -#ifndef VL_NO_LEGACY extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); -#endif extern IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE; inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) { const vluint64_t rnd = vl_rand64(); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 3524454d4..fb598bfaf 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5481,6 +5481,10 @@ public: virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return INSTR_COUNT_PLI; } virtual bool same(const AstNode* samep) const override { return true; } + bool combinable(const AstRand* samep) const { + return !seedp() && !samep->seedp() && reset() == samep->reset() + && urandom() == samep->urandom(); + } AstNode* seedp() const { return op1p(); } bool reset() const { return m_reset; } bool urandom() const { return m_urandom; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 62ef412c6..dedebfb2a 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2229,6 +2229,29 @@ private: iterate(nodep); // Again? } + bool matchConcatRand(AstConcat* nodep) { + // CONCAT(RAND, RAND) - created by Chisel code + AstRand* const aRandp = VN_CAST(nodep->lhsp(), Rand); + AstRand* const bRandp = VN_CAST(nodep->rhsp(), Rand); + if (!aRandp || !bRandp) return false; + if (!aRandp->combinable(bRandp)) return false; + UINFO(4, "Concat(Rand,Rand) => Rand: " << nodep << endl); + aRandp->dtypeFrom(nodep); // I.e. the total width + nodep->replaceWith(aRandp->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return true; + } + bool matchSelRand(AstSel* nodep) { + // SEL(RAND) - created by Chisel code + AstRand* const aRandp = VN_CAST(nodep->fromp(), Rand); + if (!aRandp) return false; + if (aRandp->seedp()) return false; + UINFO(4, "Sel(Rand) => Rand: " << nodep << endl); + aRandp->dtypeFrom(nodep); // I.e. the total width + nodep->replaceWith(aRandp->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return true; + } int operandConcatMove(AstConcat* nodep) { // CONCAT under concat (See moveConcat) // Return value: true indicates to do it; 2 means move to LHS @@ -3364,6 +3387,7 @@ private: TREEOPV("AstLogNot{$lhsp.width1, isTPure($lhsp)}", "AstNot{$lhsp}"); // CONCAT(CONCAT({a},{b}),{c}) -> CONCAT({a},CONCAT({b},{c})) // CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c})) + TREEOPV("AstConcat{matchConcatRand(nodep)}", "DONE"); TREEOPV("AstConcat{operandConcatMove(nodep)}", "moveConcat(nodep)"); TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())"); // CONCAT(a[1],a[0]) -> a[1:0] @@ -3392,6 +3416,7 @@ private: TREEOPV("AstConcat{operandConcatSame(nodep)}", "DONE"); // {a,a}->{2{a}}, {a,2{a}}->{3{a}, etc // Next rule because AUTOINST puts the width of bits in // to pins, even when the widths are exactly the same across the hierarchy. + TREEOPV("AstSel{matchSelRand(nodep)}", "DONE"); TREEOPV("AstSel{operandSelExtend(nodep)}", "DONE"); TREEOPV("AstSel{operandSelFull(nodep)}", "replaceWChild(nodep, nodep->fromp())"); TREEOPV("AstSel{$fromp.castSel}", "replaceSelSel(nodep)"); diff --git a/test_regress/t/t_sys_rand_concat.pl b/test_regress/t/t_sys_rand_concat.pl new file mode 100755 index 000000000..62d68c9f8 --- /dev/null +++ b/test_regress/t/t_sys_rand_concat.pl @@ -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 2003 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +file_grep_not(glob_one("$Self->{obj_dir}/Vt_sys_rand_concat___024root__DepSet_*__0__Slow.cpp"), qr/(<<|>>)/x); + +ok(1); +1; diff --git a/test_regress/t/t_sys_rand_concat.v b/test_regress/t/t_sys_rand_concat.v new file mode 100644 index 000000000..820834dc2 --- /dev/null +++ b/test_regress/t/t_sys_rand_concat.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2008 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +module t; + +`define TRIES 100 + + bit [6:0] b5a; // We use larger than [4:0] so make sure we truncate + bit [6:0] b5b; // We use larger than [4:0] so make sure we truncate + bit [6:0] b7c; + bit [6:0] b7d; + bit [59:0] b60c; + bit [89:0] b90c; + + bit [6:0] max_b5a; + bit [6:0] max_b5b; + bit [6:0] max_b7c; + bit [6:0] max_b7d; + bit [59:0] max_b60c; + bit [89:0] max_b90c; + + initial begin + for (int i = 0; i < `TRIES; ++i) begin + // verilator lint_off WIDTH + // Optimize away extracts + b5a = {$random}[4:0]; + b5b = {$random}[14:10]; + // Optimize away concats + b7c = {$random, $random, $random, $random, $random, $random, $random}; + b7d = {{{$random}[0]}, {{$random}[0]}, {{$random}[0]}, {{$random}[0]}, {{$random}[0]}}; + b60c = {$random, $random, $random, $random, $random, $random, $random}; + b90c = {$random, $random, $random, $random, $random, $random, $random}; + // verilator lint_on WIDTH + + max_b5a = max_b5a | b5a; + max_b5b = max_b5b | b5b; + max_b7c = max_b7c | b7c; + max_b7d = max_b7d | b7d; + max_b60c = max_b60c | b60c; + max_b90c = max_b90c | b90c; + end + + `checkh(max_b5a, 7'h1f); + `checkh(max_b5b, 7'h1f); + `checkh(max_b7c, 7'h7f); + `checkh(max_b7d, 7'h1f); + `checkh(max_b60c, ~ 60'h0); + `checkh(max_b90c, ~ 90'h0); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule