Patchwork [trans-mem] PR/45940 again

login
register
mail settings
Submitter Aldy Hernandez
Date Dec. 13, 2010, 2:26 p.m.
Message ID <4D062D09.5020803@redhat.com>
Download mbox | patch
Permalink /patch/75358/
State New
Headers show

Comments

Aldy Hernandez - Dec. 13, 2010, 2:26 p.m.
The testcase reported found some more corner cases, which I iterated 
with rth about.

The proper fix with the current infrastructure is to disable inlining 
for tm_pure functions when the caller is a tm_safe.  This is because 
tm_pure is the only escape hatch we have for "do not annotate this".  
E.g. you want to  add a call to printf for debugging, or there's some 
data you know that shouldn't be part of the transaction.

A temporary fix is to disable inlining for tm_pure functions altogether.

Can I get this in while I get the rest of the benchmarks building?

p.s. I also added some syntactic sugar for is_tm_safe_or_pure() which 
makes the code easier to read.
PR/45940
        * tree.h: Remove prototypes for is_tm_callable, is_tm_irrevocable.
	(is_tm_safe_or_pure): New.
        * trans-mem.c (is_tm_irrevocable): Make static.
        (is_tm_callable): Same.
        (diagnose_tm_1): Use is_tm_safe_or_pure.
        (ipa_tm_note_irrevocable): Same.
        (ipa_tm_mayenterirr_function): Same.
        (ipa_tm_execute): Same.
	(diagnose_tm_blocks): Change is_tm_safe to is_tm_safe_or_pure.
	* integrate.c (function_attribute_inlinable_p): Do not inline TM
	pure functions.
Aldy Hernandez - Dec. 13, 2010, 2:44 p.m.
On 12/13/10 15:26, Aldy Hernandez wrote:
> The testcase reported found some more corner cases, which I iterated 
> with rth about.
>
> The proper fix with the current infrastructure is to disable inlining 
> for tm_pure functions when the caller is a tm_safe.  This is because 
> tm_pure is the only escape hatch we have for "do not annotate this".  
> E.g. you want to  add a call to printf for debugging, or there's some 
> data you know that shouldn't be part of the transaction.
>
> A temporary fix is to disable inlining for tm_pure functions altogether.
>
> Can I get this in while I get the rest of the benchmarks building?
>
> p.s. I also added some syntactic sugar for is_tm_safe_or_pure() which 
> makes the code easier to read.
Self approval...  rth just approved this off-list.  Committed.

Patch

