Fix comparison of unpacked arrays, bug1071.

This commit is contained in:
Wilson Snyder 2016-07-23 16:58:30 -04:00
parent e8e4f1777d
commit 24dc36ba4c
5 changed files with 135 additions and 1 deletions

View File

@ -10,6 +10,8 @@ indicates the contributor was also the author of the fix; Thanks!
**** Fix false warnings on non-power-2 enums using .next/.prev.
**** Fix comparison of unpacked arrays, bug1071. [Andrew Bardsley]
**** Fix compiler warning in GCC 6. [David Horton]

View File

@ -471,6 +471,62 @@ class SliceVisitor : public AstNVisitor {
expandUniOp(nodep);
}
void expandBiOp(AstNodeBiop* nodep) {
if (!nodep->user1()) {
nodep->user1(true);
// If it's a unpacked array, blow it up into comparing each element
AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp();
UINFO(9, " Bi-Eq/Neq expansion "<<nodep<<endl);
if (AstUnpackArrayDType* adtypep = fromDtp->castUnpackArrayDType()) {
AstNodeBiop* logp = NULL;
for (int index = adtypep->rangep()->lsbConst();
index <= adtypep->rangep()->msbConst(); ++index) {
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
AstNodeBiop* clonep = nodep->cloneType
(new AstArraySel(nodep->fileline(),
nodep->lhsp()->cloneTree(false),
index),
new AstArraySel(nodep->fileline(),
nodep->rhsp()->cloneTree(false),
index))->castNodeBiop();
if (!logp) logp = clonep;
else {
switch (nodep->type()) {
case AstType::atEQ: // FALLTHRU
case AstType::atEQCASE:
logp = new AstLogAnd(nodep->fileline(), logp, clonep);
break;
case AstType::atNEQ: // FALLTHRU
case AstType::atNEQCASE:
logp = new AstLogOr(nodep->fileline(), logp, clonep);
break;
default:
nodep->v3fatalSrc("Unknown node type processing array slice");
break;
}
}
}
if (!logp) nodep->v3fatalSrc("Unpacked array with empty indices range");
nodep->replaceWith(logp);
pushDeletep(nodep); VL_DANGLING(nodep);
nodep = logp;
}
nodep->iterateChildren(*this);
}
}
virtual void visit(AstEq* nodep, AstNUser*) {
expandBiOp(nodep);
}
virtual void visit(AstNeq* nodep, AstNUser*) {
expandBiOp(nodep);
}
virtual void visit(AstEqCase* nodep, AstNUser*) {
expandBiOp(nodep);
}
virtual void visit(AstNeqCase* nodep, AstNUser*) {
expandBiOp(nodep);
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
nodep->iterateChildren(*this);

View File

@ -13,7 +13,7 @@
// please note it here, otherwise:**
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2015 by ____YOUR_NAME_HERE____.
// without warranty, 2016 by ____YOUR_NAME_HERE____.
module t (/*AUTOARG*/
// Inputs

View File

@ -0,0 +1,18 @@
#!/usr/bin/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.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,58 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2016 by Andrew Bardsley.
// bug1071
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [3:0] array_1 [2:0];
reg [3:0] array_2 [2:0];
reg [3:0] array_3 [3:1];
reg [3:0] elem;
reg array_1_ne_array_2;
reg array_1_eq_array_2;
reg array_1_ne_array_3;
reg array_1_eq_array_3;
initial begin
array_1[0] = 4'b1000;
array_1[1] = 4'b1000;
array_1[2] = 4'b1000;
array_2[0] = 4'b1000;
array_2[1] = 4'b1000;
array_2[2] = 4'b1000;
array_3[1] = 4'b1000;
array_3[2] = 4'b0100;
array_3[3] = 4'b0100;
// Comparisons only compare elements 0
array_1_ne_array_2 = array_1 != array_2; // 0
array_1_eq_array_2 = array_1 == array_2; // 0
array_1_ne_array_3 = array_1 != array_3; // 1
array_1_eq_array_3 = array_1 == array_3; // 1
`ifdef TEST_VERBOSE
$write("array_1_ne_array2==%0d\n", array_1_ne_array_2);
$write("array_1_ne_array3==%0d\n", array_1_ne_array_3);
`endif
if (array_1_ne_array_2 !== 0) $stop;
if (array_1_eq_array_2 !== 1) $stop;
if (array_1_ne_array_3 !== 1) $stop;
if (array_1_eq_array_3 !== 0) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule