Reduce depth of priority encoded case statements.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@848 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
100d5b386c
commit
52e36fb434
2
Changes
2
Changes
|
|
@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
*** When dotted signal lookup fails, help the user by showing known scopes.
|
*** When dotted signal lookup fails, help the user by showing known scopes.
|
||||||
|
|
||||||
|
*** Reduce depth of priority encoded case statements. [Eugene Weber]
|
||||||
|
|
||||||
**** Fix dotted references inside generated cells. [David Hewson]
|
**** Fix dotted references inside generated cells. [David Hewson]
|
||||||
|
|
||||||
**** Fix missed split optimization points underneath other re-split blocks.
|
**** Fix missed split optimization points underneath other re-split blocks.
|
||||||
|
|
|
||||||
|
|
@ -1167,6 +1167,7 @@ public:
|
||||||
virtual int instrCount() const { return widthInstrs()+instrCountBranch(); }
|
virtual int instrCount() const { return widthInstrs()+instrCountBranch(); }
|
||||||
AstNode* condsp() const { return op1p()->castNode(); } // op1= list of possible matching expressions
|
AstNode* condsp() const { return op1p()->castNode(); } // op1= list of possible matching expressions
|
||||||
AstNode* bodysp() const { return op2p()->castNode(); } // op2= what to do
|
AstNode* bodysp() const { return op2p()->castNode(); } // op2= what to do
|
||||||
|
void condsp(AstNode* nodep) { setOp1p(nodep); }
|
||||||
void addBodysp(AstNode* newp) { addOp2p(newp); }
|
void addBodysp(AstNode* newp) { addOp2p(newp); }
|
||||||
bool isDefault() const { return condsp()==NULL; }
|
bool isDefault() const { return condsp()==NULL; }
|
||||||
bool ignoreOverlap() const { return m_ignoreOverlap; }
|
bool ignoreOverlap() const { return m_ignoreOverlap; }
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
|
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
|
||||||
#define CASE_BARF 999999 // Magic width when non-constant
|
#define CASE_BARF 999999 // Magic width when non-constant
|
||||||
|
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
|
|
@ -275,21 +276,15 @@ private:
|
||||||
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
|
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
|
||||||
// ,istmts2, istmts3
|
// ,istmts2, istmts3
|
||||||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||||
AstNode* ifrootp = NULL;
|
// We'll do this in two stages. First stage, convert the conditions to
|
||||||
AstNode* ifnextp = NULL;
|
// the appropriate IF AND terms.
|
||||||
|
if (debug()>=9) nodep->dumpTree(cout," _comp_IN: ");
|
||||||
|
bool hadDefault = false;
|
||||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||||
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
|
||||||
if (istmtsp) istmtsp->unlinkFrBackWithNext();
|
|
||||||
if (!itemp->condsp()) {
|
if (!itemp->condsp()) {
|
||||||
// Default clause. We reordered in link, so default is always last
|
// Default clause. Just make true, we'll optimize it away later
|
||||||
if (ifnextp) {
|
itemp->condsp(new AstConst(itemp->fileline(), V3Number(itemp->fileline(), 1,1)));
|
||||||
if (istmtsp) ifnextp->castIf()->addElsesp(istmtsp);
|
hadDefault = true;
|
||||||
} else { // Just a empty case default: endcase
|
|
||||||
ifnextp = istmtsp;
|
|
||||||
}
|
|
||||||
if (!ifrootp) ifrootp = istmtsp;
|
|
||||||
ifnextp = istmtsp;
|
|
||||||
itemp = NULL; break;
|
|
||||||
} else {
|
} else {
|
||||||
// Expressioned clause
|
// Expressioned clause
|
||||||
AstNode* icondNextp = NULL;
|
AstNode* icondNextp = NULL;
|
||||||
|
|
@ -324,24 +319,67 @@ private:
|
||||||
ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp);
|
ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Replace expression in tree
|
||||||
// Make the new IF and attach in the tree
|
itemp->condsp(ifexprp);
|
||||||
if (ifexprp) {
|
|
||||||
AstIf* newp = new AstIf(itemp->fileline(), ifexprp, istmtsp, NULL);
|
|
||||||
if (ifnextp) {
|
|
||||||
ifnextp->castIf()->addElsesp(newp);
|
|
||||||
}
|
|
||||||
if (!ifrootp) ifrootp = newp;
|
|
||||||
ifnextp = newp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hadDefault) {
|
||||||
|
// If there was no default, add a empty one, this greatly simplifies below code
|
||||||
|
// and constant propagation will just eliminate it for us later.
|
||||||
|
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
|
||||||
|
new AstConst(nodep->fileline(), V3Number(nodep->fileline(),1,1)),
|
||||||
|
NULL));
|
||||||
|
}
|
||||||
|
if (debug()>=9) nodep->dumpTree(cout," _comp_COND: ");
|
||||||
|
// Now build the IF statement tree
|
||||||
|
// The tree can be quite huge. Pull ever group of 8 out, and make a OR tree.
|
||||||
|
// This reduces the depth for the bottom elements, at the cost of some of the top elements.
|
||||||
|
// If we ever have profiling data, we should pull out the most common item from here and
|
||||||
|
// instead make it the first IF branch.
|
||||||
|
int depth = 0;
|
||||||
|
AstNode* grouprootp = NULL;
|
||||||
|
AstIf* groupnextp = NULL;
|
||||||
|
AstIf* itemnextp = NULL;
|
||||||
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||||
|
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
||||||
|
if (istmtsp) istmtsp->unlinkFrBackWithNext();
|
||||||
|
// Expressioned clause
|
||||||
|
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
|
||||||
|
{ // Prepare for next group
|
||||||
|
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||||
|
if (depth == 1) { // First group or starting new group
|
||||||
|
itemnextp = NULL;
|
||||||
|
AstIf* newp = new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
|
||||||
|
if (groupnextp) groupnextp->addElsesp(newp);
|
||||||
|
else grouprootp = newp;
|
||||||
|
groupnextp = newp;
|
||||||
|
} else { // Continue group, modify if condition to OR in this new condition
|
||||||
|
AstNode* condp = groupnextp->condp()->unlinkFrBack();
|
||||||
|
groupnextp->condp(new AstOr(ifexprp->fileline(),
|
||||||
|
condp,
|
||||||
|
ifexprp->cloneTree(true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ // Make the new lower IF and attach in the tree
|
||||||
|
AstNode* itemexprp = ifexprp; ifexprp=NULL;
|
||||||
|
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
|
||||||
|
itemexprp->deleteTree(); itemexprp=NULL;
|
||||||
|
itemexprp = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,1));
|
||||||
|
}
|
||||||
|
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||||
|
if (itemnextp) itemnextp->addElsesp(newp);
|
||||||
|
else groupnextp->addIfsp(newp); // First in a new group
|
||||||
|
itemnextp = newp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debug()>=9) nodep->dumpTree(cout," _comp_TREE: ");
|
||||||
// Handle any assertions
|
// Handle any assertions
|
||||||
replaceCaseParallel(nodep, false);
|
replaceCaseParallel(nodep, false);
|
||||||
// Replace the CASE... with IF...
|
// Replace the CASE... with IF...
|
||||||
if (ifrootp) nodep->replaceWith(ifrootp);
|
if (debug()>=9) grouprootp->dumpTree(cout," _new: ");
|
||||||
|
if (grouprootp) nodep->replaceWith(grouprootp);
|
||||||
else nodep->unlinkFrBack();
|
else nodep->unlinkFrBack();
|
||||||
if (debug()>=9) ifrootp->dumpTree(cout," _new: ");
|
nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
|
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue