public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] 19/n: trans-mem: compiler tree/gimple stuff
@ 2011-11-03 19:40 Aldy Hernandez
  2011-11-04 10:44 ` Richard Guenther
  2011-11-04 15:40 ` Michael Matz
  0 siblings, 2 replies; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-03 19:40 UTC (permalink / raw)
  To: gcc-patches

These are misc tree and gimple patches, which I consider front-ish-end 
changes.

Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(.../trunk)	(revision 180744)
+++ gcc/tree.c	(.../branches/transactional-memory)	(revision 180773)
@@ -9594,6 +9594,9 @@ build_common_builtin_nodes (void)
  				    integer_type_node, NULL_TREE);
    local_define_builtin ("__builtin_eh_pointer", ftype, 
BUILT_IN_EH_POINTER,
  			"__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
+  if (flag_tm)
+    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
+		   get_identifier ("transaction_pure"));

    tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode 
(), 0);
    ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../trunk)	(revision 180744)
+++ gcc/tree.h	(.../branches/transactional-memory)	(revision 180773)
@@ -539,6 +539,9 @@ struct GTY(()) tree_common {
         ENUM_IS_SCOPED in
  	   ENUMERAL_TYPE

+       TRANSACTION_EXPR_OUTER in
+           TRANSACTION_EXPR
+
     public_flag:

         TREE_OVERFLOW in
@@ -566,6 +569,9 @@ struct GTY(()) tree_common {
         OMP_CLAUSE_PRIVATE_DEBUG in
             OMP_CLAUSE_PRIVATE

+       TRANSACTION_EXPR_RELAXED in
+           TRANSACTION_EXPR
+
     private_flag:

         TREE_PRIVATE in
@@ -1808,6 +1814,14 @@ extern void protected_set_expr_location
  #define CALL_EXPR_ARGP(NODE) \
    (&(TREE_OPERAND (CALL_EXPR_CHECK (NODE), 0)) + 3)

+/* TM directives and accessors.  */
+#define TRANSACTION_EXPR_BODY(NODE) \
+  TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 0)
+#define TRANSACTION_EXPR_OUTER(NODE) \
+  (TRANSACTION_EXPR_CHECK (NODE)->base.static_flag)
+#define TRANSACTION_EXPR_RELAXED(NODE) \
+  (TRANSACTION_EXPR_CHECK (NODE)->base.public_flag)
+
  /* OpenMP directive and clause accessors.  */

  #define OMP_BODY(NODE) \
@@ -3452,6 +3466,34 @@ struct GTY(())
  #define DECL_NO_INLINE_WARNING_P(NODE) \
    (FUNCTION_DECL_CHECK (NODE)->function_decl.no_inline_warning_flag)

+/* Nonzero in a FUNCTION_DECL means this function is the transactional
+   clone of a function - called only from inside transactions.  */
+#define DECL_IS_TM_CLONE(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.tm_clone_flag)
+
+/* Nonzero if a FUNCTION_CODE is a TM load/store.  */
+#define BUILTIN_TM_LOAD_STORE_P(FN) \
+  ((FN) >= BUILT_IN_TM_STORE_1 && (FN) <= BUILT_IN_TM_LOAD_RFW_LDOUBLE)
+
+/* Nonzero if a FUNCTION_CODE is a TM load.  */
+#define BUILTIN_TM_LOAD_P(FN) \
+  ((FN) >= BUILT_IN_TM_LOAD_1 && (FN) <= BUILT_IN_TM_LOAD_RFW_LDOUBLE)
+
+/* Nonzero if a FUNCTION_CODE is a TM store.  */
+#define BUILTIN_TM_STORE_P(FN) \
+  ((FN) >= BUILT_IN_TM_STORE_1 && (FN) <= BUILT_IN_TM_STORE_WAW_LDOUBLE)
+
+#define CASE_BUILT_IN_TM_LOAD(FN)	\
+  case BUILT_IN_TM_LOAD_##FN:		\
+  case BUILT_IN_TM_LOAD_RAR_##FN:	\
+  case BUILT_IN_TM_LOAD_RAW_##FN:	\
+  case BUILT_IN_TM_LOAD_RFW_##FN
+
+#define CASE_BUILT_IN_TM_STORE(FN)	\
+  case BUILT_IN_TM_STORE_##FN:		\
+  case BUILT_IN_TM_STORE_WAR_##FN:	\
+  case BUILT_IN_TM_STORE_WAW_##FN
+
  /* Nonzero in a FUNCTION_DECL that should be always inlined by the inliner
     disregarding size and cost heuristics.  This is equivalent to using
     the always_inline attribute without the required diagnostics if the
@@ -3539,8 +3581,9 @@ struct GTY(()) tree_function_decl {
    unsigned pure_flag : 1;
    unsigned looping_const_or_pure_flag : 1;
    unsigned has_debug_args_flag : 1;
+  unsigned tm_clone_flag : 1;

-  /* 2 bits left */
+  /* 1 bit left */
  };

  /* The source language of the translation-unit.  */
@@ -5174,6 +5217,8 @@ extern void expand_return (tree);

  /* In tree-eh.c */
  extern void using_eh_for_cleanups (void);
+extern int struct_ptr_eq (const void *, const void *);
+extern hashval_t struct_ptr_hash (const void *);

  /* In fold-const.c */

@@ -5543,6 +5588,8 @@ extern tree build_duplicate_type (tree);
  #define ECF_NOVOPS		  (1 << 9)
  /* The function does not lead to calls within current function unit.  */
  #define ECF_LEAF		  (1 << 10)
+/* Nonzero if this call performs a transactional memory operation.  */
+#define ECF_TM_OPS		  (1 << 11)

  extern int flags_from_decl_or_type (const_tree);
  extern int call_expr_flags (const_tree);
@@ -5593,6 +5640,8 @@ extern void init_attributes (void);
     a decl attribute to the declaration rather than to its type).  */
  extern tree decl_attributes (tree *, tree, int);

+extern void apply_tm_attr (tree, tree);
+
  /* In integrate.c */
  extern void set_decl_abstract_flags (tree, int);
  extern void set_decl_origin_self (tree);
@@ -5805,6 +5854,21 @@ extern unsigned HOST_WIDE_INT compute_bu
  extern unsigned HOST_WIDE_INT highest_pow2_factor (const_tree);
  extern tree build_personality_function (const char *);

+/* In trans-mem.c.  */
+extern tree build_tm_abort_call (location_t, bool);
+extern bool is_tm_safe (const_tree);
+extern bool is_tm_pure (const_tree);
+extern bool is_tm_may_cancel_outer (tree);
+extern bool is_tm_ending_fndecl (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: gcc/attribs.c
===================================================================
--- gcc/attribs.c	(.../trunk)	(revision 180744)
+++ gcc/attribs.c	(.../branches/transactional-memory)	(revision 180773)
@@ -166,7 +166,8 @@ init_attributes (void)
  	  gcc_assert (strcmp (attribute_tables[i][j].name,
  			      attribute_tables[i][k].name));
      }
-  /* Check that no name occurs in more than one table.  */
+  /* Check that no name occurs in more than one table.  Names that
+     begin with '*' are exempt, and may be overridden.  */
    for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
      {
        size_t j, k, l;
@@ -174,8 +175,9 @@ init_attributes (void)
        for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
  	for (k = 0; attribute_tables[i][k].name != NULL; k++)
  	  for (l = 0; attribute_tables[j][l].name != NULL; l++)
-	    gcc_assert (strcmp (attribute_tables[i][k].name,
-				attribute_tables[j][l].name));
+	    gcc_assert (attribute_tables[i][k].name[0] == '*'
+			|| strcmp (attribute_tables[i][k].name,
+				   attribute_tables[j][l].name));
      }
  #endif

@@ -207,7 +209,7 @@ register_attribute (const struct attribu
    slot = htab_find_slot_with_hash (attribute_hash, &str,
  				   substring_hash (str.str, str.length),
  				   INSERT);
-  gcc_assert (!*slot);
+  gcc_assert (!*slot || attr->name[0] == '*');
    *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
  }

@@ -484,3 +486,12 @@ decl_attributes (tree *node, tree attrib

    return returned_attrs;
  }
+
+/* Subroutine of set_method_tm_attributes.  Apply TM attribute ATTR
+   to the method FNDECL.  */
+
+void
+apply_tm_attr (tree fndecl, tree attr)
+{
+  decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
+}
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(.../trunk)	(revision 180744)
+++ gcc/targhooks.c	(.../branches/transactional-memory)	(revision 180773)
@@ -1214,6 +1214,12 @@ default_have_conditional_execution (void
  #endif
  }

+tree
+default_builtin_tm_load_store (tree ARG_UNUSED (type))
+{
+  return NULL_TREE;
+}
+
  /* Compute cost of moving registers to/from memory.  */

  int
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(.../trunk)	(revision 180744)
+++ gcc/targhooks.h	(.../branches/transactional-memory)	(revision 180773)
@@ -152,6 +152,9 @@ extern bool default_addr_space_subset_p
  extern rtx default_addr_space_convert (rtx, tree, tree);
  extern unsigned int default_case_values_threshold (void);
  extern bool default_have_conditional_execution (void);
+
+extern tree default_builtin_tm_load_store (tree);
+
  extern int default_memory_move_cost (enum machine_mode, reg_class_t, 
bool);
  extern int default_register_move_cost (enum machine_mode, reg_class_t,
  				       reg_class_t);
Index: gcc/gimple.def
===================================================================
--- gcc/gimple.def	(.../trunk)	(revision 180744)
+++ gcc/gimple.def	(.../branches/transactional-memory)	(revision 180773)
@@ -124,6 +124,14 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_
      CHAIN is the optional static chain link for nested functions.  */
  DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_CALL)

+/* GIMPLE_TRANSACTION <BODY, LABEL> represents __transaction_atomic and
+   __transaction_relaxed 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_TRANSACTION, "gimple_transaction", GSS_TRANSACTION)
+
  /* GIMPLE_RETURN <RETVAL> represents return statements.

     RETVAL is the value to return or NULL.  If a value is returned it
@@ -151,6 +159,12 @@ DEFGSCODE(GIMPLE_EH_FILTER, "gimple_eh_f
     be invoked if an exception propagates to this point.  */
  DEFGSCODE(GIMPLE_EH_MUST_NOT_THROW, "gimple_eh_must_not_throw", 
GSS_EH_MNT)

+/* GIMPLE_EH_ELSE <N_BODY, E_BODY> must be the sole contents of
+   a GIMPLE_TRY_FINALLY node.  For all normal exits from the try block,
+   we N_BODY is run; for all exception exits from the try block,
+   E_BODY is run.  */
+DEFGSCODE(GIMPLE_EH_ELSE, "gimple_eh_else", GSS_EH_ELSE)
+
  /* GIMPLE_RESX resumes execution after an exception.  */
  DEFGSCODE(GIMPLE_RESX, "gimple_resx", GSS_EH_CTRL)

Index: gcc/builtin-types.def
===================================================================
--- gcc/builtin-types.def	(.../trunk)	(revision 180744)
+++ gcc/builtin-types.def	(.../branches/transactional-memory)	(revision 
180773)
@@ -477,3 +477,24 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_I
  DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
  DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
  		     BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
+
+
+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_1 (BT_FN_LDOUBLE_VPTR, BT_LONGDOUBLE, BT_VOLATILE_PTR)
+
+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)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_LDOUBLE, BT_VOID,
+		     BT_VOLATILE_PTR, BT_LONGDOUBLE)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_SIZE, BT_VOID,
+		     BT_VOLATILE_PTR, BT_SIZE)
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(.../trunk)	(revision 180744)
+++ gcc/builtins.def	(.../branches/transactional-memory)	(revision 180773)
@@ -142,6 +142,13 @@ along with GCC; see the file COPYING3.
                 false, true, true, ATTRS, false, \
  	       (flag_openmp || flag_tree_parallelize_loops))

+/* Builtin used by the implementation of GNU TM.  These
+   functions are mapped to the actual implementation of the STM library. */
+#undef DEF_TM_BUILTIN
+#define DEF_TM_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
+  DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
+               false, true, true, ATTRS, false, flag_tm)
+
  /* Define an attribute list for math functions that are normally
     "impure" because some of them may write into global memory for
     `errno'.  If !flag_errno_math they are instead "const".  */
@@ -624,6 +631,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_APPLY_A
  DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32, "bswap32", 
BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64, "bswap64", 
BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_CACHE, "__clear_cache", 
BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
+/* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is 
changed.  */
  DEF_LIB_BUILTIN        (BUILT_IN_CALLOC, "calloc", 
BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_CLASSIFY_TYPE, "classify_type", 
BT_FN_INT_VAR, ATTR_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, 
ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -662,6 +670,7 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSL, "
  DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, 
ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_EXT_LIB_BUILTIN        (BUILT_IN_FORK, "fork", BT_FN_PID, 
ATTR_NOTHROW_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_FRAME_ADDRESS, "frame_address", 
BT_FN_PTR_UINT, ATTR_NULL)
+/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed.  */
  DEF_LIB_BUILTIN        (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, 
ATTR_NOTHROW_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", 
BT_FN_PTR_PTR, ATTR_NULL)
  DEF_EXT_LIB_BUILTIN    (BUILT_IN_GETTEXT, "gettext", 
BT_FN_STRING_CONST_STRING, ATTR_FORMAT_ARG_1)
@@ -698,6 +707,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_ISUNORD
  DEF_LIB_BUILTIN        (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, 
ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_C99_BUILTIN        (BUILT_IN_LLABS, "llabs", 
BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_LONGJMP, "longjmp", 
BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+/* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is 
changed.  */
  DEF_LIB_BUILTIN        (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, 
ATTR_MALLOC_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, 
ATTR_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_PARITY, "parity", BT_FN_INT_UINT, 
ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -793,3 +803,6 @@ DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUE

  /* OpenMP builtins.  */
  #include "omp-builtins.def"
+
+/* GTM builtins. */
+#include "gtm-builtins.def"
Index: gcc/gimple-low.c
===================================================================
--- gcc/gimple-low.c	(.../trunk)	(revision 180744)
+++ gcc/gimple-low.c	(.../branches/transactional-memory)	(revision 180773)
@@ -396,6 +396,11 @@ lower_stmt (gimple_stmt_iterator *gsi, s
        lower_sequence (gimple_eh_filter_failure (stmt), data);
        break;

+    case GIMPLE_EH_ELSE:
+      lower_sequence (gimple_eh_else_n_body (stmt), data);
+      lower_sequence (gimple_eh_else_e_body (stmt), data);
+      break;
+
      case GIMPLE_NOP:
      case GIMPLE_ASM:
      case GIMPLE_ASSIGN:
@@ -446,6 +451,10 @@ lower_stmt (gimple_stmt_iterator *gsi, s
        data->cannot_fallthru = false;
        return;

+    case GIMPLE_TRANSACTION:
+      lower_sequence (gimple_transaction_body (stmt), data);
+      break;
+
      default:
        gcc_unreachable ();
      }
@@ -727,6 +736,10 @@ gimple_stmt_may_fallthru (gimple stmt)
        return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
  	      && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));

+    case GIMPLE_EH_ELSE:
+      return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
+	      || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));
+
      case GIMPLE_CALL:
        /* Functions that do not return do not fall through.  */
        return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
Index: gcc/gsstruct.def
===================================================================
--- gcc/gsstruct.def	(.../trunk)	(revision 180744)
+++ gcc/gsstruct.def	(.../branches/transactional-memory)	(revision 180773)
@@ -38,6 +38,7 @@ DEFGSSTRUCT(GSS_CATCH, gimple_statement_
  DEFGSSTRUCT(GSS_EH_FILTER, gimple_statement_eh_filter, false)
  DEFGSSTRUCT(GSS_EH_MNT, gimple_statement_eh_mnt, false)
  DEFGSSTRUCT(GSS_EH_CTRL, gimple_statement_eh_ctrl, false)
+DEFGSSTRUCT(GSS_EH_ELSE, gimple_statement_eh_else, false)
  DEFGSSTRUCT(GSS_WCE, gimple_statement_wce, false)
  DEFGSSTRUCT(GSS_OMP, gimple_statement_omp, false)
  DEFGSSTRUCT(GSS_OMP_CRITICAL, gimple_statement_omp_critical, false)
@@ -49,3 +50,4 @@ DEFGSSTRUCT(GSS_OMP_SINGLE, gimple_state
  DEFGSSTRUCT(GSS_OMP_CONTINUE, gimple_statement_omp_continue, false)
  DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gimple_statement_omp_atomic_load, false)
  DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE, gimple_statement_omp_atomic_store, 
false)
+DEFGSSTRUCT(GSS_TRANSACTION, gimple_statement_transaction, false)
Index: gcc/tree-eh.c
===================================================================
--- gcc/tree-eh.c	(.../trunk)	(revision 180744)
+++ gcc/tree-eh.c	(.../branches/transactional-memory)	(revision 180773)
@@ -58,7 +58,7 @@ using_eh_for_cleanups (void)
     pointer.  Assumes all pointers are interchangeable, which is sort
     of already assumed by gcc elsewhere IIRC.  */

-static int
+int
  struct_ptr_eq (const void *a, const void *b)
  {
    const void * const * x = (const void * const *) a;
@@ -66,7 +66,7 @@ struct_ptr_eq (const void *a, const void
    return *x == *y;
  }

-static hashval_t
+hashval_t
  struct_ptr_hash (const void *a)
  {
    const void * const * x = (const void * const *) a;
@@ -284,6 +284,11 @@ collect_finally_tree (gimple stmt, gimpl
        collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
        break;

+    case GIMPLE_EH_ELSE:
+      collect_finally_tree_1 (gimple_eh_else_n_body (stmt), region);
+      collect_finally_tree_1 (gimple_eh_else_e_body (stmt), region);
+      break;
+
      default:
        /* A type, a decl, or some kind of statement that we're not
  	 interested in.  Don't walk them.  */
@@ -534,6 +539,10 @@ replace_goto_queue_1 (gimple stmt, struc
      case GIMPLE_EH_FILTER:
        replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf);
        break;
+    case GIMPLE_EH_ELSE:
+      replace_goto_queue_stmt_list (gimple_eh_else_n_body (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_eh_else_e_body (stmt), tf);
+      break;

      default:
        /* These won't have gotos in them.  */
@@ -921,6 +930,21 @@ lower_try_finally_fallthru_label (struct
    return label;
  }

+/* A subroutine of lower_try_finally.  If FINALLY consits of a
+   GIMPLE_EH_ELSE node, return it.  */
+
+static inline gimple
+get_eh_else (gimple_seq finally)
+{
+  gimple x = gimple_seq_first_stmt (finally);
+  if (gimple_code (x) == GIMPLE_EH_ELSE)
+    {
+      gcc_assert (gimple_seq_singleton_p (finally));
+      return x;
+    }
+  return NULL;
+}
+
  /* A subroutine of lower_try_finally.  If the eh_protect_cleanup_actions
     langhook returns non-null, then the language requires that the 
exception
     path out of a try_finally be treated specially.  To wit: the code 
within
@@ -950,7 +974,7 @@ honor_protect_cleanup_actions (struct le
    gimple_stmt_iterator gsi;
    bool finally_may_fallthru;
    gimple_seq finally;
-  gimple x;
+  gimple x, eh_else;

    /* First check for nothing to do.  */
    if (lang_hooks.eh_protect_cleanup_actions == NULL)
@@ -960,12 +984,18 @@ honor_protect_cleanup_actions (struct le
      return;

    finally = gimple_try_cleanup (tf->top_p);
-  finally_may_fallthru = gimple_seq_may_fallthru (finally);
+  eh_else = get_eh_else (finally);

    /* Duplicate the FINALLY block.  Only need to do this for try-finally,
-     and not for cleanups.  */
-  if (this_state)
+     and not for cleanups.  If we've got an EH_ELSE, extract it now.  */
+  if (eh_else)
+    {
+      finally = gimple_eh_else_e_body (eh_else);
+      gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
+    }
+  else if (this_state)
      finally = lower_try_finally_dup_block (finally, outer_state);
+  finally_may_fallthru = gimple_seq_may_fallthru (finally);

    /* If this cleanup consists of a TRY_CATCH_EXPR with 
TRY_CATCH_IS_CLEANUP
       set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
@@ -1011,7 +1041,7 @@ lower_try_finally_nofallthru (struct leh
  			      struct leh_tf_state *tf)
  {
    tree lab;
-  gimple x;
+  gimple x, eh_else;
    gimple_seq finally;
    struct goto_queue_node *q, *qe;

@@ -1034,15 +1064,35 @@ lower_try_finally_nofallthru (struct leh

    replace_goto_queue (tf);

-  lower_eh_constructs_1 (state, finally);
-  gimple_seq_add_seq (&tf->top_p_seq, finally);
+  /* Emit the finally block into the stream.  Lower EH_ELSE at this 
time.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      finally = gimple_eh_else_n_body (eh_else);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);

-  if (tf->may_throw)
+      if (tf->may_throw)
+	{
+	  finally = gimple_eh_else_e_body (eh_else);
+	  lower_eh_constructs_1 (state, finally);
+
+	  emit_post_landing_pad (&eh_seq, tf->region);
+	  gimple_seq_add_seq (&eh_seq, finally);
+	}
+    }
+  else
      {
-      emit_post_landing_pad (&eh_seq, tf->region);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);

-      x = gimple_build_goto (lab);
-      gimple_seq_add_stmt (&eh_seq, x);
+      if (tf->may_throw)
+	{
+	  emit_post_landing_pad (&eh_seq, tf->region);
+
+	  x = gimple_build_goto (lab);
+	  gimple_seq_add_stmt (&eh_seq, x);
+	}
      }
  }

@@ -1062,6 +1112,18 @@ lower_try_finally_onedest (struct leh_st
    finally = gimple_try_cleanup (tf->top_p);
    tf->top_p_seq = gimple_try_eval (tf->top_p);

+  /* Since there's only one destination, and the destination edge can only
+     either be EH or non-EH, that implies that all of our incoming edges
+     are of the same type.  Therefore we can lower EH_ELSE immediately.  */
+  x = get_eh_else (finally);
+  if (x)
+    {
+      if (tf->may_throw)
+        finally = gimple_eh_else_e_body (x);
+      else
+        finally = gimple_eh_else_n_body (x);
+    }
+
    lower_eh_constructs_1 (state, finally);

    if (tf->may_throw)
@@ -1132,11 +1194,18 @@ lower_try_finally_copy (struct leh_state
    gimple_seq finally;
    gimple_seq new_stmt;
    gimple_seq seq;
-  gimple x;
+  gimple x, eh_else;
    tree tmp;
    location_t tf_loc = gimple_location (tf->try_finally_expr);

    finally = gimple_try_cleanup (tf->top_p);
+
+  /* Notice EH_ELSE, and simplify some of the remaining code
+     by considering FINALLY to be the normal return path only.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    finally = gimple_eh_else_n_body (eh_else);
+
    tf->top_p_seq = gimple_try_eval (tf->top_p);
    new_stmt = NULL;

@@ -1153,7 +1222,12 @@ lower_try_finally_copy (struct leh_state

    if (tf->may_throw)
      {
-      seq = lower_try_finally_dup_block (finally, state);
+      /* We don't need to copy the EH path of EH_ELSE,
+	 since it is only emitted once.  */
+      if (eh_else)
+        seq = gimple_eh_else_e_body (eh_else);
+      else
+        seq = lower_try_finally_dup_block (finally, state);
        lower_eh_constructs_1 (state, seq);

        emit_post_landing_pad (&eh_seq, tf->region);
@@ -1252,7 +1326,7 @@ lower_try_finally_switch (struct leh_sta
    tree last_case;
    VEC (tree,heap) *case_label_vec;
    gimple_seq switch_body;
-  gimple x;
+  gimple x, eh_else;
    tree tmp;
    gimple switch_stmt;
    gimple_seq finally;
@@ -1263,9 +1337,10 @@ lower_try_finally_switch (struct leh_sta
    location_t finally_loc;

    switch_body = gimple_seq_alloc ();
+  finally = gimple_try_cleanup (tf->top_p);
+  eh_else = get_eh_else (finally);

    /* Mash the TRY block to the head of the chain.  */
-  finally = gimple_try_cleanup (tf->top_p);
    tf->top_p_seq = gimple_try_eval (tf->top_p);

    /* The location of the finally is either the last stmt in the finally
@@ -1281,7 +1356,7 @@ lower_try_finally_switch (struct leh_sta
    nlabels = VEC_length (tree, tf->dest_array);
    return_index = nlabels;
    eh_index = return_index + tf->may_return;
-  fallthru_index = eh_index + tf->may_throw;
+  fallthru_index = eh_index + (tf->may_throw && !eh_else);
    ndests = fallthru_index + tf->may_fallthru;

    finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
@@ -1319,7 +1394,23 @@ lower_try_finally_switch (struct leh_sta
        gimple_seq_add_stmt (&switch_body, x);
      }

-  if (tf->may_throw)
+  /* For EH_ELSE, emit the exception path (plus resx) now, then
+     subsequently we only need consider the normal path.  */
+  if (eh_else)
+    {
+      if (tf->may_throw)
+	{
+	  finally = gimple_eh_else_e_body (eh_else);
+	  lower_eh_constructs_1 (state, finally);
+
+	  emit_post_landing_pad (&eh_seq, tf->region);
+	  gimple_seq_add_seq (&eh_seq, finally);
+	  emit_resx (&eh_seq, tf->region);
+	}
+
+      finally = gimple_eh_else_n_body (eh_else);
+    }
+  else if (tf->may_throw)
      {
        emit_post_landing_pad (&eh_seq, tf->region);

@@ -1452,12 +1543,22 @@ lower_try_finally_switch (struct leh_sta
     the estimate of the size of the switch machinery we'd have to add.  */

  static bool
-decide_copy_try_finally (int ndests, gimple_seq finally)
+decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
  {
    int f_estimate, sw_estimate;
+  gimple eh_else;
+
+  /* If there's an EH_ELSE involved, the exception path is separate
+     and really doesn't come into play for this computation.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      ndests -= may_throw;
+      finally = gimple_eh_else_n_body (eh_else);
+    }

    if (!optimize)
-    return false;
+    return ndests == 1;

    /* Finally estimate N times, plus N gotos.  */
    f_estimate = count_insns_seq (finally, &eni_size_weights);
@@ -1563,7 +1664,8 @@ lower_try_finally (struct leh_state *sta
    /* We can easily special-case redirection to a single destination.  */
    else if (ndests == 1)
      lower_try_finally_onedest (state, &this_tf);
-  else if (decide_copy_try_finally (ndests, gimple_try_cleanup (tp)))
+  else if (decide_copy_try_finally (ndests, this_tf.may_throw,
+				    gimple_try_cleanup (tp)))
      lower_try_finally_copy (state, &this_tf);
    else
      lower_try_finally_switch (state, &this_tf);
@@ -1928,6 +2030,9 @@ lower_eh_constructs_2 (struct leh_state
  		case GIMPLE_EH_MUST_NOT_THROW:
  		    replace = lower_eh_must_not_throw (state, stmt);
  		    break;
+		case GIMPLE_EH_ELSE:
+		    /* This code is only valid with GIMPLE_TRY_FINALLY.  */
+		    gcc_unreachable ();
  		default:
  		    replace = lower_cleanup (state, stmt);
  		    break;
@@ -1942,6 +2047,10 @@ lower_eh_constructs_2 (struct leh_state
        /* Return since we don't want gsi_next () */
        return;

+    case GIMPLE_EH_ELSE:
+      /* We should be eliminating this in lower_try_finally et al.  */
+      gcc_unreachable ();
+
      default:
        /* A type, a decl, or some kind of statement that we're not
  	 interested in.  Don't walk them.  */
@@ -2832,6 +2941,10 @@ refactor_eh_r (gimple_seq seq)
  	  case GIMPLE_EH_FILTER:
  	    refactor_eh_r (gimple_eh_filter_failure (one));
  	    break;
+	  case GIMPLE_EH_ELSE:
+	    refactor_eh_r (gimple_eh_else_n_body (one));
+	    refactor_eh_r (gimple_eh_else_e_body (one));
+	    break;
  	  default:
  	    break;
  	  }
Index: gcc/gimple-pretty-print.c
===================================================================
--- gcc/gimple-pretty-print.c	(.../trunk)	(revision 180744)
+++ gcc/gimple-pretty-print.c	(.../branches/transactional-memory) 
(revision 180773)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
  #include "tree-pass.h"
  #include "gimple.h"
  #include "value-prof.h"
+#include "trans-mem.h"

  #define INDENT(SPACE)							\
    do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0)
@@ -162,6 +163,7 @@ debug_gimple_seq (gimple_seq seq)
       'd' - outputs an int as a decimal,
       's' - outputs a string,
       'n' - outputs a newline,
+     'x' - outputs an int as hexadecimal,
       '+' - increases indent by 2 then outputs a newline,
       '-' - decreases indent by 2 then outputs a newline.   */

@@ -216,6 +218,10 @@ dump_gimple_fmt (pretty_printer *buffer,
                  newline_and_indent (buffer, spc);
                  break;

+              case 'x':
+                pp_scalar (buffer, "%x", va_arg (args, int));
+                break;
+
                case '+':
                  spc += 2;
                  newline_and_indent (buffer, spc);
@@ -622,6 +628,7 @@ static void
  dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
  {
    tree lhs = gimple_call_lhs (gs);
+  tree fn = gimple_call_fn (gs);

    if (flags & TDF_ALIAS)
      {
@@ -648,8 +655,7 @@ dump_gimple_call (pretty_printer *buffer
  	dump_gimple_fmt (buffer, spc, flags, "%G <%s, %T", gs,
  			 internal_fn_name (gimple_call_internal_fn (gs)), lhs);
        else
-	dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T",
-			 gs, gimple_call_fn (gs), lhs);
+	dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", gs, fn, lhs);
        if (gimple_call_num_args (gs) > 0)
          {
            pp_string (buffer, ", ");
@@ -672,7 +678,7 @@ dump_gimple_call (pretty_printer *buffer
        if (gimple_call_internal_p (gs))
  	pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs)));
        else
-	print_call_name (buffer, gimple_call_fn (gs), flags);
+	print_call_name (buffer, fn, flags);
        pp_string (buffer, " (");
        dump_gimple_call_args (buffer, gs, flags);
        pp_character (buffer, ')');
@@ -689,9 +695,63 @@ dump_gimple_call (pretty_printer *buffer

    if (gimple_call_return_slot_opt_p (gs))
      pp_string (buffer, " [return slot optimization]");
-
    if (gimple_call_tail_p (gs))
      pp_string (buffer, " [tail call]");
+
+  /* Dump the arguments of _ITM_beginTransaction sanely.  */
+  if (TREE_CODE (fn) == ADDR_EXPR)
+    fn = TREE_OPERAND (fn, 0);
+  if (TREE_CODE (fn) == FUNCTION_DECL && DECL_IS_TM_CLONE (fn))
+    pp_string (buffer, " [tm-clone]");
+  if (TREE_CODE (fn) == FUNCTION_DECL
+      && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+      && DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_START
+      /* Check we're referring to Intel's TM specifications.  */
+      && !strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)),
+		  "__builtin__ITM_beginTransaction")
+      && gimple_call_num_args (gs) > 0
+      )
+    {
+      tree t = gimple_call_arg (gs, 0);
+      unsigned HOST_WIDE_INT props;
+      gcc_assert (TREE_CODE (t) == INTEGER_CST);
+
+      pp_string (buffer, " [ ");
+
+      /* Get the transaction code properties.  */
+      props = TREE_INT_CST_LOW (t);
+
+      if (props & PR_INSTRUMENTEDCODE)
+	pp_string (buffer, "instrumentedCode ");
+      if (props & PR_UNINSTRUMENTEDCODE)
+	pp_string (buffer, "uninstrumentedCode ");
+      if (props & PR_HASNOXMMUPDATE)
+	pp_string (buffer, "hasNoXMMUpdate ");
+      if (props & PR_HASNOABORT)
+	pp_string (buffer, "hasNoAbort ");
+      if (props & PR_HASNOIRREVOCABLE)
+	pp_string (buffer, "hasNoIrrevocable ");
+      if (props & PR_DOESGOIRREVOCABLE)
+	pp_string (buffer, "doesGoIrrevocable ");
+      if (props & PR_HASNOSIMPLEREADS)
+	pp_string (buffer, "hasNoSimpleReads ");
+      if (props & PR_AWBARRIERSOMITTED)
+	pp_string (buffer, "awBarriersOmitted ");
+      if (props & PR_RARBARRIERSOMITTED)
+	pp_string (buffer, "RaRBarriersOmitted ");
+      if (props & PR_UNDOLOGCODE)
+	pp_string (buffer, "undoLogCode ");
+      if (props & PR_PREFERUNINSTRUMENTED)
+	pp_string (buffer, "preferUninstrumented ");
+      if (props & PR_EXCEPTIONBLOCK)
+	pp_string (buffer, "exceptionBlock ");
+      if (props & PR_HASELSE)
+	pp_string (buffer, "hasElse ");
+      if (props & PR_READONLY)
+	pp_string (buffer, "readOnly ");
+
+      pp_string (buffer, "]");
+    }
  }


@@ -947,6 +1007,24 @@ dump_gimple_eh_must_not_throw (pretty_pr
  }


+/* Dump a GIMPLE_EH_ELSE tuple on the pretty_printer BUFFER, SPC spaces of
+   indent.  FLAGS specifies details to show in the dump (see TDF_* in
+   tree-pass.h).  */
+
+static void
+dump_gimple_eh_else (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  if (flags & TDF_RAW)
+    dump_gimple_fmt (buffer, spc, flags,
+                     "%G <%+N_BODY <%S>%nE_BODY <%S>%->", gs,
+                     gimple_eh_else_n_body (gs), gimple_eh_else_e_body 
(gs));
+  else
+    dump_gimple_fmt (buffer, spc, flags,
+                    "<<<if_normal_exit>>>%+{%S}%-<<<else_eh_exit>>>%+{%S}",
+                     gimple_eh_else_n_body (gs), gimple_eh_else_e_body 
(gs));
+}
+
+
  /* Dump a GIMPLE_RESX tuple on the pretty_printer BUFFER, SPC spaces of
     indent.  FLAGS specifies details to show in the dump (see TDF_* in
     tree-pass.h).  */
@@ -1269,6 +1347,86 @@ dump_gimple_omp_return (pretty_printer *
      }
  }

+/* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_transaction (pretty_printer *buffer, gimple gs, int spc, 
int flags)
+{
+  unsigned subcode = gimple_transaction_subcode (gs);
+
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags,
+		       "%G [SUBCODE=%x,LABEL=%T] <%+BODY <%S> >",
+		       gs, subcode, gimple_transaction_label (gs),
+		       gimple_transaction_body (gs));
+    }
+  else
+    {
+      if (subcode & GTMA_IS_OUTER)
+	pp_string (buffer, "__transaction_atomic [[outer]]");
+      else if (subcode & GTMA_IS_RELAXED)
+	pp_string (buffer, "__transaction_relaxed");
+      else
+	pp_string (buffer, "__transaction_atomic");
+      subcode &= ~GTMA_DECLARATION_MASK;
+
+      if (subcode || gimple_transaction_label (gs))
+	{
+	  pp_string (buffer, "  //");
+	  if (gimple_transaction_label (gs))
+	    {
+	      pp_string (buffer, " LABEL=");
+	      dump_generic_node (buffer, gimple_transaction_label (gs),
+				 spc, flags, false);
+	    }
+	  if (subcode)
+	    {
+	      pp_string (buffer, " SUBCODE=[ ");
+	      if (subcode & GTMA_HAVE_ABORT)
+		{
+		  pp_string (buffer, "GTMA_HAVE_ABORT ");
+		  subcode &= ~GTMA_HAVE_ABORT;
+		}
+	      if (subcode & GTMA_HAVE_LOAD)
+		{
+		  pp_string (buffer, "GTMA_HAVE_LOAD ");
+		  subcode &= ~GTMA_HAVE_LOAD;
+		}
+	      if (subcode & GTMA_HAVE_STORE)
+		{
+		  pp_string (buffer, "GTMA_HAVE_STORE ");
+		  subcode &= ~GTMA_HAVE_STORE;
+		}
+	      if (subcode & GTMA_MAY_ENTER_IRREVOCABLE)
+		{
+		  pp_string (buffer, "GTMA_MAY_ENTER_IRREVOCABLE ");
+		  subcode &= ~GTMA_MAY_ENTER_IRREVOCABLE;
+		}
+	      if (subcode & GTMA_DOES_GO_IRREVOCABLE)
+		{
+		  pp_string (buffer, "GTMA_DOES_GO_IRREVOCABLE ");
+		  subcode &= ~GTMA_DOES_GO_IRREVOCABLE;
+		}
+	      if (subcode)
+		pp_printf (buffer, "0x%x ", subcode);
+	      pp_string (buffer, "]");
+	    }
+	}
+
+      if (!gimple_seq_empty_p (gimple_transaction_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '{');
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_transaction_body (gs),
+			   spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_character (buffer, '}');
+	}
+    }
+}
+
  /* Dump a GIMPLE_ASM tuple on the pretty_printer BUFFER, SPC spaces of
     indent.  FLAGS specifies details to show in the dump (see TDF_* in
     tree-pass.h).  */
@@ -1855,6 +2013,10 @@ dump_gimple_stmt (pretty_printer *buffer
        dump_gimple_eh_must_not_throw (buffer, gs, spc, flags);
        break;

+    case GIMPLE_EH_ELSE:
+      dump_gimple_eh_else (buffer, gs, spc, flags);
+      break;
+
      case GIMPLE_RESX:
        dump_gimple_resx (buffer, gs, spc, flags);
        break;
@@ -1877,6 +2039,10 @@ dump_gimple_stmt (pretty_printer *buffer
        pp_string (buffer, " predictor.");
        break;

+    case GIMPLE_TRANSACTION:
+      dump_gimple_transaction (buffer, gs, spc, flags);
+      break;
+
      default:
        GIMPLE_NIY;
      }
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(.../trunk)	(revision 180744)
+++ gcc/gimplify.c	(.../branches/transactional-memory)	(revision 180773)
@@ -413,6 +413,8 @@ create_tmp_var_name (const char *prefix)
        char *preftmp = ASTRDUP (prefix);

        remove_suffix (preftmp, strlen (preftmp));
+      clean_symbol_name (preftmp);
+
        prefix = preftmp;
      }

@@ -1072,6 +1074,12 @@ voidify_wrapper_expr (tree wrapper, tree
  		}
  	      break;

+	    case TRANSACTION_EXPR:
+	      TREE_SIDE_EFFECTS (*p) = 1;
+	      TREE_TYPE (*p) = void_type_node;
+	      p = &TRANSACTION_EXPR_BODY (*p);
+	      break;
+
  	    default:
  	      goto out;
  	    }
@@ -6527,6 +6535,53 @@ gimplify_omp_atomic (tree *expr_p, gimpl
     return GS_ALL_DONE;
  }

+/* Gimplify a TRANSACTION_EXPR.  This involves gimplification of the
+   body, and adding some EH bits.  */
+
+static enum gimplify_status
+gimplify_transaction (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p, temp, tbody = TRANSACTION_EXPR_BODY (expr);
+  gimple g;
+  gimple_seq body = NULL;
+  struct gimplify_ctx gctx;
+  int subcode = 0;
+
+  /* Wrap the transaction body in a BIND_EXPR so we have a context
+     where to put decls for OpenMP.  */
+  if (TREE_CODE (tbody) != BIND_EXPR)
+    {
+      tree bind = build3 (BIND_EXPR, void_type_node, NULL, tbody, NULL);
+      TREE_SIDE_EFFECTS (bind) = 1;
+      SET_EXPR_LOCATION (bind, EXPR_LOCATION (tbody));
+      TRANSACTION_EXPR_BODY (expr) = bind;
+    }
+
+  push_gimplify_context (&gctx);
+  temp = voidify_wrapper_expr (*expr_p, NULL);
+
+  g = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body);
+  pop_gimplify_context (g);
+
+  g = gimple_build_transaction (body, NULL);
+  if (TRANSACTION_EXPR_OUTER (expr))
+    subcode = GTMA_IS_OUTER;
+  else if (TRANSACTION_EXPR_RELAXED (expr))
+    subcode = GTMA_IS_RELAXED;
+  gimple_transaction_set_subcode (g, subcode);
+
+  gimplify_seq_add_stmt (pre_p, g);
+
+  if (temp)
+    {
+      *expr_p = temp;
+      return GS_OK;
+    }
+
+  *expr_p = NULL_TREE;
+  return GS_ALL_DONE;
+}
+
  /* Convert the GENERIC expression tree *EXPR_P to GIMPLE.  If the
     expression produces a value to be used as an operand inside a GIMPLE
     statement, the value will be stored back in *EXPR_P.  This value will
@@ -7251,6 +7306,10 @@ gimplify_expr (tree *expr_p, gimple_seq
  	  ret = gimplify_omp_atomic (expr_p, pre_p);
  	  break;

+        case TRANSACTION_EXPR:
+          ret = gimplify_transaction (expr_p, pre_p);
+          break;
+
  	case TRUTH_AND_EXPR:
  	case TRUTH_OR_EXPR:
  	case TRUTH_XOR_EXPR:
Index: gcc/calls.c
===================================================================
--- gcc/calls.c	(.../trunk)	(revision 180744)
+++ gcc/calls.c	(.../branches/transactional-memory)	(revision 180773)
@@ -496,7 +496,60 @@ emit_call_1 (rtx funexp, tree fntree ATT
  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_COMMIT:
+	case BUILT_IN_TM_COMMIT_EH:
+	case BUILT_IN_TM_ABORT:
+	case BUILT_IN_TM_IRREVOCABLE:
+	case BUILT_IN_TM_GETTMCLONE_IRR:
+	case BUILT_IN_TM_MEMCPY:
+	case BUILT_IN_TM_MEMMOVE:
+        case BUILT_IN_TM_MEMSET:
+	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_STORE (LDOUBLE):
+	CASE_BUILT_IN_TM_STORE (M64):
+	CASE_BUILT_IN_TM_STORE (M128):
+	CASE_BUILT_IN_TM_STORE (M256):
+	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):
+	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+	CASE_BUILT_IN_TM_LOAD (M64):
+	CASE_BUILT_IN_TM_LOAD (M128):
+	CASE_BUILT_IN_TM_LOAD (M256):
+	case BUILT_IN_TM_LOG:
+	case BUILT_IN_TM_LOG_1:
+	case BUILT_IN_TM_LOG_2:
+	case BUILT_IN_TM_LOG_4:
+	case BUILT_IN_TM_LOG_8:
+	case BUILT_IN_TM_LOG_FLOAT:
+	case BUILT_IN_TM_LOG_DOUBLE:
+	case BUILT_IN_TM_LOG_LDOUBLE:
+	case BUILT_IN_TM_LOG_M64:
+	case BUILT_IN_TM_LOG_M128:
+	case BUILT_IN_TM_LOG_M256:
+	  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
@@ -644,6 +697,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))
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c	(.../trunk)	(revision 180744)
+++ gcc/tree-inline.c	(.../branches/transactional-memory)	(revision 180773)
@@ -1365,6 +1365,12 @@ remap_gimple_stmt (gimple stmt, copy_bod
  	    = gimple_build_omp_critical (s1, gimple_omp_critical_name (stmt));
  	  break;

+	case GIMPLE_TRANSACTION:
+	  s1 = remap_gimple_seq (gimple_transaction_body (stmt), id);
+	  copy = gimple_build_transaction (s1, gimple_transaction_label (stmt));
+	  gimple_transaction_set_subcode (copy, gimple_transaction_subcode 
(stmt));
+	  break;
+
  	default:
  	  gcc_unreachable ();
  	}
@@ -3600,6 +3606,11 @@ estimate_num_insns (gimple stmt, eni_wei
        return (weights->omp_cost
                + estimate_num_insns_seq (gimple_omp_body (stmt), weights));

+    case GIMPLE_TRANSACTION:
+      return (weights->tm_cost
+	      + estimate_num_insns_seq (gimple_transaction_body (stmt),
+					weights));
+
      default:
        gcc_unreachable ();
      }
@@ -3639,6 +3650,7 @@ init_inline_once (void)
    eni_size_weights.target_builtin_call_cost = 1;
    eni_size_weights.div_mod_cost = 1;
    eni_size_weights.omp_cost = 40;
+  eni_size_weights.tm_cost = 10;
    eni_size_weights.time_based = false;
    eni_size_weights.return_cost = 1;

@@ -3650,6 +3662,7 @@ init_inline_once (void)
    eni_time_weights.target_builtin_call_cost = 1;
    eni_time_weights.div_mod_cost = 10;
    eni_time_weights.omp_cost = 40;
+  eni_time_weights.tm_cost = 40;
    eni_time_weights.time_based = true;
    eni_time_weights.return_cost = 2;
  }
Index: gcc/tree-inline.h
===================================================================
--- gcc/tree-inline.h	(.../trunk)	(revision 180744)
+++ gcc/tree-inline.h	(.../branches/transactional-memory)	(revision 180773)
@@ -144,6 +144,9 @@ typedef struct eni_weights_d
    /* Cost for omp construct.  */
    unsigned omp_cost;

+  /* Cost for tm transaction.  */
+  unsigned tm_cost;
+
    /* Cost of return.  */
    unsigned return_cost;

Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c	(.../trunk)	(revision 180744)
+++ gcc/gimple.c	(.../branches/transactional-memory)	(revision 180773)
@@ -743,6 +743,17 @@ gimple_build_eh_must_not_throw (tree dec
    return p;
  }

+/* Build a GIMPLE_EH_ELSE statement.  */
+
+gimple
+gimple_build_eh_else (gimple_seq n_body, gimple_seq e_body)
+{
+  gimple p = gimple_alloc (GIMPLE_EH_ELSE, 0);
+  gimple_eh_else_set_n_body (p, n_body);
+  gimple_eh_else_set_e_body (p, e_body);
+  return p;
+}
+
  /* Build a GIMPLE_TRY statement.

     EVAL is the expression to evaluate.
@@ -1146,6 +1157,17 @@ gimple_build_omp_atomic_store (tree val)
    return p;
  }

+/* Build a GIMPLE_TRANSACTION statement.  */
+
+gimple
+gimple_build_transaction (gimple_seq body, tree label)
+{
+  gimple p = gimple_alloc (GIMPLE_TRANSACTION, 0);
+  gimple_transaction_set_body (p, body);
+  gimple_transaction_set_label (p, label);
+  return p;
+}
+
  /* Build a GIMPLE_PREDICT statement.  PREDICT is one of the predictors 
from
     predict.def, OUTCOME is NOT_TAKEN or TAKEN.  */

@@ -1331,7 +1353,7 @@ walk_gimple_seq (gimple_seq seq, walk_st
  {
    gimple_stmt_iterator gsi;

-  for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
+  for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
      {
        tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi);
        if (ret)
@@ -1340,8 +1362,12 @@ walk_gimple_seq (gimple_seq seq, walk_st
  	     to hold it.  */
  	  gcc_assert (wi);
  	  wi->callback_result = ret;
-	  return gsi_stmt (gsi);
+
+	  return wi->removed_stmt ? NULL : gsi_stmt (gsi);
  	}
+
+      if (!wi->removed_stmt)
+	gsi_next (&gsi);
      }

    if (wi)
@@ -1680,6 +1706,13 @@ walk_gimple_op (gimple stmt, walk_tree_f
  	return ret;
        break;

+    case GIMPLE_TRANSACTION:
+      ret = walk_tree (gimple_transaction_label_ptr (stmt), callback_op,
+		       wi, pset);
+      if (ret)
+	return ret;
+      break;
+
        /* Tuples that do not have operands.  */
      case GIMPLE_NOP:
      case GIMPLE_RESX:
@@ -1730,10 +1763,13 @@ walk_gimple_stmt (gimple_stmt_iterator *
    gimple stmt = gsi_stmt (*gsi);

    if (wi)
-    wi->gsi = *gsi;
+    {
+      wi->gsi = *gsi;
+      wi->removed_stmt = false;

-  if (wi && wi->want_locations && gimple_has_location (stmt))
-    input_location = gimple_location (stmt);
+      if (wi->want_locations && gimple_has_location (stmt))
+	input_location = gimple_location (stmt);
+    }

    ret = NULL;

@@ -1751,6 +1787,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
        gcc_assert (tree_ret == NULL);

        /* Re-read stmt in case the callback changed it.  */
+      if (wi && wi->removed_stmt)
+	return NULL;
        stmt = gsi_stmt (*gsi);
      }

@@ -1786,6 +1824,17 @@ walk_gimple_stmt (gimple_stmt_iterator *
  	return wi->callback_result;
        break;

+    case GIMPLE_EH_ELSE:
+      ret = walk_gimple_seq (gimple_eh_else_n_body (stmt),
+			     callback_stmt, callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      ret = walk_gimple_seq (gimple_eh_else_e_body (stmt),
+			     callback_stmt, callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
      case GIMPLE_TRY:
        ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt, 
callback_op,
  	                     wi);
@@ -1813,8 +1862,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
      case GIMPLE_OMP_TASK:
      case GIMPLE_OMP_SECTIONS:
      case GIMPLE_OMP_SINGLE:
-      ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt, 
callback_op,
-	                     wi);
+      ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt,
+			     callback_op, wi);
        if (ret)
  	return wi->callback_result;
        break;
@@ -1826,6 +1875,13 @@ walk_gimple_stmt (gimple_stmt_iterator *
  	return wi->callback_result;
        break;

+    case GIMPLE_TRANSACTION:
+      ret = walk_gimple_seq (gimple_transaction_body (stmt),
+			     callback_stmt, callback_op, wi);
+      if (ret)
+	return wi->callback_result;
+      break;
+
      default:
        gcc_assert (!gimple_has_substatements (stmt));
        break;
@@ -2252,6 +2308,13 @@ gimple_copy (gimple stmt)
  	  gimple_eh_filter_set_types (copy, t);
  	  break;

+	case GIMPLE_EH_ELSE:
+	  new_seq = gimple_seq_copy (gimple_eh_else_n_body (stmt));
+	  gimple_eh_else_set_n_body (copy, new_seq);
+	  new_seq = gimple_seq_copy (gimple_eh_else_e_body (stmt));
+	  gimple_eh_else_set_e_body (copy, new_seq);
+	  break;
+
  	case GIMPLE_TRY:
  	  new_seq = gimple_seq_copy (gimple_try_eval (stmt));
  	  gimple_try_set_eval (copy, new_seq);
@@ -2327,6 +2390,11 @@ gimple_copy (gimple stmt)
  	  gimple_omp_set_body (copy, new_seq);
  	  break;

+        case GIMPLE_TRANSACTION:
+	  new_seq = gimple_seq_copy (gimple_transaction_body (stmt));
+	  gimple_transaction_set_body (copy, new_seq);
+	  break;
+
  	case GIMPLE_WITH_CLEANUP_EXPR:
  	  new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt));
  	  gimple_wce_set_cleanup (copy, new_seq);
@@ -2785,7 +2853,7 @@ is_gimple_address (const_tree t)
  /* Strip out all handled components that produce invariant
     offsets.  */

-static const_tree
+const_tree
  strip_invariant_refs (const_tree op)
  {
    while (handled_component_p (op))
@@ -3085,6 +3153,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;
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(.../trunk)	(revision 180744)
+++ gcc/gimple.h	(.../branches/transactional-memory)	(revision 180773)
@@ -105,6 +105,7 @@ enum gf_mask {
      GF_CALL_NOTHROW		= 1 << 5,
      GF_CALL_ALLOCA_FOR_VAR	= 1 << 6,
      GF_CALL_INTERNAL		= 1 << 7,
+    GF_CALL_NOINLINE		= 1 << 8,
      GF_OMP_PARALLEL_COMBINED	= 1 << 0,

      /* True on an GIMPLE_OMP_RETURN statement if the return does not 
require
@@ -487,6 +488,15 @@ struct GTY(()) gimple_statement_eh_filte
    gimple_seq failure;
  };

+/* GIMPLE_EH_ELSE */
+
+struct GTY(()) gimple_statement_eh_else {
+  /* [ WORD 1-4 ]  */
+  struct gimple_statement_base gsbase;
+
+  /* [ WORD 5,6 ] */
+  gimple_seq n_body, e_body;
+};

  /* GIMPLE_EH_MUST_NOT_THROW */

@@ -757,6 +767,43 @@ struct GTY(()) gimple_statement_omp_atom
    tree val;
  };

+/* GIMPLE_TRANSACTION.  */
+
+/* Bits to be stored in the GIMPLE_TRANSACTION subcode.  */
+
+/* The __transaction_atomic was declared [[outer]] or it is
+   __transaction_relaxed.  */
+#define GTMA_IS_OUTER			(1u << 0)
+#define GTMA_IS_RELAXED			(1u << 1)
+#define GTMA_DECLARATION_MASK		(GTMA_IS_OUTER | GTMA_IS_RELAXED)
+
+/* The transaction is seen to not have an abort.  */
+#define GTMA_HAVE_ABORT			(1u << 2)
+/* The transaction is seen to have loads or stores.  */
+#define GTMA_HAVE_LOAD			(1u << 3)
+#define GTMA_HAVE_STORE			(1u << 4)
+/* The transaction MAY enter serial irrevocable mode in its dynamic 
scope.  */
+#define GTMA_MAY_ENTER_IRREVOCABLE	(1u << 5)
+/* The transaction WILL enter serial 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_DOES_GO_IRREVOCABLE	(1u << 6)
+
+struct GTY(()) gimple_statement_transaction
+{
+  /* [ WORD 1-10 ]  */
+  struct gimple_statement_with_memory_ops_base gsbase;
+
+  /* [ WORD 11 ] */
+  gimple_seq body;
+
+  /* [ WORD 12 ] */
+  tree label;
+};
+
  #define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP)	SYM,
  enum gimple_statement_structure_enum {
  #include "gsstruct.def"
@@ -779,6 +826,7 @@ union GTY ((desc ("gimple_statement_stru
    struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
    struct gimple_statement_eh_filter GTY ((tag ("GSS_EH_FILTER"))) 
gimple_eh_filter;
    struct gimple_statement_eh_mnt GTY ((tag ("GSS_EH_MNT"))) gimple_eh_mnt;
+  struct gimple_statement_eh_else GTY ((tag ("GSS_EH_ELSE"))) 
gimple_eh_else;
    struct gimple_statement_phi GTY ((tag ("GSS_PHI"))) gimple_phi;
    struct gimple_statement_eh_ctrl GTY ((tag ("GSS_EH_CTRL"))) 
gimple_eh_ctrl;
    struct gimple_statement_try GTY ((tag ("GSS_TRY"))) gimple_try;
@@ -793,6 +841,7 @@ union GTY ((desc ("gimple_statement_stru
    struct gimple_statement_omp_continue GTY ((tag 
("GSS_OMP_CONTINUE"))) gimple_omp_continue;
    struct gimple_statement_omp_atomic_load GTY ((tag 
("GSS_OMP_ATOMIC_LOAD"))) gimple_omp_atomic_load;
    struct gimple_statement_omp_atomic_store GTY ((tag 
("GSS_OMP_ATOMIC_STORE"))) gimple_omp_atomic_store;
+  struct gimple_statement_transaction GTY((tag ("GSS_TRANSACTION"))) 
gimple_transaction;
  };

  /* In gimple.c.  */
@@ -846,6 +895,7 @@ gimple gimple_build_asm_vec (const char
  gimple gimple_build_catch (tree, gimple_seq);
  gimple gimple_build_eh_filter (tree, gimple_seq);
  gimple gimple_build_eh_must_not_throw (tree);
+gimple gimple_build_eh_else (gimple_seq, gimple_seq);
  gimple gimple_build_try (gimple_seq, gimple_seq, enum gimple_try_flags);
  gimple gimple_build_wce (gimple_seq);
  gimple gimple_build_resx (int);
@@ -868,6 +918,7 @@ gimple gimple_build_omp_single (gimple_s
  gimple gimple_build_cdt (tree, tree);
  gimple gimple_build_omp_atomic_load (tree, tree);
  gimple gimple_build_omp_atomic_store (tree);
+gimple gimple_build_transaction (gimple_seq, tree);
  gimple gimple_build_predict (enum br_predictor, enum prediction);
  enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
  void sort_case_labels (VEC(tree,heap) *);
@@ -986,6 +1037,7 @@ extern bool walk_stmt_load_store_ops (gi
  				      bool (*)(gimple, tree, void *),
  				      bool (*)(gimple, tree, void *));
  extern bool gimple_ior_addresses_taken (bitmap, gimple);
+extern const_tree strip_invariant_refs (const_tree);
  extern bool gimple_call_builtin_p (gimple, enum built_in_function);
  extern bool gimple_asm_clobbers_memory_p (const_gimple);

@@ -1077,6 +1129,9 @@ extern tree canonicalize_cond_expr_cond
  /* In omp-low.c.  */
  extern tree omp_reduction_init (tree, tree);

+/* In trans-mem.c.  */
+extern void diagnose_tm_safe_errors (tree);
+
  /* In tree-nested.c.  */
  extern void lower_nested_functions (tree);
  extern void insert_field_into_struct (tree, tree);
@@ -1135,6 +1190,7 @@ gimple_has_substatements (gimple g)
      case GIMPLE_BIND:
      case GIMPLE_CATCH:
      case GIMPLE_EH_FILTER:
+    case GIMPLE_EH_ELSE:
      case GIMPLE_TRY:
      case GIMPLE_OMP_FOR:
      case GIMPLE_OMP_MASTER:
@@ -1146,6 +1202,7 @@ gimple_has_substatements (gimple g)
      case GIMPLE_OMP_SINGLE:
      case GIMPLE_OMP_CRITICAL:
      case GIMPLE_WITH_CLEANUP_EXPR:
+    case GIMPLE_TRANSACTION:
        return true;

      default:
@@ -2436,6 +2493,22 @@ gimple_call_alloca_for_var_p (gimple s)
    return (s->gsbase.subcode & GF_CALL_ALLOCA_FOR_VAR) != 0;
  }

+/* Return true if S is a noinline call.  */
+
+static inline bool
+gimple_call_noinline_p (gimple s)
+{
+  GIMPLE_CHECK (s, GIMPLE_CALL);
+  return (s->gsbase.subcode & GF_CALL_NOINLINE) != 0;
+}
+
+static inline void
+gimple_call_set_noinline_p (gimple s)
+{
+  GIMPLE_CHECK (s, GIMPLE_CALL);
+  s->gsbase.subcode |= GF_CALL_NOINLINE;
+}
+
  /* Copy all the GF_CALL_* flags from ORIG_CALL to DEST_CALL.  */

  static inline void
@@ -3178,6 +3251,35 @@ gimple_eh_must_not_throw_set_fndecl (gim
    gs->gimple_eh_mnt.fndecl = decl;
  }

+/* GIMPLE_EH_ELSE accessors.  */
+
+static inline gimple_seq
+gimple_eh_else_n_body (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
+  return gs->gimple_eh_else.n_body;
+}
+
+static inline gimple_seq
+gimple_eh_else_e_body (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
+  return gs->gimple_eh_else.e_body;
+}
+
+static inline void
+gimple_eh_else_set_n_body (gimple gs, gimple_seq seq)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
+  gs->gimple_eh_else.n_body = seq;
+}
+
+static inline void
+gimple_eh_else_set_e_body (gimple gs, gimple_seq seq)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
+  gs->gimple_eh_else.e_body = seq;
+}

  /* GIMPLE_TRY accessors. */

@@ -4556,6 +4658,67 @@ gimple_omp_continue_set_control_use (gim
    g->gimple_omp_continue.control_use = use;
  }

+/* Return the body for the GIMPLE_TRANSACTION statement GS.  */
+
+static inline gimple_seq
+gimple_transaction_body (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  return gs->gimple_transaction.body;
+}
+
+/* Return the label associated with a GIMPLE_TRANSACTION.  */
+
+static inline tree
+gimple_transaction_label (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  return gs->gimple_transaction.label;
+}
+
+static inline tree *
+gimple_transaction_label_ptr (gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  return &gs->gimple_transaction.label;
+}
+
+/* Return the subcode associated with a GIMPLE_TRANSACTION.  */
+
+static inline unsigned int
+gimple_transaction_subcode (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  return gs->gsbase.subcode;
+}
+
+/* Set BODY to be the body for the GIMPLE_TRANSACTION statement GS.  */
+
+static inline void
+gimple_transaction_set_body (gimple gs, gimple_seq body)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  gs->gimple_transaction.body = body;
+}
+
+/* Set the label associated with a GIMPLE_TRANSACTION.  */
+
+static inline void
+gimple_transaction_set_label (gimple gs, tree label)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  gs->gimple_transaction.label = label;
+}
+
+/* Set the subcode associated with a GIMPLE_TRANSACTION.  */
+
+static inline void
+gimple_transaction_set_subcode (gimple gs, unsigned int subcode)
+{
+  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
+  gs->gsbase.subcode = subcode;
+}
+

  /* Return a pointer to the return value for GIMPLE_RETURN GS.  */

@@ -4982,6 +5145,12 @@ struct walk_stmt_info
       will be visited more than once.  */
    struct pointer_set_t *pset;

+  /* Operand returned by the callbacks.  This is set when calling
+     walk_gimple_seq.  If the walk_stmt_fn or walk_tree_fn callback
+     returns non-NULL, this field will contain the tree returned by
+     the last callback.  */
+  tree callback_result;
+
    /* Indicates whether the operand being examined may be replaced
       with something that matches is_gimple_val (if true) or something
       slightly more complicated (if false).  "Something" technically
@@ -4994,23 +5163,20 @@ struct walk_stmt_info
       statement 'foo (&var)', the flag VAL_ONLY will initially be set
       to true, however, when walking &var, the operand of that
       ADDR_EXPR does not need to be a GIMPLE value.  */
-  bool val_only;
+  BOOL_BITFIELD val_only : 1;

    /* True if we are currently walking the LHS of an assignment.  */
-  bool is_lhs;
+  BOOL_BITFIELD is_lhs : 1;

    /* Optional.  Set to true by the callback functions if they made any
       changes.  */
-  bool changed;
+  BOOL_BITFIELD changed : 1;

    /* True if we're interested in location information.  */
-  bool want_locations;
+  BOOL_BITFIELD want_locations : 1;

-  /* Operand returned by the callbacks.  This is set when calling
-     walk_gimple_seq.  If the walk_stmt_fn or walk_tree_fn callback
-     returns non-NULL, this field will contain the tree returned by
-     the last callback.  */
-  tree callback_result;
+  /* True if we've removed the statement that was processed.  */
+  BOOL_BITFIELD removed_stmt : 1;
  };

  /* Callback for walk_gimple_stmt.  Called for every statement found

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-03 19:40 [patch] 19/n: trans-mem: compiler tree/gimple stuff Aldy Hernandez
@ 2011-11-04 10:44 ` Richard Guenther
  2011-11-05  0:25   ` Aldy Hernandez
                     ` (3 more replies)
  2011-11-04 15:40 ` Michael Matz
  1 sibling, 4 replies; 22+ messages in thread
From: Richard Guenther @ 2011-11-04 10:44 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches

On Thu, Nov 3, 2011 at 8:26 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> These are misc tree and gimple patches, which I consider front-ish-end
> changes.
>
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c  (.../trunk)     (revision 180744)
> +++ gcc/tree.c  (.../branches/transactional-memory)     (revision 180773)
> @@ -9594,6 +9594,9 @@ build_common_builtin_nodes (void)
>                                    integer_type_node, NULL_TREE);
>   local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
>                        "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW |
> ECF_LEAF);
> +  if (flag_tm)
> +    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
> +                  get_identifier ("transaction_pure"));

I think this should use a new ECF_TM_PURE flag, unconditionally set
with handling in the functions that handle/return ECF flags so that
transitioning this to a tree node flag instead of an attribute is easier.

>   tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (),
> 0);
>   ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h  (.../trunk)     (revision 180744)
> +++ gcc/tree.h  (.../branches/transactional-memory)     (revision 180773)
> @@ -539,6 +539,9 @@ struct GTY(()) tree_common {
>        ENUM_IS_SCOPED in
>           ENUMERAL_TYPE
>
> +       TRANSACTION_EXPR_OUTER in
> +           TRANSACTION_EXPR
> +
>    public_flag:
>
>        TREE_OVERFLOW in
> @@ -566,6 +569,9 @@ struct GTY(()) tree_common {
>        OMP_CLAUSE_PRIVATE_DEBUG in
>            OMP_CLAUSE_PRIVATE
>
> +       TRANSACTION_EXPR_RELAXED in
> +           TRANSACTION_EXPR
> +
>    private_flag:
>
>        TREE_PRIVATE in
> @@ -1808,6 +1814,14 @@ extern void protected_set_expr_location
>  #define CALL_EXPR_ARGP(NODE) \
>   (&(TREE_OPERAND (CALL_EXPR_CHECK (NODE), 0)) + 3)
>
> +/* TM directives and accessors.  */
> +#define TRANSACTION_EXPR_BODY(NODE) \
> +  TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 0)
> +#define TRANSACTION_EXPR_OUTER(NODE) \
> +  (TRANSACTION_EXPR_CHECK (NODE)->base.static_flag)
> +#define TRANSACTION_EXPR_RELAXED(NODE) \
> +  (TRANSACTION_EXPR_CHECK (NODE)->base.public_flag)
> +
>  /* OpenMP directive and clause accessors.  */
>
>  #define OMP_BODY(NODE) \
> @@ -3452,6 +3466,34 @@ struct GTY(())
>  #define DECL_NO_INLINE_WARNING_P(NODE) \
>   (FUNCTION_DECL_CHECK (NODE)->function_decl.no_inline_warning_flag)
>
> +/* Nonzero in a FUNCTION_DECL means this function is the transactional
> +   clone of a function - called only from inside transactions.  */
> +#define DECL_IS_TM_CLONE(NODE) \
> +  (FUNCTION_DECL_CHECK (NODE)->function_decl.tm_clone_flag)

Why is it necessary to know whether a clone is a tm clone?

> +/* Nonzero if a FUNCTION_CODE is a TM load/store.  */
> +#define BUILTIN_TM_LOAD_STORE_P(FN) \
> +  ((FN) >= BUILT_IN_TM_STORE_1 && (FN) <= BUILT_IN_TM_LOAD_RFW_LDOUBLE)
> +
> +/* Nonzero if a FUNCTION_CODE is a TM load.  */
> +#define BUILTIN_TM_LOAD_P(FN) \
> +  ((FN) >= BUILT_IN_TM_LOAD_1 && (FN) <= BUILT_IN_TM_LOAD_RFW_LDOUBLE)
> +
> +/* Nonzero if a FUNCTION_CODE is a TM store.  */
> +#define BUILTIN_TM_STORE_P(FN) \
> +  ((FN) >= BUILT_IN_TM_STORE_1 && (FN) <= BUILT_IN_TM_STORE_WAW_LDOUBLE)
> +
> +#define CASE_BUILT_IN_TM_LOAD(FN)      \
> +  case BUILT_IN_TM_LOAD_##FN:          \
> +  case BUILT_IN_TM_LOAD_RAR_##FN:      \
> +  case BUILT_IN_TM_LOAD_RAW_##FN:      \
> +  case BUILT_IN_TM_LOAD_RFW_##FN
> +
> +#define CASE_BUILT_IN_TM_STORE(FN)     \
> +  case BUILT_IN_TM_STORE_##FN:         \
> +  case BUILT_IN_TM_STORE_WAR_##FN:     \
> +  case BUILT_IN_TM_STORE_WAW_##FN
> +
>  /* Nonzero in a FUNCTION_DECL that should be always inlined by the inliner
>    disregarding size and cost heuristics.  This is equivalent to using
>    the always_inline attribute without the required diagnostics if the
> @@ -3539,8 +3581,9 @@ struct GTY(()) tree_function_decl {
>   unsigned pure_flag : 1;
>   unsigned looping_const_or_pure_flag : 1;
>   unsigned has_debug_args_flag : 1;
> +  unsigned tm_clone_flag : 1;
>
> -  /* 2 bits left */
> +  /* 1 bit left */
>  };
>
>  /* The source language of the translation-unit.  */
> @@ -5174,6 +5217,8 @@ extern void expand_return (tree);
>
>  /* In tree-eh.c */
>  extern void using_eh_for_cleanups (void);
> +extern int struct_ptr_eq (const void *, const void *);
> +extern hashval_t struct_ptr_hash (const void *);
>
>  /* In fold-const.c */
>
> @@ -5543,6 +5588,8 @@ extern tree build_duplicate_type (tree);
>  #define ECF_NOVOPS               (1 << 9)
>  /* The function does not lead to calls within current function unit.  */
>  #define ECF_LEAF                 (1 << 10)
> +/* Nonzero if this call performs a transactional memory operation.  */
> +#define ECF_TM_OPS               (1 << 11)

What's this flag useful for?  Isn't it the case that you want to conservatively
know whether a call might perform a tm operation?  Thus, the flag
should be inverted?  Is this the same as "TM pure"?

>  extern int flags_from_decl_or_type (const_tree);
>  extern int call_expr_flags (const_tree);
> @@ -5593,6 +5640,8 @@ extern void init_attributes (void);
>    a decl attribute to the declaration rather than to its type).  */
>  extern tree decl_attributes (tree *, tree, int);
>
> +extern void apply_tm_attr (tree, tree);
> +
>  /* In integrate.c */
>  extern void set_decl_abstract_flags (tree, int);
>  extern void set_decl_origin_self (tree);
> @@ -5805,6 +5854,21 @@ extern unsigned HOST_WIDE_INT compute_bu
>  extern unsigned HOST_WIDE_INT highest_pow2_factor (const_tree);
>  extern tree build_personality_function (const char *);
>
> +/* In trans-mem.c.  */
> +extern tree build_tm_abort_call (location_t, bool);
> +extern bool is_tm_safe (const_tree);
> +extern bool is_tm_pure (const_tree);
> +extern bool is_tm_may_cancel_outer (tree);
> +extern bool is_tm_ending_fndecl (tree);
> +extern void record_tm_replacement (tree, tree);
> +extern void tm_malloc_replacement (tree);
> +
> +static inline bool
> +is_tm_safe_or_pure (tree x)

const_tree

> +{
> +  return is_tm_safe (x) || is_tm_pure (x);
> +}
> +
>  /* In tree-inline.c.  */
>
>  void init_inline_once (void);
> Index: gcc/attribs.c
> ===================================================================
> --- gcc/attribs.c       (.../trunk)     (revision 180744)
> +++ gcc/attribs.c       (.../branches/transactional-memory)     (revision
> 180773)
> @@ -166,7 +166,8 @@ init_attributes (void)
>          gcc_assert (strcmp (attribute_tables[i][j].name,
>                              attribute_tables[i][k].name));
>     }
> -  /* Check that no name occurs in more than one table.  */
> +  /* Check that no name occurs in more than one table.  Names that
> +     begin with '*' are exempt, and may be overridden.  */
>   for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
>     {
>       size_t j, k, l;
> @@ -174,8 +175,9 @@ init_attributes (void)
>       for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
>        for (k = 0; attribute_tables[i][k].name != NULL; k++)
>          for (l = 0; attribute_tables[j][l].name != NULL; l++)
> -           gcc_assert (strcmp (attribute_tables[i][k].name,
> -                               attribute_tables[j][l].name));
> +           gcc_assert (attribute_tables[i][k].name[0] == '*'
> +                       || strcmp (attribute_tables[i][k].name,
> +                                  attribute_tables[j][l].name));
>     }
>  #endif
>
> @@ -207,7 +209,7 @@ register_attribute (const struct attribu
>   slot = htab_find_slot_with_hash (attribute_hash, &str,
>                                   substring_hash (str.str, str.length),
>                                   INSERT);
> -  gcc_assert (!*slot);
> +  gcc_assert (!*slot || attr->name[0] == '*');
>   *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
>  }

The above changes seem to belong to a different changeset and look
strange.  Why would attributes ever appear in two different tables?

> @@ -484,3 +486,12 @@ decl_attributes (tree *node, tree attrib
>
>   return returned_attrs;
>  }
> +
> +/* Subroutine of set_method_tm_attributes.  Apply TM attribute ATTR
> +   to the method FNDECL.  */
> +
> +void
> +apply_tm_attr (tree fndecl, tree attr)
> +{
> +  decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
> +}
> Index: gcc/targhooks.c
> ===================================================================
> --- gcc/targhooks.c     (.../trunk)     (revision 180744)
> +++ gcc/targhooks.c     (.../branches/transactional-memory)     (revision
> 180773)
> @@ -1214,6 +1214,12 @@ default_have_conditional_execution (void
>  #endif
>  }
>
> +tree
> +default_builtin_tm_load_store (tree ARG_UNUSED (type))
> +{
> +  return NULL_TREE;
> +}
> +
>  /* Compute cost of moving registers to/from memory.  */
>
>  int
> Index: gcc/targhooks.h
> ===================================================================
> --- gcc/targhooks.h     (.../trunk)     (revision 180744)
> +++ gcc/targhooks.h     (.../branches/transactional-memory)     (revision
> 180773)
> @@ -152,6 +152,9 @@ extern bool default_addr_space_subset_p
>  extern rtx default_addr_space_convert (rtx, tree, tree);
>  extern unsigned int default_case_values_threshold (void);
>  extern bool default_have_conditional_execution (void);
> +
> +extern tree default_builtin_tm_load_store (tree);
> +
>  extern int default_memory_move_cost (enum machine_mode, reg_class_t, bool);
>  extern int default_register_move_cost (enum machine_mode, reg_class_t,
>                                       reg_class_t);
> Index: gcc/gimple.def
> ===================================================================
> --- gcc/gimple.def      (.../trunk)     (revision 180744)
> +++ gcc/gimple.def      (.../branches/transactional-memory)     (revision
> 180773)
> @@ -124,6 +124,14 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_
>     CHAIN is the optional static chain link for nested functions.  */
>  DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_CALL)
>
> +/* GIMPLE_TRANSACTION <BODY, LABEL> represents __transaction_atomic and
> +   __transaction_relaxed 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_TRANSACTION, "gimple_transaction", GSS_TRANSACTION)
> +
>  /* GIMPLE_RETURN <RETVAL> represents return statements.
>
>    RETVAL is the value to return or NULL.  If a value is returned it
> @@ -151,6 +159,12 @@ DEFGSCODE(GIMPLE_EH_FILTER, "gimple_eh_f
>    be invoked if an exception propagates to this point.  */
>  DEFGSCODE(GIMPLE_EH_MUST_NOT_THROW, "gimple_eh_must_not_throw", GSS_EH_MNT)
>
> +/* GIMPLE_EH_ELSE <N_BODY, E_BODY> must be the sole contents of
> +   a GIMPLE_TRY_FINALLY node.  For all normal exits from the try block,
> +   we N_BODY is run; for all exception exits from the try block,
> +   E_BODY is run.  */
> +DEFGSCODE(GIMPLE_EH_ELSE, "gimple_eh_else", GSS_EH_ELSE)
> +
>  /* GIMPLE_RESX resumes execution after an exception.  */
>  DEFGSCODE(GIMPLE_RESX, "gimple_resx", GSS_EH_CTRL)
>
> Index: gcc/builtin-types.def
> ===================================================================
> --- gcc/builtin-types.def       (.../trunk)     (revision 180744)
> +++ gcc/builtin-types.def       (.../branches/transactional-memory)
> (revision 180773)
> @@ -477,3 +477,24 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_I
>  DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
>  DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
>                     BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
> +
> +
> +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_1 (BT_FN_LDOUBLE_VPTR, BT_LONGDOUBLE, BT_VOLATILE_PTR)
> +
> +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)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_LDOUBLE, BT_VOID,
> +                    BT_VOLATILE_PTR, BT_LONGDOUBLE)
> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_SIZE, BT_VOID,
> +                    BT_VOLATILE_PTR, BT_SIZE)
> Index: gcc/builtins.def
> ===================================================================
> --- gcc/builtins.def    (.../trunk)     (revision 180744)
> +++ gcc/builtins.def    (.../branches/transactional-memory)     (revision
> 180773)
> @@ -142,6 +142,13 @@ along with GCC; see the file COPYING3.
>                false, true, true, ATTRS, false, \
>               (flag_openmp || flag_tree_parallelize_loops))
>
> +/* Builtin used by the implementation of GNU TM.  These
> +   functions are mapped to the actual implementation of the STM library. */
> +#undef DEF_TM_BUILTIN
> +#define DEF_TM_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
> +  DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
> +               false, true, true, ATTRS, false, flag_tm)
> +
>  /* Define an attribute list for math functions that are normally
>    "impure" because some of them may write into global memory for
>    `errno'.  If !flag_errno_math they are instead "const".  */
> @@ -624,6 +631,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_APPLY_A
>  DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32,
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64,
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_CACHE, "__clear_cache",
> BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
> +/* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed.
>  */
>  DEF_LIB_BUILTIN        (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE,
> ATTR_MALLOC_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLASSIFY_TYPE, "classify_type",
> BT_FN_INT_VAR, ATTR_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT,
> ATTR_CONST_NOTHROW_LEAF_LIST)
> @@ -662,6 +670,7 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSL, "
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG,
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_EXT_LIB_BUILTIN        (BUILT_IN_FORK, "fork", BT_FN_PID,
> ATTR_NOTHROW_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FRAME_ADDRESS, "frame_address",
> BT_FN_PTR_UINT, ATTR_NULL)
> +/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed.  */
>  DEF_LIB_BUILTIN        (BUILT_IN_FREE, "free", BT_FN_VOID_PTR,
> ATTR_NOTHROW_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr",
> BT_FN_PTR_PTR, ATTR_NULL)
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_GETTEXT, "gettext",
> BT_FN_STRING_CONST_STRING, ATTR_FORMAT_ARG_1)
> @@ -698,6 +707,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_ISUNORD
>  DEF_LIB_BUILTIN        (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG,
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG,
> ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT,
> ATTR_NORETURN_NOTHROW_LEAF_LIST)
> +/* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed.
>  */
>  DEF_LIB_BUILTIN        (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE,
> ATTR_MALLOC_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR,
> ATTR_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_PARITY, "parity", BT_FN_INT_UINT,
> ATTR_CONST_NOTHROW_LEAF_LIST)
> @@ -793,3 +803,6 @@ DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUE
>
>  /* OpenMP builtins.  */
>  #include "omp-builtins.def"
> +
> +/* GTM builtins. */
> +#include "gtm-builtins.def"
> Index: gcc/gimple-low.c
> ===================================================================
> --- gcc/gimple-low.c    (.../trunk)     (revision 180744)
> +++ gcc/gimple-low.c    (.../branches/transactional-memory)     (revision
> 180773)
> @@ -396,6 +396,11 @@ lower_stmt (gimple_stmt_iterator *gsi, s
>       lower_sequence (gimple_eh_filter_failure (stmt), data);
>       break;
>
> +    case GIMPLE_EH_ELSE:
> +      lower_sequence (gimple_eh_else_n_body (stmt), data);
> +      lower_sequence (gimple_eh_else_e_body (stmt), data);
> +      break;
> +
>     case GIMPLE_NOP:
>     case GIMPLE_ASM:
>     case GIMPLE_ASSIGN:
> @@ -446,6 +451,10 @@ lower_stmt (gimple_stmt_iterator *gsi, s
>       data->cannot_fallthru = false;
>       return;
>
> +    case GIMPLE_TRANSACTION:
> +      lower_sequence (gimple_transaction_body (stmt), data);
> +      break;
> +
>     default:
>       gcc_unreachable ();
>     }
> @@ -727,6 +736,10 @@ gimple_stmt_may_fallthru (gimple stmt)
>       return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
>              && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
>
> +    case GIMPLE_EH_ELSE:
> +      return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
> +             || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));
> +
>     case GIMPLE_CALL:
>       /* Functions that do not return do not fall through.  */
>       return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
> Index: gcc/gsstruct.def
> ===================================================================
> --- gcc/gsstruct.def    (.../trunk)     (revision 180744)
> +++ gcc/gsstruct.def    (.../branches/transactional-memory)     (revision
> 180773)
> @@ -38,6 +38,7 @@ DEFGSSTRUCT(GSS_CATCH, gimple_statement_
>  DEFGSSTRUCT(GSS_EH_FILTER, gimple_statement_eh_filter, false)
>  DEFGSSTRUCT(GSS_EH_MNT, gimple_statement_eh_mnt, false)
>  DEFGSSTRUCT(GSS_EH_CTRL, gimple_statement_eh_ctrl, false)
> +DEFGSSTRUCT(GSS_EH_ELSE, gimple_statement_eh_else, false)
>  DEFGSSTRUCT(GSS_WCE, gimple_statement_wce, false)
>  DEFGSSTRUCT(GSS_OMP, gimple_statement_omp, false)
>  DEFGSSTRUCT(GSS_OMP_CRITICAL, gimple_statement_omp_critical, false)
> @@ -49,3 +50,4 @@ DEFGSSTRUCT(GSS_OMP_SINGLE, gimple_state
>  DEFGSSTRUCT(GSS_OMP_CONTINUE, gimple_statement_omp_continue, false)
>  DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gimple_statement_omp_atomic_load, false)
>  DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE, gimple_statement_omp_atomic_store, false)
> +DEFGSSTRUCT(GSS_TRANSACTION, gimple_statement_transaction, false)
> Index: gcc/tree-eh.c
> ===================================================================
> --- gcc/tree-eh.c       (.../trunk)     (revision 180744)
> +++ gcc/tree-eh.c       (.../branches/transactional-memory)     (revision
> 180773)
> @@ -58,7 +58,7 @@ using_eh_for_cleanups (void)
>    pointer.  Assumes all pointers are interchangeable, which is sort
>    of already assumed by gcc elsewhere IIRC.  */
>
> -static int
> +int
>  struct_ptr_eq (const void *a, const void *b)
>  {
>   const void * const * x = (const void * const *) a;
> @@ -66,7 +66,7 @@ struct_ptr_eq (const void *a, const void
>   return *x == *y;
>  }
>
> -static hashval_t
> +hashval_t
>  struct_ptr_hash (const void *a)
>  {
>   const void * const * x = (const void * const *) a;

Rather than exporting those here consider moving them to a common
header as inline functions.

  const void * const * x = (const void * const *) a;
  return (size_t)*x >> 4;

and on the way change that to (intptr_t)*x >> 4

> @@ -284,6 +284,11 @@ collect_finally_tree (gimple stmt, gimpl
>       collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
>       break;
>
> +    case GIMPLE_EH_ELSE:
> +      collect_finally_tree_1 (gimple_eh_else_n_body (stmt), region);
> +      collect_finally_tree_1 (gimple_eh_else_e_body (stmt), region);
> +      break;
> +
>     default:
>       /* A type, a decl, or some kind of statement that we're not
>         interested in.  Don't walk them.  */
> @@ -534,6 +539,10 @@ replace_goto_queue_1 (gimple stmt, struc
>     case GIMPLE_EH_FILTER:
>       replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf);
>       break;
> +    case GIMPLE_EH_ELSE:
> +      replace_goto_queue_stmt_list (gimple_eh_else_n_body (stmt), tf);
> +      replace_goto_queue_stmt_list (gimple_eh_else_e_body (stmt), tf);
> +      break;
>
>     default:
>       /* These won't have gotos in them.  */
> @@ -921,6 +930,21 @@ lower_try_finally_fallthru_label (struct
>   return label;
>  }
>
> +/* A subroutine of lower_try_finally.  If FINALLY consits of a
> +   GIMPLE_EH_ELSE node, return it.  */
> +
> +static inline gimple
> +get_eh_else (gimple_seq finally)
> +{
> +  gimple x = gimple_seq_first_stmt (finally);
> +  if (gimple_code (x) == GIMPLE_EH_ELSE)
> +    {
> +      gcc_assert (gimple_seq_singleton_p (finally));
> +      return x;
> +    }
> +  return NULL;
> +}
> +
>  /* A subroutine of lower_try_finally.  If the eh_protect_cleanup_actions
>    langhook returns non-null, then the language requires that the exception
>    path out of a try_finally be treated specially.  To wit: the code within
> @@ -950,7 +974,7 @@ honor_protect_cleanup_actions (struct le
>   gimple_stmt_iterator gsi;
>   bool finally_may_fallthru;
>   gimple_seq finally;
> -  gimple x;
> +  gimple x, eh_else;
>
>   /* First check for nothing to do.  */
>   if (lang_hooks.eh_protect_cleanup_actions == NULL)
> @@ -960,12 +984,18 @@ honor_protect_cleanup_actions (struct le
>     return;
>
>   finally = gimple_try_cleanup (tf->top_p);
> -  finally_may_fallthru = gimple_seq_may_fallthru (finally);
> +  eh_else = get_eh_else (finally);
>
>   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
> -     and not for cleanups.  */
> -  if (this_state)
> +     and not for cleanups.  If we've got an EH_ELSE, extract it now.  */
> +  if (eh_else)
> +    {
> +      finally = gimple_eh_else_e_body (eh_else);
> +      gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
> +    }
> +  else if (this_state)
>     finally = lower_try_finally_dup_block (finally, outer_state);
> +  finally_may_fallthru = gimple_seq_may_fallthru (finally);
>
>   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
>      set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
> @@ -1011,7 +1041,7 @@ lower_try_finally_nofallthru (struct leh
>                              struct leh_tf_state *tf)
>  {
>   tree lab;
> -  gimple x;
> +  gimple x, eh_else;
>   gimple_seq finally;
>   struct goto_queue_node *q, *qe;
>
> @@ -1034,15 +1064,35 @@ lower_try_finally_nofallthru (struct leh
>
>   replace_goto_queue (tf);
>
> -  lower_eh_constructs_1 (state, finally);
> -  gimple_seq_add_seq (&tf->top_p_seq, finally);
> +  /* Emit the finally block into the stream.  Lower EH_ELSE at this time.
>  */
> +  eh_else = get_eh_else (finally);
> +  if (eh_else)
> +    {
> +      finally = gimple_eh_else_n_body (eh_else);
> +      lower_eh_constructs_1 (state, finally);
> +      gimple_seq_add_seq (&tf->top_p_seq, finally);
>
> -  if (tf->may_throw)
> +      if (tf->may_throw)
> +       {
> +         finally = gimple_eh_else_e_body (eh_else);
> +         lower_eh_constructs_1 (state, finally);
> +
> +         emit_post_landing_pad (&eh_seq, tf->region);
> +         gimple_seq_add_seq (&eh_seq, finally);
> +       }
> +    }
> +  else
>     {
> -      emit_post_landing_pad (&eh_seq, tf->region);
> +      lower_eh_constructs_1 (state, finally);
> +      gimple_seq_add_seq (&tf->top_p_seq, finally);
>
> -      x = gimple_build_goto (lab);
> -      gimple_seq_add_stmt (&eh_seq, x);
> +      if (tf->may_throw)
> +       {
> +         emit_post_landing_pad (&eh_seq, tf->region);
> +
> +         x = gimple_build_goto (lab);
> +         gimple_seq_add_stmt (&eh_seq, x);
> +       }
>     }
>  }
>
> @@ -1062,6 +1112,18 @@ lower_try_finally_onedest (struct leh_st
>   finally = gimple_try_cleanup (tf->top_p);
>   tf->top_p_seq = gimple_try_eval (tf->top_p);
>
> +  /* Since there's only one destination, and the destination edge can only
> +     either be EH or non-EH, that implies that all of our incoming edges
> +     are of the same type.  Therefore we can lower EH_ELSE immediately.  */
> +  x = get_eh_else (finally);
> +  if (x)
> +    {
> +      if (tf->may_throw)
> +        finally = gimple_eh_else_e_body (x);
> +      else
> +        finally = gimple_eh_else_n_body (x);
> +    }
> +
>   lower_eh_constructs_1 (state, finally);
>
>   if (tf->may_throw)
> @@ -1132,11 +1194,18 @@ lower_try_finally_copy (struct leh_state
>   gimple_seq finally;
>   gimple_seq new_stmt;
>   gimple_seq seq;
> -  gimple x;
> +  gimple x, eh_else;
>   tree tmp;
>   location_t tf_loc = gimple_location (tf->try_finally_expr);
>
>   finally = gimple_try_cleanup (tf->top_p);
> +
> +  /* Notice EH_ELSE, and simplify some of the remaining code
> +     by considering FINALLY to be the normal return path only.  */
> +  eh_else = get_eh_else (finally);
> +  if (eh_else)
> +    finally = gimple_eh_else_n_body (eh_else);
> +
>   tf->top_p_seq = gimple_try_eval (tf->top_p);
>   new_stmt = NULL;
>
> @@ -1153,7 +1222,12 @@ lower_try_finally_copy (struct leh_state
>
>   if (tf->may_throw)
>     {
> -      seq = lower_try_finally_dup_block (finally, state);
> +      /* We don't need to copy the EH path of EH_ELSE,
> +        since it is only emitted once.  */
> +      if (eh_else)
> +        seq = gimple_eh_else_e_body (eh_else);
> +      else
> +        seq = lower_try_finally_dup_block (finally, state);
>       lower_eh_constructs_1 (state, seq);
>
>       emit_post_landing_pad (&eh_seq, tf->region);
> @@ -1252,7 +1326,7 @@ lower_try_finally_switch (struct leh_sta
>   tree last_case;
>   VEC (tree,heap) *case_label_vec;
>   gimple_seq switch_body;
> -  gimple x;
> +  gimple x, eh_else;
>   tree tmp;
>   gimple switch_stmt;
>   gimple_seq finally;
> @@ -1263,9 +1337,10 @@ lower_try_finally_switch (struct leh_sta
>   location_t finally_loc;
>
>   switch_body = gimple_seq_alloc ();
> +  finally = gimple_try_cleanup (tf->top_p);
> +  eh_else = get_eh_else (finally);
>
>   /* Mash the TRY block to the head of the chain.  */
> -  finally = gimple_try_cleanup (tf->top_p);
>   tf->top_p_seq = gimple_try_eval (tf->top_p);
>
>   /* The location of the finally is either the last stmt in the finally
> @@ -1281,7 +1356,7 @@ lower_try_finally_switch (struct leh_sta
>   nlabels = VEC_length (tree, tf->dest_array);
>   return_index = nlabels;
>   eh_index = return_index + tf->may_return;
> -  fallthru_index = eh_index + tf->may_throw;
> +  fallthru_index = eh_index + (tf->may_throw && !eh_else);
>   ndests = fallthru_index + tf->may_fallthru;
>
>   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
> @@ -1319,7 +1394,23 @@ lower_try_finally_switch (struct leh_sta
>       gimple_seq_add_stmt (&switch_body, x);
>     }
>
> -  if (tf->may_throw)
> +  /* For EH_ELSE, emit the exception path (plus resx) now, then
> +     subsequently we only need consider the normal path.  */
> +  if (eh_else)
> +    {
> +      if (tf->may_throw)
> +       {
> +         finally = gimple_eh_else_e_body (eh_else);
> +         lower_eh_constructs_1 (state, finally);
> +
> +         emit_post_landing_pad (&eh_seq, tf->region);
> +         gimple_seq_add_seq (&eh_seq, finally);
> +         emit_resx (&eh_seq, tf->region);
> +       }
> +
> +      finally = gimple_eh_else_n_body (eh_else);
> +    }
> +  else if (tf->may_throw)
>     {
>       emit_post_landing_pad (&eh_seq, tf->region);
>
> @@ -1452,12 +1543,22 @@ lower_try_finally_switch (struct leh_sta
>    the estimate of the size of the switch machinery we'd have to add.  */
>
>  static bool
> -decide_copy_try_finally (int ndests, gimple_seq finally)
> +decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
>  {
>   int f_estimate, sw_estimate;
> +  gimple eh_else;
> +
> +  /* If there's an EH_ELSE involved, the exception path is separate
> +     and really doesn't come into play for this computation.  */
> +  eh_else = get_eh_else (finally);
> +  if (eh_else)
> +    {
> +      ndests -= may_throw;
> +      finally = gimple_eh_else_n_body (eh_else);
> +    }
>
>   if (!optimize)
> -    return false;
> +    return ndests == 1;
>
>   /* Finally estimate N times, plus N gotos.  */
>   f_estimate = count_insns_seq (finally, &eni_size_weights);
> @@ -1563,7 +1664,8 @@ lower_try_finally (struct leh_state *sta
>   /* We can easily special-case redirection to a single destination.  */
>   else if (ndests == 1)
>     lower_try_finally_onedest (state, &this_tf);
> -  else if (decide_copy_try_finally (ndests, gimple_try_cleanup (tp)))
> +  else if (decide_copy_try_finally (ndests, this_tf.may_throw,
> +                                   gimple_try_cleanup (tp)))
>     lower_try_finally_copy (state, &this_tf);
>   else
>     lower_try_finally_switch (state, &this_tf);
> @@ -1928,6 +2030,9 @@ lower_eh_constructs_2 (struct leh_state
>                case GIMPLE_EH_MUST_NOT_THROW:
>                    replace = lower_eh_must_not_throw (state, stmt);
>                    break;
> +               case GIMPLE_EH_ELSE:
> +                   /* This code is only valid with GIMPLE_TRY_FINALLY.  */
> +                   gcc_unreachable ();
>                default:
>                    replace = lower_cleanup (state, stmt);
>                    break;
> @@ -1942,6 +2047,10 @@ lower_eh_constructs_2 (struct leh_state
>       /* Return since we don't want gsi_next () */
>       return;
>
> +    case GIMPLE_EH_ELSE:
> +      /* We should be eliminating this in lower_try_finally et al.  */
> +      gcc_unreachable ();
> +
>     default:
>       /* A type, a decl, or some kind of statement that we're not
>         interested in.  Don't walk them.  */
> @@ -2832,6 +2941,10 @@ refactor_eh_r (gimple_seq seq)
>          case GIMPLE_EH_FILTER:
>            refactor_eh_r (gimple_eh_filter_failure (one));
>            break;
> +         case GIMPLE_EH_ELSE:
> +           refactor_eh_r (gimple_eh_else_n_body (one));
> +           refactor_eh_r (gimple_eh_else_e_body (one));
> +           break;
>          default:
>            break;
>          }
> Index: gcc/gimple-pretty-print.c
> ===================================================================
> --- gcc/gimple-pretty-print.c   (.../trunk)     (revision 180744)
> +++ gcc/gimple-pretty-print.c   (.../branches/transactional-memory)
> (revision 180773)
> @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
>  #include "tree-pass.h"
>  #include "gimple.h"
>  #include "value-prof.h"
> +#include "trans-mem.h"
>
>  #define INDENT(SPACE)                                                  \
>   do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0)
> @@ -162,6 +163,7 @@ debug_gimple_seq (gimple_seq seq)
>      'd' - outputs an int as a decimal,
>      's' - outputs a string,
>      'n' - outputs a newline,
> +     'x' - outputs an int as hexadecimal,
>      '+' - increases indent by 2 then outputs a newline,
>      '-' - decreases indent by 2 then outputs a newline.   */
>
> @@ -216,6 +218,10 @@ dump_gimple_fmt (pretty_printer *buffer,
>                 newline_and_indent (buffer, spc);
>                 break;
>
> +              case 'x':
> +                pp_scalar (buffer, "%x", va_arg (args, int));
> +                break;
> +
>               case '+':
>                 spc += 2;
>                 newline_and_indent (buffer, spc);
> @@ -622,6 +628,7 @@ static void
>  dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
>  {
>   tree lhs = gimple_call_lhs (gs);
> +  tree fn = gimple_call_fn (gs);
>
>   if (flags & TDF_ALIAS)
>     {
> @@ -648,8 +655,7 @@ dump_gimple_call (pretty_printer *buffer
>        dump_gimple_fmt (buffer, spc, flags, "%G <%s, %T", gs,
>                         internal_fn_name (gimple_call_internal_fn (gs)),
> lhs);
>       else
> -       dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T",
> -                        gs, gimple_call_fn (gs), lhs);
> +       dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", gs, fn, lhs);
>       if (gimple_call_num_args (gs) > 0)
>         {
>           pp_string (buffer, ", ");
> @@ -672,7 +678,7 @@ dump_gimple_call (pretty_printer *buffer
>       if (gimple_call_internal_p (gs))
>        pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs)));
>       else
> -       print_call_name (buffer, gimple_call_fn (gs), flags);
> +       print_call_name (buffer, fn, flags);
>       pp_string (buffer, " (");
>       dump_gimple_call_args (buffer, gs, flags);
>       pp_character (buffer, ')');
> @@ -689,9 +695,63 @@ dump_gimple_call (pretty_printer *buffer
>
>   if (gimple_call_return_slot_opt_p (gs))
>     pp_string (buffer, " [return slot optimization]");
> -
>   if (gimple_call_tail_p (gs))
>     pp_string (buffer, " [tail call]");
> +
> +  /* Dump the arguments of _ITM_beginTransaction sanely.  */
> +  if (TREE_CODE (fn) == ADDR_EXPR)
> +    fn = TREE_OPERAND (fn, 0);
> +  if (TREE_CODE (fn) == FUNCTION_DECL && DECL_IS_TM_CLONE (fn))
> +    pp_string (buffer, " [tm-clone]");
> +  if (TREE_CODE (fn) == FUNCTION_DECL
> +      && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
> +      && DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_START
> +      /* Check we're referring to Intel's TM specifications.  */
> +      && !strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)),
> +                 "__builtin__ITM_beginTransaction")

Huh.  Are there others that would use the same builtin?

> +      && gimple_call_num_args (gs) > 0
> +      )

) goes to the previouys line.

> +    {
> +      tree t = gimple_call_arg (gs, 0);
> +      unsigned HOST_WIDE_INT props;
> +      gcc_assert (TREE_CODE (t) == INTEGER_CST);
> +
> +      pp_string (buffer, " [ ");
> +
> +      /* Get the transaction code properties.  */
> +      props = TREE_INT_CST_LOW (t);
> +
> +      if (props & PR_INSTRUMENTEDCODE)
> +       pp_string (buffer, "instrumentedCode ");
> +      if (props & PR_UNINSTRUMENTEDCODE)
> +       pp_string (buffer, "uninstrumentedCode ");
> +      if (props & PR_HASNOXMMUPDATE)
> +       pp_string (buffer, "hasNoXMMUpdate ");
> +      if (props & PR_HASNOABORT)
> +       pp_string (buffer, "hasNoAbort ");
> +      if (props & PR_HASNOIRREVOCABLE)
> +       pp_string (buffer, "hasNoIrrevocable ");
> +      if (props & PR_DOESGOIRREVOCABLE)
> +       pp_string (buffer, "doesGoIrrevocable ");
> +      if (props & PR_HASNOSIMPLEREADS)
> +       pp_string (buffer, "hasNoSimpleReads ");
> +      if (props & PR_AWBARRIERSOMITTED)
> +       pp_string (buffer, "awBarriersOmitted ");
> +      if (props & PR_RARBARRIERSOMITTED)
> +       pp_string (buffer, "RaRBarriersOmitted ");
> +      if (props & PR_UNDOLOGCODE)
> +       pp_string (buffer, "undoLogCode ");
> +      if (props & PR_PREFERUNINSTRUMENTED)
> +       pp_string (buffer, "preferUninstrumented ");
> +      if (props & PR_EXCEPTIONBLOCK)
> +       pp_string (buffer, "exceptionBlock ");
> +      if (props & PR_HASELSE)
> +       pp_string (buffer, "hasElse ");
> +      if (props & PR_READONLY)
> +       pp_string (buffer, "readOnly ");
> +
> +      pp_string (buffer, "]");
> +    }
>  }
>
>
> @@ -947,6 +1007,24 @@ dump_gimple_eh_must_not_throw (pretty_pr
>  }
>
>
> +/* Dump a GIMPLE_EH_ELSE tuple on the pretty_printer BUFFER, SPC spaces of
> +   indent.  FLAGS specifies details to show in the dump (see TDF_* in
> +   tree-pass.h).  */
> +
> +static void
> +dump_gimple_eh_else (pretty_printer *buffer, gimple gs, int spc, int flags)
> +{
> +  if (flags & TDF_RAW)
> +    dump_gimple_fmt (buffer, spc, flags,
> +                     "%G <%+N_BODY <%S>%nE_BODY <%S>%->", gs,
> +                     gimple_eh_else_n_body (gs), gimple_eh_else_e_body
> (gs));
> +  else
> +    dump_gimple_fmt (buffer, spc, flags,
> +                    "<<<if_normal_exit>>>%+{%S}%-<<<else_eh_exit>>>%+{%S}",
> +                     gimple_eh_else_n_body (gs), gimple_eh_else_e_body
> (gs));
> +}
> +
> +
>  /* Dump a GIMPLE_RESX tuple on the pretty_printer BUFFER, SPC spaces of
>    indent.  FLAGS specifies details to show in the dump (see TDF_* in
>    tree-pass.h).  */
> @@ -1269,6 +1347,86 @@ dump_gimple_omp_return (pretty_printer *
>     }
>  }
>
> +/* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER.  */
> +
> +static void
> +dump_gimple_transaction (pretty_printer *buffer, gimple gs, int spc, int
> flags)
> +{
> +  unsigned subcode = gimple_transaction_subcode (gs);
> +
> +  if (flags & TDF_RAW)
> +    {
> +      dump_gimple_fmt (buffer, spc, flags,
> +                      "%G [SUBCODE=%x,LABEL=%T] <%+BODY <%S> >",
> +                      gs, subcode, gimple_transaction_label (gs),
> +                      gimple_transaction_body (gs));
> +    }
> +  else
> +    {
> +      if (subcode & GTMA_IS_OUTER)
> +       pp_string (buffer, "__transaction_atomic [[outer]]");
> +      else if (subcode & GTMA_IS_RELAXED)
> +       pp_string (buffer, "__transaction_relaxed");
> +      else
> +       pp_string (buffer, "__transaction_atomic");
> +      subcode &= ~GTMA_DECLARATION_MASK;
> +
> +      if (subcode || gimple_transaction_label (gs))
> +       {
> +         pp_string (buffer, "  //");
> +         if (gimple_transaction_label (gs))
> +           {
> +             pp_string (buffer, " LABEL=");
> +             dump_generic_node (buffer, gimple_transaction_label (gs),
> +                                spc, flags, false);
> +           }
> +         if (subcode)
> +           {
> +             pp_string (buffer, " SUBCODE=[ ");
> +             if (subcode & GTMA_HAVE_ABORT)
> +               {
> +                 pp_string (buffer, "GTMA_HAVE_ABORT ");
> +                 subcode &= ~GTMA_HAVE_ABORT;
> +               }
> +             if (subcode & GTMA_HAVE_LOAD)
> +               {
> +                 pp_string (buffer, "GTMA_HAVE_LOAD ");
> +                 subcode &= ~GTMA_HAVE_LOAD;
> +               }
> +             if (subcode & GTMA_HAVE_STORE)
> +               {
> +                 pp_string (buffer, "GTMA_HAVE_STORE ");
> +                 subcode &= ~GTMA_HAVE_STORE;
> +               }
> +             if (subcode & GTMA_MAY_ENTER_IRREVOCABLE)
> +               {
> +                 pp_string (buffer, "GTMA_MAY_ENTER_IRREVOCABLE ");
> +                 subcode &= ~GTMA_MAY_ENTER_IRREVOCABLE;
> +               }
> +             if (subcode & GTMA_DOES_GO_IRREVOCABLE)
> +               {
> +                 pp_string (buffer, "GTMA_DOES_GO_IRREVOCABLE ");
> +                 subcode &= ~GTMA_DOES_GO_IRREVOCABLE;
> +               }
> +             if (subcode)
> +               pp_printf (buffer, "0x%x ", subcode);
> +             pp_string (buffer, "]");
> +           }
> +       }
> +
> +      if (!gimple_seq_empty_p (gimple_transaction_body (gs)))
> +       {
> +         newline_and_indent (buffer, spc + 2);
> +         pp_character (buffer, '{');
> +         pp_newline (buffer);
> +         dump_gimple_seq (buffer, gimple_transaction_body (gs),
> +                          spc + 4, flags);
> +         newline_and_indent (buffer, spc + 2);
> +         pp_character (buffer, '}');
> +       }
> +    }
> +}
> +
>  /* Dump a GIMPLE_ASM tuple on the pretty_printer BUFFER, SPC spaces of
>    indent.  FLAGS specifies details to show in the dump (see TDF_* in
>    tree-pass.h).  */
> @@ -1855,6 +2013,10 @@ dump_gimple_stmt (pretty_printer *buffer
>       dump_gimple_eh_must_not_throw (buffer, gs, spc, flags);
>       break;
>
> +    case GIMPLE_EH_ELSE:
> +      dump_gimple_eh_else (buffer, gs, spc, flags);
> +      break;
> +
>     case GIMPLE_RESX:
>       dump_gimple_resx (buffer, gs, spc, flags);
>       break;
> @@ -1877,6 +2039,10 @@ dump_gimple_stmt (pretty_printer *buffer
>       pp_string (buffer, " predictor.");
>       break;
>
> +    case GIMPLE_TRANSACTION:
> +      dump_gimple_transaction (buffer, gs, spc, flags);
> +      break;
> +
>     default:
>       GIMPLE_NIY;
>     }
> Index: gcc/gimplify.c
> ===================================================================
> --- gcc/gimplify.c      (.../trunk)     (revision 180744)
> +++ gcc/gimplify.c      (.../branches/transactional-memory)     (revision
> 180773)
> @@ -413,6 +413,8 @@ create_tmp_var_name (const char *prefix)
>       char *preftmp = ASTRDUP (prefix);
>
>       remove_suffix (preftmp, strlen (preftmp));
> +      clean_symbol_name (preftmp);
> +
>       prefix = preftmp;
>     }
>
> @@ -1072,6 +1074,12 @@ voidify_wrapper_expr (tree wrapper, tree
>                }
>              break;
>
> +           case TRANSACTION_EXPR:
> +             TREE_SIDE_EFFECTS (*p) = 1;
> +             TREE_TYPE (*p) = void_type_node;
> +             p = &TRANSACTION_EXPR_BODY (*p);
> +             break;
> +
>            default:
>              goto out;
>            }
> @@ -6527,6 +6535,53 @@ gimplify_omp_atomic (tree *expr_p, gimpl
>    return GS_ALL_DONE;
>  }
>
> +/* Gimplify a TRANSACTION_EXPR.  This involves gimplification of the
> +   body, and adding some EH bits.  */
> +
> +static enum gimplify_status
> +gimplify_transaction (tree *expr_p, gimple_seq *pre_p)
> +{
> +  tree expr = *expr_p, temp, tbody = TRANSACTION_EXPR_BODY (expr);
> +  gimple g;
> +  gimple_seq body = NULL;
> +  struct gimplify_ctx gctx;
> +  int subcode = 0;
> +
> +  /* Wrap the transaction body in a BIND_EXPR so we have a context
> +     where to put decls for OpenMP.  */
> +  if (TREE_CODE (tbody) != BIND_EXPR)
> +    {
> +      tree bind = build3 (BIND_EXPR, void_type_node, NULL, tbody, NULL);
> +      TREE_SIDE_EFFECTS (bind) = 1;
> +      SET_EXPR_LOCATION (bind, EXPR_LOCATION (tbody));
> +      TRANSACTION_EXPR_BODY (expr) = bind;
> +    }
> +
> +  push_gimplify_context (&gctx);
> +  temp = voidify_wrapper_expr (*expr_p, NULL);
> +
> +  g = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body);
> +  pop_gimplify_context (g);
> +
> +  g = gimple_build_transaction (body, NULL);
> +  if (TRANSACTION_EXPR_OUTER (expr))
> +    subcode = GTMA_IS_OUTER;
> +  else if (TRANSACTION_EXPR_RELAXED (expr))
> +    subcode = GTMA_IS_RELAXED;
> +  gimple_transaction_set_subcode (g, subcode);
> +
> +  gimplify_seq_add_stmt (pre_p, g);
> +
> +  if (temp)
> +    {
> +      *expr_p = temp;
> +      return GS_OK;
> +    }
> +
> +  *expr_p = NULL_TREE;
> +  return GS_ALL_DONE;
> +}
> +
>  /* Convert the GENERIC expression tree *EXPR_P to GIMPLE.  If the
>    expression produces a value to be used as an operand inside a GIMPLE
>    statement, the value will be stored back in *EXPR_P.  This value will
> @@ -7251,6 +7306,10 @@ gimplify_expr (tree *expr_p, gimple_seq
>          ret = gimplify_omp_atomic (expr_p, pre_p);
>          break;
>
> +        case TRANSACTION_EXPR:
> +          ret = gimplify_transaction (expr_p, pre_p);
> +          break;
> +
>        case TRUTH_AND_EXPR:
>        case TRUTH_OR_EXPR:
>        case TRUTH_XOR_EXPR:
> Index: gcc/calls.c
> ===================================================================
> --- gcc/calls.c (.../trunk)     (revision 180744)
> +++ gcc/calls.c (.../branches/transactional-memory)     (revision 180773)
> @@ -496,7 +496,60 @@ emit_call_1 (rtx funexp, tree fntree ATT
>  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_COMMIT:
> +       case BUILT_IN_TM_COMMIT_EH:
> +       case BUILT_IN_TM_ABORT:
> +       case BUILT_IN_TM_IRREVOCABLE:
> +       case BUILT_IN_TM_GETTMCLONE_IRR:
> +       case BUILT_IN_TM_MEMCPY:
> +       case BUILT_IN_TM_MEMMOVE:
> +        case BUILT_IN_TM_MEMSET:
> +       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_STORE (LDOUBLE):
> +       CASE_BUILT_IN_TM_STORE (M64):
> +       CASE_BUILT_IN_TM_STORE (M128):
> +       CASE_BUILT_IN_TM_STORE (M256):
> +       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):
> +       CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> +       CASE_BUILT_IN_TM_LOAD (M64):
> +       CASE_BUILT_IN_TM_LOAD (M128):
> +       CASE_BUILT_IN_TM_LOAD (M256):
> +       case BUILT_IN_TM_LOG:
> +       case BUILT_IN_TM_LOG_1:
> +       case BUILT_IN_TM_LOG_2:
> +       case BUILT_IN_TM_LOG_4:
> +       case BUILT_IN_TM_LOG_8:
> +       case BUILT_IN_TM_LOG_FLOAT:
> +       case BUILT_IN_TM_LOG_DOUBLE:
> +       case BUILT_IN_TM_LOG_LDOUBLE:
> +       case BUILT_IN_TM_LOG_M64:
> +       case BUILT_IN_TM_LOG_M128:
> +       case BUILT_IN_TM_LOG_M256:
> +         flags |= ECF_TM_OPS;
> +         break;
> +       default:
> +         break;
> +       }
> +    }

This should not be in special_function_p which is solely to check
for the identifiers.  Instead the caller of this function should handle
the builtin codes (flags_from_decl_or_type).

> +  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
> @@ -644,6 +697,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;
> +

Thus, here.

>       flags = special_function_p (exp, flags);
>     }
>   else if (TYPE_P (exp) && TYPE_READONLY (exp))
> Index: gcc/tree-inline.c
> ===================================================================
> --- gcc/tree-inline.c   (.../trunk)     (revision 180744)
> +++ gcc/tree-inline.c   (.../branches/transactional-memory)     (revision
> 180773)
> @@ -1365,6 +1365,12 @@ remap_gimple_stmt (gimple stmt, copy_bod
>            = gimple_build_omp_critical (s1, gimple_omp_critical_name
> (stmt));
>          break;
>
> +       case GIMPLE_TRANSACTION:
> +         s1 = remap_gimple_seq (gimple_transaction_body (stmt), id);
> +         copy = gimple_build_transaction (s1, gimple_transaction_label
> (stmt));
> +         gimple_transaction_set_subcode (copy, gimple_transaction_subcode
> (stmt));
> +         break;
> +
>        default:
>          gcc_unreachable ();
>        }
> @@ -3600,6 +3606,11 @@ estimate_num_insns (gimple stmt, eni_wei
>       return (weights->omp_cost
>               + estimate_num_insns_seq (gimple_omp_body (stmt), weights));
>
> +    case GIMPLE_TRANSACTION:
> +      return (weights->tm_cost
> +             + estimate_num_insns_seq (gimple_transaction_body (stmt),
> +                                       weights));
> +

Huh, so we now have non-lowered gimple sub-sequence throughout all
optimizations (inlining especially)?  :(

I think I miss tree-cfg.c parts that do any verification of the new gimple
kinds.

>     default:
>       gcc_unreachable ();
>     }
> @@ -3639,6 +3650,7 @@ init_inline_once (void)
>   eni_size_weights.target_builtin_call_cost = 1;
>   eni_size_weights.div_mod_cost = 1;
>   eni_size_weights.omp_cost = 40;
> +  eni_size_weights.tm_cost = 10;
>   eni_size_weights.time_based = false;
>   eni_size_weights.return_cost = 1;
>
> @@ -3650,6 +3662,7 @@ init_inline_once (void)
>   eni_time_weights.target_builtin_call_cost = 1;
>   eni_time_weights.div_mod_cost = 10;
>   eni_time_weights.omp_cost = 40;
> +  eni_time_weights.tm_cost = 40;
>   eni_time_weights.time_based = true;
>   eni_time_weights.return_cost = 2;
>  }
> Index: gcc/tree-inline.h
> ===================================================================
> --- gcc/tree-inline.h   (.../trunk)     (revision 180744)
> +++ gcc/tree-inline.h   (.../branches/transactional-memory)     (revision
> 180773)
> @@ -144,6 +144,9 @@ typedef struct eni_weights_d
>   /* Cost for omp construct.  */
>   unsigned omp_cost;
>
> +  /* Cost for tm transaction.  */
> +  unsigned tm_cost;
> +
>   /* Cost of return.  */
>   unsigned return_cost;
>
> Index: gcc/gimple.c
> ===================================================================
> --- gcc/gimple.c        (.../trunk)     (revision 180744)
> +++ gcc/gimple.c        (.../branches/transactional-memory)     (revision
> 180773)
> @@ -743,6 +743,17 @@ gimple_build_eh_must_not_throw (tree dec
>   return p;
>  }
>
> +/* Build a GIMPLE_EH_ELSE statement.  */
> +
> +gimple
> +gimple_build_eh_else (gimple_seq n_body, gimple_seq e_body)
> +{
> +  gimple p = gimple_alloc (GIMPLE_EH_ELSE, 0);
> +  gimple_eh_else_set_n_body (p, n_body);
> +  gimple_eh_else_set_e_body (p, e_body);
> +  return p;
> +}
> +
>  /* Build a GIMPLE_TRY statement.
>
>    EVAL is the expression to evaluate.
> @@ -1146,6 +1157,17 @@ gimple_build_omp_atomic_store (tree val)
>   return p;
>  }
>
> +/* Build a GIMPLE_TRANSACTION statement.  */
> +
> +gimple
> +gimple_build_transaction (gimple_seq body, tree label)
> +{
> +  gimple p = gimple_alloc (GIMPLE_TRANSACTION, 0);
> +  gimple_transaction_set_body (p, body);
> +  gimple_transaction_set_label (p, label);
> +  return p;
> +}
> +
>  /* Build a GIMPLE_PREDICT statement.  PREDICT is one of the predictors from
>    predict.def, OUTCOME is NOT_TAKEN or TAKEN.  */
>
> @@ -1331,7 +1353,7 @@ walk_gimple_seq (gimple_seq seq, walk_st

As you are changing features of this walker you should update its
documentation.

>  {
>   gimple_stmt_iterator gsi;
>
> -  for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
> +  for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
>     {
>       tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi);
>       if (ret)
> @@ -1340,8 +1362,12 @@ walk_gimple_seq (gimple_seq seq, walk_st
>             to hold it.  */
>          gcc_assert (wi);
>          wi->callback_result = ret;
> -         return gsi_stmt (gsi);
> +
> +         return wi->removed_stmt ? NULL : gsi_stmt (gsi);
>        }
> +
> +      if (!wi->removed_stmt)
> +       gsi_next (&gsi);
>     }
>
>   if (wi)
> @@ -1680,6 +1706,13 @@ walk_gimple_op (gimple stmt, walk_tree_f
>        return ret;
>       break;
>
> +    case GIMPLE_TRANSACTION:
> +      ret = walk_tree (gimple_transaction_label_ptr (stmt), callback_op,
> +                      wi, pset);
> +      if (ret)
> +       return ret;
> +      break;
> +
>       /* Tuples that do not have operands.  */
>     case GIMPLE_NOP:
>     case GIMPLE_RESX:
> @@ -1730,10 +1763,13 @@ walk_gimple_stmt (gimple_stmt_iterator *
>   gimple stmt = gsi_stmt (*gsi);
>
>   if (wi)
> -    wi->gsi = *gsi;
> +    {
> +      wi->gsi = *gsi;
> +      wi->removed_stmt = false;
>
> -  if (wi && wi->want_locations && gimple_has_location (stmt))
> -    input_location = gimple_location (stmt);
> +      if (wi->want_locations && gimple_has_location (stmt))
> +       input_location = gimple_location (stmt);
> +    }
>
>   ret = NULL;
>
> @@ -1751,6 +1787,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
>       gcc_assert (tree_ret == NULL);
>
>       /* Re-read stmt in case the callback changed it.  */
> +      if (wi && wi->removed_stmt)
> +       return NULL;
>       stmt = gsi_stmt (*gsi);
>     }
>
> @@ -1786,6 +1824,17 @@ walk_gimple_stmt (gimple_stmt_iterator *
>        return wi->callback_result;
>       break;
>
> +    case GIMPLE_EH_ELSE:
> +      ret = walk_gimple_seq (gimple_eh_else_n_body (stmt),
> +                            callback_stmt, callback_op, wi);
> +      if (ret)
> +       return wi->callback_result;
> +      ret = walk_gimple_seq (gimple_eh_else_e_body (stmt),
> +                            callback_stmt, callback_op, wi);
> +      if (ret)
> +       return wi->callback_result;
> +      break;
> +
>     case GIMPLE_TRY:
>       ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt,
> callback_op,
>                             wi);
> @@ -1813,8 +1862,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
>     case GIMPLE_OMP_TASK:
>     case GIMPLE_OMP_SECTIONS:
>     case GIMPLE_OMP_SINGLE:
> -      ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt,
> callback_op,
> -                            wi);
> +      ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt,
> +                            callback_op, wi);
>       if (ret)
>        return wi->callback_result;
>       break;
> @@ -1826,6 +1875,13 @@ walk_gimple_stmt (gimple_stmt_iterator *
>        return wi->callback_result;
>       break;
>
> +    case GIMPLE_TRANSACTION:
> +      ret = walk_gimple_seq (gimple_transaction_body (stmt),
> +                            callback_stmt, callback_op, wi);
> +      if (ret)
> +       return wi->callback_result;
> +      break;
> +
>     default:
>       gcc_assert (!gimple_has_substatements (stmt));
>       break;
> @@ -2252,6 +2308,13 @@ gimple_copy (gimple stmt)
>          gimple_eh_filter_set_types (copy, t);
>          break;
>
> +       case GIMPLE_EH_ELSE:
> +         new_seq = gimple_seq_copy (gimple_eh_else_n_body (stmt));
> +         gimple_eh_else_set_n_body (copy, new_seq);
> +         new_seq = gimple_seq_copy (gimple_eh_else_e_body (stmt));
> +         gimple_eh_else_set_e_body (copy, new_seq);
> +         break;
> +
>        case GIMPLE_TRY:
>          new_seq = gimple_seq_copy (gimple_try_eval (stmt));
>          gimple_try_set_eval (copy, new_seq);
> @@ -2327,6 +2390,11 @@ gimple_copy (gimple stmt)
>          gimple_omp_set_body (copy, new_seq);
>          break;
>
> +        case GIMPLE_TRANSACTION:
> +         new_seq = gimple_seq_copy (gimple_transaction_body (stmt));
> +         gimple_transaction_set_body (copy, new_seq);
> +         break;
> +
>        case GIMPLE_WITH_CLEANUP_EXPR:
>          new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt));
>          gimple_wce_set_cleanup (copy, new_seq);
> @@ -2785,7 +2853,7 @@ is_gimple_address (const_tree t)
>  /* Strip out all handled components that produce invariant
>    offsets.  */
>
> -static const_tree
> +const_tree
>  strip_invariant_refs (const_tree op)
>  {
>   while (handled_component_p (op))

If you export this please move it to tree.c.

> @@ -3085,6 +3153,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;

An unused function.  Please move it to where you need it instead,
make it static and adjust it in a way to do exactly what you want.
After the above change it looks strange - handling V_C_E but
not other component refs.

> Index: gcc/gimple.h
> ===================================================================
> --- gcc/gimple.h        (.../trunk)     (revision 180744)
> +++ gcc/gimple.h        (.../branches/transactional-memory)     (revision
> 180773)
> @@ -105,6 +105,7 @@ enum gf_mask {
>     GF_CALL_NOTHROW            = 1 << 5,
>     GF_CALL_ALLOCA_FOR_VAR     = 1 << 6,
>     GF_CALL_INTERNAL           = 1 << 7,
> +    GF_CALL_NOINLINE           = 1 << 8,
>     GF_OMP_PARALLEL_COMBINED   = 1 << 0,

?  Why not use GF_CALL_CANNOT_INLINE?

>     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
> @@ -487,6 +488,15 @@ struct GTY(()) gimple_statement_eh_filte
>   gimple_seq failure;
>  };
>
> +/* GIMPLE_EH_ELSE */
> +
> +struct GTY(()) gimple_statement_eh_else {
> +  /* [ WORD 1-4 ]  */
> +  struct gimple_statement_base gsbase;
> +
> +  /* [ WORD 5,6 ] */
> +  gimple_seq n_body, e_body;
> +};
>
>  /* GIMPLE_EH_MUST_NOT_THROW */
>
> @@ -757,6 +767,43 @@ struct GTY(()) gimple_statement_omp_atom
>   tree val;
>  };
>
> +/* GIMPLE_TRANSACTION.  */
> +
> +/* Bits to be stored in the GIMPLE_TRANSACTION subcode.  */
> +
> +/* The __transaction_atomic was declared [[outer]] or it is
> +   __transaction_relaxed.  */
> +#define GTMA_IS_OUTER                  (1u << 0)
> +#define GTMA_IS_RELAXED                        (1u << 1)
> +#define GTMA_DECLARATION_MASK          (GTMA_IS_OUTER | GTMA_IS_RELAXED)
> +
> +/* The transaction is seen to not have an abort.  */
> +#define GTMA_HAVE_ABORT                        (1u << 2)
> +/* The transaction is seen to have loads or stores.  */
> +#define GTMA_HAVE_LOAD                 (1u << 3)
> +#define GTMA_HAVE_STORE                        (1u << 4)
> +/* The transaction MAY enter serial irrevocable mode in its dynamic scope.
>  */
> +#define GTMA_MAY_ENTER_IRREVOCABLE     (1u << 5)
> +/* The transaction WILL enter serial 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_DOES_GO_IRREVOCABLE       (1u << 6)
> +
> +struct GTY(()) gimple_statement_transaction
> +{
> +  /* [ WORD 1-10 ]  */
> +  struct gimple_statement_with_memory_ops_base gsbase;
> +
> +  /* [ WORD 11 ] */
> +  gimple_seq body;
> +
> +  /* [ WORD 12 ] */
> +  tree label;
> +};
> +
>  #define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP)  SYM,
>  enum gimple_statement_structure_enum {
>  #include "gsstruct.def"
> @@ -779,6 +826,7 @@ union GTY ((desc ("gimple_statement_stru
>   struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
>   struct gimple_statement_eh_filter GTY ((tag ("GSS_EH_FILTER")))
> gimple_eh_filter;
>   struct gimple_statement_eh_mnt GTY ((tag ("GSS_EH_MNT"))) gimple_eh_mnt;
> +  struct gimple_statement_eh_else GTY ((tag ("GSS_EH_ELSE")))
> gimple_eh_else;
>   struct gimple_statement_phi GTY ((tag ("GSS_PHI"))) gimple_phi;
>   struct gimple_statement_eh_ctrl GTY ((tag ("GSS_EH_CTRL")))
> gimple_eh_ctrl;
>   struct gimple_statement_try GTY ((tag ("GSS_TRY"))) gimple_try;
> @@ -793,6 +841,7 @@ union GTY ((desc ("gimple_statement_stru
>   struct gimple_statement_omp_continue GTY ((tag ("GSS_OMP_CONTINUE")))
> gimple_omp_continue;
>   struct gimple_statement_omp_atomic_load GTY ((tag
> ("GSS_OMP_ATOMIC_LOAD"))) gimple_omp_atomic_load;
>   struct gimple_statement_omp_atomic_store GTY ((tag
> ("GSS_OMP_ATOMIC_STORE"))) gimple_omp_atomic_store;
> +  struct gimple_statement_transaction GTY((tag ("GSS_TRANSACTION")))
> gimple_transaction;
>  };
>
>  /* In gimple.c.  */
> @@ -846,6 +895,7 @@ gimple gimple_build_asm_vec (const char
>  gimple gimple_build_catch (tree, gimple_seq);
>  gimple gimple_build_eh_filter (tree, gimple_seq);
>  gimple gimple_build_eh_must_not_throw (tree);
> +gimple gimple_build_eh_else (gimple_seq, gimple_seq);
>  gimple gimple_build_try (gimple_seq, gimple_seq, enum gimple_try_flags);
>  gimple gimple_build_wce (gimple_seq);
>  gimple gimple_build_resx (int);
> @@ -868,6 +918,7 @@ gimple gimple_build_omp_single (gimple_s
>  gimple gimple_build_cdt (tree, tree);
>  gimple gimple_build_omp_atomic_load (tree, tree);
>  gimple gimple_build_omp_atomic_store (tree);
> +gimple gimple_build_transaction (gimple_seq, tree);
>  gimple gimple_build_predict (enum br_predictor, enum prediction);
>  enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
>  void sort_case_labels (VEC(tree,heap) *);
> @@ -986,6 +1037,7 @@ extern bool walk_stmt_load_store_ops (gi
>                                      bool (*)(gimple, tree, void *),
>                                      bool (*)(gimple, tree, void *));
>  extern bool gimple_ior_addresses_taken (bitmap, gimple);
> +extern const_tree strip_invariant_refs (const_tree);
>  extern bool gimple_call_builtin_p (gimple, enum built_in_function);
>  extern bool gimple_asm_clobbers_memory_p (const_gimple);
>
> @@ -1077,6 +1129,9 @@ extern tree canonicalize_cond_expr_cond
>  /* In omp-low.c.  */
>  extern tree omp_reduction_init (tree, tree);
>
> +/* In trans-mem.c.  */
> +extern void diagnose_tm_safe_errors (tree);
> +
>  /* In tree-nested.c.  */
>  extern void lower_nested_functions (tree);
>  extern void insert_field_into_struct (tree, tree);
> @@ -1135,6 +1190,7 @@ gimple_has_substatements (gimple g)
>     case GIMPLE_BIND:
>     case GIMPLE_CATCH:
>     case GIMPLE_EH_FILTER:
> +    case GIMPLE_EH_ELSE:
>     case GIMPLE_TRY:
>     case GIMPLE_OMP_FOR:
>     case GIMPLE_OMP_MASTER:
> @@ -1146,6 +1202,7 @@ gimple_has_substatements (gimple g)
>     case GIMPLE_OMP_SINGLE:
>     case GIMPLE_OMP_CRITICAL:
>     case GIMPLE_WITH_CLEANUP_EXPR:
> +    case GIMPLE_TRANSACTION:
>       return true;
>
>     default:
> @@ -2436,6 +2493,22 @@ gimple_call_alloca_for_var_p (gimple s)
>   return (s->gsbase.subcode & GF_CALL_ALLOCA_FOR_VAR) != 0;
>  }
>
> +/* Return true if S is a noinline call.  */
> +
> +static inline bool
> +gimple_call_noinline_p (gimple s)
> +{
> +  GIMPLE_CHECK (s, GIMPLE_CALL);
> +  return (s->gsbase.subcode & GF_CALL_NOINLINE) != 0;
> +}
> +
> +static inline void
> +gimple_call_set_noinline_p (gimple s)
> +{
> +  GIMPLE_CHECK (s, GIMPLE_CALL);
> +  s->gsbase.subcode |= GF_CALL_NOINLINE;
> +}

See above.  We have *_cannot_inline already.

>  /* Copy all the GF_CALL_* flags from ORIG_CALL to DEST_CALL.  */
>
>  static inline void
> @@ -3178,6 +3251,35 @@ gimple_eh_must_not_throw_set_fndecl (gim
>   gs->gimple_eh_mnt.fndecl = decl;
>  }
>
> +/* GIMPLE_EH_ELSE accessors.  */
> +
> +static inline gimple_seq
> +gimple_eh_else_n_body (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
> +  return gs->gimple_eh_else.n_body;
> +}
> +
> +static inline gimple_seq
> +gimple_eh_else_e_body (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
> +  return gs->gimple_eh_else.e_body;
> +}
> +
> +static inline void
> +gimple_eh_else_set_n_body (gimple gs, gimple_seq seq)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
> +  gs->gimple_eh_else.n_body = seq;
> +}
> +
> +static inline void
> +gimple_eh_else_set_e_body (gimple gs, gimple_seq seq)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
> +  gs->gimple_eh_else.e_body = seq;
> +}
>
>  /* GIMPLE_TRY accessors. */
>
> @@ -4556,6 +4658,67 @@ gimple_omp_continue_set_control_use (gim
>   g->gimple_omp_continue.control_use = use;
>  }
>
> +/* Return the body for the GIMPLE_TRANSACTION statement GS.  */
> +
> +static inline gimple_seq
> +gimple_transaction_body (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  return gs->gimple_transaction.body;
> +}
> +
> +/* Return the label associated with a GIMPLE_TRANSACTION.  */
> +
> +static inline tree
> +gimple_transaction_label (const_gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  return gs->gimple_transaction.label;
> +}
> +
> +static inline tree *
> +gimple_transaction_label_ptr (gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  return &gs->gimple_transaction.label;
> +}
> +
> +/* Return the subcode associated with a GIMPLE_TRANSACTION.  */
> +
> +static inline unsigned int
> +gimple_transaction_subcode (const_gimple gs)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  return gs->gsbase.subcode;
> +}
> +
> +/* Set BODY to be the body for the GIMPLE_TRANSACTION statement GS.  */
> +
> +static inline void
> +gimple_transaction_set_body (gimple gs, gimple_seq body)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  gs->gimple_transaction.body = body;
> +}
> +
> +/* Set the label associated with a GIMPLE_TRANSACTION.  */
> +
> +static inline void
> +gimple_transaction_set_label (gimple gs, tree label)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  gs->gimple_transaction.label = label;
> +}
> +
> +/* Set the subcode associated with a GIMPLE_TRANSACTION.  */
> +
> +static inline void
> +gimple_transaction_set_subcode (gimple gs, unsigned int subcode)
> +{
> +  GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
> +  gs->gsbase.subcode = subcode;
> +}
> +
>
>  /* Return a pointer to the return value for GIMPLE_RETURN GS.  */
>
> @@ -4982,6 +5145,12 @@ struct walk_stmt_info
>      will be visited more than once.  */
>   struct pointer_set_t *pset;
>
> +  /* Operand returned by the callbacks.  This is set when calling
> +     walk_gimple_seq.  If the walk_stmt_fn or walk_tree_fn callback
> +     returns non-NULL, this field will contain the tree returned by
> +     the last callback.  */
> +  tree callback_result;
> +
>   /* Indicates whether the operand being examined may be replaced
>      with something that matches is_gimple_val (if true) or something
>      slightly more complicated (if false).  "Something" technically
> @@ -4994,23 +5163,20 @@ struct walk_stmt_info
>      statement 'foo (&var)', the flag VAL_ONLY will initially be set
>      to true, however, when walking &var, the operand of that
>      ADDR_EXPR does not need to be a GIMPLE value.  */
> -  bool val_only;
> +  BOOL_BITFIELD val_only : 1;
>
>   /* True if we are currently walking the LHS of an assignment.  */
> -  bool is_lhs;
> +  BOOL_BITFIELD is_lhs : 1;
>
>   /* Optional.  Set to true by the callback functions if they made any
>      changes.  */
> -  bool changed;
> +  BOOL_BITFIELD changed : 1;
>
>   /* True if we're interested in location information.  */
> -  bool want_locations;
> +  BOOL_BITFIELD want_locations : 1;
>
> -  /* Operand returned by the callbacks.  This is set when calling
> -     walk_gimple_seq.  If the walk_stmt_fn or walk_tree_fn callback
> -     returns non-NULL, this field will contain the tree returned by
> -     the last callback.  */
> -  tree callback_result;
> +  /* True if we've removed the statement that was processed.  */
> +  BOOL_BITFIELD removed_stmt : 1;
>  };
>
>  /* Callback for walk_gimple_stmt.  Called for every statement found
>

Otherwise looks ok to me.

Richard.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-03 19:40 [patch] 19/n: trans-mem: compiler tree/gimple stuff Aldy Hernandez
  2011-11-04 10:44 ` Richard Guenther
@ 2011-11-04 15:40 ` Michael Matz
  2011-11-05  8:47   ` Aldy Hernandez
  1 sibling, 1 reply; 22+ messages in thread
From: Michael Matz @ 2011-11-04 15:40 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches

Hi,

On Thu, 3 Nov 2011, Aldy Hernandez wrote:

> +/* GIMPLE_EH_ELSE <N_BODY, E_BODY> must be the sole contents of
> +   a GIMPLE_TRY_FINALLY node.  For all normal exits from the try block,
> +   we N_BODY is run; for all exception exits from the try block,

s/we //

> +++ gcc/calls.c	(.../branches/transactional-memory)	(revision 180773)
> @@ -496,7 +496,60 @@ emit_call_1 (rtx funexp, tree fntree ATT
>  static int
>  special_function_p (const_tree fndecl, int flags)
>  {
> +	case BUILT_IN_TM_IRREVOCABLE:
> +	case BUILT_IN_TM_GETTMCLONE_IRR:
> +	case BUILT_IN_TM_MEMCPY:
> +	case BUILT_IN_TM_MEMMOVE:
> +        case BUILT_IN_TM_MEMSET:

Whitespace.

> @@ -1751,6 +1787,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
>        gcc_assert (tree_ret == NULL);
> 
>        /* Re-read stmt in case the callback changed it.  */
> +      if (wi && wi->removed_stmt)
> +	return NULL;
>        stmt = gsi_stmt (*gsi);

Comment belongs to the stmt assignment, not to the new if/return.

> @@ -3085,6 +3153,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;

The function get_call_expr_in is unused in our compiler (and you don't 
introduce a new use), so instead of amending it, just remove it.

> Index: gcc/gimple.h
> ===================================================================
> --- gcc/gimple.h	(.../trunk)	(revision 180744)
> +++ gcc/gimple.h	(.../branches/transactional-memory)	(revision
> 180773)
> @@ -105,6 +105,7 @@ enum gf_mask {
>      GF_CALL_NOTHROW		= 1 << 5,
>      GF_CALL_ALLOCA_FOR_VAR	= 1 << 6,
>      GF_CALL_INTERNAL		= 1 << 7,
> +    GF_CALL_NOINLINE		= 1 << 8,
>      GF_OMP_PARALLEL_COMBINED	= 1 << 0,
...
> +/* Return true if S is a noinline call.  */
> +
> +static inline bool
> +gimple_call_noinline_p (gimple s)
> +{
> +  GIMPLE_CHECK (s, GIMPLE_CALL);
> +  return (s->gsbase.subcode & GF_CALL_NOINLINE) != 0;
> +}
> +
> +static inline void
> +gimple_call_set_noinline_p (gimple s)
> +{
> +  GIMPLE_CHECK (s, GIMPLE_CALL);
> +  s->gsbase.subcode |= GF_CALL_NOINLINE;
> +}

This flag is only used by the new accessors gimple_call_noinline_p and 
gimple_call_set_noinline_p.  The latter is used in 
trans-mem.c:ipa_tm_insert_gettmclone_call, but marked as hack.  The flag 
isn't tested anywhere (i.e. no calls to gimple_call_noinline_p).  Hence 
this whole thing is unused, presumably the hack was transformed into a 
real solution :)  So, don't add the flag or the accessors, and remove the 
call from trans-mem.c.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-04 10:44 ` Richard Guenther
@ 2011-11-05  0:25   ` Aldy Hernandez
  2011-11-05  2:54     ` Richard Henderson
  2011-11-05  3:11   ` Richard Henderson
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-05  0:25 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Torvald Riegel

[-- Attachment #1: Type: text/plain, Size: 4337 bytes --]

Richard, I am going to address your suggestions in pieces, with 
individual patchsets, so we can tackle the less trivial bits in separate 
patches.  So don't worry, I'm not forgetting the rest your suggestions.

Below I will address what I fix with this patch.

>> +/* Nonzero in a FUNCTION_DECL means this function is the transactional
>> +   clone of a function - called only from inside transactions.  */
>> +#define DECL_IS_TM_CLONE(NODE) \
>> +  (FUNCTION_DECL_CHECK (NODE)->function_decl.tm_clone_flag)
>
> Why is it necessary to know whether a clone is a tm clone?

How do you mean?  First, there are a few pretty printing places where we 
dump that a function is a clone.  It is easy to debug dumps when you 
know which function is the clone and which is the original function, 
since we will dump both variants at code generation time.

Second, there is code in the TM lowering bits where we assert that we 
are not trying to lower TM clones ahead of time.  And there is a check 
in gate_tm_init() where we specify that the entire function is a TM 
region if it is a clone.

etc, etc.

Does this answer your question?

>> +static inline bool
>> +is_tm_safe_or_pure (tree x)
>
> const_tree
>
>> +{
>> +  return is_tm_safe (x) || is_tm_pure (x);
>> +}
>> +

Done.

> The above changes seem to belong to a different changeset and look
> strange.  Why would attributes ever appear in two different tables?

This was a recent patch by Torvald.  I will ask him, but nevertheless, I 
can submit this separately.

>> -static hashval_t
>> +hashval_t
>>   struct_ptr_hash (const void *a)
>>   {
>>    const void * const * x = (const void * const *) a;
>
> Rather than exporting those here consider moving them to a common
> header as inline functions.
>
>    const void * const * x = (const void * const *) a;
>    return (size_t)*x>>  4;
>
> and on the way change that to (intptr_t)*x>>  4

Done, done.

>> +&&  DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
>> +&&  DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_START
>> +      /* Check we're referring to Intel's TM specifications.  */
>> +&&  !strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)),
>> +                 "__builtin__ITM_beginTransaction")
>
> Huh.  Are there others that would use the same builtin?

Overly cautious.  Agreed, no need for this.  Removed.

>
>> +&&  gimple_call_num_args (gs)>  0
>> +      )
>
> ) goes to the previouys line.

Fixed.

>> +       case BUILT_IN_TM_LOG_M64:
>> +       case BUILT_IN_TM_LOG_M128:
>> +       case BUILT_IN_TM_LOG_M256:
>> +         flags |= ECF_TM_OPS;
>> +         break;
>> +       default:
>> +         break;
>> +       }
>> +    }
>
> This should not be in special_function_p which is solely to check
> for the identifiers.  Instead the caller of this function should handle
> the builtin codes (flags_from_decl_or_type).
>
>> +  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
>> @@ -644,6 +697,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;
>> +
>
> Thus, here.

Fixed.

> As you are changing features of this walker you should update its
> documentation.

Fixed.

>> -static const_tree
>> +const_tree
>>   strip_invariant_refs (const_tree op)
>>   {
>>    while (handled_component_p (op))
>
> If you export this please move it to tree.c.
>
>> @@ -3085,6 +3153,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;
>
> An unused function.  Please move it to where you need it instead,
> make it static and adjust it in a way to do exactly what you want.
> After the above change it looks strange - handling V_C_E but
> not other component refs.

I see no reference to this function anywhere in the compiler (including 
trans-mem.*).  I have removed this everywhere in the compiler

I am committing the following, after having bootstrapped and regtested 
all languages on x86-64.

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 12676 bytes --]

	* gimple.c (walk_gimple_seq): Document usage of removed_stmt
	field.
	(get_call_expr_in): Remove.
	(strip_invariant_refs): Move from here...
	* tree.c (strip_invariant_refs): ...to here.
	* gimple-pretty-print.c (dump_gimple_call): Remove explicit check
	for __builtin_ITM_beginTransaction identifier.
	* tree-eh.c (struct_ptr_eq): Make inline and move to tree.h.
	(struct_ptr_hash): Same.
	* gimple.h (get_call_expr_in): Remove prototype.
	(strip_invariant_refs): Move from here...
	* tree.h (strip_invariant_refs): ...to here.
	(is_tm_safe_or_pure): Make argument const_tree.
	* tree-inline.c (gimple_expand_calls_inline): Remove reference to
	get_call_expr_in in comment.

Index: tree.c
===================================================================
--- tree.c	(revision 180772)
+++ tree.c	(working copy)
@@ -11145,6 +11145,37 @@ tree_strip_sign_nop_conversions (tree ex
   return exp;
 }
 
+/* Strip out all handled components that produce invariant
+   offsets.  */
+
+const_tree
+strip_invariant_refs (const_tree op)
+{
+  while (handled_component_p (op))
+    {
+      switch (TREE_CODE (op))
+	{
+	case ARRAY_REF:
+	case ARRAY_RANGE_REF:
+	  if (!is_gimple_constant (TREE_OPERAND (op, 1))
+	      || TREE_OPERAND (op, 2) != NULL_TREE
+	      || TREE_OPERAND (op, 3) != NULL_TREE)
+	    return NULL;
+	  break;
+
+	case COMPONENT_REF:
+	  if (TREE_OPERAND (op, 2) != NULL_TREE)
+	    return NULL;
+	  break;
+
+	default:;
+	}
+      op = TREE_OPERAND (op, 0);
+    }
+
+  return op;
+}
+
 static GTY(()) tree gcc_eh_personality_decl;
 
 /* Return the GCC personality function decl.  */
Index: tree.h
===================================================================
--- tree.h	(revision 180772)
+++ tree.h	(working copy)
@@ -5193,6 +5193,7 @@ extern bool auto_var_in_fn_p (const_tree
 extern tree build_low_bits_mask (tree, unsigned);
 extern tree tree_strip_nop_conversions (tree);
 extern tree tree_strip_sign_nop_conversions (tree);
+extern const_tree strip_invariant_refs (const_tree);
 extern tree lhd_gcc_personality (void);
 extern void assign_assembler_name_if_neeeded (tree);
 extern void warn_deprecated_use (tree, tree);
@@ -5217,8 +5218,25 @@ extern void expand_return (tree);
 
 /* In tree-eh.c */
 extern void using_eh_for_cleanups (void);
-extern int struct_ptr_eq (const void *, const void *);
-extern hashval_t struct_ptr_hash (const void *);
+
+/* Compare and hash for any structure which begins with a canonical
+   pointer.  Assumes all pointers are interchangeable, which is sort
+   of already assumed by gcc elsewhere IIRC.  */
+
+static inline int
+struct_ptr_eq (const void *a, const void *b)
+{
+  const void * const * x = (const void * const *) a;
+  const void * const * y = (const void * const *) b;
+  return *x == *y;
+}
+
+static inline hashval_t
+struct_ptr_hash (const void *a)
+{
+  const void * const * x = (const void * const *) a;
+  return (intptr_t)*x >> 4;
+}
 
 /* In fold-const.c */
 
@@ -5864,7 +5882,7 @@ extern void record_tm_replacement (tree,
 extern void tm_malloc_replacement (tree);
 
 static inline bool
-is_tm_safe_or_pure (tree x)
+is_tm_safe_or_pure (const_tree x)
 {
   return is_tm_safe (x) || is_tm_pure (x);
 }
Index: tree-eh.c
===================================================================
--- tree-eh.c	(revision 180772)
+++ tree-eh.c	(working copy)
@@ -54,26 +54,6 @@ using_eh_for_cleanups (void)
 
 /* Misc functions used in this file.  */
 
-/* Compare and hash for any structure which begins with a canonical
-   pointer.  Assumes all pointers are interchangeable, which is sort
-   of already assumed by gcc elsewhere IIRC.  */
-
-int
-struct_ptr_eq (const void *a, const void *b)
-{
-  const void * const * x = (const void * const *) a;
-  const void * const * y = (const void * const *) b;
-  return *x == *y;
-}
-
-hashval_t
-struct_ptr_hash (const void *a)
-{
-  const void * const * x = (const void * const *) a;
-  return (size_t)*x >> 4;
-}
-
-
 /* Remember and lookup EH landing pad data for arbitrary statements.
    Really this means any statement that could_throw_p.  We could
    stuff this information into the stmt_ann data structure, but:
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c	(revision 180772)
+++ gimple-pretty-print.c	(working copy)
@@ -706,11 +706,7 @@ dump_gimple_call (pretty_printer *buffer
   if (TREE_CODE (fn) == FUNCTION_DECL
       && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
       && DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_START
-      /* Check we're referring to Intel's TM specifications.  */
-      && !strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)),
-		  "__builtin__ITM_beginTransaction")
-      && gimple_call_num_args (gs) > 0
-      )
+      && gimple_call_num_args (gs) > 0)
     {
       tree t = gimple_call_arg (gs, 0);
       unsigned HOST_WIDE_INT props;
Index: calls.c
===================================================================
--- calls.c	(revision 180772)
+++ calls.c	(working copy)
@@ -496,60 +496,7 @@ emit_call_1 (rtx funexp, tree fntree ATT
 static int
 special_function_p (const_tree fndecl, int flags)
 {
-  if (fndecl == NULL)
-    return flags;
-
-  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
-    {
-      switch (DECL_FUNCTION_CODE (fndecl))
-	{
-	case BUILT_IN_TM_COMMIT:
-	case BUILT_IN_TM_COMMIT_EH:
-	case BUILT_IN_TM_ABORT:
-	case BUILT_IN_TM_IRREVOCABLE:
-	case BUILT_IN_TM_GETTMCLONE_IRR:
-	case BUILT_IN_TM_MEMCPY:
-	case BUILT_IN_TM_MEMMOVE:
-        case BUILT_IN_TM_MEMSET:
-	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_STORE (LDOUBLE):
-	CASE_BUILT_IN_TM_STORE (M64):
-	CASE_BUILT_IN_TM_STORE (M128):
-	CASE_BUILT_IN_TM_STORE (M256):
-	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):
-	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
-	CASE_BUILT_IN_TM_LOAD (M64):
-	CASE_BUILT_IN_TM_LOAD (M128):
-	CASE_BUILT_IN_TM_LOAD (M256):
-	case BUILT_IN_TM_LOG:
-	case BUILT_IN_TM_LOG_1:
-	case BUILT_IN_TM_LOG_2:
-	case BUILT_IN_TM_LOG_4:
-	case BUILT_IN_TM_LOG_8:
-	case BUILT_IN_TM_LOG_FLOAT:
-	case BUILT_IN_TM_LOG_DOUBLE:
-	case BUILT_IN_TM_LOG_LDOUBLE:
-	case BUILT_IN_TM_LOG_M64:
-	case BUILT_IN_TM_LOG_M128:
-	case BUILT_IN_TM_LOG_M256:
-	  flags |= ECF_TM_OPS;
-	  break;
-	default:
-	  break;
-	}
-    }
-
-  if (DECL_NAME (fndecl)
+  if (fndecl && 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
@@ -664,6 +611,69 @@ alloca_call_p (const_tree exp)
   return false;
 }
 
+/* Return TRUE if FNDECL is either a TM builtin or a TM cloned
+   function.  Return FALSE otherwise.  */
+
+static bool
+is_tm_builtin (const_tree fndecl)
+{
+  if (fndecl == NULL)
+    return false;
+
+  if (DECL_IS_TM_CLONE (fndecl))
+    return true;
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      switch (DECL_FUNCTION_CODE (fndecl))
+	{
+	case BUILT_IN_TM_COMMIT:
+	case BUILT_IN_TM_COMMIT_EH:
+	case BUILT_IN_TM_ABORT:
+	case BUILT_IN_TM_IRREVOCABLE:
+	case BUILT_IN_TM_GETTMCLONE_IRR:
+	case BUILT_IN_TM_MEMCPY:
+	case BUILT_IN_TM_MEMMOVE:
+        case BUILT_IN_TM_MEMSET:
+	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_STORE (LDOUBLE):
+	CASE_BUILT_IN_TM_STORE (M64):
+	CASE_BUILT_IN_TM_STORE (M128):
+	CASE_BUILT_IN_TM_STORE (M256):
+	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):
+	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+	CASE_BUILT_IN_TM_LOAD (M64):
+	CASE_BUILT_IN_TM_LOAD (M128):
+	CASE_BUILT_IN_TM_LOAD (M256):
+	case BUILT_IN_TM_LOG:
+	case BUILT_IN_TM_LOG_1:
+	case BUILT_IN_TM_LOG_2:
+	case BUILT_IN_TM_LOG_4:
+	case BUILT_IN_TM_LOG_8:
+	case BUILT_IN_TM_LOG_FLOAT:
+	case BUILT_IN_TM_LOG_DOUBLE:
+	case BUILT_IN_TM_LOG_LDOUBLE:
+	case BUILT_IN_TM_LOG_M64:
+	case BUILT_IN_TM_LOG_M128:
+	case BUILT_IN_TM_LOG_M256:
+	  return true;
+	default:
+	  break;
+	}
+    }
+  return false;
+}
+
 /* Detect flags (function attributes) from the function decl or type node.  */
 
 int
@@ -697,7 +707,7 @@ flags_from_decl_or_type (const_tree exp)
       if (TREE_NOTHROW (exp))
 	flags |= ECF_NOTHROW;
 
-      if (DECL_IS_TM_CLONE (exp))
+      if (is_tm_builtin (exp))
 	flags |= ECF_TM_OPS;
 
       flags = special_function_p (exp, flags);
Index: tree-inline.c
===================================================================
--- tree-inline.c	(revision 180772)
+++ tree-inline.c	(working copy)
@@ -4054,9 +4054,7 @@ expand_call_inline (basic_block bb, gimp
 
 /* Expand call statements reachable from STMT_P.
    We can only have CALL_EXPRs as the "toplevel" tree code or nested
-   in a MODIFY_EXPR.  See gimple.c:get_call_expr_in().  We can
-   unfortunately not use that function here because we need a pointer
-   to the CALL_EXPR, not the tree itself.  */
+   in a MODIFY_EXPR.  */
 
 static bool
 gimple_expand_calls_inline (basic_block bb, copy_body_data *id)
Index: gimple.c
===================================================================
--- gimple.c	(revision 180772)
+++ gimple.c	(working copy)
@@ -1341,9 +1341,11 @@ gimple_seq_copy (gimple_seq src)
 /* Walk all the statements in the sequence SEQ calling walk_gimple_stmt
    on each one.  WI is as in walk_gimple_stmt.
 
-   If walk_gimple_stmt returns non-NULL, the walk is stopped, the
-   value is stored in WI->CALLBACK_RESULT and the statement that
-   produced the value is returned.
+   If walk_gimple_stmt returns non-NULL, the walk is stopped, and the
+   value is stored in WI->CALLBACK_RESULT.  Also, the statement that
+   produced the value is returned if this statement has not been
+   removed by a callback (wi->removed_stmt).  If the statement has
+   been removed, NULL is returned.
 
    Otherwise, all the statements are walked and NULL returned.  */
 
@@ -2850,37 +2852,6 @@ is_gimple_address (const_tree t)
     }
 }
 
-/* Strip out all handled components that produce invariant
-   offsets.  */
-
-const_tree
-strip_invariant_refs (const_tree op)
-{
-  while (handled_component_p (op))
-    {
-      switch (TREE_CODE (op))
-	{
-	case ARRAY_REF:
-	case ARRAY_RANGE_REF:
-	  if (!is_gimple_constant (TREE_OPERAND (op, 1))
-	      || TREE_OPERAND (op, 2) != NULL_TREE
-	      || TREE_OPERAND (op, 3) != NULL_TREE)
-	    return NULL;
-	  break;
-
-	case COMPONENT_REF:
-	  if (TREE_OPERAND (op, 2) != NULL_TREE)
-	    return NULL;
-	  break;
-
-	default:;
-	}
-      op = TREE_OPERAND (op, 0);
-    }
-
-  return op;
-}
-
 /* Return true if T is a gimple invariant address.  */
 
 bool
@@ -3143,23 +3114,6 @@ is_gimple_mem_ref_addr (tree t)
 		  || decl_address_invariant_p (TREE_OPERAND (t, 0)))));
 }
 
