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]

[trans-mem] finish tm pass reorg


With this patch we finally get back to something that (at least for a few test cases) compiles all the way to assembly. Still to do in order to be semi-functional are IPA and the library interface.


r~
        * gimple.def (GIMPLE_TM_ATOMIC): Move before GIMPLE_RETURN.
        * gimple.h (gimple_statement_tm_atomic): Inherit from
        gimple_statement_with_memory_ops_base.
        * tree-passes.h, passes.c (pass_tm_done): Remove.
        * trans-mem.c (PROB_VERY_UNLIKELY, PROB_ALWAYS): New.
        (execute_tm_done): Merge into ...
        (execute_tm_edges): ... here.  Collect region before splitting edges.
        (pass_tm_done): Remove.
        (split_and_add_tm_edge): Merge into ...
        (expand_block_edges): ... here.
        (checkpoint_live_in_variables): Remove.
        (expand_tm_atomic): Update edge probabilities, create eh label.
        * tree-cfg.c (gimple_redirect_edge_and_branch): Handle TM_ATOMIC.
        * tree-eh.c (lower_try_finally): Zero this_state.

--- gimple.def	(revision 141414)
+++ gimple.def	(local)
@@ -140,6 +140,13 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", stru
 DEFGSCODE(GIMPLE_CALL, "gimple_call",
 	  struct gimple_statement_with_memory_ops)
 
+/* GIMPLE_TM_ATOMIC <BODY, LABEL> represents __tm_atomic blocks.
+   BODY is the sequence of statements inside the transaction.
+   LABEL is a label for the statement immediately following the
+   transaction.  This is before RETURN so that it has MEM_OPS,
+   so that it can clobber global memory.  */
+DEFGSCODE(GIMPLE_TM_ATOMIC, "gimple_tm_atomic", NULL)
+
 /* GIMPLE_RETURN <RETVAL> represents return statements.
 
    RETVAL is the value to return or NULL.  If a value is returned it
@@ -355,9 +362,3 @@ DEFGSCODE(GIMPLE_PREDICT, "gimple_predic
     
     This tuple should not exist outside of the gimplifier proper.  */
 DEFGSCODE(GIMPLE_WITH_CLEANUP_EXPR, "gimple_with_cleanup_expr", NULL)
-
-/* GIMPLE_TM_ATOMIC <BODY, LABEL> represents __tm_atomic blocks.
-   BODY is the sequence of statements inside the transaction.
-   LABEL is a label for the statement immediately following the
-   transaction.  */
-DEFGSCODE(GIMPLE_TM_ATOMIC, "gimple_tm_atomic", NULL)
--- gimple.h	(revision 141414)
+++ gimple.h	(local)
@@ -746,13 +746,13 @@ struct gimple_statement_omp_atomic_store
 
 struct gimple_statement_tm_atomic GTY(())
 {
-  /* [ WORD 1-4 ]  */
-  struct gimple_statement_base gsbase;
+  /* [ WORD 1-10 ]  */
+  struct gimple_statement_with_memory_ops_base gsbase;
 
-  /* [ WORD 5 ] */
+  /* [ WORD 11 ] */
   gimple_seq body;
 
-  /* [ WORD 6 ] */
+  /* [ WORD 12 ] */
   tree label;
 };
 
--- passes.c	(revision 141414)
+++ passes.c	(local)
@@ -710,7 +710,6 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tm_mark);
       NEXT_PASS (pass_tm_memopt);
       NEXT_PASS (pass_tm_edges);
-      NEXT_PASS (pass_tm_done);
     }
   NEXT_PASS (pass_del_ssa);
   NEXT_PASS (pass_nrv);
--- trans-mem.c	(revision 141414)
+++ trans-mem.c	(local)
@@ -31,6 +31,10 @@
 #include "flags.h"
 
 
+#define PROB_VERY_UNLIKELY	(REG_BR_PROB_BASE / 2000 - 1)
+#define PROB_ALWAYS		(REG_BR_PROB_BASE)
+
+
 /* The representation of a transaction changes several times during the
    lowering process.  In the beginning, in the front-end we have the
    GENERIC tree TM_ATOMIC.  For example,
@@ -510,17 +514,6 @@ gate_tm_init (void)
   return true;
 }
 
-/* Free the transactional memory data structures.  */
-
-static unsigned int
-execute_tm_done (void)
-{
-  bitmap_obstack_release (&tm_obstack);
-  free_dominance_info (CDI_DOMINATORS);
-
-  return 0;
-}
-
 struct gimple_opt_pass pass_tm_init =
 {
  {
@@ -539,49 +532,30 @@ struct gimple_opt_pass pass_tm_init =
   0,					/* todo_flags_finish */
  }
 };
