===================================================================
@@ -5393,6 +5393,7 @@ extern tree build_tm_abort_call (locatio
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);
===================================================================
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm" } */
+
+int george;
+
+__attribute__((transaction_callable))
+void q2()
+{
+ __transaction [[atomic]]
+ {
+ george=999;
+ }
+ q2();
+}
===================================================================
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm" } */
+
+int george;
+
+void q1()
+{
+ __transaction [[atomic]] {
+ george=999;
+ }
+ q1();
+}
+
+/* { dg-final { scan-assembler-not "ZGTt2q1" } } */
===================================================================
@@ -292,7 +292,7 @@ is_transactional_stmt (const_gimple stmt
/* Return true for built in functions that "end" a transaction. */
-static bool
+bool
is_tm_ending_fndecl (tree fndecl)
{
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
@@ -4279,6 +4279,89 @@ ipa_tm_insert_gettmclone_call (struct cg
return true;
}
+/* Helper function for ipa_tm_transform_calls*. Given a call
+ statement in GSI which resides inside transaction REGION, redirect
+ the call to either its wrapper function, or its clone.
+ PAST_TM_ENDING_STMT is true if we have scanned past the end of one
+ of the TM ending statements. */
+
+static void
+ipa_tm_transform_calls_redirect (struct cgraph_node *node,
+ struct tm_region *region,
+ gimple_stmt_iterator *gsi,
+ bool past_tm_ending_stmt,
+ bool *need_ssa_rename_p)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ struct cgraph_node *new_node;
+ struct cgraph_edge *e = cgraph_edge (node, stmt);
+ tree fndecl = gimple_call_fndecl (stmt);
+
+ /* We only redirect calls inside of a transaction, with the
+ exception of recursive calls to the clone itself. We must make
+ sure recursive calls in a cloned function get redirected to the
+ clone itself, not the original function. So... bail unless we're
+ inside a transaction or we're handling this special case. */
+ if (past_tm_ending_stmt
+ && (e->caller != e->callee
+ || !DECL_IS_TM_CLONE (e->callee->decl)))
+ return;
+
+ /* For a recursive call to the clone, call the clone directly. No
+ need to go through the runtime... */
+ if (e->caller == e->callee
+ && DECL_IS_TM_CLONE (e->callee->decl))
+ fndecl = e->callee->decl;
+ else
+ {
+ /* ...otherwise start looking for a replacement. */
+ fndecl = find_tm_replacement_function (fndecl);
+ }
+
+ /* If there is a replacement, use it, otherwise use the clone. */
+ if (fndecl)
+ {
+ new_node = cgraph_node (fndecl);
+
+ /* ??? Mark all transaction_wrap functions tm_may_enter_irr.
+
+ We can't do this earlier in record_tm_replacement because
+ cgraph_remove_unreachable_nodes is called before we inject
+ references to the node. Further, we can't do this in some
+ nice central place in ipa_tm_execute because we don't have
+ the exact list of wrapper functions that would be used.
+ Marking more wrappers than necessary results in the creation
+ of unnecessary cgraph_nodes, which can cause some of the
+ other IPA passes to crash.
+
+ We do need to mark these nodes so that we get the proper
+ result in expand_call_tm. */
+ new_node->local.tm_may_enter_irr = 1;
+ }
+ else
+ {
+ struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+ new_node = d->clone;
+
+ /* As we've already skipped pure calls and appropriate builtins,
+ and we've already marked irrevocable blocks, if we can't come
+ up with a static replacement, then ask the runtime. */
+ if (new_node == NULL)
+ {
+ *need_ssa_rename_p |=
+ ipa_tm_insert_gettmclone_call (node, region, gsi, stmt);
+ cgraph_remove_edge (e);
+ return;
+ }
+
+ fndecl = new_node->decl;
+ }
+
+ cgraph_redirect_edge_callee (e, new_node);
+ gimple_call_set_fndecl (stmt, fndecl);
+ return;
+}
+
/* Helper function for ipa_tm_transform_calls. For a given BB,
install calls to tm_irrevocable when IRR_BLOCKS are reached,
redirect other calls to the generated transactional clone. */
@@ -4289,6 +4372,7 @@ ipa_tm_transform_calls_1 (struct cgraph_
{
gimple_stmt_iterator gsi;
bool need_ssa_rename = false;
+ bool past_tm_ending_stmt = false;
if (irr_blocks && bitmap_bit_p (irr_blocks, bb->index))
{
@@ -4299,8 +4383,6 @@ ipa_tm_transform_calls_1 (struct cgraph_
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- struct cgraph_edge *e;
- struct cgraph_node *new_node;
tree fndecl;
if (!is_gimple_call (stmt))
@@ -4310,61 +4392,26 @@ ipa_tm_transform_calls_1 (struct cgraph_
fndecl = gimple_call_fndecl (stmt);
- /* For indirect calls, pass the address through the runtime. */
- if (fndecl == NULL)
- {
- need_ssa_rename |=
- ipa_tm_insert_gettmclone_call (node, region, &gsi, stmt);
- continue;
- }
-
- /* Don't scan past the end of the transaction. */
- if (is_tm_ending_fndecl (fndecl))
- break;
- e = cgraph_edge (node, stmt);
-
- /* If there is a replacement, use it, otherwise use the clone. */
- fndecl = find_tm_replacement_function (fndecl);
- if (fndecl)
+ if (!past_tm_ending_stmt)
{
- new_node = cgraph_node (fndecl);
-
- /* ??? Mark all transaction_wrap functions tm_may_enter_irr.
-
- We can't do this earlier in record_tm_replacement because
- cgraph_remove_unreachable_nodes is called before we inject
- references to the node. Further, we can't do this in some
- nice central place in ipa_tm_execute because we don't have
- the exact list of wrapper functions that would be used.
- Marking more wrappers than necessary results in the creation
- of unnecessary cgraph_nodes, which can cause some of the
- other IPA passes to crash.
-
- We do need to mark these nodes so that we get the proper
- result in expand_call_tm. */
- new_node->local.tm_may_enter_irr = 1;
- }
- else
- {
- struct tm_ipa_cg_data *d = get_cg_data (e->callee);
- new_node = d->clone;
-
- /* As we've already skipped pure calls and appropriate builtins,
- and we've already marked irrevocable blocks, if we can't come
- up with a static replacement, then ask the runtime. */
- if (new_node == NULL)
+ /* For indirect calls, pass the address through the runtime. */
+ if (fndecl == NULL)
{
need_ssa_rename |=
- ipa_tm_insert_gettmclone_call (node, region, &gsi, stmt);
- cgraph_remove_edge (e);
+ ipa_tm_insert_gettmclone_call (node, region, &gsi, stmt);
continue;
}
- fndecl = new_node->decl;
+ if (is_tm_ending_fndecl (fndecl))
+ past_tm_ending_stmt = true;
}
- cgraph_redirect_edge_callee (e, new_node);
- gimple_call_set_fndecl (stmt, fndecl);
+ /* Redirect edges to the appropriate replacement or clone. This
+ will even redirect calls outside of a transaction, but only
+ if they're recursive calls to the clone. */
+ ipa_tm_transform_calls_redirect (node, region, &gsi,
+ past_tm_ending_stmt,
+ &need_ssa_rename);
}
return need_ssa_rename;
@@ -4500,7 +4547,7 @@ ipa_tm_execute (void)
bitmap_obstack_initialize (&tm_obstack);
bb_in_TM_region = BITMAP_ALLOC (&tm_obstack);
- /* Build a bitmap of all BB"s inside transaction regions. */
+ /* Build a bitmap of all BB's inside transaction regions. */
for (node = cgraph_nodes; node; node = node->next)
if (node->reachable && node->lowered
&& cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
@@ -4509,7 +4556,9 @@ ipa_tm_execute (void)
regions = ipa_tm_region_init (node);
for ( ; regions; regions = regions->next)
{
- get_tm_region_blocks (regions->entry_block, NULL, NULL,
+ get_tm_region_blocks (regions->entry_block,
+ regions->exit_blocks,
+ NULL,
bb_in_TM_region, false);
}
}
===================================================================
@@ -2253,6 +2253,13 @@ is_ctrl_altering_stmt (gimple t)
/* A call also alters control flow if it does not return. */
if (flags & ECF_NORETURN)
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
+ && is_tm_ending_fndecl (gimple_call_fndecl (t)))
+ return true;
}
break;