Index: tree.h
===================================================================
--- tree.h	(revision 166496)
+++ tree.h	(working copy)
@@ -5390,12 +5390,16 @@  extern tree build_personality_function (
 extern tree build_tm_abort_call (location_t, bool);
 extern bool is_tm_safe (tree);
 extern bool is_tm_pure (tree);
-extern bool is_tm_callable (tree);
-extern bool is_tm_irrevocable (tree);
 extern bool is_tm_may_cancel_outer (tree);
 extern void record_tm_replacement (tree, tree);
 extern void tm_malloc_replacement (tree);
 
+static inline bool
+is_tm_safe_or_pure (tree x)
+{
+  return is_tm_safe (x) || is_tm_pure (x);
+}
+
 /* In tree-inline.c.  */
 
 void init_inline_once (void);
Index: testsuite/g++.dg/tm/nested-2.C
===================================================================
--- testsuite/g++.dg/tm/nested-2.C	(revision 166496)
+++ testsuite/g++.dg/tm/nested-2.C	(working copy)
@@ -12,7 +12,7 @@  class HashTree
 {
 public:
    __attribute__((transaction_safe))
-   void *operator new(long unsigned int);
+   void *operator new(__SIZE_TYPE__);
    __attribute__((transaction_safe))
    int add_element();
 private:
Index: testsuite/g++.dg/tm/nested-3.C
===================================================================
--- testsuite/g++.dg/tm/nested-3.C	(revision 166496)
+++ testsuite/g++.dg/tm/nested-3.C	(working copy)
@@ -14,7 +14,7 @@  class HashTree
 {
 public:
    __attribute__((transaction_safe))
-   void *operator new(long unsigned int);
+   void *operator new(__SIZE_TYPE__);
    __attribute__((transaction_safe))
    int add_element();
 private:
Index: testsuite/g++.dg/tm/pr45940-2.C
===================================================================
--- testsuite/g++.dg/tm/pr45940-2.C	(revision 0)
+++ testsuite/g++.dg/tm/pr45940-2.C	(revision 0)
@@ -0,0 +1,30 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O1" }
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add(int dv )
+{
+    int r;
+    __asm__ ("" : "=r"(r));
+    return r;
+}
+
+class sp_counted_base
+{
+public:   
+    __attribute__((transaction_safe))
+    void release()
+    {   
+        if( atomic_exchange_and_add(-1 ) == 1 )
+        {
+        }
+    }
+};
+
+sp_counted_base *base;
+
+void here(){
+  __transaction[[atomic]] {
+    base->release();
+  }
+}
Index: testsuite/g++.dg/tm/pr45940.C
===================================================================
--- testsuite/g++.dg/tm/pr45940.C	(revision 0)
+++ testsuite/g++.dg/tm/pr45940.C	(revision 0)
@@ -0,0 +1,30 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O0" }
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add(int dv )
+{
+    int r;
+    __asm__ ("" : "=r"(r));
+    return r;
+}
+
+class sp_counted_base
+{
+public:   
+    __attribute__((transaction_safe))
+    void release()
+    {   
+        if( atomic_exchange_and_add(-1 ) == 1 )
+        {
+        }
+    }
+};
+
+sp_counted_base *base;
+
+void here(){
+  __transaction[[atomic]] {
+    base->release();
+  }
+}
Index: testsuite/g++.dg/tm/pr45940-3.C
===================================================================
--- testsuite/g++.dg/tm/pr45940-3.C	(revision 0)
+++ testsuite/g++.dg/tm/pr45940-3.C	(revision 0)
@@ -0,0 +1,69 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O0" }
+
+__attribute__((transaction_safe))
+void* operator new (__SIZE_TYPE__);
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add( int * pw, int dv )
+{
+    int r;
+    __asm__ ("" : "=r"(r));
+    return r;
+}
+
+class sp_counted_base
+{
+protected:
+    int use_count_;        // #shared
+public:   
+    __attribute__((transaction_safe))
+    virtual void dispose() = 0; // nothrow
+
+    __attribute__((transaction_safe))
+    void release() // nothrow
+    {   
+        if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
+        {
+            dispose();
+        }
+    }
+};
+
+class sp_counted_base_x86 : public sp_counted_base
+{
+public:
+  void dispose()
+  {
+    release();
+  }
+};
+
+class shared_count
+{
+private:
+    sp_counted_base * pi_;
+public:
+    int j;
+    __attribute__((transaction_safe))
+    shared_count(): pi_(new sp_counted_base_x86()), j(0)
+    {
+    }
+    __attribute__((transaction_safe))
+    ~shared_count() // nothrow
+    {  
+        if( pi_ != 0 ) pi_->release();
+    }
+};
+
+volatile int i = 1;
+shared_count * c;
+int main()
+{
+  if ( i == 0) {
+    __transaction [[atomic]] {
+     shared_count sc;
+    }
+  }
+  return 0;
+}
Index: testsuite/g++.dg/tm/pr45940-4.C
===================================================================
--- testsuite/g++.dg/tm/pr45940-4.C	(revision 0)
+++ testsuite/g++.dg/tm/pr45940-4.C	(revision 0)
@@ -0,0 +1,69 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O1" }
+
+__attribute__((transaction_safe))
+void* operator new (__SIZE_TYPE__);
+
+__attribute__((transaction_pure))
+inline int atomic_exchange_and_add( int * pw, int dv )
+{
+    int r;
+    __asm__ ("" : "=r"(r));
+    return r;
+}
+
+class sp_counted_base
+{
+protected:
+    int use_count_;        // #shared
+public:   
+    __attribute__((transaction_safe))
+    virtual void dispose() = 0; // nothrow
+
+    __attribute__((transaction_safe))
+    void release() // nothrow
+    {   
+        if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
+        {
+            dispose();
+        }
+    }
+};
+
+class sp_counted_base_x86 : public sp_counted_base
+{
+public:
+  void dispose()
+  {
+    release();
+  }
+};
+
+class shared_count
+{
+private:
+    sp_counted_base * pi_;
+public:
+    int j;
+    __attribute__((transaction_safe))
+    shared_count(): pi_(new sp_counted_base_x86()), j(0)
+    {
+    }
+    __attribute__((transaction_safe))
+    ~shared_count() // nothrow
+    {  
+        if( pi_ != 0 ) pi_->release();
+    }
+};
+
+volatile int i = 1;
+shared_count * c;
+int main()
+{
+  if ( i == 0) {
+    __transaction [[atomic]] {
+     shared_count sc;
+    }
+  }
+  return 0;
+}
Index: trans-mem.c
===================================================================
--- trans-mem.c	(revision 167111)
+++ trans-mem.c	(working copy)
@@ -184,7 +184,7 @@  is_tm_pure (tree x)
 
 /* Return true if X has been marked TM_IRREVOCABLE.  */
 
-bool
+static bool
 is_tm_irrevocable (tree x)
 {
   tree attrs = get_attrs_for (x);
@@ -247,7 +247,7 @@  is_tm_pure_call (gimple call)
 
 /* Return true if X has been marked TM_CALLABLE.  */
 
-bool
+static bool
 is_tm_callable (tree x)
 {
   tree attrs = get_attrs_for (x);
@@ -587,7 +587,7 @@  diagnose_tm_1 (gimple_stmt_iterator *gsi
 		replacement = NULL_TREE;
 	      }
 
-	    if (is_tm_safe (fn) || is_tm_pure (fn))
+	    if (is_tm_safe_or_pure (fn))
 	      is_safe = true;
 	    else if (is_tm_callable (fn) || is_tm_irrevocable (fn))
 	      {
@@ -736,7 +736,7 @@  diagnose_tm_blocks (void)
 
   /* If we saw something other than a call that makes this function
      unsafe, remember it so that the IPA pass only needs to scan calls.  */
-  if (d.saw_unsafe && !is_tm_safe (current_function_decl))
+  if (d.saw_unsafe && !is_tm_safe_or_pure (current_function_decl))
     cgraph_local_info (current_function_decl)->tm_may_enter_irr = 1;
 
   return 0;
@@ -3495,8 +3495,7 @@  ipa_tm_note_irrevocable (struct cgraph_n
 	continue;
       /* Even if we think we can go irrevocable, believe the user
 	 above all.  */
-      if (is_tm_safe (e->caller->decl)
-	  || is_tm_pure (e->caller->decl))
+      if (is_tm_safe_or_pure (e->caller->decl))
 	continue;
       if (gimple_call_in_transaction_p (e->call_stmt))
 	d->want_irr_scan_normal = true;
@@ -3792,9 +3791,9 @@  ipa_tm_mayenterirr_function (struct cgra
   tree decl = node->decl;
 
   /* Filter out all functions that are marked.  */
-  if (is_tm_safe (decl))
+  if (is_tm_safe_or_pure (decl))
     return false;
-  if (is_tm_pure (decl) || (flags_from_decl_or_type (decl) & ECF_CONST) != 0)
+  if ((flags_from_decl_or_type (decl) & ECF_CONST) != 0)
     return false;
   if (is_tm_irrevocable (decl))
     return true;
@@ -4443,8 +4442,7 @@  ipa_tm_execute (void)
       if (is_tm_irrevocable (node->decl))
 	ipa_tm_note_irrevocable (node, &worklist);
       else if (a <= AVAIL_NOT_AVAILABLE
-	       && !is_tm_safe (node->decl)
-	       && !is_tm_pure (node->decl))
+	       && !is_tm_safe_or_pure (node->decl))
 	ipa_tm_note_irrevocable (node, &worklist);
       else if (a >= AVAIL_OVERWRITABLE)
 	{
@@ -4512,8 +4510,7 @@  ipa_tm_execute (void)
       node->local.tm_may_enter_irr = true;
 
       for (e = node->callers; e ; e = e->next_caller)
-	if (!is_tm_safe (e->caller->decl)
-	    && !is_tm_pure (e->caller->decl)
+	if (!is_tm_safe_or_pure (e->caller->decl)
 	    && !e->caller->local.tm_may_enter_irr)
 	  maybe_push_queue (e->caller, &worklist, &d->in_worklist);
     }
Index: integrate.c
===================================================================
--- integrate.c	(revision 166496)
+++ integrate.c	(working copy)
@@ -72,6 +72,15 @@  static void set_block_abstract_flags (tr
 bool
 function_attribute_inlinable_p (const_tree fndecl)
 {
+  /* TM pure functions should not get inlined if the outer function is
+     a TM safe function.
+
+     FIXME: In the meantime, prevent pure functions from being
+     inlined.  */
+  if (flag_tm
+      && is_tm_pure (fndecl))
+    return false;
+
   if (targetm.attribute_table)
     {
       const_tree a;