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] rtl expansion of gimple transactions


The transaction rewrite I posted last week didn't include expanding rtl. Here's the expansion, and all the changes to the rtl cfg to add the proper transaction restart edges.


r~
        * builtin-attrs.def (ATTR_RETURNS_TWICE): Remove.
        (ATTR_RETURNSTWICE_NOTHROW_LIST): Remove.
        * builtin-types.def: The TM builtin types are not variadic.
        * calls.c (emit_call_1): Set REG_EH_REGION properly for nothrow
        tm functions; add REG_TM as needed.
        (special_function_p): Add ECF_TM_OPS for TM builtins.
        (flags_from_decl_or_type): Add ECF_TM_OPS for TM clones.
        * cfgbuild.c (control_flow_insn_p): Tidy.
        (struct tmee_data, rtl_make_eh_edge_1): New.
        (rtl_make_eh_edge): Use them with foreach_reachable_handler;
        use foreach_reachable_transaction for TM functions.
        * cfgexpand.c (gimple_assign_rhs_to_tree): Assert we don't
        look past TM_LOAD/TM_STORE.
        (build_tm_load, build_tm_store): New.
        (gimple_to_tree): Use them.
        * except.c (get_eh_region_rtl_label): New.
        (frob_transaction_start): New.
        (build_post_landing_pads): Call it.
        (build_post_landing_pads_tm_only): New.
        (finish_eh_generation): Call it.
        (arh_to_landing_pad, arh_to_label, reachable_handlers): Remove.
        (can_throw_internal): True for TM insns inside a transaction.
        (gate_handle_eh): Enable for TM.
        * except.h (reachable_handlers): Remove.
        (get_eh_region_rtl_label): Declare.
        * gimple.c (get_call_expr_in): Look through VIEW_CONVERT_EXPR.
        * gtm-builtins.def (BUILT_IN_TM_START): Don't mark RETURNS_TWICE.
        * reg-notes.def (TM): New.
        * tree-eh.c (maybe_clean_or_replace_eh_stmt): Handle transactions.
        * tree-optimize.c (execute_fixup_cfg): Likewise.
        * tree.h (ECF_TM_OPS): New.

--- builtin-attrs.def	(revision 141210)
+++ builtin-attrs.def	(local)
@@ -94,7 +94,6 @@ DEF_ATTR_IDENT (ATTR_SENTINEL, "sentinel
 DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
 DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
 DEF_ATTR_IDENT (ATTR_TYPEGENERIC, "type generic")
-DEF_ATTR_IDENT (ATTR_RETURNS_TWICE, "returns_twice")
 
 DEF_ATTR_TREE_LIST (ATTR_NOVOPS_LIST, ATTR_NOVOPS, ATTR_NULL, ATTR_NULL)
 
@@ -112,8 +111,6 @@ DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_
 			ATTR_NULL, ATTR_NOTHROW_LIST)
 DEF_ATTR_TREE_LIST (ATTR_SENTINEL_NOTHROW_LIST, ATTR_SENTINEL,	\
 			ATTR_NULL, ATTR_NOTHROW_LIST)
-DEF_ATTR_TREE_LIST (ATTR_RETURNSTWICE_NOTHROW_LIST, ATTR_RETURNS_TWICE,
-			ATTR_NULL, ATTR_NOTHROW_LIST)
 
 /* Functions whose pointer parameter(s) are all nonnull.  */
 DEF_ATTR_TREE_LIST (ATTR_NONNULL_LIST, ATTR_NONNULL, ATTR_NULL, ATTR_NULL)
