Remove AstJumpLabel

AstJumpGo now references one if its enclosing AstJumpBlocks, and
branches straight after the referenced block.

That is:

```
JumpBlock a {
   ...
   JumpGo(a);
   ...
}
// <--- the JumpGo(a) goes here
```

This is sufficient for all use cases and makes control flow much easier to
reason about. As a result, V3Const can optimize a bit more aggressively.

Second half of, and fixes #6216
This commit is contained in:
Geza Lore 2025-07-23 11:46:18 +01:00
parent 763183f067
commit 30db66fef5
9 changed files with 163 additions and 234 deletions

View File

@ -3279,14 +3279,13 @@ public:
bool isDelayed() const { return m_delayed; }
};
class AstJumpBlock final : public AstNodeStmt {
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
// Block of code that might contain AstJumpGo statements as children,
// which when exectued branch to right after the referenced AstJumpBlock.
// AstJumpBlocks can nest, and an AstJumpGo can reference any of the
// encolsing AstJumpBlocks (can break out of mulitple levels).
// Parents: {statement list}
// Children: {statement list, with JumpGo and JumpLabel below}
// Children: {statement list, with JumpGo below}
// @astgen op1 := stmtsp : List[AstNode]
// @astgen op2 := endStmtsp : List[AstNode]
//
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
VIsCached m_purity; // Pure state
public:
// After construction must call ->labelp to associate with appropriate label
@ -3295,66 +3294,35 @@ public:
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstJumpBlock;
const char* broken() const override;
int instrCount() const override { return 0; }
bool maybePointedTo() const override VL_MT_SAFE { return true; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
int labelNum() const { return m_labelNum; }
void labelNum(int flag) { m_labelNum = flag; }
AstJumpLabel* labelp() const { return m_labelp; }
void labelp(AstJumpLabel* labelp) { m_labelp = labelp; }
bool isPure() override;
private:
bool getPurityRecurse() const;
};
class AstJumpGo final : public AstNodeStmt {
// Jump point; branch down to a JumpLabel
// No support for backward jumps at present
// Parents: {statement list with JumpBlock above}
// Branch to right after the referenced encloding AstJumpBlock
// Parents: statement, including the referenced AstJumpBlock
// Children: none
//
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
// @astgen ptr := m_blockp : AstJumpBlock // The AstJumpBlock we are branching after
public:
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
AstJumpGo(FileLine* fl, AstJumpBlock* blockp)
: ASTGEN_SUPER_JumpGo(fl)
, m_labelp{labelp} {}
, m_blockp{blockp} {}
ASTGEN_MEMBERS_AstJumpGo;
const char* broken() const override;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* samep) const override {
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
return blockp() == VN_DBG_AS(samep, JumpGo)->blockp();
}
bool isGateOptimizable() const override { return false; }
bool isBrancher() const override {
return true; // SPECIAL: We don't process code after breaks
}
AstJumpLabel* labelp() const { return m_labelp; }
};
class AstJumpLabel final : public AstNodeStmt {
// Jump point declaration
// Parents: {statement list with JumpBlock above}
// Children: none
// @astgen ptr := m_blockp : AstJumpBlock // [After V3Jump] Pointer to declaration
public:
AstJumpLabel(FileLine* fl, AstJumpBlock* blockp)
: ASTGEN_SUPER_JumpLabel(fl)
, m_blockp{blockp} {}
ASTGEN_MEMBERS_AstJumpLabel;
bool maybePointedTo() const override VL_MT_SAFE { return true; }
const char* broken() const override {
BROKEN_RTN(!blockp()->brokeExistsAbove());
BROKEN_RTN(blockp()->labelp() != this);
return nullptr;
}
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
int instrCount() const override { return 0; }
bool sameNode(const AstNode* samep) const override {
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
}
AstJumpBlock* blockp() const { return m_blockp; }
};
class AstMonitorOff final : public AstNodeStmt {

View File

@ -1139,10 +1139,6 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
return nodep;
}
const char* AstJumpBlock::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return nullptr;
}
bool AstJumpBlock::isPure() {
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
return m_purity.get();
@ -1977,21 +1973,6 @@ AstNodeExpr* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
}
void AstJumpGo::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " -> ";
if (labelp()) {
labelp()->dump(str);
} else {
str << "%E:UNLINKED";
}
}
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
const char* AstJumpGo::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return nullptr;
}
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
str << " -> ";
if (blockp()) {
@ -2000,7 +1981,11 @@ void AstJumpLabel::dump(std::ostream& str) const {
str << "%E:UNLINKED";
}
}
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
const char* AstJumpGo::broken() const {
BROKEN_RTN(!blockp()->brokeExistsAbove());
return nullptr;
}
void AstMemberDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);

