virtual void visit(AstIf* nodep, AstNUser*) {
	if (nodep->user1SetOnce()) return;
	if (nodep->uniquePragma() || nodep->unique0Pragma()) {
	    AstNodeIf* ifp = nodep;
	    AstNode* propp = NULL;
	    bool hasDefaultElse = false;
	    do {
		// If this statement ends with 'else if', then nextIf will point to the
		// nextIf statement.  Otherwise it will be null.
		AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
		ifp->condp()->iterateAndNext(*this);

		// Recurse into the true case.
		ifp->ifsp()->iterateAndNext(*this);
		
		// If the last else is not an else if, recurse into that too.
		if (ifp->elsesp() && !nextifp) {
		    ifp->elsesp()->iterateAndNext(*this);
		}
		
		// Build a bitmask of the true predicates
	        AstNode* predp = ifp->condp()->cloneTree(false);
	        if (propp) {
		    propp = new AstConcat(nodep->fileline(), predp, propp);
		} else {
		    propp = predp;
		}

		// Record if this ends with an 'else' that does not have an if
		if (ifp->elsesp() && !nextifp) {
		    hasDefaultElse = true;
		}
		
		ifp = nextifp;
	    } while (ifp);

	    AstNode *newifp = nodep->cloneTree(false);
	    bool allow_none = nodep->unique0Pragma();
	    
	    // Note: if this ends with an 'else', then we don't need to validate that one of the
	    // predicates evaluates to true.
	    AstNode* ohot = ((allow_none || hasDefaultElse)
			     ? (new AstOneHot0(nodep->fileline(), propp))->castNode()
			     : (new AstOneHot (nodep->fileline(), propp))->castNode());
	    AstIf* checkifp = new AstIf (nodep->fileline(),
					 new AstLogNot (nodep->fileline(), ohot),
					 newFireAssert(nodep, "'unique if' statement violated"),
					 newifp);
	    checkifp->branchPred(AstBranchPred::BP_UNLIKELY);
	    nodep->replaceWith(checkifp);
	    pushDeletep(nodep);
	} else {
	    nodep->iterateChildren(*this);
	}
    }
示例#2
0
void PrintVisitor::visit(const AstIf &ref)
{
	cout << "AstIf<Condition="; ref.GetCondition()->accept(*this);
	cout << "; Consequent="; ref.GetConsequent()->accept(*this);

	if (ref.HasElse())
	{
		cout << "; Alternative="; ref.GetAlternative()->accept(*this);
	}

	cout << ">\n";
}
示例#3
0
文件: V3Case.cpp 项目: grg/verilator
    AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) {
	if (msb<0) {
	    // There's no space for a IF.  We know upperValue is thus down to a specific
	    // exact value, so just return the tree value
	    // Note can't clone here, as we're going to check for equivelence above
	    return m_valueItem[upperValue];
	}
	else {
	    // Make left and right subtrees
	    // cexpr[msb:lsb] == 1
	    AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0);
	    AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));

	    if (tree0p == tree1p) {
		// Same logic on both sides, so we can just return one of 'em
		return tree0p;
	    }
	    // We could have a "checkerboard" with A B A B, we can use the same IF on both edges
	    bool same = true;
	    for (uint32_t a=upperValue,
		     b=(upperValue|(1UL<<msb));
		 a < (upperValue|(1UL<<msb));
		 a++, b++) {
		if (m_valueItem[a] != m_valueItem[b]) { same=false; break; }
	    }
	    if (same) {
		tree1p->deleteTree(); tree1p=NULL;
		return tree0p;
	    }

	    // Must have differing logic, so make a selection

	    // Case expressions can't be linked twice, so clone them
	    if (tree0p && !tree0p->user3()) tree0p = tree0p->cloneTree(true);
	    if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true);

	    // Alternate scheme if we ever do multiple bits at a time:
	    //V3Number nummask (cexprp->fileline(), cexprp->width(), (1UL<<msb));
	    //AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
	    //                            new AstConst(cexprp->fileline(), nummask));
	    AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false),
					msb, 1);
	    AstNode* eqp = new AstNeq(cexprp->fileline(),
				      new AstConst(cexprp->fileline(), 0),
				      and1p);
	    AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
	    ifp->user3(1);	// So we don't bother to clone it
	    return ifp;
	}
    }
    void newPslAssertion(AstNode* nodep, AstNode* propp, AstSenTree* sentreep,
			 AstNode* stmtsp, const string& message) {
	propp->unlinkFrBack();
	sentreep->unlinkFrBack();
	if (stmtsp) stmtsp->unlinkFrBack();
	//
	AstNode* bodysp = NULL;
	bool selfDestruct = false;
	if (AstPslCover* snodep = nodep->castPslCover()) {
	    if (!v3Global.opt.coverageUser()) {
		selfDestruct = true;
	    } else {
		// V3Coverage assigned us a bucket to increment.
		AstCoverInc* covincp = snodep->coverincp()->castCoverInc();
		if (!covincp) snodep->v3fatalSrc("Missing AstCoverInc under assertion");
		covincp->unlinkFrBack();
		if (message!="") covincp->declp()->comment(message);
		bodysp = covincp;
	    }
	} else if (nodep->castPslAssert()) {
	    bodysp = newFireAssert(nodep,message);
	    // We assert the property is always true... so report when it fails
	    // (Note this is opposite the behavior of coverage statements.)
	    // Need: 'never' operator: not hold in current or any future cycle
	    propp = new AstLogNot (nodep->fileline(), propp);
	} else {
	    nodep->v3fatalSrc("Unknown node type");
	}
	if (stmtsp) bodysp = bodysp->addNext(stmtsp);
	AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
	bodysp = ifp;
	if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
	//
	AstNode* newp = new AstAlways (nodep->fileline(),
				       VAlwaysKwd::ALWAYS,
				       sentreep,
				       bodysp);
	// Install it
	if (selfDestruct) {
	    // Delete it after making the tree.  This way we can tell the user
	    // if it wasn't constructed nicely or has other errors without needing --coverage.
	    newp->deleteTree();
	    nodep->unlinkFrBack();
	} else {
	    nodep->replaceWith(newp);
	}
	// Bye
	pushDeletep(nodep); nodep=NULL;
    }
