marshalling to implement data sharing and copying clauses.
Contributed by Diego Novillo <dnovillo@redhat.com>
- Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GCC.
case GIMPLE_TRY: \
case GIMPLE_CATCH: \
case GIMPLE_EH_FILTER: \
+ case GIMPLE_TRANSACTION: \
/* The sub-statements for these should be walked. */ \
*handled_ops_p = false; \
break;
if (TREE_ADDRESSABLE (decl))
return true;
+ /* lower_send_shared_vars only uses copy-in, but not copy-out
+ for these. */
+ if (TREE_READONLY (decl)
+ || ((TREE_CODE (decl) == RESULT_DECL
+ || TREE_CODE (decl) == PARM_DECL)
+ && DECL_BY_REFERENCE (decl)))
+ return false;
+
/* Disallow copy-in/out in nested parallel if
decl is shared in outer parallel, otherwise
each thread could store the shared variable
in its own copy-in location, making the
variable no longer really shared. */
- if (!TREE_READONLY (decl) && shared_ctx->is_nested)
+ if (shared_ctx->is_nested)
{
omp_context *up;
}
}
- /* For tasks avoid using copy-in/out, unless they are readonly
- (in which case just copy-in is used). As tasks can be
+ /* For tasks avoid using copy-in/out. As tasks can be
deferred or executed in different thread, when GOMP_task
returns, the task hasn't necessarily terminated. */
- if (!TREE_READONLY (decl) && is_task_ctx (shared_ctx))
+ if (is_task_ctx (shared_ctx))
{
tree outer;
maybe_mark_addressable_and_ret:
return omp_copy_decl_2 (var, DECL_NAME (var), TREE_TYPE (var), ctx);
}
+/* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
+ as appropriate. */
+static tree
+omp_build_component_ref (tree obj, tree field)
+{
+ tree ret = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL);
+ if (TREE_THIS_VOLATILE (field))
+ TREE_THIS_VOLATILE (ret) |= 1;
+ if (TREE_READONLY (field))
+ TREE_READONLY (ret) |= 1;
+ return ret;
+}
+
/* Build tree nodes to access the field for VAR on the receiver side. */
static tree
field = x;
x = build_simple_mem_ref (ctx->receiver_decl);
- x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL);
+ x = omp_build_component_ref (x, field);
if (by_ref)
x = build_simple_mem_ref (x);
build_sender_ref (tree var, omp_context *ctx)
{
tree field = lookup_sfield (var, ctx);
- return build3 (COMPONENT_REF, TREE_TYPE (field),
- ctx->sender_decl, field, NULL);
+ return omp_build_component_ref (ctx->sender_decl, field);
}
/* Add a new field for VAR inside the structure CTX->SENDER_DECL. */
old_fn = current_function_decl;
push_cfun (child_cfun);
current_function_decl = child_fn;
- bind = gimplify_body (&DECL_SAVED_TREE (child_fn), child_fn, false);
+ bind = gimplify_body (child_fn, false);
seq = gimple_seq_alloc ();
gimple_seq_add_stmt (&seq, bind);
new_seq = maybe_catch_exception (seq);
/* Check OpenMP nesting restrictions. */
-static void
-check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
+static bool
+check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
{
switch (gimple_code (stmt))
{
case GIMPLE_OMP_TASK:
if (is_gimple_call (stmt))
{
- warning (0, "barrier region may not be closely nested inside "
- "of work-sharing, critical, ordered, master or "
- "explicit task region");
- return;
+ error_at (gimple_location (stmt),
+ "barrier region may not be closely nested inside "
+ "of work-sharing, critical, ordered, master or "
+ "explicit task region");
+ return false;
}
- warning (0, "work-sharing region may not be closely nested inside "
- "of work-sharing, critical, ordered, master or explicit "
- "task region");
- return;
+ error_at (gimple_location (stmt),
+ "work-sharing region may not be closely nested inside "
+ "of work-sharing, critical, ordered, master or explicit "
+ "task region");
+ return false;
case GIMPLE_OMP_PARALLEL:
- return;
+ return true;
default:
break;
}
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SINGLE:
case GIMPLE_OMP_TASK:
- warning (0, "master region may not be closely nested inside "
- "of work-sharing or explicit task region");
- return;
+ error_at (gimple_location (stmt),
+ "master region may not be closely nested inside "
+ "of work-sharing or explicit task region");
+ return false;
case GIMPLE_OMP_PARALLEL:
- return;
+ return true;
default:
break;
}
{
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_TASK:
- warning (0, "ordered region may not be closely nested inside "
- "of critical or explicit task region");
- return;
+ error_at (gimple_location (stmt),
+ "ordered region may not be closely nested inside "
+ "of critical or explicit task region");
+ return false;
case GIMPLE_OMP_FOR:
if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
OMP_CLAUSE_ORDERED) == NULL)
- warning (0, "ordered region must be closely nested inside "
+ {
+ error_at (gimple_location (stmt),
+ "ordered region must be closely nested inside "
"a loop region with an ordered clause");
- return;
+ return false;
+ }
+ return true;
case GIMPLE_OMP_PARALLEL:
- return;
+ return true;
default:
break;
}
&& (gimple_omp_critical_name (stmt)
== gimple_omp_critical_name (ctx->stmt)))
{
- warning (0, "critical region may not be nested inside a critical "
- "region with the same name");
- return;
+ error_at (gimple_location (stmt),
+ "critical region may not be nested inside a critical "
+ "region with the same name");
+ return false;
}
break;
default:
break;
}
+ return true;
}
/* Check the OpenMP nesting restrictions. */
if (ctx != NULL)
{
+ bool remove = false;
if (is_gimple_omp (stmt))
- check_omp_nesting_restrictions (stmt, ctx);
+ remove = !check_omp_nesting_restrictions (stmt, ctx);
else if (is_gimple_call (stmt))
{
tree fndecl = gimple_call_fndecl (stmt);
if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
- check_omp_nesting_restrictions (stmt, ctx);
+ remove = !check_omp_nesting_restrictions (stmt, ctx);
+ }
+ if (remove)
+ {
+ stmt = gimple_build_nop ();
+ gsi_replace (gsi, stmt, false);
}
}
{
int fn_index, start_ix, next_ix;
+ if (fd.chunk_size == NULL
+ && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
+ fd.chunk_size = integer_zero_node;
gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
fn_index = (fd.sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
? 3 : fd.sched_kind;
unsigned i, casei;
bool exit_reachable = region->cont != NULL;
- gcc_assert (exit_reachable == (region->exit != NULL));
+ gcc_assert (region->exit != NULL);
entry_bb = region->entry;
l0_bb = single_succ (entry_bb);
l1_bb = region->cont;
l2_bb = region->exit;
- if (exit_reachable)
+ if (single_pred_p (l2_bb) && single_pred (l2_bb) == l0_bb)
+ l2 = gimple_block_label (l2_bb);
+ else
{
- if (single_pred_p (l2_bb) && single_pred (l2_bb) == l0_bb)
- l2 = gimple_block_label (l2_bb);
+ /* This can happen if there are reductions. */
+ len = EDGE_COUNT (l0_bb->succs);
+ gcc_assert (len > 0);
+ e = EDGE_SUCC (l0_bb, len - 1);
+ si = gsi_last_bb (e->dest);
+ l2 = NULL_TREE;
+ if (gsi_end_p (si)
+ || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
+ l2 = gimple_block_label (e->dest);
else
- {
- /* This can happen if there are reductions. */
- len = EDGE_COUNT (l0_bb->succs);
- gcc_assert (len > 0);
- e = EDGE_SUCC (l0_bb, len - 1);
- si = gsi_last_bb (e->dest);
- l2 = NULL_TREE;
- if (gsi_end_p (si)
- || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
- l2 = gimple_block_label (e->dest);
- else
- FOR_EACH_EDGE (e, ei, l0_bb->succs)
+ FOR_EACH_EDGE (e, ei, l0_bb->succs)
+ {
+ si = gsi_last_bb (e->dest);
+ if (gsi_end_p (si)
+ || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
{
- si = gsi_last_bb (e->dest);
- if (gsi_end_p (si)
- || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
- {
- l2 = gimple_block_label (e->dest);
- break;
- }
+ l2 = gimple_block_label (e->dest);
+ break;
}
- }
- default_bb = create_empty_bb (l1_bb->prev_bb);
+ }
}
+ if (exit_reachable)
+ default_bb = create_empty_bb (l1_bb->prev_bb);
else
- {
- default_bb = create_empty_bb (l0_bb);
- l2 = gimple_block_label (default_bb);
- }
+ default_bb = create_empty_bb (l0_bb);
/* We will build a switch() with enough cases for all the
GIMPLE_OMP_SECTION regions, a '0' case to handle the end of more work
vnext = NULL_TREE;
}
- i = 0;
- if (exit_reachable)
- {
- t = build_case_label (build_int_cst (unsigned_type_node, 0), NULL, l2);
- VEC_quick_push (tree, label_vec, t);
- i++;
- }
+ t = build_case_label (build_int_cst (unsigned_type_node, 0), NULL, l2);
+ VEC_quick_push (tree, label_vec, t);
+ i = 1;
/* Convert each GIMPLE_OMP_SECTION into a CASE_LABEL_EXPR. */
for (inner = region->inner, casei = 1;
gsi_remove (&si, true);
single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
-
- /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
- si = gsi_last_bb (l2_bb);
- if (gimple_omp_return_nowait_p (gsi_stmt (si)))
- t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
- else
- t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
- stmt = gimple_build_call (t, 0);
- gsi_insert_after (&si, stmt, GSI_SAME_STMT);
- gsi_remove (&si, true);
}
+ /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
+ si = gsi_last_bb (l2_bb);
+ if (gimple_omp_return_nowait_p (gsi_stmt (si)))
+ t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
+ else
+ t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
+ stmt = gimple_build_call (t, 0);
+ gsi_insert_after (&si, stmt, GSI_SAME_STMT);
+ gsi_remove (&si, true);
+
set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb);
}
operation as a normal volatile load. */
static bool
-expand_omp_atomic_load (basic_block load_bb, tree addr, tree loaded_val)
+expand_omp_atomic_load (basic_block load_bb, tree addr,
+ tree loaded_val, int index)
{
- /* FIXME */
- (void) load_bb;
- (void) addr;
- (void) loaded_val;
- return false;
+ enum built_in_function tmpbase;
+ gimple_stmt_iterator gsi;
+ basic_block store_bb;
+ location_t loc;
+ gimple stmt;
+ tree decl, call, type, itype;
+
+ gsi = gsi_last_bb (load_bb);
+ stmt = gsi_stmt (gsi);
+ gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
+ loc = gimple_location (stmt);
+
+ /* ??? If the target does not implement atomic_load_optab[mode], and mode
+ is smaller than word size, then expand_atomic_load assumes that the load
+ is atomic. We could avoid the builtin entirely in this case. */
+
+ tmpbase = (enum built_in_function) (BUILT_IN_ATOMIC_LOAD_N + index + 1);
+ decl = builtin_decl_explicit (tmpbase);
+ if (decl == NULL_TREE)
+ return false;
+
+ type = TREE_TYPE (loaded_val);
+ itype = TREE_TYPE (TREE_TYPE (decl));
+
+ call = build_call_expr_loc (loc, decl, 2, addr,
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+ if (!useless_type_conversion_p (type, itype))
+ call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
+ call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
+
+ force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
+ gsi_remove (&gsi, true);
+
+ store_bb = single_succ (load_bb);
+ gsi = gsi_last_bb (store_bb);
+ gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
+ gsi_remove (&gsi, true);
+
+ if (gimple_in_ssa_p (cfun))
+ update_ssa (TODO_update_ssa_no_phi);
+
+ return true;
}
/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
operation as a normal volatile store. */
static bool
-expand_omp_atomic_store (basic_block load_bb, tree addr)
+expand_omp_atomic_store (basic_block load_bb, tree addr,
+ tree loaded_val, tree stored_val, int index)
{
- /* FIXME */
- (void) load_bb;
- (void) addr;
- return false;
+ enum built_in_function tmpbase;
+ gimple_stmt_iterator gsi;
+ basic_block store_bb = single_succ (load_bb);
+ location_t loc;
+ gimple stmt;
+ tree decl, call, type, itype;
+ enum machine_mode imode;
+ bool exchange;
+
+ gsi = gsi_last_bb (load_bb);
+ stmt = gsi_stmt (gsi);
+ gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
+
+ /* If the load value is needed, then this isn't a store but an exchange. */
+ exchange = gimple_omp_atomic_need_value_p (stmt);
+
+ gsi = gsi_last_bb (store_bb);
+ stmt = gsi_stmt (gsi);
+ gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE);
+ loc = gimple_location (stmt);
+
+ /* ??? If the target does not implement atomic_store_optab[mode], and mode
+ is smaller than word size, then expand_atomic_store assumes that the store
+ is atomic. We could avoid the builtin entirely in this case. */
+
+ tmpbase = (exchange ? BUILT_IN_ATOMIC_EXCHANGE_N : BUILT_IN_ATOMIC_STORE_N);
+ tmpbase = (enum built_in_function) ((int) tmpbase + index + 1);
+ decl = builtin_decl_explicit (tmpbase);
+ if (decl == NULL_TREE)
+ return false;
+
+ type = TREE_TYPE (stored_val);
+
+ /* Dig out the type of the function's second argument. */
+ itype = TREE_TYPE (decl);
+ itype = TYPE_ARG_TYPES (itype);
+ itype = TREE_CHAIN (itype);
+ itype = TREE_VALUE (itype);
+ imode = TYPE_MODE (itype);
+
+ if (exchange && !can_atomic_exchange_p (imode, true))
+ return false;
+
+ if (!useless_type_conversion_p (itype, type))
+ stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val);
+ call = build_call_expr_loc (loc, decl, 3, addr, stored_val,
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+ if (exchange)
+ {
+ if (!useless_type_conversion_p (type, itype))
+ call = build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
+ call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
+ }
+
+ force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
+ gsi_remove (&gsi, true);
+
+ /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */
+ gsi = gsi_last_bb (load_bb);
+ gsi_remove (&gsi, true);
+
+ if (gimple_in_ssa_p (cfun))
+ update_ssa (TODO_update_ssa_no_phi);
+
+ return true;
}
/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
- operation as a __sync_fetch_and_op builtin. INDEX is log2 of the
+ operation as a __atomic_fetch_op builtin. INDEX is log2 of the
size of the data type, and thus usable to find the index of the builtin
decl. Returns false if the expression is not of the proper form. */
{
enum built_in_function oldbase, newbase, tmpbase;
tree decl, itype, call;
- direct_optab optab, oldoptab, newoptab;
tree lhs, rhs;
basic_block store_bb = single_succ (load_bb);
gimple_stmt_iterator gsi;
gimple stmt;
location_t loc;
+ enum tree_code code;
bool need_old, need_new;
+ enum machine_mode imode;
/* We expect to find the following sequences:
return false;
/* Check for one of the supported fetch-op operations. */
- switch (gimple_assign_rhs_code (stmt))
+ code = gimple_assign_rhs_code (stmt);
+ switch (code)
{
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
- oldbase = BUILT_IN_SYNC_FETCH_AND_ADD_N;
- newbase = BUILT_IN_SYNC_ADD_AND_FETCH_N;
- optab = sync_add_optab;
- oldoptab = sync_old_add_optab;
- newoptab = sync_new_add_optab;
+ oldbase = BUILT_IN_ATOMIC_FETCH_ADD_N;
+ newbase = BUILT_IN_ATOMIC_ADD_FETCH_N;
break;
case MINUS_EXPR:
- oldbase = BUILT_IN_SYNC_FETCH_AND_SUB_N;
- newbase = BUILT_IN_SYNC_SUB_AND_FETCH_N;
- optab = sync_add_optab;
- oldoptab = sync_old_add_optab;
- newoptab = sync_new_add_optab;
+ oldbase = BUILT_IN_ATOMIC_FETCH_SUB_N;
+ newbase = BUILT_IN_ATOMIC_SUB_FETCH_N;
break;
case BIT_AND_EXPR:
- oldbase = BUILT_IN_SYNC_FETCH_AND_AND_N;
- newbase = BUILT_IN_SYNC_AND_AND_FETCH_N;
- optab = sync_and_optab;
- oldoptab = sync_old_and_optab;
- newoptab = sync_new_and_optab;
+ oldbase = BUILT_IN_ATOMIC_FETCH_AND_N;
+ newbase = BUILT_IN_ATOMIC_AND_FETCH_N;
break;
case BIT_IOR_EXPR:
- oldbase = BUILT_IN_SYNC_FETCH_AND_OR_N;
- newbase = BUILT_IN_SYNC_OR_AND_FETCH_N;
- optab = sync_ior_optab;
- oldoptab = sync_old_ior_optab;
- newoptab = sync_new_ior_optab;
+ oldbase = BUILT_IN_ATOMIC_FETCH_OR_N;
+ newbase = BUILT_IN_ATOMIC_OR_FETCH_N;
break;
case BIT_XOR_EXPR:
- oldbase = BUILT_IN_SYNC_FETCH_AND_XOR_N;
- newbase = BUILT_IN_SYNC_XOR_AND_FETCH_N;
- optab = sync_xor_optab;
- oldoptab = sync_old_xor_optab;
- newoptab = sync_new_xor_optab;
+ oldbase = BUILT_IN_ATOMIC_FETCH_XOR_N;
+ newbase = BUILT_IN_ATOMIC_XOR_FETCH_N;
break;
default:
return false;
}
+
/* Make sure the expression is of the proper form. */
if (operand_equal_p (gimple_assign_rhs1 (stmt), loaded_val, 0))
rhs = gimple_assign_rhs2 (stmt);
if (decl == NULL_TREE)
return false;
itype = TREE_TYPE (TREE_TYPE (decl));
+ imode = TYPE_MODE (itype);
- if (need_new)
- {
- /* expand_sync_fetch_operation can always compensate when interested
- in the new value. */
- if (direct_optab_handler (newoptab, TYPE_MODE (itype))
- == CODE_FOR_nothing
- && direct_optab_handler (oldoptab, TYPE_MODE (itype))
- == CODE_FOR_nothing)
- return false;
- }
- else if (need_old)
- {
- /* When interested in the old value, expand_sync_fetch_operation
- can compensate only if the operation is reversible. AND and OR
- are not reversible. */
- if (direct_optab_handler (oldoptab, TYPE_MODE (itype))
- == CODE_FOR_nothing
- && (oldbase == BUILT_IN_SYNC_FETCH_AND_AND_N
- || oldbase == BUILT_IN_SYNC_FETCH_AND_OR_N
- || direct_optab_handler (newoptab, TYPE_MODE (itype))
- == CODE_FOR_nothing))
- return false;
- }
- else if (direct_optab_handler (optab, TYPE_MODE (itype)) == CODE_FOR_nothing)
+ /* We could test all of the various optabs involved, but the fact of the
+ matter is that (with the exception of i486 vs i586 and xadd) all targets
+ that support any atomic operaton optab also implements compare-and-swap.
+ Let optabs.c take care of expanding any compare-and-swap loop. */
+ if (!can_compare_and_swap_p (imode, true))
return false;
gsi = gsi_last_bb (load_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
- call = build_call_expr_loc (loc, decl, 2, addr,
- fold_convert_loc (loc, itype, rhs));
+
+ /* OpenMP does not imply any barrier-like semantics on its atomic ops.
+ It only requires that the operation happen atomically. Thus we can
+ use the RELAXED memory model. */
+ call = build_call_expr_loc (loc, decl, 3, addr,
+ fold_convert_loc (loc, itype, rhs),
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+
if (need_old || need_new)
{
lhs = need_old ? loaded_val : stored_val;
edge e;
enum built_in_function fncode;
+ /* ??? We need a non-pointer interface to __atomic_compare_exchange in
+ order to use the RELAXED memory model effectively. */
fncode = (enum built_in_function)((int)BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+ index + 1);
cmpxchg = builtin_decl_explicit (fncode);
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
itype = TREE_TYPE (TREE_TYPE (cmpxchg));
- if (direct_optab_handler (sync_compare_and_swap_optab, TYPE_MODE (itype))
- == CODE_FOR_nothing)
+ if (!can_compare_and_swap_p (TYPE_MODE (itype), true))
return false;
/* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
loaded_val = *addr;
and replace
- GIMPLE_OMP_ATOMIC_ATORE (stored_val) with
+ GIMPLE_OMP_ATOMIC_STORE (stored_val) with
*addr = stored_val;
*/
/* __sync builtins require strict data alignment. */
if (exact_log2 (align) >= index)
{
- /* Atomic load. FIXME: have some target hook signalize what loads
- are actually atomic? */
+ /* Atomic load. */
if (loaded_val == stored_val
&& (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
|| GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
&& GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
- && expand_omp_atomic_load (load_bb, addr, loaded_val))
+ && expand_omp_atomic_load (load_bb, addr, loaded_val, index))
return;
- /* Atomic store. FIXME: have some target hook signalize what
- stores are actually atomic? */
+ /* Atomic store. */
if ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
|| GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
&& GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
&& store_bb == single_succ (load_bb)
&& first_stmt (store_bb) == store
- && expand_omp_atomic_store (load_bb, addr))
+ && expand_omp_atomic_store (load_bb, addr, loaded_val,
+ stored_val, index))
return;
/* When possible, use specialized atomic update functions. */
if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
- && store_bb == single_succ (load_bb))
- {
- if (expand_omp_atomic_fetch_op (load_bb, addr,
- loaded_val, stored_val, index))
- return;
- }
+ && store_bb == single_succ (load_bb)
+ && expand_omp_atomic_fetch_op (load_bb, addr,
+ loaded_val, stored_val, index))
+ return;
/* If we don't have specialized __sync builtins, try and implement
as a compare and swap loop. */
sf = (tree) n->value;
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_simple_mem_ref_loc (loc, sarg);
- src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = omp_build_component_ref (src, sf);
t = build2 (MODIFY_EXPR, TREE_TYPE (*p), *p, src);
append_to_statement_list (t, &list);
}
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_simple_mem_ref_loc (loc, sarg);
- src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = omp_build_component_ref (src, sf);
dst = build_simple_mem_ref_loc (loc, arg);
- dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ dst = omp_build_component_ref (dst, f);
t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
append_to_statement_list (t, &list);
break;
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_simple_mem_ref_loc (loc, sarg);
- src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = omp_build_component_ref (src, sf);
if (use_pointer_for_field (decl, NULL) || is_reference (decl))
src = build_simple_mem_ref_loc (loc, src);
}
else
src = decl;
dst = build_simple_mem_ref_loc (loc, arg);
- dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ dst = omp_build_component_ref (dst, f);
t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
append_to_statement_list (t, &list);
break;
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_simple_mem_ref_loc (loc, sarg);
- src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = omp_build_component_ref (src, sf);
if (use_pointer_for_field (decl, NULL))
src = build_simple_mem_ref_loc (loc, src);
}
else
src = decl;
dst = build_simple_mem_ref_loc (loc, arg);
- dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ dst = omp_build_component_ref (dst, f);
t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
append_to_statement_list (t, &list);
break;
sf = (tree) n->value;
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_simple_mem_ref_loc (loc, sarg);
- src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
+ src = omp_build_component_ref (src, sf);
src = build_simple_mem_ref_loc (loc, src);
dst = build_simple_mem_ref_loc (loc, arg);
- dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
+ dst = omp_build_component_ref (dst, f);
t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
append_to_statement_list (t, &list);
n = splay_tree_lookup (ctx->field_map,
df = (tree) n->value;
df = *(tree *) pointer_map_contains (tcctx.cb.decl_map, df);
ptr = build_simple_mem_ref_loc (loc, arg);
- ptr = build3 (COMPONENT_REF, TREE_TYPE (df), ptr, df, NULL);
+ ptr = omp_build_component_ref (ptr, df);
t = build2 (MODIFY_EXPR, TREE_TYPE (ptr), ptr,
build_fold_addr_expr_loc (loc, dst));
append_to_statement_list (t, &list);
lower_omp (gimple_try_eval (stmt), ctx);
lower_omp (gimple_try_cleanup (stmt), ctx);
break;
+ case GIMPLE_TRANSACTION:
+ lower_omp (gimple_transaction_body (stmt), ctx);
+ break;
case GIMPLE_BIND:
lower_omp (gimple_bind_body (stmt), ctx);
break;