From 9b5af2958a35174a67076c0f27cff0ed5950736d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 11 Feb 2009 14:34:32 -0800 Subject: Add high-level support for @cast()ing This handles all of the parsing, traversal, and optimization. It doesn't actually resolve the cast yet though. * staptree.h (struct cast_op, visitor::visit_cast_op): New. * staptree.cxx (cast_op::print/visit, various visitor::visit_cast_op's): Incorporate cast_op into the basic tree operations. * parse.cxx (parser::parse_symbol): Parse @cast operator with an expression operand, type string, and optional module string. * translate.cxx (c_unparser::visit_cast_op): Error out if a @cast survives to translation. * elaborate.cxx (typeresolution_info::visit_cast_op): Error out if a @cast survives to type resolution. (symbol_fetcher::visit_cast_op): treat @casts as a symbol target (void_statement_reducer::visit_cast_op): unused @casts can be discarded, but the operand should still be evaluated. --- ChangeLog | 15 ++++++++++++++ elaborate.cxx | 31 +++++++++++++++++++++++++++++ elaborate.h | 1 + parse.cxx | 49 ++++++++++++++++++++++++++++++++++++++++++++- staptree.cxx | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ staptree.h | 15 ++++++++++++++ translate.cxx | 8 ++++++++ 7 files changed, 182 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6a609a62..b641d3b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-02-11 Josh Stone + + * staptree.h (struct cast_op, visitor::visit_cast_op): New. + * staptree.cxx (cast_op::print/visit, various visitor::visit_cast_op's): + Incorporate cast_op into the basic tree operations. + * parse.cxx (parser::parse_symbol): Parse @cast operator with an + expression operand, type string, and optional module string. + * translate.cxx (c_unparser::visit_cast_op): Error out if a @cast + survives to translation. + * elaborate.cxx (typeresolution_info::visit_cast_op): Error out if a + @cast survives to type resolution. + (symbol_fetcher::visit_cast_op): treat @casts as a symbol target + (void_statement_reducer::visit_cast_op): unused @casts can be discarded, + but the operand should still be evaluated. + 2009-02-11 Dave Brolley * stap-client: s/jar/zip/. diff --git a/elaborate.cxx b/elaborate.cxx index ba50defb..981fc7c7 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -701,6 +701,11 @@ struct symbol_fetcher e->base->visit_indexable (this); } + void visit_cast_op (cast_op* e) + { + sym = e; + } + void throwone (const token* t) { throw semantic_error ("Expecting symbol or array index expression", t); @@ -2505,6 +2510,7 @@ struct void_statement_reducer: public update_visitor void visit_concatenation (concatenation* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); + void visit_cast_op (cast_op* e); // these are a bit hairy to grok due to the intricacies of indexables and // stats, so I'm chickening out and skipping them... @@ -2772,6 +2778,19 @@ void_statement_reducer::visit_print_format (print_format* e) provide (e); } +void +void_statement_reducer::visit_cast_op (cast_op* e) +{ + // When the result of a cast operation isn't needed, it's just as good to + // evaluate the operand directly + + if (session.verbose>2) + clog << "Eliding unused typecast " << *e->tok << endl; + + relaxed_p = false; + e->operand->visit(this); +} + void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) { @@ -3398,6 +3417,18 @@ typeresolution_info::visit_target_symbol (target_symbol* e) } +void +typeresolution_info::visit_cast_op (cast_op* e) +{ + // Like target_symbol, a cast_op shouldn't survive this far + // unless it was not resolved and its value is really needed. + if (e->saved_conversion_error) + throw (* (e->saved_conversion_error)); + else + throw semantic_error("unresolved cast expression", e->tok); +} + + void typeresolution_info::visit_arrayindex (arrayindex* e) { diff --git a/elaborate.h b/elaborate.h index c8697595..9cc4cbda 100644 --- a/elaborate.h +++ b/elaborate.h @@ -95,6 +95,7 @@ struct typeresolution_info: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; diff --git a/parse.cxx b/parse.cxx index 0419dcb9..aeb11998 100644 --- a/parse.cxx +++ b/parse.cxx @@ -2331,7 +2331,54 @@ parser::parse_symbol () bool pf_stream, pf_format, pf_delim, pf_newline, pf_char; - if (name.size() > 0 && name[0] == '@') + if (name == "@cast") + { + // type-punning time + cast_op *cop = new cast_op; + cop->tok = t; + cop->base_name = name; + expect_op("("); + cop->operand = parse_expression (); + expect_op(","); + expect_unknown(tok_string, cop->type); + if (peek_op (",")) + { + next(); + expect_unknown(tok_string, cop->module); + } + expect_op(")"); + while (true) + { + string c; + if (peek_op ("->")) + { + next(); + expect_ident_or_keyword (c); + cop->components.push_back + (make_pair (target_symbol::comp_struct_member, c)); + } + else if (peek_op ("[")) + { + next(); + expect_unknown (tok_number, c); + expect_op ("]"); + cop->components.push_back + (make_pair (target_symbol::comp_literal_array_index, c)); + } + else + break; + } + // if there aren't any dereferences, then the cast is pointless + if (cop->components.empty()) + { + expression *op = cop->operand; + delete cop; + return op; + } + return cop; + } + + else if (name.size() > 0 && name[0] == '@') { stat_op *sop = new stat_op; if (name == "@avg") diff --git a/staptree.cxx b/staptree.cxx index 9ffbaf09..d6586d86 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -277,6 +277,28 @@ void target_symbol::print (std::ostream& o) const } +void cast_op::print (std::ostream& o) const +{ + o << base_name << '(' << *operand; + o << ", " << lex_cast_qstring (type); + if (module.length() > 0) + o << ", " << lex_cast_qstring (module); + o << ')'; + for (unsigned i = 0; i < components.size(); ++i) + { + switch (components[i].first) + { + case comp_literal_array_index: + o << '[' << components[i].second << ']'; + break; + case comp_struct_member: + o << "->" << components[i].second; + break; + } + } +} + + void vardecl::print (ostream& o) const { o << name; @@ -1219,6 +1241,12 @@ target_symbol::visit (visitor* u) u->visit_target_symbol(this); } +void +cast_op::visit (visitor* u) +{ + u->visit_cast_op(this); +} + void arrayindex::visit (visitor* u) { @@ -1585,6 +1613,12 @@ traversing_visitor::visit_target_symbol (target_symbol*) { } +void +traversing_visitor::visit_cast_op (cast_op* e) +{ + e->operand->visit (this); +} + void traversing_visitor::visit_arrayindex (arrayindex* e) { @@ -1679,6 +1713,17 @@ varuse_collecting_visitor::visit_target_symbol (target_symbol *e) embedded_seen = true; } +void +varuse_collecting_visitor::visit_cast_op (cast_op *e) +{ + // As with target_symbols, unresolved cast assignments need to preserved + // for later error handling. + if (is_active_lvalue (e)) + embedded_seen = true; + + functioncall_traversing_visitor::visit_cast_op (e); +} + void varuse_collecting_visitor::visit_print_format (print_format* e) { @@ -2063,6 +2108,12 @@ throwing_visitor::visit_target_symbol (target_symbol* e) throwone (e->tok); } +void +throwing_visitor::visit_cast_op (cast_op* e) +{ + throwone (e->tok); +} + void throwing_visitor::visit_arrayindex (arrayindex* e) { @@ -2296,6 +2347,13 @@ update_visitor::visit_target_symbol (target_symbol* e) provide (e); } +void +update_visitor::visit_cast_op (cast_op* e) +{ + e->operand = require (e->operand); + provide (e); +} + void update_visitor::visit_arrayindex (arrayindex* e) { @@ -2527,6 +2585,12 @@ deep_copy_visitor::visit_target_symbol (target_symbol* e) update_visitor::visit_target_symbol(n); } +void +deep_copy_visitor::visit_cast_op (cast_op* e) +{ + update_visitor::visit_cast_op(new cast_op(*e)); +} + void deep_copy_visitor::visit_arrayindex (arrayindex* e) { diff --git a/staptree.h b/staptree.h index 0cd0ee0d..7092f980 100644 --- a/staptree.h +++ b/staptree.h @@ -238,6 +238,15 @@ struct target_symbol: public symbol }; +struct cast_op: public target_symbol +{ + expression *operand; + std::string type, module; + void print (std::ostream& o) const; + void visit (visitor* u); +}; + + struct arrayindex: public expression { std::vector indexes; @@ -680,6 +689,7 @@ struct visitor virtual void visit_print_format (print_format* e) = 0; virtual void visit_stat_op (stat_op* e) = 0; virtual void visit_hist_op (hist_op* e) = 0; + virtual void visit_cast_op (cast_op* e) = 0; }; @@ -720,6 +730,7 @@ struct traversing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; @@ -759,6 +770,7 @@ struct varuse_collecting_visitor: public functioncall_traversing_visitor void visit_pre_crement (pre_crement *e); void visit_post_crement (post_crement *e); void visit_foreach_loop (foreach_loop *s); + void visit_cast_op (cast_op* e); bool side_effect_free (); bool side_effect_free_wrt (const std::set& vars); @@ -808,6 +820,7 @@ struct throwing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A visitor similar to a traversing_visitor, but with the ability to rewrite @@ -868,6 +881,7 @@ struct update_visitor: public visitor virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); + virtual void visit_cast_op (cast_op* e); private: std::stack targets; @@ -922,6 +936,7 @@ struct deep_copy_visitor: public update_visitor virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); + virtual void visit_cast_op (cast_op* e); }; #endif // STAPTREE_H diff --git a/translate.cxx b/translate.cxx index 0d430ea3..da647722 100644 --- a/translate.cxx +++ b/translate.cxx @@ -150,6 +150,7 @@ struct c_unparser: public unparser, public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A shadow visitor, meant to generate temporary variable declarations @@ -3487,6 +3488,13 @@ c_unparser::visit_target_symbol (target_symbol* e) } +void +c_unparser::visit_cast_op (cast_op* e) +{ + throw semantic_error("cannot translate general cast expression", e->tok); +} + + void c_tmpcounter::load_map_indices(arrayindex *e) { -- cgit