This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [trans-mem] lots of irrevocability fixes


Total revamp of irrevocability and associated machinery.

We now have a tm_may_enter_irr bit in cgraph which we use throughout.
We now use/set a GTMA_DOES_GO_IRREVOKABLE bit for atomic blocks in addition
to GTMA_MAY_ENTER_IRREVOKABLE.  GTMA_DOES_GO_IRREVOKABLE is set when we
are absolutely sure the atomic block will go into serial irrevocable
mode.  GTMA_MAY_ENTER_IRREVOKABLE is set when the block *may* enter
irrevocable mode.

Both of these flags allow us to accurately set PR_DOESGOIRREVOKABLE and
PR_HASNOIRREVOKABLE for the run-time.

I have renamed GTMA_MUST_CALL_IRREVOKABLE into GTMA_DOES_GO_IRREVOKABLE
to better reflect the run-time API.  No sense using a different name for
every stage and confusing the hell out of me.

Tested on x86-64 Linux.

Approved off-list by Richard.  Committing.

	* cgraph.h (cgraph_local_info): Add tm_may_enter_irr.
	* gimple-pretty-print.c (dump_gimple_tm_atomic_subcode): Rename
	GTMA_MUST_CALL_IRREVOKABLE to GTMA_DOES_GO_IRREVOKABLE.
	* trans-mem.c (expand_call_tm): Handle irrevocability.
	(execute_tm_mark): Set GTMA_DOES_GO_IRREVOKABLE and
	GTMA_MAY_ENTER_IRREVOKABLE.
	(expand_tm_atomic): Set PR_DOESGOIRREVOKABLE,
	PR_UNINSTRUMENTEDCODE, and PR_HASNOIRREVOKABLE appropriately.
	(ipa_tm_scan_calls_tm_atomic): Set tm_may_enter_irr for
	replacement functions.
	(ipa_tm_scan_calls_clone): Same.
	(ipa_tm_transform_tm_atomic): If the block goes irrevocable, don't
	transform anything.
	(ipa_tm_transform_clone): Set tm_may_enter_irr for non safe
	functions.
	(ipa_tm_execute): Set tm_may_enter_irr for non-local tm_callable
	functions. Swap loops calling ipa_tm_transform_clone and
	ipa_tm_transform_tm_atomic.
	* gimple.h: Rename GTMA_MUST_CALL_IRREVOKABLE into
	GTMA_DOES_GO_IRREVOKABLE.

Index: cgraph.h
===================================================================
--- cgraph.h	(revision 150023)
+++ cgraph.h	(working copy)
@@ -98,6 +98,9 @@ struct GTY(()) cgraph_local_info {
   /* True if the function is going to be emitted in some other translation
      unit, referenced from vtable.  */
   unsigned vtable_method : 1;
+
+  /* True if the function may enter serial irrevocable mode.  */
+  unsigned tm_may_enter_irr : 1;
 };
 
 /* Information about the function that needs to be computed globally
Index: testsuite/gcc.dg/tm/irrevocable-4.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-4.c	(revision 0)
+++ testsuite/gcc.dg/tm/irrevocable-4.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
+
+extern void bar(void) __attribute__((tm_callable));
+void orig(void);
+void xyz(void) __attribute__((tm_wrap (orig)));
+
+
+foo()
+{
+	__tm_atomic orig();
+}
+
+/* { dg-final { scan-tree-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmmark" } } */
Index: testsuite/gcc.dg/tm/irrevocable-2.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-2.c	(revision 150023)
+++ testsuite/gcc.dg/tm/irrevocable-2.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmedge" } */
 
 /* Test that a direct call to __builtin__ITM_changeTransactionMode()
    sets the irrevocable bit.  */
@@ -16,4 +16,5 @@ foo()
 	}
 }
 
