From 546ccd56c4b56d046eea2c3603cc1a060a27eb75 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 6 May 2020 21:33:05 -0400 Subject: [PATCH] Internals: Enable future JumpGo to non-end. No functional change intended. --- src/V3Ast.h | 1 + src/V3AstNodes.cpp | 20 ++++++++++++--- src/V3AstNodes.h | 64 ++++++++++++++++++++++++++++++++++++---------- src/V3Broken.cpp | 12 +++++++++ src/V3Const.cpp | 25 ++++++++++++------ src/V3EmitC.cpp | 13 ++++++---- src/V3EmitV.cpp | 13 ++++++---- src/V3Life.cpp | 2 +- src/V3LinkJump.cpp | 20 ++++++++++----- src/V3Simulate.h | 6 +++++ 10 files changed, 133 insertions(+), 43 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 0383f6d9d..13cc8be24 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1508,6 +1508,7 @@ public: } bool brokeExists() const; bool brokeExistsAbove() const; + bool brokeExistsBelow() const; // CONSTRUCTORS virtual ~AstNode() {} diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index c7fb643c2..bcfc68fa0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -746,6 +746,14 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { return nodep; } +const char* AstJumpBlock::broken() const { + BROKEN_RTN(!labelp()->brokeExistsBelow()); + return NULL; +} +void AstJumpBlock::cloneRelink() { + if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); +} + const char* AstScope::broken() const { BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists()); BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists()); @@ -753,7 +761,6 @@ const char* AstScope::broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return NULL; } - void AstScope::cloneRelink() { if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep(); if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep(); @@ -761,7 +768,6 @@ void AstScope::cloneRelink() { static_cast(m_modp)->clonep(); } } - string AstScope::nameDotless() const { string out = shortName(); string::size_type pos; @@ -780,7 +786,6 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const { if (out.substr(0, 1) == ".") out.replace(0, 1, ""); return AstNode::prettyName(out); } - string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const { string out; for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) { @@ -1142,6 +1147,15 @@ void AstJumpGo::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstJumpLabel::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " -> "; + if (blockp()) { + blockp()->dump(str); + } else { + str << "%Error:UNLINKED"; + } +} void AstMemberSel::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> "; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 420deba68..235125f93 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4292,44 +4292,81 @@ public: void priorityPragma(bool flag) { m_priorityPragma = flag; } }; -class AstJumpLabel : public AstNodeStmt { - // Jump point declaration - // Separate from AstJumpGo; as a declaration can't be deleted +class AstJumpBlock : public AstNodeStmt { + // Block of code including a JumpGo and JumpLabel // Parents: {statement list} - // Children: {statement list, with JumpGo below} + // Children: {statement list, with JumpGo and JumpLabel below} private: + AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment public: - AstJumpLabel(FileLine* fl, AstNode* stmtsp) + // After construction must call ->labelp to associate with appropriate label + AstJumpBlock(FileLine* fl, AstNode* stmtsp) : ASTGEN_SUPER(fl) , m_labelNum(0) { addNOp1p(stmtsp); } + virtual const char* broken() const; + virtual void cloneRelink(); + ASTNODE_NODE_FUNCS(JumpBlock) virtual int instrCount() const { return 0; } - ASTNODE_NODE_FUNCS(JumpLabel) virtual bool maybePointedTo() const { return true; } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } // op1 = Statements AstNode* stmtsp() const { return op1p(); } // op1 = List of statements void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block + void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); } 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; } +}; + +class AstJumpLabel : public AstNodeStmt { + // Jump point declaration + // Parents: {statement list with JumpBlock above} + // Children: none +private: + AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration +public: + AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) + : ASTGEN_SUPER(fl) + , m_blockp(blockp) {} + ASTNODE_NODE_FUNCS(JumpLabel) + virtual bool maybePointedTo() const { return true; } + virtual const char* broken() const { + BROKEN_RTN(!blockp()->brokeExistsAbove()); + BROKEN_RTN(blockp()->labelp() != this); + return NULL; + } + virtual void cloneRelink() { + if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); + } + virtual void dump(std::ostream& str) const; + virtual int instrCount() const { return 0; } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { + return blockp() == static_cast(samep)->blockp(); + } + AstJumpBlock* blockp() const { return m_blockp; } }; class AstJumpGo : public AstNodeStmt { - // Jump point; branch up to the JumpLabel - // Parents: {statement list} + // Jump point; branch down to a JumpLabel + // No support for backward jumps at present + // Parents: {statement list with JumpBlock above} + // Children: none private: AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration public: AstJumpGo(FileLine* fl, AstJumpLabel* labelp) - : ASTGEN_SUPER(fl) { - m_labelp = labelp; - } - ASTNODE_NODE_FUNCS(JumpGo) + : ASTGEN_SUPER(fl) + , m_labelp(labelp) {} + ASTNODE_NODE_FUNCS(JumpGo); virtual const char* broken() const { - BROKEN_RTN(!labelp()->brokeExistsAbove()); + BROKEN_RTN(!labelp()->brokeExistsBelow()); return NULL; } virtual void cloneRelink() { @@ -4339,7 +4376,6 @@ public: virtual int instrCount() const { return instrCountBranch(); } virtual V3Hash sameHash() const { return V3Hash(labelp()); } virtual bool same(const AstNode* samep) const { - // Also same if identical tree structure all the way down, but hard to detect return labelp() == static_cast(samep)->labelp(); } virtual bool isGateOptimizable() const { return false; } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 21db1485f..d8afe8742 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -131,6 +131,14 @@ public: if (!(iter->second & FLAG_LINKABLE)) return false; return true; } + static bool okIfAbove(const AstNode* nodep) { + // Must be linked to and below current node + if (!okIfLinkedTo(nodep)) return false; + NodeMap::iterator iter = s_nodes.find(nodep); + if (iter == s_nodes.end()) return false; + if ((iter->second & FLAG_UNDER_NOW)) return false; + return true; + } static bool okIfBelow(const AstNode* nodep) { // Must be linked to and below current node if (!okIfLinkedTo(nodep)) return false; @@ -193,6 +201,10 @@ bool AstNode::brokeExistsAbove() const { // Called by node->broken() routines to do table lookup return BrokenTable::okIfBelow(this); } +bool AstNode::brokeExistsBelow() const { + // Called by node->broken() routines to do table lookup + return BrokenTable::okIfAbove(this); +} //###################################################################### diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 4cff5c4b8..7db3b5647 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2167,24 +2167,32 @@ private: } virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { iterateChildren(nodep); - m_hasJumpDelay = true; + // Jump to label where label immediately follows label is not useful + if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) { + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + // Keep the label, might be other jumps pointing to it, gets cleaned later + return; + } if (m_doExpensive) { // 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 (!nodep->nextp()) { - if (AstJumpLabel* aboveLabelp = VN_CAST(nodep->abovep(), JumpLabel)) { - if (aboveLabelp == nodep->labelp()) { - UINFO(4, "JUMPGO => last remove " << nodep << endl); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - return; + if (AstJumpBlock* aboveBlockp = VN_CAST(nodep->abovep(), JumpBlock)) { + if (aboveBlockp == nodep->labelp()->blockp()) { + if (aboveBlockp->endStmtsp() == nodep->labelp()) { + UINFO(4, "JUMPGO => last remove " << nodep << endl); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } } } } - nodep->labelp()->user4(true); + nodep->labelp()->blockp()->user4(true); } + m_hasJumpDelay = true; } - virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { + virtual void visit(AstJumpBlock* nodep) VL_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 @@ -2199,6 +2207,7 @@ private: } else { nodep->unlinkFrBack(); } + nodep->labelp()->unlinkFrBack()->deleteTree(); VL_DO_DANGLING(nodep->deleteTree(), nodep); } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index d31156ccf..016bb6b3f 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -697,15 +697,18 @@ public: iterateAndNextNull(nodep->lhsp()); puts(")"); } - virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { - puts("goto __Vlabel" + cvtToStr(nodep->labelp()->labelNum()) + ";\n"); - } - virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { + virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE { nodep->labelNum(++m_labelNum); puts("{\n"); // Make it visually obvious label jumps outside these iterateAndNextNull(nodep->stmtsp()); + iterateAndNextNull(nodep->endStmtsp()); puts("}\n"); - puts("__Vlabel" + cvtToStr(nodep->labelNum()) + ": ;\n"); + } + virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { + puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); + } + virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { + puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); } virtual void visit(AstWhile* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->precondsp()); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 5b28dec41..3fee6c161 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -272,14 +272,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->filep()) iterateAndNextNull(nodep->filep()); puts(");\n"); } - virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { - putbs("disable " + cvtToHex(nodep->labelp()) + ";\n"); - } - virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { - putbs("begin : " + cvtToHex(nodep) + "\n"); + virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE { + putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n"); if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp()); puts("end\n"); } + virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { + putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); + } + virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { + putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); + } virtual void visit(AstNodeReadWriteMem* nodep) VL_OVERRIDE { putfs(nodep, nodep->verilogKwd()); putbs(" ("); diff --git a/src/V3Life.cpp b/src/V3Life.cpp index fdad0d2e2..5172dab1e 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -390,7 +390,7 @@ private: VL_DO_DANGLING(delete condLifep, condLifep); VL_DO_DANGLING(delete bodyLifep, bodyLifep); } - virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE { + virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE { // As with While's we can't predict if a JumpGo will kill us or not // It's worse though as an IF(..., JUMPGO) may change the control flow. // Just don't optimize blocks with labels; they're rare - so far. diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 867e2a66a..566060394 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -21,9 +21,11 @@ // FOR -> WHILEs // // Add JumpLabel which branches to after statements within JumpLabel -// RETURN -> JUMPLABEL(statements with RETURN changed to JUMPGO) -// WHILE(... BREAK) -> JUMPLABEL(WHILE(... statements with BREAK changed to JUMPGO) -// WHILE(... CONTINUE) -> WHILE(JUMPLABEL(... statements with CONTINUE changed to JUMPGO) +// RETURN -> JUMPBLOCK(statements with RETURN changed to JUMPGO, ..., JUMPLABEL) +// WHILE(... BREAK) -> JUMPBLOCK(WHILE(... statements with BREAK changed to JUMPGO), +// ... JUMPLABEL) +// WHILE(... CONTINUE) -> WHILE(JUMPBLOCK(... statements with CONTINUE changed to JUMPGO, +// ... JUMPPABEL)) // //************************************************************************* @@ -90,7 +92,9 @@ private: if (VN_IS(underp, JumpLabel)) { return VN_CAST(underp, JumpLabel); } else { // Move underp stuff to be under a new label - AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL); + AstJumpBlock* blockp = new AstJumpBlock(nodep->fileline(), NULL); + AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), blockp); + blockp->labelp(labelp); AstNRelinker repHandle; if (under_and_next) { @@ -98,14 +102,16 @@ private: } else { underp->unlinkFrBack(&repHandle); } - repHandle.relink(labelp); + repHandle.relink(blockp); - labelp->addStmtsp(underp); + 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)) labelp->addPrev(varp->unlinkFrBack()); + if (VN_IS(varp, Var)) blockp->addPrev(varp->unlinkFrBack()); } + // Label goes last + blockp->addEndStmtsp(labelp); return labelp; } } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index ac14e601f..2d9e018e9 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -818,6 +818,10 @@ private: virtual void visit(AstComment*) VL_OVERRIDE {} + virtual void visit(AstJumpBlock* nodep) VL_OVERRIDE { + if (jumpingOver(nodep)) return; + iterateChildren(nodep); + } virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { if (jumpingOver(nodep)) return; checkNodeInfo(nodep); @@ -827,6 +831,8 @@ private: } } virtual void visit(AstJumpLabel* nodep) VL_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); iterateChildren(nodep);