virtual void visit(AstScopeName* nodep, AstNUser*) {
     // If there's a %m in the display text, we add a special node that will contain the name()
     // Similar code in V3Begin
     // To keep correct visual order, must add before other Text's
     AstNode* afterp = nodep->scopeAttrp();
     if (afterp) afterp->unlinkFrBackWithNext();
     nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
     if (afterp) nodep->scopeAttrp(afterp);
     afterp = nodep->scopeEntrp();
     if (afterp) afterp->unlinkFrBackWithNext();
     nodep->scopeEntrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
     if (afterp) nodep->scopeEntrp(afterp);
     nodep->iterateChildren(*this);
 }
    virtual void visit(AstGenIf* nodep, AstNUser*) {
	UINFO(9,"  GENIF "<<nodep<<endl);
	nodep->condp()->iterateAndNext(*this);
	// We suppress errors when widthing params since short-circuiting in
	// the conditional evaluation may mean these error can never occur. We
	// then make sure that short-circuiting is used by constifyParamsEdit.
	V3Width::widthGenerateParamsEdit(nodep);  // Param typed widthing will
						  // NOT recurse the body.
	V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change
	if (AstConst* constp = nodep->condp()->castConst()) {
	    AstNode* keepp = (constp->isZero()
			      ? nodep->elsesp()
			      : nodep->ifsp());
	    if (keepp) {
		keepp->unlinkFrBackWithNext();
		nodep->replaceWith(keepp);
	    } else {
		nodep->unlinkFrBack();
	    }
	    nodep->deleteTree(); nodep=NULL;
	    // Normal edit rules will now recurse the replacement
	} else {
	    nodep->condp()->v3error("Generate If condition must evaluate to constant");
	}
    }
Esempio n. 3
0
    virtual void visit(AstRepeat* nodep, AstNUser*) {
	// So later optimizations don't need to deal with them,
	//    REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
	// Note var can be signed or unsigned based on original number.
	AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
   	string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
	// Spec says value is integral, if negative is ignored
	AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
				  nodep->findSigned32DType());
	varp->usedLoopIdx(true);
	m_modp->addStmtp(varp);
	AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
					countp);
	AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
				      new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
						 new AstConst(nodep->fileline(), 1)));
	V3Number zero (nodep->fileline(), 32, 0);  zero.isSigned(true);
	AstNode* zerosp = new AstConst(nodep->fileline(), zero);
	AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
				    zerosp);
	AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
	AstNode* newp = new AstWhile(nodep->fileline(),
				     condp,
				     bodysp,
				     decp);
	initsp = initsp->addNext(newp);
	newp = initsp;
	nodep->replaceWith(newp);
	nodep->deleteTree(); VL_DANGLING(nodep);
    }
Esempio n. 4
0
    void newVAssertion(AstVAssert* nodep, AstNode* propp) {
	propp->unlinkFrBackWithNext();
	AstNode* passsp = nodep->passsp(); if (passsp) passsp->unlinkFrBackWithNext();
	AstNode* failsp = nodep->failsp(); if (failsp) failsp->unlinkFrBackWithNext();
	//
	if (nodep->castVAssert()) {
	    if (passsp) passsp = newIfAssertOn(passsp);
	    if (failsp) failsp = newIfAssertOn(failsp);
	} else {
	    nodep->v3fatalSrc("Unknown node type");
	}

	AstIf* ifp = new AstIf (nodep->fileline(), propp, passsp, failsp);
	AstNode* newp = ifp;
	if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
	//
	// Install it
	nodep->replaceWith(newp);
	// Bye
	pushDeletep(nodep); nodep=NULL;
    }
Esempio n. 5
0
    virtual void visit(AstScopeName* nodep, AstNUser*) {
	// If there's a %m in the display text, we add a special node that will contain the name()
	string prefix = (string)("__DOT__")+m_scopep->name();
	// TOP and above will be the user's name().
	// Note 'TOP.' is stripped by scopePrettyName
	// To keep correct visual order, must add before other Text's
	AstNode* afterp = nodep->scopeAttrp();
	if (afterp) afterp->unlinkFrBackWithNext();
	nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
	if (afterp) nodep->scopeAttrp(afterp);
	nodep->iterateChildren(*this);
    }
    virtual void visit(AstScopeName* nodep, AstNUser*) {
	// If there's a %m in the display text, we add a special node that will contain the name()
	// Similar code in V3Inline
	if (nodep->user1SetOnce()) return;  // Don't double-add text's
	if (m_namedScope != "") {
	    // To keep correct visual order, must add before other Text's
	    AstNode* afterp = nodep->scopeAttrp();
	    if (afterp) afterp->unlinkFrBackWithNext();
	    nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_namedScope));
	    if (afterp) nodep->scopeAttrp(afterp);
	}
	nodep->iterateChildren(*this);
    }
