Hi, On Fri, Nov 04, 2011 at 08:01:41AM -0700, Delesley Hutchins wrote: > Thanks for the suggestion. Unfortunately, knowing the original > declaration doesn't help me; I also need to know the original > arguments that were passed at the call site, before those arguments > were removed by ipa-sra.
I see, that is tough. Once you re-base the analysis on 4.7, you might be able to use the new debugging stuff for this purpose: http://gcc.gnu.org/ml/gcc-patches/2011-06/msg00649.html Apart from that, I think that the information about the original actual arguments is indeed lost in the transformation. Martin > > > (Of course, ipa-sra removes scalar parameters only when they are not > > used in the first place and so there should be nothing to analyze.) > > The problem is that the static analysis may be using the parameters, > even if those parameters are not used in the body of the function. > For example: > > void dummyLock (Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) { } > void dummyUnlock(Mutex* mu) UNLOCK_FUNCTION(mu) { } > > Mutex* mutex; > int a GUARDED_BY(mutex); > > void foo() { > // add mutex to set of held locks > dummyLock(mutex); // gets rewritten by ipa-sra to dummyLock(). Oops! > // okay to modify a, because we've "locked" mutex > a = 0; > // remove mutex from set of held locks > dummyUnlock(mutex); // gets rewritten by ipa-sra to dummyUnlock(). Oops! > } > > The annotations here tell the static analyzer to treat dummyLock and > dummyUnlock as valid lock functions, even though they don't > technically do anything. Such a pattern is not quite as deranged as > it may at first appear -- it is used, for example, when creating a > template class that may choose to either acquire a lock, or not, > depending on its template parameter. Ipa-sra kills the arguments, so > I no longer know which mutex was locked. > > -DeLesley > > > > Martin > > > > > >> > >> Bootstrapped and passed gcc regression testsuite on > >> x86_64-unknown-linux-gnu. Okay for google/gcc-4_6? > >> > >> -DeLesley > >> > >> Changelog.google-4_6: > >> 2011-11-02 DeLesley Hutchins <deles...@google.com> > >> * tree-threadsafe-analyze.c: > >> Ignores invalid attributes, issues a warning, recovers gracefully. > >> * common.opt: > >> Adds new thread safety warning. > >> > >> testsuite/Changelog.google-4_6: > >> 2011-11-02 DeLesley Hutchins <deles...@google.com> > >> * g++.dg/thread-ann/thread_annot_lock-82.C: > >> Expanded regression test > >> > >> -- > >> DeLesley Hutchins | Software Engineer | deles...@google.com | 505-206-0315 > > > >> Index: testsuite/g++.dg/thread-ann/thread_annot_lock-82.C > >> =================================================================== > >> --- testsuite/g++.dg/thread-ann/thread_annot_lock-82.C (revision > >> 180716) > >> +++ testsuite/g++.dg/thread-ann/thread_annot_lock-82.C (working > >> copy) > >> @@ -1,7 +1,7 @@ > >> -// Test template methods in the presence of cloned constructors. > >> -// Regression test for bugfix. > >> +// Regression tests: fix ICE issues when IPA-SRA deletes formal > >> +// function parameters. > >> // { dg-do compile } > >> -// { dg-options "-Wthread-safety -O3" } > >> +// { dg-options "-Wthread-safety -Wthread-warn-optimization -O3" } > >> > >> #include "thread_annot_common.h" > >> > >> @@ -10,6 +10,7 @@ void do_something(void* a); > >> > >> class Foo { > >> Mutex mu_; > >> + int a GUARDED_BY(mu_); > >> > >> // with optimization turned on, ipa-sra should eliminate the hidden > >> // "this" argument, thus invalidating EXCLUSIVE_LOCKS_REQUIRED. > >> @@ -18,6 +19,7 @@ class Foo { > >> } > >> > >> void foo(Foo* f); > >> + void bar(); > >> }; > >> > >> void Foo::foo(Foo* f) { > >> @@ -28,3 +30,17 @@ void Foo::foo(Foo* f) { > >> mu_.Unlock(); > >> } > >> > >> + > >> +class SCOPED_LOCKABLE DummyMutexLock { > >> +public: > >> + // IPA-SRA should kill the parameters to these functions > >> + explicit DummyMutexLock(Mutex* mutex) EXCLUSIVE_LOCK_FUNCTION(mutex) {} > >> + ~DummyMutexLock() UNLOCK_FUNCTION() {} > >> +}; > >> + > >> + > >> +void Foo::bar() { > >> + // Matches two warnings: > >> + DummyMutexLock dlock(&mu_); // { dg-warning "attribute has been > >> removed by optimization." } > >> + a = 1; // warning here should be suppressed, due to errors handling > >> dlock > >> +} > >> Index: common.opt > >> =================================================================== > >> --- common.opt (revision 180716) > >> +++ common.opt (working copy) > >> @@ -680,6 +680,10 @@ Wthread-attr-bind-param > >> Common Var(warn_thread_attr_bind_param) Init(1) Warning > >> Make the thread safety analysis try to bind the function parameters used > >> in the attributes > >> > >> +Wthread-warn-optimization > >> +Common Var(warn_thread_optimization) Init(0) Warning > >> +Warn when optimizations invalidate the thread safety analysis. > >> + > >> Wtype-limits > >> Common Var(warn_type_limits) Init(-1) Warning > >> Warn if a comparison is always true or always false due to the limited > >> range of the data type > >> Index: tree-threadsafe-analyze.c > >> =================================================================== > >> --- tree-threadsafe-analyze.c (revision 180716) > >> +++ tree-threadsafe-analyze.c (working copy) > >> @@ -1594,7 +1594,10 @@ get_actual_argument_from_position (gimple call, tr > >> > >> lock_pos = TREE_INT_CST_LOW (pos_arg); > >> > >> - gcc_assert (lock_pos >= 1 && lock_pos <= num_args); > >> + /* The ipa-sra optimization can occasionally delete arguments, thus > >> + invalidating the index. */ > >> + if (lock_pos < 1 || lock_pos > num_args) > >> + return NULL_TREE; > >> > >> /* The lock position specified in the attributes is 1-based, so we need > >> to > >> subtract 1 from it when accessing the call arguments. */ > >> @@ -1734,7 +1737,27 @@ handle_lock_primitive_attrs (gimple call, tree fde > >> a formal parameter, we need to grab the corresponding actual argument > >> of the call. */ > >> else if (TREE_CODE (arg) == INTEGER_CST) > >> - arg = get_actual_argument_from_position (call, arg); > >> + { > >> + arg = get_actual_argument_from_position (call, arg); > >> + /* If ipa-sra has rewritten the call, then recover as gracefully as > >> + possible. */ > >> + if (!arg) > >> + { > >> + /* Add the universal lock to the lockset to suppress subsequent > >> + errors. */ > >> + if (is_exclusive_lock) > >> + pointer_set_insert(live_excl_locks, error_mark_node); > >> + else > >> + pointer_set_insert(live_shared_locks, error_mark_node); > >> + > >> + if (warn_thread_optimization) > >> + warning_at (*locus, OPT_Wthread_safety, > >> + G_("Lock attribute has been removed by " > >> + "optimization.")); > >> + > >> + return; > >> + } > >> + } > >> else if (TREE_CODE (get_leftmost_base_var (arg)) == PARM_DECL) > >> { > >> tree new_base > >> @@ -1890,7 +1913,18 @@ handle_unlock_primitive_attr (gimple call, tree fd > >> a formal parameter, we need to grab the corresponding actual > >> argument > >> of the call. */ > >> if (TREE_CODE (arg) == INTEGER_CST) > >> - lockable = get_actual_argument_from_position (call, arg); > >> + { > >> + lockable = get_actual_argument_from_position (call, arg); > >> + /* If ipa-sra has rewritten the call, then fail as gracefully as > >> + possible -- just leave the lock in the lockset. */ > >> + if (!lockable) { > >> + if (warn_thread_optimization) > >> + warning_at (*locus, OPT_Wthread_safety, > >> + G_("Unlock attribute has been removed by " > >> + "optimization.")); > >> + return; > >> + } > >> + } > >> else if (TREE_CODE (get_leftmost_base_var (arg)) == PARM_DECL) > >> { > >> tree fdecl = gimple_call_fndecl (call); > >> @@ -1908,7 +1942,15 @@ handle_unlock_primitive_attr (gimple call, tree fd > >> } > >> else > >> { > >> - gcc_assert (base_obj); > >> + /* If ipa-sra has killed arguments, then base_obj may be NULL. > >> + Attempt to recover gracefully by leaving the lock in the > >> lockset. */ > >> + if (!base_obj) { > >> + if (warn_thread_optimization) > >> + warning_at (*locus, OPT_Wthread_safety, > >> + G_("Unlock attribute has been removed by " > >> + "optimization.")); > >> + return; > >> + } > >> > >> /* Check if the primitive is an unlock routine (e.g. the destructor > >> or > >> a release function) of a scoped_lock. If so, get the lock that is > >> @@ -2099,6 +2141,9 @@ handle_function_lock_requirement (gimple call, tre > >> else if (TREE_CODE (lock) == INTEGER_CST) > >> { > >> lock = get_actual_argument_from_position (call, lock); > >> + /* Ignore attribute if ipa-sra has killed the argument. */ > >> + if (!lock) > >> + return; > >> /* If the lock is a function argument, we don't want to > >> prepend the base object to the lock name. Set the > >> TMP_BASE_OBJ to NULL. */ > > > > > > > > -- > DeLesley Hutchins | Software Engineer | deles...@google.com | 505-206-0315