--- builtin-types.def	(revision 141210)
+++ builtin-types.def	(local)
@@ -475,22 +475,17 @@ DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VO
 		     BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
 
 
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I1_VPTR, BT_I1, BT_VOLATILE_PTR)
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I2_VPTR, BT_I2, BT_VOLATILE_PTR)
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I4_VPTR, BT_I4, BT_VOLATILE_PTR)
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I8_VPTR, BT_I8, BT_VOLATILE_PTR)
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_FLOAT_VPTR, BT_FLOAT, BT_VOLATILE_PTR)
-DEF_FUNCTION_TYPE_VAR_1 (BT_FN_DOUBLE_VPTR, BT_DOUBLE, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_I1_VPTR, BT_I1, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_I2_VPTR, BT_I2, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_I4_VPTR, BT_I4, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_I8_VPTR, BT_I8, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT_VPTR, BT_FLOAT, BT_VOLATILE_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_VPTR, BT_DOUBLE, BT_VOLATILE_PTR)
 
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_I1, BT_VOID, 
-                         BT_VOLATILE_PTR, BT_I1)
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_I2, BT_VOID, 
-                         BT_VOLATILE_PTR, BT_I2)
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_I4, BT_VOID,
-                         BT_VOLATILE_PTR, BT_I4)
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_I8, BT_VOID, 
-                         BT_VOLATILE_PTR, BT_I8)
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_FLOAT, BT_VOID, 
-                         BT_VOLATILE_PTR, BT_FLOAT)
-DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_VPTR_DOUBLE, BT_VOID, 
-                         BT_VOLATILE_PTR, BT_DOUBLE)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I1, BT_VOID, BT_VOLATILE_PTR, BT_I1)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I2, BT_VOID, BT_VOLATILE_PTR, BT_I2)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I4, BT_VOID, BT_VOLATILE_PTR, BT_I4)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I8, BT_VOID, BT_VOLATILE_PTR, BT_I8)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_FLOAT, BT_VOID, BT_VOLATILE_PTR, BT_FLOAT)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_DOUBLE, BT_VOID, 
+                     BT_VOLATILE_PTR, BT_DOUBLE)
--- calls.c	(revision 141210)
+++ calls.c	(local)
@@ -376,19 +376,20 @@ emit_call_1 (rtx funexp, tree fntree, tr
   if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
     RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
 
-  /* If this call can't throw, attach a REG_EH_REGION reg note to that
-     effect.  */
-  if (ecf_flags & ECF_NOTHROW)
-    add_reg_note (call_insn, REG_EH_REGION, const0_rtx);
-  else
-    {
-      int rn = lookup_expr_eh_region (fntree);
-
-      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't
-	 throw, which we already took care of.  */
-      if (rn > 0)
-	add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn));
-    }
+  /* If this call can't throw, attach a REG_EH_REGION reg note
+     to that effect.  When doing transactional memory, we can
+     desire an EH_REGION note even on calls that don't "throw"
+     in the true EH sense.  */
+  {
+    int rn = lookup_expr_eh_region (fntree);
+    if (rn < 0)
+      {
+	if (ecf_flags & ECF_NOTHROW)
+	  rn = 0;
+      }
+    if (rn >= 0)
+      add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn));
+  }
 
   if (ecf_flags & ECF_NORETURN)
     add_reg_note (call_insn, REG_NORETURN, const0_rtx);
@@ -399,6 +400,9 @@ emit_call_1 (rtx funexp, tree fntree, tr
       cfun->calls_setjmp = 1;
     }
 
+  if (ecf_flags & ECF_TM_OPS)
+    add_reg_note (call_insn, REG_TM, const0_rtx);
+
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
   /* Restore this now, so that we do defer pops for this call's args
@@ -471,7 +475,34 @@ emit_call_1 (rtx funexp, tree fntree, tr
 static int
 special_function_p (const_tree fndecl, int flags)
 {
-  if (fndecl && DECL_NAME (fndecl)
+  if (fndecl == NULL)
+    return flags;
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      switch (DECL_FUNCTION_CODE (fndecl))
+	{
+	case BUILT_IN_TM_ABORT:
+	case BUILT_IN_TM_STORE_1:
+	case BUILT_IN_TM_STORE_2:
+	case BUILT_IN_TM_STORE_4:
+	case BUILT_IN_TM_STORE_8:
+	case BUILT_IN_TM_STORE_FLOAT:
+	case BUILT_IN_TM_STORE_DOUBLE:
+	case BUILT_IN_TM_LOAD_1:
+	case BUILT_IN_TM_LOAD_2:
+	case BUILT_IN_TM_LOAD_4:
+	case BUILT_IN_TM_LOAD_8:
+	case BUILT_IN_TM_LOAD_FLOAT:
+	case BUILT_IN_TM_LOAD_DOUBLE:
+	  flags |= ECF_TM_OPS;
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  if (DECL_NAME (fndecl)
       && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
       /* Exclude functions not at the file scope, or not `extern',
 	 since they are not the magic functions we would otherwise
@@ -614,6 +645,9 @@ flags_from_decl_or_type (const_tree exp)
       if (TREE_NOTHROW (exp))
 	flags |= ECF_NOTHROW;
 
+      if (DECL_IS_TM_CLONE (exp))
+	flags |= ECF_TM_OPS;
+
       flags = special_function_p (exp, flags);
     }
   else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
--- cfgbuild.c	(revision 141210)
+++ cfgbuild.c	(local)
@@ -110,13 +110,17 @@ control_flow_insn_p (const_rtx insn)
 	   || find_reg_note (insn, REG_NORETURN, 0))
 	  && GET_CODE (PATTERN (insn)) != COND_EXEC)
 	return true;
+
       /* Call insn may return to the nonlocal goto handler.  */