-/* If T makes a function call, return the corresponding CALL_EXPR operand.
-   Otherwise, return NULL_TREE.  */
-
-tree
-get_call_expr_in (tree t)
-{
-  if (TREE_CODE (t) == MODIFY_EXPR)
-    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;
-}
-
 
 /* Given a memory reference expression T, return its base address.
    The base address of a memory reference expression is the main
Index: gimple.h
===================================================================
--- gimple.h	(revision 180772)
+++ gimple.h	(working copy)
@@ -1015,8 +1015,6 @@ extern bool is_gimple_non_addressable (t
 
 /* Returns true iff T is a valid call address expression.  */
 extern bool is_gimple_call_addr (tree);
-/* If T makes a function call, returns the CALL_EXPR operand.  */
-extern tree get_call_expr_in (tree t);
 
 extern void recalculate_side_effects (tree);
 extern bool gimple_compare_field_offset (tree, tree);
@@ -1037,7 +1035,6 @@ extern bool walk_stmt_load_store_ops (gi
 				      bool (*)(gimple, tree, void *),
 				      bool (*)(gimple, tree, void *));
 extern bool gimple_ior_addresses_taken (bitmap, gimple);
-extern const_tree strip_invariant_refs (const_tree);
 extern bool gimple_call_builtin_p (gimple, enum built_in_function);
 extern bool gimple_asm_clobbers_memory_p (const_gimple);
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05  0:25   ` Aldy Hernandez
@ 2011-11-05  2:54     ` Richard Henderson
  2011-11-05  9:11       ` Richard Guenther
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Henderson @ 2011-11-05  2:54 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Guenther, gcc-patches, Torvald Riegel

On 11/04/2011 04:53 PM, Aldy Hernandez wrote:
>> Why is it necessary to know whether a clone is a tm clone?
> 
> How do you mean?  First, there are a few pretty printing places where we dump that a function is a clone.  It is easy to debug dumps when you know which function is the clone and which is the original function, since we will dump both variants at code generation time.
> 
> Second, there is code in the TM lowering bits where we assert that we are not trying to lower TM clones ahead of time.  And there is a check in gate_tm_init() where we specify that the entire function is a TM region if it is a clone.
> 
> etc, etc.
> 
> Does this answer your question?

Richi, if it's the use of the bit in the tree node that you're worried about,
we could probably put it in cgraph_node.local instead.  But we do need the 
knowledge.


r~

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-04 10:44 ` Richard Guenther
  2011-11-05  0:25   ` Aldy Hernandez
@ 2011-11-05  3:11   ` Richard Henderson
  2011-11-05  3:23     ` Richard Henderson
  2011-11-05 21:26   ` Aldy Hernandez
  2011-11-06  0:51   ` Aldy Hernandez
  3 siblings, 1 reply; 22+ messages in thread
From: Richard Henderson @ 2011-11-05  3:11 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Aldy Hernandez, gcc-patches

On 11/04/2011 03:36 AM, Richard Guenther wrote:
>> > +    case GIMPLE_TRANSACTION:
>> > +      return (weights->tm_cost
>> > +             + estimate_num_insns_seq (gimple_transaction_body (stmt),
>> > +                                       weights));
>> > +
> Huh, so we now have non-lowered gimple sub-sequence throughout all
> optimizations (inlining especially)?  :(

No.  I'm not sure why we're still looking at gimple_transaction_body
here -- that should be NULL after lowering.


r~

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05  3:11   ` Richard Henderson
@ 2011-11-05  3:23     ` Richard Henderson
  2011-11-05 10:18       ` Richard Guenther
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Henderson @ 2011-11-05  3:23 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Aldy Hernandez, gcc-patches

