OSDN Git Service

PR middle-end/51516
[pf3gnuchains/gcc-fork.git] / gcc / trans-mem.c
index 3c0bd60..8780825 100644 (file)
@@ -544,7 +544,6 @@ struct diagnose_tm
   unsigned int summary_flags : 8;
   unsigned int block_flags : 8;
   unsigned int func_flags : 8;
-  unsigned int saw_unsafe : 1;
   unsigned int saw_volatile : 1;
   gimple stmt;
 };
@@ -659,13 +658,41 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
                if (TREE_CODE (fn) == ADDR_EXPR)
                  fn = TREE_OPERAND (fn, 0);
                if (d->block_flags & DIAG_TM_SAFE)
-                 error_at (gimple_location (stmt),
-                           "unsafe function call %qD within "
-                           "atomic transaction", fn);
+                 {
+                   if (direct_call_p)
+                     error_at (gimple_location (stmt),
+                               "unsafe function call %qD within "
+                               "atomic transaction", fn);
+                   else
+                     {
+                       if (!DECL_P (fn) || DECL_NAME (fn))
+                         error_at (gimple_location (stmt),
+                                   "unsafe function call %qE within "
+                                   "atomic transaction", fn);
+                       else
+                         error_at (gimple_location (stmt),
+                                   "unsafe indirect function call within "
+                                   "atomic transaction");
+                     }
+                 }
                else
-                 error_at (gimple_location (stmt),
-                           "unsafe function call %qD within "
-                           "%<transaction_safe%> function", fn);
+                 {
+                   if (direct_call_p)
+                     error_at (gimple_location (stmt),
+                               "unsafe function call %qD within "
+                               "%<transaction_safe%> function", fn);
+                   else
+                     {
+                       if (!DECL_P (fn) || DECL_NAME (fn))
+                         error_at (gimple_location (stmt),
+                                   "unsafe function call %qE within "
+                                   "%<transaction_safe%> function", fn);
+                       else
+                         error_at (gimple_location (stmt),
+                                   "unsafe indirect function call within "
+                                   "%<transaction_safe%> function");
+                     }
+                 }
              }
          }
       }
@@ -681,8 +708,6 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
       else if (d->func_flags & DIAG_TM_SAFE)
        error_at (gimple_location (stmt),
                  "asm not allowed in %<transaction_safe%> function");
-      else
-       d->saw_unsafe = true;
       break;
 
     case GIMPLE_TRANSACTION:
@@ -697,8 +722,6 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
            else if (d->func_flags & DIAG_TM_SAFE)
              error_at (gimple_location (stmt),
                        "relaxed transaction in %<transaction_safe%> function");
-           else
-             d->saw_unsafe = true;
            inner_flags = DIAG_TM_RELAXED;
          }
        else if (gimple_transaction_subcode (stmt) & GTMA_IS_OUTER)
@@ -713,8 +736,6 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
            else if (d->func_flags & DIAG_TM_SAFE)
              error_at (gimple_location (stmt),
                        "outer transaction in %<transaction_safe%> function");
-           else
-             d->saw_unsafe = true;
            inner_flags |= DIAG_TM_OUTER;
          }
 
@@ -734,8 +755,6 @@ diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 
            walk_gimple_seq (gimple_transaction_body (stmt),
                             diagnose_tm_1, diagnose_tm_1_op, &wi_inner);
-
-           d->saw_unsafe |= d_inner.saw_unsafe;
          }
       }
       break;
@@ -766,11 +785,6 @@ diagnose_tm_blocks (void)
   walk_gimple_seq (gimple_body (current_function_decl),
                   diagnose_tm_1, diagnose_tm_1_op, &wi);
 
-  /* If we saw something other than a call that makes this function
-     unsafe, remember it so that the IPA pass only needs to scan calls.  */
-  if (d.saw_unsafe && !is_tm_safe_or_pure (current_function_decl))
-    cgraph_local_info (current_function_decl)->tm_may_enter_irr = 1;
-
   return 0;
 }
 
