Ejemplo n.º 1
0
    AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
	// Return lhs-rhs, but if rhs is negative use an add, so we won't
	// have to deal with signed math and related 32bit sign extension problems
	if (rhs == 0) {
	    return lhsp;
	} else if (lhsp->castConst()) {
	    // Optional vs just making add/sub below, but saves constification some work
	    V3Number num (lhsp->fileline(), lhsp->width());
	    num.opSub(lhsp->castConst()->num(), V3Number(lhsp->fileline(), 32, rhs));
	    num.isSigned(lhsp->isSigned());
	    AstNode* newp = new AstConst(lhsp->fileline(), num);
	    return newp;
	} else if (rhs > 0) {
	    AstNode* newp = new AstSub(lhsp->fileline(), lhsp,
				       new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
	    // We must make sure sub gets sign of original value, not from the constant
	    newp->dtypeFrom(lhsp);
	    return newp;
	} else {  // rhs < 0;
	    AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
				       new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
	    // We must make sure sub gets sign of original value, not from the constant
	    newp->dtypeFrom(lhsp);
	    return newp;
	}
    }
Ejemplo n.º 2
0
    bool countLoops(AstAssign *initp, AstNode *condp, AstNode *incp, int max, int &outLoopsr) {
	outLoopsr = 0;
	V3Number loopValue = V3Number(initp->fileline());
	if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
	    return false;
	}
	while (1) {
	    V3Number res = V3Number(initp->fileline());
	    if (!simulateTree(condp, &loopValue, NULL, res)) {
		return false;
	    }
	    if (!res.isEqOne()) {
		break;
	    }

	    outLoopsr++;

	    // Run inc
	    AstAssign* incpass = incp->castAssign();
	    V3Number newLoopValue = V3Number(initp->fileline());
	    if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) {
		return false;
	    }
	    loopValue.opAssign(newLoopValue);
	    if (outLoopsr > max) {
		return false;
	    }
	}
	return true;
    }
Ejemplo 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);
    }
    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;
    }
Ejemplo n.º 5
0
    void visit(AstSel* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (!nodep->user1Inc()) {
	    // Guard against reading/writing past end of bit vector array
	    int maxmsb = 0;
	    bool lvalue = false;
	    AstNode* basefromp = AstArraySel::baseFromp(nodep);
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
		maxmsb = (varrefp->varp()->width()-1);
	    } else {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
		maxmsb = basefromp->width()-1;
	    }
	    int maxlsb = maxmsb - nodep->width() + 1;
	    if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
	    V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);

	    // See if the condition is constant true
	    AstNode* condp = new AstLte (nodep->fileline(),
					 nodep->lsbp()->cloneTree(false),
					 new AstConst(nodep->fileline(), maxlsbnum));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue) {
		// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else { // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
Ejemplo n.º 6
0
    virtual void visit(AstSel* nodep) {
	nodep->iterateChildren(*this);
	if (!nodep->user1SetOnce()) {
	    // Guard against reading/writing past end of bit vector array
	    AstNode* basefromp = AstArraySel::baseFromp(nodep);
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
	    }
	    // Find range of dtype we are selecting from
	    // Similar code in V3Const::warnSelect
	    int maxmsb = nodep->fromp()->dtypep()->width()-1;
	    if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
	    V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb);

	    // If (maxmsb >= selected), we're in bound
	    AstNode* condp = new AstGte (nodep->fileline(),
					 new AstConst(nodep->fileline(), maxmsbnum),
					 nodep->lsbp()->cloneTree(false));
	    // See if the condition is constant true (e.g. always in bound due to constant select)
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue) {
		// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else { // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
Ejemplo n.º 7
0
    void visitEqNeqWild(AstNodeBiop* nodep) {
	UINFO(4," N/EQWILD->EQ "<<nodep<<endl);
	V3Const::constifyEdit(nodep->lhsp());  // lhsp may change
	V3Const::constifyEdit(nodep->rhsp());  // rhsp may change
	if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) {
	    // Both sides are constant, node can be constant
	    V3Const::constifyEdit(nodep); VL_DANGLING(nodep);
	    return;
	} else {
	    AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
	    AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
	    AstNode* newp;
	    if (!rhsp->castConst()) {
		nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable");  // Says spec.
		// Replace with anything that won't cause more errors
		newp = new AstEq (nodep->fileline(), lhsp, rhsp);
	    } else {
		// X or Z's become mask, ala case statements.
		V3Number nummask  (rhsp->fileline(), rhsp->width());
		nummask.opBitsNonX(rhsp->castConst()->num());
		V3Number numval   (rhsp->fileline(), rhsp->width());
		numval.opBitsOne  (rhsp->castConst()->num());
		AstNode* and1p = new AstAnd(nodep->fileline(), lhsp,
					    new AstConst(nodep->fileline(), nummask));
		AstNode* and2p = new AstConst(nodep->fileline(), numval);
		if (nodep->castEqWild())
		    newp  = new AstEq  (nodep->fileline(), and1p, and2p);
		else newp = new AstNeq (nodep->fileline(), and1p, and2p);
		rhsp->deleteTree(); VL_DANGLING(rhsp);
	    }
	    nodep->replaceWith(newp);
	    nodep->deleteTree(); VL_DANGLING(nodep);
	    // Iterate tree now that we may have gotten rid of the compare
	    newp->iterateChildren(*this);
	}
    }