示例#5
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);
		}
	    }
	}
    }
示例#6
0
    virtual void visit(AstCoverToggle* nodep) {
	//nodep->dumpTree(cout,"ct:");
	//COVERTOGGLE(INC, ORIG, CHANGE) ->
	//   IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
	AstNode* incp = nodep->incp()->unlinkFrBack();
	AstNode* origp = nodep->origp()->unlinkFrBack();
	AstNode* changep = nodep->changep()->unlinkFrBack();
	AstIf* newp = new AstIf(nodep->fileline(),
				new AstXor(nodep->fileline(),
					   origp,
					   changep),
				incp, NULL);
	// We could add another IF to detect posedges, and only increment if so.
	// It's another whole branch though verus a potential memory miss.
	// We'll go with the miss.
	newp->addIfsp(new AstAssign(nodep->fileline(),
				    changep->cloneTree(false),
				    origp->cloneTree(false)));
	nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
    }
示例#7
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;
    }
示例#8
0
static bool
RenderIf(WasmRenderContext& c, AstIf& if_)
{
    if (!c.buffer.append("(if "))
        return false;
    if (!RenderExpr(c, if_.cond()))
        return false;

    if (!c.buffer.append(" (then "))
        return false;

    if (!RenderName(c, if_.thenName()))
        return false;

    c.indent++;
    if (!RenderExprList(c, if_.thenExprs()))
        return false;
    c.indent--;

    if (if_.hasElse()) {
        if (!c.buffer.append(") (else "))
            return false;

        if (!RenderName(c, if_.elseName()))
            return false;

        c.indent++;
        if (!RenderExprList(c, if_.elseExprs()))
            return false;
        c.indent--;
    }

    return c.buffer.append("))");
}
示例#9
0
    virtual void visit(AstNodeIf* nodep) {
        const ColorSet& colors = m_ifColorp->colors(nodep);
        typedef vl_unordered_map<uint32_t, AstNodeIf*> CloneMap;
        CloneMap clones;

        for (ColorSet::const_iterator color = colors.begin();
             color != colors.end(); ++color) {
            // Clone this if into its set of split blocks
            AstSplitPlaceholder* if_placeholderp = makePlaceholderp();
            AstSplitPlaceholder* else_placeholderp = makePlaceholderp();
            AstIf* clonep =
                new AstIf(nodep->fileline(),
                          nodep->condp()->cloneTree(true),
                          if_placeholderp,
                          else_placeholderp);
            AstIf* origp = VN_CAST(nodep, If);
            if (origp) {
                // Preserve pragmas from unique if's
                // so assertions work properly
                clonep->uniquePragma(origp->uniquePragma());
                clonep->unique0Pragma(origp->unique0Pragma());
                clonep->priorityPragma(origp->priorityPragma());
            }
            clones[*color] = clonep;
            m_addAfter[*color]->addNextHere(clonep);
            m_addAfter[*color] = if_placeholderp;
        }

        iterateAndNextNull(nodep->ifsp());

        for (ColorSet::const_iterator color = colors.begin();
             color != colors.end(); ++color) {
            m_addAfter[*color] = clones[*color]->elsesp();
        }

        iterateAndNextNull(nodep->elsesp());

        for (ColorSet::const_iterator color = colors.begin();
             color != colors.end(); ++color) {
            m_addAfter[*color] = clones[*color];
        }
    }