Esempio n. 7
0
    AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
	// Put label under given node, and if WHILE optionally at end of iteration
	UINFO(4,"Create label for "<<nodep<<endl);
	if (nodep->castJumpLabel()) return nodep->castJumpLabel(); // Done

	AstNode* underp = NULL;
	bool     under_and_next = true;
	if (nodep->castBegin()) underp = nodep->castBegin()->stmtsp();
	else if (nodep->castNodeFTask()) underp = nodep->castNodeFTask()->stmtsp();
	else if (nodep->castWhile()) {
	    if (endOfIter) {
		// Note we jump to end of bodysp; a FOR loop has its increment under incsp() which we don't skip
		underp = nodep->castWhile()->bodysp();
	    } else {
		underp = nodep; under_and_next=false; // IE we skip the entire while
	    }
	}
	else {
	    nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
	    return NULL;
	}
	// Skip over variables as we'll just move them in a momement
	// Also this would otherwise prevent us from using a label twice
	// see t_func_return test.
	while (underp && underp->castVar()) underp = underp->nextp();
	if (underp) UINFO(5,"  Underpoint is "<<underp<<endl);

	if (!underp) {
	    nodep->v3fatalSrc("Break/disable/continue not under expected statement");
	    return NULL;
	} else if (underp->castJumpLabel()) {
	    return underp->castJumpLabel();
	} else { // Move underp stuff to be under a new label
	    AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);

	    AstNRelinker repHandle;
	    if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
	    else underp->unlinkFrBack(&repHandle);
	    repHandle.relink(labelp);

	    labelp->addStmtsp(underp);
	    // Keep any AstVars under the function not under the new JumpLabel
	    for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
		nextp = varp->nextp();
		if (varp->castVar()) {
		    labelp->addPrev(varp->unlinkFrBack());
		}
	    }
	    return labelp;
	}
    }
    virtual void visit(AstGenCase* nodep, AstNUser*) {
	UINFO(9,"  GENCASE "<<nodep<<endl);
	AstNode* keepp = NULL;
	nodep->exprp()->iterateAndNext(*this);
	V3Case::caseLint(nodep);
	V3Width::widthParamsEdit(nodep);  // Param typed widthing will NOT recurse the body,
					  // don't trigger errors yet.
	V3Const::constifyParamsEdit(nodep->exprp());  // exprp may change
	AstConst* exprp = nodep->exprp()->castConst();
	// Constify
	for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
	    for (AstNode* ep = itemp->condsp(); ep; ) {
		AstNode* nextp = ep->nextp(); //May edit list
		ep->iterateAndNext(*this);
		V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change
		// cppcheck-suppress redundantAssignment
		ep = nextp;
	    }
	}
	// Item match
	for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
	    if (!itemp->isDefault()) {
		for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) {
		    if (AstConst* ccondp = ep->castConst()) {
			V3Number match (nodep->fileline(), 1);
			match.opEq(ccondp->num(), exprp->num());
			if (!keepp && match.isNeqZero()) {
			    keepp = itemp->bodysp();
			}
		    } else {
			itemp->v3error("Generate Case item does not evaluate to constant");
		    }
		}
	    }
	}
	// Else default match
	for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
	    if (itemp->isDefault()) {
		if (!keepp) keepp=itemp->bodysp();
	    }
	}
	// Replace
	if (keepp) {
	    keepp->unlinkFrBackWithNext();
	    nodep->replaceWith(keepp);
	}
	else nodep->unlinkFrBack();
	nodep->deleteTree(); nodep=NULL;
    }
Esempio n. 9
0
    virtual void visit(AstCell* nodep, AstNUser*) {
	if (nodep->modp()->user1()) {  // Marked with inline request
	    UINFO(5," Inline CELL   "<<nodep<<endl);
	    UINFO(5,"   To MOD      "<<m_modp<<endl);
	    ++m_statCells;

	    // Before cloning simplify pin assignments
	    // Better off before, as if module has multiple instantiations
	    // we'll save work, and we can't call pinReconnectSimple in
	    // this loop as it clone()s itself.
	    for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
		if (!pinp->exprp()) continue;
		V3Inst::pinReconnectSimple(pinp, nodep, m_modp, false);
	    }

	    // Clone original module
	    if (debug()>=9) { nodep->dumpTree(cout,"inlcell:"); }
	    //if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
	    AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
	    if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); }
	    // Clear var markings and find cell cross references
	    AstNode::user2ClearTree();
	    AstNode::user4ClearTree();
	    { InlineCollectVisitor(nodep->modp()); }  // {} to destroy visitor immediately
	    // Create data for dotted variable resolution
	    AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
						       nodep->name(), nodep->modp()->origName());
	    m_modp->addInlinesp(inlinep);  // Must be parsed before any AstCells
	    // Create assignments to the pins
	    for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
		if (!pinp->exprp()) continue;
		UINFO(6,"     Pin change from "<<pinp->modVarp()<<endl);
		// Make new signal; even though we'll optimize the interconnect, we
		// need an alias to trace correctly.  If tracing is disabled, we'll
		// delete it in later optimizations.
		AstVar* pinOldVarp = pinp->modVarp();
		AstVar* pinNewVarp = pinOldVarp->clonep()->castVar();

		AstNode* connectRefp = pinp->exprp();
		if (!connectRefp->castConst() && !connectRefp->castVarRef()) {
		    pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
		}
		if (pinNewVarp->isOutOnly() && connectRefp->castConst()) {
		    pinp->v3error("Output port is connected to a constant pin, electrical short");
		}

		// Propagate any attributes across the interconnect
		pinNewVarp->propagateAttrFrom(pinOldVarp);
		if (connectRefp->castVarRef()) {
		    connectRefp->castVarRef()->varp()->propagateAttrFrom(pinOldVarp);
		}

		// One to one interconnect won't make a temporary variable.
		// This prevents creating a lot of extra wires for clock signals.
		// It will become a tracing alias.
		UINFO(6,"One-to-one "<<connectRefp<<endl);
		UINFO(6,"       -to "<<pinNewVarp<<endl);
		pinNewVarp->user2p(connectRefp);
		// Public output inside the cell must go via an assign rather than alias
		// Else the public logic will set the alias, loosing the value to be propagated up
		// (InOnly isn't a problem as the AssignAlias will create the assignment for us)
		pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
	    }
	    // Cleanup var names, etc, to not conflict
	    { InlineRelinkVisitor(newmodp, m_modp, nodep); }
	    // Move statements to top module
	    if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
	    AstNode* stmtsp = newmodp->stmtsp();
	    if (stmtsp) stmtsp->unlinkFrBackWithNext();
	    if (stmtsp) m_modp->addStmtp(stmtsp);
	    // Remove the cell
	    newmodp->deleteTree(); newmodp=NULL; // Clear any leftover ports, etc
	    nodep->unlinkFrBack();
	    pushDeletep(nodep); nodep = NULL;
	    if (debug()>=9) { m_modp->dumpTree(cout,"donemod:"); }
	}
    }