View File

@ -38,6 +38,7 @@
#include <algorithm>
#include <memory>
#include <type_traits>
#include <unordered_set>
VL_DEFINE_DEBUG_FUNCTIONS;
@ -912,7 +913,6 @@ class ConstVisitor final : public VNVisitor {
// ** only when m_warn/m_doExpensive is set. If state is needed other times,
// ** must track down everywhere V3Const is called and make sure no overlaps.
// AstVar::user4p -> Used by variable marking/finding
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
// AstEnum::user4 -> bool. Recursing.
// STATE
@ -938,6 +938,7 @@ class ConstVisitor final : public VNVisitor {
static uint32_t s_globalPassNum; // Counts number of times ConstVisitor invoked as global pass
V3UniqueNames m_concswapNames; // For generating unique temporary variable names
std::map<const AstNode*, bool> m_containsMemberAccess; // Caches results of matchBiopToBitwise
std::unordered_set<AstJumpBlock*> m_usedJumpBlocks; // JumpBlocks used by some JumpGo
// METHODS
@ -2303,19 +2304,6 @@ class ConstVisitor final : public VNVisitor {
}
return false;
}
bool replaceJumpGoNext(AstJumpGo* nodep, AstNode* abovep) {
// If JumpGo has an upper JumpBlock that is to same label, then
// code will by normal sequential operation do the JUMPGO and it
// can be removed.
if (nodep->nextp()) return false; // Label jumps other statements
AstJumpBlock* const aboveBlockp = VN_CAST(abovep, JumpBlock);
if (!aboveBlockp) return false;
if (aboveBlockp != nodep->labelp()->blockp()) return false;
if (aboveBlockp->endStmtsp() != nodep->labelp()) return false;
UINFO(4, "JUMPGO => last remove " << nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return true;
}
// Boolean replacements
bool operandBoolShift(const AstNode* nodep) {
@ -3402,52 +3390,39 @@ class ConstVisitor final : public VNVisitor {
// Jump elimination
void visit(AstJumpGo* nodep) override {
iterateChildren(nodep);
// Jump to label where label immediately follows this JumpGo is not useful
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
// Keep the label, might be other jumps pointing to it, gets cleaned later
return;
}
if (m_doExpensive) {
// Any non-label statements (at this statement level) can never execute
while (nodep->nextp() && !VN_IS(nodep->nextp(), JumpLabel)) {
pushDeletep(nodep->nextp()->unlinkFrBack());
// Any statements following the JumpGo (at this statement level) never execute, delete
if (nodep->nextp()) pushDeletep(nodep->nextp()->unlinkFrBackWithNext());
// JumpGo as last statement in target JumpBlock (including last in a last sub-list),
// is a no-op, remove it.
for (AstNode* abovep = nodep->abovep(); abovep; abovep = abovep->abovep()) {
if (abovep == nodep->blockp()) {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
// If last statement in a jump label we have JumpLabel(...., JumpGo)
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
if (replaceJumpGoNext(nodep, nodep->abovep())) return;
// Also optimize If with a then or else's final statement being this JumpGo
// We only do single ifs... Ideally we'd look at control flow and delete any
// Jumps where any following control flow point is the label
if (!nodep->nextp()) {
if (AstNodeIf* const aboveIfp = VN_CAST(nodep->abovep(), NodeIf)) {
if (!aboveIfp->nextp()) {
if (replaceJumpGoNext(nodep, aboveIfp->abovep())) return;
}
}
}
nodep->labelp()->blockp()->user4(true);
// Stop if not doing expensive, or if the above node is not the last in its list,
// ... or if it's not an 'if' TODO: it would be enough if it was not a branch.
if (!m_doExpensive || abovep->nextp() || !VN_IS(abovep, If)) break;
}
// Mark JumpBlock as used
m_usedJumpBlocks.emplace(nodep->blockp());
m_hasJumpDelay = true;
}
void visit(AstJumpBlock* nodep) override {
// Because JumpLabels disable many optimizations,
// remove JumpLabels that are not pointed to by any AstJumpGos
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
iterateChildren(nodep);
// AstJumpGo's below here that point to this node will set user4
if (m_doExpensive && !nodep->user4()) {
// Remove if empty
if (!nodep->stmtsp()) {
UINFO(4, "JUMPLABEL => empty " << nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return;
}
// If no JumpGo points to this node, replace it with its body
if (!m_usedJumpBlocks.count(nodep)) {
UINFO(4, "JUMPLABEL => unused " << nodep);
AstNode* underp = nullptr;
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
if (underp) {
nodep->replaceWith(underp);
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep->labelp()->unlinkFrBack());
nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}

View File

@ -26,6 +26,7 @@
#include <algorithm>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@ -117,7 +118,7 @@ public:
class EmitCFunc VL_NOT_FINAL : public EmitCConstInit {
VMemberMap m_memberMap;
AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting
int m_labelNum = 0; // Next label number
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
bool m_inUC = false; // Inside an AstUCStmt or AstUCExpr
bool m_emitConstInit = false; // Emitting constant initializer
bool m_createdScopeHash = false; // Already created a scope hash
@ -993,25 +994,29 @@ public:
puts(";\n");
}
void visit(AstJumpBlock* nodep) override {
nodep->labelNum(++m_labelNum);
// Allocate label number
const size_t n = m_labelNumbers.size();
const bool newEntry = m_labelNumbers.emplace(nodep, n).second;
UASSERT_OBJ(newEntry, nodep, "AstJumpBlock visited twide");
// Emit
putns(nodep, "{\n"); // Make it visually obvious label jumps outside these
VL_RESTORER(m_createdScopeHash);
iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->endStmtsp());
puts("__Vlabel" + std::to_string(n) + ": ;\n");
puts("}\n");
}
void visit(AstJumpGo* nodep) override {
// Retrieve target label number - must already exist (from enclosing AstJumpBlock)
const size_t n = m_labelNumbers.at(nodep->blockp());
// Emit
putns(nodep, "goto __Vlabel" + std::to_string(n) + ";\n");
}
void visit(AstCLocalScope* nodep) override {
putns(nodep, "{\n");
VL_RESTORER(m_createdScopeHash);
iterateAndNextConstNull(nodep->stmtsp());
puts("}\n");
}
void visit(AstJumpGo* nodep) override {
putns(nodep, "goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
}
void visit(AstJumpLabel* nodep) override {
putns(nodep, "__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
}
void visit(AstWhile* nodep) override {
VL_RESTORER(m_createdScopeHash);
putns(nodep, "while (");

View File

@ -20,6 +20,7 @@
#include "V3EmitCBase.h"
#include <unordered_map>
#include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
@ -37,6 +38,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
std::deque<AstNodeArrayDType*> m_packedps; // Packed arrays to print with BasicDType
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
// METHODS
virtual void puts(const string& str) = 0;
@ -308,14 +310,23 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
puts(");\n");
}
void visit(AstJumpBlock* nodep) override {
putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n");
if (nodep->stmtsp()) iterateAndNextConstNull(nodep->stmtsp());
// Allocate label number
const size_t n = m_labelNumbers.size();
const bool newEntry = m_labelNumbers.emplace(nodep, n).second;
UASSERT_OBJ(newEntry, nodep, "AstJumpBlock visited twide");
// Emit
putbs("begin : label" + std::to_string(n) + "\n");
iterateAndNextConstNull(nodep->stmtsp());
puts("end\n");
}
void visit(AstJumpGo* nodep) override {
putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
// Retrieve target label number - Sometimes EmitV is used by debug code,
// so allow printing with an unknown target
const auto it = m_labelNumbers.find(nodep->blockp());
const std::string label
= it != m_labelNumbers.end() ? "label" + std::to_string(it->second) : "<UNKNOWN>";
putbs("disable " + label + ";\n");
}
void visit(AstJumpLabel* nodep) override { putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); }
void visit(AstNodeReadWriteMem* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs("(");

View File

@ -320,9 +320,7 @@ class HasherVisitor final : public VNVisitorConst {
});
}
void visit(AstJumpGo* nodep) override {
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
iterateConstNull(nodep->labelp());
});
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() {});
}
void visit(AstTraceInc* nodep) override {
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //

View File

@ -45,8 +45,8 @@ VL_DEFINE_DEBUG_FUNCTIONS;
class LinkJumpVisitor final : public VNVisitor {
// NODE STATE
// AstNode::user1() -> AstJumpLabel*, for this block if endOfIter
// AstNode::user2() -> AstJumpLabel*, for this block if !endOfIter
// AstNode::user1() -> AstJumpBlock*, for body of this loop
// AstNode::user2() -> AstJumpBlock*, for this block
// AstNodeBlock::user3() -> bool, true if contains a fork
const VNUser1InUse m_user1InUse;
const VNUser2InUse m_user2InUse;
@ -65,36 +65,34 @@ class LinkJumpVisitor final : public VNVisitor {
"__VprocessQueue"}; // Names for queues needed for 'disable' handling
// METHODS
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);
if (VN_IS(nodep, JumpLabel)) return VN_AS(nodep, JumpLabel); // Done
// Get (and create if necessary) the JumpBlock for this statement
AstJumpBlock* getJumpBlock(AstNode* nodep, bool endOfIter) {
// Wrap 'nodep' in JumpBlock. If loop, wrap the body instead if endOfIter is true
UINFO(4, "Create JumpBlock for " << nodep);
// Made it previously? We always jump to the end, so this works out
if (endOfIter) {
if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpLabel);
if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpBlock);
} else {
if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpLabel);
if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpBlock);
}
AstNode* underp = nullptr;
bool under_and_next = true;
if (VN_IS(nodep, NodeBlock)) {
underp = VN_AS(nodep, NodeBlock)->stmtsp();
} else if (VN_IS(nodep, NodeFTask)) {
underp = VN_AS(nodep, NodeFTask)->stmtsp();
} else if (VN_IS(nodep, Foreach)) {
if (AstNodeBlock* const blockp = VN_CAST(nodep, NodeBlock)) {
underp = blockp->stmtsp();
} else if (AstNodeFTask* const fTaskp = VN_CAST(nodep, NodeFTask)) {
underp = fTaskp->stmtsp();
} else if (AstForeach* const foreachp = VN_CAST(nodep, Foreach)) {
if (endOfIter) {
underp = VN_AS(nodep, Foreach)->stmtsp();
underp = foreachp->stmtsp();
} else {
underp = nodep;
under_and_next = false; // IE we skip the entire foreach
}
} else if (VN_IS(nodep, While)) {
} else if (AstWhile* const whilep = VN_CAST(nodep, While)) {
if (endOfIter) {
// Note we jump to end of bodysp; a FOR loop has its
// increment under incsp() which we don't skip
underp = VN_AS(nodep, While)->stmtsp();
underp = whilep->stmtsp();
} else {
underp = nodep;
under_and_next = false; // IE we skip the entire while
@ -118,36 +116,32 @@ class LinkJumpVisitor final : public VNVisitor {
UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement");
UINFO(5, " Underpoint is " << underp);
if (VN_IS(underp, JumpLabel)) {
return VN_AS(underp, JumpLabel);
} else { // Move underp stuff to be under a new label
AstJumpBlock* const blockp = new AstJumpBlock{nodep->fileline(), nullptr};
AstJumpLabel* const labelp = new AstJumpLabel{nodep->fileline(), blockp};
blockp->labelp(labelp);
VNRelinker repHandle;
if (under_and_next) {
underp->unlinkFrBackWithNext(&repHandle);
} else {
underp->unlinkFrBack(&repHandle);
}
repHandle.relink(blockp);
blockp->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 (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
}
// Label goes last
blockp->addEndStmtsp(labelp);
if (endOfIter) {
nodep->user1p(labelp);
} else {
nodep->user2p(labelp);
}
return labelp;
// If already wrapped, we are done ...
if (!underp->nextp() || !under_and_next) {
if (AstJumpBlock* const blockp = VN_CAST(underp, JumpBlock)) return blockp;
}
// Move underp stuff to be under a new AstJumpBlock
VNRelinker repHandle;
if (under_and_next) {
underp->unlinkFrBackWithNext(&repHandle);
} else {
underp->unlinkFrBack(&repHandle);
}
AstJumpBlock* const blockp = new AstJumpBlock{nodep->fileline(), underp};
if (endOfIter) {
nodep->user1p(blockp);
} else {
nodep->user2p(blockp);
}
repHandle.relink(blockp);
// Keep any AstVars under the function not under the new JumpLabel
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
nextp = varp->nextp();
if (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
}
return blockp;
}
void addPrefixToBlocksRecurse(const std::string& prefix, AstNode* const nodep) {
// Add a prefix to blocks
@ -379,8 +373,8 @@ class LinkJumpVisitor final : public VNVisitor {
nodep->lhsp()->unlinkFrBackWithNext()});
}
// Jump to the end of the function call
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
nodep->addHereThisAsNext(new AstJumpGo{nodep->fileline(), labelp});
AstJumpBlock* const blockp = getJumpBlock(m_ftaskp, false);
nodep->addHereThisAsNext(new AstJumpGo{nodep->fileline(), blockp});
}
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -391,8 +385,8 @@ class LinkJumpVisitor final : public VNVisitor {
nodep->v3error("break isn't underneath a loop");
} else {
// Jump to the end of the loop
AstJumpLabel* const labelp = findAddLabel(m_loopp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
AstJumpBlock* const blockp = getJumpBlock(m_loopp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
}
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -404,8 +398,8 @@ class LinkJumpVisitor final : public VNVisitor {
} else {
// Jump to the end of this iteration
// If a "for" loop then need to still do the post-loop increment
AstJumpLabel* const labelp = findAddLabel(m_loopp, true);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
AstJumpBlock* const blockp = getJumpBlock(m_loopp, true);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
}
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -444,8 +438,8 @@ class LinkJumpVisitor final : public VNVisitor {
"Unsupported: disabling block that contains a fork");
} else {
// Jump to the end of the named block
AstJumpLabel* const labelp = findAddLabel(beginp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
AstJumpBlock* const blockp = getJumpBlock(beginp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
}
} else {
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"

View File

@ -397,10 +397,9 @@ private:
UASSERT_OBJ(vscp, nodep, "Not linked");
return vscp;
}
bool jumpingOver(const AstNode* nodep) const {
// True to jump over this node - all visitors must call this up front
return (m_jumpp && m_jumpp->labelp() != nodep);
}
// True if current node might be jumped over - all visitors must call this up front
bool jumpingOver() const { return m_jumpp; }
void assignOutValue(AstNodeAssign* nodep, AstNode* vscp, const AstNodeExpr* valuep) {
if (VN_IS(nodep, AssignDly)) {
// Don't do setValue, as value isn't yet visible to following statements
@ -413,7 +412,7 @@ private:
// VISITORS
void visit(AstAlways* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
}
@ -421,7 +420,7 @@ private:
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
}
void visit(AstVarRef* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!optimizable()) return; // Accelerate
UASSERT_OBJ(nodep->varp(), nodep, "Unlinked");
iterateChildrenConst(nodep->varp());
@ -490,7 +489,7 @@ private:
}
}
void visit(AstVarXRef* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (m_scoped) {
badNodeType(nodep);
return;
@ -500,7 +499,7 @@ private:
}
}
void visit(AstNodeFTask* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!m_params) {
badNodeType(nodep);
return;
@ -520,7 +519,7 @@ private:
iterateChildrenConst(nodep);
}
void visit(AstInitialStatic* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!m_params) {
badNodeType(nodep);
return;
@ -529,7 +528,7 @@ private:
iterateChildrenConst(nodep);
}
void visit(AstNodeIf* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
UINFO(5, " IF " << nodep);
checkNodeInfo(nodep);
if (m_checkOnly) {
@ -856,7 +855,7 @@ private:
}
}
void visit(AstNodeAssign* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
@ -900,7 +899,7 @@ private:
iterateChildrenConst(nodep);
}
void visit(AstNodeCase* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
UINFO(5, " CASE " << nodep);
checkNodeInfo(nodep);
if (m_checkOnly) {
@ -939,7 +938,7 @@ private:
void visit(AstCaseItem* nodep) override {
// Real handling is in AstNodeCase
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
}
@ -947,12 +946,12 @@ private:
void visit(AstComment*) override {}
void visit(AstStmtExpr* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
}
void visit(AstExprStmt* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
checkNodeInfo(nodep);
iterateAndNextConstNull(nodep->stmtsp());
if (!optimizable()) return;
@ -962,30 +961,24 @@ private:
}
void visit(AstJumpBlock* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
iterateChildrenConst(nodep);
if (m_jumpp && m_jumpp->blockp() == nodep) {
UINFO(5, " JUMP DONE " << nodep);
m_jumpp = nullptr;
}
}
void visit(AstJumpGo* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
checkNodeInfo(nodep);
if (!m_checkOnly) {
UINFO(5, " JUMP GO " << nodep);
m_jumpp = nodep;
}
}
void visit(AstJumpLabel* nodep) override {
// This only supports forward jumps. That's all we make at present,
// AstJumpGo::broken uses brokeExistsBelow() to check this.
if (jumpingOver(nodep)) return;
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
if (m_jumpp && m_jumpp->labelp() == nodep) {
UINFO(5, " JUMP DONE " << nodep);
m_jumpp = nullptr;
}
}
void visit(AstStop* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (m_params) { // This message seems better than an obscure $stop
// The spec says $stop is just ignored, it seems evil to ignore assertions
clearOptimizable(
@ -1030,7 +1023,7 @@ private:
void visit(AstWhile* nodep) override {
// Doing lots of Whiles is slow, so only for parameters
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
UINFO(5, " WHILE " << nodep);
if (!m_params) {
badNodeType(nodep);
@ -1044,15 +1037,15 @@ private:
while (true) {
UINFO(5, " WHILE-ITER " << nodep);
iterateAndNextConstNull(nodep->condp());
if (jumpingOver(nodep)) break;
if (jumpingOver()) break;
if (!optimizable()) break;
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
break;
}
iterateAndNextConstNull(nodep->stmtsp());
if (jumpingOver(nodep)) break;
if (jumpingOver()) break;
iterateAndNextConstNull(nodep->incsp());
if (jumpingOver(nodep)) break;
if (jumpingOver()) break;
// Prep for next loop
if (loops++
@ -1068,7 +1061,7 @@ private:
}
void visit(AstFuncRef* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!optimizable()) return; // Accelerate
UINFO(5, " FUNCREF " << nodep);
checkNodeInfo(nodep);
@ -1140,7 +1133,7 @@ private:
}
void visit(AstVar* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!m_params) {
badNodeType(nodep);
return;
@ -1148,12 +1141,12 @@ private:
}
void visit(AstScopeName* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
// Ignore
}
void visit(AstSFormatF* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
@ -1214,7 +1207,7 @@ private:
}
void visit(AstDisplay* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
if (!optimizable()) return; // Accelerate
// We ignore isPredictOptimizable as $display is often in constant
// functions and we want them to work if used with parameters
@ -1242,11 +1235,11 @@ private:
// Some CMethods such as size() on queues could be supported, but
// instead we should change those methods to new Ast types so we can
// properly dispatch them
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
knownBadNodeType(nodep);
}
void visit(AstMemberSel* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
knownBadNodeType(nodep);
}
// ====
@ -1255,7 +1248,7 @@ private:
// AstCoverInc, AstFinish,
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
void visit(AstNode* nodep) override {
if (jumpingOver(nodep)) return;
if (jumpingOver()) return;
badNodeType(nodep);
}

View File

@ -116,10 +116,10 @@ module Vt_debug_emitv_t;
endtask
function f;
input int signed v;
begin : label0
begin : label1
$display("stmt");
f = ((v == 'sh0) ? 'sh63 : ((~ v) + 'sh1));
disable label0;
disable label1;
end
endfunction
initial begin
@ -203,12 +203,12 @@ module Vt_debug_emitv_t;
begin : unnamedblk3
int signed i;
i = 'sh0;
begin : label0
begin : label2
while ((i < cyc)) begin
begin
sum = (sum + i);
if ((sum > 'sha)) begin
disable label0;
disable label2;
end
else begin
sum = (sum + 'sh1);
@ -390,13 +390,13 @@ module Vt_debug_emitv_sub;
endtask
function f;
input int signed v;
begin : label0
begin : label3
if ((v == 'sh0)) begin
f = 'sh21;
disable label0;
disable label3;
end
f = ({32'h1{{31'h0, v[2]}}} + 32'h1);
disable label0;
disable label3;
end
endfunction
real r;