On 11/04/2011 07:36 PM, Richard Henderson wrote:
> On 11/04/2011 03:36 AM, Richard Guenther wrote:
>>>> +    case GIMPLE_TRANSACTION:
>>>> +      return (weights->tm_cost
>>>> +             + estimate_num_insns_seq (gimple_transaction_body (stmt),
>>>> +                                       weights));
>>>> +
>> Huh, so we now have non-lowered gimple sub-sequence throughout all
>> optimizations (inlining especially)?  :(
> 
> No.  I'm not sure why we're still looking at gimple_transaction_body
> here -- that should be NULL after lowering.

... of course, I'm not sure why we're looking at all those other
nested statements there inside the inliner either.  At least we're
doing the same thing as everyone else here.


r~

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-04 15:40 ` Michael Matz
@ 2011-11-05  8:47   ` Aldy Hernandez
  0 siblings, 0 replies; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-05  8:47 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2177 bytes --]

On 11/04/11 08:26, Michael Matz wrote:
> Hi,
>
> On Thu, 3 Nov 2011, Aldy Hernandez wrote:
>
>> +/* GIMPLE_EH_ELSE<N_BODY, E_BODY>  must be the sole contents of
>> +   a GIMPLE_TRY_FINALLY node.  For all normal exits from the try block,
>> +   we N_BODY is run; for all exception exits from the try block,
>
> s/we //
Fixed

>
>> +++ gcc/calls.c	(.../branches/transactional-memory)	(revision 180773)
>> @@ -496,7 +496,60 @@ emit_call_1 (rtx funexp, tree fntree ATT
>>   static int
>>   special_function_p (const_tree fndecl, int flags)
>>   {
>> +	case BUILT_IN_TM_IRREVOCABLE:
>> +	case BUILT_IN_TM_GETTMCLONE_IRR:
>> +	case BUILT_IN_TM_MEMCPY:
>> +	case BUILT_IN_TM_MEMMOVE:
>> +        case BUILT_IN_TM_MEMSET:
>
> Whitespace.
Fixed

>
>> @@ -1751,6 +1787,8 @@ walk_gimple_stmt (gimple_stmt_iterator *
>>         gcc_assert (tree_ret == NULL);
>>
>>         /* Re-read stmt in case the callback changed it.  */
>> +      if (wi&&  wi->removed_stmt)
>> +	return NULL;
>>         stmt = gsi_stmt (*gsi);
>
> Comment belongs to the stmt assignment, not to the new if/return.
Fixed