@@ -1003,7 +1017,7 @@ tm_log_add (basic_block entry_block, tree addr, gimple stmt)
             special constructors and the like.  */
          && !TREE_ADDRESSABLE (type))
        {
-         lp->save_var = create_tmp_var (TREE_TYPE (lp->addr), "tm_save");
+         lp->save_var = create_tmp_reg (TREE_TYPE (lp->addr), "tm_save");
          add_referenced_var (lp->save_var);
          lp->stmts = NULL;
          lp->entry_block = entry_block;
@@ -2160,7 +2174,7 @@ expand_assign_tm (struct tm_region *region, gimple_stmt_iterator *gsi)
     }
   if (!gcall)
     {
-      tree lhs_addr, rhs_addr;
+      tree lhs_addr, rhs_addr, tmp;
 
       if (load_p)
        transaction_subcode_ior (region, GTMA_HAVE_LOAD);
@@ -2169,13 +2183,29 @@ expand_assign_tm (struct tm_region *region, gimple_stmt_iterator *gsi)
 
       /* ??? Figure out if there's any possible overlap between the LHS
         and the RHS and if not, use MEMCPY.  */
-      lhs_addr = gimplify_addr (gsi, lhs);
+
+      if (load_p && is_gimple_reg (lhs))
+       {
+         tmp = create_tmp_var (TREE_TYPE (lhs), NULL);
+         lhs_addr = build_fold_addr_expr (tmp);
+       }
+      else
+       {
+         tmp = NULL_TREE;
+         lhs_addr = gimplify_addr (gsi, lhs);
+       }
       rhs_addr = gimplify_addr (gsi, rhs);
       gcall = gimple_build_call (builtin_decl_explicit (BUILT_IN_TM_MEMMOVE),
                                 3, lhs_addr, rhs_addr,
                                 TYPE_SIZE_UNIT (TREE_TYPE (lhs)));
       gimple_set_location (gcall, loc);
       gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
+
+      if (tmp)
+       {
+         gcall = gimple_build_assign (lhs, tmp);
+         gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
+       }
     }
 
   /* Now that we have the load/store in its instrumented form, add
@@ -2319,7 +2349,8 @@ expand_block_tm (struct tm_region *region, basic_block bb)
        {
        case GIMPLE_ASSIGN:
          /* Only memory reads/writes need to be instrumented.  */