Ejemplo n.º 8
0
    bool forUnroller(AstNode* nodep,
		     AstAssign* initp,
		     AstNode* condp,
		     AstNode* precondsp,
		     AstNode* incp, AstNode* bodysp) {
	V3Number loopValue = V3Number(nodep->fileline());
	if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
	    return false;
	}
	AstNode* stmtsp = NULL;
	if (initp) {
	    initp->unlinkFrBack();	// Always a single statement; nextp() may be nodep
	    // Don't add to list, we do it once, and setting loop index isn't needed as we're constant propagating it
	}
	if (precondsp) {
	    precondsp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(precondsp);
	}
	if (bodysp) {
	    bodysp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(bodysp);  // Maybe null if no body
	}
	if (incp && !nodep->castGenFor()) {  // Generates don't need to increment loop index
	    incp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(incp);  // Maybe null if no body
	}
	// Mark variable to disable some later warnings
	m_forVarp->usedLoopIdx(true);

	AstNode* newbodysp = NULL;
	++m_statLoops;
	if (stmtsp) {
	    int times = 0;
	    while (1) {
		UINFO(8,"      Looping "<<loopValue<<endl);
		V3Number res = V3Number(nodep->fileline());
		if (!simulateTree(condp, &loopValue, NULL, res)) {
		    nodep->v3error("Loop unrolling failed.");
		    return false;
		}
		if (!res.isEqOne()) {
		    break;  // Done with the loop
		}
		else {
		    // Replace iterator values with constant.
		    AstNode* oneloopp = stmtsp->cloneTree(true);

		    m_varValuep = new AstConst(nodep->fileline(), loopValue);

		    // Iteration requires a back, so put under temporary node
		    if (oneloopp) {
			AstBegin* tempp = new AstBegin(oneloopp->fileline(),"[EditWrapper]",oneloopp);
			m_varModeReplace = true;
			tempp->stmtsp()->iterateAndNext(*this);
			m_varModeReplace = false;
			oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); VL_DANGLING(tempp);
		    }
		    if (m_generate) {
			string index = AstNode::encodeNumber(m_varValuep->toSInt());
			string nname = m_beginName + "__BRA__" + index + "__KET__";
			oneloopp = new AstBegin(oneloopp->fileline(),nname,oneloopp,true);
		    }
		    pushDeletep(m_varValuep); m_varValuep=NULL;
		    if (newbodysp) newbodysp->addNext(oneloopp);
		    else newbodysp = oneloopp;

		    ++m_statIters;
		    if (++times > unrollCount()*3) {
			nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<<unrollCount());
			break;
		    }

		    // loopValue += valInc
		    AstAssign *incpass = incp->castAssign();
		    V3Number newLoopValue = V3Number(nodep->fileline());
		    if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) {
			nodep->v3error("Loop unrolling failed");
			return false;
		    }
		    loopValue.opAssign(newLoopValue);
		}
	    }
	}
	// Replace the FOR()
	if (newbodysp) nodep->replaceWith(newbodysp);
	else nodep->unlinkFrBack();
	if (bodysp) { pushDeletep(bodysp); VL_DANGLING(bodysp); }
	if (precondsp) { pushDeletep(precondsp); VL_DANGLING(precondsp); }
	if (initp) { pushDeletep(initp); VL_DANGLING(initp); }
	if (incp && !incp->backp()) { pushDeletep(incp); VL_DANGLING(incp); }
	if (debug()>=9) newbodysp->dumpTree(cout,"-  _new: ");
	return true;
    }