>
>> @@ -3085,6 +3153,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;
>
> The function get_call_expr_in is unused in our compiler (and you don't
> introduce a new use), so instead of amending it, just remove it.
Fixed in previous patch.

>> +    GF_CALL_NOINLINE		= 1<<  8,

> This flag is only used by the new accessors gimple_call_noinline_p and
> gimple_call_set_noinline_p.  The latter is used in
> trans-mem.c:ipa_tm_insert_gettmclone_call, but marked as hack.  The flag
> isn't tested anywhere (i.e. no calls to gimple_call_noinline_p).  Hence
> this whole thing is unused, presumably the hack was transformed into a
> real solution :)  So, don't add the flag or the accessors, and remove the
> call from trans-mem.c.

Excellent catch!  Thanks so much.  Fixed.

The attached patch has been bootstrapped and regtested on x86-64 Linux.

Committing to branch.

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 3572 bytes --]

        * trans-mem.c (ipa_tm_insert_gettmclone_call): Remove call to
	gimple_call_set_noinline_p.
	* gimple.h (enum gf_mask): Remove GF_CALL_NOINLINE.
	(gimple_call_noinline_p): Remove.
	(gimple_call_set_noinline_p): Remove.
	* gimple.c (walk_gimple_stmt): Move comment down.
	* calls.c (is_tm_builtin): Fix whitespace problem.
	* gimple.def (GIMPLE_EH_ELSE): Fix typo in comment.