-         if (gimple_assign_single_p (stmt))
+         if (gimple_assign_single_p (stmt)
+             && !gimple_clobber_p (stmt))
            {
              expand_assign_tm (region, &gsi);
              continue;
@@ -3491,18 +3522,24 @@ DEF_VEC_ALLOC_P (cgraph_node_p, heap);
 typedef VEC (cgraph_node_p, heap) *cgraph_node_queue;
 
 /* Return the ipa data associated with NODE, allocating zeroed memory
-   if necessary.  */
+   if necessary.  TRAVERSE_ALIASES is true if we must traverse aliases
+   and set *NODE accordingly.  */
 
 static struct tm_ipa_cg_data *
-get_cg_data (struct cgraph_node *node)
+get_cg_data (struct cgraph_node **node, bool traverse_aliases)
 {
-  struct tm_ipa_cg_data *d = (struct tm_ipa_cg_data *) node->aux;
+  struct tm_ipa_cg_data *d;
+
+  if (traverse_aliases && (*node)->alias)
+    *node = cgraph_get_node ((*node)->thunk.alias);
+
+  d = (struct tm_ipa_cg_data *) (*node)->aux;
 
   if (d == NULL)
     {
       d = (struct tm_ipa_cg_data *)
        obstack_alloc (&tm_obstack.obstack, sizeof (*d));
-      node->aux = (void *) d;
+      (*node)->aux = (void *) d;
       memset (d, 0, sizeof (*d));
     }
 
@@ -3551,7 +3588,7 @@ ipa_tm_scan_calls_block (cgraph_node_queue *callees_p,
 
              node = cgraph_get_node (fndecl);
              gcc_assert (node != NULL);
-             d = get_cg_data (node);
+             d = get_cg_data (&node, true);
 
              pcallers = (for_clone ? &d->tm_callers_clone
                          : &d->tm_callers_normal);
@@ -3612,7 +3649,7 @@ static void
 ipa_tm_note_irrevocable (struct cgraph_node *node,
                         cgraph_node_queue *worklist_p)
 {
-  struct tm_ipa_cg_data *d = get_cg_data (node);
+  struct tm_ipa_cg_data *d = get_cg_data (&node, true);
   struct cgraph_edge *e;
 
   d->is_irrevocable = true;
@@ -3620,6 +3657,7 @@ ipa_tm_note_irrevocable (struct cgraph_node *node,
   for (e = node->callers; e ; e = e->next_caller)
     {
       basic_block bb;
+      struct cgraph_node *caller;
 
       /* Don't examine recursive calls.  */
       if (e->caller == node)
@@ -3629,7 +3667,8 @@ ipa_tm_note_irrevocable (struct cgraph_node *node,
       if (is_tm_safe_or_pure (e->caller->decl))
        continue;
 
-      d = get_cg_data (e->caller);
+      caller = e->caller;
+      d = get_cg_data (&caller, true);
 
       /* Check if the callee is in a transactional region.  If so,
         schedule the function for normal re-scan as well.  */
@@ -3639,7 +3678,7 @@ ipa_tm_note_irrevocable (struct cgraph_node *node,
          && bitmap_bit_p (d->transaction_blocks_normal, bb->index))
        d->want_irr_scan_normal = true;
 
-      maybe_push_queue (e->caller, worklist_p, &d->in_worklist);
+      maybe_push_queue (caller, worklist_p, &d->in_worklist);
     }
 }
 
@@ -3673,6 +3712,7 @@ ipa_tm_scan_irr_block (basic_block bb)
          if (TREE_CODE (fn) == ADDR_EXPR)
            {
              struct tm_ipa_cg_data *d;
+             struct cgraph_node *node;
 
              fn = TREE_OPERAND (fn, 0);
              if (is_tm_ending_fndecl (fn))
@@ -3680,8 +3720,13 @@ ipa_tm_scan_irr_block (basic_block bb)
              if (find_tm_replacement_function (fn))
                break;
 
-             d = get_cg_data (cgraph_get_node (fn));
-             if (d->is_irrevocable)
+             node = cgraph_get_node(fn);
+             d = get_cg_data (&node, true);
+
+             /* Return true if irrevocable, but above all, believe
+                the user.  */
+             if (d->is_irrevocable
+                 && !is_tm_safe_or_pure (fn))
                return true;
            }
          break;
@@ -3834,13 +3879,16 @@ ipa_tm_decrement_clone_counts (basic_block bb, bool for_clone)
            {
              struct tm_ipa_cg_data *d;
              unsigned *pcallers;
+             struct cgraph_node *tnode;
 
              if (is_tm_ending_fndecl (fndecl))
                continue;
              if (find_tm_replacement_function (fndecl))
                continue;
 
-             d = get_cg_data (cgraph_get_node (fndecl));
+             tnode = cgraph_get_node (fndecl);
+             d = get_cg_data (&tnode, true);
+
              pcallers = (for_clone ? &d->tm_callers_clone
                          : &d->tm_callers_normal);
 
@@ -3865,11 +3913,16 @@ ipa_tm_scan_irr_function (struct cgraph_node *node, bool for_clone)
   VEC (basic_block, heap) *queue;
   bool ret = false;
 
+  /* Builtin operators (operator new, and such).  */
+  if (DECL_STRUCT_FUNCTION (node->decl) == NULL
+      || DECL_STRUCT_FUNCTION (node->decl)->cfg == NULL)
+    return false;
+
   current_function_decl = node->decl;
   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
   calculate_dominance_info (CDI_DOMINATORS);
 
-  d = get_cg_data (node);
+  d = get_cg_data (&node, true);
   queue = VEC_alloc (basic_block, heap, 10);
   new_irr = BITMAP_ALLOC (&tm_obstack);
 
@@ -3948,9 +4001,13 @@ ipa_tm_scan_irr_function (struct cgraph_node *node, bool for_clone)
 static bool
 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);
+  struct tm_ipa_cg_data *d;
+  tree decl;
+  unsigned flags;
+
+  d = get_cg_data (&node, true);
+  decl = node->decl;
+  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
@@ -4189,7 +4246,8 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data)
 
   /* Based loosely on C++'s make_alias_for().  */
   TREE_PUBLIC (new_decl) = TREE_PUBLIC (old_decl);
-  DECL_CONTEXT (new_decl) = NULL;
+  DECL_CONTEXT (new_decl) = DECL_CONTEXT (old_decl);
+  DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
   TREE_READONLY (new_decl) = TREE_READONLY (old_decl);
   DECL_EXTERNAL (new_decl) = 0;
   DECL_ARTIFICIAL (new_decl) = 1;
@@ -4198,12 +4256,13 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data)
   TREE_SYMBOL_REFERENCED (tm_name) = 1;
 
   /* Perform the same remapping to the comdat group.  */
-  if (DECL_COMDAT (new_decl))
+  if (DECL_ONE_ONLY (new_decl))
     DECL_COMDAT_GROUP (new_decl) = tm_mangle (DECL_COMDAT_GROUP (old_decl));
 
   new_node = cgraph_same_body_alias (NULL, new_decl, info->new_decl);
   new_node->tm_clone = true;
-  get_cg_data (node)->clone = new_node;
+  /* ?? Do not traverse aliases here.  */
+  get_cg_data (&node, false)->clone = new_node;
 
   record_tm_clone_pair (old_decl, new_decl);
 
@@ -4233,13 +4292,13 @@ ipa_tm_create_version (struct cgraph_node *old_node)
   TREE_SYMBOL_REFERENCED (tm_name) = 1;
 
   /* Perform the same remapping to the comdat group.  */
-  if (DECL_COMDAT (new_decl))
+  if (DECL_ONE_ONLY (new_decl))
     DECL_COMDAT_GROUP (new_decl) = tm_mangle (DECL_COMDAT_GROUP (old_decl));
 
   new_node = cgraph_copy_node_for_versioning (old_node, new_decl, NULL, NULL);
   new_node->lowered = true;
   new_node->tm_clone = 1;
-  get_cg_data (old_node)->clone = new_node;
+  get_cg_data (&old_node, true)->clone = new_node;
 
   if (cgraph_function_body_availability (old_node) >= AVAIL_OVERWRITABLE)
     {
@@ -4249,6 +4308,7 @@ ipa_tm_create_version (struct cgraph_node *old_node)
        {
          DECL_EXTERNAL (new_decl) = 0;
          TREE_PUBLIC (new_decl) = 0;
+         DECL_WEAK (new_decl) = 0;
        }
 
       tree_function_versioning (old_decl, new_decl, NULL, false, NULL,
@@ -4456,7 +4516,10 @@ ipa_tm_transform_calls_redirect (struct cgraph_node *node,
     }
   else
     {
-      struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+      struct tm_ipa_cg_data *d;
+      struct cgraph_node *tnode = e->callee;
+
+      d = get_cg_data (&tnode, true);
       new_node = d->clone;
 
       /* As we've already skipped pure calls and appropriate builtins,
@@ -4466,7 +4529,6 @@ ipa_tm_transform_calls_redirect (struct cgraph_node *node,
        {
          *need_ssa_rename_p |=
            ipa_tm_insert_gettmclone_call (node, region, gsi, stmt);
-         cgraph_remove_edge (e);
          return;
        }
 
@@ -4558,10 +4620,12 @@ ipa_tm_transform_calls (struct cgraph_node *node, struct tm_region *region,
 static void
 ipa_tm_transform_transaction (struct cgraph_node *node)
 {
-  struct tm_ipa_cg_data *d = get_cg_data (node);
+  struct tm_ipa_cg_data *d;
   struct tm_region *region;
   bool need_ssa_rename = false;
 
+  d = get_cg_data (&node, true);
+
   current_function_decl = node->decl;
   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
   calculate_dominance_info (CDI_DOMINATORS);
@@ -4595,9 +4659,11 @@ ipa_tm_transform_transaction (struct cgraph_node *node)
 static void
 ipa_tm_transform_clone (struct cgraph_node *node)
 {
-  struct tm_ipa_cg_data *d = get_cg_data (node);
+  struct tm_ipa_cg_data *d;
   bool need_ssa_rename;
 
+  d = get_cg_data (&node, true);
+
   /* If this function makes no calls and has no irrevocable blocks,
      then there's nothing to do.  */
   /* ??? Remove non-aborting top-level transactions.  */
@@ -4644,7 +4710,7 @@ ipa_tm_execute (void)
     if (is_tm_callable (node->decl)
        && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       {
-       d = get_cg_data (node);
+       d = get_cg_data (&node, true);
        maybe_push_queue (node, &tm_callees, &d->in_callee_queue);
       }
 
@@ -4670,19 +4736,16 @@ ipa_tm_execute (void)
        tm_region_init (NULL);
        if (all_tm_regions)
          {
-           d = get_cg_data (node);
+           d = get_cg_data (&node, true);
 
            /* Scan for calls that are in each transaction.  */
            ipa_tm_scan_calls_transaction (d, &tm_callees);
 
-           /* If we saw something that will make us go irrevocable, put it
-              in the worklist so we can scan the function later
-              (ipa_tm_scan_irr_function) and mark the irrevocable blocks.  */
-           if (node->local.tm_may_enter_irr)
-             {
-               maybe_push_queue (node, &irr_worklist, &d->in_worklist);
-               d->want_irr_scan_normal = true;
-             }
+           /* Put it in the worklist so we can scan the function
+              later (ipa_tm_scan_irr_function) and mark the
+              irrevocable blocks.  */
+           maybe_push_queue (node, &irr_worklist, &d->in_worklist);
+           d->want_irr_scan_normal = true;
          }
 
        pop_cfun ();
@@ -4696,13 +4759,12 @@ ipa_tm_execute (void)
     {
       node = VEC_index (cgraph_node_p, tm_callees, i);
       a = cgraph_function_body_availability (node);
-      d = get_cg_data (node);
+      d = get_cg_data (&node, true);
 
-      /* If we saw something that will make us go irrevocable, put it
-        in the worklist so we can scan the function later
-        (ipa_tm_scan_irr_function) and mark the irrevocable blocks.  */
-      if (node->local.tm_may_enter_irr)
-       maybe_push_queue (node, &irr_worklist, &d->in_worklist);
+      /* Put it in the worklist so we can scan the function later
+        (ipa_tm_scan_irr_function) and mark the irrevocable
+        blocks.  */
+      maybe_push_queue (node, &irr_worklist, &d->in_worklist);
 
       /* Some callees cannot be arbitrarily cloned.  These will always be
         irrevocable.  Mark these now, so that we need not scan them.  */
@@ -4722,7 +4784,7 @@ ipa_tm_execute (void)
              if (node->alias)
                {
                  node = cgraph_get_node (node->thunk.alias);
-                 d = get_cg_data (node);
+                 d = get_cg_data (&node, true);
                  maybe_push_queue (node, &tm_callees, &d->in_callee_queue);
                  continue;
                }
@@ -4748,7 +4810,7 @@ ipa_tm_execute (void)
        }
 
       node = VEC_index (cgraph_node_p, irr_worklist, i);
-      d = get_cg_data (node);
+      d = get_cg_data (&node, true);
       d->in_worklist = false;
 
       if (d->want_irr_scan_normal)
@@ -4768,7 +4830,7 @@ ipa_tm_execute (void)
       node = VEC_index (cgraph_node_p, tm_callees, i);
       if (ipa_tm_mayenterirr_function (node))
        {
-         d = get_cg_data (node);
+         d = get_cg_data (&node, true);
          gcc_assert (d->in_worklist == false);
          maybe_push_queue (node, &irr_worklist, &d->in_worklist);
        }
@@ -4789,7 +4851,7 @@ ipa_tm_execute (void)
        }
 
       node = VEC_index (cgraph_node_p, irr_worklist, i);
-      d = get_cg_data (node);
+      d = get_cg_data (&node, true);
       d->in_worklist = false;
       node->local.tm_may_enter_irr = true;
 
@@ -4800,7 +4862,7 @@ ipa_tm_execute (void)
          if (!is_tm_safe_or_pure (caller->decl)
              && !caller->local.tm_may_enter_irr)
            {
-             d = get_cg_data (caller);
+             d = get_cg_data (&caller, true);
              maybe_push_queue (caller, &irr_worklist, &d->in_worklist);
            }
        }
@@ -4812,7 +4874,8 @@ ipa_tm_execute (void)
          if (ref->use == IPA_REF_ALIAS
              && !caller->local.tm_may_enter_irr)
            {
-             d = get_cg_data (caller);
+             /* ?? Do not traverse aliases here.  */
+             d = get_cg_data (&caller, false);
              maybe_push_queue (caller, &irr_worklist, &d->in_worklist);
            }
        }
@@ -4824,7 +4887,7 @@ ipa_tm_execute (void)
     if (node->reachable && node->lowered
        && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       {
-       d = get_cg_data (node);
+       d = get_cg_data (&node, true);
        if (is_tm_safe (node->decl))
          ipa_tm_diagnose_tm_safe (node);
        else if (d->all_tm_regions)
@@ -4843,7 +4906,7 @@ ipa_tm_execute (void)
        continue;
 
       a = cgraph_function_body_availability (node);
-      d = get_cg_data (node);
+      d = get_cg_data (&node, true);
 
       if (a <= AVAIL_NOT_AVAILABLE)
        doit = is_tm_callable (node->decl);
@@ -4863,7 +4926,7 @@ ipa_tm_execute (void)
       node = VEC_index (cgraph_node_p, tm_callees, i);
       if (node->analyzed)
        {
-         d = get_cg_data (node);
+         d = get_cg_data (&node, true);
          if (d->clone)
            ipa_tm_transform_clone (node);
        }
@@ -4872,7 +4935,7 @@ ipa_tm_execute (void)
     if (node->reachable && node->lowered
        && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       {
-       d = get_cg_data (node);
+       d = get_cg_data (&node, true);
        if (d->all_tm_regions)
          ipa_tm_transform_transaction (node);
       }