-      return ((nonlocal_goto_handler_labels
-	       && (0 == (note = find_reg_note (insn, REG_EH_REGION,
-					       NULL_RTX))
-		   || INTVAL (XEXP (note, 0)) >= 0))
-	      /* Or may trap.  */
-	      || can_throw_internal (insn));
+      if (nonlocal_goto_handler_labels)
+	{
+	  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+	  if (note == 0 || INTVAL (XEXP (note, 0)) >= 0)
+	    return true;
+	}
+
+      /* Or may trap.  */
+      return can_throw_internal (insn);
 
     case INSN:
       /* Treat trap instructions like noreturn calls (same provision).  */
@@ -198,21 +202,58 @@ make_label_edge (sbitmap edge_cache, bas
   cached_make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
 }
 
+struct tmee_data
+{
+  sbitmap edge_cache;
+  basic_block src;
+  int flags;
+};
+
+static void
+rtl_make_eh_edge_1 (struct eh_region *region, void *xdata)
+{
+  const struct tmee_data *data = (const struct tmee_data *)xdata;
+  make_label_edge (data->edge_cache, data->src,
+		   get_eh_region_rtl_label (region), data->flags);
+}
+
 /* Create the edges generated by INSN in REGION.  */
 
 void
 rtl_make_eh_edge (sbitmap edge_cache, basic_block src, rtx insn)
 {
-  int is_call = CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0;
-  rtx handlers, i;
+  struct tmee_data data;
+  int region_nr;
+  bool is_resx;
+
+  data.edge_cache = edge_cache;
+  data.src = src;
+  data.flags = ((CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0)
+		| EDGE_ABNORMAL | EDGE_EH);
 
-  handlers = reachable_handlers (insn);
+  is_resx = false;
+  if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RESX)
+    {
+      region_nr = XINT (PATTERN (insn), 0);
+      is_resx = true;
+    }
+  else
+    {
+      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+      if (!note)
+	return;
+      region_nr = INTVAL (XEXP (note, 0));
+      if (region_nr <= 0)
+	return;
+    }
 
-  for (i = handlers; i; i = XEXP (i, 1))
-    make_label_edge (edge_cache, src, XEXP (i, 0),
-		     EDGE_ABNORMAL | EDGE_EH | is_call);
+  foreach_reachable_handler (region_nr, is_resx, rtl_make_eh_edge_1, &data);
 
-  free_INSN_LIST_list (&handlers);
+  if (flag_tm && find_reg_note (insn, REG_TM, NULL_RTX))
+    {
+      data.flags &= ~EDGE_EH;
+      foreach_reachable_transaction (region_nr, rtl_make_eh_edge_1, &data);
+    }
 }
 
 /* States of basic block as seen by find_many_sub_basic_blocks.  */
