Order initial statements based on variables used. Merge from bug683 branch.

This commit is contained in:
Wilson Snyder 2014-04-01 22:01:25 -04:00
parent 3b43556c41
commit 091818483a
5 changed files with 76 additions and 69 deletions

View File

@ -320,28 +320,6 @@ private:
}
nodep->deleteTree(); nodep = NULL;
}
void moveInitial(AstActive* nodep) {
// Change to CFunc
AstNode* stmtsp = nodep->stmtsp();
if (stmtsp) {
if (!m_scopep) nodep->v3fatalSrc("Initial Active not under scope\n");
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_initial__"+m_scopep->nameDotless(),
m_scopep);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(true);
stmtsp->unlinkFrBackWithNext();
funcp->addStmtsp(stmtsp);
nodep->replaceWith(funcp);
// Add top level call to it
AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
callp->argTypes("vlSymsp");
m_initFuncp->addStmtsp(callp);
} else {
nodep->unlinkFrBack();
}
nodep->deleteTree(); nodep=NULL;
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
nodep->iterateChildren(*this);
// Link to global function
@ -365,13 +343,14 @@ private:
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
else m_settleFuncp->addStmtsp(stmtsp); // else add to top level function
}
void addToInitial(AstNode* stmtsp) {
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
else m_initFuncp->addStmtsp(stmtsp); // else add to top level function
}
virtual void visit(AstActive* nodep, AstNUser*) {
// Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block
if (nodep->hasInitial()) {
moveInitial(nodep);
}
else if (!m_topScopep || !nodep->stmtsp()) {
if (!m_topScopep || !nodep->stmtsp()) {
// Not at the top or empty block...
// Only empty blocks should be leftover on the non-top. Killem.
if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active");
@ -381,6 +360,7 @@ private:
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time
if (nodep->hasInitial()) nodep->v3fatalSrc("Initial block should not have clock sensitivity");
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
UINFO(4," sameSenseTree\n");
} else {
@ -392,6 +372,10 @@ private:
}
// Move statements to if
m_lastIfp->addIfsp(stmtsp);
} else if (nodep->hasInitial()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function
addToInitial(stmtsp);
} else if (nodep->hasSettle()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function

View File

@ -690,7 +690,8 @@ class EmitCImp : EmitCStmts {
}
changep->lhsp()->iterateAndNext(*this);
if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]");
puts(" ^ ");
if (changep->lhsp()->isDouble()) puts(" != ");
else puts(" ^ ");
changep->rhsp()->iterateAndNext(*this);
if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]");
puts(")");

View File

@ -339,7 +339,8 @@ private:
varscp->user1p(newup);
}
OrderUser* up = (OrderUser*)(varscp->user1p());
return up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp);
OrderVarVertex* varVxp = up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp);
return varVxp;
}
V3GraphEdge* findEndEdge(V3GraphVertex* vertexp, AstNode* errnodep, OrderLoopEndVertex*& evertexpr) {
@ -396,41 +397,56 @@ private:
void nodeMarkCircular(OrderVarVertex* vertexp, OrderEdge* edgep) {
AstVarScope* nodep = vertexp->varScp();
nodep->circular(true);
++m_statCut[vertexp->type()];
if (edgep) ++m_statCut[edgep->type()];
if (vertexp->isClock()) {
// Seems obvious; no warning yet
//nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<<nodep->prettyName());
} else if (nodep->varp()->isSigPublic()) {
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
}
} else {
// We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more
// First v3warn not inside warnIsOff so we can see the suppressions with --debug
nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
if (v3Global.opt.reportUnoptflat()) {
// Report candidate variables for splitting
reportLoopVars(vertexp);
// Do a subgraph for the UNOPTFLAT loop
OrderGraph loopGraph;
m_graph.subtreeLoops(&OrderEdge::followComboConnected,
vertexp, &loopGraph);
loopGraph.dumpDotFilePrefixedAlways("unoptflat");
OrderLogicVertex* fromLVtxp = NULL;
OrderLogicVertex* toLVtxp = NULL;
if (edgep) {
fromLVtxp = dynamic_cast<OrderLogicVertex*>(edgep->fromp());
toLVtxp = dynamic_cast<OrderLogicVertex*>(edgep->top());
}
//
if ((fromLVtxp && fromLVtxp->nodep()->castInitial())
|| (toLVtxp && toLVtxp->nodep()->castInitial())) {
// IEEE does not specify ordering between initial blocks, so we can do whatever we want
// We especially do not want to evaluate multiple times, so do not mark the edge circular
}
else {
nodep->circular(true);
++m_statCut[vertexp->type()];
if (edgep) ++m_statCut[edgep->type()];
//
if (vertexp->isClock()) {
// Seems obvious; no warning yet
//nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<<nodep->prettyName());
} else if (nodep->varp()->isSigPublic()) {
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
}
} else {
// We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more
// First v3warn not inside warnIsOff so we can see the suppressions with --debug
nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
if (v3Global.opt.reportUnoptflat()) {
// Report candidate variables for splitting
reportLoopVars(vertexp);
// Do a subgraph for the UNOPTFLAT loop
OrderGraph loopGraph;
m_graph.subtreeLoops(&OrderEdge::followComboConnected,
vertexp, &loopGraph);
loopGraph.dumpDotFilePrefixedAlways("unoptflat");
}
}
}
}
@ -580,7 +596,6 @@ private:
}
virtual void visit(AstActive* nodep, AstNUser*) {
// Create required activation blocks and add to module
if (nodep->hasInitial()) return; // Ignore initials
UINFO(4," ACTIVE "<<nodep<<endl);
m_activep = nodep;
m_activeSenVxp = NULL;
@ -758,6 +773,11 @@ private:
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
virtual void visit(AstInitial* nodep, AstNUser*) {
// We use initials to setup parameters and static consts's which may be referenced
// in user initial blocks. So use ordering to sort them all out.
iterateNewStmt(nodep);
}
virtual void visit(AstCFunc*, AstNUser*) {
// Ignore for now
// We should detect what variables are set in the function, and make
@ -996,7 +1016,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
) {
UINFO(9," from d="<<(void*)fromVertexp->domainp()<<" "<<fromVertexp<<endl);
if (!domainp // First input to this vertex
|| domainp->hasSettle()) { // or, we can ignore being in the settle domain
|| domainp->hasSettle() // or, we can ignore being in the settle domain
|| domainp->hasInitial()) {
domainp = fromVertexp->domainp();
}
else if (domainp->hasCombo()) {
@ -1006,7 +1027,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
// Any combo input means this vertex must remain combo
domainp = m_comboDomainp;
}
else if (fromVertexp->domainp()->hasSettle()) {
else if (fromVertexp->domainp()->hasSettle()
|| fromVertexp->domainp()->hasInitial()) {
// Ignore that we have a constant (initial) input
}
else if (domainp != fromVertexp->domainp()) {

View File

@ -13,9 +13,9 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
q{created tag with scope = top.v.tag
created tag with scope = top.v.b.gen[0].tag
q{created tag with scope = top.v.b.gen[0].tag
created tag with scope = top.v.b.gen[1].tag
created tag with scope = top.v.tag
mod a has scope = top.v
mod a has tag = top.v.tag
mod b has scope = top.v.b

View File

@ -15,7 +15,7 @@ compile (
fails => 1,
expect=>
'.*%Warning-UNOPTFLAT: Widest candidate vars to split:
%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:\d+: v.x, width 3, fanout 12
%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:\d+: v.x, width 3, fanout \d+
.*%Error: Exiting due to ',
);