From 889a1211f1394b475b02f70daa2d9712af297c83 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 1 Dec 2022 22:00:24 +0900 Subject: [PATCH] Fix 3786 (Internal error in bit op tree optimization) (#3793) * Tests: Add a test to reproduce 3786 * Fix #3786 (Internal error in bit op tree optimization). --- src/V3Const.cpp | 10 +++++++++ test_regress/t/t_const_opt.v | 20 ++++++++++++++++-- test_regress/t/t_const_opt_no_expand.pl | 27 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_const_opt_no_expand.pl diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 2790b9620..89972e6c1 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -122,6 +122,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor { const AstConst* constp() const { return m_constp; } int wordIdx() const { return m_wordIdx; } bool polarity() const { return m_polarity; } + bool missingWordSel() const { + // When V3Expand is skipped, WordSel is not inserted. + return m_refp->isWide() && m_wordIdx == -1; + } int lsb() const { return m_lsb; } int msb() const { return std::min(m_msb, varWidth() - 1); } @@ -132,6 +136,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { UASSERT_OBJ(m_wordIdx == -1, m_refp, "Bad word index into non-wide"); return width; } else { + if (missingWordSel()) return width; UASSERT_OBJ(m_wordIdx >= 0, m_refp, "Bad word index into wide"); const int bitsInMSW = VL_BITBIT_E(width) ? VL_BITBIT_E(width) : VL_EDATASIZE; return m_wordIdx == m_refp->widthWords() - 1 ? bitsInMSW : VL_EDATASIZE; @@ -393,6 +398,11 @@ class ConstBitOpTreeVisitor final : public VNVisitor { if (!varInfop) { varInfop = new VarInfo{this, ref.refp(), ref.varWidth()}; m_varInfos[idx].reset(varInfop); + if (ref.missingWordSel()) { + // ConstBitOpTreeVisitor makes some constants for masks and its type is uint64_t. + // That's why V3Expand, that inserts WordSel, is needed. + CONST_BITOP_SET_FAILED("V3Expand is skipped", ref.refp()); + } } else { if (!varInfop->sameVarAs(ref.refp())) CONST_BITOP_SET_FAILED("different var (scope?)", ref.refp()); diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index d1c545a61..8ebb397b3 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -62,7 +62,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'h9366e49d91bfe942 +`define EXPECTED_SUM 64'h94c0495e8e279723 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -90,10 +90,11 @@ module Test(/*AUTOARG*/ logic bug3509_out; wire bug3399_out0; wire bug3399_out1; + logic bug3786_out; output logic o; - logic [11:0] tmp; + logic [12:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -121,6 +122,7 @@ module Test(/*AUTOARG*/ tmp[9] <= bug3509_out; tmp[10]<= bug3399_out0; tmp[11]<= bug3399_out1; + tmp[12]<= bug3786_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); @@ -129,6 +131,7 @@ module Test(/*AUTOARG*/ bug3470 i_bug3470(.clk(clk), .in(d), .out(bug3470_out)); bug3509 i_bug3509(.clk(clk), .in(d), .out(bug3509_out)); bug3399 i_bug3399(.clk(clk), .in(d), .out0(bug3399_out0), .out1(bug3399_out1)); + bug3786 i_bug3786(.clk(clk), .in(d), .out(bug3786_out)); endmodule @@ -315,3 +318,16 @@ module bug3399(input wire clk, input wire [31:0] in, inout wire out0, inout wire assign out0 = driver[0] ? d[0] : 1'bz; assign out1 = driver[1] ? d[1] : 1'bz; endmodule + +// Bug3786 +// When V3Expand is skipped, wide number is not split by WORDSEL. +// Bit op tree opt. expects that bit width is 64 bit at most. +module bug3786(input wire clk, input wire [31:0] in, inout wire out); + logic [127:0] d0, d1; + always_ff @(posedge clk) begin + d0 <= {d0[127:32], in}; + d1 <= d1; + end + + assign out = ^{d1, d0}; +endmodule diff --git a/test_regress/t/t_const_opt_no_expand.pl b/test_regress/t/t_const_opt_no_expand.pl new file mode 100755 index 000000000..db812ea9a --- /dev/null +++ b/test_regress/t/t_const_opt_no_expand.pl @@ -0,0 +1,27 @@ +#!/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); +top_filename("t/t_const_opt.v"); + +compile( + verilator_flags2 => ["-Wno-UNOPTTHREADS", "-fno-dfg", "-fno-expand", + "--stats", "$Self->{t_dir}/t_const_opt.cpp"], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt}) { + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 2); +} +ok(1); +1;