--- cfgexpand.c	(revision 141210)
+++ cfgexpand.c	(local)
@@ -51,8 +51,10 @@ gimple_assign_rhs_to_tree (gimple stmt)
 {
   tree t;
   enum gimple_rhs_class grhs_class;
-    
-  grhs_class = get_gimple_rhs_class (gimple_expr_code (stmt));
+  enum tree_code code;
+
+  code = gimple_expr_code (stmt);
+  grhs_class = get_gimple_rhs_class (code);
 
   if (grhs_class == GIMPLE_BINARY_RHS)
     t = build2 (gimple_assign_rhs_code (stmt),
@@ -64,7 +66,10 @@ gimple_assign_rhs_to_tree (gimple stmt)
 		TREE_TYPE (gimple_assign_lhs (stmt)),
 		gimple_assign_rhs1 (stmt));
   else if (grhs_class == GIMPLE_SINGLE_RHS)
-    t = gimple_assign_rhs1 (stmt);
+    {
+      gcc_assert (code != TM_LOAD && code != TM_STORE);
+      t = gimple_assign_rhs1 (stmt);
+    }
   else
     gcc_unreachable ();
 
@@ -94,6 +99,99 @@ set_expr_location_r (tree *tp, int *ws A
   return NULL_TREE;
 }
 
+/* Construct a memory load in a transactional context.  */
+
+static tree
+build_tm_load (tree lhs, tree rhs)
+{
+  enum built_in_function code = END_BUILTINS;
+  tree t, type = TREE_TYPE (rhs);
+
+  if (type == float_type_node)
+    code = BUILT_IN_TM_LOAD_FLOAT;
+  else if (type == double_type_node)
+    code = BUILT_IN_TM_LOAD_DOUBLE;
+  else if (TYPE_SIZE_UNIT (type) != NULL
+	   && host_integerp (TYPE_SIZE_UNIT (type), 1))
+    {
+      switch (tree_low_cst (TYPE_SIZE_UNIT (type), 1))
+	{
+	case 1:
+	  code = BUILT_IN_TM_LOAD_1;
+	  break;
+	case 2:
+	  code = BUILT_IN_TM_LOAD_2;
+	  break;
+	case 4:
+	  code = BUILT_IN_TM_LOAD_4;
+	  break;
+	case 8:
+	  code = BUILT_IN_TM_LOAD_8;
+	  break;
+	}
+    }
+
+  if (code == END_BUILTINS)
+    {
+      sorry ("transactional load for %T not supported", type);
+      code = BUILT_IN_TM_LOAD_4;
+    }
+
+  t = built_in_decls[code];
+  t = build_call_expr (t, 1, build_fold_addr_expr (rhs));
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (t)) != TYPE_MAIN_VARIANT (type))
+    t = build1 (VIEW_CONVERT_EXPR, type, t);
+  t = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, t);
+
+  return t;
+}
+
+/* Similarly for storing TYPE in a transactional context.  */
+
+static tree
+build_tm_store (tree lhs, tree rhs)
+{
+  enum built_in_function code = END_BUILTINS;
+  tree t, fn, type = TREE_TYPE (rhs), simple_type;
+
+  if (type == float_type_node)
+    code = BUILT_IN_TM_STORE_FLOAT;
+  else if (type == double_type_node)
+    code = BUILT_IN_TM_STORE_DOUBLE;
+  else if (TYPE_SIZE_UNIT (type) != NULL
+	   && host_integerp (TYPE_SIZE_UNIT (type), 1))
+    {
+      switch (tree_low_cst (TYPE_SIZE_UNIT (type), 1))
+	{
+	case 1:
+	  code = BUILT_IN_TM_STORE_1;
+	  break;
+	case 2:
+	  code = BUILT_IN_TM_STORE_2;
+	  break;
+	case 4:
+	  code = BUILT_IN_TM_STORE_4;
+	  break;
+	case 8:
+	  code = BUILT_IN_TM_STORE_8;
+	  break;
+	}
+    }
+
+  if (code == END_BUILTINS)
+    {
+      sorry ("transactional load for %T not supported", type);
+      code = BUILT_IN_TM_STORE_4;
+    }
+
+  fn = built_in_decls[code];
+  simple_type = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))));
+  if (TYPE_MAIN_VARIANT (simple_type) != TYPE_MAIN_VARIANT (type))
+    rhs = build1 (VIEW_CONVERT_EXPR, simple_type, rhs);
+  t = build_call_expr (fn, 2, build_fold_addr_expr (lhs), rhs);
+
+  return t;
+}
 
 /* RTL expansion has traditionally been done on trees, so the
    transition to doing it on GIMPLE tuples is very invasive to the RTL
@@ -115,10 +213,23 @@ gimple_to_tree (gimple stmt)
       {
 	tree lhs = gimple_assign_lhs (stmt);
 
-	t = gimple_assign_rhs_to_tree (stmt);
-	t = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, t);
-	if (gimple_assign_nontemporal_move_p (stmt))
-	  MOVE_NONTEMPORAL (t) = true;
+	switch (gimple_expr_code (stmt))
+	  {
+	  case TM_LOAD:
+	    t = build_tm_load (lhs, gimple_assign_rhs1 (stmt));
+	    break;
+				 
+	  case TM_STORE:
+	    t = build_tm_store (lhs, gimple_assign_rhs1 (stmt));
+	    break;
+
+	  default:
+	    t = gimple_assign_rhs_to_tree (stmt);
+	    t = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, t);
+	    if (gimple_assign_nontemporal_move_p (stmt))
+	      MOVE_NONTEMPORAL (t) = true;
+	    break;
+	  }
       }
       break;
 	                                 
--- except.c	(revision 141210)
+++ except.c	(local)
@@ -549,6 +549,12 @@ set_eh_region_tree_label (struct eh_regi
 {
   region->tree_label = lab;
 }
+
+rtx
+get_eh_region_rtl_label (struct eh_region *region)
+{
+  return (crtl->eh.built_landing_pads ? region->landing_pad : region->label);
+}
 
 void
 expand_resx_expr (tree exp)
@@ -1380,6 +1386,56 @@ emit_to_new_bb_before (rtx seq, rtx insn
   return bb;
 }
 
+/* Rearrange the EH label for a transaction region immediately after
+   the call to __tm_start.  This means moving the insns copying the
+   return value from hard register to pseudo into the next block.
+   This models the effect of the setjmp accurately.  */
+
+static void
+frob_transaction_start (struct eh_region *region)
+{
+  rtx insn, call = NULL, last = NULL;
+
+  /* Appease get_eh_region_rtl_label.  */
+  region->landing_pad = region->label; 
+
+  for (insn = PREV_INSN (region->label); ; insn = PREV_INSN (insn))
+    {
+      if (NONJUMP_INSN_P (insn))
+	{
+	  if (last == NULL)
+	    last = insn;
+	}
+      else if (CALL_P (insn))
+	{
+	  call = insn;
+	  break;
+	}
+    }
+
+#ifdef ENABLE_CHECKING
+  /* Check that the call is in fact to __tm_start.  */
+  {
+    rtx x = SET_SRC (PATTERN (call));
+    tree decl;
+    gcc_assert (GET_CODE (x) == CALL);
+    x = XEXP (x, 0);
+    gcc_assert (MEM_P (x));
+    x = XEXP (x, 0);
+    decl = SYMBOL_REF_DECL (x);
+    /* DECL could be null due to the target popping the real symbol_ref
+       into the constant pool.  Don't try that hard... */
+    gcc_assert (!decl || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+			  && DECL_FUNCTION_CODE (decl) == BUILT_IN_TM_START));
+  }
+#endif
+
+  insn = NEXT_INSN (region->label);
+  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
+
+  reorder_insns (NEXT_INSN (call), last, insn);
+}
+
 /* Generate the code to actually handle exceptions, which will follow the
    landing pads.  */
 
