+2015-12-22 Richard Henderson <rth@redhat.com>
+
+ PR ipa/67811
+ * gimple.h (struct gtransaction): Add label_norm, label_uninst;
+ replace label with label_over.
+ (gimple_build_transaction): Remove label parameter.
+ (gimple_transaction_label_norm): New.
+ (gimple_transaction_label_uninst): New.
+ (gimple_transaction_label_over): Rename from gimple_transaction_label.
+ (gimple_transaction_label_norm_ptr): New.
+ (gimple_transaction_label_uninst_ptr): New.
+ (gimple_transaction_label_over_ptr): Rename from
+ gimple_transaction_label_ptr.
+ (gimple_transaction_set_label_norm): New.
+ (gimple_transaction_set_label_uninst): New.
+ (gimple_transaction_set_label_over): Rename from
+ gimple_transaction_set_label.
+ * gimple-pretty-print.c (dump_gimple_transaction): Update.
+ * gimple-streamer-in.c (input_gimple_stmt) [GIMPLE_TRANSACTION]: Same.
+ * gimple-streamer-out.c (output_gimple_stmt) [GIMPLE_TRANSACTION]: Same.
+ * gimple-walk.c (walk_gimple_op) [GIMPLE_TRANSACTION]: Same.
+ * tree-cfg.c (make_edges_bb) [GIMPLE_TRANSACTION]: Same.
+ (cleanup_dead_labels) [GIMPLE_TRANSACTION]: Same.
+ (verify_gimple_transaction): Same.
+ (gimple_redirect_edge_and_branch) [GIMPLE_TRANSACTION]: Same.
+ * tree-inline.c (remap_gimple_stmt) [GIMPLE_TRANSACTION]: Same.
+ * gimple.c (gimple_build_transaction): Remove label parameter;
+ initialize all three label memebers.
+ * gimplify.c (gimplify_transaction): Update call
+ to gimple_build_transaction.
+ * trans-mem.c (make_tm_uninst): New.
+ (lower_transaction): Create uninstrumented code path here...
+ (ipa_tm_scan_calls_transaction): ... not here.
+ (ipa_uninstrument_transaction): Remove.
+
2015-12-22 Peter Bergner <bergner@vnet.ibm.com>
PR target/68772
if (flags & TDF_RAW)
{
dump_gimple_fmt (buffer, spc, flags,
- "%G [SUBCODE=%x,LABEL=%T] <%+BODY <%S> >",
- gs, subcode, gimple_transaction_label (gs),
+ "%G [SUBCODE=%x,NORM=%T,UNINST=%T,OVER=%T] "
+ "<%+BODY <%S> >",
+ gs, subcode, gimple_transaction_label_norm (gs),
+ gimple_transaction_label_uninst (gs),
+ gimple_transaction_label_over (gs),
gimple_transaction_body (gs));
}
else
pp_string (buffer, "__transaction_atomic");
subcode &= ~GTMA_DECLARATION_MASK;
- if (subcode || gimple_transaction_label (gs))
+ if (gimple_transaction_body (gs))
+ {
+ newline_and_indent (buffer, spc + 2);
+ pp_left_brace (buffer);
+ pp_newline (buffer);
+ dump_gimple_seq (buffer, gimple_transaction_body (gs),
+ spc + 4, flags);
+ newline_and_indent (buffer, spc + 2);
+ pp_right_brace (buffer);
+ }
+ else
{
pp_string (buffer, " //");
- if (gimple_transaction_label (gs))
+ if (gimple_transaction_label_norm (gs))
+ {
+ pp_string (buffer, " NORM=");
+ dump_generic_node (buffer, gimple_transaction_label_norm (gs),
+ spc, flags, false);
+ }
+ if (gimple_transaction_label_uninst (gs))
{
- pp_string (buffer, " LABEL=");
- dump_generic_node (buffer, gimple_transaction_label (gs),
+ pp_string (buffer, " UNINST=");
+ dump_generic_node (buffer, gimple_transaction_label_uninst (gs),
+ spc, flags, false);
+ }
+ if (gimple_transaction_label_over (gs))
+ {
+ pp_string (buffer, " OVER=");
+ dump_generic_node (buffer, gimple_transaction_label_over (gs),
spc, flags, false);
}
if (subcode)
pp_right_bracket (buffer);
}
}
-
- if (!gimple_seq_empty_p (gimple_transaction_body (gs)))
- {
- newline_and_indent (buffer, spc + 2);
- pp_left_brace (buffer);
- pp_newline (buffer);
- dump_gimple_seq (buffer, gimple_transaction_body (gs),
- spc + 4, flags);
- newline_and_indent (buffer, spc + 2);
- pp_right_brace (buffer);
- }
}
}
break;
case GIMPLE_TRANSACTION:
- gimple_transaction_set_label (as_a <gtransaction *> (stmt),
- stream_read_tree (ib, data_in));
+ gimple_transaction_set_label_norm (as_a <gtransaction *> (stmt),
+ stream_read_tree (ib, data_in));
+ gimple_transaction_set_label_uninst (as_a <gtransaction *> (stmt),
+ stream_read_tree (ib, data_in));
+ gimple_transaction_set_label_over (as_a <gtransaction *> (stmt),
+ stream_read_tree (ib, data_in));
break;
default:
case GIMPLE_TRANSACTION:
{
- gtransaction *trans_stmt = as_a <gtransaction *> (stmt);
- gcc_assert (gimple_transaction_body (trans_stmt) == NULL);
- stream_write_tree (ob, gimple_transaction_label (trans_stmt), true);
+ gtransaction *txn = as_a <gtransaction *> (stmt);
+ gcc_assert (gimple_transaction_body (txn) == NULL);
+ stream_write_tree (ob, gimple_transaction_label_norm (txn), true);
+ stream_write_tree (ob, gimple_transaction_label_uninst (txn), true);
+ stream_write_tree (ob, gimple_transaction_label_over (txn), true);
}
break;
break;
case GIMPLE_TRANSACTION:
- ret = walk_tree (gimple_transaction_label_ptr (
- as_a <gtransaction *> (stmt)),
- callback_op, wi, pset);
- if (ret)
- return ret;
+ {
+ gtransaction *txn = as_a <gtransaction *> (stmt);
+
+ ret = walk_tree (gimple_transaction_label_norm_ptr (txn),
+ callback_op, wi, pset);
+ if (ret)
+ return ret;
+ ret = walk_tree (gimple_transaction_label_uninst_ptr (txn),
+ callback_op, wi, pset);
+ if (ret)
+ return ret;
+ ret = walk_tree (gimple_transaction_label_over_ptr (txn),
+ callback_op, wi, pset);
+ if (ret)
+ return ret;
+ }
break;
case GIMPLE_OMP_RETURN:
/* Build a GIMPLE_TRANSACTION statement. */
gtransaction *
-gimple_build_transaction (gimple_seq body, tree label)
+gimple_build_transaction (gimple_seq body)
{
gtransaction *p
= as_a <gtransaction *> (gimple_alloc (GIMPLE_TRANSACTION, 0));
gimple_transaction_set_body (p, body);
- gimple_transaction_set_label (p, label);
+ gimple_transaction_set_label_norm (p, 0);
+ gimple_transaction_set_label_uninst (p, 0);
+ gimple_transaction_set_label_over (p, 0);
return p;
}
/* [ WORD 10 ] */
gimple_seq body;
- /* [ WORD 11 ] */
- tree label;
+ /* [ WORD 11-13 ] */
+ tree label_norm;
+ tree label_uninst;
+ tree label_over;
};
#define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP) SYM,
gomp_teams *gimple_build_omp_teams (gimple_seq, tree);
gomp_atomic_load *gimple_build_omp_atomic_load (tree, tree);
gomp_atomic_store *gimple_build_omp_atomic_store (tree);
-gtransaction *gimple_build_transaction (gimple_seq, tree);
+gtransaction *gimple_build_transaction (gimple_seq);
extern void gimple_seq_add_stmt (gimple_seq *, gimple *);
extern void gimple_seq_add_stmt_without_update (gimple_seq *, gimple *);
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
static inline gimple_seq
gimple_transaction_body (gtransaction *transaction_stmt)
{
- return *gimple_transaction_body_ptr (transaction_stmt);
+ return transaction_stmt->body;
}
/* Return the label associated with a GIMPLE_TRANSACTION. */
static inline tree
-gimple_transaction_label (const gtransaction *transaction_stmt)
+gimple_transaction_label_norm (const gtransaction *transaction_stmt)
{
- return transaction_stmt->label;
+ return transaction_stmt->label_norm;
}
static inline tree *
-gimple_transaction_label_ptr (gtransaction *transaction_stmt)
+gimple_transaction_label_norm_ptr (gtransaction *transaction_stmt)
{
- return &transaction_stmt->label;
+ return &transaction_stmt->label_norm;
+}
+
+static inline tree
+gimple_transaction_label_uninst (const gtransaction *transaction_stmt)
+{
+ return transaction_stmt->label_uninst;
+}
+
+static inline tree *
+gimple_transaction_label_uninst_ptr (gtransaction *transaction_stmt)
+{
+ return &transaction_stmt->label_uninst;
+}
+
+static inline tree
+gimple_transaction_label_over (const gtransaction *transaction_stmt)
+{
+ return transaction_stmt->label_over;
+}
+
+static inline tree *
+gimple_transaction_label_over_ptr (gtransaction *transaction_stmt)
+{
+ return &transaction_stmt->label_over;
}
/* Return the subcode associated with a GIMPLE_TRANSACTION. */
/* Set the label associated with a GIMPLE_TRANSACTION. */
static inline void
-gimple_transaction_set_label (gtransaction *transaction_stmt, tree label)
+gimple_transaction_set_label_norm (gtransaction *transaction_stmt, tree label)
+{
+ transaction_stmt->label_norm = label;
+}
+
+static inline void
+gimple_transaction_set_label_uninst (gtransaction *transaction_stmt, tree label)
+{
+ transaction_stmt->label_uninst = label;
+}
+
+static inline void
+gimple_transaction_set_label_over (gtransaction *transaction_stmt, tree label)
{
- transaction_stmt->label = label;
+ transaction_stmt->label_over = label;
}
/* Set the subcode associated with a GIMPLE_TRANSACTION. */
transaction_stmt->subcode = subcode;
}
-
/* Return a pointer to the return value for GIMPLE_RETURN GS. */
static inline tree *
body_stmt = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body);
pop_gimplify_context (body_stmt);
- trans_stmt = gimple_build_transaction (body, NULL);
+ trans_stmt = gimple_build_transaction (body);
if (TRANSACTION_EXPR_OUTER (expr))
subcode = GTMA_IS_OUTER;
else if (TRANSACTION_EXPR_RELAXED (expr))
+2015-12-22 Richard Henderson <rth@redhat.com>
+
+ * g++.dg/tm/noexcept-1.C: Update expected must_not_throw count.
+ * g++.dg/tm/noexcept-4.C: Likewise.
+ * g++.dg/tm/noexcept-5.C: Likewise.
+ * g++.dg/tm/pr67811.C: New.
+
2015-12-22 Peter Bergner <bergner@vnet.ibm.com>
PR target/68772
return global;
}
-/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 12 "tmlower" } } */
/* { dg-final { scan-tree-dump-times "ITM_RU" 6 "tmmark" } } */
+ __transaction_atomic noexcept (global + 6);
}
-/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 12 "tmlower" } } */
/* { dg-final { scan-tree-dump-times "ITM_RU" 6 "tmmark" } } */
}
}
}
-/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 1 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 2 "tmlower" } } */
/* { dg-final { scan-tree-dump-times "ITM_RU" 1 "tmmark" } } */
--- /dev/null
+// { dg-do compile }
+// { dg-options "-fgnu-tm" }
+
+void f()
+{
+ __transaction_relaxed {
+ try { throw 42; }
+ catch (...) { }
+ }
+}
+
*state |= GTMA_HAVE_LOAD | GTMA_HAVE_STORE;
}
+/* Iterate through the statements in the sequence, moving labels
+ (and thus edges) of transactions from "label_norm" to "label_uninst". */
+
+static tree
+make_tm_uninst (gimple_stmt_iterator *gsi, bool *handled_ops_p,
+ struct walk_stmt_info *)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+
+ if (gtransaction *txn = dyn_cast <gtransaction *> (stmt))
+ {
+ *handled_ops_p = true;
+ txn->label_uninst = txn->label_norm;
+ txn->label_norm = NULL;
+ }
+ else
+ *handled_ops_p = !gimple_has_substatements (stmt);
+
+ return NULL_TREE;
+}
+
/* Lower a GIMPLE_TRANSACTION statement. */
static void
g = gimple_build_try (gimple_transaction_body (stmt),
gimple_seq_alloc_with_stmt (g), GIMPLE_TRY_FINALLY);
- gsi_insert_after (gsi, g, GSI_CONTINUE_LINKING);
- gimple_transaction_set_body (stmt, NULL);
+ /* For a (potentially) outer transaction, create two paths. */
+ gimple_seq uninst = NULL;
+ if (outer_state == NULL)
+ {
+ uninst = copy_gimple_seq_and_replace_locals (g);
+ /* In the uninstrumented copy, reset inner transactions to have only
+ an uninstrumented code path. */
+ memset (&this_wi, 0, sizeof (this_wi));
+ walk_gimple_seq (uninst, make_tm_uninst, NULL, &this_wi);
+ }
+
+ tree label1 = create_artificial_label (UNKNOWN_LOCATION);
+ gsi_insert_after (gsi, gimple_build_label (label1), GSI_CONTINUE_LINKING);
+ gsi_insert_after (gsi, g, GSI_CONTINUE_LINKING);
+ gimple_transaction_set_label_norm (stmt, label1);
/* If the transaction calls abort or if this is an outer transaction,
add an "over" label afterwards. */
- if ((this_state & (GTMA_HAVE_ABORT))
+ tree label3 = NULL;
+ if ((this_state & GTMA_HAVE_ABORT)
+ || outer_state == NULL
|| (gimple_transaction_subcode (stmt) & GTMA_IS_OUTER))
{
- tree label = create_artificial_label (UNKNOWN_LOCATION);
- gimple_transaction_set_label (stmt, label);
- gsi_insert_after (gsi, gimple_build_label (label), GSI_CONTINUE_LINKING);
+ label3 = create_artificial_label (UNKNOWN_LOCATION);
+ gimple_transaction_set_label_over (stmt, label3);
}
+ if (uninst != NULL)
+ {
+ gsi_insert_after (gsi, gimple_build_goto (label3), GSI_CONTINUE_LINKING);
+
+ tree label2 = create_artificial_label (UNKNOWN_LOCATION);
+ gsi_insert_after (gsi, gimple_build_label (label2), GSI_CONTINUE_LINKING);
+ gsi_insert_seq_after (gsi, uninst, GSI_CONTINUE_LINKING);
+ gimple_transaction_set_label_uninst (stmt, label2);
+ }
+
+ if (label3 != NULL)
+ gsi_insert_after (gsi, gimple_build_label (label3), GSI_CONTINUE_LINKING);
+
+ gimple_transaction_set_body (stmt, NULL);
+
/* Record the set of operations found for use later. */
this_state |= gimple_transaction_subcode (stmt) & GTMA_DECLARATION_MASK;
gimple_transaction_set_subcode (stmt, this_state);
}
}
-/* Duplicate the basic blocks in QUEUE for use in the uninstrumented
- code path. QUEUE are the basic blocks inside the transaction
- represented in REGION.
-
- Later in split_code_paths() we will add the conditional to choose
- between the two alternatives. */
-
-static void
-ipa_uninstrument_transaction (struct tm_region *region,
- vec<basic_block> queue)
-{
- gimple *transaction = region->transaction_stmt;
- basic_block transaction_bb = gimple_bb (transaction);
- int n = queue.length ();
- basic_block *new_bbs = XNEWVEC (basic_block, n);
-
- copy_bbs (queue.address (), n, new_bbs, NULL, 0, NULL, NULL, transaction_bb,
- true);
- edge e = make_edge (transaction_bb, new_bbs[0], EDGE_TM_UNINSTRUMENTED);
- add_phi_args_after_copy (new_bbs, n, e);
-
- // Now we will have a GIMPLE_ATOMIC with 3 possible edges out of it.
- // a) EDGE_FALLTHRU into the transaction
- // b) EDGE_TM_ABORT out of the transaction
- // c) EDGE_TM_UNINSTRUMENTED into the uninstrumented blocks.
-
- free (new_bbs);
-}
-
/* A subroutine of ipa_tm_scan_calls_transaction and ipa_tm_scan_calls_clone.
Queue all callees within block BB. */
ipa_tm_scan_calls_transaction (struct tm_ipa_cg_data *d,
cgraph_node_queue *callees_p)
{
- struct tm_region *r;
-
d->transaction_blocks_normal = BITMAP_ALLOC (&tm_obstack);
d->all_tm_regions = all_tm_regions;
- for (r = all_tm_regions; r; r = r->next)
+ for (tm_region *r = all_tm_regions; r; r = r->next)
{
vec<basic_block> bbs;
basic_block bb;
unsigned i;
bbs = get_tm_region_blocks (r->entry_block, r->exit_blocks, NULL,
- d->transaction_blocks_normal, false);
-
- // Generate the uninstrumented code path for this transaction.
- ipa_uninstrument_transaction (r, bbs);
+ d->transaction_blocks_normal, false, false);
FOR_EACH_VEC_ELT (bbs, i, bb)
ipa_tm_scan_calls_block (callees_p, bb, false);
bbs.release ();
}
-
- // ??? copy_bbs should maintain cgraph edges for the blocks as it is
- // copying them, rather than forcing us to do this externally.
- cgraph_edge::rebuild_edges ();
-
- // ??? In ipa_uninstrument_transaction we don't try to update dominators
- // because copy_bbs doesn't return a VEC like iterate_fix_dominators expects.
- // Instead, just release dominators here so update_ssa recomputes them.
- free_dominance_info (CDI_DOMINATORS);
-
- // When building the uninstrumented code path, copy_bbs will have invoked
- // create_new_def_for starting an "ssa update context". There is only one
- // instance of this context, so resolve ssa updates before moving on to
- // the next function.
- update_ssa (TODO_update_ssa);
}
/* Scan all calls in NODE as if this is the transactional clone,
case GIMPLE_TRANSACTION:
{
- tree abort_label
- = gimple_transaction_label (as_a <gtransaction *> (last));
- if (abort_label)
- make_edge (bb, label_to_block (abort_label), EDGE_TM_ABORT);
- fallthru = true;
+ gtransaction *txn = as_a <gtransaction *> (last);
+ tree label1 = gimple_transaction_label_norm (txn);
+ tree label2 = gimple_transaction_label_uninst (txn);
+
+ if (label1)
+ make_edge (bb, label_to_block (label1), EDGE_FALLTHRU);
+ if (label2)
+ make_edge (bb, label_to_block (label2),
+ EDGE_TM_UNINSTRUMENTED | (label1 ? 0 : EDGE_FALLTHRU));
+
+ tree label3 = gimple_transaction_label_over (txn);
+ if (gimple_transaction_subcode (txn) & GTMA_HAVE_ABORT)
+ make_edge (bb, label_to_block (label3), EDGE_TM_ABORT);
+
+ fallthru = false;
}
break;
case GIMPLE_TRANSACTION:
{
- gtransaction *trans_stmt = as_a <gtransaction *> (stmt);
- tree label = gimple_transaction_label (trans_stmt);
+ gtransaction *txn = as_a <gtransaction *> (stmt);
+
+ label = gimple_transaction_label_norm (txn);
+ if (label)
+ {
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_transaction_set_label_norm (txn, new_label);
+ }
+
+ label = gimple_transaction_label_uninst (txn);
+ if (label)
+ {
+ new_label = main_block_label (label);
+ if (new_label != label)
+ gimple_transaction_set_label_uninst (txn, new_label);
+ }
+
+ label = gimple_transaction_label_over (txn);
if (label)
{
- tree new_label = main_block_label (label);
+ new_label = main_block_label (label);
if (new_label != label)
- gimple_transaction_set_label (trans_stmt, new_label);
+ gimple_transaction_set_label_over (txn, new_label);
}
}
break;
static bool
verify_gimple_transaction (gtransaction *stmt)
{
- tree lab = gimple_transaction_label (stmt);
+ tree lab;
+
+ lab = gimple_transaction_label_norm (stmt);
if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
return true;
+ lab = gimple_transaction_label_uninst (stmt);
+ if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
+ return true;
+ lab = gimple_transaction_label_over (stmt);
+ if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
+ return true;
+
return verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
}
break;
case GIMPLE_TRANSACTION:
- /* The ABORT edge has a stored label associated with it, otherwise
- the edges are simply redirectable. */
- if (e->flags == 0)
- gimple_transaction_set_label (as_a <gtransaction *> (stmt),
- gimple_block_label (dest));
+ if (e->flags & EDGE_TM_ABORT)
+ gimple_transaction_set_label_over (as_a <gtransaction *> (stmt),
+ gimple_block_label (dest));
+ else if (e->flags & EDGE_TM_UNINSTRUMENTED)
+ gimple_transaction_set_label_uninst (as_a <gtransaction *> (stmt),
+ gimple_block_label (dest));
+ else
+ gimple_transaction_set_label_norm (as_a <gtransaction *> (stmt),
+ gimple_block_label (dest));
break;
default:
gtransaction *new_trans_stmt;
s1 = remap_gimple_seq (gimple_transaction_body (old_trans_stmt),
id);
- copy = new_trans_stmt
- = gimple_build_transaction (
- s1,
- gimple_transaction_label (old_trans_stmt));
- gimple_transaction_set_subcode (
- new_trans_stmt,
+ copy = new_trans_stmt = gimple_build_transaction (s1);
+ gimple_transaction_set_subcode (new_trans_stmt,
gimple_transaction_subcode (old_trans_stmt));
+ gimple_transaction_set_label_norm (new_trans_stmt,
+ gimple_transaction_label_norm (old_trans_stmt));
+ gimple_transaction_set_label_uninst (new_trans_stmt,
+ gimple_transaction_label_uninst (old_trans_stmt));
+ gimple_transaction_set_label_over (new_trans_stmt,
+ gimple_transaction_label_over (old_trans_stmt));
}
break;