Esempio n. 10
0
    void replaceCaseComplicated(AstCase* nodep) {
	// CASEx(cexpr,ITEM(icond1,istmts1),ITEM(icond2,istmts2),ITEM(default,istmts3))
	// ->  IF((cexpr==icond1),istmts1,
	//		         IF((EQ (AND MASK cexpr) (AND MASK icond1)
	//				,istmts2, istmts3
	AstNode* cexprp = nodep->exprp()->unlinkFrBack();
	// We'll do this in two stages.  First stage, convert the conditions to
	// 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()) {
	    if (!itemp->condsp()) {
		// Default clause.  Just make true, we'll optimize it away later
		itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
		hadDefault = true;
	    } else {
		// Expressioned clause
		AstNode* icondNextp = NULL;
		AstNode* ifexprp = NULL;	// If expression to test
		for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) {
		    icondNextp = icondp->nextp();
		    icondp->unlinkFrBack();

		    AstNode* condp = NULL;  // Default is to use and1p/and2p
		    AstConst* iconstp = icondp->castConst();
		    if (iconstp && neverItem(nodep, iconstp)) {
			// X in casez can't ever be executed
			icondp->deleteTree(); icondp=NULL; iconstp=NULL;
			// For simplicity, make expression that is not equal, and let later
			// optimizations remove it
			condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
		    } else if (AstInsideRange* irangep = icondp->castInsideRange()) {
			// Similar logic in V3Width::visit(AstInside)
			AstNode* ap = AstGte::newTyped(itemp->fileline(),
						       cexprp->cloneTree(false),
						       irangep->lhsp()->unlinkFrBack());
			AstNode* bp = AstLte::newTyped(itemp->fileline(),
						       cexprp->cloneTree(false),
						       irangep->rhsp()->unlinkFrBack());
			condp = new AstAnd(itemp->fileline(), ap, bp);
		    } else if (iconstp && iconstp->num().isFourState()
			       && (nodep->casex() || nodep->casez() || nodep->caseInside())) {
			V3Number nummask (itemp->fileline(), iconstp->width());
			nummask.opBitsNonX(iconstp->num());
			V3Number numval  (itemp->fileline(), iconstp->width());
			numval.opBitsOne(iconstp->num());
			AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
						    new AstConst(itemp->fileline(), nummask));
			AstNode* and2p = new AstAnd(itemp->fileline(),
						    new AstConst(itemp->fileline(), numval),
						    new AstConst(itemp->fileline(), nummask));
			icondp->deleteTree(); icondp=NULL; iconstp=NULL;
			condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
		    } else {
			// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
			AstNode* and1p = cexprp->cloneTree(false);
			AstNode* and2p = icondp;
			condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
		    }
		    if (!ifexprp) {
			ifexprp = condp;
		    } else {
			ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp);
		    }
		}
		// Replace expression in tree
		itemp->condsp(ifexprp);
	    }
	}
	cexprp->deleteTree(); cexprp=NULL;
	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(), AstConst::LogicTrue()),
					     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(), AstConst::LogicTrue());
		}
		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
	replaceCaseParallel(nodep, false);
	// Replace the CASE... with IF...
	if (debug()>=9) grouprootp->dumpTree(cout,"     _new: ");
	if (grouprootp) nodep->replaceWith(grouprootp);
	else nodep->unlinkFrBack();
	nodep->deleteTree(); nodep=NULL;
    }