Inline C functions that are used only once, msg1525.

This commit is contained in:
Wilson Snyder 2014-11-27 10:52:38 -05:00
parent 5078152292
commit 68c6f0ff07
9 changed files with 72 additions and 12 deletions

View File

@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks!
** SystemPerl mode is deprecated and now untested. ** SystemPerl mode is deprecated and now untested.
*** Inline C functions that are used only once, msg1525. [Jie Xu]
* Verilator 3.866 2014-11-15 * Verilator 3.866 2014-11-15

View File

@ -1399,6 +1399,10 @@ especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
both compilation and link. Note LTO may cause excessive compile times on both compilation and link. Note LTO may cause excessive compile times on
large designs. large designs.
If you are using your own makefiles, you may want to compile the Verilated
code with -DVL_INLINE_OPT=inline. This will inline functions, however this
requires that all cpp files be compiled in a single compiler run.
You may uncover further tuning possibilities by profiling the Verilog code. You may uncover further tuning possibilities by profiling the Verilog code.
Use Verilator's --profile-cfuncs, then GCC's -g -pg. You can then run Use Verilator's --profile-cfuncs, then GCC's -g -pg. You can then run
either oprofile or gprof to see where in the C++ code the time is spent. either oprofile or gprof to see where in the C++ code the time is spent.

View File

@ -12,5 +12,9 @@ require 5.005;
use warnings; use warnings;
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n"; print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
foreach my $param (@ARGV) { foreach my $param (@ARGV) {
if ($param =~ /^-D([^=]+)=(.*)/) {
print "#define $1 $2\n"
} else {
print "#include \"$param\"\n" print "#include \"$param\"\n"
}
} }

View File

@ -23,7 +23,9 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
# Programs # Programs
SP_PREPROC = sp_preproc SP_PREPROC = sp_preproc
SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer SP_INCLUDER = $(VERILATOR_INCLUDER)
VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
###################################################################### ######################################################################
# Make checks # Make checks
@ -151,15 +153,15 @@ VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW)) VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
ifneq ($(VM_PARALLEL_BUILDS),1) ifneq ($(VM_PARALLEL_BUILDS),0)
# Fast building, all .cpp's in one fell swoop # Fast building, all .cpp's in one fell swoop
# This saves about 5 sec per module, but can be slower if only a little changes # This saves about 5 sec per module, but can be slower if only a little changes
VK_OBJS += $(VM_PREFIX)__ALLcls.o $(VM_PREFIX)__ALLsup.o VK_OBJS += $(VM_PREFIX)__ALLcls.o $(VM_PREFIX)__ALLsup.o
all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp
$(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP) $(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP)
$(SP_INCLUDER) $^ > $@ $(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
$(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP) $(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP)
$(SP_INCLUDER) $^ > $@ $(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
else else
#Slow way of building... Each .cpp file by itself #Slow way of building... Each .cpp file by itself
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT)) VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))

View File

@ -105,6 +105,13 @@
# define VL_UNIQUE_PTR auto_ptr # define VL_UNIQUE_PTR auto_ptr
#endif #endif
//=========================================================================
// Optimization
#ifndef VL_INLINE_OPT
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif
//========================================================================= //=========================================================================
// Warning disabled // Warning disabled

View File

@ -4699,6 +4699,7 @@ private:
bool m_formCallTree:1; // Make a global function to call entire tree of functions 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_slow:1; // Slow routine, called once or just at init time
bool m_funcPublic:1; // From user public task/function bool m_funcPublic:1; // From user public task/function
bool m_isInline:1; // Inline function
bool m_isStatic:1; // Function is declared static (no this) bool m_isStatic:1; // Function is declared static (no this)
bool m_symProlog:1; // Setup symbol table for later instructions bool m_symProlog:1; // Setup symbol table for later instructions
bool m_entryPoint:1; // User may call into this top level function bool m_entryPoint:1; // User may call into this top level function
@ -4719,6 +4720,7 @@ public:
m_formCallTree = false; m_formCallTree = false;
m_slow = false; m_slow = false;
m_funcPublic = false; m_funcPublic = false;
m_isInline = false;
m_isStatic = true; // Note defaults to static, later we see where thisp is needed m_isStatic = true; // Note defaults to static, later we see where thisp is needed
m_symProlog = false; m_symProlog = false;
m_entryPoint = false; m_entryPoint = false;
@ -4748,6 +4750,7 @@ public:
string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); } string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); }
bool dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; } bool dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; }
void dontCombine(bool flag) { m_dontCombine = flag; } void dontCombine(bool flag) { m_dontCombine = flag; }
bool dontInline() const { return !dontCombine() && !slow() && !skipDecl() && !funcPublic(); }
bool skipDecl() const { return m_skipDecl; } bool skipDecl() const { return m_skipDecl; }
void skipDecl(bool flag) { m_skipDecl = flag; } void skipDecl(bool flag) { m_skipDecl = flag; }
bool declPrivate() const { return m_declPrivate; } bool declPrivate() const { return m_declPrivate; }
@ -4762,6 +4765,8 @@ public:
string argTypes() const { return m_argTypes; } string argTypes() const { return m_argTypes; }
void funcType(AstCFuncType flag) { m_funcType = flag; } void funcType(AstCFuncType flag) { m_funcType = flag; }
AstCFuncType funcType() const { return m_funcType; } AstCFuncType funcType() const { return m_funcType; }
bool isInline() const { return m_isInline; }
void isInline(bool flag) { m_isInline = flag; }
bool isStatic() const { return m_isStatic; } bool isStatic() const { return m_isStatic; }
void isStatic(bool flag) { m_isStatic = flag; } void isStatic(bool flag) { m_isStatic = flag; }
bool symProlog() const { return m_symProlog; } bool symProlog() const { return m_symProlog; }

