summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--elaborate.cxx89
-rw-r--r--translate.cxx87
3 files changed, 159 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 614d9cd9..11171c31 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-08-10 David Smith <dsmith@redhat.com>
+
+ * elaborate.cxx (duplicate_function_remover): Added class.
+ (get_functionsig): Added function.
+ (semantic_pass_opt5): New function merges duplicate identical
+ functions into one function.
+ (semantic_pass_optimize): Calls semantic_pass_opt5.
+
+ * translate.cxx (c_unparser::emit_probe): Changed to merge
+ duplicate probes bodies by making the duplicate probe just call
+ the original probe (BZ# 2421).
+
2006-08-08 Li Guanglei <guanglei@cn.ibm.com>
* stapprobes.5.in: document process.*, tcp.*, udp.*
diff --git a/elaborate.cxx b/elaborate.cxx
index b6d0f226..00a3a7c2 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1550,6 +1550,94 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
}
}
+struct duplicate_function_remover: public functioncall_traversing_visitor
+{
+ systemtap_session& s;
+ bool& relaxed_p;
+ map<functiondecl*, functiondecl*>& duplicate_function_map;
+
+ duplicate_function_remover(systemtap_session& sess, bool& r,
+ map<functiondecl*, functiondecl*>&dfm):
+ s(sess), relaxed_p(r), duplicate_function_map(dfm) {};
+
+ void visit_functioncall (functioncall* e);
+};
+
+void
+duplicate_function_remover::visit_functioncall (functioncall *e)
+{
+ functioncall_traversing_visitor::visit_functioncall (e);
+
+ // If the current function call reference points to a function that
+ // is a duplicate, replace it.
+ if (duplicate_function_map.count(e->referent) != 0)
+ {
+ if (s.verbose>2)
+ clog << "Changing " << e->referent->name
+ << " reference to "
+ << duplicate_function_map[e->referent]->name
+ << " reference\n";
+ e->tok = duplicate_function_map[e->referent]->tok;
+ e->function = duplicate_function_map[e->referent]->name;
+ e->referent = duplicate_function_map[e->referent];
+
+ relaxed_p = false;
+ }
+}
+
+static string
+get_functionsig (functiondecl* f)
+{
+ ostringstream s;
+
+ // Get the "name:args body" of the function in s. We have to
+ // include the args since the function 'x1(a, b)' is different than
+ // the function 'x2(b, a)' even if the bodies of the two functions
+ // are exactly the same.
+ f->printsig(s);
+ f->body->print(s);
+
+ // printsig puts f->name + ':' on the front. Remove this
+ // (otherwise, functions would never compare equal).
+ string str = s.str().erase(0, f->name.size() + 1);
+
+ // Return the function signature.
+ return str;
+}
+
+void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
+{
+ // Walk through all the functions, looking for duplicates.
+ map<string, functiondecl*> functionsig_map;
+ map<functiondecl*, functiondecl*> duplicate_function_map;
+ for (unsigned i=0; i < s.functions.size(); i++)
+ {
+ string functionsig = get_functionsig(s.functions[i]);
+
+ if (functionsig_map.count(functionsig) == 0)
+ // This function is unique. Remember it.
+ functionsig_map[functionsig] = s.functions[i];
+ else
+ // This function is a duplicate.
+ duplicate_function_map[s.functions[i]]
+ = functionsig_map[functionsig];
+ }
+
+ // If we have duplicate functions, traverse down the tree, replacing
+ // the appropriate function calls.
+ // duplicate_function_remover::visit_functioncall() handles the
+ // details of replacing the function calls. Note that we don't
+ // delete the duplicate functiondecl itself, we'll let pass 1 do
+ // that.
+ if (duplicate_function_map.size() != 0)
+ {
+ duplicate_function_remover dfr (s, relaxed_p, duplicate_function_map);
+
+ for (unsigned i=0; i < s.probes.size(); i++)
+ s.probes[i]->body->visit(&dfr);
+ }
+}
+
static int
semantic_pass_optimize (systemtap_session& s)
@@ -1571,6 +1659,7 @@ semantic_pass_optimize (systemtap_session& s)
semantic_pass_opt2 (s, relaxed_p);
semantic_pass_opt3 (s, relaxed_p);
semantic_pass_opt4 (s, relaxed_p);
+ semantic_pass_opt5 (s, relaxed_p);
}
if (s.probes.size() == 0)
diff --git a/translate.cxx b/translate.cxx
index 967949a4..88eb9634 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -68,6 +68,8 @@ struct c_unparser: public unparser, public visitor
unsigned tmpvar_counter;
unsigned label_counter;
+ map<string, string> probe_contents;
+
c_unparser (systemtap_session* ss):
session (ss), o (ss->op), current_probe(0), current_function (0),
tmpvar_counter (0), label_counter (0) {}
@@ -1270,40 +1272,67 @@ c_unparser::emit_probe (derived_probe* v)
o->newline() << "static void " << v->name << " (struct context * __restrict__ c) {";
o->indent(1);
- // initialize frame pointer
- o->newline() << "struct " << v->name << "_locals * __restrict__ l =";
- o->newline(1) << "& c->locals[0]." << v->name << ";";
- o->newline(-1) << "(void) l;"; // make sure "l" is marked used
-
- // emit all read/write locks for global variables
- varuse_collecting_visitor vut;
- v->body->visit (& vut);
- emit_locks (vut);
+ // If we about to emit a probe that is exactly the same as another
+ // probe previously emitted, make the second probe just call the
+ // first one.
+ //
+ // Notice we're using the probe body itself instead of the emitted C
+ // probe body to compare probes. We need to do this because the
+ // emitted C probe body has stuff in it like:
+ //
+ // c->last_stmt = "identifier 'printf' at foo.stp:<line>:<column>";
+ //
+ // which would make comparisons impossible.
+ ostringstream oss;
+ v->body->print(oss);
- // initialize locals
- for (unsigned j=0; j<v->locals.size(); j++)
- {
- if (v->locals[j]->index_types.size() > 0) // array?
- throw semantic_error ("array locals not supported", v->tok);
- else if (v->locals[j]->type == pe_long)
- o->newline() << "l->" << c_varname (v->locals[j]->name)
- << " = 0;";
- else if (v->locals[j]->type == pe_string)
- o->newline() << "l->" << c_varname (v->locals[j]->name)
- << "[0] = '\\0';";
- else
- throw semantic_error ("unsupported local variable type",
- v->locals[j]->tok);
+ // If an identical probe has already been emitted, just call that
+ // one.
+ if (probe_contents.count(oss.str()) != 0)
+ {
+ o->newline() << probe_contents[oss.str()] << " (c);";
}
+ // This probe is unique. Remember it and output it.
+ else
+ {
+ probe_contents[oss.str()] = v->name;
+
+ // initialize frame pointer
+ o->newline() << "struct " << v->name << "_locals * __restrict__ l =";
+ o->newline(1) << "& c->locals[0]." << v->name << ";";
+ o->newline(-1) << "(void) l;"; // make sure "l" is marked used
+
+ // emit all read/write locks for global variables
+ varuse_collecting_visitor vut;
+ v->body->visit (& vut);
+ emit_locks (vut);
+
+ // initialize locals
+ for (unsigned j=0; j<v->locals.size(); j++)
+ {
+ if (v->locals[j]->index_types.size() > 0) // array?
+ throw semantic_error ("array locals not supported", v->tok);
+ else if (v->locals[j]->type == pe_long)
+ o->newline() << "l->" << c_varname (v->locals[j]->name)
+ << " = 0;";
+ else if (v->locals[j]->type == pe_string)
+ o->newline() << "l->" << c_varname (v->locals[j]->name)
+ << "[0] = '\\0';";
+ else
+ throw semantic_error ("unsupported local variable type",
+ v->locals[j]->tok);
+ }
- v->body->visit (this);
+ v->body->visit (this);
- o->newline(-1) << "out:";
- // NB: no need to uninitialize locals, except if arrays can somedays be local
- // XXX: do this flush only if the body included a print/printf/etc. routine!
- o->newline(1) << "_stp_print_flush();";
+ o->newline(-1) << "out:";
+ // NB: no need to uninitialize locals, except if arrays can
+ // somedays be local XXX: do this flush only if the body
+ // included a print/printf/etc. routine!
+ o->newline(1) << "_stp_print_flush();";
- emit_unlocks (vut);
+ emit_unlocks (vut);
+ }
o->newline(-1) << "}\n";