Ejemplo n.º 9
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;
    }
Ejemplo n.º 10
0
    bool isCaseTreeFast(AstCase* nodep) {
	int width = 0;
	bool opaque = false;
	m_caseItems = 0;
	m_caseNoOverlapsAllCovered = true;
	for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
	    for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
		if (icondp->width() > width) width = icondp->width();
		if (icondp->isDouble()) opaque = true;
		if (!icondp->castConst()) width = CASE_BARF;  // Can't parse; not a constant
		m_caseItems++;
	    }
	}
	m_caseWidth = width;
	if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
	    m_caseNoOverlapsAllCovered = false;
	    return false;	// Too wide for analysis
	}
	UINFO(8,"Simple case statement: "<<nodep<<endl);
	// Zero list of items for each value
	for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) m_valueItem[i] = NULL;
	// Now pick up the values for each assignment
	// We can cheat and use uint32_t's because we only support narrow case's
	bool bitched = false;
	for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
	    for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
		//if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
		AstConst* iconstp = icondp->castConst();
		if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this\n");
		if (neverItem(nodep, iconstp)) {
		    // X in casez can't ever be executed
		} else {
		    V3Number nummask (itemp->fileline(), iconstp->width());
		    nummask.opBitsNonX(iconstp->num());
		    uint32_t mask = nummask.toUInt();
		    V3Number numval  (itemp->fileline(), iconstp->width());
		    numval.opBitsOne(iconstp->num());
		    uint32_t val  = numval.toUInt();
		    for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
			if ((i & mask) == val) {
			    if (!m_valueItem[i]) {
				m_valueItem[i] = itemp;
			    } else if (!itemp->ignoreOverlap() && !bitched) {
				itemp->v3warn(CASEOVERLAP,"Case values overlap (example pattern 0x"<<hex<<i<<")");
				bitched = true;
				m_caseNoOverlapsAllCovered = false;
			    }
			}
		    }
		}
	    }
	    // Defaults were moved to last in the caseitem list by V3LinkDot
	    if (itemp->isDefault()) {  // Case statement's default... Fill the table
		for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
		    if (!m_valueItem[i]) m_valueItem[i] = itemp;
		}
	    }
	}
	for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
	    if (!m_valueItem[i]) {
		nodep->v3warn(CASEINCOMPLETE,"Case values incompletely covered (example pattern 0x"<<hex<<i<<")");
		m_caseNoOverlapsAllCovered = false;
		return false;
	    }
	}
	if (m_caseItems <= 3) return false;	// Not worth simplifing
	// Convert valueItem from AstCaseItem* to the expression
	// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
	for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
	    m_valueItem[i] = m_valueItem[i]->castCaseItem()->bodysp();
	}
	return true;  // All is fine
    }