@@ -1491,16 +1547,44 @@ build_post_landing_pads (void)
 
 	case ERT_CATCH:
 	case ERT_THROW:
-	case ERT_TRANSACTION:
 	  /* Nothing to do.  */
 	  break;
 
+	case ERT_TRANSACTION:
+	  frob_transaction_start (region);
+	  break;
+
 	default:
 	  gcc_unreachable ();
 	}
     }
 }
 
+/* Similar, but only expect to process ERT_TRANSACTION nodes.  This is
+   used when EH is not enabled, but TM is.  */
+
+static void
+build_post_landing_pads_tm_only (void)
+{
+  int i;
+
+  for (i = cfun->eh->last_region_number; i > 0; --i)
+    {
+      struct eh_region *region;
+
+      region = VEC_index (eh_region, cfun->eh->region_array, i);
+      /* Mind we don't process a region more than once.  */
+      if (!region || region->region_number != i)
+	continue;
+
+      if (region->type == ERT_TRANSACTION)
+	frob_transaction_start (region);
+      else
+	gcc_unreachable ();
+    }
+}
+
+
 /* Replace RESX patterns with jumps to the next handler if any, or calls to
    _Unwind_Resume otherwise.  */
 
@@ -1665,7 +1749,8 @@ sjlj_find_directly_reachable_regions (st
       if (!note || INTVAL (XEXP (note, 0)) <= 0)
 	continue;
 
-      region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
+      region = VEC_index (eh_region, cfun->eh->region_array,
+			  INTVAL (XEXP (note, 0)));
 
       type_thrown = NULL_TREE;
       if (region->type == ERT_THROW)
@@ -2062,14 +2147,23 @@ finish_eh_generation (void)
   if (cfun->eh->region_tree == NULL)
     return;
 
+  /* If doing TM but not EH, go ahead and frob the record for the
+     setjmp-y start of the transaction.  */
+  if (!doing_eh (0))
+    {
+      build_post_landing_pads_tm_only ();
+      crtl->eh.built_landing_pads = 1;
+      return;
+    }
+
   /* The object here is to provide find_basic_blocks with detailed
-     information (via reachable_handlers) on how exception control
-     flows within the function.  In this first pass, we can include
-     type information garnered from ERT_THROW and ERT_ALLOWED_EXCEPTIONS
-     regions, and hope that it will be useful in deleting unreachable
-     handlers.  Subsequently, we will generate landing pads which will
-     connect many of the handlers, and then type information will not
-     be effective.  Still, this is a win over previous implementations.  */
+     information on how exception control flows within the function.
+     In this first pass, we can include type information garnered
+     from ERT_THROW and ERT_ALLOWED_EXCEPTIONS regions, and hope that
+     it will be useful in deleting unreachable handlers.  Subsequently,
+     we will generate landing pads which will connect many of the handlers,
+     and then type information will not be effective.  Still, this is
+     a win over previous implementations.  */
 
   /* These registers are used by the landing pads.  Make sure they
      have been generated.  */
@@ -2624,54 +2718,6 @@ foreach_reachable_transaction (int regio
     }
 }
 