-/* { dg-final { scan-ipa-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmipa" } } */
+/* { dg-final { scan-tree-dump-times "doesGoIrrevocable" 1 "tmedge" } } */
+/* { dg-final { scan-tree-dump-times "hasNoIrrevocable" 0 "tmedge" } } */
Index: testsuite/gcc.dg/tm/irrevocable-3.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-3.c	(revision 0)
+++ testsuite/gcc.dg/tm/irrevocable-3.c	(revision 0)
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
+
+extern void bar(void) __attribute__((tm_callable));
+
+foo()
+{
+	__tm_atomic bar();
+}
+
+/* { dg-final { scan-tree-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmmark" } } */
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c	(revision 150023)
+++ gimple-pretty-print.c	(working copy)
@@ -1134,8 +1134,8 @@ dump_gimple_tm_atomic_subcode (pretty_pr
     pp_string (buffer, "GTMA_HAVE_CALL_TM ");
   if (subcode & GTMA_MAY_ENTER_IRREVOKABLE)
     pp_string (buffer, "GTMA_MAY_ENTER_IRREVOKABLE ");
-  if (subcode & GTMA_MUST_CALL_IRREVOKABLE)
-    pp_string (buffer, "GTMA_MUST_CALL_IRREVOKABLE ");
+  if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+    pp_string (buffer, "GTMA_DOES_GO_IRREVOKABLE ");
   if (subcode & GTMA_HAVE_UNCOMMITTED_THROW)
     pp_string (buffer, "GTMA_HAVE_UNCOMMITTED_THROW ");
   pp_string (buffer, "]");
Index: trans-mem.c
===================================================================
--- trans-mem.c	(revision 150023)
+++ trans-mem.c	(working copy)
@@ -731,7 +731,7 @@ tm_region_init_1 (gimple stmt, void *xda
   struct tm_region *region;
   basic_block bb = gimple_bb (stmt);
 
-  /* ??? Verify that the statement (and the block) havn't been deleted.  */
+  /* ??? Verify that the statement (and the block) haven't been deleted.  */
   gcc_assert (bb != NULL);
   gcc_assert (gimple_code (stmt) == GIMPLE_TM_ATOMIC);
 
@@ -1103,6 +1103,7 @@ expand_call_tm (struct tm_region *region
   gimple stmt = gsi_stmt (*gsi);
   tree lhs = gimple_call_lhs (stmt);
   tree fn_decl;
+  struct cgraph_node *node;
 
   if (is_tm_pure_call (stmt))
     return false;
@@ -1111,7 +1112,22 @@ expand_call_tm (struct tm_region *region
 
   /* For indirect calls, we already generated a call into the runtime.  */
   if (!fn_decl)
-    return false;
+    {
+      tree fn = gimple_call_fn (stmt);
+
+      /* We are guaranteed never to go irrevocable on a safe or pure
+	 call, and the pure call was handled above.  */
+      if (fn && is_tm_safe (TREE_TYPE (fn)))
+	return false;
+      else
+	tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
+      
+      return false;
+    }
+
+  node = cgraph_node (fn_decl);
+  if (node->local.tm_may_enter_irr)
+    tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
 
   if (is_tm_abort (fn_decl))
     {
@@ -1188,13 +1204,13 @@ execute_tm_mark (void)
 
 	/* Collect a new SUBCODE set, now that optimizations are done...  */
 	gimple_tm_atomic_set_subcode (region->tm_atomic_stmt, 0);
-	/* ...but keep the bits that require IPA to collect.  Ideally
-	   we should do IPA again to make sure things like DCE didn't
-	   invalidate irrevocability, but we are certain not to
-	   introduce things that go irrevocable, so it's safe to keep
-	   the irrevocability bit.  */
-	gimple_tm_atomic_set_subcode (region->tm_atomic_stmt,
-				      subcode & GTMA_MAY_ENTER_IRREVOKABLE);
+	/* ...but keep the GTMA_DOES_GO_IRREVOKABLE bit, since we can
+	   almost be sure never to insert anything during optimization that
+	   will cause certain irrevocability to be reversed.  */
+	if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+	  gimple_tm_atomic_set_subcode (region->tm_atomic_stmt,
+					GTMA_DOES_GO_IRREVOKABLE |
+					GTMA_MAY_ENTER_IRREVOKABLE);
 
 	VEC_quick_push (basic_block, queue, region->entry_block);
 	do
@@ -1309,11 +1325,14 @@ expand_tm_atomic (struct tm_region *regi
 
   /* ??? There are plenty of bits here we're not computing.  */
   subcode = gimple_tm_atomic_subcode (region->tm_atomic_stmt);
-  flags = PR_INSTRUMENTEDCODE;
+  if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+    flags = PR_DOESGOIRREVOKABLE | PR_UNINSTRUMENTEDCODE;
+  else
+    flags = PR_INSTRUMENTEDCODE;
+  if ((subcode & GTMA_MAY_ENTER_IRREVOKABLE) == 0)
+    flags |= PR_HASNOIRREVOKABLE;
   if ((subcode & GTMA_HAVE_ABORT) == 0)
     flags |= PR_HASNOABORT;
-  if (subcode & GTMA_MUST_CALL_IRREVOKABLE)
-    flags |= PR_DOESGOIRREVOKABLE;
   t2 = build_int_cst (TREE_TYPE (status), flags);
   g = gimple_build_call (tm_start, 1, t2);
   gimple_call_set_lhs (g, status);
@@ -1531,7 +1550,7 @@ struct gimple_opt_pass pass_tm_memopt =
 
 	(d) Place tm_irrevokable calls at the beginning of the relevant
 	    blocks.  Special case here is the entry block for the entire
-	    tm_atomic region; there we mark it MUST_CALL_IRREVOKABLE for
+	    tm_atomic region; there we mark it GTMA_DOES_GO_IRREVOKABLE for
 	    the library to begin the region in serial mode.  Decrement
 	    the call count for all callees in the irrevokable region.
 
@@ -1621,6 +1640,7 @@ ipa_tm_scan_calls_tm_atomic (struct cgra
 			     cgraph_node_queue *callees_p)
 {
   struct cgraph_edge *e;
+  tree replacement;
 
   for (e = node->callees; e ; e = e->next_callee)
     if (gimple_call_in_tm_atomic_p (e->call_stmt))
@@ -1629,8 +1649,12 @@ ipa_tm_scan_calls_tm_atomic (struct cgra
 
 	if (is_tm_pure_call (e->call_stmt))
 	  continue;
-	if (find_tm_replacement_function (e->callee->decl))
-	  continue;
+	if ((replacement = find_tm_replacement_function (e->callee->decl)))
+	  {
+	    struct cgraph_local_info *local = cgraph_local_info (replacement);
+	    local->tm_may_enter_irr = true;
+	    continue;
+	  }
 	
 	d = get_cg_data (e->callee);
 	d->tm_callers_normal++;
@@ -1648,13 +1672,24 @@ ipa_tm_scan_calls_clone (struct cgraph_n
   struct cgraph_edge *e;
 
   for (e = node->callees; e ; e = e->next_callee)
-    if (!is_tm_pure_call (e->call_stmt))
-      {
-	struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+    {
+      tree replacement = find_tm_replacement_function (e->callee->decl);
 
-	d->tm_callers_clone++;
-	maybe_push_queue (e->callee, callees_p, &d->in_callee_queue);
-      }
+      if (replacement)
+	{
+	  struct cgraph_local_info *local = cgraph_local_info (replacement);
+	  local->tm_may_enter_irr = true;
+	  continue;
+	}
+
+      if (!is_tm_pure_call (e->call_stmt))
+	{
+	  struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+
+	  d->tm_callers_clone++;
+	  maybe_push_queue (e->callee, callees_p, &d->in_callee_queue);
+	}
+    }
 }
 
 /* The function NODE has been detected to be irrevokable.  Push all
@@ -1972,6 +2007,8 @@ ipa_tm_create_version (struct cgraph_nod
   if (!DECL_EXTERNAL (old_decl))
     tree_function_versioning (old_decl, new_decl, NULL, false, NULL);
 
+  /* ?? We should be able to remove DECL_IS_TM_CLONE.  We have enough
+     bits in cgraph to calculate all this.  */
   DECL_IS_TM_CLONE (new_decl) = 1;
 
   /* Determine if the symbol is already a valid C++ mangled name.  Do this
@@ -2211,10 +2248,18 @@ ipa_tm_transform_tm_atomic (struct cgrap
   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
   calculate_dominance_info (CDI_DOMINATORS);
 
-  /* ??? Update the marks for the GIMPLE_TM_ATOMIC node, in particular
-     note the MUST_CALL_IRREVOKABLE and don't transform anything.  */
   for (region = d->all_tm_regions; region; region = region->next)
     {
+      /* If we're sure to go irrevocable, don't transform anything.  */
+      if (d->irrevokable_blocks_normal
+	  && bitmap_bit_p (d->irrevokable_blocks_normal,
+			   region->entry_block->index))
+	{
+	  tm_atomic_subcode_ior (region, GTMA_DOES_GO_IRREVOKABLE);
+	  tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
+	  break;
+	}
+
       need_ssa_rename |=
 	ipa_tm_transform_calls (node, region, region->entry_block,
 				d->irrevokable_blocks_normal);
@@ -2245,6 +2290,9 @@ ipa_tm_transform_clone (struct cgraph_no
   push_cfun (DECL_STRUCT_FUNCTION (current_function_decl));
   calculate_dominance_info (CDI_DOMINATORS);
 
+  if (!is_tm_safe (TREE_TYPE (current_function_decl)))
+    node->local.tm_may_enter_irr = true;
+
   need_ssa_rename =
     ipa_tm_transform_calls (d->clone, NULL, single_succ (ENTRY_BLOCK_PTR),
 			    d->irrevokable_blocks_clone);
@@ -2333,8 +2381,17 @@ ipa_tm_execute (void)
 	  continue;
 	}
 
-      if (a >= AVAIL_OVERWRITABLE && !d->is_irrevokable)
-	ipa_tm_scan_calls_clone (node, &tm_callees);
+      if (a >= AVAIL_OVERWRITABLE)
+	{
+	  if (!d->is_irrevokable)
+	    ipa_tm_scan_calls_clone (node, &tm_callees);
+	}
+      else
+	{
+	  /* Non-local tm_callable may enter irrevocable mode.  */
+	  if (is_tm_callable (node->decl))
+	    node->local.tm_may_enter_irr = true;
+	}
     }
 
   /* Iterate scans until no more work to be done.  Prefer not to use
@@ -2387,14 +2444,6 @@ ipa_tm_execute (void)
     }
 
   /* Redirect calls to the new clones, and insert irrevokable marks.  */
-  for (node = cgraph_nodes; node; node = node->next)
-    if (node->reachable && node->lowered
-	&& cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
-      {
-	d = get_cg_data (node);
-	if (d->all_tm_regions)
-	  ipa_tm_transform_tm_atomic (node);
-      }
   for (i = 0; i < VEC_length (cgraph_node_p, tm_callees); ++i)
     {
       node = VEC_index (cgraph_node_p, tm_callees, i);
@@ -2405,6 +2454,14 @@ ipa_tm_execute (void)
 	    ipa_tm_transform_clone (node);
 	}
     }
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->reachable && node->lowered
+	&& cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
+      {
+	d = get_cg_data (node);
+	if (d->all_tm_regions)
+	  ipa_tm_transform_tm_atomic (node);
+      }
 
   /* Free and clear all data structures.  */
   VEC_free (cgraph_node_p, heap, tm_callees);
Index: gimple.h
===================================================================
--- gimple.h	(revision 150023)
+++ gimple.h	(working copy)
@@ -728,12 +728,14 @@ struct GTY(()) gimple_statement_omp_atom
 /* Atomic statement may enter serial irrevocable mode in its dynamic
    scope.  */
 #define GTMA_MAY_ENTER_IRREVOKABLE	(1u << 4)
-/* An irrevocable block post-dominates the entire transaction, such
+/* Atomic statement is sure to enter irrevocable mode.
+
+   An irrevocable block post-dominates the entire transaction, such
    that all invocations of the transaction will go serial-irrevocable.
    In such case, we don't bother instrumenting the transaction, and
    tell the runtime that it should begin the transaction in
    serial-irrevocable mode.  */
-#define GTMA_MUST_CALL_IRREVOKABLE	(1u << 5)
+#define GTMA_DOES_GO_IRREVOKABLE	(1u << 5)
 #define GTMA_HAVE_UNCOMMITTED_THROW	(1u << 6)
 
 struct GTY(()) gimple_statement_tm_atomic


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]