summaryrefslogtreecommitdiffstats
path: root/elaborate.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'elaborate.cxx')
-rw-r--r--elaborate.cxx568
1 files changed, 522 insertions, 46 deletions
diff --git a/elaborate.cxx b/elaborate.cxx
index 2f246e2c..73358a1d 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1,5 +1,6 @@
// elaboration functions
// Copyright (C) 2005-2008 Red Hat Inc.
+// Copyright (C) 2008 Intel Corporation
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
@@ -322,7 +323,7 @@ match_node::find_and_build (systemtap_session& s,
throw semantic_error (string("probe point truncated at position ") +
lex_cast<string> (pos) +
- " (follow:" + alternatives + ")");
+ " (follow:" + alternatives + ")", loc->tok);
}
map<string, literal *> param_map;
@@ -394,7 +395,8 @@ match_node::find_and_build (systemtap_session& s,
throw semantic_error(string("probe point mismatch at position ") +
lex_cast<string> (pos) +
- " (alternatives:" + alternatives + ")");
+ " (alternatives:" + alternatives + ")",
+ loc->tok);
}
}
else
@@ -409,7 +411,8 @@ match_node::find_and_build (systemtap_session& s,
throw semantic_error (string("probe point mismatch at position ") +
lex_cast<string> (pos) +
- " (alternatives:" + alternatives + ")");
+ " (alternatives:" + alternatives + ")",
+ loc->tok);
}
match_node* subnode = i->second;
@@ -1194,11 +1197,40 @@ systemtap_session::systemtap_session ():
op (0), up (0),
sym_kprobes_text_start (0),
sym_kprobes_text_end (0),
- sym_stext (0)
+ sym_stext (0),
+ module_cache (0),
+ last_token (0)
{
}
+// Print this given token, but abbreviate it if the last one had the
+// same file name.
+void
+systemtap_session::print_token (ostream& o, const token* tok)
+{
+ assert (tok);
+
+ if (last_token && last_token->location.file == tok->location.file)
+ {
+ stringstream tmpo;
+ tmpo << *tok;
+ string ts = tmpo.str();
+ // search & replace the file name with nothing
+ size_t idx = ts.find (tok->location.file);
+ if (idx != string::npos)
+ ts.replace (idx, tok->location.file.size(), "");
+
+ o << ts;
+ }
+ else
+ o << *tok;
+
+ last_token = tok;
+}
+
+
+
void
systemtap_session::print_error (const semantic_error& e)
{
@@ -1211,9 +1243,9 @@ systemtap_session::print_error (const semantic_error& e)
message << "semantic error: " << e.what ();
if (e.tok1 || e.tok2)
message << ": ";
- if (e.tok1) message << *e.tok1;
+ if (e.tok1) print_token (message, e.tok1);
message << e.msg2;
- if (e.tok2) message << *e.tok2;
+ if (e.tok2) print_token (message, e.tok2);
message << endl;
message_str = message.str();
@@ -1228,6 +1260,19 @@ systemtap_session::print_error (const semantic_error& e)
print_error (* e.chain);
}
+void
+systemtap_session::print_warning (const string& message_str, const token* tok)
+{
+ // Duplicate elimination
+ if (seen_warnings.find (message_str) == seen_warnings.end())
+ {
+ seen_warnings.insert (message_str);
+ clog << "WARNING: " << message_str;
+ if (tok) { clog << ": "; print_token (clog, tok); }
+ clog << endl;
+ }
+}
+
// ------------------------------------------------------------------------
// semantic processing: symbol resolution
@@ -1558,7 +1603,7 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
{
if (s.functions[i]->tok->location.file == s.user_file->name && // !tapset
! s.suppress_warnings)
- clog << "WARNING: eliding unused function " << *s.functions[i]->tok << endl;
+ s.print_warning ("eliding unused function '" + s.functions[i]->name + "'", s.functions[i]->tok);
else if (s.verbose>2)
clog << "Eliding unused function " << s.functions[i]->name
<< endl;
@@ -1579,10 +1624,10 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
// Do away with local & global variables that are never
// written nor read.
-void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
+void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
{
varuse_collecting_visitor vut;
-
+
for (unsigned i=0; i<s.probes.size(); i++)
{
s.probes[i]->body->visit (& vut);
@@ -1601,7 +1646,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
// Now in vut.read/written, we have a mixture of all locals, globals
- for (unsigned i=0; i<s.probes.size(); i++)
+ for (unsigned i=0; i<s.probes.size(); i++)
for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
{
vardecl* l = s.probes[i]->locals[j];
@@ -1611,7 +1656,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
{
if (l->tok->location.file == s.user_file->name && // !tapset
! s.suppress_warnings)
- clog << "WARNING: eliding unused variable " << *l->tok << endl;
+ s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
clog << "Eliding unused local variable "
<< l->name << " in " << s.probes[i]->name << endl;
@@ -1626,12 +1671,24 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
else
{
if (vut.written.find (l) == vut.written.end())
- if (! s.suppress_warnings)
- clog << "WARNING: read-only local variable " << *l->tok << endl;
-
+ if (iterations == 0 && ! s.suppress_warnings)
+ {
+ stringstream o;
+ vector<vardecl*>::iterator it;
+ for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+ for (it = s.globals.begin(); it != s.globals.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+
+ s.print_warning ("read-only local variable '" + l->name + "' " +
+ (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
+ }
j++;
}
}
+
for (unsigned i=0; i<s.functions.size(); i++)
for (unsigned j=0; j<s.functions[i]->locals.size(); /* see below */)
{
@@ -1641,7 +1698,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
{
if (l->tok->location.file == s.user_file->name && // !tapset
! s.suppress_warnings)
- clog << "WARNING: eliding unused variable " << *l->tok << endl;
+ s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
clog << "Eliding unused local variable "
<< l->name << " in function " << s.functions[i]->name
@@ -1657,8 +1714,25 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
else
{
if (vut.written.find (l) == vut.written.end())
- if (! s.suppress_warnings)
- clog << "WARNING: read-only local variable " << *l->tok << endl;
+ if (iterations == 0 && ! s.suppress_warnings)
+ {
+ stringstream o;
+ vector<vardecl*>::iterator it;
+ for ( it = s.functions[i]->formal_args.begin() ;
+ it != s.functions[i]->formal_args.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+ for (it = s.functions[i]->locals.begin(); it != s.functions[i]->locals.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+ for (it = s.globals.begin(); it != s.globals.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+
+ s.print_warning ("read-only local variable '" + l->name + "' " +
+ (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
+ }
+
j++;
}
}
@@ -1670,7 +1744,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
{
if (l->tok->location.file == s.user_file->name && // !tapset
! s.suppress_warnings)
- clog << "WARNING: eliding unused variable " << *l->tok << endl;
+ s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
clog << "Eliding unused global variable "
<< l->name << endl;
@@ -1683,10 +1757,19 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
}
else
{
- if (vut.written.find (l) == vut.written.end() &&
- ! l->init) // no initializer
- if (! s.suppress_warnings)
- clog << "WARNING: read-only global variable " << *l->tok << endl;
+ if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
+ if (iterations == 0 && ! s.suppress_warnings)
+ {
+ stringstream o;
+ vector<vardecl*>::iterator it;
+ for (it = s.globals.begin(); it != s.globals.end(); it++)
+ if (l->name != (*it)->name)
+ o << " " << (*it)->name;
+
+ s.print_warning ("read-only global variable '" + l->name + "' " +
+ (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
+ }
+
i++;
}
}
@@ -1912,7 +1995,20 @@ dead_stmtexpr_remover::visit_block (block *s)
current_stmt = & s->statements[i];
s->statements[i]->visit (this);
if (*current_stmt != 0)
- new_stmts.push_back (*current_stmt);
+ {
+ // flatten nested blocks into this one
+ block *b = dynamic_cast<block *>(*current_stmt);
+ if (b)
+ {
+ if (session.verbose>2)
+ clog << "Flattening nested block " << *b->tok << endl;
+ new_stmts.insert(new_stmts.end(),
+ b->statements.begin(), b->statements.end());
+ relaxed_p = false;
+ }
+ else
+ new_stmts.push_back (*current_stmt);
+ }
current_stmt = last_stmt;
}
if (new_stmts.size() == 0)
@@ -1948,27 +2044,49 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s)
}
current_stmt = last_stmt;
- if (s->elseblock == 0 && s->thenblock == 0)
+ if (s->thenblock == 0)
{
- // We may be able to elide this statement, if the condition
- // expression is side-effect-free.
- varuse_collecting_visitor vct;
- s->condition->visit(& vct);
- if (vct.side_effect_free ())
+ if (s->elseblock == 0)
+ {
+ // We may be able to elide this statement, if the condition
+ // expression is side-effect-free.
+ varuse_collecting_visitor vct;
+ s->condition->visit(& vct);
+ if (vct.side_effect_free ())
+ {
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free if statement "
+ << *s->tok << endl;
+ *current_stmt = 0; // yeah, baby
+ }
+ else
+ {
+ // We can still turn it into a simple expr_statement though...
+ if (session.verbose>2)
+ clog << "Creating simple evaluation from if statement "
+ << *s->tok << endl;
+ expr_statement *es = new expr_statement;
+ es->value = s->condition;
+ es->tok = es->value->tok;
+ *current_stmt = es;
+ }
+ }
+ else
{
+ // For an else without a then, we can invert the condition logic to
+ // avoid having a null statement in the thenblock
if (session.verbose>2)
- clog << "Eliding side-effect-free if statement " << *s->tok << endl;
- *current_stmt = 0; // yeah, baby
- return;
+ clog << "Inverting the condition of if statement "
+ << *s->tok << endl;
+ unary_expression *ue = new unary_expression;
+ ue->operand = s->condition;
+ ue->tok = ue->operand->tok;
+ ue->op = "!";
+ s->condition = ue;
+ s->thenblock = s->elseblock;
+ s->elseblock = 0;
}
}
-
- if (s->thenblock == 0)
- {
- // Can't elide this whole if/else statement; put a null in there.
- s->thenblock = new null_statement();
- s->thenblock->tok = s->tok;
- }
}
void
@@ -2084,8 +2202,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
if (p->body == 0)
{
if (! s.suppress_warnings)
- clog << "WARNING: side-effect-free probe '" << p->name << "' "
- << *p->tok << endl;
+ s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok);
p->body = new null_statement();
p->body->tok = p->tok;
@@ -2109,8 +2226,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
if (fn->body == 0)
{
if (! s.suppress_warnings)
- clog << "WARNING: side-effect-free function '" << fn->name << "' "
- << *fn->tok << endl;
+ s.print_warning ("side-effect-free function '" + fn->name + "'", fn->tok);
fn->body = new null_statement();
fn->body->tok = fn->tok;
@@ -2124,6 +2240,362 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
}
}
+
+// ------------------------------------------------------------------------
+
+// The goal of this visitor is to reduce top-level expressions in void context
+// into separate statements that evaluate each subcomponent of the expression.
+// The dead-statement-remover can later remove some parts if they have no side
+// effects.
+struct void_statement_reducer: public traversing_visitor
+{
+ systemtap_session& session;
+ bool& relaxed_p;
+ statement** current_stmt; // pointer to current stmt* being iterated
+ expr_statement* current_expr; // pointer to current expr being iterated
+ set<vardecl*> focal_vars; // vars considered subject to side-effects
+
+ void_statement_reducer(systemtap_session& s, bool& r):
+ session(s), relaxed_p(r), current_stmt(0), current_expr(0) {}
+
+ // these just maintain current_stmt while recursing, but don't visit
+ // expressions in the conditional / loop controls.
+ void visit_expr_statement (expr_statement* s);
+ void visit_block (block *s);
+ void visit_if_statement (if_statement* s);
+ void visit_for_loop (for_loop* s);
+ void visit_foreach_loop (foreach_loop* s);
+
+ // these expressions get rewritten into their statement equivalents
+ void visit_logical_or_expr (logical_or_expr* e);
+ void visit_logical_and_expr (logical_and_expr* e);
+ void visit_ternary_expression (ternary_expression* e);
+
+ // all of these can be reduced into simpler statements
+ void visit_binary_expression (binary_expression* e);
+ void visit_unary_expression (unary_expression* e);
+ void visit_comparison (comparison* e);
+ void visit_concatenation (concatenation* e);
+ void visit_functioncall (functioncall* e);
+ void visit_print_format (print_format* e);
+
+ // these are a bit hairy to grok due to the intricacies of indexables and
+ // stats, so I'm chickening out and skipping them...
+ void visit_array_in (array_in* e) {}
+ void visit_arrayindex (arrayindex* e) {}
+ void visit_stat_op (stat_op* e) {}
+ void visit_hist_op (hist_op* e) {}
+
+ // these can't be reduced because they always have an effect
+ void visit_return_statement (return_statement* s) {}
+ void visit_delete_statement (delete_statement* s) {}
+ void visit_pre_crement (pre_crement* e) {}
+ void visit_post_crement (post_crement* e) {}
+ void visit_assignment (assignment* e) {}
+};
+
+
+void
+void_statement_reducer::visit_expr_statement (expr_statement* s)
+{
+ assert(!current_expr); // it shouldn't be possible to have nested expr's
+ current_expr = s;
+ s->value->visit (this);
+ current_expr = NULL;
+}
+
+void
+void_statement_reducer::visit_block (block *s)
+{
+ statement** last_stmt = current_stmt;
+ for (unsigned i=0; i<s->statements.size(); i++ )
+ {
+ current_stmt = & s->statements[i];
+ s->statements[i]->visit (this);
+ }
+ current_stmt = last_stmt;
+}
+
+void
+void_statement_reducer::visit_if_statement (if_statement* s)
+{
+ statement** last_stmt = current_stmt;
+ current_stmt = & s->thenblock;
+ s->thenblock->visit (this);
+
+ if (s->elseblock)
+ {
+ current_stmt = & s->elseblock;
+ s->elseblock->visit (this);
+ }
+ current_stmt = last_stmt;
+}
+
+void
+void_statement_reducer::visit_for_loop (for_loop* s)
+{
+ statement** last_stmt = current_stmt;
+ current_stmt = & s->block;
+ s->block->visit (this);
+ current_stmt = last_stmt;
+}
+
+void
+void_statement_reducer::visit_foreach_loop (foreach_loop* s)
+{
+ statement** last_stmt = current_stmt;
+ current_stmt = & s->block;
+ s->block->visit (this);
+ current_stmt = last_stmt;
+}
+
+void
+void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
+{
+ // In void context, the evaluation of "a || b" is exactly like
+ // "if (!a) b", so let's do that instead.
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Creating if statement from unused logical-or "
+ << *e->tok << endl;
+
+ if_statement *is = new if_statement;
+ is->tok = e->tok;
+ is->elseblock = 0;
+ *current_stmt = is;
+ current_expr = NULL;
+
+ unary_expression *ue = new unary_expression;
+ ue->operand = e->left;
+ ue->tok = e->tok;
+ ue->op = "!";
+ is->condition = ue;
+
+ expr_statement *es = new expr_statement;
+ es->value = e->right;
+ es->tok = es->value->tok;
+ is->thenblock = es;
+
+ is->visit(this);
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
+{
+ // In void context, the evaluation of "a && b" is exactly like
+ // "if (a) b", so let's do that instead.
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Creating if statement from unused logical-and "
+ << *e->tok << endl;
+
+ if_statement *is = new if_statement;
+ is->tok = e->tok;
+ is->elseblock = 0;
+ is->condition = e->left;
+ *current_stmt = is;
+ current_expr = NULL;
+
+ expr_statement *es = new expr_statement;
+ es->value = e->right;
+ es->tok = es->value->tok;
+ is->thenblock = es;
+
+ is->visit(this);
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_ternary_expression (ternary_expression* e)
+{
+ // In void context, the evaluation of "a ? b : c" is exactly like
+ // "if (a) b else c", so let's do that instead.
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Creating if statement from unused ternary expression "
+ << *e->tok << endl;
+
+ if_statement *is = new if_statement;
+ is->tok = e->tok;
+ is->condition = e->cond;
+ *current_stmt = is;
+ current_expr = NULL;
+
+ expr_statement *es = new expr_statement;
+ es->value = e->truevalue;
+ es->tok = es->value->tok;
+ is->thenblock = es;
+
+ es = new expr_statement;
+ es->value = e->falsevalue;
+ es->tok = es->value->tok;
+ is->elseblock = es;
+
+ is->visit(this);
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_binary_expression (binary_expression* e)
+{
+ // When the result of a binary operation isn't needed, it's just as good to
+ // evaluate the operands as sequential statements in a block.
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Eliding unused binary " << *e->tok << endl;
+
+ block *b = new block;
+ b->tok = current_expr->tok;
+ *current_stmt = b;
+ current_expr = NULL;
+
+ expr_statement *es = new expr_statement;
+ es->value = e->left;
+ es->tok = es->value->tok;
+ b->statements.push_back(es);
+
+ es = new expr_statement;
+ es->value = e->right;
+ es->tok = es->value->tok;
+ b->statements.push_back(es);
+
+ b->visit(this);
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_unary_expression (unary_expression* e)
+{
+ // When the result of a unary operation isn't needed, it's just as good to
+ // evaluate the operand directly
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Eliding unused unary " << *e->tok << endl;
+
+ current_expr->value = e->operand;
+ current_expr->tok = current_expr->value->tok;
+ current_expr->value->visit(this);
+
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_comparison (comparison* e)
+{
+ visit_binary_expression(e);
+}
+
+void
+void_statement_reducer::visit_concatenation (concatenation* e)
+{
+ visit_binary_expression(e);
+}
+
+void
+void_statement_reducer::visit_functioncall (functioncall* e)
+{
+ // If a function call is pure and its result ignored, we can elide the call
+ // and just evaluate the arguments in sequence
+
+ if (!e->args.size())
+ return;
+
+ varuse_collecting_visitor vut;
+ vut.traversed.insert (e->referent);
+ vut.current_function = e->referent;
+ e->referent->body->visit (& vut);
+ if (!vut.side_effect_free_wrt (focal_vars))
+ return;
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free function call " << *e->tok << endl;
+
+ block *b = new block;
+ b->tok = e->tok;
+ *current_stmt = b;
+ current_expr = NULL;
+
+ for (unsigned i=0; i<e->args.size(); i++ )
+ {
+ expr_statement *es = new expr_statement;
+ es->value = e->args[i];
+ es->tok = es->value->tok;
+ b->statements.push_back(es);
+ }
+
+ b->visit(this);
+ relaxed_p = false;
+}
+
+void
+void_statement_reducer::visit_print_format (print_format* e)
+{
+ // When an sprint's return value is ignored, we can simply evaluate the
+ // arguments in sequence
+
+ if (e->print_to_stream || !e->args.size())
+ return;
+
+ assert(current_expr && current_expr->value == e);
+
+ if (session.verbose>2)
+ clog << "Eliding unused print " << *e->tok << endl;
+
+ block *b = new block;
+ b->tok = e->tok;
+ *current_stmt = b;
+ current_expr = NULL;
+
+ for (unsigned i=0; i<e->args.size(); i++ )
+ {
+ expr_statement *es = new expr_statement;
+ es->value = e->args[i];
+ es->tok = es->value->tok;
+ b->statements.push_back(es);
+ }
+
+ b->visit(this);
+ relaxed_p = false;
+}
+
+
+void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
+{
+ // Let's simplify statements with unused computed values.
+
+ void_statement_reducer vuv (s, relaxed_p);
+ // This instance may be reused for multiple probe/function body trims.
+
+ vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
+
+ for (unsigned i=0; i<s.probes.size(); i++)
+ {
+ derived_probe* p = s.probes[i];
+ vuv.current_stmt = & p->body;
+ p->body->visit (& vuv);
+ }
+ for (unsigned i=0; i<s.functions.size(); i++)
+ {
+ functiondecl* fn = s.functions[i];
+ vuv.current_stmt = & fn->body;
+ fn->body->visit (& vuv);
+ }
+}
+
+
struct duplicate_function_remover: public functioncall_traversing_visitor
{
systemtap_session& s;
@@ -2176,7 +2648,7 @@ get_functionsig (functiondecl* f)
return str;
}
-void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
+void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
{
// Walk through all the functions, looking for duplicates.
map<string, functiondecl*> functionsig_map;
@@ -2232,6 +2704,7 @@ semantic_pass_optimize1 (systemtap_session& s)
int rc = 0;
bool relaxed_p = false;
+ unsigned iterations = 0;
while (! relaxed_p)
{
if (pending_interrupts) break;
@@ -2239,9 +2712,12 @@ semantic_pass_optimize1 (systemtap_session& s)
relaxed_p = true; // until proven otherwise
semantic_pass_opt1 (s, relaxed_p);
- semantic_pass_opt2 (s, relaxed_p);
+ semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
semantic_pass_opt3 (s, relaxed_p);
semantic_pass_opt4 (s, relaxed_p);
+ semantic_pass_opt5 (s, relaxed_p);
+
+ iterations ++;
}
return rc;
@@ -2263,7 +2739,7 @@ semantic_pass_optimize2 (systemtap_session& s)
if (pending_interrupts) break;
relaxed_p = true; // until proven otherwise
- semantic_pass_opt5 (s, relaxed_p);
+ semantic_pass_opt6 (s, relaxed_p);
}
return rc;