示例#10
0
void IrGen::visit(AstIf& if_) {
  // setup needed basic blocks
  Function* functionIr = m_builder.GetInsertBlock()->getParent();
  BasicBlock* ThenFirstBB =
    BasicBlock::Create(llvmContext, "if_then", functionIr);
  BasicBlock* ElseFirstBB = BasicBlock::Create(llvmContext, "if_else");
  BasicBlock* MergeBB = BasicBlock::Create(llvmContext, "if_merge");

  // current BB:
  Value* condIr = callAcceptOn(if_.condition());
  assert(condIr);
  m_builder.CreateCondBr(condIr, ThenFirstBB, ElseFirstBB);

  // thenFirstBB:
  m_builder.SetInsertPoint(ThenFirstBB);
  Value* thenValue = callAcceptOn(if_.action());
  assert(thenValue);
  if (!if_.action().objType().isNoreturn()) { m_builder.CreateBr(MergeBB); }
  BasicBlock* ThenLastBB = m_builder.GetInsertBlock();

  // elseFirstBB:
  functionIr->getBasicBlockList().push_back(ElseFirstBB);
  m_builder.SetInsertPoint(ElseFirstBB);
  Value* elseValue = nullptr;
  if (if_.elseAction()) {
    elseValue = callAcceptOn(*if_.elseAction());
    assert(elseValue);
    if (!if_.elseAction()->objType().isNoreturn()) {
      m_builder.CreateBr(MergeBB);
    }
  }
  else {
    elseValue = m_abstractObject;
    m_builder.CreateBr(MergeBB);
  }
  BasicBlock* ElseLastBB = m_builder.GetInsertBlock();

  // mergeBB:
  // also sets IrValue of this AstIf
  functionIr->getBasicBlockList().push_back(MergeBB);
  m_builder.SetInsertPoint(MergeBB);
  if (thenValue != m_abstractObject && elseValue != m_abstractObject) {
    PHINode* phi = m_builder.CreatePHI(thenValue->getType(), 2, "if_phi");
    assert(phi);
    phi->addIncoming(thenValue, ThenLastBB);
    phi->addIncoming(elseValue, ElseLastBB);
    allocateAndInitLocalIrObjectFor(if_, phi);
  }
  else {
    allocateAndInitLocalIrObjectFor(if_, m_abstractObject);
  }
}
示例#11
0
    virtual void visit(AstActive* nodep, AstNUser*) {
	// Careful if adding variables here, ACTIVES can be under other ACTIVES
	// Need to save and restore any member state in AstUntilStable block
	if (!m_topScopep || !nodep->stmtsp()) {
	    // Not at the top or empty block...
	    // Only empty blocks should be leftover on the non-top.  Killem.
	    if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active");
	    nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
	} else {
	    UINFO(4,"  ACTIVE  "<<nodep<<endl);
	    AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
	    if (nodep->hasClocked()) {
		// Remember the latest sensitivity so we can compare it next time
		if (nodep->hasInitial()) nodep->v3fatalSrc("Initial block should not have clock sensitivity");
		if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
		    UINFO(4,"    sameSenseTree\n");
		} else {
		    clearLastSen();
		    m_lastSenp = nodep->sensesp();
		    // Make a new if statement
		    m_lastIfp = makeActiveIf(m_lastSenp);
		    addToEvalLoop(m_lastIfp);
		}
		// Move statements to if
		m_lastIfp->addIfsp(stmtsp);
	    } else if (nodep->hasInitial()) {
		// Don't need to: clearLastSen();, as we're adding it to different cfunc
		// Move statements to function
		addToInitial(stmtsp);
	    } else if (nodep->hasSettle()) {
		// Don't need to: clearLastSen();, as we're adding it to different cfunc
		// Move statements to function
		addToSettleLoop(stmtsp);
	    } else {
		// Combo
		clearLastSen();
		// Move statements to function
		addToEvalLoop(stmtsp);
	    }
	    nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
	}
    }