Index: gimple.def
===================================================================
--- gimple.def	(revision 180974)
+++ gimple.def	(working copy)
@@ -161,7 +161,7 @@ DEFGSCODE(GIMPLE_EH_MUST_NOT_THROW, "gim
 
 /* GIMPLE_EH_ELSE <N_BODY, E_BODY> must be the sole contents of
    a GIMPLE_TRY_FINALLY node.  For all normal exits from the try block,
-   we N_BODY is run; for all exception exits from the try block,
+   N_BODY is run; for all exception exits from the try block,
    E_BODY is run.  */
 DEFGSCODE(GIMPLE_EH_ELSE, "gimple_eh_else", GSS_EH_ELSE)
 
Index: trans-mem.c
===================================================================
--- trans-mem.c	(revision 180974)
+++ trans-mem.c	(working copy)
@@ -4367,12 +4367,6 @@ ipa_tm_insert_gettmclone_call (struct cg
   if (gimple_call_nothrow_p (stmt))
     gimple_call_set_nothrow (stmt, true);
 
-  /* ??? This is a hack to prevent tree-eh.c inlineable_call_p from
-     deciding that the indirect call we have after this transformation
-     might be inlinable, and thus changing the value of can_throw_internal,
-     and thus requiring extra EH edges.  */
-  gimple_call_set_noinline_p (stmt);
-
   gimple_call_set_fn (stmt, callfn);
 
   /* Discarding OBJ_TYPE_REF above may produce incompatible LHS and RHS
Index: calls.c
===================================================================
--- calls.c	(revision 181004)
+++ calls.c	(working copy)
@@ -634,7 +634,7 @@ is_tm_builtin (const_tree fndecl)
 	case BUILT_IN_TM_GETTMCLONE_IRR:
 	case BUILT_IN_TM_MEMCPY:
 	case BUILT_IN_TM_MEMMOVE:
-        case BUILT_IN_TM_MEMSET:
+	case BUILT_IN_TM_MEMSET:
 	CASE_BUILT_IN_TM_STORE (1):
 	CASE_BUILT_IN_TM_STORE (2):
 	CASE_BUILT_IN_TM_STORE (4):
Index: gimple.c
===================================================================
--- gimple.c	(revision 181004)
+++ gimple.c	(working copy)
@@ -1788,9 +1788,10 @@ walk_gimple_stmt (gimple_stmt_iterator *
 	 a value to return.  */
       gcc_assert (tree_ret == NULL);
 
-      /* Re-read stmt in case the callback changed it.  */
       if (wi && wi->removed_stmt)
 	return NULL;
+
+      /* Re-read stmt in case the callback changed it.  */
       stmt = gsi_stmt (*gsi);
     }
 
Index: gimple.h
===================================================================
--- gimple.h	(revision 181004)
+++ gimple.h	(working copy)
@@ -105,7 +105,6 @@ enum gf_mask {
     GF_CALL_NOTHROW		= 1 << 5,
     GF_CALL_ALLOCA_FOR_VAR	= 1 << 6,
     GF_CALL_INTERNAL		= 1 << 7,
-    GF_CALL_NOINLINE		= 1 << 8,
     GF_OMP_PARALLEL_COMBINED	= 1 << 0,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
@@ -2490,22 +2489,6 @@ gimple_call_alloca_for_var_p (gimple s)
   return (s->gsbase.subcode & GF_CALL_ALLOCA_FOR_VAR) != 0;
 }
 
-/* Return true if S is a noinline call.  */
-
-static inline bool
-gimple_call_noinline_p (gimple s)
-{
-  GIMPLE_CHECK (s, GIMPLE_CALL);
-  return (s->gsbase.subcode & GF_CALL_NOINLINE) != 0;
-}
-
-static inline void
-gimple_call_set_noinline_p (gimple s)
-{
-  GIMPLE_CHECK (s, GIMPLE_CALL);
-  s->gsbase.subcode |= GF_CALL_NOINLINE;
-}
-
 /* Copy all the GF_CALL_* flags from ORIG_CALL to DEST_CALL.  */
 
 static inline void

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05  2:54     ` Richard Henderson
@ 2011-11-05  9:11       ` Richard Guenther
  2011-11-05 18:14         ` Aldy Hernandez
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Guenther @ 2011-11-05  9:11 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches, Torvald Riegel

On Sat, Nov 5, 2011 at 3:24 AM, Richard Henderson <rth@redhat.com> wrote:
> On 11/04/2011 04:53 PM, Aldy Hernandez wrote:
>>> Why is it necessary to know whether a clone is a tm clone?
>>
>> How do you mean?  First, there are a few pretty printing places where we dump that a function is a clone.  It is easy to debug dumps when you know which function is the clone and which is the original function, since we will dump both variants at code generation time.
>>
>> Second, there is code in the TM lowering bits where we assert that we are not trying to lower TM clones ahead of time.  And there is a check in gate_tm_init() where we specify that the entire function is a TM region if it is a clone.
>>
>> etc, etc.
>>
>> Does this answer your question?
>
> Richi, if it's the use of the bit in the tree node that you're worried about,
> we could probably put it in cgraph_node.local instead.  But we do need the
> knowledge.

Yeah, I was worried about /* 1 bit left */ ;)  Putting it in the
cgraph node sounds more appealing
indeed.

Thanks,
Richard.

>
> r~
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05  3:23     ` Richard Henderson
@ 2011-11-05 10:18       ` Richard Guenther
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Guenther @ 2011-11-05 10:18 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches

On Sat, Nov 5, 2011 at 3:54 AM, Richard Henderson <rth@redhat.com> wrote:
> On 11/04/2011 07:36 PM, Richard Henderson wrote:
>> On 11/04/2011 03:36 AM, Richard Guenther wrote:
>>>>> +    case GIMPLE_TRANSACTION:
>>>>> +      return (weights->tm_cost
>>>>> +             + estimate_num_insns_seq (gimple_transaction_body (stmt),
>>>>> +                                       weights));
>>>>> +
>>> Huh, so we now have non-lowered gimple sub-sequence throughout all
>>> optimizations (inlining especially)?  :(
>>
>> No.  I'm not sure why we're still looking at gimple_transaction_body
>> here -- that should be NULL after lowering.
> ... of course, I'm not sure why we're looking at all those other
> nested statements there inside the inliner either.  At least we're
> doing the same thing as everyone else here.

It might be because of nested function lowering which works on
gimple like it falls out of the gimplifier.  So it might all be correct
after all ...

Sorry for the noise.

Richard.

>
> r~
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05  9:11       ` Richard Guenther
@ 2011-11-05 18:14         ` Aldy Hernandez
  2011-11-05 23:03           ` Richard Guenther
  0 siblings, 1 reply; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-05 18:14 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Richard Henderson, gcc-patches, Torvald Riegel


>> Richi, if it's the use of the bit in the tree node that you're worried about,
>> we could probably put it in cgraph_node.local instead.  But we do need the
>> knowledge.
>
> Yeah, I was worried about /* 1 bit left */ ;)  Putting it in the
> cgraph node sounds more appealing
> indeed.