-/* Retrieve a list of labels of exception handlers which can be
-   reached by a given insn.  */
-
-static void
-arh_to_landing_pad (struct eh_region *region, void *data)
-{
-  rtx *p_handlers = (rtx *) data;
-  if (! *p_handlers)
-    *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX);
-}
-
-static void
-arh_to_label (struct eh_region *region, void *data)
-{
-  rtx *p_handlers = (rtx *) data;
-  *p_handlers = alloc_INSN_LIST (region->label, *p_handlers);
-}
-
-rtx
-reachable_handlers (rtx insn)
-{
-  bool is_resx = false;
-  rtx handlers = NULL;
-  int region_number;
-
-  if (JUMP_P (insn)
-      && GET_CODE (PATTERN (insn)) == RESX)
-    {
-      region_number = XINT (PATTERN (insn), 0);
-      is_resx = true;
-    }
-  else
-    {
-      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-      if (!note || INTVAL (XEXP (note, 0)) <= 0)
-	return NULL;
-      region_number = INTVAL (XEXP (note, 0));
-    }
-
-  foreach_reachable_handler (region_number, is_resx,
-			     (crtl->eh.built_landing_pads
-			      ? arh_to_landing_pad
-			      : arh_to_label),
-			     &handlers);
-
-  return handlers;
-}
-
 /* Determine if the given INSN can throw an exception that is caught
    within the function.  */
 
@@ -2711,6 +2757,7 @@ bool
 can_throw_internal (const_rtx insn)
 {
   rtx note;
+  int region_number;
 
   if (! INSN_P (insn))
     return false;
@@ -2728,8 +2775,23 @@ can_throw_internal (const_rtx insn)
   note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
   if (!note || INTVAL (XEXP (note, 0)) <= 0)
     return false;
+  region_number = INTVAL (XEXP (note, 0));
+
+  /* Check for transactional builtins.  */
+  if (flag_tm && find_reg_note (insn, REG_TM, NULL_RTX))
+    {
+      struct eh_region *region;
+
+      region = VEC_index (eh_region, cfun->eh->region_array, region_number);
+      while (region)
+	{
+	  if (region->type == ERT_TRANSACTION)
+	    return true;
+	  region = region->outer;
+	}
+    }
 
-  return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false);
+  return can_throw_internal_1 (region_number, false);
 }
 
 /* Determine if the given INSN can throw an exception that is
@@ -3985,7 +4047,7 @@ default_init_unwind_resume_libfunc (void
 static bool
 gate_handle_eh (void)
 {
-  return doing_eh (0);
+  return flag_tm || doing_eh (0);
 }
 
 /* Complete generation of exception handling code.  */
