Exemplo n.º 1
0
    virtual void visit(AstWhile* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (m_varModeCheck || m_varModeReplace) {
	} else {
	    // Constify before unroll call, as it may change what is underneath.
	    if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp());  // precondsp may change
	    if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
	    // Grab initial value
	    AstNode* initp = NULL;  // Should be statement before the while.
	    if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
	    if (initp) { V3Const::constifyEdit(initp); VL_DANGLING(initp); }
	    if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
	    // Grab assignment
	    AstNode* incp = NULL;  // Should be last statement
	    if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
	    if (nodep->incsp()) incp = nodep->incsp();
	    else {
		for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
		if (incp) { V3Const::constifyEdit(incp); VL_DANGLING(incp); }
		for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}  // Again, as may have changed
	    }
	    // And check it
	    if (forUnrollCheck(nodep, initp,
			       nodep->precondsp(), nodep->condp(),
			       incp, nodep->bodysp())) {
		pushDeletep(nodep); VL_DANGLING(nodep); // Did replacement
	    }
	}
    }
    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;
    }
    virtual void visit(AstUdpTable* nodep, AstNUser*) {
	UINFO(5,"UDPTABLE  "<<nodep<<endl);
	if (!v3Global.opt.bboxUnsup()) {
	    // We don't warn until V3Inst, so that UDPs that are in libraries and
	    // never used won't result in any warnings.
	} else {
	    // Massive hack, just tie off all outputs so our analysis can proceed
	    AstVar* varoutp = NULL;
	    for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
		if (AstVar* varp = stmtp->castVar()) {
		    if (varp->isInput()) {
		    } else if (varp->isOutput()) {
			if (varoutp) { varp->v3error("Multiple outputs not allowed in udp modules"); }
			varoutp = varp;
			// Tie off
			m_modp->addStmtp(new AstAssignW(varp->fileline(),
							new AstVarRef(varp->fileline(), varp, true),
							new AstConst(varp->fileline(), AstConst::LogicFalse())));
		    } else {
			varp->v3error("Only inputs and outputs are allowed in udp modules");
		    }
		}
	    }
	    nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
	}
    }
void AstTypeTable::repairCache() {
    // After we mass-change widthMin in V3WidthCommit, we need to correct the table.
    clearCache();
    for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) {
	if (AstBasicDType* bdtypep = nodep->castBasicDType()) {
	    (void)findInsertSameDType(bdtypep);
	}
    }
}
Exemplo n.º 5
0
    virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
	AstNode* pinp = nodep->pinsp();
	AstNodeFTask* taskp = nodep->taskp();
	// We'll deal with mismatching pins later
	if (!taskp) return;
	for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) {
	    if (AstVar* portp = stmtp->castVar()) {
		if (portp->isIO()) {
		    if (portp->isInput()) {
			pinp->iterate(*this);
		    } else {  // Output or Inout
			m_setRefLvalue = true;
			pinp->iterate(*this);
			m_setRefLvalue = false;
		    }
		    // Advance pin
		    pinp = pinp->nextp();
		}
	    }
	}
    }
Exemplo n.º 6
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;
	}
    }
Exemplo n.º 7
0
void EmitCSyms::emitDpiImp() {
    UINFO(6,__FUNCTION__<<": "<<endl);
    string filename = v3Global.opt.makeDir()+"/"+topClassName()+"__Dpi.cpp";
    AstCFile* cfilep = newCFile(filename, false/*slow*/, true/*source*/);
    cfilep->support(true);
    V3OutCFile hf (filename);
    m_ofp = &hf;

    m_ofp->putsHeader();
    puts("// DESCR" "IPTION: Verilator output: Implementation of DPI export functions.\n");
    puts("//\n");
    puts("// Verilator compiles this file in when DPI functions are used.\n");
    puts("// If you have multiple Verilated designs with the same DPI exported\n");
    puts("// function names, you will get multiple definition link errors from here.\n");
    puts("// This is an unfortunate result of the DPI specification.\n");
    puts("// To solve this, either\n");
    puts("//    1. Call "+topClassName()+"::{export_function} instead,\n");
    puts("//       and do not even bother to compile this file\n");
    puts("// or 2. Compile all __Dpi.cpp files in the same compiler run,\n");
    puts("//       and #ifdefs already inserted here will sort everything out.\n");
    puts("\n");

    puts("#include \""+topClassName()+"__Dpi.h\"\n");
    puts("#include \""+topClassName()+".h\"\n");
    puts("\n");

    for (vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
	AstCFunc* nodep = *it;
	if (nodep->dpiExportWrapper()) {
	    puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n");
	    puts("#define _VL_DPIDECL_"+nodep->name()+"\n");
	    puts(nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+") {\n");
	    puts("// DPI Export at "+nodep->fileline()->ascii()+"\n");
	    puts("return "+topClassName()+"::"+nodep->name()+"(");
	    string args;
	    for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
		if (AstVar* portp = stmtp->castVar()) {
		    if (portp->isIO() && !portp->isFuncReturn()) {
			if (args != "") args+= ", ";
			args += portp->name();
		    }
		}
	    }
	    puts(args+");\n");
	    puts("}\n");
	    puts("#endif\n");
	    puts("\n");
	}
    }
}
    void makeSmallNames(AstNodeModule* modp) {
	vector<int> usedLetter; usedLetter.resize(256);
	// Pass 1, assign first letter to each gparam's name
	for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
	    if (AstVar* varp = stmtp->castVar()) {
		if (varp->isGParam()||varp->isIfaceRef()) {
		    char ch = varp->name()[0];
		    ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
		    varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
		    usedLetter[static_cast<int>(ch)]++;
		}
	    }
	}
    }