-
-struct gimple_opt_pass pass_tm_done =
-{
- {
-  GIMPLE_PASS,
-  "tminit",				/* name */
-  NULL,					/* gate */
-  execute_tm_done,			/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  0,					/* tv_id */
-  PROP_ssa | PROP_cfg,			/* properties_required */
-  0,			                /* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  0,					/* todo_flags_finish */
- }
-};
 
 /* Add FLAGS to the GIMPLE_TM_ATOMIC subcode for the transaction region
    represented by STATE.  */
 
 static inline void
-tm_atomic_subcode_ior (struct tm_region *state, unsigned flags)
+tm_atomic_subcode_ior (struct tm_region *region, unsigned flags)
 {
-  if (state->tm_atomic_stmt)
-    gimple_tm_atomic_set_subcode (state->tm_atomic_stmt,
-      gimple_tm_atomic_subcode (state->tm_atomic_stmt) | flags);
+  if (region->tm_atomic_stmt)
+    gimple_tm_atomic_set_subcode (region->tm_atomic_stmt,
+      gimple_tm_atomic_subcode (region->tm_atomic_stmt) | flags);
 }
 
 
 /* Construct a call to TM_IRREVOKABLE and insert it before GSI.  */
 
 static void
-expand_irrevokable (struct tm_region *state, gimple_stmt_iterator *gsi)
+expand_irrevokable (struct tm_region *region, gimple_stmt_iterator *gsi)
 {
   gimple g;
 
-  tm_atomic_subcode_ior (state, GTMA_HAVE_CALL_IRREVOKABLE);
+  tm_atomic_subcode_ior (region, GTMA_HAVE_CALL_IRREVOKABLE);
 
   g = gimple_build_call (built_in_decls[BUILT_IN_TM_IRREVOKABLE], 0);
-  add_stmt_to_eh_region (g, state->region_nr);
+  add_stmt_to_eh_region (g, region->region_nr);
 
   gsi_insert_before (gsi, g, GSI_SAME_STMT);
 }