Ejemplo n.º 11
0
    void forUnroller(AstNode* nodep,
		     AstNode* initp,
		     AstNode* precondsp, AstNode* condp,
		     AstNode* incp, AstNode* bodysp,
		     const V3Number& numInit,
		     AstNodeBiop* cmpInstrp, const V3Number& numStop,
		     AstNodeBiop* incInstrp, const V3Number& numInc) {
	UINFO(4, "   Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl);
	UINFO(6, "    cmpI "<<cmpInstrp<<endl);
	UINFO(6, "    IncI "<<incInstrp<<endl);
	AstNode* stmtsp = NULL;
	if (initp) {
	    initp->unlinkFrBack();	// Always a single statement; nextp() may be nodep
	    // Don't add to list, we do it once, and setting loop index isn't needed as we're constant propagating it
	}
	if (precondsp) {
	    precondsp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(precondsp);
	}
	if (bodysp) {
	    bodysp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(bodysp);  // Maybe null if no body
	}
	if (incp && !nodep->castGenFor()) {  // Generates don't need to increment loop index
	    incp->unlinkFrBackWithNext();
	    // cppcheck-suppress nullPointer  // addNextNull deals with it
	    stmtsp = stmtsp->addNextNull(incp);  // Maybe null if no body
	}
	// Mark variable to disable some later warnings
	m_forVarp->usedLoopIdx(true);

	// If it's a While, then incp is already part of bodysp.
	V3Number loopValue(nodep->fileline(), m_forVarp->width());  // May differ in size from numInitp
	loopValue.opAssign(numInit);

	AstNode* newbodysp = NULL;
	++m_statLoops;
	if (stmtsp) {
	    int times = 0;
	    while (1) {
		UINFO(8,"      Looping "<<loopValue<<endl);
		// if loopValue<valStop
		V3Number contin (nodep->fileline(), 1);
		cmpInstrp->numberOperate(contin, loopValue, numStop);
		if (contin.isEqZero()) {
		    break;  // Done with the loop
		} else {
		    // Replace iterator values with constant.
		    AstNode* oneloopp = stmtsp->cloneTree(true);

		    m_varValuep = new AstConst(nodep->fileline(), loopValue);

		    // Iteration requires a back, so put under temporary node
		    if (oneloopp) {
			AstBegin* tempp = new AstBegin(oneloopp->fileline(),"[EditWrapper]",oneloopp);
			m_varModeReplace = true;
			tempp->stmtsp()->iterateAndNext(*this);
			m_varModeReplace = false;
			oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
		    }
		    if (m_generate) {
			string index = AstNode::encodeNumber(m_varValuep->toSInt());
			string nname = m_beginName + "__BRA__" + index + "__KET__";
			oneloopp = new AstBegin(oneloopp->fileline(),nname,oneloopp,true);
		    }

		    if (newbodysp) newbodysp->addNext(oneloopp);
		    else newbodysp = oneloopp;

		    ++m_statIters;
		    if (++times > unrollCount()*3) {
			nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<<unrollCount());
			break;
		    }

		    //loopValue += valInc
		    V3Number newnum(nodep->fileline(), m_forVarp->width());  // Can't increment in-place
		    incInstrp->numberOperate(newnum, loopValue, numInc);
		    loopValue.opAssign(newnum);

		    pushDeletep(m_varValuep); m_varValuep=NULL;
		}
	    }
	}
	// Replace the FOR()
	if (newbodysp) nodep->replaceWith(newbodysp);
	else nodep->unlinkFrBack();
	if (bodysp) { pushDeletep(bodysp); bodysp=NULL; }
	if (precondsp) { pushDeletep(precondsp); precondsp=NULL; }
	if (initp) { pushDeletep(initp); initp=NULL; }
	if (incp && !incp->backp()) { pushDeletep(incp); incp=NULL; }
	if (debug()>=9) newbodysp->dumpTree(cout,"-  _new: ");
    }
