This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [trans-mem] lots of irrevocability fixes
Total revamp of irrevocability and associated machinery.
We now have a tm_may_enter_irr bit in cgraph which we use throughout.
We now use/set a GTMA_DOES_GO_IRREVOKABLE bit for atomic blocks in addition
to GTMA_MAY_ENTER_IRREVOKABLE. GTMA_DOES_GO_IRREVOKABLE is set when we
are absolutely sure the atomic block will go into serial irrevocable
mode. GTMA_MAY_ENTER_IRREVOKABLE is set when the block *may* enter
irrevocable mode.
Both of these flags allow us to accurately set PR_DOESGOIRREVOKABLE and
PR_HASNOIRREVOKABLE for the run-time.
I have renamed GTMA_MUST_CALL_IRREVOKABLE into GTMA_DOES_GO_IRREVOKABLE
to better reflect the run-time API. No sense using a different name for
every stage and confusing the hell out of me.
Tested on x86-64 Linux.
Approved off-list by Richard. Committing.
* cgraph.h (cgraph_local_info): Add tm_may_enter_irr.
* gimple-pretty-print.c (dump_gimple_tm_atomic_subcode): Rename
GTMA_MUST_CALL_IRREVOKABLE to GTMA_DOES_GO_IRREVOKABLE.
* trans-mem.c (expand_call_tm): Handle irrevocability.
(execute_tm_mark): Set GTMA_DOES_GO_IRREVOKABLE and
GTMA_MAY_ENTER_IRREVOKABLE.
(expand_tm_atomic): Set PR_DOESGOIRREVOKABLE,
PR_UNINSTRUMENTEDCODE, and PR_HASNOIRREVOKABLE appropriately.
(ipa_tm_scan_calls_tm_atomic): Set tm_may_enter_irr for
replacement functions.
(ipa_tm_scan_calls_clone): Same.
(ipa_tm_transform_tm_atomic): If the block goes irrevocable, don't
transform anything.
(ipa_tm_transform_clone): Set tm_may_enter_irr for non safe
functions.
(ipa_tm_execute): Set tm_may_enter_irr for non-local tm_callable
functions. Swap loops calling ipa_tm_transform_clone and
ipa_tm_transform_tm_atomic.
* gimple.h: Rename GTMA_MUST_CALL_IRREVOKABLE into
GTMA_DOES_GO_IRREVOKABLE.
Index: cgraph.h
===================================================================
--- cgraph.h (revision 150023)
+++ cgraph.h (working copy)
@@ -98,6 +98,9 @@ struct GTY(()) cgraph_local_info {
/* True if the function is going to be emitted in some other translation
unit, referenced from vtable. */
unsigned vtable_method : 1;
+
+ /* True if the function may enter serial irrevocable mode. */
+ unsigned tm_may_enter_irr : 1;
};
/* Information about the function that needs to be computed globally
Index: testsuite/gcc.dg/tm/irrevocable-4.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-4.c (revision 0)
+++ testsuite/gcc.dg/tm/irrevocable-4.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
+
+extern void bar(void) __attribute__((tm_callable));
+void orig(void);
+void xyz(void) __attribute__((tm_wrap (orig)));
+
+
+foo()
+{
+ __tm_atomic orig();
+}
+
+/* { dg-final { scan-tree-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmmark" } } */
Index: testsuite/gcc.dg/tm/irrevocable-2.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-2.c (revision 150023)
+++ testsuite/gcc.dg/tm/irrevocable-2.c (working copy)
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmedge" } */
/* Test that a direct call to __builtin__ITM_changeTransactionMode()
sets the irrevocable bit. */
@@ -16,4 +16,5 @@ foo()
}
}
-/* { dg-final { scan-ipa-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmipa" } } */
+/* { dg-final { scan-tree-dump-times "doesGoIrrevocable" 1 "tmedge" } } */
+/* { dg-final { scan-tree-dump-times "hasNoIrrevocable" 0 "tmedge" } } */
Index: testsuite/gcc.dg/tm/irrevocable-3.c
===================================================================
--- testsuite/gcc.dg/tm/irrevocable-3.c (revision 0)
+++ testsuite/gcc.dg/tm/irrevocable-3.c (revision 0)
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
+
+extern void bar(void) __attribute__((tm_callable));
+
+foo()
+{
+ __tm_atomic bar();
+}
+
+/* { dg-final { scan-tree-dump-times "GTMA_MAY_ENTER_IRREVOKABLE" 1 "tmmark" } } */
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c (revision 150023)
+++ gimple-pretty-print.c (working copy)
@@ -1134,8 +1134,8 @@ dump_gimple_tm_atomic_subcode (pretty_pr
pp_string (buffer, "GTMA_HAVE_CALL_TM ");
if (subcode & GTMA_MAY_ENTER_IRREVOKABLE)
pp_string (buffer, "GTMA_MAY_ENTER_IRREVOKABLE ");
- if (subcode & GTMA_MUST_CALL_IRREVOKABLE)
- pp_string (buffer, "GTMA_MUST_CALL_IRREVOKABLE ");
+ if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+ pp_string (buffer, "GTMA_DOES_GO_IRREVOKABLE ");
if (subcode & GTMA_HAVE_UNCOMMITTED_THROW)
pp_string (buffer, "GTMA_HAVE_UNCOMMITTED_THROW ");
pp_string (buffer, "]");
Index: trans-mem.c
===================================================================
--- trans-mem.c (revision 150023)
+++ trans-mem.c (working copy)
@@ -731,7 +731,7 @@ tm_region_init_1 (gimple stmt, void *xda
struct tm_region *region;
basic_block bb = gimple_bb (stmt);
- /* ??? Verify that the statement (and the block) havn't been deleted. */
+ /* ??? Verify that the statement (and the block) haven't been deleted. */
gcc_assert (bb != NULL);
gcc_assert (gimple_code (stmt) == GIMPLE_TM_ATOMIC);
@@ -1103,6 +1103,7 @@ expand_call_tm (struct tm_region *region
gimple stmt = gsi_stmt (*gsi);
tree lhs = gimple_call_lhs (stmt);
tree fn_decl;
+ struct cgraph_node *node;
if (is_tm_pure_call (stmt))
return false;
@@ -1111,7 +1112,22 @@ expand_call_tm (struct tm_region *region
/* For indirect calls, we already generated a call into the runtime. */
if (!fn_decl)
- return false;
+ {
+ tree fn = gimple_call_fn (stmt);
+
+ /* We are guaranteed never to go irrevocable on a safe or pure
+ call, and the pure call was handled above. */
+ if (fn && is_tm_safe (TREE_TYPE (fn)))
+ return false;
+ else
+ tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
+
+ return false;
+ }
+
+ node = cgraph_node (fn_decl);
+ if (node->local.tm_may_enter_irr)
+ tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
if (is_tm_abort (fn_decl))
{
@@ -1188,13 +1204,13 @@ execute_tm_mark (void)
/* Collect a new SUBCODE set, now that optimizations are done... */
gimple_tm_atomic_set_subcode (region->tm_atomic_stmt, 0);
- /* ...but keep the bits that require IPA to collect. Ideally
- we should do IPA again to make sure things like DCE didn't
- invalidate irrevocability, but we are certain not to
- introduce things that go irrevocable, so it's safe to keep
- the irrevocability bit. */
- gimple_tm_atomic_set_subcode (region->tm_atomic_stmt,
- subcode & GTMA_MAY_ENTER_IRREVOKABLE);
+ /* ...but keep the GTMA_DOES_GO_IRREVOKABLE bit, since we can
+ almost be sure never to insert anything during optimization that
+ will cause certain irrevocability to be reversed. */
+ if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+ gimple_tm_atomic_set_subcode (region->tm_atomic_stmt,
+ GTMA_DOES_GO_IRREVOKABLE |
+ GTMA_MAY_ENTER_IRREVOKABLE);
VEC_quick_push (basic_block, queue, region->entry_block);
do
@@ -1309,11 +1325,14 @@ expand_tm_atomic (struct tm_region *regi
/* ??? There are plenty of bits here we're not computing. */
subcode = gimple_tm_atomic_subcode (region->tm_atomic_stmt);
- flags = PR_INSTRUMENTEDCODE;
+ if (subcode & GTMA_DOES_GO_IRREVOKABLE)
+ flags = PR_DOESGOIRREVOKABLE | PR_UNINSTRUMENTEDCODE;
+ else
+ flags = PR_INSTRUMENTEDCODE;
+ if ((subcode & GTMA_MAY_ENTER_IRREVOKABLE) == 0)
+ flags |= PR_HASNOIRREVOKABLE;
if ((subcode & GTMA_HAVE_ABORT) == 0)
flags |= PR_HASNOABORT;
- if (subcode & GTMA_MUST_CALL_IRREVOKABLE)
- flags |= PR_DOESGOIRREVOKABLE;
t2 = build_int_cst (TREE_TYPE (status), flags);
g = gimple_build_call (tm_start, 1, t2);
gimple_call_set_lhs (g, status);
@@ -1531,7 +1550,7 @@ struct gimple_opt_pass pass_tm_memopt =
(d) Place tm_irrevokable calls at the beginning of the relevant
blocks. Special case here is the entry block for the entire
- tm_atomic region; there we mark it MUST_CALL_IRREVOKABLE for
+ tm_atomic region; there we mark it GTMA_DOES_GO_IRREVOKABLE for
the library to begin the region in serial mode. Decrement
the call count for all callees in the irrevokable region.
@@ -1621,6 +1640,7 @@ ipa_tm_scan_calls_tm_atomic (struct cgra
cgraph_node_queue *callees_p)
{
struct cgraph_edge *e;
+ tree replacement;
for (e = node->callees; e ; e = e->next_callee)
if (gimple_call_in_tm_atomic_p (e->call_stmt))
@@ -1629,8 +1649,12 @@ ipa_tm_scan_calls_tm_atomic (struct cgra
if (is_tm_pure_call (e->call_stmt))
continue;
- if (find_tm_replacement_function (e->callee->decl))
- continue;
+ if ((replacement = find_tm_replacement_function (e->callee->decl)))
+ {
+ struct cgraph_local_info *local = cgraph_local_info (replacement);
+ local->tm_may_enter_irr = true;
+ continue;
+ }
d = get_cg_data (e->callee);
d->tm_callers_normal++;
@@ -1648,13 +1672,24 @@ ipa_tm_scan_calls_clone (struct cgraph_n
struct cgraph_edge *e;
for (e = node->callees; e ; e = e->next_callee)
- if (!is_tm_pure_call (e->call_stmt))
- {
- struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+ {
+ tree replacement = find_tm_replacement_function (e->callee->decl);
- d->tm_callers_clone++;
- maybe_push_queue (e->callee, callees_p, &d->in_callee_queue);
- }
+ if (replacement)
+ {
+ struct cgraph_local_info *local = cgraph_local_info (replacement);
+ local->tm_may_enter_irr = true;
+ continue;
+ }
+
+ if (!is_tm_pure_call (e->call_stmt))
+ {
+ struct tm_ipa_cg_data *d = get_cg_data (e->callee);
+
+ d->tm_callers_clone++;
+ maybe_push_queue (e->callee, callees_p, &d->in_callee_queue);
+ }
+ }
}
/* The function NODE has been detected to be irrevokable. Push all
@@ -1972,6 +2007,8 @@ ipa_tm_create_version (struct cgraph_nod
if (!DECL_EXTERNAL (old_decl))
tree_function_versioning (old_decl, new_decl, NULL, false, NULL);
+ /* ?? 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;
/* Determine if the symbol is already a valid C++ mangled name. Do this
@@ -2211,10 +2248,18 @@ ipa_tm_transform_tm_atomic (struct cgrap
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
calculate_dominance_info (CDI_DOMINATORS);
- /* ??? Update the marks for the GIMPLE_TM_ATOMIC node, in particular
- note the MUST_CALL_IRREVOKABLE and don't transform anything. */
for (region = d->all_tm_regions; region; region = region->next)
{
+ /* If we're sure to go irrevocable, don't transform anything. */
+ if (d->irrevokable_blocks_normal
+ && bitmap_bit_p (d->irrevokable_blocks_normal,
+ region->entry_block->index))
+ {
+ tm_atomic_subcode_ior (region, GTMA_DOES_GO_IRREVOKABLE);
+ tm_atomic_subcode_ior (region, GTMA_MAY_ENTER_IRREVOKABLE);
+ break;
+ }
+
need_ssa_rename |=
ipa_tm_transform_calls (node, region, region->entry_block,
d->irrevokable_blocks_normal);
@@ -2245,6 +2290,9 @@ ipa_tm_transform_clone (struct cgraph_no
push_cfun (DECL_STRUCT_FUNCTION (current_function_decl));
calculate_dominance_info (CDI_DOMINATORS);
+ if (!is_tm_safe (TREE_TYPE (current_function_decl)))
+ node->local.tm_may_enter_irr = true;
+
need_ssa_rename =
ipa_tm_transform_calls (d->clone, NULL, single_succ (ENTRY_BLOCK_PTR),
d->irrevokable_blocks_clone);
@@ -2333,8 +2381,17 @@ ipa_tm_execute (void)
continue;
}
- if (a >= AVAIL_OVERWRITABLE && !d->is_irrevokable)
- ipa_tm_scan_calls_clone (node, &tm_callees);
+ if (a >= AVAIL_OVERWRITABLE)
+ {
+ if (!d->is_irrevokable)
+ ipa_tm_scan_calls_clone (node, &tm_callees);
+ }
+ else
+ {
+ /* Non-local tm_callable may enter irrevocable mode. */
+ if (is_tm_callable (node->decl))
+ node->local.tm_may_enter_irr = true;
+ }
}
/* Iterate scans until no more work to be done. Prefer not to use
@@ -2387,14 +2444,6 @@ ipa_tm_execute (void)
}
/* Redirect calls to the new clones, and insert irrevokable marks. */
- for (node = cgraph_nodes; node; node = node->next)
- if (node->reachable && node->lowered
- && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
- {
- d = get_cg_data (node);
- if (d->all_tm_regions)
- ipa_tm_transform_tm_atomic (node);
- }
for (i = 0; i < VEC_length (cgraph_node_p, tm_callees); ++i)
{
node = VEC_index (cgraph_node_p, tm_callees, i);
@@ -2405,6 +2454,14 @@ ipa_tm_execute (void)
ipa_tm_transform_clone (node);
}
}
+ for (node = cgraph_nodes; node; node = node->next)
+ if (node->reachable && node->lowered
+ && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
+ {
+ d = get_cg_data (node);
+ if (d->all_tm_regions)
+ ipa_tm_transform_tm_atomic (node);
+ }
/* Free and clear all data structures. */
VEC_free (cgraph_node_p, heap, tm_callees);
Index: gimple.h
===================================================================
--- gimple.h (revision 150023)
+++ gimple.h (working copy)
@@ -728,12 +728,14 @@ struct GTY(()) gimple_statement_omp_atom
/* Atomic statement may enter serial irrevocable mode in its dynamic
scope. */
#define GTMA_MAY_ENTER_IRREVOKABLE (1u << 4)
-/* An irrevocable block post-dominates the entire transaction, such
+/* Atomic statement is sure to enter 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_MUST_CALL_IRREVOKABLE (1u << 5)
+#define GTMA_DOES_GO_IRREVOKABLE (1u << 5)
#define GTMA_HAVE_UNCOMMITTED_THROW (1u << 6)
struct GTY(()) gimple_statement_tm_atomic