Exemplo n.º 9
0
    virtual void visit(AstNodeModule* nodep, AstNUser*) {
	// Create required blocks and add to module
	string scopename;
	if (!m_aboveScopep) scopename = "TOP";
	else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name();

	UINFO(4," MOD AT "<<scopename<<"  "<<nodep<<endl);
        AstNode::user1ClearTree();

	m_scopep = new AstScope((m_aboveCellp?(AstNode*)m_aboveCellp:(AstNode*)nodep)->fileline(),
				nodep, scopename, m_aboveScopep, m_aboveCellp);

	// Now for each child cell, iterate the module this cell points to
	for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) {
	    if (AstCell* cellp = cellnextp->castCell()) {
		AstScope* oldScopep = m_scopep;
		AstCell* oldAbCellp = m_aboveCellp;
		AstScope* oldAbScopep = m_aboveScopep;
		{
		    m_aboveCellp = cellp;
		    m_aboveScopep = m_scopep;
		    AstNodeModule* modp = cellp->modp();
		    if (!modp) cellp->v3fatalSrc("Unlinked mod");
		    modp->accept(*this);  // Recursive call to visit(AstNodeModule)
		}
		// Done, restore vars
		m_scopep = oldScopep;
		m_aboveCellp = oldAbCellp;
		m_aboveScopep = oldAbScopep;
	    }
	}

	// Create scope for the current usage of this module
	UINFO(4," back AT "<<scopename<<"  "<<nodep<<endl);
        AstNode::user1ClearTree();
	m_modp = nodep;
	if (m_modp->isTop()) {
	    AstTopScope* topscp = new AstTopScope(nodep->fileline(), m_scopep);
	    m_modp->addStmtp(topscp);
	} else {
	    m_modp->addStmtp(m_scopep);
	}

	// Copy blocks into this scope
	// If this is the first usage of the block ever, we can simply move the reference
	nodep->iterateChildren(*this);

	// ***Note m_scopep is passed back to the caller of the routine (above)
    }
Exemplo n.º 10
0
    // VISITORS  //========== Case assertions
    virtual void visit(AstCase* nodep, AstNUser*) {
	nodep->iterateChildren(*this);
	if (!nodep->user1Inc()) {
	    bool has_default=false;
	    for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
		if (itemp->isDefault()) has_default=true;
	    }
	    if (nodep->fullPragma() || nodep->priorityPragma()) {
		// Simply need to add a default if there isn't one already
		++m_statAsFull;
		if (!has_default) {
		    nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
						     newFireAssert(nodep, "synthesis full_case, but non-match found")));
		}
	    }
	    if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
		// Need to check that one, and only one of the case items match at any moment
		// If there's a default, we allow none to match, else exactly one must match
		++m_statAsFull;
		if (!has_default && !nodep->itemsp()) {
		    // Not parallel, but harmlessly so.
		} else {
		    AstNode* propp = NULL;
		    for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
			for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
			    AstNode* onep = new AstEq(icondp->fileline(),
						      nodep->exprp()->cloneTree(false),
						      icondp->cloneTree(false));
			    if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
			    else propp = onep;
			}
		    }
		    bool allow_none = has_default || nodep->unique0Pragma();
		    AstNode* ohot = (allow_none
				     ? (new AstOneHot0(nodep->fileline(), propp))->castNode()
				     : (new AstOneHot (nodep->fileline(), propp))->castNode());
		    AstIf* ifp = new AstIf (nodep->fileline(),
					    new AstLogNot (nodep->fileline(), ohot),
					    newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
					    NULL);
		    ifp->branchPred(AstBranchPred::BP_UNLIKELY);
		    nodep->addNotParallelp(ifp);
		}
	    }
	}
    }
