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; 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*) { virtual void visit(AstCFunc* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
// Link to global function // Link to global function
@ -365,13 +343,14 @@ private:
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body 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 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*) { virtual void visit(AstActive* nodep, AstNUser*) {
// Careful if adding variables here, ACTIVES can be under other ACTIVES // Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block // Need to save and restore any member state in AstUntilStable block
if (nodep->hasInitial()) { if (!m_topScopep || !nodep->stmtsp()) {
moveInitial(nodep);
}
else if (!m_topScopep || !nodep->stmtsp()) {
// Not at the top or empty block... // Not at the top or empty block...
// Only empty blocks should be leftover on the non-top. Killem. // Only empty blocks should be leftover on the non-top. Killem.
if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active"); if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active");
@ -381,6 +360,7 @@ private:
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext(); AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) { if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time // 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)) { if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
UINFO(4," sameSenseTree\n"); UINFO(4," sameSenseTree\n");
} else { } else {
@ -392,6 +372,10 @@ private:
} }
// Move statements to if // Move statements to if
m_lastIfp->addIfsp(stmtsp); 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()) { } else if (nodep->hasSettle()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc // Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function // Move statements to function

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ compile (
fails => 1, fails => 1,
expect=> expect=>
'.*%Warning-UNOPTFLAT: Widest candidate vars to split: '.*%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 ', .*%Error: Exiting due to ',
); );