Richi, is this a blocker, or merely a suggestion?  If this is a 
requirement for merging, I can do so.  Just want to make sure where best 
to spend my time.

If this is a suggestion, I can put it on my laundry list of future 
things todo (after merge, 4.8?, etc).

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-04 10:44 ` Richard Guenther
  2011-11-05  0:25   ` Aldy Hernandez
  2011-11-05  3:11   ` Richard Henderson
@ 2011-11-05 21:26   ` Aldy Hernandez
  2011-11-05 23:16     ` Richard Guenther
  2011-11-06  0:51   ` Aldy Hernandez
  3 siblings, 1 reply; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-05 21:26 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Richard Henderson

[rth, see below]

>>    local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
>>                         "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW |
>> ECF_LEAF);
>> +  if (flag_tm)
>> +    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
>> +                  get_identifier ("transaction_pure"));
>
> I think this should use a new ECF_TM_PURE flag, unconditionally set
> with handling in the functions that handle/return ECF flags so that
> transitioning this to a tree node flag instead of an attribute is easier.

I could add a ECF_TM_PURE flag and attach it to the BUILT_IN_EH_POINTER 
in the local_define_builtin above, but we still need the attribute for 
function decl's as in:

__attribute__((transaction_pure)) void foo();

Attributes seem like a clean way to approach this.

I don't see what the flag buys us.  Or am I misunderstanding something?

>> +/* Nonzero if this call performs a transactional memory operation.  */
>> +#define ECF_TM_OPS               (1<<  11)
>
> What's this flag useful for?  Isn't it the case that you want to conservatively
> know whether a call might perform a tm operation?  Thus, the flag
> should be inverted?  Is this the same as "TM pure"?

Richard?

>> +    case GIMPLE_TRANSACTION:
>> +      return (weights->tm_cost
>> +             + estimate_num_insns_seq (gimple_transaction_body (stmt),
>> +                                       weights));
>> +
>
> Huh, so we now have non-lowered gimple sub-sequence throughout all
> optimizations (inlining especially)?  :(

Richard addressed this elsewhere.

> I think I miss tree-cfg.c parts that do any verification of the new gimple
> kinds.

Yes, they're there.  I see you commented on them in the middle/end 
patch.  I will fix the issues you brought up on that thread.

> ?  Why not use GF_CALL_CANNOT_INLINE?

As per Michael Matz's suggestion, I have removed all reference to this 
unused flag.

>> +static inline void
>> +gimple_call_set_noinline_p (gimple s)
>> +{
>> +  GIMPLE_CHECK (s, GIMPLE_CALL);
>> +  s->gsbase.subcode |= GF_CALL_NOINLINE;
>> +}
>
> See above.  We have *_cannot_inline already.

Similarly here.

Richi, I have fixed or addressed all the issues in this thread, with the 
exception of your EFC_TM_PURE and ECF_TM_OPS questions, which I am 
deferring to rth and then fixing if required.  I will now go through the 
middle-end thread (which erroneously also prefixed with [patch] 19/n...).

Aldy

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05 18:14         ` Aldy Hernandez
@ 2011-11-05 23:03           ` Richard Guenther
  2011-11-06 10:10             ` Aldy Hernandez
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Guenther @ 2011-11-05 23:03 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Henderson, gcc-patches, Torvald Riegel

On Sat, Nov 5, 2011 at 4:09 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>>> Richi, if it's the use of the bit in the tree node that you're worried
>>> about,
>>> we could probably put it in cgraph_node.local instead.  But we do need
>>> the
>>> knowledge.
>>
>> Yeah, I was worried about /* 1 bit left */ ;)  Putting it in the
>> cgraph node sounds more appealing
>> indeed.
>
>
> Richi, is this a blocker, or merely a suggestion?  If this is a requirement
> for merging, I can do so.  Just want to make sure where best to spend my
> time.

Well - we usually don't grab bits off the tree nodes lightly.  Especially if
the cgraph seems to be more fit.

> If this is a suggestion, I can put it on my laundry list of future things
> todo (after merge, 4.8?, etc).

There are not many consumers of the flag, so fixing it shouldn't be hard.
For 4.7 definitely.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05 21:26   ` Aldy Hernandez
@ 2011-11-05 23:16     ` Richard Guenther
  2011-11-07 19:06       ` Richard Henderson
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Guenther @ 2011-11-05 23:16 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches, Richard Henderson

On Sat, Nov 5, 2011 at 10:05 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
> [rth, see below]
>
>>>   local_define_builtin ("__builtin_eh_pointer", ftype,
>>> BUILT_IN_EH_POINTER,
>>>                        "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW |
>>> ECF_LEAF);
>>> +  if (flag_tm)
>>> +    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
>>> +                  get_identifier ("transaction_pure"));
>>
>> I think this should use a new ECF_TM_PURE flag, unconditionally set
>> with handling in the functions that handle/return ECF flags so that
>> transitioning this to a tree node flag instead of an attribute is easier.
>
> I could add a ECF_TM_PURE flag and attach it to the BUILT_IN_EH_POINTER in
> the local_define_builtin above, but we still need the attribute for function
> decl's as in:
>
> __attribute__((transaction_pure)) void foo();
>
> Attributes seem like a clean way to approach this.

The middle-end interfacing is supposed to be via ECF_ flags, the user interface
via attributes.  What's the semantic of transaction-pure vs. ...

> I don't see what the flag buys us.  Or am I misunderstanding something?
>
>>> +/* Nonzero if this call performs a transactional memory operation.  */
>>> +#define ECF_TM_OPS               (1<<  11)
>>
>> What's this flag useful for?  Isn't it the case that you want to
>> conservatively
>> know whether a call might perform a tm operation?  Thus, the flag
>> should be inverted?  Is this the same as "TM pure"?

... this?

> Richard?

> Richi, I have fixed or addressed all the issues in this thread, with the
> exception of your EFC_TM_PURE and ECF_TM_OPS questions, which I am deferring
> to rth and then fixing if required.

Yeah, seems to be still an open question.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-04 10:44 ` Richard Guenther
                     ` (2 preceding siblings ...)
  2011-11-05 21:26   ` Aldy Hernandez
@ 2011-11-06  0:51   ` Aldy Hernandez
  2011-11-06 10:17     ` Richard Guenther
  3 siblings, 1 reply; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-06  0:51 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, Richard Henderson

[-- Attachment #1: Type: text/plain, Size: 2401 bytes --]

[rth, see below]

>> Index: gcc/attribs.c
>> ===================================================================
>> --- gcc/attribs.c       (.../trunk)     (revision 180744)
>> +++ gcc/attribs.c       (.../branches/transactional-memory)     (revision
>> 180773)
>> @@ -166,7 +166,8 @@ init_attributes (void)
>>           gcc_assert (strcmp (attribute_tables[i][j].name,
>>                               attribute_tables[i][k].name));
>>      }
>> -  /* Check that no name occurs in more than one table.  */
>> +  /* Check that no name occurs in more than one table.  Names that
>> +     begin with '*' are exempt, and may be overridden.  */
>>    for (i = 0; i<  ARRAY_SIZE (attribute_tables); i++)
>>      {
>>        size_t j, k, l;
>> @@ -174,8 +175,9 @@ init_attributes (void)
>>        for (j = i + 1; j<  ARRAY_SIZE (attribute_tables); j++)
>>         for (k = 0; attribute_tables[i][k].name != NULL; k++)
>>           for (l = 0; attribute_tables[j][l].name != NULL; l++)
>> -           gcc_assert (strcmp (attribute_tables[i][k].name,
>> -                               attribute_tables[j][l].name));
>> +           gcc_assert (attribute_tables[i][k].name[0] == '*'
>> +                       || strcmp (attribute_tables[i][k].name,
>> +                                  attribute_tables[j][l].name));
>>      }
>>   #endif
>>
>> @@ -207,7 +209,7 @@ register_attribute (const struct attribu
>>    slot = htab_find_slot_with_hash (attribute_hash,&str,
>>                                    substring_hash (str.str, str.length),
>>                                    INSERT);
>> -  gcc_assert (!*slot);
>> +  gcc_assert (!*slot || attr->name[0] == '*');
>>    *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
>>   }
>
> The above changes seem to belong to a different changeset and look
> strange.  Why would attributes ever appear in two different tables?

I couldn't find a corresponding gcc-patches message for this patch, but 
I was able to hunt down full the patch, which I am attaching for discussion.

This seems to be a change required for allowing '*' to override 
builtins, so it is indeed part of the branch.  Perhaps with the full 
context it is easier to review.

I will defer to rth to answer any questions on the original motivation.

Richi, do you have any particular issue with the attribs.c change?  Does 
this context resolve any questions you may have had?

Aldy

[-- Attachment #2: x --]
[-- Type: text/plain, Size: 12093 bytes --]

Index: ChangeLog.tm
===================================================================
--- ChangeLog.tm	(revision 149303)
+++ ChangeLog.tm	(revision 149304)
@@ -1,3 +1,17 @@
+2009-07-06  Richard Henderson  <rth@redhat.com>
+
+	* attribs.c (init_attributes): Allow '*' prefix for overrides.
+	(register_attribute): Likewise.
+	* builtin-attrs.def (ATTR_TM_REGPARM): New.
+	(ATTR_TM_NOTHROW_LIST, ATTR_TM_NORETURN_NOTHROW_LIST,
+	ATTR_TM_NOTHROW_NONNULL, ATTR_TM_CONST_NOTHROW_LIST,
+	ATTR_TM_PURE_NOTHROW_LIST): New.
+	* c-common.c (ignore_attribute): New.
+	(c_common_attribute_table): Add "*tm regparm".
+
+	* config/i386/i386.c (ix86_handle_tm_regparm_attribute): New.
+	(ix86_attribute_table): Add "*tm regparm".
+
 2009-07-02  Richard Henderson  <rth@redhat.com>
 
 	* c-typeck.c (c_finish_tm_atomic): Use build_stmt.
Index: attribs.c
===================================================================
--- attribs.c	(revision 149303)
+++ attribs.c	(revision 149304)
@@ -166,7 +166,8 @@ init_attributes (void)
 	  gcc_assert (strcmp (attribute_tables[i][j].name,
 			      attribute_tables[i][k].name));
     }
-  /* Check that no name occurs in more than one table.  */
+  /* Check that no name occurs in more than one table.  Names that
+     begin with '*' are exempt, and may be overridden.  */
   for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       size_t j, k, l;
@@ -174,8 +175,9 @@ init_attributes (void)
       for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
 	for (k = 0; attribute_tables[i][k].name != NULL; k++)
 	  for (l = 0; attribute_tables[j][l].name != NULL; l++)
-	    gcc_assert (strcmp (attribute_tables[i][k].name,
-				attribute_tables[j][l].name));
+	    gcc_assert (attribute_tables[i][k].name[0] == '*'
+			|| strcmp (attribute_tables[i][k].name,
+				   attribute_tables[j][l].name));
     }
 #endif
 
@@ -202,7 +204,7 @@ register_attribute (const struct attribu
   slot = htab_find_slot_with_hash (attribute_hash, &str,
 				   substring_hash (str.str, str.length),
 				   INSERT);
-  gcc_assert (!*slot);
+  gcc_assert (!*slot || attr->name[0] == '*');
   *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
 }
 
Index: builtin-attrs.def
===================================================================
--- builtin-attrs.def	(revision 149303)
+++ builtin-attrs.def	(revision 149304)
@@ -94,6 +94,7 @@ 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_TM_REGPARM, "*tm regparm")
 
 DEF_ATTR_TREE_LIST (ATTR_NOVOPS_LIST, ATTR_NOVOPS, ATTR_NULL, ATTR_NULL)
 
@@ -192,6 +193,19 @@ DEF_FORMAT_ATTRIBUTE_NOTHROW(STRFMON,3,3
 #undef DEF_FORMAT_ATTRIBUTE_NOTHROW
 #undef DEF_FORMAT_ATTRIBUTE_BOTH
 
+/* Transactional memory variants of the above.  */
+
+DEF_ATTR_TREE_LIST (ATTR_TM_NOTHROW_LIST,
+		    ATTR_TM_REGPARM, ATTR_NULL, ATTR_NOTHROW_LIST)
+DEF_ATTR_TREE_LIST (ATTR_TM_NORETURN_NOTHROW_LIST,
+		    ATTR_TM_REGPARM, ATTR_NULL, ATTR_NORETURN_NOTHROW_LIST)
+DEF_ATTR_TREE_LIST (ATTR_TM_NOTHROW_NONNULL,
+		    ATTR_TM_REGPARM, ATTR_NULL, ATTR_NOTHROW_NONNULL)
+DEF_ATTR_TREE_LIST (ATTR_TM_CONST_NOTHROW_LIST,
+		    ATTR_TM_REGPARM, ATTR_NULL, ATTR_CONST_NOTHROW_LIST)
+DEF_ATTR_TREE_LIST (ATTR_TM_PURE_NOTHROW_LIST,
+		    ATTR_TM_REGPARM, ATTR_NULL, ATTR_PURE_NOTHROW_LIST)
+
 /* Construct a tree for a format_arg attribute.  */
 #define DEF_FORMAT_ARG_ATTRIBUTE(FA)					\
   DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_##FA, ATTR_FORMAT_ARG,		\
Index: testsuite/gcc.dg/tm/indirect-1.c
===================================================================
--- testsuite/gcc.dg/tm/indirect-1.c	(revision 0)
+++ testsuite/gcc.dg/tm/indirect-1.c	(revision 149304)
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm" } */
+
+void foo(void (*fn)(void))
+{
+  __tm_atomic {
+    fn();
+  }
+}
Index: except.c
===================================================================
--- except.c	(revision 149303)
+++ except.c	(revision 149304)
@@ -2895,13 +2895,18 @@ remove_eh_handler_and_replace (struct eh
     }
 }
 
-/* Splice REGION from the region tree and replace it by the outer region
-   etc.  */
+/* Splice REGION from the region tree and replace it by an outer region.  */
 
 static void
 remove_eh_handler (struct eh_region_d *region)
 {
-  remove_eh_handler_and_replace (region, region->outer, true);
+  struct eh_region_d *outer;
+
+  for (outer = region->outer; outer; outer = outer->outer)
+    if (outer->type != ERT_TRANSACTION)
+      break;
+
+  remove_eh_handler_and_replace (region, outer, true);
 }
 
 /* Remove Eh region R that has turned out to have no code in its handler.  */
Index: c-common.c
===================================================================
--- c-common.c	(revision 149303)
+++ c-common.c	(revision 149304)
@@ -530,6 +530,7 @@ static tree handle_type_generic_attribut
 static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 static tree handle_target_attribute (tree *, tree, tree, int, bool *);
 static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
+static tree ignore_attribute (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -830,6 +831,10 @@ const struct attribute_spec c_common_att
 			      handle_target_attribute },
   { "optimize",               1, -1, true, false, false,
 			      handle_optimize_attribute },
+  /* For internal use only.  The leading '*' both prevents its usage in
+     source code and signals that it may be overridden by machine tables.  */
+  { "*tm regparm",	      0, 0, false, true, true,
+                              ignore_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -7865,6 +7870,19 @@ handle_optimize_attribute (tree *node, t
 
   return NULL_TREE;
 }
+
+/* Ignore the given attribute.  Used when this attribute may be usefully
+   overridden by the target, but is not used generically.  */
+
+static tree
+ignore_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args),
+		  int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  *no_add_attrs = true;
+  return NULL_TREE;
+}
+
+
 \f
 /* Check for valid arguments being passed to a function.
    ATTRS is a list of attributes.  There are NARGS arguments in the array
Index: gtm-builtins.def
===================================================================
--- gtm-builtins.def	(revision 149303)
+++ gtm-builtins.def	(revision 149304)
@@ -1,49 +1,49 @@
 DEF_TM_BUILTIN (BUILT_IN_TM_START, "_ITM_beginTransaction",
-		BT_FN_UINT_UINT, ATTR_NOTHROW_LIST)
+		BT_FN_UINT_UINT, ATTR_TM_NOTHROW_LIST)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_COMMIT, "_ITM_commitTransaction",
-		BT_FN_VOID, ATTR_NOTHROW_LIST)
+		BT_FN_VOID, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_ABORT, "_ITM_abortTransaction",
-		BT_FN_INT, ATTR_NORETURN_NOTHROW_LIST)
+		BT_FN_INT, ATTR_TM_NORETURN_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_IRREVOKABLE, "_ITM_changeTransactionMode",
-		BT_FN_INT, ATTR_NOTHROW_LIST)
+		BT_FN_INT, ATTR_TM_NOTHROW_LIST)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_MEMCPY, "_ITM_memcpyRtWt",
-		BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL)
+		BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_TM_NOTHROW_NONNULL)
 DEF_TM_BUILTIN (BUILT_IN_TM_MEMMOVE, "_ITM_memmoveRtWt",
-		BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL)
+		BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_TM_NOTHROW_NONNULL)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_GETTMCLONE_IRR, "_ITM_getTMCloneOrIrrevokable",
-		BT_FN_PTR_PTR, ATTR_NOTHROW_NONNULL)
+		BT_FN_PTR_PTR, ATTR_TM_NOTHROW_NONNULL)
 DEF_TM_BUILTIN (BUILT_IN_TM_GETTMCLONE_SAFE, "_ITM_getTMCloneSafe",
-		BT_FN_PTR_PTR, ATTR_CONST_NOTHROW_LIST)
+		BT_FN_PTR_PTR, ATTR_TM_CONST_NOTHROW_LIST)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_1, "_ITM_WU1",
-		BT_FN_VOID_VPTR_I1, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_I1, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_2, "_ITM_WU2",
-		BT_FN_VOID_VPTR_I2, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_I2, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_4, "_ITM_WU4",
-		BT_FN_VOID_VPTR_I4, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_I4, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_8, "_ITM_WU8",
-		BT_FN_VOID_VPTR_I8, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_I8, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_FLOAT, "_ITM_WF",
-		BT_FN_VOID_VPTR_FLOAT, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_FLOAT, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_DOUBLE, "_ITM_WD",
-		BT_FN_VOID_VPTR_DOUBLE, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_DOUBLE, ATTR_TM_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_STORE_LDOUBLE, "_ITM_WE",
-		BT_FN_VOID_VPTR_LDOUBLE, ATTR_NOTHROW_LIST)
+		BT_FN_VOID_VPTR_LDOUBLE, ATTR_TM_NOTHROW_LIST)
 
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_1, "_ITM_RU1",
-		BT_FN_I1_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_I1_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_2, "_ITM_RU2",
-		BT_FN_I2_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_I2_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_4, "_ITM_RU4",
-		BT_FN_I4_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_I4_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_8, "_ITM_RU8",
-		BT_FN_I8_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_I8_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_FLOAT, "_ITM_RF",
-		BT_FN_FLOAT_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_FLOAT_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_DOUBLE, "_ITM_RD",
-		BT_FN_DOUBLE_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_DOUBLE_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
 DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_LDOUBLE, "_ITM_RE",
-		BT_FN_LDOUBLE_VPTR, ATTR_PURE_NOTHROW_LIST)
+		BT_FN_LDOUBLE_VPTR, ATTR_TM_PURE_NOTHROW_LIST)
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 149303)
+++ config/i386/i386.c	(revision 149304)
@@ -4377,6 +4377,39 @@ ix86_handle_cconv_attribute (tree *node,
   return NULL_TREE;
 }
 
+/* The transactional memory builtins are implicitly regparm or fastcall
+   depending on the ABI.  Override the generic do-nothing attribute that
+   these builtins were declared with, and replace it with one of the two
+   attributes that we expect elsewhere.  */
+
+static tree
+ix86_handle_tm_regparm_attribute (tree *node, tree name, tree args,
+				  int flags ATTRIBUTE_UNUSED,
+				  bool *no_add_attrs)
+{
+  tree alt;
+
+  /* In no case do we want to add the placeholder attribute.  */
+  *no_add_attrs = true;
+
+  /* The 64-bit ABI is unchanged for transactional memory.  */
+  if (TARGET_64BIT)
+    return NULL_TREE;
+
+  /* ??? Is there a better way to validate 32-bit windows?  We have
+     cfun->machine->call_abi, but that seems to be set only for 64-bit.  */
+  if (CHECK_STACK_LIMIT > 0)
+    alt = tree_cons (get_identifier ("fastcall"), NULL, NULL);
+  else
+    {
+      alt = tree_cons (NULL, build_int_cst (NULL, 2), NULL);
+      alt = tree_cons (get_identifier ("regparm"), alt, NULL);
+    }
+  decl_attributes (node, alt, flags);
+
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
@@ -30424,6 +30457,10 @@ static const struct attribute_spec ix86_
   /* Sseregparm attribute says we are using x86_64 calling conventions
      for FP arguments.  */
   { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute },
+  /* The transactional memory builtins are implicitly regparm or fastcall
+     depending on the ABI.  Override the generic do-nothing attribute that
+     these builtins were declared with.  */
+  { "*tm regparm", 0, 0, false, true, true, ix86_handle_tm_regparm_attribute },
   /* force_align_arg_pointer says this function realigns the stack at entry.  */
   { (const char *)&ix86_force_align_arg_pointer_string, 0, 0,
     false, true,  true, ix86_handle_cconv_attribute },

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05 23:03           ` Richard Guenther
@ 2011-11-06 10:10             ` Aldy Hernandez
  2011-11-06 10:51               ` Richard Guenther
  0 siblings, 1 reply; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-06 10:10 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Richard Henderson, gcc-patches, Torvald Riegel

