diff options
author | Josh Stone <jistone@redhat.com> | 2009-02-10 20:10:33 -0800 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-02-10 20:10:33 -0800 |
commit | 8040a4b42cd0fc66142d3ef2f905ea0267726b76 (patch) | |
tree | ca0d5d32c5f87dcb2803e5172d3d8ad471eaaf4d /elaborate.cxx | |
parent | 098043c5f96ee58756342cfbe7b49c2572f79a15 (diff) | |
parent | 9f9873dfc0978ef3ce7b7b5aa7ae1e2b5b4909b9 (diff) | |
download | systemtap-steved-8040a4b42cd0fc66142d3ef2f905ea0267726b76.tar.gz systemtap-steved-8040a4b42cd0fc66142d3ef2f905ea0267726b76.tar.xz systemtap-steved-8040a4b42cd0fc66142d3ef2f905ea0267726b76.zip |
Merge branch 'update_visitor'
This brings a new update_visitor that makes it easier to traverse the
parse tree and modify parts of it as necessary. I wrote this as part of
my in-progress work to allow @cast() expansion, but I was able to apply
it to the dwarf/etc. target variable expanders and to the optimization
stages. I think the resulting code is more predictable and easier to
follow...
Conflicts:
ChangeLog (bumped my commit dates to push dates...)
Diffstat (limited to 'elaborate.cxx')
-rw-r--r-- | elaborate.cxx | 376 |
1 files changed, 120 insertions, 256 deletions
diff --git a/elaborate.cxx b/elaborate.cxx index 5678e8a7..ba50defb 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -2091,59 +2091,30 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati // ------------------------------------------------------------------------ -struct dead_assignment_remover: public traversing_visitor +struct dead_assignment_remover: public update_visitor { systemtap_session& session; bool& relaxed_p; const varuse_collecting_visitor& vut; - expression** current_expr; dead_assignment_remover(systemtap_session& s, bool& r, const varuse_collecting_visitor& v): - session(s), relaxed_p(r), vut(v), current_expr(0) {} - - void visit_expr_statement (expr_statement* s); - // XXX: other places where an assignment may be nested should be - // handled too (e.g., loop/if conditionals, array indexes, function - // parameters). Until then, they result in visit_assignment() being - // called with null current_expr. + session(s), relaxed_p(r), vut(v) {} void visit_assignment (assignment* e); - void visit_binary_expression (binary_expression* e); - void visit_arrayindex (arrayindex* e); - void visit_functioncall (functioncall* e); - void visit_if_statement (if_statement* e); - void visit_for_loop (for_loop* e); }; void -dead_assignment_remover::visit_expr_statement (expr_statement* s) -{ - expression** last_expr = current_expr; - current_expr = & s->value; - s->value->visit (this); - s->tok = s->value->tok; // in case it was replaced - current_expr = last_expr; -} - - -void dead_assignment_remover::visit_assignment (assignment* e) { + e->left = require (e->left); + e->right = require (e->right); + symbol* left = get_symbol_within_expression (e->left); vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target - if (current_expr && // see XXX above: this case represents a missed - // optimization opportunity - *current_expr == e && // we're not nested any deeper than expected - leftvar) // not unresolved $target; intended sideeffect cannot be elided + if (leftvar) // not unresolved $target, so intended sideeffect may be elided { - expression** last_expr = current_expr; - e->left->visit (this); - current_expr = &e->right; - e->right->visit (this); - current_expr = last_expr; - if (vut.read.find(leftvar) == vut.read.end()) // var never read? { // NB: Not so fast! The left side could be an array whose @@ -2163,9 +2134,9 @@ dead_assignment_remover::visit_assignment (assignment* e) break; } - varuse_collecting_visitor vut; - e->left->visit (& vut); - if (vut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars + varuse_collecting_visitor lvut; + e->left->visit (& lvut); + if (lvut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars { /* PR 1119: NB: This is not necessary here. A write-only variable will also be elided soon at the next _opt2 iteration. @@ -2178,77 +2149,13 @@ dead_assignment_remover::visit_assignment (assignment* e) clog << "Eliding assignment to " << leftvar->name << " at " << *e->tok << endl; - *current_expr = e->right; // goodbye assignment* + provide (e->right); // goodbye assignment* relaxed_p = false; + return; } } } -} - -void -dead_assignment_remover::visit_binary_expression (binary_expression* e) -{ - expression** last_expr = current_expr; - current_expr = &e->left; - e->left->visit (this); - current_expr = &e->right; - e->right->visit (this); - current_expr = last_expr; -} - -void -dead_assignment_remover::visit_arrayindex (arrayindex *e) -{ - symbol *array = NULL; - hist_op *hist = NULL; - classify_indexable(e->base, array, hist); - - if (array) - { - expression** last_expr = current_expr; - for (unsigned i=0; i < e->indexes.size(); i++) - { - current_expr = & e->indexes[i]; - e->indexes[i]->visit (this); - } - current_expr = last_expr; - } -} - -void -dead_assignment_remover::visit_functioncall (functioncall* e) -{ - expression** last_expr = current_expr; - for (unsigned i=0; i<e->args.size(); i++) - { - current_expr = & e->args[i]; - e->args[i]->visit (this); - } - current_expr = last_expr; -} - -void -dead_assignment_remover::visit_if_statement (if_statement* s) -{ - expression** last_expr = current_expr; - current_expr = & s->condition; - s->condition->visit (this); - s->thenblock->visit (this); - if (s->elseblock) - s->elseblock->visit (this); - current_expr = last_expr; -} - -void -dead_assignment_remover::visit_for_loop (for_loop* s) -{ - expression** last_expr = current_expr; - if (s->init) s->init->visit (this); - current_expr = & s->cond; - s->cond->visit (this); - if (s->incr) s->incr->visit (this); - s->block->visit (this); - current_expr = last_expr; + provide (e); } // Let's remove assignments to variables that are never read. We @@ -2268,9 +2175,10 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p) // This instance may be reused for multiple probe/function body trims. for (unsigned i=0; i<s.probes.size(); i++) - s.probes[i]->body->visit (& dar); - for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) - it->second->body->visit (& dar); + s.probes[i]->body = dar.require (s.probes[i]->body); + for (map<string,functiondecl*>::iterator it = s.functions.begin(); + it != s.functions.end(); it++) + it->second->body = dar.require (it->second->body); // The rewrite operation is performed within the visitor. // XXX: we could also zap write-only globals here @@ -2279,15 +2187,14 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p) // ------------------------------------------------------------------------ -struct dead_stmtexpr_remover: public traversing_visitor +struct dead_stmtexpr_remover: public update_visitor { systemtap_session& session; bool& relaxed_p; - statement** current_stmt; // pointer to current stmt* being iterated set<vardecl*> focal_vars; // vars considered subject to side-effects dead_stmtexpr_remover(systemtap_session& s, bool& r): - session(s), relaxed_p(r), current_stmt(0) {} + session(s), relaxed_p(r) {} void visit_block (block *s); void visit_null_statement (null_statement *s); @@ -2306,7 +2213,8 @@ dead_stmtexpr_remover::visit_null_statement (null_statement *s) // easy! if (session.verbose>2) clog << "Eliding side-effect-free null statement " << *s->tok << endl; - *current_stmt = 0; + s = 0; + provide (s); } @@ -2316,13 +2224,11 @@ dead_stmtexpr_remover::visit_block (block *s) vector<statement*> new_stmts; for (unsigned i=0; i<s->statements.size(); i++ ) { - statement** last_stmt = current_stmt; - current_stmt = & s->statements[i]; - s->statements[i]->visit (this); - if (*current_stmt != 0) + statement* new_stmt = require (s->statements[i], true); + if (new_stmt != 0) { // flatten nested blocks into this one - block *b = dynamic_cast<block *>(*current_stmt); + block *b = dynamic_cast<block *>(new_stmt); if (b) { if (session.verbose>2) @@ -2332,42 +2238,32 @@ dead_stmtexpr_remover::visit_block (block *s) relaxed_p = false; } else - new_stmts.push_back (*current_stmt); + new_stmts.push_back (new_stmt); } - current_stmt = last_stmt; } if (new_stmts.size() == 0) { if (session.verbose>2) clog << "Eliding side-effect-free empty block " << *s->tok << endl; - *current_stmt = 0; + s = 0; } else if (new_stmts.size() == 1) { if (session.verbose>2) clog << "Eliding side-effect-free singleton block " << *s->tok << endl; - *current_stmt = new_stmts[0]; + provide (new_stmts[0]); + return; } else - { - s->statements = new_stmts; - } + s->statements = new_stmts; + provide (s); } void dead_stmtexpr_remover::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); - // null *current_stmt is OK here. - } - current_stmt = last_stmt; + s->thenblock = require (s->thenblock, true); + s->elseblock = require (s->elseblock, true); if (s->thenblock == 0) { @@ -2382,7 +2278,7 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) if (session.verbose>2) clog << "Eliding side-effect-free if statement " << *s->tok << endl; - *current_stmt = 0; // yeah, baby + s = 0; // yeah, baby } else { @@ -2393,7 +2289,8 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) expr_statement *es = new expr_statement; es->value = s->condition; es->tok = es->value->tok; - *current_stmt = es; + provide (es); + return; } } else @@ -2412,31 +2309,27 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) s->elseblock = 0; } } + provide (s); } void dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s) { - statement** last_stmt = current_stmt; - current_stmt = & s->block; - s->block->visit (this); - current_stmt = last_stmt; + s->block = require(s->block, true); if (s->block == 0) { if (session.verbose>2) clog << "Eliding side-effect-free foreach statement " << *s->tok << endl; - *current_stmt = 0; // yeah, baby + s = 0; // yeah, baby } + provide (s); } void dead_stmtexpr_remover::visit_for_loop (for_loop *s) { - statement** last_stmt = current_stmt; - current_stmt = & s->block; - s->block->visit (this); - current_stmt = last_stmt; + s->block = require(s->block, true); if (s->block == 0) { @@ -2450,14 +2343,16 @@ dead_stmtexpr_remover::visit_for_loop (for_loop *s) { if (session.verbose>2) clog << "Eliding side-effect-free for statement " << *s->tok << endl; - *current_stmt = 0; // yeah, baby - return; + s = 0; // yeah, baby + } + else + { + // Can't elide this whole statement; put a null in there. + s->block = new null_statement(); + s->block->tok = s->tok; } - - // Can't elide this whole statement; put a null in there. - s->block = new null_statement(); - s->block->tok = s->tok; } + provide (s); } @@ -2467,8 +2362,7 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) { // Run a varuse query against the operand expression. If it has no // side-effects, replace the entire statement expression by a null - // statement. This replacement is done by overwriting the - // current_stmt pointer. + // statement with the provide() call. // // Unlike many other visitors, we do *not* traverse this outermost // one into the expression subtrees. There is no need - no @@ -2481,8 +2375,7 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) varuse_collecting_visitor vut; s->value->visit (& vut); - if (vut.side_effect_free_wrt (focal_vars) && - *current_stmt == s) // we're not nested any deeper than expected + if (vut.side_effect_free_wrt (focal_vars)) { /* PR 1119: NB: this message is not a good idea here. It can name some arbitrary RHS expression of an assignment. @@ -2497,10 +2390,10 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) // NB: this 0 pointer is invalid to leave around for any length of // time, but the parent parse tree objects above handle it. - * current_stmt = 0; - + s = 0; relaxed_p = false; } + provide (s); } @@ -2525,8 +2418,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) duv.focal_vars.insert (p->locals.begin(), p->locals.end()); - duv.current_stmt = & p->body; - p->body->visit (& duv); + p->body = duv.require(p->body, true); if (p->body == 0) { if (! s.suppress_warnings) @@ -2551,8 +2443,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) duv.focal_vars.insert (s.globals.begin(), s.globals.end()); - duv.current_stmt = & fn->body; - fn->body->visit (& duv); + fn->body = duv.require(fn->body, true); if (fn->body == 0) { if (! s.suppress_warnings) @@ -2577,21 +2468,27 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) // 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 +// +// All expressions must be overridden here so we never visit their subexpressions +// accidentally. Thus, the only visited expressions should be value of an +// expr_statement. +// +// For an expression to replace its expr_statement with something else, it will +// let the new statement provide(), and then provide(0) for itself. The +// expr_statement will take this as a sign that it's been replaced. +struct void_statement_reducer: public update_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) {} + session(s), relaxed_p(r) {} - // 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); + + // expressions in conditional / loop controls are definitely a side effect, + // but still recurse into the child statements void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); void visit_foreach_loop (foreach_loop* s); @@ -2611,72 +2508,54 @@ struct void_statement_reducer: public traversing_visitor // 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) {} + void visit_array_in (array_in* e) { provide (e); } + void visit_arrayindex (arrayindex* e) { provide (e); } + void visit_stat_op (stat_op* e) { provide (e); } + void visit_hist_op (hist_op* e) { provide (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 visit_return_statement (return_statement* s) { provide (s); } + void visit_delete_statement (delete_statement* s) { provide (s); } + void visit_pre_crement (pre_crement* e) { provide (e); } + void visit_post_crement (post_crement* e) { provide (e); } + void visit_assignment (assignment* e) { provide (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; -} + s->value = require (s->value, true); -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; + // if the expression provides 0, that's our signal that a new + // statement has been provided, so we shouldn't provide this one. + if (s->value != 0) + provide(s); } 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; + // s->condition is never void + s->thenblock = require (s->thenblock); + s->elseblock = require (s->elseblock); + provide (s); } 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; + // s->init/cond/incr are never void + s->block = require (s->block); + provide (s); } 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; + // s->indexes/base/limit are never void + s->block = require (s->block); + provide (s); } void @@ -2685,8 +2564,6 @@ 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; @@ -2694,8 +2571,6 @@ void_statement_reducer::visit_logical_or_expr (logical_or_expr* e) 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; @@ -2710,6 +2585,8 @@ void_statement_reducer::visit_logical_or_expr (logical_or_expr* e) is->visit(this); relaxed_p = false; + e = 0; + provide (e); } void @@ -2718,8 +2595,6 @@ 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; @@ -2728,8 +2603,6 @@ void_statement_reducer::visit_logical_and_expr (logical_and_expr* e) 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; @@ -2738,6 +2611,8 @@ void_statement_reducer::visit_logical_and_expr (logical_and_expr* e) is->visit(this); relaxed_p = false; + e = 0; + provide (e); } void @@ -2746,8 +2621,6 @@ 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; @@ -2755,8 +2628,6 @@ void_statement_reducer::visit_ternary_expression (ternary_expression* e) 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; @@ -2770,6 +2641,8 @@ void_statement_reducer::visit_ternary_expression (ternary_expression* e) is->visit(this); relaxed_p = false; + e = 0; + provide (e); } void @@ -2778,15 +2651,11 @@ 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; + b->tok = e->tok; expr_statement *es = new expr_statement; es->value = e->left; @@ -2800,6 +2669,8 @@ void_statement_reducer::visit_binary_expression (binary_expression* e) b->visit(this); relaxed_p = false; + e = 0; + provide (e); } void @@ -2808,16 +2679,11 @@ 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; + e->operand->visit(this); } void @@ -2839,24 +2705,26 @@ void_statement_reducer::visit_functioncall (functioncall* e) // and just evaluate the arguments in sequence if (!e->args.size()) - return; + { + provide (e); + 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); + { + provide (e); + return; + } 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++ ) { @@ -2868,6 +2736,8 @@ void_statement_reducer::visit_functioncall (functioncall* e) b->visit(this); relaxed_p = false; + e = 0; + provide (e); } void @@ -2877,17 +2747,16 @@ void_statement_reducer::visit_print_format (print_format* e) // arguments in sequence if (e->print_to_stream || !e->args.size()) - return; - - assert(current_expr && current_expr->value == e); + { + provide (e); + return; + } 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++ ) { @@ -2899,6 +2768,8 @@ void_statement_reducer::visit_print_format (print_format* e) b->visit(this); relaxed_p = false; + e = 0; + provide (e); } @@ -2912,17 +2783,10 @@ void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) 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 (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) - { - functiondecl* fn = it->second; - vuv.current_stmt = & fn->body; - fn->body->visit (& vuv); - } + s.probes[i]->body = vuv.require (s.probes[i]->body); + for (map<string,functiondecl*>::iterator it = s.functions.begin(); + it != s.functions.end(); it++) + it->second->body = vuv.require (it->second->body); } |