Fix power operator with wide numbers and constants (#4721) (#4763)

This commit is contained in:
Wilson Snyder 2023-12-19 19:22:54 -05:00
parent 654ab117f2
commit 55ad950609
9 changed files with 117 additions and 10 deletions

View File

@ -47,7 +47,7 @@ Verilator 5.019 devel
* Fix compilers seeing empty input due to file system races (#4708). [Flavien Solt]
* Fix shift of > 32-bit number (#4719). [Flavien Solt]
* Fix Windows include gates in filesystem Flush implementation. (#4720). [William D. Jones]
* Fix 0**0 with wide numbers (#4721). [Flavien Solt]
* Fix power operator with wide numbers and constants (#4721) (#4763). [Flavien Solt]
* Fix parameter passing to ports (#4723). [Ryszard Rozak, Antmicro Ltd.]
* Fix block names of nested do..while loops (#4728). [Ryszard Rozak, Antmicro Ltd.]

View File

@ -3434,10 +3434,6 @@ class ConstVisitor final : public VNVisitor {
TREEOP ("AstPowSS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPowSU {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPowUS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPow {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowUS {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstShiftL {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstShiftLOvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
@ -3479,7 +3475,7 @@ class ConstVisitor final : public VNVisitor {
TREEOP ("AstMul {operandIsPowTwo($lhsp), operandsSameSize($lhsp,,$rhsp)}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstPow {operandIsTwo($lhsp), !$rhsp.isZero}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
// Trinary ops

View File

@ -482,6 +482,11 @@ V3Number& V3Number::setAllBitsXRemoved() {
}
}
}
V3Number& V3Number::setValue1() {
m_data.num()[0] = {1, 0};
for (int i = 1; i < words(); i++) m_data.num()[i] = {0, 0};
return *this;
}
V3Number& V3Number::setMask(int nbits) {
setZero();
@ -2139,18 +2144,18 @@ V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign,
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setQuad(1); // Overrides lhs 0 -> return 0
if (rhs.isEqZero()) return setValue1(); // Overrides lhs 0 -> return 1
// We may want to special case when the lhs is 2, so we can get larger outputs
if (rsign && rhs.isNegative()) {
if (lhs.isEqZero()) {
return setAllBitsXRemoved();
} else if (lhs.isEqOne()) {
return setQuad(1);
return setValue1();
} else if (lsign && lhs.isEqAllOnes()) {
if (rhs.bitIs1(0)) {
return setAllBits1(); // -1^odd=-1
} else {
return setQuad(1); // -1^even=1
return setValue1(); // -1^even=1
}
}
return setZero();

View File

@ -581,6 +581,7 @@ public:
V3Number& setAllBitsZ();
V3Number& setAllBits0();
V3Number& setAllBits1();
V3Number& setValue1();
V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
// ACCESSORS

View File

@ -12,6 +12,8 @@
#ifndef TEST_CHECK_H_
#define TEST_CHECK_H_
#include <iostream>
extern int errors;
#ifdef TEST_VERBOSE

View File

@ -1,7 +1,7 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2005 by Wilson Snyder.
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`define STRINGIFY(x) `"x`"
@ -235,6 +235,11 @@ module t (/*AUTOARG*/
$write("- cyc%0d: %0x**%0x = sh %0x\n", cyc, a, b, shifted);
`endif
// Constant versions
`checkh(67'h0 ** 21'h0, 67'h1);
`checkh(67'h1 ** 21'h0, 67'h1);
`checkh(67'h2 ** 21'h0, 67'h1);
`checkh(67'h0 ** 21'h1, 67'h0);
`checkh(67'h0 ** 21'h4, 67'h0);
`checkh(67'h1 ** 21'h31, 67'h1);
`checkh(67'h2 ** 21'h10, 67'h10000);
`checkh(67'd10 ** 21'h3, 67'h3e8);

View File

@ -0,0 +1,42 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
#include VM_PREFIX_INCLUDE
#include "TestCheck.h"
int errors = 0;
std::unique_ptr<VM_PREFIX> topp;
int main(int argc, char** argv) {
vluint64_t sim_time = 1100;
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
contextp->commandArgs(argc, argv);
topp.reset(new VM_PREFIX{"top"});
topp->eval();
{ contextp->timeInc(10); }
int cyc = 0;
while ((contextp->time() < sim_time) && !contextp->gotFinish()) {
topp->eval();
contextp->timeInc(5);
++cyc;
if (cyc > 10) break;
}
TEST_CHECK_EQ(topp->out_data, 1);
topp->final();
topp.reset();
printf("*-* All Finished *-*\n");
return errors != 0;
}

27
test_regress/t/t_math_pow7.pl Executable file
View File

@ -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 2023 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(
make_top_shell => 0,
make_main => 0,
verilator_flags2 => [
"--exe",
"$Self->{t_dir}/$Self->{name}.cpp"
],
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,29 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2005 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`define STRINGIFY(x) `"x`"
`define stop $stop
`ifdef VERILATOR
`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)
`else
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(0)
`endif
module t (/*AUTOARG*/
// Outputs
out_data
);
output [11:0] out_data;
wire [11:0] out_data;
wire [11:0] a;
wire [2:0] b;
assign a = 12'h000 ** { b };
assign b = 3'b0;
assign out_data = a;
endmodule