[-- Attachment #1: Type: text/plain, Size: 634 bytes --]


> Well - we usually don't grab bits off the tree nodes lightly.  Especially if
> the cgraph seems to be more fit.
>
>> If this is a suggestion, I can put it on my laundry list of future things
>> todo (after merge, 4.8?, etc).
>
> There are not many consumers of the flag, so fixing it shouldn't be hard.
> For 4.7 definitely.

Fair enough.

The following patch puts the bit in the cgraph structure.

There was a comment originally that we may be able to calculate this bit 
from the CFG, but I'm not sure whether this applies any more, or how 
much work it would be.  I left the comment in.

Tested on x86-64 Linux.

OK for branch?

[-- Attachment #2: curr --]
[-- Type: text/plain, Size: 7340 bytes --]

	* cgraph.c (dump_cgraph_node): Handle tm_clone.
	* cgraph.h (struct cgraph_node): Add tm_clone field.
	(decl_is_tm_clone): New.
	* tree.h (DECL_IS_TM_CLONE): Remove.
	* trans-mem.c (execute_lower_tm): Rename DECL_IS_TM_CLONE to
	decl_is_tm_clone.
	(gate_tm_init): Same.
	(ipa_tm_create_version_alias): Set tm_clone.
	(ipa_tm_create_version): Same.
	(ipa_tm_transform_calls_redirect): Rename DECL_IS_TM_CLONE to
	decl_is_tm_clone.
	* calls.c (is_tm_builtin): Same.
	* tree-cfg.c (dump_function_to_file): Same.
	* print-tree.c (print_node): Same.
	* gimple-pretty-print.c (dump_gimple_call): Same.

Index: cgraph.c
===================================================================
--- cgraph.c	(revision 181017)
+++ cgraph.c	(working copy)
@@ -1840,6 +1840,8 @@ dump_cgraph_node (FILE *f, struct cgraph
     fprintf (f, " only_called_at_exit");
   else if (node->alias)
     fprintf (f, " alias");
+  if (node->tm_clone)
+    fprintf (f, " tm_clone");
 
   fprintf (f, "\n");
 
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 181017)
+++ cgraph.h	(working copy)
@@ -248,6 +248,11 @@ struct GTY((chain_next ("%h.next"), chai
   unsigned only_called_at_startup : 1;
   /* True when function can only be called at startup (from static dtor).  */
   unsigned only_called_at_exit : 1;
+  /* True when function is the transactional clone of a function which
+     is called only from inside transactions.  */
+  /* ?? We should be able to remove this.  We have enough bits in
+     cgraph to calculate it.  */
+  unsigned tm_clone : 1;
 };
 
 typedef struct cgraph_node *cgraph_node_ptr;
@@ -1087,4 +1092,14 @@ cgraph_edge_recursive_p (struct cgraph_e
   else
     return e->caller->decl == callee->decl;
 }
+
+/* Return true if the TM_CLONE bit is set for a given FNDECL.  */
+static inline bool
+decl_is_tm_clone (const_tree fndecl)
+{
+  struct cgraph_node *n = cgraph_get_node (fndecl);
+  if (n)
+    return n->tm_clone;
+  return false;
+}
 #endif  /* GCC_CGRAPH_H  */
Index: tree.h
===================================================================
--- tree.h	(revision 181017)
+++ tree.h	(working copy)
@@ -3466,11 +3466,6 @@ struct GTY(())
 #define DECL_NO_INLINE_WARNING_P(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.no_inline_warning_flag)
 
-/* Nonzero in a FUNCTION_DECL means this function is the transactional
-   clone of a function - called only from inside transactions.  */
-#define DECL_IS_TM_CLONE(NODE) \
-  (FUNCTION_DECL_CHECK (NODE)->function_decl.tm_clone_flag)
-
 /* Nonzero if a FUNCTION_CODE is a TM load/store.  */
 #define BUILTIN_TM_LOAD_STORE_P(FN) \
   ((FN) >= BUILT_IN_TM_STORE_1 && (FN) <= BUILT_IN_TM_LOAD_RFW_LDOUBLE)
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c	(revision 181017)
+++ gimple-pretty-print.c	(working copy)
@@ -701,7 +701,7 @@ dump_gimple_call (pretty_printer *buffer
   /* Dump the arguments of _ITM_beginTransaction sanely.  */
   if (TREE_CODE (fn) == ADDR_EXPR)
     fn = TREE_OPERAND (fn, 0);
-  if (TREE_CODE (fn) == FUNCTION_DECL && DECL_IS_TM_CLONE (fn))
+  if (TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn))
     pp_string (buffer, " [tm-clone]");
   if (TREE_CODE (fn) == FUNCTION_DECL
       && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
Index: trans-mem.c
===================================================================
--- trans-mem.c	(revision 181017)
+++ trans-mem.c	(working copy)
@@ -1683,7 +1683,7 @@ execute_lower_tm (void)
   struct walk_stmt_info wi;
 
   /* Transactional clones aren't created until a later pass.  */
-  gcc_assert (!DECL_IS_TM_CLONE (current_function_decl));
+  gcc_assert (!decl_is_tm_clone (current_function_decl));
 
   memset (&wi, 0, sizeof (wi));
   walk_gimple_seq (gimple_body (current_function_decl),
@@ -1901,7 +1901,7 @@ gate_tm_init (void)
   bitmap_obstack_initialize (&tm_obstack);
 
   /* If the function is a TM_CLONE, then the entire function is the region.  */
-  if (DECL_IS_TM_CLONE (current_function_decl))
+  if (decl_is_tm_clone (current_function_decl))
     {
       struct tm_region *region = (struct tm_region *)
 	obstack_alloc (&tm_obstack.obstack, sizeof (struct tm_region));
@@ -4194,11 +4194,8 @@ ipa_tm_create_version_alias (struct cgra
   if (DECL_COMDAT (new_decl))
     DECL_COMDAT_GROUP (new_decl) = tm_mangle (DECL_COMDAT_GROUP (old_decl));
 
-  /* ??? 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;
-
   new_node = cgraph_same_body_alias (NULL, new_decl, info->new_decl);
+  new_node->tm_clone = true;
   get_cg_data (node)->clone = new_node;
 
   record_tm_clone_pair (old_decl, new_decl);
@@ -4232,11 +4229,8 @@ ipa_tm_create_version (struct cgraph_nod
   if (DECL_COMDAT (new_decl))
     DECL_COMDAT_GROUP (new_decl) = tm_mangle (DECL_COMDAT_GROUP (old_decl));
 
-  /* ??? 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;
-
   new_node = cgraph_copy_node_for_versioning (old_node, new_decl, NULL, NULL);
+  new_node->tm_clone = 1;
   get_cg_data (old_node)->clone = new_node;
 
   if (cgraph_function_body_availability (old_node) >= AVAIL_OVERWRITABLE)
@@ -4418,7 +4412,7 @@ ipa_tm_transform_calls_redirect (struct 
   /* Fixup recursive calls inside clones.  */
   /* ??? Why did cgraph_copy_node_for_versioning update the call edges 
      for recursion but not update the call statements themselves?  */
-  if (e->caller == e->callee && DECL_IS_TM_CLONE (current_function_decl))
+  if (e->caller == e->callee && decl_is_tm_clone (current_function_decl))
     {
       gimple_call_set_fndecl (stmt, current_function_decl);
       return;
Index: calls.c
===================================================================
--- calls.c	(revision 181017)
+++ calls.c	(working copy)
@@ -620,7 +620,7 @@ is_tm_builtin (const_tree fndecl)
   if (fndecl == NULL)
     return false;
 
-  if (DECL_IS_TM_CLONE (fndecl))
+  if (decl_is_tm_clone (fndecl))
     return true;
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
Index: print-tree.c
===================================================================
--- print-tree.c	(revision 181017)
+++ print-tree.c	(working copy)
@@ -424,7 +424,7 @@ print_node (FILE *file, const char *pref
 	fputs (" built-in", file);
       if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node))
 	fputs (" static-chain", file);
-      if (TREE_CODE (node) == FUNCTION_DECL && DECL_IS_TM_CLONE (node))
+      if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node))
 	fputs (" tm-clone", file);
 
       if (code == FIELD_DECL && DECL_PACKED (node))
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 181017)
+++ tree-cfg.c	(working copy)
@@ -6503,7 +6503,7 @@ dump_function_to_file (tree fn, FILE *fi
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
   tree chain;
-  bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && DECL_IS_TM_CLONE (fn);
+  bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn);
 
   fprintf (file, "%s %s(", lang_hooks.decl_printable_name (fn, 2),
 	   tmclone ? "[tm-clone] " : "");

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-06  0:51   ` Aldy Hernandez
@ 2011-11-06 10:17     ` Richard Guenther
  2011-11-07 17:47       ` Richard Henderson
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Guenther @ 2011-11-06 10:17 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: gcc-patches, Richard Henderson

On Sun, Nov 6, 2011 at 12:16 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> [rth, see below]
>
>>> Index: gcc/attribs.c
>>> ===================================================================
>>> --- gcc/attribs.c       (.../trunk)     (revision 180744)
>>> +++ gcc/attribs.c       (.../branches/transactional-memory)     (revision
>>> 180773)
>>> @@ -166,7 +166,8 @@ init_attributes (void)
>>>          gcc_assert (strcmp (attribute_tables[i][j].name,
>>>                              attribute_tables[i][k].name));
>>>     }
>>> -  /* Check that no name occurs in more than one table.  */
>>> +  /* Check that no name occurs in more than one table.  Names that
>>> +     begin with '*' are exempt, and may be overridden.  */
>>>   for (i = 0; i<  ARRAY_SIZE (attribute_tables); i++)
>>>     {
>>>       size_t j, k, l;
>>> @@ -174,8 +175,9 @@ init_attributes (void)
>>>       for (j = i + 1; j<  ARRAY_SIZE (attribute_tables); j++)
>>>        for (k = 0; attribute_tables[i][k].name != NULL; k++)
>>>          for (l = 0; attribute_tables[j][l].name != NULL; l++)
>>> -           gcc_assert (strcmp (attribute_tables[i][k].name,
>>> -                               attribute_tables[j][l].name));
>>> +           gcc_assert (attribute_tables[i][k].name[0] == '*'
>>> +                       || strcmp (attribute_tables[i][k].name,
>>> +                                  attribute_tables[j][l].name));
>>>     }
>>>  #endif
>>>
>>> @@ -207,7 +209,7 @@ register_attribute (const struct attribu
>>>   slot = htab_find_slot_with_hash (attribute_hash,&str,
>>>                                   substring_hash (str.str, str.length),
>>>                                   INSERT);
>>> -  gcc_assert (!*slot);
>>> +  gcc_assert (!*slot || attr->name[0] == '*');
>>>   *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
>>>  }
>>
>> The above changes seem to belong to a different changeset and look
>> strange.  Why would attributes ever appear in two different tables?
>
> I couldn't find a corresponding gcc-patches message for this patch, but I
> was able to hunt down full the patch, which I am attaching for discussion.
>
> This seems to be a change required for allowing '*' to override builtins, so
> it is indeed part of the branch.  Perhaps with the full context it is easier
> to review.

Ah, indeed ...

> I will defer to rth to answer any questions on the original motivation.
>
> Richi, do you have any particular issue with the attribs.c change?  Does
> this context resolve any questions you may have had?

... no, it just looked weird without seeing a use.  Now, target specific
attributes on a non-target specific builtin are of course weird.  Which
explains the patch, sort-of.  Still feels like a hack, but I can't think
of anything better, other than a target hook that we'd call for
all middle-end builtins we generate and which would allow target specific
modifications.  No idea if that would be better.  I'll defer to rth for this.

Richard.

> Aldy
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-06 10:10             ` Aldy Hernandez
@ 2011-11-06 10:51               ` Richard Guenther
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Guenther @ 2011-11-06 10:51 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Richard Henderson, gcc-patches, Torvald Riegel

On Sun, Nov 6, 2011 at 4:41 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
>
>> Well - we usually don't grab bits off the tree nodes lightly.  Especially
>> if
>> the cgraph seems to be more fit.
>>
>>> If this is a suggestion, I can put it on my laundry list of future things
>>> todo (after merge, 4.8?, etc).
>>
>> There are not many consumers of the flag, so fixing it shouldn't be hard.
>> For 4.7 definitely.
>
> Fair enough.
>
> The following patch puts the bit in the cgraph structure.
>
> There was a comment originally that we may be able to calculate this bit
> from the CFG, but I'm not sure whether this applies any more, or how much
> work it would be.  I left the comment in.
>
> Tested on x86-64 Linux.
>
> OK for branch?

Ok.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-06 10:17     ` Richard Guenther
@ 2011-11-07 17:47       ` Richard Henderson
  0 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2011-11-07 17:47 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Aldy Hernandez, gcc-patches

On 11/06/2011 02:09 AM, Richard Guenther wrote:
>> > Richi, do you have any particular issue with the attribs.c change?  Does
>> > this context resolve any questions you may have had?
> ... no, it just looked weird without seeing a use.  Now, target specific
> attributes on a non-target specific builtin are of course weird.  Which
> explains the patch, sort-of.  Still feels like a hack, but I can't think
> of anything better, other than a target hook that we'd call for
> all middle-end builtins we generate and which would allow target specific
> modifications.  No idea if that would be better.  I'll defer to rth for this.

I tried 2 or 3 ideas on the way to this hack.

I guess the idea of a target hook that gets called for *all* builtins
has a better chance of being useful for something else in the future.

I'll work up something and see if it looks any cleaner...


r~

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-05 23:16     ` Richard Guenther
@ 2011-11-07 19:06       ` Richard Henderson
  2011-11-07 19:46         ` Aldy Hernandez
  2011-11-07 22:38         ` Richard Guenther
  0 siblings, 2 replies; 22+ messages in thread
From: Richard Henderson @ 2011-11-07 19:06 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Aldy Hernandez, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1994 bytes --]

On 11/05/2011 03:09 PM, Richard Guenther wrote:
> On Sat, Nov 5, 2011 at 10:05 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>> [rth, see below]
>>
>>>>   local_define_builtin ("__builtin_eh_pointer", ftype,
>>>> BUILT_IN_EH_POINTER,
>>>>                        "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW |
>>>> ECF_LEAF);
>>>> +  if (flag_tm)
>>>> +    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
>>>> +                  get_identifier ("transaction_pure"));
>>>
>>> I think this should use a new ECF_TM_PURE flag, unconditionally set
>>> with handling in the functions that handle/return ECF flags so that
>>> transitioning this to a tree node flag instead of an attribute is easier.
>>
>> I could add a ECF_TM_PURE flag and attach it to the BUILT_IN_EH_POINTER in
>> the local_define_builtin above, but we still need the attribute for function
>> decl's as in:
>>
>> __attribute__((transaction_pure)) void foo();
>>
>> Attributes seem like a clean way to approach this.
> 
> The middle-end interfacing is supposed to be via ECF_ flags, the user interface
> via attributes.  What's the semantic of transaction-pure vs. ...
> 
>> I don't see what the flag buys us.  Or am I misunderstanding something?
>>
>>>> +/* Nonzero if this call performs a transactional memory operation.  */
>>>> +#define ECF_TM_OPS               (1<<  11)
>>>
>>> What's this flag useful for?  Isn't it the case that you want to
>>> conservatively
>>> know whether a call might perform a tm operation?  Thus, the flag
>>> should be inverted?  Is this the same as "TM pure"?
> 
> ... this?
> 
>> Richard?
> 
>> Richi, I have fixed or addressed all the issues in this thread, with the
>> exception of your EFC_TM_PURE and ECF_TM_OPS questions, which I am deferring
>> to rth and then fixing if required.
> 
> Yeah, seems to be still an open question.

I hope this cleanup both addresses the above questions and tidies things
up as indicated.  Please ask if you've got more questions.

Ok, Richi?


r~

[-- Attachment #2: z --]
[-- Type: text/plain, Size: 7520 bytes --]

diff --git a/gcc/calls.c b/gcc/calls.c
index 515ab97..382de7f 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -707,13 +707,28 @@ flags_from_decl_or_type (const_tree exp)
       if (TREE_NOTHROW (exp))
 	flags |= ECF_NOTHROW;
 
-      if (is_tm_builtin (exp))
-	flags |= ECF_TM_OPS;
+      if (flag_tm)
+	{
+	  if (is_tm_builtin (exp))
+	    flags |= ECF_TM_BUILTIN;
+	  else if ((flags & ECF_CONST) != 0
+		   || lookup_attribute ("transaction_pure",
+					TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+	    flags |= ECF_TM_PURE;
+	}
 
       flags = special_function_p (exp, flags);
     }
-  else if (TYPE_P (exp) && TYPE_READONLY (exp))
-    flags |= ECF_CONST;
+  else if (TYPE_P (exp))
+    {
+      if (TYPE_READONLY (exp))
+	flags |= ECF_CONST;
+
+      if (flag_tm
+	  && ((flags & ECF_CONST) != 0
+	      || lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp))))
+	flags |= ECF_TM_PURE;
+    }
 
   if (TREE_THIS_VOLATILE (exp))
     {
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index ba25fd8..be399a0 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -172,14 +172,8 @@ get_attrs_for (const_tree x)
 bool
 is_tm_pure (const_tree x)
 {
-  if (flag_tm)
-    {
-      tree attrs = get_attrs_for (x);
-      if (attrs)
-	return lookup_attribute ("transaction_pure", attrs) != NULL;
-      return false;
-    }
-  return false;
+  unsigned flags = flags_from_decl_or_type (x);
+  return (flags & ECF_TM_PURE) != 0;
 }
 
 /* Return true if X has been marked TM_IRREVOCABLE.  */
@@ -229,10 +223,6 @@ static bool
 is_tm_pure_call (gimple call)
 {
   tree fn = gimple_call_fn (call);
-  unsigned flags;
-
-  if (is_tm_pure (TREE_TYPE (fn)))
-    return true;
 
   if (TREE_CODE (fn) == ADDR_EXPR)
     {
@@ -241,9 +231,8 @@ is_tm_pure_call (gimple call)
     }
   else
     fn = TREE_TYPE (fn);
-  flags = flags_from_decl_or_type (fn);
 
-  return (flags & ECF_CONST) != 0;
+  return is_tm_pure (fn);
 }
 
 /* Return true if X has been marked TM_CALLABLE.  */
@@ -2484,7 +2473,7 @@ make_tm_edge (gimple stmt, basic_block bb, struct tm_region *region)
 }
 
 
-/* Split block BB as necessary for every TM_OPS function we added, and
+/* Split block BB as necessary for every builtin function we added, and
    wire up the abnormal back edges implied by the transaction restart.  */
 
 static void
@@ -2496,15 +2485,16 @@ expand_block_edges (struct tm_region *region, basic_block bb)
     {
       gimple stmt = gsi_stmt (gsi);
 
-      /* ??? TM_COMMIT (and any other ECF_TM_OPS function) in a nested
+      /* ??? TM_COMMIT (and any other tm builtin function) in a nested
 	 transaction has an abnormal edge back to the outer-most transaction
 	 (there are no nested retries), while a TM_ABORT also has an abnormal
 	 backedge to the inner-most transaction.  We haven't actually saved
 	 the inner-most transaction here.  We should be able to get to it
 	 via the region_nr saved on STMT, and read the transaction_stmt from
 	 that, and find the first region block from there.  */
+      /* ??? Shouldn't we split for any non-pure, non-irrevocable function?  */
       if (gimple_code (stmt) == GIMPLE_CALL
-	  && (gimple_call_flags (stmt) & ECF_TM_OPS) != 0)
+	  && (gimple_call_flags (stmt) & ECF_TM_BUILTIN) != 0)
 	{
 	  if (gsi_one_before_end_p (gsi))
 	    make_tm_edge (stmt, bb, region);
@@ -3934,11 +3924,18 @@ ipa_tm_mayenterirr_function (struct cgraph_node *node)
 {
   struct tm_ipa_cg_data *d = get_cg_data (node);
   tree decl = node->decl;
+  unsigned flags = flags_from_decl_or_type (decl);
+
+  /* Handle some TM builtins.  Ordinarily these aren't actually generated
+     at this point, but handling these functions when written in by the
+     user makes it easier to build unit tests.  */
+  if (flags & ECF_TM_BUILTIN)
+    return false;
 
   /* Filter out all functions that are marked.  */
-  if (is_tm_safe_or_pure (decl))
+  if (flags & ECF_TM_PURE)
     return false;
-  if ((flags_from_decl_or_type (decl) & ECF_CONST) != 0)
+  if (is_tm_safe (decl))
     return false;
   if (is_tm_irrevocable (decl))
     return true;
@@ -3947,11 +3944,6 @@ ipa_tm_mayenterirr_function (struct cgraph_node *node)
   if (find_tm_replacement_function (decl))
     return true;
 
-  /* Handle some TM builtins.  */
-  if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
-      && (flags_from_decl_or_type (decl) & ECF_TM_OPS) != 0)
-    return false;
-
   /* If we aren't seeing the final version of the function we don't
      know what it will contain at runtime.  */
   if (cgraph_function_body_availability (node) < AVAIL_AVAILABLE)
@@ -4394,8 +4386,10 @@ ipa_tm_transform_calls_redirect (struct cgraph_node *node,
       return;
     }
 
-  /* If the call is to the TM runtime, do nothing further.  */
-  if (flags_from_decl_or_type (fndecl) & ECF_TM_OPS)
+  /* Handle some TM builtins.  Ordinarily these aren't actually generated
+     at this point, but handling these functions when written in by the
+     user makes it easier to build unit tests.  */
+  if (flags_from_decl_or_type (fndecl) & ECF_TM_BUILTIN)
     return;
 
   /* Fixup recursive calls inside clones.  */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 61e4476..7cb4a3d 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2298,9 +2298,9 @@ is_ctrl_altering_stmt (gimple t)
 	  return true;
 
 	/* TM ending statements have backedges out of the transaction.
-	   Return true so we split the basic block containing
-	   them.  */
-	if ((flags & ECF_TM_OPS)
+	   Return true so we split the basic block containing them.
+	   Note that the TM_BUILTIN test is merely an optimization.  */
+	if ((flags & ECF_TM_BUILTIN)
 	    && is_tm_ending_fndecl (gimple_call_fndecl (t)))
 	  return true;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 30c6bb8..ba6c2e1 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9428,6 +9428,8 @@ local_define_builtin (const char *name, tree type, enum built_in_function code,
   if (ecf_flags & ECF_LEAF)
     DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"),
 					NULL, DECL_ATTRIBUTES (decl));
+  if ((ecf_flags & ECF_TM_PURE) && flag_tm)
+    apply_tm_attr (decl, get_identifier ("transaction_pure"));
 
   set_builtin_decl (code, decl, true);
 }
@@ -9593,10 +9595,8 @@ build_common_builtin_nodes (void)
   ftype = build_function_type_list (ptr_type_node,
 				    integer_type_node, NULL_TREE);
   local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
-			"__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
-  if (flag_tm)
-    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
-		   get_identifier ("transaction_pure"));
+			"__builtin_eh_pointer",
+			ECF_PURE | ECF_NOTHROW | ECF_LEAF | ECF_TM_PURE);
 
   tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
   ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
diff --git a/gcc/tree.h b/gcc/tree.h
index 23f3d69..ab20272 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5601,8 +5601,10 @@ extern tree build_duplicate_type (tree);
 #define ECF_NOVOPS		  (1 << 9)
 /* The function does not lead to calls within current function unit.  */
 #define ECF_LEAF		  (1 << 10)
-/* Nonzero if this call performs a transactional memory operation.  */
-#define ECF_TM_OPS		  (1 << 11)
+/* Nonzero if this call does not affect transactions.  */
+#define ECF_TM_PURE		  (1 << 11)
+/* Nonzero if this call is into the transaction runtime library.  */
+#define ECF_TM_BUILTIN		  (1 << 12)
 
 extern int flags_from_decl_or_type (const_tree);
 extern int call_expr_flags (const_tree);

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-07 19:06       ` Richard Henderson
@ 2011-11-07 19:46         ` Aldy Hernandez
  2011-11-07 22:38         ` Richard Guenther
  1 sibling, 0 replies; 22+ messages in thread
From: Aldy Hernandez @ 2011-11-07 19:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Guenther, gcc-patches


> I hope this cleanup both addresses the above questions and tidies things
> up as indicated.  Please ask if you've got more questions.

BTW, please add a merged changelog entry to ChangeLog.tm-merge.  No need 
for a ChangeLog.tm, unless we don't merge, in case we're back to 
ChangeLog.tm for a complete history :(.

Thanks for doing this Richard H.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch] 19/n: trans-mem: compiler tree/gimple stuff
  2011-11-07 19:06       ` Richard Henderson
  2011-11-07 19:46         ` Aldy Hernandez
@ 2011-11-07 22:38         ` Richard Guenther
  1 sibling, 0 replies; 22+ messages in thread
From: Richard Guenther @ 2011-11-07 22:38 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Aldy Hernandez, gcc-patches

On Mon, Nov 7, 2011 at 8:01 PM, Richard Henderson <rth@redhat.com> wrote:
> On 11/05/2011 03:09 PM, Richard Guenther wrote:
>> On Sat, Nov 5, 2011 at 10:05 PM, Aldy Hernandez <aldyh@redhat.com> wrote:
>>> [rth, see below]
>>>
>>>>>   local_define_builtin ("__builtin_eh_pointer", ftype,
>>>>> BUILT_IN_EH_POINTER,
>>>>>                        "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW |
>>>>> ECF_LEAF);
>>>>> +  if (flag_tm)
>>>>> +    apply_tm_attr (builtin_decl_explicit (BUILT_IN_EH_POINTER),
>>>>> +                  get_identifier ("transaction_pure"));
>>>>
>>>> I think this should use a new ECF_TM_PURE flag, unconditionally set
>>>> with handling in the functions that handle/return ECF flags so that
>>>> transitioning this to a tree node flag instead of an attribute is easier.
>>>
>>> I could add a ECF_TM_PURE flag and attach it to the BUILT_IN_EH_POINTER in
>>> the local_define_builtin above, but we still need the attribute for function
>>> decl's as in:
>>>
>>> __attribute__((transaction_pure)) void foo();
>>>
>>> Attributes seem like a clean way to approach this.
>>
>> The middle-end interfacing is supposed to be via ECF_ flags, the user interface
>> via attributes.  What's the semantic of transaction-pure vs. ...
>>
>>> I don't see what the flag buys us.  Or am I misunderstanding something?
>>>
>>>>> +/* Nonzero if this call performs a transactional memory operation.  */
>>>>> +#define ECF_TM_OPS               (1<<  11)
>>>>
>>>> What's this flag useful for?  Isn't it the case that you want to
>>>> conservatively
>>>> know whether a call might perform a tm operation?  Thus, the flag
>>>> should be inverted?  Is this the same as "TM pure"?
>>
>> ... this?
>>
>>> Richard?
>>
>>> Richi, I have fixed or addressed all the issues in this thread, with the
>>> exception of your EFC_TM_PURE and ECF_TM_OPS questions, which I am deferring
>>> to rth and then fixing if required.
>>
>> Yeah, seems to be still an open question.
>
> I hope this cleanup both addresses the above questions and tidies things
> up as indicated.  Please ask if you've got more questions.
>
> Ok, Richi?

Yes,

Thanks,
Richard.

>
> r~
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-11-07 22:27 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-03 19:40 [patch] 19/n: trans-mem: compiler tree/gimple stuff Aldy Hernandez
2011-11-04 10:44 ` Richard Guenther
2011-11-05  0:25   ` Aldy Hernandez
2011-11-05  2:54     ` Richard Henderson
2011-11-05  9:11       ` Richard Guenther
2011-11-05 18:14         ` Aldy Hernandez
2011-11-05 23:03           ` Richard Guenther
2011-11-06 10:10             ` Aldy Hernandez
2011-11-06 10:51               ` Richard Guenther
2011-11-05  3:11   ` Richard Henderson
2011-11-05  3:23     ` Richard Henderson
2011-11-05 10:18       ` Richard Guenther
2011-11-05 21:26   ` Aldy Hernandez
2011-11-05 23:16     ` Richard Guenther
2011-11-07 19:06       ` Richard Henderson
2011-11-07 19:46         ` Aldy Hernandez
2011-11-07 22:38         ` Richard Guenther
2011-11-06  0:51   ` Aldy Hernandez
2011-11-06 10:17     ` Richard Guenther
2011-11-07 17:47       ` Richard Henderson
2011-11-04 15:40 ` Michael Matz
2011-11-05  8:47   ` Aldy Hernandez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).