@@ -733,7 +707,7 @@ build_tm_store (tree lhs, tree rhs, gimp
 /* Expand an assignment statement into transactional builtins.  */
 
 static void
-expand_assign_tm (struct tm_region *state, gimple_stmt_iterator *gsi)
+expand_assign_tm (struct tm_region *region, gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
   tree lhs = gimple_assign_lhs (stmt);
@@ -744,7 +718,7 @@ expand_assign_tm (struct tm_region *stat
 
   if (load_p && store_p)
     {
-      tm_atomic_subcode_ior (state, GTMA_HAVE_LOAD | GTMA_HAVE_STORE);
+      tm_atomic_subcode_ior (region, GTMA_HAVE_LOAD | GTMA_HAVE_STORE);
 
       gcall = gimple_build_call (built_in_decls [BUILT_IN_TM_MEMCPY], 3,
 				 build_fold_addr_expr (lhs),
@@ -754,18 +728,18 @@ expand_assign_tm (struct tm_region *stat
     }
   else if (load_p)
     {
-      tm_atomic_subcode_ior (state, GTMA_HAVE_LOAD);
+      tm_atomic_subcode_ior (region, GTMA_HAVE_LOAD);
       gcall = build_tm_load (lhs, rhs, gsi);
     }
   else if (store_p)
     {
-      tm_atomic_subcode_ior (state, GTMA_HAVE_STORE);
+      tm_atomic_subcode_ior (region, GTMA_HAVE_STORE);
       gcall = build_tm_store (lhs, rhs, gsi);
     }
   else
     return;
 
-  add_stmt_to_eh_region  (gcall, state->region_nr);
+  add_stmt_to_eh_region  (gcall, region->region_nr);
   mark_vops_in_stmt (stmt);
   gsi_remove (gsi, true);
 }
@@ -784,7 +758,7 @@ find_tm_clone (tree orig_decl ATTRIBUTE_
    one of the builtins that end a transaction.  */
 
 static bool
-expand_call_tm (struct tm_region *state, gimple_stmt_iterator *gsi)
+expand_call_tm (struct tm_region *region, gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
   tree fn_decl;
@@ -795,7 +769,7 @@ expand_call_tm (struct tm_region *state,
     return false;
 
   if (flag_exceptions && !(flags & ECF_NOTHROW))
-    tm_atomic_subcode_ior (state, GTMA_HAVE_UNCOMMITTED_THROW);
+    tm_atomic_subcode_ior (region, GTMA_HAVE_UNCOMMITTED_THROW);
 
   fn_decl = gimple_call_fndecl (stmt);
   if (!fn_decl)
@@ -803,7 +777,7 @@ expand_call_tm (struct tm_region *state,
       /* ??? The ABI under discussion has us calling into the runtime
 	 to determine if there's a transactional version of this function.
 	 For now, just switch to irrevokable mode.  */
-      expand_irrevokable (state, gsi);
+      expand_irrevokable (region, gsi);
       return false;
     }
 
@@ -825,7 +799,7 @@ expand_call_tm (struct tm_region *state,
 	case BUILT_IN_TM_COMMIT:
 	case BUILT_IN_TM_ABORT:
 	  /* Both of these calls end a transaction.  */
-	  if (lookup_stmt_eh_region (stmt) == state->region_nr)
+	  if (lookup_stmt_eh_region (stmt) == region->region_nr)
 	    return true;
 
 	default:
@@ -842,7 +816,7 @@ expand_call_tm (struct tm_region *state,
       return false;
     }
 
-  expand_irrevokable (state, gsi);
+  expand_irrevokable (region, gsi);
   return false;
 }
 
@@ -850,7 +824,7 @@ expand_call_tm (struct tm_region *state,
 /* Expand all statements in BB as appropriate for being inside
    a transaction.  */
 static void
-expand_block_tm (struct tm_region *state, basic_block bb)
+expand_block_tm (struct tm_region *region, basic_block bb)
 {
   gimple_stmt_iterator gsi;
 
@@ -863,18 +837,18 @@ expand_block_tm (struct tm_region *state
 	  /* Only memory reads/writes need to be instrumented.  */
 	  if (gimple_assign_single_p (stmt))
 	    {
-	      expand_assign_tm (state, &gsi);
+	      expand_assign_tm (region, &gsi);
 	      continue;
 	    }
 	  break;
 
 	case GIMPLE_CALL:
-	  if (expand_call_tm (state, &gsi))
+	  if (expand_call_tm (region, &gsi))
 	    return;
 	  break;
 
 	case GIMPLE_ASM:
-	  expand_irrevokable (state, &gsi);
+	  expand_irrevokable (region, &gsi);
 	  break;
 
 	default:
@@ -954,102 +928,52 @@ struct gimple_opt_pass pass_tm_mark =
    represented by STATE.  */
 
 static inline void
-make_tm_edge (basic_block bb, struct tm_region *state)
-{
-  make_edge (bb, state->entry_block, EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
-}
-
-
-/* Split the block at GSI and create an abnormal back edge.  */
-
-static void ATTRIBUTE_UNUSED
-split_and_add_tm_edge (struct tm_region *state, gimple_stmt_iterator *gsi)
+make_tm_edge (basic_block bb, struct tm_region *region)
 {
-  basic_block bb = gsi->bb;
-  if (!gsi_one_before_end_p (*gsi))
-    {
-      edge e = split_block (bb, gsi_stmt (*gsi));
-      *gsi = gsi_start_bb (e->dest);
-    }
-
-  make_tm_edge (bb, state);
+  make_edge (bb, region->entry_block, EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
 }
 
 
-/* ??? Find real values for these bits.  */
-#define TM_START_RESTORE_LIVE_IN	1
-#define TM_START_ABORT			2
-
-/* All local variables that have been modified since the beginning of the
-   transaction up until the last possible transaction restart need to be
-   reset when we restart the transaction.
-
-   Here we implement this by replacing the new SSA_NAME created by the
-   PHI at the join of the abnormal backedges by the old SSA_NAME that
-   was originally live at entry to the transaction.  This does result in
-   the old SSA_NAME continuing to stay live when new values are defined,
-   and this isn't necessarily the most efficient implementation, but it
-   is just about the easiest.  */
-
-static void ATTRIBUTE_UNUSED
-checkpoint_live_in_variables (edge e)
+static void
+expand_block_edges (struct tm_region *region, basic_block bb)
 {
   gimple_stmt_iterator gsi;
 
-  for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); )
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
     {
-      gimple phi = gsi_stmt (gsi);
-      tree old_ssa, new_ssa;
-      unsigned i, n;
-
-      new_ssa = gimple_phi_result (phi);
-      old_ssa = gimple_phi_arg_def (phi, e->dest_idx);
-
-      /* We need to recompute SSA_NAME_OCCURS_IN_ABNORMAL_PHI on each
-	 of the other arguments to the PHI, discounting the one abnormal
-	 phi node that we're about to delete.  */
-      for (i = 0, n = gimple_phi_num_args (phi); i < n; ++i)
-	{
-	  tree arg = gimple_phi_arg_def (phi, i);
-	  imm_use_iterator imm_iter;
-	  use_operand_p use_p;
-	  bool in_abnormal_phi;
-
-	  if (TREE_CODE (arg) != SSA_NAME
-	      || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg))
-	    continue;
+      gimple stmt = gsi_stmt (gsi);
 
-	  in_abnormal_phi = false;
-	  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, arg)
+      if (gimple_code (stmt) == GIMPLE_CALL
+	  && (gimple_call_flags (stmt) & ECF_TM_OPS) != 0)
+	{
+	  if (!gsi_one_before_end_p (gsi))
 	    {
-	      gimple phi2 = USE_STMT (use_p);
-	      if (gimple_code (phi2) == GIMPLE_PHI && phi2 != phi)
-		{
-		  unsigned ix = PHI_ARG_INDEX_FROM_USE (use_p);
-		  if (gimple_phi_arg_edge (phi2, ix)->flags & EDGE_ABNORMAL)
-		    {
-		      in_abnormal_phi = true;
-		      break;
-		    }
-		}
+	      edge e = split_block (bb, stmt);
+	      make_tm_edge (bb, region);
+	      bb = e->dest;
+	      gsi = gsi_start_bb (bb);
+	      continue;
 	    }
-	  SSA_NAME_OCCURS_IN_ABNORMAL_PHI (arg) = in_abnormal_phi;
+
+	  make_tm_edge (bb, region);
 	}
 
-      replace_uses_by (new_ssa, old_ssa);
-      remove_phi_node (&gsi, true);
+      gsi_next (&gsi);
     }
 }
 
+/* ??? Find real values for these bits.  */
+#define TM_START_RESTORE_LIVE_IN	1
+#define TM_START_ABORT			2
+
 static void
 expand_tm_atomic (struct tm_region *region)
 {
   tree status, tm_start;
-  basic_block atomic_bb, test_bb;
+  basic_block atomic_bb;
   gimple_stmt_iterator gsi;
   tree t1, t2;
   gimple g;
-  edge e;
 
   mark_vops_in_stmt (region->tm_atomic_stmt);
 
@@ -1066,9 +990,14 @@ expand_tm_atomic (struct tm_region *regi
   gsi_insert_before (&gsi, g, GSI_SAME_STMT);
   gsi_remove (&gsi, true);
 
+  /* If we have an ABORT statement, create a test following the start
+     call to perform the abort.  */
   if (gimple_tm_atomic_label (region->tm_atomic_stmt))
     {
-      test_bb = create_empty_bb (atomic_bb);
+      edge e1, e2;
+      basic_block test_bb;
+
+      region->entry_block = test_bb = create_empty_bb (atomic_bb);
       gsi = gsi_last_bb (test_bb);
 
       t1 = make_rename_temp (TREE_TYPE (status), NULL);
@@ -1080,13 +1009,27 @@ expand_tm_atomic (struct tm_region *regi
       g = gimple_build_cond (NE_EXPR, t1, t2, NULL, NULL);
       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
 
-      make_edge (test_bb, region->entry_block, EDGE_FALSE_VALUE);
-
-      e = BRANCH_EDGE (atomic_bb);
-      redirect_edge_pred (e, test_bb);
-      e->flags = EDGE_TRUE_VALUE;
-    }
+      e1 = FALLTHRU_EDGE (atomic_bb);
+      e2 = make_edge (test_bb, e1->dest, EDGE_FALSE_VALUE);
+      redirect_edge_succ (e1, test_bb);
+      e1->probability = PROB_ALWAYS;
+
+      e1 = BRANCH_EDGE (atomic_bb);
+      redirect_edge_pred (e1, test_bb);
+      e1->flags = EDGE_TRUE_VALUE;
+      e1->probability = PROB_VERY_UNLIKELY;
+      e2->probability = PROB_ALWAYS - PROB_VERY_UNLIKELY;
+    }
+
+  /* Record an EH label for the region.  This will be where the 
+     transaction restart backedge goes.  This is sort of fake,
+     since the runtime actually uses longjmp to get back here,
+     but its existance makes it easier to interface with the
+     rest of the EH code in creating the CFG.  */
+  set_eh_region_tree_label (get_eh_region_from_number (region->region_nr),
+			    gimple_block_label (region->entry_block));
 
+  /* The GIMPLE_TM_ATOMIC statement no longer exists.  */
   region->tm_atomic_stmt = NULL;
 }
 
@@ -1096,11 +1039,49 @@ static unsigned int
 execute_tm_edges (void)
 {
   struct tm_region *region;
+  basic_block bb;
+  VEC (basic_block, heap) *queue;
+  bitmap blocks;
+  bitmap_iterator iter;
+  unsigned int i;
+
+  queue = VEC_alloc (basic_block, heap, 10);
+  blocks = BITMAP_ALLOC (&tm_obstack);
 
   for (region = all_tm_regions; region ; region = region->next)
-    {
-      expand_tm_atomic (region);
-    }
+    if (region->exit_blocks)
+      {
+	/* Collect the set of blocks in this region.  Do this before
+	   splitting edges, so that we don't have to play with the
+	   dominator tree in the middle.  */
+	bitmap_clear (blocks);
+	VEC_quick_push (basic_block, queue, region->entry_block);
+	do
+	  {
+	    bb = VEC_pop (basic_block, queue);
+	    bitmap_set_bit (blocks, bb->index);
+	    if (!bitmap_bit_p (region->exit_blocks, bb->index))
+	      for (bb = first_dom_son (CDI_DOMINATORS, bb);
+		   bb;
+		   bb = next_dom_son (CDI_DOMINATORS, bb))
+		VEC_safe_push (basic_block, heap, queue, bb);
+	  }
+	while (!VEC_empty (basic_block, queue));
+
+	expand_tm_atomic (region);
+
+	EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, iter)
+	  expand_block_edges (region, BASIC_BLOCK (i));
+      }
+
+  VEC_free (basic_block, heap, queue);
+  BITMAP_FREE (blocks);
+
+  /* We've got to release the dominance info now, to indicate that it
+     must be rebuilt completely.  Otherwise we'll crash trying to update
+     the SSA web in the TODO section following this pass.  */
+  free_dominance_info (CDI_DOMINATORS);
+  bitmap_obstack_release (&tm_obstack);
 
   return 0;
 }
--- tree-cfg.c	(revision 141414)
+++ tree-cfg.c	(local)
@@ -4851,6 +4851,14 @@ gimple_redirect_edge_and_branch (edge e,
       /* The edges from OMP constructs can be simply redirected.  */
       break;
 
+    case GIMPLE_TM_ATOMIC:
+      /* The ABORT edge has a stored label associated with it, otherwise
+	 the edges are simply redirectable.  */
+      /* ??? We don't really need this label after the cfg is created.  */
+      if (e->flags == 0)
+	gimple_tm_atomic_set_label (stmt, gimple_block_label (dest));
+      break;
+
     default:
       /* Otherwise it must be a fallthru edge, and we don't need to
 	 do anything besides redirecting it.  */
--- tree-eh.c	(revision 141414)
+++ tree-eh.c	(local)
@@ -1575,6 +1575,7 @@ lower_try_finally (struct leh_state *sta
   else
     this_tf.region = NULL;
 
+  memset (&this_state, 0, sizeof (this_state));
   this_state.cur_region = this_tf.region;
   this_state.prev_try = state->prev_try;
   this_state.tf = &this_tf;
--- tree-pass.h	(revision 141414)
+++ tree-pass.h	(local)
@@ -393,7 +393,6 @@ extern struct gimple_opt_pass pass_tm_in
 extern struct gimple_opt_pass pass_tm_mark;
 extern struct gimple_opt_pass pass_tm_memopt;
 extern struct gimple_opt_pass pass_tm_edges;
-extern struct gimple_opt_pass pass_tm_done;
 
 /* IPA Passes */
 extern struct ipa_opt_pass pass_ipa_inline;

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