--- except.h	(revision 141210)
+++ except.h	(local)
@@ -59,7 +59,6 @@ extern void finish_eh_generation (void);
 extern void init_eh (void);
 extern void init_eh_for_function (void);
 
-extern rtx reachable_handlers (rtx);
 extern void maybe_remove_eh_handler (rtx);
 
 extern void convert_from_eh_region_ranges (void);
@@ -98,6 +97,7 @@ extern struct eh_region *get_eh_region_f
 extern bool get_eh_region_may_contain_throw (struct eh_region *);
 extern tree get_eh_region_tree_label (struct eh_region *);
 extern void set_eh_region_tree_label (struct eh_region *, tree);
+extern rtx get_eh_region_rtl_label (struct eh_region *);
 
 typedef void (*eh_callback) (struct eh_region *, void *);
 extern void foreach_reachable_handler (int, bool, eh_callback, void *);
--- gimple.c	(revision 141210)
+++ gimple.c	(local)
@@ -3086,6 +3086,8 @@ get_call_expr_in (tree t)
     t = TREE_OPERAND (t, 1);
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
     t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
+    t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CALL_EXPR)
     return t;
   return NULL_TREE;
--- gtm-builtins.def	(revision 141210)
+++ gtm-builtins.def	(local)
@@ -1,5 +1,5 @@
 DEF_TM_BUILTIN (BUILT_IN_TM_START, "__gtm_start",
-		BT_FN_UINT_UINT, ATTR_RETURNSTWICE_NOTHROW_LIST)
+		BT_FN_UINT_UINT, ATTR_NOTHROW_LIST)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_COMMIT, "__gtm_commit",
 		BT_FN_VOID, ATTR_NOTHROW_LIST)
--- reg-notes.def	(revision 141210)
+++ reg-notes.def	(local)
@@ -147,3 +147,8 @@ REG_NOTE (CROSSING_JUMP)
 /* This kind of note is generated at each to `setjmp', and similar
    functions that can return twice.  */
 REG_NOTE (SETJMP)
+
+/* This kind of note is generated at each transactional memory
+   builtin, to indicate we need to generate transaction restart
+   edges for this insn.  */
+REG_NOTE (TM)
--- tree-eh.c	(revision 141210)
+++ tree-eh.c	(local)
@@ -2443,7 +2443,8 @@ maybe_clean_or_replace_eh_stmt (gimple o
 
   if (region_nr >= 0)
     {
-      bool new_stmt_could_throw = stmt_could_throw_p (new_stmt);
+      bool new_stmt_could_throw
+	= stmt_could_throw_p (new_stmt) || is_transactional_stmt (new_stmt);
 
       if (new_stmt == old_stmt && new_stmt_could_throw)
 	return false;
--- tree-optimize.c	(revision 141210)
+++ tree-optimize.c	(local)
@@ -316,7 +316,9 @@ execute_fixup_cfg (void)
 		  }
 	      }
 
-	    if (!stmt_could_throw_p (stmt) && lookup_stmt_eh_region (stmt))
+	    if (!stmt_could_throw_p (stmt)
+		&& !is_transactional_stmt (stmt)
+		&& lookup_stmt_eh_region (stmt))
 	      remove_stmt_from_eh_region (stmt);
 	  }
 
--- tree.h	(revision 141210)
+++ tree.h	(local)
@@ -5029,6 +5029,8 @@ extern tree build_duplicate_type (tree);
 /* Function does not read or write memory (but may have side effects, so
    it does not necessarily fit ECF_CONST).  */
 #define ECF_NOVOPS		  (1 << 9)
+/* Nonzero if this call performs a transactional memory operation.  */
+#define ECF_TM_OPS		  (1 << 10)
 
 extern int flags_from_decl_or_type (const_tree);
 extern int call_expr_flags (const_tree);

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