diff --git a/src/V3Ast.h b/src/V3Ast.h index 14ba42da5..207b3e11e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -544,9 +544,12 @@ public: static const char* const names[] = { "FALSE", "TRUE", "UNK"}; return names[m_e]; } - bool trueU() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; } - bool falseU() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; } + bool trueKnown() const { return m_e == BU_TRUE; } + bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; } + bool falseKnown() const { return m_e == BU_FALSE; } + bool falseUnknown() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; } bool unknown() const { return m_e == BU_UNKNOWN; } + void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; } }; inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator==(VBoolOrUnknown lhs, VBoolOrUnknown::en rhs) { return (lhs.m_e == rhs); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8b2f93b3b..fa85dd516 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1336,7 +1336,7 @@ void AstCFunc::dump(std::ostream& str) const { if (slow()) str<<" [SLOW]"; if (pure()) str<<" [PURE]"; if (isStatic().unknown()) str<<" [STATICU]"; - else if (isStatic().trueU()) str<<" [STATIC]"; + else if (isStatic().trueUnknown()) str<<" [STATIC]"; if (dpiImport()) str<<" [DPII]"; if (dpiExport()) str<<" [DPIX]"; if (dpiExportWrapper()) str<<" [DPIXWR]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 37947da07..f8b74b796 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -6629,6 +6629,7 @@ private: string m_rtnType; // void, bool, or other return type string m_argTypes; string m_ifdef; // #ifdef symbol around this function + VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) VBoolOrUnknown m_isStatic; // Function is declared static (no this) bool m_dontCombine:1; // V3Combine shouldn't compare this func tree, it's special bool m_skipDecl:1; // Don't declare it @@ -6636,6 +6637,7 @@ private: bool m_formCallTree:1; // Make a global function to call entire tree of functions bool m_slow:1; // Slow routine, called once or just at init time bool m_funcPublic:1; // From user public task/function + bool m_isMethod:1; // Is inside a class definition bool m_isInline:1; // Inline function bool m_symProlog:1; // Setup symbol table for later instructions bool m_entryPoint:1; // User may call into this top level function @@ -6648,6 +6650,7 @@ public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="") : ASTGEN_SUPER(fl) { m_funcType = AstCFuncType::FT_NORMAL; + m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed m_isStatic = VBoolOrUnknown::BU_UNKNOWN; // Unknown until see where thisp needed m_scopep = scopep; m_name = name; @@ -6658,6 +6661,7 @@ public: m_formCallTree = false; m_slow = false; m_funcPublic = false; + m_isMethod = true; m_isInline = false; m_symProlog = false; m_entryPoint = false; @@ -6683,8 +6687,11 @@ public: // virtual void name(const string& name) { m_name = name; } virtual int instrCount() const { return dpiImport() ? instrCountDpi() : 0; } + VBoolOrUnknown isConst() const { return m_isConst; } + void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); } + void isConst(VBoolOrUnknown flag) { m_isConst = flag; } VBoolOrUnknown isStatic() const { return m_isStatic; } - void isStatic(bool flag) { m_isStatic = flag ? VBoolOrUnknown::BU_TRUE : VBoolOrUnknown::BU_FALSE; } + void isStatic(bool flag) { m_isStatic.setTrueOrFalse(flag); } void isStatic(VBoolOrUnknown flag) { m_isStatic = flag; } void cname(const string& name) { m_cname = name; } string cname() const { return m_cname; } @@ -6710,6 +6717,8 @@ public: string ifdef() const { return m_ifdef; } void funcType(AstCFuncType flag) { m_funcType = flag; } AstCFuncType funcType() const { return m_funcType; } + bool isMethod() const { return m_isMethod; } + void isMethod(bool flag) { m_isMethod = flag; } bool isInline() const { return m_isInline; } void isInline(bool flag) { m_isInline = flag; } bool symProlog() const { return m_symProlog; } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 59fb8214a..e04a62393 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -138,7 +138,7 @@ private: // (Here instead of new visitor after V3Descope just to avoid another visitor) void needNonStaticFunc(AstNode* nodep) { UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function"); - if (m_funcp->isStatic().trueU()) { + if (m_funcp->isStatic().trueUnknown()) { UINFO(5,"Mark non-public due to "<isStatic(false); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 5a1635586..f48a27ce5 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -273,7 +273,7 @@ private: virtual void visit(AstCFunc* nodep) VL_OVERRIDE { if (!nodep->user1()) { m_needThis = false; - m_allowThis = nodep->isStatic().falseU(); // Non-static or unknown if static + m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static iterateChildren(nodep); nodep->user1(true); if (m_needThis) nodep->isStatic(false); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 4986c4a45..b05c781b0 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -155,13 +155,17 @@ public: return lhsp->name() < rhsp->name(); } }; - void emitIntFuncDecls(AstNodeModule* modp) { + void emitIntFuncDecls(AstNodeModule* modp, bool methodFuncs) { typedef std::vector FuncVec; FuncVec funcsp; for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) { - if (!funcp->skipDecl()) { funcsp.push_back(funcp); } + if (!funcp->skipDecl() + && funcp->isMethod() == methodFuncs + && !funcp->dpiImport()) { // DPI is prototyped in __Dpi.h + funcsp.push_back(funcp); + } } } @@ -169,21 +173,20 @@ public: for (FuncVec::iterator it = funcsp.begin(); it != funcsp.end(); ++it) { const AstCFunc* funcp = *it; - if (!funcp->dpiImport()) { // DPI is prototyped in __Dpi.h - ofp()->putsPrivate(funcp->declPrivate()); - if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n"); - if (funcp->isStatic().trueU()) puts("static "); - puts(funcp->rtnTypeVoid()); - puts(" "); - puts(funcp->nameProtect()); - puts("(" + cFuncArgs(funcp) + ")"); - if (funcp->slow()) puts(" VL_ATTR_COLD"); - puts(";\n"); - if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); - } + ofp()->putsPrivate(funcp->declPrivate()); + if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n"); + if (funcp->isStatic().trueUnknown()) puts("static "); + puts(funcp->rtnTypeVoid()); + puts(" "); + puts(funcp->nameProtect()); + puts("(" + cFuncArgs(funcp) + ")"); + if (funcp->isConst().trueKnown()) puts(" const"); + if (funcp->slow()) puts(" VL_ATTR_COLD"); + puts(";\n"); + if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); } - if (modp->isTop() && v3Global.opt.mtasks()) { + if (methodFuncs && modp->isTop() && v3Global.opt.mtasks()) { // Emit the mtask func prototypes. AstExecGraph* execGraphp = v3Global.rootp()->execGraphp(); UASSERT_OBJ(execGraphp, v3Global.rootp(), "Root should have an execGraphp"); @@ -1245,8 +1248,10 @@ class EmitCImp : EmitCStmts { if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n"); if (nodep->isInline()) puts("VL_INLINE_OPT "); puts(nodep->rtnTypeVoid()); puts(" "); - puts(prefixNameProtect(m_modp) + "::" + nodep->nameProtect() + "(" + cFuncArgs(nodep) - + ") {\n"); + if (nodep->isMethod()) puts(prefixNameProtect(m_modp) + "::"); + puts(nodep->nameProtect() + "(" + cFuncArgs(nodep) + ")"); + if (nodep->isConst().trueKnown()) puts(" const"); + puts(" {\n"); // "+" in the debug indicates a print from the model puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ "); @@ -2738,7 +2743,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { ofp()->putsPrivate(false); // public: puts("void "+protect("__Vconfigure")+"("+symClassName()+"* symsp, bool first);\n"); - emitIntFuncDecls(modp); + emitIntFuncDecls(modp, true); if (v3Global.opt.trace()) { ofp()->putsPrivate(false); // public: @@ -2757,6 +2762,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("} VL_ATTR_ALIGNED(128);\n"); + emitIntFuncDecls(modp, false); + // Save/restore if (v3Global.opt.savable() && modp->isTop()) { puts("\n");