Ejemplo n.º 12
0
    virtual void visit(AstArraySel* nodep) {
	nodep->iterateChildren(*this);
	if (!nodep->user1SetOnce()) {
	    if (debug()==9) nodep->dumpTree(cout,"-in: ");
	    // Guard against reading/writing past end of arrays
	    AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		lvalue = varrefp->lvalue();
	    } else if (basefromp->castConst()) {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
	    } else {
		nodep->v3fatalSrc("No VarRef or Const under ArraySel");
	    }
	    // Find range of dtype we are selecting from
	    int declElements = -1;
	    AstNodeDType* dtypep = nodep->fromp()->dtypep()->skipRefp();
	    if (!dtypep) nodep->v3fatalSrc("Select of non-selectable type");
	    if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
		declElements = adtypep->elementsConst();
	    } else {
		nodep->v3error("Select from non-array "<<dtypep->prettyTypeName());
	    }
	    if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
	    V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), declElements-1);

	    // See if the condition is constant true
	    AstNode* condp = new AstGte (nodep->fileline(),
					 new AstConst(nodep->fileline(), widthnum),
					 nodep->bitp()->cloneTree(false));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue
		     && !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
		// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		if (nodep->isString()) {
		    xnum = V3Number(V3Number::String(), nodep->fileline(), "");
		} else {
		    xnum.setAllBitsX();
		}
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional, can blow away temp xor
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else if (!lvalue) {  // Mid-multidimension read, just use zero
		// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
		AstNRelinker replaceHandle;
		AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
		V3Number zeronum (nodep->fileline(), bitp->width(), 0);
		AstNode* newp = new AstCondBound (bitp->fileline(),
						  condp,
						  bitp,
						  new AstConst(bitp->fileline(), zeronum));
		// Added X's, tristate them too
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		replaceHandle.relink(newp);
		newp->accept(*this);
	    }
	    else {  // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }
Ejemplo n.º 13
0
    virtual void visit(AstConst* nodep) {
	if (m_constXCvt
	    && nodep->num().isFourState()) {
	    UINFO(4," CONST4 "<<nodep<<endl);
	    if (debug()>=9) nodep->dumpTree(cout,"  Const_old: ");
	    // CONST(num) -> VARREF(newvarp)
	    //		-> VAR(newvarp)
	    //		-> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X))
	    V3Number numb1 (nodep->fileline(), nodep->width());
	    numb1.opBitsOne(nodep->num());
	    V3Number numbx (nodep->fileline(), nodep->width());
	    numbx.opBitsXZ(nodep->num());
	    if (v3Global.opt.xAssign()!="unique") {
		// All X bits just become 0; fastest simulation, but not nice
		V3Number numnew (nodep->fileline(), numb1.width());
		if (v3Global.opt.xAssign()=="1") {
		    numnew.opOr(numb1, numbx);
		} else {
		    numnew.opAssign(numb1);
		}
		AstConst* newp = new AstConst(nodep->fileline(), numnew);
		nodep->replaceWith(newp);
		nodep->deleteTree(); VL_DANGLING(nodep);
		UINFO(4,"   -> "<<newp<<endl);
	    } else {
		// Make a Vxrand variable
		// We use the special XTEMP type so it doesn't break pure functions
		if (!m_modp) nodep->v3fatalSrc("X number not under module");
		string newvarname = ((string)"__Vxrand"
				     +cvtToStr(m_modp->varNumGetInc()));
		AstVar* newvarp
		    = new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname,
				  VFlagLogicPacked(), nodep->width());
		++m_statUnkVars;
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
		replaceHandle.relink(newref1p);	    // Replace const with varref
		AstInitial* newinitp
		    = new AstInitial(
			nodep->fileline(),
			new AstAssign(
			    nodep->fileline(),
			    new AstVarRef(nodep->fileline(), newvarp, true),
			    new AstOr(nodep->fileline(),
				      new AstConst(nodep->fileline(),numb1),
				      new AstAnd(nodep->fileline(),
						 new AstConst(nodep->fileline(),numbx),
						 new AstRand(nodep->fileline(),
							     nodep->dtypep(), true)))));
		// Add inits in front of other statement.
		// In the future, we should stuff the initp into the module's constructor.
		AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext();
		m_modp->addStmtp(newvarp);
		m_modp->addStmtp(newinitp);
		m_modp->addStmtp(afterp);
		if (debug()>=9) newref1p->dumpTree(cout,"     _new: ");
		if (debug()>=9) newvarp->dumpTree(cout,"     _new: ");
		if (debug()>=9) newinitp->dumpTree(cout,"     _new: ");
		nodep->deleteTree(); VL_DANGLING(nodep);
	    }
	}
    }
