diff options
author | fche <fche> | 2006-04-25 17:40:53 +0000 |
---|---|---|
committer | fche <fche> | 2006-04-25 17:40:53 +0000 |
commit | 1b07c728305a32a8d1fa1bb5da9d428e34dddf4e (patch) | |
tree | f86471e86673dbd7ce49f755f7d980aec43a5a58 | |
parent | fe7e582fac54df14452fa017529bf642f2047e5f (diff) | |
download | systemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.tar.gz systemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.tar.xz systemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.zip |
2006-04-25 Frank Ch. Eigler <fche@elastic.org>
PR 2427.
* staptree.cxx (varuse_collecting_visitor::visit_embeddedcode):
Support /* pure */ declaration. Stop using __tvar_ naming hack.
(v_c_u::visit_print_format): Mark sprint and sprintf as
side-effect-free.
(deep_copy_visitor::visit_print_format): Propagate raw_components.
* stap.1.in: Document declaration.
* elaborate.cxx (semantic_pass_opt2): Verbose message tweak.
(dead_stmtexpr_remover): Extend for more aggressive optimization.
* tapsets.cxx (dwarf,mark_var_expanding_copy_visotor): Add
/* pure */ declaration to rvalue expansions.
* tapset/*.stp: Added /* pure */ declarations to many functions.
* testsuite/parseok/unparsers.stp: Propagate guru mode flag.
* testsuite/buildok/twentyfour.stp: New test.
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | elaborate.cxx | 56 | ||||
-rw-r--r-- | stap.1.in | 11 | ||||
-rw-r--r-- | staptree.cxx | 28 | ||||
-rw-r--r-- | tapset/aux_syscalls.stp | 36 | ||||
-rw-r--r-- | tapset/context.stp | 34 | ||||
-rw-r--r-- | tapset/conversions.stp | 8 | ||||
-rw-r--r-- | tapset/endian.stp | 14 | ||||
-rw-r--r-- | tapset/errno.stp | 4 | ||||
-rw-r--r-- | tapset/return.stp | 2 | ||||
-rw-r--r-- | tapset/string.stp | 6 | ||||
-rw-r--r-- | tapset/timestamp.stp | 8 | ||||
-rw-r--r-- | tapsets.cxx | 24 | ||||
-rwxr-xr-x | testsuite/buildok/twentyfour.stp | 14 | ||||
-rwxr-xr-x | testsuite/parseok/unparser.stp | 8 |
15 files changed, 178 insertions, 92 deletions
@@ -1,3 +1,20 @@ +2006-04-25 Frank Ch. Eigler <fche@elastic.org> + + PR 2427. + * staptree.cxx (varuse_collecting_visitor::visit_embeddedcode): + Support /* pure */ declaration. Stop using __tvar_ naming hack. + (v_c_u::visit_print_format): Mark sprint and sprintf as + side-effect-free. + (deep_copy_visitor::visit_print_format): Propagate raw_components. + * stap.1.in: Document declaration. + * elaborate.cxx (semantic_pass_opt2): Verbose message tweak. + (dead_stmtexpr_remover): Extend for more aggressive optimization. + * tapsets.cxx (dwarf,mark_var_expanding_copy_visotor): Add + /* pure */ declaration to rvalue expansions. + * tapset/*.stp: Added /* pure */ declarations to many functions. + * testsuite/parseok/unparsers.stp: Propagate guru mode flag. + * testsuite/buildok/twentyfour.stp: New test. + 2006-04-24 Frank Ch. Eigler <fche@elastic.org> PR 2599. diff --git a/elaborate.cxx b/elaborate.cxx index 61e63cb1..976becd6 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -21,6 +21,9 @@ extern "C" { #include <cassert> #include <set> #include <vector> +#include <algorithm> +#include <iterator> + using namespace std; @@ -1247,7 +1250,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) { if (s.verbose>2) clog << "Eliding unused local variable " - << l->name << " in probe #" << i << endl; + << l->name << " in " << s.probes[i]->name << endl; s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j); relaxed_p = false; // don't increment j @@ -1379,6 +1382,7 @@ struct dead_stmtexpr_remover: public traversing_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) {} @@ -1421,7 +1425,23 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) varuse_collecting_visitor vut; s->value->visit (& vut); - if (vut.written.empty() && !vut.embedded_seen) + + // Note that side-effect-freeness is not simply this test: + // + // (vut.written.empty() && !vut.embedded_seen) + // + // That's because the vut.written list may consist of local + // variables of called functions. Visible side-effects occur if + // *our* locals, or any *globals* are written-to. + + + set<vardecl*> intersection; + insert_iterator<set<vardecl*> > int_it (intersection, intersection.begin()); + set_intersection (vut.written.begin(), vut.written.end(), + focal_vars.begin(), focal_vars.end(), + int_it); + + if (intersection.empty() && ! vut.embedded_seen) { if (session.verbose>2) clog << "Eliding side-effect-free expression " @@ -1437,6 +1457,15 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s) relaxed_p = false; } + else if(session.verbose>3) + { + clog << "keeping expression " << *s->tok + << " because it writes: "; + for (std::set<vardecl*>::iterator k = intersection.begin(); + k != intersection.end(); k++) + clog << (*k)->name << " "; + clog << "and/or embedded: " << vut.embedded_seen << endl; + } } @@ -1450,9 +1479,25 @@ void semantic_pass_opt4 (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 (& duv); + { + duv.focal_vars.clear (); + duv.focal_vars.insert (s.globals.begin(), + s.globals.end()); + duv.focal_vars.insert (s.probes[i]->locals.begin(), + s.probes[i]->locals.end()); + s.probes[i]->body->visit (& duv); + } for (unsigned i=0; i<s.functions.size(); i++) - s.functions[i]->body->visit (& duv); + { + duv.focal_vars.clear (); + duv.focal_vars.insert (s.functions[i]->locals.begin(), + s.functions[i]->locals.end()); + duv.focal_vars.insert (s.functions[i]->formal_args.begin(), + s.functions[i]->formal_args.end()); + duv.focal_vars.insert (s.globals.begin(), + s.globals.end()); + s.functions[i]->body->visit (& duv); + } } @@ -1974,9 +2019,6 @@ typeresolution_info::visit_functioncall (functioncall* e) if (e->type == pe_stats) invalid (e->tok, e->type); - // XXX: but what about functions that return no value, - // and are used only as an expression-statement for side effects? - // now resolve the function parameters if (e->args.size() != e->referent->formal_args.size()) unresolved (e->tok); // symbol resolution should prevent this @@ -646,10 +646,13 @@ with "$") are found and have their run-time locations decoded. .PP Next, all probes and functions are analyzed for optimization opportunities, in order to remove variables, expressions, and -functions that have no useful value and no side-effect. Since this -process can hide latent code errors such as type mismatches or invalid -$target variables, it sometimes may be useful to disable the -optimizations with the +functions that have no useful value and no side-effect. Embedded-C +functions are assumed to have side-effects unless they include the +magic string +.BR /*\ pure\ */ . +Since this optimization can hide latent code errors such as type +mismatches or invalid $target variables, it sometimes may be useful +to disable the optimizations with the .BR \-u option. .PP diff --git a/staptree.cxx b/staptree.cxx index 2f62198f..75c2c17d 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -1495,19 +1495,19 @@ functioncall_traversing_visitor::visit_functioncall (functioncall* e) void varuse_collecting_visitor::visit_embeddedcode (embeddedcode *s) { - // In order to elide unused but correct functions generated to - // get $target variables, we encode our knowledge that such - // functions are side-effect-free. We tell them apart from ordinary - // tapset embedded-C functions by the naming prefix. XXX Something - // apart from this heuristic would be nice. XXX Similarly, some - // tapset embedded-C functions are pure and disposable, like - // substr(). + // We want to elide embedded-C functions when possible. For + // example, each $target variable access is expanded to an + // embedded-C function call. Yet, for safety reasons, we should + // presume that embedded-C functions have intentional side-effects. + // + // To tell these two types of functions apart, we apply a + // Kludge(tm): we look for a magic string within the function body. + // $target variables as rvalues will have this; lvalues won't. + // Also, explicit side-effect-free tapset functions will have this. assert (current_function); // only they get embedded code - string name = current_function->name; - if (name.length() > 10 && name.substr(0, 10) == "_tvar_get_") + if (s->code.find ("/* pure */") != string::npos) return; - // NB: setter functions naturally have side-effects embedded_seen = true; } @@ -1520,7 +1520,12 @@ varuse_collecting_visitor::visit_print_format (print_format* e) // are implemented as statement-expressions containing a // print_format. They have side-effects, but not via the // embedded-code detection method above. - embedded_seen = true; + // + // But sprint and sprintf don't have side-effects. + + if (e->print_to_stream) + embedded_seen = true; // a proxy for "has unknown side-effects" + functioncall_traversing_visitor::visit_print_format (e); } @@ -2185,6 +2190,7 @@ deep_copy_visitor::visit_print_format (print_format* e) n->tok = e->tok; n->print_with_format = e->print_with_format; n->print_to_stream = e->print_to_stream; + n->raw_components = e->raw_components; n->components = e->components; for (unsigned i = 0; i < e->args.size(); ++i) { diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp index 37e9ddf9..b1e2c446 100644 --- a/tapset/aux_syscalls.stp +++ b/tapset/aux_syscalls.stp @@ -3,7 +3,7 @@ # copy and decode it and return a string. # function _struct_timeval_u:string(uaddr:long) -%{ +%{ /* pure */ struct timeval tv; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -18,7 +18,7 @@ function _struct_timeval_u:string(uaddr:long) %} function _struct_timeval:string(addr:long) -%{ +%{ /* pure */ struct timeval *tv; char *ptr = (char *)(unsigned long)THIS->addr; @@ -31,7 +31,7 @@ function _struct_timeval:string(addr:long) %} function _struct_timezone_u:string(uaddr:long) -%{ +%{ /* pure */ struct timezone tz; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -46,7 +46,7 @@ function _struct_timezone_u:string(uaddr:long) %} function _struct_timespec_u:string(uaddr:long) -%{ +%{ /* pure */ struct timespec ts; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -62,7 +62,7 @@ function _struct_timespec_u:string(uaddr:long) %} function _struct_timespec:string(addr:long) -%{ +%{ /* pure */ struct timespec *ts; char *ptr = (char *)(unsigned long)THIS->addr; @@ -76,7 +76,7 @@ function _struct_timespec:string(addr:long) %} function _struct_itimerspec_u:string(uaddr:long) -%{ +%{ /* pure */ struct itimerspec its; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -93,7 +93,7 @@ function _struct_itimerspec_u:string(uaddr:long) %} function _struct_itimerval_u:string(uaddr:long) -%{ +%{ /* pure */ struct itimerval itv; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -110,7 +110,7 @@ function _struct_itimerval_u:string(uaddr:long) %} function _struct_itimerval:string(addr:long) -%{ +%{ /* pure */ struct itimerval *itv; char *ptr = (char *)(unsigned long)THIS->addr; @@ -196,7 +196,7 @@ void _stp_sockaddr_str(char *str, const int strlen, char *buf, int len) %} function _struct_sockaddr_u:string(uaddr:long, len:long) -%{ +%{ /* pure */ char *ptr = (char *)(unsigned long)THIS->uaddr; if (ptr == NULL) strlcpy (THIS->__retvalue, "NULL", MAXSTRINGLEN); @@ -211,7 +211,7 @@ function _struct_sockaddr_u:string(uaddr:long, len:long) %} function _signal_name:string(sig:long) -%{ +%{ /* pure */ int sig = THIS->sig; char *res = 0; @@ -308,7 +308,7 @@ function _signal_name:string(sig:long) %} function _struct_rlimit_u:string(uaddr:long) -%{ +%{ /* pure */ struct rlimit rl; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -324,7 +324,7 @@ function _struct_rlimit_u:string(uaddr:long) %} function _fildes_u:string (uaddr:long) -%{ +%{ /* pure */ int fd[2]; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -339,7 +339,7 @@ function _fildes_u:string (uaddr:long) %} function _fd_set_u:string(uaddr:long) -%{ +%{ /* pure */ fd_set fdset; char *ptr = (char *)(unsigned long)THIS->uaddr; @@ -355,7 +355,7 @@ function _fd_set_u:string(uaddr:long) function _semctl_cmd:string(cmd:long) -%{ +%{ /* pure */ int cmd = THIS->cmd; char *res = 0; @@ -407,7 +407,7 @@ function _semctl_cmd:string(cmd:long) %} function __sem_flags:string(semflg:long) -%{ +%{ /* pure */ long semflg = THIS->semflg; char *str = THIS->__retvalue; @@ -420,7 +420,7 @@ function __sem_flags:string(semflg:long) %} function __fork_flags:string(flags:long) -%{ +%{ /* pure */ long flags = THIS->flags; char *str = THIS->__retvalue; if (flags & CLONE_FS) @@ -456,7 +456,7 @@ function __fork_flags:string(flags:long) /* This function copies an argv from userspace. */ function __get_argv:string(a:long) -%{ +%{ /* pure */ char __user *__user *argv = (char __user *__user *)(long)THIS->a; char __user *vstr; int space, rc, len = MAXSTRINGLEN; @@ -518,7 +518,7 @@ function __get_argv:string(a:long) * the string it points to. Should be rarely necessary. */ function __string:string (a:long) -%{ +%{ /* pure */ char *str =(char *)(long)THIS->a; strlcpy(THIS->__retvalue, str, MAXSTRINGLEN); %} diff --git a/tapset/context.stp b/tapset/context.stp index a93b36b3..221c853b 100644 --- a/tapset/context.stp +++ b/tapset/context.stp @@ -18,7 +18,7 @@ function print_backtrace () %{ } %} -function backtrace:string () %{ +function backtrace:string () %{ /* pure */ if (CONTEXT->regs) { /* XXX: this won't be necessary when runtime and translator */ /* agree on what a string is. */ @@ -29,47 +29,47 @@ function backtrace:string () %{ strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); %} -function execname:string () %{ +function execname:string () %{ /* pure */ strlcpy (THIS->__retvalue, current->comm, MAXSTRINGLEN); %} -function pid:long () %{ +function pid:long () %{ /* pure */ THIS->__retvalue = current->tgid; %} -function tid:long () %{ +function tid:long () %{ /* pure */ THIS->__retvalue = current->pid; %} -function ppid:long () %{ +function ppid:long () %{ /* pure */ THIS->__retvalue = current->parent->tgid; %} -function pexecname:string () %{ +function pexecname:string () %{ /* pure */ strlcpy (THIS->__retvalue, current->parent->comm, MAXSTRINGLEN); %} -function gid:long () %{ +function gid:long () %{ /* pure */ THIS->__retvalue = current->gid; %} -function egid:long () %{ +function egid:long () %{ /* pure */ THIS->__retvalue = current->egid; %} -function uid:long () %{ +function uid:long () %{ /* pure */ THIS->__retvalue = current->uid; %} -function euid:long () %{ +function euid:long () %{ /* pure */ THIS->__retvalue = current->euid; %} -function cpuid:long () %{ +function cpuid:long () %{ /* pure */ THIS->__retvalue = current->thread_info->cpu; %} -function cpu:long () %{ +function cpu:long () %{ /* pure */ THIS->__retvalue = current->thread_info->cpu; /* smp_processor_id()? */ %} @@ -84,11 +84,11 @@ function print_stack(stk:string) %{ } %} -function pp:string () %{ +function pp:string () %{ /* pure */ strlcpy (THIS->__retvalue, CONTEXT->probe_point, MAXSTRINGLEN); %} -function probefunc:string () %{ +function probefunc:string () %{ /* pure */ char *start = strstr(CONTEXT->probe_point, "function(\""); if (start) { char *ptr = start+10; @@ -100,7 +100,7 @@ function probefunc:string () %{ } %} -function is_return:long () %{ +function is_return:long () %{ /* pure */ char *ptr = strrchr(CONTEXT->probe_point, '.'); if (ptr) { if (strcmp(ptr+1,"return") == 0) @@ -108,11 +108,11 @@ function is_return:long () %{ } %} -function target:long () %{ +function target:long () %{ /* pure */ THIS->__retvalue = _stp_target; %} -function returnval:long () %{ +function returnval:long () %{ /* pure */ if (CONTEXT->regs) { #if defined (__i386__) THIS->__retvalue = CONTEXT->regs->eax; diff --git a/tapset/conversions.stp b/tapset/conversions.stp index b05d7a8e..7a664a58 100644 --- a/tapset/conversions.stp +++ b/tapset/conversions.stp @@ -6,15 +6,15 @@ // Public License (GPL); either version 2, or (at your option) any // later version. -function hexstring:string (num:long) %{ +function hexstring:string (num:long) %{ /* pure */ snprintf (THIS->__retvalue, MAXSTRINGLEN, "0x%llx", (long long) THIS->num); %} -function string:string (num:long) %{ +function string:string (num:long) %{ /* pure */ snprintf (THIS->__retvalue, MAXSTRINGLEN, "%lld", (long long) THIS->num); %} -function kernel_string:string (addr:long) %{ +function kernel_string:string (addr:long) %{ /* pure */ char *destination = THIS->__retvalue; deref_string (destination, THIS->addr, MAXSTRINGLEN); goto success; @@ -30,7 +30,7 @@ success: ; # NB: accessing user space is hazardous from certain kernel contexts. # Errors should be returned when this is detected. -function user_string:string (addr:long) %{ +function user_string:string (addr:long) %{ /* pure */ long rc = _stp_strncpy_from_user (THIS->__retvalue, (const char __user*) (uintptr_t) THIS->addr, MAXSTRINGLEN); diff --git a/tapset/endian.stp b/tapset/endian.stp index ddcc2546..fc2c8937 100644 --- a/tapset/endian.stp +++ b/tapset/endian.stp @@ -2,30 +2,30 @@ # val: 0 - native (default) # 1 - little endian # 2 - big endian -function set_endian:long (val:long) %{ +function set_endian:long (val:long) %{ /* pure */ _stp_endian = THIS->val; %} -function big_endian2:long (val:long) %{ +function big_endian2:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_be16(THIS->val); %} -function big_endian4:long (val:long) %{ +function big_endian4:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_be32(THIS->val); %} -function big_endian8:long (val:long) %{ +function big_endian8:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_be64(THIS->val); %} -function little_endian2:long (val:long) %{ +function little_endian2:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_le16(THIS->val); %} -function little_endian4:long (val:long) %{ +function little_endian4:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_le32(THIS->val); %} -function little_endian8:long (val:long) %{ +function little_endian8:long (val:long) %{ /* pure */ THIS->__retvalue = cpu_to_le64(THIS->val); %} diff --git a/tapset/errno.stp b/tapset/errno.stp index d3ab90e3..10c4532e 100644 --- a/tapset/errno.stp +++ b/tapset/errno.stp @@ -343,7 +343,7 @@ const char * const errlist[] = { const int Maxerrno = sizeof(errlist)/sizeof(char *); %} -function errno_str:string (err:long) %{ +function errno_str:string (err:long) %{ /* pure */ long e = THIS->err; if (e < 0 && e > -Maxerrno && errlist[-e]) strlcpy (THIS->__retvalue, errlist[-e], MAXSTRINGLEN); @@ -352,7 +352,7 @@ function errno_str:string (err:long) %{ %} /* for syscall tapset. set returnp = 1 for decimal, 2 for hex */ -function returnstr:string (returnp:long) %{ +function returnstr:string (returnp:long) %{ /* pure */ long ret; if (CONTEXT->regs) { diff --git a/tapset/return.stp b/tapset/return.stp index 8f13e08a..98ff8a73 100644 --- a/tapset/return.stp +++ b/tapset/return.stp @@ -1,4 +1,4 @@ -function retval:long() %{ +function retval:long() %{ /* pure */ if (CONTEXT->regs) { #if defined (__i386__) THIS->__retvalue = CONTEXT->regs->eax; diff --git a/tapset/string.stp b/tapset/string.stp index 249ff831..19b8f81f 100644 --- a/tapset/string.stp +++ b/tapset/string.stp @@ -8,7 +8,7 @@ * @param s string * @return Returns the length of the string. */ -function strlen:long(s:string) %{ +function strlen:long(s:string) %{ /* pure */ THIS->__retvalue=strlen(THIS->s); %} @@ -17,7 +17,7 @@ function strlen:long(s:string) %{ * @param str string * @return Returns the length of the string. */ -function substr:string(str:string,start:long,stop:long) %{ +function substr:string(str:string,start:long,stop:long) %{ /* pure */ int len=strlen(THIS->str); if(THIS->start<0 || THIS->stop<0 || THIS->start>len || THIS->stop>len || @@ -39,7 +39,7 @@ function substr:string(str:string,start:long,stop:long) %{ * @param s2 string * @return Returns 1 if s2 is in s1. */ -function isinstr:long(s1:string,s2:string) %{ +function isinstr:long(s1:string,s2:string) %{ /* pure */ if(strstr(THIS->s1,THIS->s2)!=NULL) THIS->__retvalue = 1; else diff --git a/tapset/timestamp.stp b/tapset/timestamp.stp index ee9478cb..67e2e73a 100644 --- a/tapset/timestamp.stp +++ b/tapset/timestamp.stp @@ -13,28 +13,28 @@ // return processor cycle counter (if any) -function get_cycles:long () %{ +function get_cycles:long () %{ /* pure */ cycles_t c = get_cycles(); THIS->__retvalue = (int64_t) c; %} // return in microseconds since epoch -function gettimeofday_us:long () %{ +function gettimeofday_us:long () %{ /* pure */ struct timeval tm; do_gettimeofday (& tm); THIS->__retvalue = (tm.tv_sec * 1000000ULL) + (tm.tv_usec); %} // return in milliseconds since epoch -function gettimeofday_ms:long () %{ +function gettimeofday_ms:long () %{ /* pure */ struct timeval tm; do_gettimeofday (& tm); THIS->__retvalue = (tm.tv_sec * 1000ULL) + (tm.tv_usec / 1000); %} // return in seconds since epoch -function gettimeofday_s:long () %{ +function gettimeofday_s:long () %{ /* pure */ struct timeval tm; do_gettimeofday (& tm); THIS->__retvalue = tm.tv_sec; diff --git a/tapsets.cxx b/tapsets.cxx index 07daf865..50386480 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2598,9 +2598,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) if (lvalue && !q.sess.guru_mode) throw semantic_error("write to target variable not permitted", e->tok); - // NB: This naming convention is used by varuse_collecting_visitor - // to make elision of these functions possible. - string fname = (string(lvalue ? "_tvar_set" : "_tvar_get") + string fname = (string(lvalue ? "_dwarf_tvar_set" : "_dwarf_tvar_get") + "_" + e->base_name.substr(1) + "_" + lex_cast<string>(tick++)); @@ -2615,6 +2613,8 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) e->components, lvalue, fdecl->type); + if (! lvalue) + ec->code += "/* pure */"; } catch (const semantic_error& er) { @@ -3454,18 +3454,18 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) fdecl->tok = e->tok; embeddedcode *ec = new embeddedcode; ec->tok = e->tok; - bool lvalue = is_active_lvalue(e); - if (lvalue) throw semantic_error("write to marker parameter not permitted", e->tok); + if (is_active_lvalue (e)) + throw semantic_error("write to marker parameter not permitted", e->tok); - // NB: This naming convention is used by varuse_collecting_visitor - // to make elision of these functions possible. - string fname = (string(lvalue ? "_tvar_set" : "_tvar_get") - + "_" + e->base_name.substr(1) - + "_" + lex_cast<string>(tick++)); + string fname = string("_mark_tvar_get") + + "_" + e->base_name.substr(1) + + "_" + lex_cast<string>(tick++); - ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") + probe_name - + string(".__mark_arg") + lex_cast<string>(argnum) + string (";"); + ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") + + probe_name + string(".__mark_arg") + + lex_cast<string>(argnum) + string (";"); + ec->code += "/* pure */"; fdecl->name = fname; fdecl->body = ec; fdecl->type = (argtype == 'N' ? pe_long : diff --git a/testsuite/buildok/twentyfour.stp b/testsuite/buildok/twentyfour.stp new file mode 100755 index 00000000..a889fe56 --- /dev/null +++ b/testsuite/buildok/twentyfour.stp @@ -0,0 +1,14 @@ +#! stap -gp4 + +# If the optimizer is working, this function will get elided, +# and thus will compile successfully. + +function pure() %{ /* pure */ +#error "should have been elided" +%} + + +probe begin +{ + pure () +} diff --git a/testsuite/parseok/unparser.stp b/testsuite/parseok/unparser.stp index 710c4636..b5deb146 100755 --- a/testsuite/parseok/unparser.stp +++ b/testsuite/parseok/unparser.stp @@ -14,8 +14,12 @@ do do if head -1 $file | grep -q stap then - echo $file - ./stap -p1 $file | ./stap -p1 - > /dev/null + if head -1 $file | fgrep -q -- g # guru mode + then guru=-g + else guru= + fi + echo $file $guru + ./stap $guru -p1 $file | ./stap $guru -p1 - > /dev/null fi done done |