// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Branch prediction // // Code available from: http://www.veripool.org/verilator // //************************************************************************* // // Copyright 2003-2019 by Wilson Snyder. This program is free software; you can // redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License // Version 2.0. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* // BRANCH TRANSFORMATIONS: // At each IF/(IF else). // Count underneath $display/$stop statements. // If more on if than else, this branch is unlikely, or vice-versa. // At each FTASKREF, // Count calls into the function // Then, if FTASK is called only once, add inline attribute // //************************************************************************* #include "config_build.h" #include "verilatedos.h" #include "V3Global.h" #include "V3Branch.h" #include "V3Ast.h" #include #include //###################################################################### // Branch state, as a visitor of each AstNode class BranchVisitor : public AstNVisitor { private: // NODE STATE // Entire netlist: // AstFTask::user1() -> int. Number of references AstUser1InUse m_inuser1; // TYPES typedef std::vector CFuncVec; // STATE int m_likely; // Excuses for branch likely taken int m_unlikely; // Excuses for branch likely not taken CFuncVec m_cfuncsp; // List of all tasks // METHODS VL_DEBUG_FUNC; // Declare debug() void reset() { m_likely = false; m_unlikely = false; } void checkUnlikely(AstNode* nodep) { if (nodep->isUnlikely()) { UINFO(4," UNLIKELY: "<ifsp()); int ifLikely = m_likely; int ifUnlikely = m_unlikely; // Do else reset(); iterateAndNextNull(nodep->elsesp()); int elseLikely = m_likely; int elseUnlikely = m_unlikely; // Compute int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely); if (likeness>0) { nodep->branchPred(AstBranchPred::BP_LIKELY); } else if (likeness<0) { nodep->branchPred(AstBranchPred::BP_UNLIKELY); } // else leave unknown } m_likely = lastLikely; m_unlikely = lastUnlikely; } virtual void visit(AstCCall* nodep) { checkUnlikely(nodep); nodep->funcp()->user1Inc(); iterateChildren(nodep); } virtual void visit(AstCFunc* nodep) { checkUnlikely(nodep); m_cfuncsp.push_back(nodep); iterateChildren(nodep); } virtual void visit(AstNode* nodep) { checkUnlikely(nodep); iterateChildren(nodep); } // METHODS void calc_tasks() { for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) { AstCFunc* nodep = *it; if (!nodep->dontInline()) { nodep->isInline(true); } } } public: // CONSTUCTORS explicit BranchVisitor(AstNetlist* nodep) { reset(); iterateChildren(nodep); calc_tasks(); } virtual ~BranchVisitor() {} }; //###################################################################### // Branch class functions void V3Branch::branchAll(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<