static bool
RenderIf(WasmRenderContext& c, AstIf& if_)
{
    if (!RenderExpr(c, if_.cond()))
        return false;

    if (!RenderIndent(c))
        return false;

    MAP_AST_EXPR(c, if_);
    if (!c.buffer.append("if"))
        return false;
    if (!RenderBlockNameAndSignature(c, if_.name(), if_.type()))
        return false;
    if (!c.buffer.append('\n'))
        return false;

    c.indent++;
    if (!RenderExprList(c, if_.thenExprs()))
        return false;
    c.indent--;

    if (if_.hasElse()) {
        if (!RenderIndent(c))
            return false;

        if (!c.buffer.append("else\n"))
            return false;

        c.indent++;
        if (!RenderExprList(c, if_.elseExprs()))
            return false;
        c.indent--;
    }

    if (!RenderIndent(c))
        return false;

    return c.buffer.append("end");
}
示例#13
0
文件: V3Case.cpp 项目: grg/verilator
    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;
    }
示例#14
0
    AstNode* createDlyArray(AstAssignDly* nodep, AstNode* lhsp) {
	// Create delayed assignment
	// See top of this file for transformation
	// Return the new LHS for the assignment, Null = unlink
	// Find selects
	AstNode* newlhsp = NULL;	// NULL = unlink old assign
	AstSel*  bitselp = NULL;
	AstArraySel*  arrayselp = NULL;
	if (lhsp->castSel()) {
	    bitselp = lhsp->castSel();
	    arrayselp = bitselp->fromp()->castArraySel();
	} else {
	    arrayselp = lhsp->castArraySel();
	}
	if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
	if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");

	UINFO(4,"AssignDlyArray: "<<nodep<<endl);
	//
	//=== Dimensions: __Vdlyvdim__
	deque<AstNode*> dimvalp;		// Assignment value for each dimension of assignment
	AstNode* dimselp=arrayselp;
	for (; dimselp->castArraySel(); dimselp=dimselp->castArraySel()->fromp()) {
	    AstNode* valp = dimselp->castArraySel()->bitp()->unlinkFrBack();
	    dimvalp.push_front(valp);
	}
	AstVarRef* varrefp = dimselp->castVarRef();
	if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n");
	if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
	varrefp->unlinkFrBack();
	AstVar* oldvarp = varrefp->varp();
	int modVecNum = oldvarp->user4();  oldvarp->user4(modVecNum+1);
	//
	deque<AstNode*> dimreadps;		// Read value for each dimension of assignment
	for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
	    AstNode* dimp = dimvalp[dimension];
	    if (dimp->castConst()) { // bit = const, can just use it
		dimreadps.push_front(dimp);
	    } else {
		string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
				     +"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width());
		AstAssign* bitassignp
		    = new AstAssign (nodep->fileline(),
				     new AstVarRef(nodep->fileline(), bitvscp, true),
				     dimp);
		nodep->addNextHere(bitassignp);
		dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
	    }
	}
	//
	//=== Bitselect: __Vdlyvlsb__
	AstNode* bitreadp=NULL;  // Code to read Vdlyvlsb
	if (bitselp) {
	    AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
	    if (bitselp->fromp()->castConst()) {// vlsb = constant, can just push constant into where we use it
		bitreadp = lsbvaluep;
	    } else {
		string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
		AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width());
		AstAssign* bitassignp = new AstAssign (nodep->fileline(),
						       new AstVarRef(nodep->fileline(), bitvscp, true),
						       lsbvaluep);
		nodep->addNextHere(bitassignp);
		bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
	    }
	}
	//
	//=== Value: __Vdlyvval__
	AstNode* valreadp;	// Code to read Vdlyvval
	if (nodep->rhsp()->castConst()) {	// vval = constant, can just push constant into where we use it
	    valreadp = nodep->rhsp()->unlinkFrBack();
	} else {
	    string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, nodep->rhsp()->width());
	    newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
	    valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
	}
	//
	//=== Setting/not setting boolean: __Vdlyvset__
	AstVarScope* setvscp;
	AstAssignPre* setinitp = NULL;

	if (nodep->user3p()) {
	    // Simplistic optimization.  If the previous statement in same scope was also a =>,
	    // then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
	    // This is good for code like:
	    //    for (i=0; i<5; i++)  vector[i] <= something;
	    setvscp = nodep->user3p()->castNode()->castVarScope();
	    ++m_statSharedSet;
	} else {  // Create new one
	    string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
	    setvscp = createVarSc(varrefp->varScopep(), setvarname, 1);
	    setinitp = new AstAssignPre (nodep->fileline(),
					 new AstVarRef(nodep->fileline(), setvscp, true),
					 new AstConst(nodep->fileline(), 0));
	    AstAssign* setassignp
		= new AstAssign (nodep->fileline(),
				 new AstVarRef(nodep->fileline(), setvscp, true),
				 new AstConst(nodep->fileline(),
					      V3Number(nodep->fileline(),1,true)));
	    nodep->addNextHere(setassignp);
	}
	if (m_nextDlyp) {  // Tell next assigndly it can share the variable
	    m_nextDlyp->user3p(setvscp);
	}
	//
	// Create ALWAYSPOST for delayed variable
	// We add all logic to the same block if it's for the same memory
	// This insures that multiple assignments to the same memory will result
	// in correctly ordered code - the last assignment must be last.
	// It also has the nice side effect of assisting cache locality.
	AstNode* selectsp = varrefp;
	for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) {
	    selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
	}
	if (bitselp) {
	    selectsp = new AstSel(nodep->fileline(), selectsp, bitreadp,
				  bitselp->widthp()->cloneTree(false));
	}
	// Build "IF (changeit) ...
	UINFO(9,"   For "<<setvscp<<endl);
	UINFO(9,"     & "<<varrefp<<endl);
	AstAlwaysPost* finalp = varrefp->varScopep()->user4p()->castNode()->castAlwaysPost();
	if (finalp) {
	    AstActive* oldactivep = finalp->user2p()->castNode()->castActive();
	    checkActivePost(varrefp, oldactivep);
	    if (setinitp) oldactivep->addStmtsp(setinitp);
	} else { // first time we've dealt with this memory
	    finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/);
	    UINFO(9,"     Created "<<finalp<<endl);
	    AstActive* newactp = createActivePost(varrefp);
	    newactp->addStmtsp(finalp);
	    varrefp->varScopep()->user4p(finalp);
	    finalp->user2p(newactp);
	    if (setinitp) newactp->addStmtsp(setinitp);
	}
	AstIf* postLogicp;
	if (finalp->user3p()->castNode() == setvscp) {
	    // Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
	    // we can share the IF statement too
	    postLogicp = finalp->user4p()->castNode()->castIf();
	    if (!postLogicp) nodep->v3fatalSrc("Delayed assignment misoptimized; prev var found w/o associated IF");
	} else {
	    postLogicp = new AstIf (nodep->fileline(),
				    new AstVarRef(nodep->fileline(), setvscp, false),
				    NULL,
				    NULL);
	    UINFO(9,"     Created "<<postLogicp<<endl);
	    finalp->addBodysp(postLogicp);
	    finalp->user3p(setvscp);	// Remember IF's vset variable
	    finalp->user4p(postLogicp);	// and the associated IF, as we may be able to reuse it
	}
	postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp));
	return newlhsp;
    }