Exemplo n.º 11
0
    // VISITORS
    virtual void visit(AstNodeModule* nodep, AstNUser*) {
	allNodes(nodep);
	if (!m_fast) {
	    nodep->iterateChildrenConst(*this);
	} else {
	    for (AstNode* searchp = nodep->stmtsp(); searchp; searchp=searchp->nextp()) {
		if (AstCFunc* funcp = searchp->castCFunc()) {
		    if (funcp->name() == "_eval") {
			m_instrs=0;
			m_counting = true;
			funcp->iterateChildrenConst(*this);
			m_counting = false;
		    }
		}
	    }
	}
    }
Exemplo n.º 12
0
    // Autoflush
    virtual void visit(AstDisplay* nodep, AstNUser*) {
	startStatement(nodep);
	nodep->iterateChildren(*this);
	m_stmtp = NULL;
	if (v3Global.opt.autoflush()) {
	    AstNode* searchp = nodep->nextp();
	    while (searchp && searchp->castComment()) searchp = searchp->nextp();
	    if (searchp
		&& searchp->castDisplay()
		&& nodep->filep()->sameGateTree(searchp->castDisplay()->filep())) {
		// There's another display next; we can just wait to flush
	    } else {
		UINFO(4,"Autoflush "<<nodep<<endl);
		nodep->addNextHere(new AstFFlush(nodep->fileline(),
						 nodep->filep()->cloneTree(true)));
	    }
	}
    }
void AstTypeTable::clearCache() {
    // When we mass-change widthMin in V3WidthCommit, we need to correct the table.
    // Just clear out the maps; the search functions will be used to rebuild the map
    for (int i=0; i<(int)(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
	m_basicps[i] = NULL;
    }
    for (int isbit=0; isbit<_IDX0_MAX; ++isbit) {
	for (int numer=0; numer<AstNumeric::_ENUM_MAX; ++numer) {
	    LogicMap& mapr = m_logicMap[isbit][numer];
	    mapr.clear();
	}
    }
    m_detailedMap.clear();
    // Clear generic()'s so dead detection will work
    for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) {
	if (AstBasicDType* bdtypep = nodep->castBasicDType()) {
	    bdtypep->generic(false);
	}
    }
}
Exemplo n.º 14
0
    virtual void visit(AstCell* nodep, AstNUser*) {
	// Cell: Resolve its filename.  If necessary, parse it.
	if (nodep->user1SetOnce()) return;  // AstBind and AstNodeModule may call a cell twice
	if (!nodep->modp()) {
	    UINFO(4,"Link Cell: "<<nodep<<endl);
	    // Use findIdFallback instead of findIdFlat; it doesn't matter for now
	    // but we might support modules-under-modules someday.
	    AstNodeModule* modp = resolveModule(nodep,nodep->modName());
	    if (modp) {
		nodep->modp(modp);
		// Track module depths, so can sort list from parent down to children
		new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
	    }
	}
	// Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()"
	// the empty middle is identical to the empty rule that must find pins in "(,)".
	if (nodep->pinsp() && !nodep->pinsp()->nextp()
	    && nodep->pinsp()->name() == ""
	    && !nodep->pinsp()->exprp()) {
	    pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
	}
	if (nodep->paramsp() && !nodep->paramsp()->nextp()
	    && nodep->paramsp()->name() == ""
	    && !nodep->paramsp()->exprp()) {
	    pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
	}
	// Convert .* to list of pins
	bool pinStar = false;
	for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
	    nextp = pinp->nextp()->castPin();
	    if (pinp->dotStar()) {
		if (pinStar) pinp->v3error("Duplicate .* in a cell");
		pinStar = true;
		// Done with this fake pin
		pinp->unlinkFrBack()->deleteTree(); pinp=NULL;
	    }
	}
	// Convert unnamed pins to pin number based assignments
	for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum()));
	}
	for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
	    if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
	}
	if (nodep->modp()) {
	    // Note what pins exist
	    set<string> ports;	// Symbol table of all connected port names
	    for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
		if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
		if (!pinp->exprp()) pinp->v3warn(PINNOCONNECT,"Cell pin is not connected: "<<pinp->prettyName());
		if (ports.find(pinp->name()) == ports.end()) {
		    ports.insert(pinp->name());
		}
	    }
	    // We search ports, rather than in/out declarations as they aren't resolved yet,
	    // and it's easier to do it now than in V3LinkDot when we'd need to repeat steps.
	    for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep; portnodep=portnodep->nextp()) {
		if (AstPort* portp = portnodep->castPort()) {
		    if (ports.find(portp->name()) == ports.end()
			&& ports.find("__pinNumber"+cvtToStr(portp->pinNum())) == ports.end()) {
			if (pinStar) {
			    UINFO(9,"    need .* PORT  "<<portp<<endl);
			    // Create any not already connected
			    AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),
						      new AstVarRef(nodep->fileline(),portp->name(),false));
			    newp->svImplicit(true);
			    nodep->addPinsp(newp);
			} else {  // warn on the CELL that needs it, not the port
			    nodep->v3warn(PINMISSING, "Cell has missing pin: "<<portp->prettyName());
			    AstPin* newp = new AstPin(nodep->fileline(),0,portp->name(),NULL);
			    nodep->addPinsp(newp);
			}
		    }
		}
	    }
	}
	if (nodep->modp()->castIface()) {
	    // Cell really is the parent's instantiation of an interface, not a normal module
	    // Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
	    // in the same way that a child does.  Rename though to avoid conflict with cell.
	    // This is quite similar to how classes work; when unpacked classes are better supported
	    // may remap interfaces to be more like a class.
	    if (!nodep->hasIfaceVar()) {
		string varName = nodep->name()+"__Viftop";  // V3LinkDot looks for this naming
		AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
		idtypep->cellp(nodep);  // Only set when real parent cell known
		idtypep->ifacep(NULL);  // cellp overrides
		AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
		varp->isIfaceParent(true);
		nodep->addNextHere(varp);
		nodep->hasIfaceVar(true);
	    }
	}
	if (nodep->modp()) {
	    nodep->iterateChildren(*this);
	}
	UINFO(4," Link Cell done: "<<nodep<<endl);
    }
