forked from github/verilator
Add optimization of operators between concats, msg1447.
This commit is contained in:
parent
85c3179dbd
commit
cf6d07aafa
2
Changes
2
Changes
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.865 devel
|
||||
|
||||
*** Add optimization of operators between concats, msg1447. [Jie Xu]
|
||||
|
||||
**** Fix generate unrolling with function call, bug830. [Steven Slatter]
|
||||
|
||||
**** Fix cast-to-size context-determined sizing, bug828. [Geoff Barrett]
|
||||
|
@ -450,6 +450,56 @@ private:
|
||||
if (afterComment(lowerIfp->elsesp())) return false;
|
||||
return true;
|
||||
}
|
||||
bool ifConcatMergeableBiop(AstNode* nodep) {
|
||||
return (nodep->castAnd()
|
||||
|| nodep->castOr()
|
||||
|| nodep->castXor()
|
||||
|| nodep->castXnor());
|
||||
}
|
||||
bool ifAdjacent(AstNode* lhsp, AstNode* rhsp) {
|
||||
if (!v3Global.opt.oAssemble()) return false; // opt disabled
|
||||
AstSel* lselp = lhsp->castSel();
|
||||
AstSel* rselp = rhsp->castSel();
|
||||
if (!lselp || !lhsp->castVarRef()) return false;
|
||||
if (!rselp || !rhsp->castVarRef()) return false;
|
||||
// a[a:b] a[b-1:c] are adjacent // a a[1:0] are adjacent as well
|
||||
AstVarRef* lvarp = lselp->fromp()->castVarRef();
|
||||
AstVarRef* rvarp = rselp->fromp()->castVarRef();
|
||||
if (!lvarp || !rvarp || !lvarp->same(rvarp)) return false;
|
||||
AstConst* lstart = lselp->lsbp()->castConst();
|
||||
AstConst* rstart = rselp->lsbp()->castConst();
|
||||
AstConst* lwidth = lselp->widthp()->castConst();
|
||||
AstConst* rwidth = rselp->widthp()->castConst();
|
||||
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
|
||||
// a[i:j] a[j-1:k]
|
||||
int rend = (rstart->toSInt() + rwidth->toSInt());
|
||||
if (rend == lstart->toSInt()) return true;
|
||||
return false;
|
||||
}
|
||||
bool concatMergeable(AstNode* lhsp, AstNode* rhsp) {
|
||||
if (!v3Global.opt.oAssemble()) return false; // opt disabled
|
||||
if (lhsp->type() != rhsp->type()) return false;
|
||||
if (!ifConcatMergeableBiop(lhsp)) return false;
|
||||
|
||||
AstNodeBiop* lp = lhsp->castNodeBiop();
|
||||
AstNodeBiop* rp = rhsp->castNodeBiop();
|
||||
if (!lp || !rp) return false;
|
||||
// {a[]&b[], a[]&b[]}
|
||||
bool lad = ifAdjacent(lp->lhsp(), rp->lhsp());
|
||||
bool rad = ifAdjacent(lp->rhsp(), rp->rhsp());
|
||||
if (lad && lad) return true;
|
||||
// {a[] & b[]&c[], a[] & b[]&c[]}
|
||||
else if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true;
|
||||
// {a[]&b[] & c[], a[]&b[] & c[]}
|
||||
else if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true;
|
||||
else {
|
||||
// {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])}
|
||||
if (concatMergeable(lp->lhsp(), rp->lhsp())
|
||||
&& concatMergeable(lp->rhsp(), rp->rhsp()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Constant Replacement functions.
|
||||
@ -668,6 +718,45 @@ private:
|
||||
rrp->deleteTree();
|
||||
//nodep->dumpTree(cout, " repShiftSame_new: ");
|
||||
}
|
||||
void replaceConcatSel(AstConcat* nodep) {
|
||||
// {a[1], a[0]} -> a[1:0]
|
||||
AstSel* lselp = nodep->lhsp()->unlinkFrBack()->castSel();
|
||||
AstSel* rselp = nodep->rhsp()->unlinkFrBack()->castSel();
|
||||
int lstart = lselp->lsbConst();
|
||||
int lwidth = lselp->widthConst();
|
||||
int rstart = rselp->lsbConst();
|
||||
int rwidth = rselp->widthConst();
|
||||
|
||||
if ((rstart + rwidth) != lstart) nodep->v3fatalSrc("tried to merge two selects which are not adjacent");
|
||||
AstSel* newselp = new AstSel(lselp->fromp()->fileline(), rselp->fromp()->cloneTree(false), rstart, lwidth+rwidth);
|
||||
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
|
||||
|
||||
nodep->replaceWith(newselp);
|
||||
lselp->deleteTree(); lselp = NULL;
|
||||
rselp->deleteTree(); rselp = NULL;
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
}
|
||||
void replaceConcatMerge(AstConcat* nodep) {
|
||||
AstNodeBiop* lp = nodep->lhsp()->castNodeBiop();
|
||||
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
|
||||
AstNode* llp = lp->lhsp()->cloneTree(false);
|
||||
AstNode* lrp = lp->rhsp()->cloneTree(false);
|
||||
AstNode* rlp = rp->lhsp()->cloneTree(false);
|
||||
AstNode* rrp = rp->rhsp()->cloneTree(false);
|
||||
if (concatMergeable(lp, rp)) {
|
||||
AstConcat* newlp = new AstConcat(rlp->fileline(), llp, rlp);
|
||||
AstConcat* newrp = new AstConcat(rrp->fileline(), lrp, rrp);
|
||||
// use the lhs to replace the parent concat
|
||||
lp->lhsp()->replaceWith(newlp);
|
||||
lp->rhsp()->replaceWith(newrp);
|
||||
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::fromBool(true));
|
||||
UINFO(5, "merged "<< nodep <<endl);
|
||||
rp->unlinkFrBack()->deleteTree(); rp = NULL;
|
||||
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); nodep = NULL;
|
||||
lp->lhsp()->accept(*this);
|
||||
lp->rhsp()->accept(*this);
|
||||
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
|
||||
}
|
||||
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
|
||||
// -> EXTEND(nodep)
|
||||
// like a AstExtend{$rhsp}, but we need to set the width correctly from base node
|
||||
@ -2064,6 +2153,9 @@ private:
|
||||
// CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
|
||||
TREEOPV("AstConcat{operandConcatMove(nodep)}", "moveConcat(nodep)");
|
||||
TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())");
|
||||
// CONCAT(a[1],a[0]) -> a[1:0]
|
||||
TREEOPV("AstConcat{$lhsp->castSel(), $rhsp->castSel(), ifAdjacent($lhsp,,$rhsp)}", "replaceConcatSel(nodep)");
|
||||
TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)");
|
||||
// Common two-level operations that can be simplified
|
||||
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
|
@ -774,6 +774,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
case 'b': m_oCombine = flag; break;
|
||||
case 'c': m_oConst = flag; break;
|
||||
case 'd': m_oDedupe = flag; break;
|
||||
case 'm': m_oAssemble = flag; break;
|
||||
case 'e': m_oCase = flag; break;
|
||||
case 'f': m_oFlopGater = flag; break;
|
||||
case 'g': m_oGate = flag; break;
|
||||
@ -1319,6 +1320,7 @@ void V3Options::optimize(int level) {
|
||||
m_oSubstConst = flag;
|
||||
m_oTable = flag;
|
||||
m_oDedupe = flag;
|
||||
m_oAssemble = flag;
|
||||
// And set specific optimization levels
|
||||
if (level >= 3) {
|
||||
m_inlineMult = -1; // Maximum inlining
|
||||
|
@ -139,6 +139,7 @@ class V3Options {
|
||||
bool m_oCombine; // main switch: -Ob: common icode packing
|
||||
bool m_oConst; // main switch: -Oc: constant folding
|
||||
bool m_oDedupe; // main switch: -Od: logic deduplication
|
||||
bool m_oAssemble; // main switch: -Om: assign assemble
|
||||
bool m_oExpand; // main switch: -Ox: expansion of C macros
|
||||
bool m_oFlopGater; // main switch: -Of: flop gater detection
|
||||
bool m_oGate; // main switch: -Og: gate wire elimination
|
||||
@ -282,6 +283,7 @@ class V3Options {
|
||||
bool oCombine() const { return m_oCombine; }
|
||||
bool oConst() const { return m_oConst; }
|
||||
bool oDedupe() const { return m_oDedupe; }
|
||||
bool oAssemble() const { return m_oAssemble; }
|
||||
bool oExpand() const { return m_oExpand; }
|
||||
bool oFlopGater() const { return m_oFlopGater; }
|
||||
bool oGate() const { return m_oGate; }
|
||||
|
18
test_regress/t/t_concat_opt.pl
Executable file
18
test_regress/t/t_concat_opt.pl
Executable 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 2004 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;
|
67
test_regress/t/t_concat_opt.v
Normal file
67
test_regress/t/t_concat_opt.v
Normal file
@ -0,0 +1,67 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2004 by Jie Xu.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
integer cyc; initial cyc=1;
|
||||
|
||||
reg [31:0] in_a;
|
||||
reg [31:0] in_b;
|
||||
reg [31:0] in_c;
|
||||
reg [31:0] in_d;
|
||||
reg [31:0] in_e;
|
||||
reg [15:0] in_f;
|
||||
|
||||
|
||||
reg [31:0] out_x;
|
||||
reg [31:0] out_y;
|
||||
reg [31:0] out_z;
|
||||
reg [31:0] out_o;
|
||||
reg [31:0] out_p;
|
||||
reg [31:0] out_q;
|
||||
|
||||
assign out_x = {in_a[31:16] & in_f, in_a[15:0] & in_f};
|
||||
assign out_y = {in_a[31:18] & in_b[31:18], in_a[17:0] & in_b[17:0]};
|
||||
assign out_z = {in_c[31:14] & in_d[31:14] & in_e[31:14], in_c[13:0] & in_d[13:0] & in_e[13:0]};
|
||||
assign out_o = out_z | out_y;
|
||||
assign out_p = {in_a[31:16] & in_f | in_e[31:16], in_a[15:0] & in_f | in_e[15:0]};
|
||||
assign out_q = {{in_a[31:25] ^ in_e[31:25], in_a[24:16] ^ in_e[24:16]}, {in_a[15:5] ^ in_e[15:5], in_a[4:0] ^ in_e[4:0]}};
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
in_a <= cyc;
|
||||
in_b <= cyc + 1;
|
||||
in_c <= cyc + 3;
|
||||
in_d <= cyc + 8;
|
||||
in_e <= cyc;
|
||||
in_f <= cyc[15:0];
|
||||
|
||||
if (out_x != (in_a & {2{in_f}}))
|
||||
$stop;
|
||||
if (out_y != (in_a&in_b))
|
||||
$stop;
|
||||
if (out_z != (in_e&in_d&in_c))
|
||||
$stop;
|
||||
if (out_o != (((in_a&in_b)|(in_c&in_e&in_d))))
|
||||
$stop;
|
||||
if (out_p != (in_a & {2{in_f}} | in_e))
|
||||
$stop;
|
||||
if (out_q != (in_a ^ in_e))
|
||||
$stop;
|
||||
|
||||
if (cyc==100) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user