View File

@ -21,6 +21,9 @@
// At each IF/(IF else). // At each IF/(IF else).
// Count underneath $display/$stop statements. // Count underneath $display/$stop statements.
// If more on if than else, this branch is unlikely, or vice-versa. // 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
// //
//************************************************************************* //*************************************************************************
@ -40,9 +43,18 @@
class BranchVisitor : public AstNVisitor { class BranchVisitor : public AstNVisitor {
private: private:
// NODE STATE
// Entire netlist:
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
// TYPES
typedef vector<AstCFunc*> CFuncVec;
// STATE // STATE
int m_likely; // Excuses for branch likely taken int m_likely; // Excuses for branch likely taken
int m_unlikely; // Excuses for branch likely not taken int m_unlikely; // Excuses for branch likely not taken
CFuncVec m_cfuncsp; // List of all tasks
// METHODS // METHODS
static int debug() { static int debug() {
@ -55,6 +67,12 @@ private:
m_likely = false; m_likely = false;
m_unlikely = false; m_unlikely = false;
} }
void checkUnlikely(AstNode* nodep) {
if (nodep->isUnlikely()) {
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
}
// VISITORS // VISITORS
virtual void visit(AstNodeIf* nodep, AstNUser*) { virtual void visit(AstNodeIf* nodep, AstNUser*) {
@ -83,20 +101,37 @@ private:
m_likely = lastLikely; m_likely = lastLikely;
m_unlikely = lastUnlikely; m_unlikely = lastUnlikely;
} }
virtual void visit(AstNode* nodep, AstNUser*) { virtual void visit(AstCCall* nodep, AstNUser*) {
// Default: Just iterate checkUnlikely(nodep);
if (nodep->isUnlikely()) { nodep->funcp()->user1Inc();
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
virtual void visit(AstCFunc* nodep, AstNUser*) {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
checkUnlikely(nodep);
nodep->iterateChildren(*this);
}
// 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: public:
// CONSTUCTORS // CONSTUCTORS
BranchVisitor(AstNetlist* nodep) { BranchVisitor(AstNetlist* nodep) {
reset(); reset();
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
calc_tasks();
} }
virtual ~BranchVisitor() {} virtual ~BranchVisitor() {}
}; };

View File

@ -829,6 +829,7 @@ class EmitCImp : EmitCStmts {
splitSizeInc(nodep); splitSizeInc(nodep);
puts("\n"); puts("\n");
if (nodep->isInline()) puts("VL_INLINE_OPT ");
puts(nodep->rtnTypeVoid()); puts(" "); puts(nodep->rtnTypeVoid()); puts(" ");
puts(modClassName(m_modp)+"::"+nodep->name() puts(modClassName(m_modp)+"::"+nodep->name()
+"("+cFuncArgs(nodep)+") {\n"); +"("+cFuncArgs(nodep)+") {\n");

View File

@ -52,7 +52,7 @@ endif
#Our own compile rules; Faster compile, all in one file #Our own compile rules; Faster compile, all in one file
$(VM_PREFIX)__ALLboth.cpp: $(VK_CLASSES_CPP) $(VK_SUPPORT_CPP) $(VM_PREFIX)__ALLboth.cpp: $(VK_CLASSES_CPP) $(VK_SUPPORT_CPP)
$(SP_INCLUDER) $^ > $@ $(VERILATOR_INCLUDER) -DVL_INLINE_OPT=inline $^ > $@
$(VM_PREFIX)__ALLboth.o: $(VM_PREFIX)__ALLboth.cpp $(VM_PREFIX)__ALLboth.o: $(VM_PREFIX)__ALLboth.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $< $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<