Exemplo n.º 15
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;
    }
Exemplo n.º 16
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
    }
Exemplo n.º 17
0
    void makePublicFuncWrappers() {
	// We recorded all public functions in m_modFuncs.
	// If for any given name only one function exists, we can use that function directly.
	// If multiple functions exist, we need to select the appropriate scope.
	for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) {
	    string name = it->first;
	    AstCFunc* topFuncp = it->second;
	    FuncMmap::iterator nextIt1 = it; ++nextIt1;
	    bool moreOfSame1 =  (nextIt1!=m_modFuncs.end() && nextIt1->first == name);
	    if (moreOfSame1) {
		// Multiple functions under this name, need a wrapper function
		UINFO(6,"  Wrapping "<<name<<" multifuncs\n");
		AstCFunc* newfuncp = topFuncp->cloneTree(false);
		if (newfuncp->initsp())  newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
		if (newfuncp->stmtsp())  newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
		if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
		newfuncp->name(name);
		newfuncp->isStatic(false);
		newfuncp->addInitsp(
		    new AstCStmt(newfuncp->fileline(),
				 EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
		newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
		topFuncp->addNextHere(newfuncp);
		// In the body, call each function if it matches the given scope
		for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) {
		    it = eachIt;
		    AstCFunc* funcp = eachIt->second;
		    FuncMmap::iterator nextIt2 = eachIt; ++nextIt2;
		    bool moreOfSame =  (nextIt2!=m_modFuncs.end() && nextIt2->first == name);
		    if (!funcp->scopep()) funcp->v3fatalSrc("Not scoped");

		    UINFO(6,"     Wrapping "<<name<<" "<<funcp<<endl);
		    UINFO(6,"  at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl);
		    funcp->declPrivate(true);
		    AstNode* argsp = NULL;
		    for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
			if (AstVar* portp = stmtp->castVar()) {
			    if (portp->isIO() && !portp->isFuncReturn()) {
				argsp = argsp->addNextNull(new AstVarRef(portp->fileline(), portp,
									 portp->isOutput()));
			    }
			}
		    }

		    AstNode* returnp = new AstCReturn (funcp->fileline(),
						       new AstCCall (funcp->fileline(),
								     funcp,
								     argsp));

		    if (moreOfSame) {
			AstIf* ifp = new AstIf (funcp->fileline(),
						new AstEq(funcp->fileline(),
							  new AstCMath(funcp->fileline(),
								       "this", 64),
							  new AstCMath(funcp->fileline(),
								       string("&(")
								       +funcp->scopep()->nameVlSym()
								       +")", 64)),
						returnp, NULL);
			newfuncp->addStmtsp(ifp);
		    } else {
			newfuncp->addStmtsp(returnp);
		    }
		}
		// Not really any way the user could do this, and we'd need to come up with some return value
		//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY,
		//				      string("%%Error: ")+name+"() called with bad scope", NULL));
		//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
		if (debug()>=9) newfuncp->dumpTree(cout,"   newfunc: ");
	    } else {
		// Only a single function under this name, we can simply rename it
		UINFO(6,"  Wrapping "<<name<<" just one "<<topFuncp<<endl);
		topFuncp->name(name);
	    }
	}
    }