Improve V3MergeCond

- Do try to merge after assignment to condition when possible.
- Do not try to merge reduced form if not the expected statement.
  This used to cause a crash.
This commit is contained in:
Geza Lore 2020-07-02 12:48:50 +01:00
parent cc50126ad3
commit a17f51eac0
3 changed files with 78 additions and 30 deletions

View File

@ -108,11 +108,11 @@ private:
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildrenConst(nodep); }
public:
// Set user1 on all referenced AstVar
void operator()(AstNode* node) {
AstNode::user1ClearTree();
iterate(node);
}
// Remove marks from AstVars (clear user1)
void clear() { AstNode::user1ClearTree(); }
// Mark all AstVars referenced by setting user1
void mark(AstNode* node) { iterate(node); }
};
class MergeCondVisitor : public AstNVisitor {
@ -239,6 +239,7 @@ private:
m_mgCondp = NULL;
m_mgLastp = NULL;
m_mgNextp = NULL;
m_markVars.clear();
}
void addToList(AstNode* nodep, AstNode* condp) {
@ -248,7 +249,7 @@ private:
m_mgFirstp = nodep;
m_mgCondp = condp;
m_listLenght = 0;
m_markVars(condp);
m_markVars.mark(condp);
}
// Add node
++m_listLenght;
@ -268,9 +269,14 @@ private:
if (AstNodeCond* const condp = extractCond(rhsp)) {
if (!m_checkMergeable(nodep)) {
// Node not mergeable.
// Finish current list if any, do not start a new one.
if (m_mgFirstp) mergeEnd();
return;
// If no current list, then this node is just special, move on.
if (!m_mgFirstp) return;
// Otherwise finish current list
mergeEnd();
// Finishing the list might make the node mergeable again, e.g.
// if the reason we could not merge was due to the condition
// being assigned, so check again and stop only if still no.
if (!m_checkMergeable(nodep)) return;
}
if (m_mgFirstp && (m_mgNextp != nodep || !condp->condp()->sameTree(m_mgCondp))) {
// Node in different list, or has different condition.
@ -282,7 +288,7 @@ private:
} else if (m_mgFirstp) {
// RHS is not a conditional, but we already started a list.
// If it's a 1-bit signal, and a mergeable assignment, try reduced forms
if (rhsp->widthMin() == 1 && m_checkMergeable(nodep)) {
if (m_mgNextp == nodep && rhsp->widthMin() == 1 && m_checkMergeable(nodep)) {
// Is it a 'lhs = cond & value' or 'lhs = value & cond'?
if (AstAnd* const andp = VN_CAST(rhsp, And)) {
if (andp->lhsp()->sameTree(m_mgCondp) || andp->rhsp()->sameTree(m_mgCondp)) {
@ -320,6 +326,7 @@ public:
m_mgLastp = NULL;
m_mgNextp = NULL;
m_listLenght = 0;
m_markVars.clear();
iterate(nodep);
}
virtual ~MergeCondVisitor() {

View File

@ -21,9 +21,9 @@ execute(
if ($Self->{vlt}) {
# Note, with vltmt this might be split differently, so only checking vlt
file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i,
10);
11);
file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i,
640);
644);
file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i,
64);
}

View File

@ -162,32 +162,73 @@ module t (/*AUTOARG*/
// Things not to merge
always @(posedge clk) begin
reg x;
reg y;
reg z;
reg w;
reg bits [63:0];
reg x;
reg y;
reg z;
reg w;
// Unpack these to test core algorithm
for (int i = 0; i < 64; i = i + 1) begin
bits[i] = crc[i];
end
// Do not merge if condition appears in an LVALUE
x = crc[0];
y = x ? crc[2] : crc[1];
x = x ? crc[3] : crc[4];
x = x ? crc[5] : crc[6];
x = bits[0];
y = x ? bits[2] : bits[1];
x = x ? bits[3] : bits[4];
x = x ? bits[5] : bits[6];
`check(x, (crc[0] ? crc[3] : crc[4]) ? crc[5] : crc[6]);
`check(y, crc[0] ? crc[2] : crc[1]);
`check(x, (bits[0] ? bits[3] : bits[4]) ? bits[5] : bits[6]);
`check(y, bits[0] ? bits[2] : bits[1]);
// However do merge when starting a new list in the same block with the
// previous condition variable, but without the condition being an LVALUE
x = cond2 ? bits[0] : bits[1];
y = cond2 & bits[2];
z = cond2 & bits[3];
w = cond2 & bits[4];
`check(x, cond2 ? bits[0] : bits[1]);
`check(y, cond2 & bits[2]);
`check(z, cond2 & bits[3]);
`check(w, cond2 & bits[4]);
// Do not merge if condition is not a pure expression
$c("int _cnt = 0;");
x = $c("_cnt++") ? crc[0] : crc[1];
y = $c("_cnt++") ? crc[2] : crc[3];
z = $c("_cnt++") ? crc[4] : crc[5];
w = $c("_cnt++") ? crc[6] : crc[7];
x = $c("_cnt++") ? bits[0] : bits[1];
y = $c("_cnt++") ? bits[2] : bits[3];
z = $c("_cnt++") ? bits[4] : bits[5];
w = $c("_cnt++") ? bits[6] : bits[7];
$c("if (_cnt != 4) abort();");
`check(x, crc[1]);
`check(y, crc[2]);
`check(z, crc[4]);
`check(w, crc[6]);
`check(x, bits[1]);
`check(y, bits[2]);
`check(z, bits[4]);
`check(w, bits[6]);
// Do not merge with assignment under other statement
x = cond2 ? bits[0] : bits[1];
if (bits[1]) begin
y = cond2 ? bits[2] : bits[3];
end
`check(x, cond2 ? bits[0] : bits[1]);
if (bits[1]) begin
`check(y, cond2 ? bits[2] : bits[3]);
end
// Do not merge with assignment under other statement
x = cond2 ? bits[0] : bits[1];
if (bits[1]) begin
y = cond2 & bits[2];
end
`check(x, cond2 ? bits[0] : bits[1]);
if (bits[1]) begin
`check(y, cond2 & bits[2]);
end
end
endmodule