Ejemplo n.º 14
0
void test(string lhss, string op, string rhss, string exps) {
    char* l1 = strdup(lhss.c_str());
    char* r1 = strdup(rhss.c_str());
    char* e1 = strdup(exps.c_str());

    V3Number lhnum (new FileLine ("ck",__LINE__), l1);
    V3Number rhnum (new FileLine ("ck",__LINE__), r1);
    V3Number expnum (new FileLine("ck",__LINE__), e1);

    V3Number gotnum (new FileLine("ck",__LINE__), expnum.width());

    if (op=="redOr")	 	gotnum.opRedOr		(lhnum);
    else if (op=="redAnd")	gotnum.opRedAnd		(lhnum);
    else if (op=="redXor")	gotnum.opRedXor		(lhnum);
    else if (op=="redXnor")	gotnum.opRedXnor	(lhnum);
    else if (op=="concat")	gotnum.opConcat		(lhnum,rhnum);
    else if (op=="repl")	gotnum.opRepl		(lhnum,rhnum);
    else if (op=="~")	 	gotnum.opNot		(lhnum);
    else if (op=="!")	 	gotnum.opLogNot		(lhnum);
    else if (op=="negate") 	gotnum.opNegate		(lhnum);
    else if (op=="+")	 	gotnum.opAdd		(lhnum,rhnum);
    else if (op=="-")	 	gotnum.opSub		(lhnum,rhnum);
    else if (op=="*")	 	gotnum.opMul		(lhnum,rhnum);
    else if (op=="/")	 	gotnum.opDiv		(lhnum,rhnum);
    else if (op=="%")	 	gotnum.opModDiv		(lhnum,rhnum);
    else if (op=="&")	 	gotnum.opAnd		(lhnum,rhnum);
    else if (op=="|")	 	gotnum.opOr		(lhnum,rhnum);
    else if (op=="<")	 	gotnum.opLt		(lhnum,rhnum);
    else if (op==">")	 	gotnum.opGt		(lhnum,rhnum);
    else if (op==">>")	 	gotnum.opShiftR		(lhnum,rhnum);
    else if (op=="<<")	 	gotnum.opShiftL		(lhnum,rhnum);
    else if (op=="==")	 	gotnum.opEq		(lhnum,rhnum);
    else if (op=="===")	 	gotnum.opCaseEq		(lhnum,rhnum);
    else if (op=="==?")	 	gotnum.opWildEq		(lhnum,rhnum);
    else if (op=="!=")	 	gotnum.opNeq		(lhnum,rhnum);
    else if (op=="!==")	 	gotnum.opCaseNeq	(lhnum,rhnum);
    else if (op=="!=?")	 	gotnum.opWildNeq	(lhnum,rhnum);
    else if (op=="<=")	 	gotnum.opLte		(lhnum,rhnum);
    else if (op==">=")	 	gotnum.opGte		(lhnum,rhnum);
    else if (op=="&&")	 	gotnum.opLogAnd		(lhnum,rhnum);
    else if (op=="||")	 	gotnum.opLogOr		(lhnum,rhnum);
    else v3fatalSrc("Bad opcode: "<<op);

    UINFO(0,"------- Test:\n"
	  <<"       "<<lhnum<<" "<<op<<endl
	  <<"       "<<rhnum<<endl
	  <<"     = "<<expnum<<endl
	  <<"    =? "<<gotnum<<endl);

    V3Number ok (new FileLine("ck",__LINE__), 1);
    ok.opCaseEq(expnum,gotnum);
    if (ok.toUInt()!=1) {
	v3fatalSrc("%Error:Test FAILED\n");
    }
}
Ejemplo n.º 15
0
    virtual void visit(AstArraySel* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (!nodep->user1Inc()) {
	    if (debug()==9) nodep->dumpTree(cout,"-in: ");
	    // Guard against reading/writing past end of arrays
	    AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
	    int dimension      = AstArraySel::dimension(nodep->fromp());
	    int maxmsb = 0;
	    bool lvalue = false;
	    if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
		AstArrayDType* adtypep = varrefp->varp()->dtypep()->dtypeDimensionp(dimension)->castArrayDType();
		if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth");
		lvalue = varrefp->lvalue();
		maxmsb = adtypep->elementsConst()-1;
	    } else if (AstConst* lhconstp = basefromp->castConst()) {
		// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
		maxmsb = lhconstp->width();
	    } else {
		nodep->v3fatalSrc("No VarRef or Const under ArraySel\n");
	    }
	    if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
	    V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb);

	    // See if the condition is constant true
	    AstNode* condp = new AstLte (nodep->fileline(),
					 nodep->bitp()->cloneTree(false),
					 new AstConst(nodep->fileline(), widthnum));
	    // Note below has null backp(); the Edit function knows how to deal with that.
	    condp = V3Const::constifyEdit(condp);
	    if (condp->isOne()) {
		// We don't need to add a conditional; we know the existing expression is ok
		condp->deleteTree();
	    }
	    else if (!lvalue
		&& !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
		// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
		AstNRelinker replaceHandle;
		nodep->unlinkFrBack(&replaceHandle);
		V3Number xnum (nodep->fileline(), nodep->width());
		xnum.setAllBitsX();
		AstNode* newp = new AstCondBound (nodep->fileline(),
						  condp,
						  nodep,
						  new AstConst(nodep->fileline(), xnum));
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		// Link in conditional, can blow away temp xor
		replaceHandle.relink(newp);
		// Added X's, tristate them too
		newp->accept(*this);
	    }
	    else if (!lvalue) {  // Mid-multidimension read, just use zero
		// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
		AstNRelinker replaceHandle;
		AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
		V3Number zeronum (nodep->fileline(), bitp->width(), 0);
		AstNode* newp = new AstCondBound (bitp->fileline(),
						  condp,
						  bitp,
						  new AstConst(bitp->fileline(), zeronum));
		// Added X's, tristate them too
		if (debug()>=9) newp->dumpTree(cout,"        _new: ");
		replaceHandle.relink(newp);
		newp->accept(*this);
	    }
	    else {  // lvalue
		replaceBoundLvalue(nodep, condp);
	    }
	}
    }