[rth, more comments for you below]
On 11/04/11 04:14, Richard Guenther wrote:
new_version = cgraph_create_node (new_decl);
- new_version->analyzed = true;
+ new_version->analyzed = old_version->analyzed;
Hm? analyzed means "with body", sure you have a body if you clone.
new_version->local = old_version->local;
new_version->local.externally_visible = false;
new_version->local.local = true;
@@ -2294,6 +2294,7 @@ cgraph_copy_node_for_versioning (struct
new_version->rtl = old_version->rtl;
new_version->reachable = true;
new_version->count = old_version->count;
+ new_version->lowered = true;
OTOH this isn't necessary true. cgraph exists before lowering.
I don't understand what you want me to do on either of these two
comments. Could you elaborate?
+ /* TM pure functions should not get inlined if the outer function is
+ a TM safe function. */
+ else if (flag_tm
Please move flag checks into the respective prediates. Any reason
why the is_tm_pure () predicate wouldn't already do the correct thing
with !flag_tm?
Done.
+ /* Map gimple stmt to tree label (or list of labels) for transaction
+ restart and abort. */
+ htab_t GTY ((param_is (struct tm_restart_node))) tm_restart;
+
As this maps 'gimple' to tree shouldn't this go to fn->gimple_df instead?
That way you avoid growing generic struct function. Or in to eh_status,
if that looks like a better fit.
Done.
+ /* Mark all calls that can have a transaction restart. */
Why isn't this done when we expand the call? This walking of the
RTL sequence looks like a hack (an easy one, albeit).
+ if (cfun->tm_restart&& is_gimple_call (stmt))
+ {
+ struct tm_restart_node dummy;
+ void **slot;
+
+ dummy.stmt = stmt;
+ slot = htab_find_slot (cfun->tm_restart,&dummy, NO_INSERT);
+ if (slot)
+ {
+ struct tm_restart_node *n = (struct tm_restart_node *) *slot;
+ tree list = n->label_or_list;
+ rtx insn;
+
+ for (insn = next_real_insn (last); !CALL_P (insn);
+ insn = next_real_insn (insn))
+ continue;
+
+ if (TREE_CODE (list) == LABEL_DECL)
+ add_reg_note (insn, REG_TM, label_rtx (list));
+ else
+ for (; list ; list = TREE_CHAIN (list))
+ add_reg_note (insn, REG_TM, label_rtx (TREE_VALUE (list)));
+ }
+ }
I can certainly move this to expand_call_stmt() if you prefer. Do you
have an objection to the RTL walk? This isn't my code, but I'm open to
suggestions on an alternative to implement.
+ /* After expanding, the tm_restart map is no longer needed. */
+ cfun->tm_restart = NULL;
You should still free it, to not confuse the statistics code I think.
Done.
+finish_tm_clone_pairs (void)
+{
+ bool switched = false;
+
+ if (tm_clone_pairs == NULL)
+ return;
+
+ htab_traverse_noresize (tm_clone_pairs, finish_tm_clone_pairs_1,
+ (void *)&switched);
This makes the generated table dependent on memory layout. You
need to walk the pairs in some deterministic order. In fact why not
walk all cgraph_nodes looking for the pairs - they should be still
in the list of clones for a node and you've marked it with DECL_TM_CLONE.
You can then sort them by cgraph node uid.
Did you check bootstrapping GCC with TM enabled and address-space
randomization turned on?
Actually, the table organization is irrelevant, because upon registering
of the table in the runtime, we qsort the entire thing. We then do a
binary search to find items. See _ITM_registerTMCloneTable() and
find_clone() in the libitm runtime.
+/* In gtm-low.c */
+extern bool is_transactional_stmt (const_gimple);
+
gimple.h please. looks like a gimple predicate as well, so the implementation
should be in gimple.c?
Woo hoo! Unused function. I've removed it altogether.
case GIMPLE_GOTO:
- if (!computed_goto_p (stmt))
+ if (!computed_goto_p (stmt))
{
- tree new_dest = main_block_label (gimple_goto_dest (stmt));
- gimple_goto_set_dest (stmt, new_dest);
+ label = gimple_goto_dest (stmt);
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_goto_set_dest (stmt, new_label);
What's the reason for this changes? Optimization?
Yes. Rth can elaborate if you deem necessary.
+/* Verify the contents of a GIMPLE_TRANSACTION. Returns true if there
+ is a problem, otherwise false. */
+
+static bool
+verify_gimple_transaction (gimple stmt)
+{
+ tree lab = gimple_transaction_label (stmt);
+ if (lab != NULL&& TREE_CODE (lab) != LABEL_DECL)
+ return true;
ISTR this has substatements, so you should handle this in
verify_gimple_in_seq_2 and make sure to verify those substatements.
I have added verification for the substatements in
verify_gimple_transaction()...
@@ -4155,6 +4210,9 @@ verify_gimple_stmt (gimple stmt)
case GIMPLE_ASM:
return false;
+ case GIMPLE_TRANSACTION:
+ return verify_gimple_transaction (stmt);
+
Not here.
...but we still need to check the transaction in verify_gimple_stmt()
(as well as in verify_gimple_in_seq_2), because verify_gimple_in_cfg()
will verify a gimple_transaction by calling verify_gimple_stmt, so we
must handle GIMPLE_TRANSACTION in verify_gimple_stmt also.
+ case GIMPLE_TRANSACTION:
+ err |= verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
+ break;
I am calling verify_gimple_transaction() now. See patch.
+ case GIMPLE_TRANSACTION:
+ /* The ABORT edge has a stored label associated with it, otherwise
+ the edges are simply redirectable. */
+ /* ??? We don't really need this label after the cfg is created. */
+ if (e->flags == 0)
+ gimple_transaction_set_label (stmt, gimple_block_label (dest));
So why set it (and thus keep it live)?
This seems like leftovers from a previous incantation. However, I'm not
100% sure, so I have disabled the code, but left it in a comment. A
full bootstrap/regtest revealed no regressions.
rth, do you have any objections to remove this?
Tested on x86-64 Linux.
OK for branch?
p.s. This changelog entry is for ChangeLog.tm, but I will adapt a merged
ChangeLog entry for ChangeLog.tm-merge as well. And will do so from now on.
* tree-cfg.c (verify_gimple_transaction): Verify body. Move down.
(verify_gimple_in_seq_2): Verify the label in a
GIMPLE_TRANSACTION.
* function.h (struct function): Move tm_restart field to struct
gimple_df in tree-flow.h
Move tm_restart_node to tree-flow.h
* tree-flow.h (struct gimple_df): New location for tm_restart
field.
New location for tm_restart_node.
(is_transactional_stmt): Remove.
* trans-mem.c (is_transactional_stmt): Remove.
(make_tm_edge): Field tm_restart is now in gimple_df.
* cfgexpand.c (gimple_expand_cfg): Field tm_restart is now in
cfun->gimple_df.
Free tm_restart.
* cfgexpand.c (expand_gimple_stmt): Field tm_restart is now in
gimple_df.
* ipa-inline.c (can_inline_edge_p): Do not check flag_tm.
* trans-mem.c (is_tm_pure): Check flag_tm.
(is_tm_safe): Same.
Index: ipa-inline.c
===================================================================
--- ipa-inline.c (revision 181028)
+++ ipa-inline.c (working copy)
@@ -286,8 +286,7 @@ can_inline_edge_p (struct cgraph_edge *e
}
/* TM pure functions should not get inlined if the outer function is
a TM safe function. */
- else if (flag_tm
- && is_tm_pure (callee->decl)
+ else if (is_tm_pure (callee->decl)
&& is_tm_safe (e->caller->decl))
{
e->inline_failed = CIF_UNSPECIFIED;
Index: function.h
===================================================================
--- function.h (revision 181028)
+++ function.h (working copy)
@@ -467,14 +467,6 @@ extern GTY(()) struct rtl_data x_rtl;
want to do differently. */
#define crtl (&x_rtl)
-/* This structure is used to map a gimple statement to a label,
- or list of labels to represent transaction restart. */
-
-struct GTY(()) tm_restart_node {
- gimple stmt;
- tree label_or_list;
-};
-
struct GTY(()) stack_usage
{
/* # of bytes of static stack space allocated by the function. */
@@ -526,10 +518,6 @@ struct GTY(()) function {
/* Value histograms attached to particular statements. */
htab_t GTY((skip)) value_histograms;
- /* Map gimple stmt to tree label (or list of labels) for transaction
- restart and abort. */
- htab_t GTY ((param_is (struct tm_restart_node))) tm_restart;
-
/* For function.c. */
/* Points to the FUNCTION_DECL of this function. */
Index: trans-mem.c
===================================================================
--- trans-mem.c (revision 181028)
+++ trans-mem.c (working copy)
@@ -172,9 +172,13 @@ get_attrs_for (const_tree x)
bool
is_tm_pure (const_tree x)
{
- tree attrs = get_attrs_for (x);
- if (attrs)
- return lookup_attribute ("transaction_pure", attrs) != NULL;
+ if (flag_tm)
+ {
+ tree attrs = get_attrs_for (x);
+ if (attrs)
+ return lookup_attribute ("transaction_pure", attrs) != NULL;
+ return false;
+ }
return false;
}
@@ -205,16 +209,17 @@ is_tm_irrevocable (tree x)
bool
is_tm_safe (const_tree x)
{
- tree attrs = get_attrs_for (x);
-
- if (attrs)
+ if (flag_tm)
{
- if (lookup_attribute ("transaction_safe", attrs))
- return true;
- if (lookup_attribute ("transaction_may_cancel_outer", attrs))
- return true;
+ tree attrs = get_attrs_for (x);
+ if (attrs)
+ {
+ if (lookup_attribute ("transaction_safe", attrs))
+ return true;
+ if (lookup_attribute ("transaction_may_cancel_outer", attrs))
+ return true;
+ }
}
-
return false;
}
@@ -270,22 +275,6 @@ is_tm_may_cancel_outer (tree x)
return false;
}
-/* Return true if STMT may alter control flow via a transactional edge. */
-
-bool
-is_transactional_stmt (const_gimple stmt)
-{
- switch (gimple_code (stmt))
- {
- case GIMPLE_CALL:
- return (gimple_call_flags (stmt) & ECF_TM_OPS) != 0;
- case GIMPLE_TRANSACTION:
- return true;
- default:
- return false;
- }
-}
-
/* Return true for built in functions that "end" a transaction. */
bool
@@ -2470,13 +2459,13 @@ make_tm_edge (gimple stmt, basic_block b
void **slot;
struct tm_restart_node *n, dummy;
- if (cfun->tm_restart == NULL)
- cfun->tm_restart = htab_create_ggc (31, struct_ptr_hash,
- struct_ptr_eq, ggc_free);
+ if (cfun->gimple_df->tm_restart == NULL)
+ cfun->gimple_df->tm_restart = htab_create_ggc (31, struct_ptr_hash,
+ struct_ptr_eq, ggc_free);
dummy.stmt = stmt;
dummy.label_or_list = gimple_block_label (region->entry_block);
- slot = htab_find_slot (cfun->tm_restart, &dummy, INSERT);
+ slot = htab_find_slot (cfun->gimple_df->tm_restart, &dummy, INSERT);
n = (struct tm_restart_node *) *slot;
if (n == NULL)
{
Index: cfgexpand.c
===================================================================
--- cfgexpand.c (revision 181028)
+++ cfgexpand.c (working copy)
@@ -2097,13 +2097,13 @@ expand_gimple_stmt (gimple stmt)
}
/* Mark all calls that can have a transaction restart. */
- if (cfun->tm_restart && is_gimple_call (stmt))
+ if (cfun->gimple_df->tm_restart && is_gimple_call (stmt))
{
struct tm_restart_node dummy;
void **slot;
dummy.stmt = stmt;
- slot = htab_find_slot (cfun->tm_restart, &dummy, NO_INSERT);
+ slot = htab_find_slot (cfun->gimple_df->tm_restart, &dummy, NO_INSERT);
if (slot)
{
struct tm_restart_node *n = (struct tm_restart_node *) *slot;
@@ -4483,7 +4483,11 @@ gimple_expand_cfg (void)
naked_return_label = NULL;
/* After expanding, the tm_restart map is no longer needed. */
- cfun->tm_restart = NULL;
+ if (cfun->gimple_df->tm_restart)
+ {
+ htab_delete (cfun->gimple_df->tm_restart);
+ cfun->gimple_df->tm_restart = NULL;
+ }
/* Tag the blocks with a depth number so that change_scope can find
the common parent easily. */
Index: tree-flow.h
===================================================================
--- tree-flow.h (revision 181028)
+++ tree-flow.h (working copy)
@@ -33,6 +33,14 @@ along with GCC; see the file COPYING3.
#include "tree-ssa-alias.h"
+/* This structure is used to map a gimple statement to a label,
+ or list of labels to represent transaction restart. */
+
+struct GTY(()) tm_restart_node {
+ gimple stmt;
+ tree label_or_list;
+};
+
/* Gimple dataflow datastructure. All publicly available fields shall have
gimple_ accessor defined in tree-flow-inline.h, all publicly modifiable
fields should have gimple_set accessor. */
@@ -80,6 +88,10 @@ struct GTY(()) gimple_df {
unsigned int ipa_pta : 1;
struct ssa_operands ssa_operands;
+
+ /* Map gimple stmt to tree label (or list of labels) for transaction
+ restart and abort. */
+ htab_t GTY ((param_is (struct tm_restart_node))) tm_restart;
};
/* Accessors for internal use only. Generic code should use abstraction
@@ -778,9 +790,6 @@ extern bool maybe_duplicate_eh_stmt (gim
extern bool verify_eh_edges (gimple);
extern bool verify_eh_dispatch_edge (gimple);
-/* In gtm-low.c */
-extern bool is_transactional_stmt (const_gimple);
-
/* In tree-ssa-pre.c */
struct pre_expr_d;
void add_to_value (unsigned int, struct pre_expr_d *);
Index: tree-cfg.c
===================================================================
--- tree-cfg.c (revision 181028)
+++ tree-cfg.c (working copy)
@@ -117,6 +117,7 @@ static int gimple_verify_flow_info (void
static void gimple_make_forwarder_block (edge);
static void gimple_cfg2vcg (FILE *);
static gimple first_non_label_stmt (basic_block);
+static bool verify_gimple_transaction (gimple);
/* Flowgraph optimization and cleanup. */
static void gimple_merge_blocks (basic_block, basic_block);
@@ -4098,18 +4099,6 @@ verify_gimple_switch (gimple stmt)
return false;
}
-/* Verify the contents of a GIMPLE_TRANSACTION. Returns true if there
- is a problem, otherwise false. */
-
-static bool
-verify_gimple_transaction (gimple stmt)
-{
- tree lab = gimple_transaction_label (stmt);
- if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
- return true;
- return false;
-}
-
/* Verify a gimple debug statement STMT.
Returns true if anything is wrong. */
@@ -4339,7 +4328,7 @@ verify_gimple_in_seq_2 (gimple_seq stmts
break;
case GIMPLE_TRANSACTION:
- err |= verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
+ err |= verify_gimple_transaction (stmt);
break;
default:
@@ -4355,6 +4344,18 @@ verify_gimple_in_seq_2 (gimple_seq stmts
return err;
}
+/* Verify the contents of a GIMPLE_TRANSACTION. Returns true if there
+ is a problem, otherwise false. */
+
+static bool
+verify_gimple_transaction (gimple stmt)
+{
+ tree lab = gimple_transaction_label (stmt);
+ if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
+ return true;
+ return verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
+}
+
/* Verify the GIMPLE statements inside the statement list STMTS. */
@@ -5122,9 +5123,10 @@ gimple_redirect_edge_and_branch (edge e,
case GIMPLE_TRANSACTION:
/* The ABORT edge has a stored label associated with it, otherwise
the edges are simply redirectable. */
- /* ??? We don't really need this label after the cfg is created. */
- if (e->flags == 0)
+ /* ??? We don't really need this label after the cfg is created.
+ if (&e->flags == 0)
gimple_transaction_set_label (stmt, gimple_block_label (dest));
+ */
break;
default: