Commit a509ebb5 by Razya Ladelsky

2007-09-23 Razya Ladelsky

            Zdenek Dvorak

        OMP_ATOMIC Changes,
        Reduction support for automatic parallelization.

        * expr.c (expand_expr_real_1): Add cases for OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * Makefile.in: Add dependencies to expr.o, tree-parloops.o, omp-low.o
        * tree-pretty-print.c (dump_generic_node): Add OMP_ATOMIC_LOAD
        and OMP_ATOMIC_STORE.
        * tree.h (OMP_DIRECTIVE_P): Add OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * gimple-low.c (lower_stmt): Same.
        * gimplify.c (gimplify_expr): Same.
        (gimplify_omp_atomic_fetch_op, gimplify_omp_atomic_pipeline,
        gimplify_omp_atomic_mutex): Remove.
        (gimplify_omp_atomic): Change it to simply gimplify the
        statement instead of expanding it.
        * omp-low.c: Add includes to optabs.h, cfgloop.h.
        (expand_omp_atomic, expand_omp_atomic_pipeline,
        goa_stabilize_expr, expand_omp_atomic_mutex,
        expand_omp_atomic_fetch_op): New functions to implement
        expansion of OMP_ATOMIC.
        (expand_omp, build_omp_regions_1): Add support for
        OMP_ATOMIC_LOAD/OMP_ATOMIC_STORE.
        * tree-cfg.c (make_edges): add case for OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * tree-gimple.c (is_gimple_stmt): Add OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * tree-parloops.c: add include to tree-vectorizer.h.
        (reduction_info): New structure for reduction.
        (reduction_list): New list to represent list of reductions
        per loop.
        (struct data_arg): New helper structure for reduction.
        (reduction_info_hash, reduction_info_eq, reduction_phi,
        initialize_reductions,
        create_call_for_reduction, create_phi_for_local_result,
        create_call_for_reduction_1, create_loads_for_reductions,
        create_final_loads_for_reduction): New functions.
        (loop_parallel_p): Identify reductions, add reduction_list parameter.
        (separate_decls_in_loop_name): Support reduction variables.
        (separate_decls_in_loop): Add reduction_list and ld_st_data arguments,
        call create_loads_for_reduction for each reduction.
        (canonicalize_loop_ivs): Identify reductions, add reduction_list
        parameter.
        (transform_to_exit_first_loop): Add reduction support, add
        reduction_list parameter.
        (gen_parallel_loop): Add reduction_list parameter. Add call
        separate_decls_in_loop with
        the new argument. Traverse reductions and call
        initialize_reductions, create_call_for_reduction.
        (parallelize_loops): Create and delete the reduction list.
        (add_field_for_name): Change use of data parameter. Add fields for
        reductions.
        * tree-vectorizer.h (vect_analyze_loop_form): Add declaration.
        * tree-vect-analyze.c (vect_analyze_loop_form): export it.
        * tree.def: Add definitions for OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * tree-inline.c (estimate_num_insns_1): add cases for
        OMP_ATOMIC_LOAD, OMP_ATOMIC_STORE.
        * tree-cfg.c (make_edges): Add OMP_ATOMIC_LOAD,
        OMP_ATOMIC_STORE.
        * tree-ssa-operands.c (get_addr_dereference_operands):
        New function. Subroutine of get_indirect_ref_operands.
        (get_indirect_ref_operands): Call get_addr_dereference_operands.
        (get_expr_operands): Support OMP_ATOMIC_LOAD, OMP_ATOMIC_STORE.

From-SVN: r129716
parent 245a5fe5
2007-09-23 Razya Ladelsky
Zdenek Dvorak
OMP_ATOMIC Changes,
Reduction support for automatic parallelization.
* expr.c (expand_expr_real_1): Add cases for OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* Makefile.in: Add dependencies to expr.o, tree-parloops.o, omp-low.o
* tree-pretty-print.c (dump_generic_node): Add OMP_ATOMIC_LOAD
and OMP_ATOMIC_STORE.
* tree.h (OMP_DIRECTIVE_P): Add OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* gimple-low.c (lower_stmt): Same.
* gimplify.c (gimplify_expr): Same.
(gimplify_omp_atomic_fetch_op, gimplify_omp_atomic_pipeline,
gimplify_omp_atomic_mutex): Remove.
(gimplify_omp_atomic): Change it to simply gimplify the
statement instead of expanding it.
* omp-low.c: Add includes to optabs.h, cfgloop.h.
(expand_omp_atomic, expand_omp_atomic_pipeline,
goa_stabilize_expr, expand_omp_atomic_mutex,
expand_omp_atomic_fetch_op): New functions to implement
expansion of OMP_ATOMIC.
(expand_omp, build_omp_regions_1): Add support for
OMP_ATOMIC_LOAD/OMP_ATOMIC_STORE.
* tree-cfg.c (make_edges): add case for OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* tree-gimple.c (is_gimple_stmt): Add OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* tree-parloops.c: add include to tree-vectorizer.h.
(reduction_info): New structure for reduction.
(reduction_list): New list to represent list of reductions
per loop.
(struct data_arg): New helper structure for reduction.
(reduction_info_hash, reduction_info_eq, reduction_phi,
initialize_reductions,
create_call_for_reduction, create_phi_for_local_result,
create_call_for_reduction_1, create_loads_for_reductions,
create_final_loads_for_reduction): New functions.
(loop_parallel_p): Identify reductions, add reduction_list parameter.
(separate_decls_in_loop_name): Support reduction variables.
(separate_decls_in_loop): Add reduction_list and ld_st_data arguments,
call create_loads_for_reduction for each reduction.
(canonicalize_loop_ivs): Identify reductions, add reduction_list
parameter.
(transform_to_exit_first_loop): Add reduction support, add
reduction_list parameter.
(gen_parallel_loop): Add reduction_list parameter. Add call
separate_decls_in_loop with
the new argument. Traverse reductions and call
initialize_reductions, create_call_for_reduction.
(parallelize_loops): Create and delete the reduction list.
(add_field_for_name): Change use of data parameter. Add fields for
reductions.
* tree-vectorizer.h (vect_analyze_loop_form): Add declaration.
* tree-vect-analyze.c (vect_analyze_loop_form): export it.
* tree.def: Add definitions for OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* tree-inline.c (estimate_num_insns_1): add cases for
OMP_ATOMIC_LOAD, OMP_ATOMIC_STORE.
* tree-cfg.c (make_edges): Add OMP_ATOMIC_LOAD,
OMP_ATOMIC_STORE.
* tree-ssa-operands.c (get_addr_dereference_operands):
New function. Subroutine of get_indirect_ref_operands.
(get_indirect_ref_operands): Call get_addr_dereference_operands.
(get_expr_operands): Support OMP_ATOMIC_LOAD, OMP_ATOMIC_STORE.
2007-10-29 Hans-Peter Nilsson <hp@axis.com> 2007-10-29 Hans-Peter Nilsson <hp@axis.com>
* config/cris/cris.c: Include df.h. * config/cris/cris.c: Include df.h.
...@@ -2234,7 +2234,7 @@ gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ ...@@ -2234,7 +2234,7 @@ gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ omp-low.o : omp-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(RTL_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_H) \ $(RTL_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) toplev.h tree-pass.h \ $(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) toplev.h tree-pass.h \
$(GGC_H) $(SPLAY_TREE_H) $(GGC_H) $(SPLAY_TREE_H) $(OPTABS_H) $(CFGLOOP_H)
tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \ $(TREE_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \
$(TM_H) coretypes.h $(TM_H) coretypes.h
...@@ -2278,7 +2278,8 @@ tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ ...@@ -2278,7 +2278,8 @@ tree-loop-linear.o: tree-loop-linear.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TARGET_H) tree-chrec.h $(OBSTACK_H) $(TARGET_H) tree-chrec.h $(OBSTACK_H)
tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_FLOW_H) $(TREE_H) $(RTL_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(GGC_H) \ $(TREE_FLOW_H) $(TREE_H) $(RTL_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(GGC_H) \
$(DIAGNOSTIC_H) tree-pass.h $(SCEV_H) langhooks.h gt-tree-parloops.h $(DIAGNOSTIC_H) tree-pass.h $(SCEV_H) langhooks.h gt-tree-parloops.h \
tree-vectorizer.h
tree-stdarg.o: tree-stdarg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ tree-stdarg.o: tree-stdarg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(FUNCTION_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \ $(TREE_H) $(FUNCTION_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) tree-pass.h \
tree-stdarg.h $(TARGET_H) langhooks.h tree-stdarg.h $(TARGET_H) langhooks.h
...@@ -2390,7 +2391,7 @@ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ ...@@ -2390,7 +2391,7 @@ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h reload.h \ typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h reload.h \
$(GGC_H) langhooks.h intl.h $(TM_P_H) $(REAL_H) $(TARGET_H) \ $(GGC_H) langhooks.h intl.h $(TM_P_H) $(REAL_H) $(TARGET_H) \
tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \ tree-iterator.h gt-expr.h $(MACHMODE_H) $(TIMEVAR_H) $(TREE_FLOW_H) \
tree-pass.h $(DF_H) tree-pass.h $(DF_H) $(DIAGNOSTIC_H)
dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \
langhooks.h $(GGC_H) gt-dojump.h langhooks.h $(GGC_H) gt-dojump.h
......
...@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h" #include "target.h"
#include "timevar.h" #include "timevar.h"
#include "df.h" #include "df.h"
#include "diagnostic.h"
/* Decide whether a function's arguments should be processed /* Decide whether a function's arguments should be processed
from first to last or from last to first. from first to last or from last to first.
...@@ -9360,6 +9361,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -9360,6 +9361,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
goto binop; goto binop;
} }
case OMP_ATOMIC_LOAD:
case OMP_ATOMIC_STORE:
/* OMP expansion is not run when there were errors, so these codes
can get here. */
gcc_assert (errorcount != 0);
return NULL_RTX;
default: default:
return lang_hooks.expand_expr (exp, original_target, tmode, return lang_hooks.expand_expr (exp, original_target, tmode,
modifier, alt_rtl); modifier, alt_rtl);
......
...@@ -251,6 +251,8 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) ...@@ -251,6 +251,8 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
case OMP_ORDERED: case OMP_ORDERED:
case OMP_CRITICAL: case OMP_CRITICAL:
case OMP_RETURN: case OMP_RETURN:
case OMP_ATOMIC_LOAD:
case OMP_ATOMIC_STORE:
case OMP_CONTINUE: case OMP_CONTINUE:
break; break;
......
...@@ -5273,7 +5273,7 @@ gimplify_omp_workshare (tree *expr_p, tree *pre_p) ...@@ -5273,7 +5273,7 @@ gimplify_omp_workshare (tree *expr_p, tree *pre_p)
EXPR is this stabilized form. */ EXPR is this stabilized form. */
static bool static bool
goa_lhs_expr_p (const_tree expr, const_tree addr) goa_lhs_expr_p (tree expr, tree addr)
{ {
/* Also include casts to other type variants. The C front end is fond /* Also include casts to other type variants. The C front end is fond
of adding these for e.g. volatile variables. This is like of adding these for e.g. volatile variables. This is like
...@@ -5293,66 +5293,7 @@ goa_lhs_expr_p (const_tree expr, const_tree addr) ...@@ -5293,66 +5293,7 @@ goa_lhs_expr_p (const_tree expr, const_tree addr)
return false; return false;
} }
/* A subroutine of gimplify_omp_atomic. Attempt to implement the atomic /* Walk *EXPR_P and replace
operation as a __sync_fetch_and_op builtin. INDEX is log2 of the
size of the data type, and thus usable to find the index of the builtin
decl. Returns GS_UNHANDLED if the expression is not of the proper form. */
static enum gimplify_status
gimplify_omp_atomic_fetch_op (tree *expr_p, tree addr, tree rhs, int index)
{
enum built_in_function base;
tree decl, itype;
enum insn_code *optab;
/* Check for one of the supported fetch-op operations. */
switch (TREE_CODE (rhs))
{
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
base = BUILT_IN_FETCH_AND_ADD_N;
optab = sync_add_optab;
break;
case MINUS_EXPR:
base = BUILT_IN_FETCH_AND_SUB_N;
optab = sync_add_optab;
break;
case BIT_AND_EXPR:
base = BUILT_IN_FETCH_AND_AND_N;
optab = sync_and_optab;
break;
case BIT_IOR_EXPR:
base = BUILT_IN_FETCH_AND_OR_N;
optab = sync_ior_optab;
break;
case BIT_XOR_EXPR:
base = BUILT_IN_FETCH_AND_XOR_N;
optab = sync_xor_optab;
break;
default:
return GS_UNHANDLED;
}
/* Make sure the expression is of the proper form. */
if (goa_lhs_expr_p (TREE_OPERAND (rhs, 0), addr))
rhs = TREE_OPERAND (rhs, 1);
else if (commutative_tree_code (TREE_CODE (rhs))
&& goa_lhs_expr_p (TREE_OPERAND (rhs, 1), addr))
rhs = TREE_OPERAND (rhs, 0);
else
return GS_UNHANDLED;
decl = built_in_decls[base + index + 1];
itype = TREE_TYPE (TREE_TYPE (decl));
if (optab[TYPE_MODE (itype)] == CODE_FOR_nothing)
return GS_UNHANDLED;
*expr_p = build_call_expr (decl, 2, addr, fold_convert (itype, rhs));
return GS_OK;
}
/* A subroutine of gimplify_omp_atomic_pipeline. Walk *EXPR_P and replace
appearances of *LHS_ADDR with LHS_VAR. If an expression does not involve appearances of *LHS_ADDR with LHS_VAR. If an expression does not involve
the lhs, evaluate it into a temporary. Return 1 if the lhs appeared as the lhs, evaluate it into a temporary. Return 1 if the lhs appeared as
a subexpression, 0 if it did not, or -1 if an error was encountered. */ a subexpression, 0 if it did not, or -1 if an error was encountered. */
...@@ -5396,144 +5337,6 @@ goa_stabilize_expr (tree *expr_p, tree *pre_p, tree lhs_addr, tree lhs_var) ...@@ -5396,144 +5337,6 @@ goa_stabilize_expr (tree *expr_p, tree *pre_p, tree lhs_addr, tree lhs_var)
return saw_lhs; return saw_lhs;
} }
/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as:
oldval = *addr;
repeat:
newval = rhs; // with oldval replacing *addr in rhs
oldval = __sync_val_compare_and_swap (addr, oldval, newval);
if (oldval != newval)
goto repeat;
INDEX is log2 of the size of the data type, and thus usable to find the
index of the builtin decl. */
static enum gimplify_status
gimplify_omp_atomic_pipeline (tree *expr_p, tree *pre_p, tree addr,
tree rhs, int index)
{
tree oldval, oldival, oldival2, newval, newival, label;
tree type, itype, cmpxchg, x, iaddr;
cmpxchg = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N + index + 1];
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
itype = TREE_TYPE (TREE_TYPE (cmpxchg));
if (sync_compare_and_swap[TYPE_MODE (itype)] == CODE_FOR_nothing)
return GS_UNHANDLED;
oldval = create_tmp_var (type, NULL);
newval = create_tmp_var (type, NULL);
/* Precompute as much of RHS as possible. In the same walk, replace
occurrences of the lhs value with our temporary. */
if (goa_stabilize_expr (&rhs, pre_p, addr, oldval) < 0)
return GS_ERROR;
x = build_fold_indirect_ref (addr);
x = build_gimple_modify_stmt (oldval, x);
gimplify_and_add (x, pre_p);
/* For floating-point values, we'll need to view-convert them to integers
so that we can perform the atomic compare and swap. Simplify the
following code by always setting up the "i"ntegral variables. */
if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
{
oldival = oldval;
newival = newval;
iaddr = addr;
}
else
{
oldival = create_tmp_var (itype, NULL);
newival = create_tmp_var (itype, NULL);
x = build1 (VIEW_CONVERT_EXPR, itype, oldval);
x = build_gimple_modify_stmt (oldival, x);
gimplify_and_add (x, pre_p);
iaddr = fold_convert (build_pointer_type (itype), addr);
}
oldival2 = create_tmp_var (itype, NULL);
label = create_artificial_label ();
x = build1 (LABEL_EXPR, void_type_node, label);
gimplify_and_add (x, pre_p);
x = build_gimple_modify_stmt (newval, rhs);
gimplify_and_add (x, pre_p);
if (newval != newival)
{
x = build1 (VIEW_CONVERT_EXPR, itype, newval);
x = build_gimple_modify_stmt (newival, x);
gimplify_and_add (x, pre_p);
}
x = build_gimple_modify_stmt (oldival2, fold_convert (itype, oldival));
gimplify_and_add (x, pre_p);
x = build_call_expr (cmpxchg, 3, iaddr, fold_convert (itype, oldival),
fold_convert (itype, newival));
if (oldval == oldival)
x = fold_convert (type, x);
x = build_gimple_modify_stmt (oldival, x);
gimplify_and_add (x, pre_p);
/* For floating point, be prepared for the loop backedge. */
if (oldval != oldival)
{
x = build1 (VIEW_CONVERT_EXPR, type, oldival);
x = build_gimple_modify_stmt (oldval, x);
gimplify_and_add (x, pre_p);
}
/* Note that we always perform the comparison as an integer, even for
floating point. This allows the atomic operation to properly
succeed even with NaNs and -0.0. */
x = build3 (COND_EXPR, void_type_node,
build2 (NE_EXPR, boolean_type_node,
fold_convert (itype, oldival), oldival2),
build1 (GOTO_EXPR, void_type_node, label), NULL);
gimplify_and_add (x, pre_p);
*expr_p = NULL;
return GS_ALL_DONE;
}
/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as:
GOMP_atomic_start ();
*addr = rhs;
GOMP_atomic_end ();
The result is not globally atomic, but works so long as all parallel
references are within #pragma omp atomic directives. According to
responses received from omp@openmp.org, appears to be within spec.
Which makes sense, since that's how several other compilers handle
this situation as well. */
static enum gimplify_status
gimplify_omp_atomic_mutex (tree *expr_p, tree *pre_p, tree addr, tree rhs)
{
tree t;
t = built_in_decls[BUILT_IN_GOMP_ATOMIC_START];
t = build_call_expr (t, 0);
gimplify_and_add (t, pre_p);
t = build_fold_indirect_ref (addr);
t = build_gimple_modify_stmt (t, rhs);
gimplify_and_add (t, pre_p);
t = built_in_decls[BUILT_IN_GOMP_ATOMIC_END];
t = build_call_expr (t, 0);
gimplify_and_add (t, pre_p);
*expr_p = NULL;
return GS_ALL_DONE;
}
/* Gimplify an OMP_ATOMIC statement. */ /* Gimplify an OMP_ATOMIC statement. */
static enum gimplify_status static enum gimplify_status
...@@ -5542,46 +5345,26 @@ gimplify_omp_atomic (tree *expr_p, tree *pre_p) ...@@ -5542,46 +5345,26 @@ gimplify_omp_atomic (tree *expr_p, tree *pre_p)
tree addr = TREE_OPERAND (*expr_p, 0); tree addr = TREE_OPERAND (*expr_p, 0);
tree rhs = TREE_OPERAND (*expr_p, 1); tree rhs = TREE_OPERAND (*expr_p, 1);
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
HOST_WIDE_INT index; tree tmp_load, load, store;
/* Make sure the type is one of the supported sizes. */ tmp_load = create_tmp_var (type, NULL);
index = tree_low_cst (TYPE_SIZE_UNIT (type), 1); if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
index = exact_log2 (index); return GS_ERROR;
if (index >= 0 && index <= 4)
{
enum gimplify_status gs;
unsigned int align;
if (DECL_P (TREE_OPERAND (addr, 0)))
align = DECL_ALIGN_UNIT (TREE_OPERAND (addr, 0));
else if (TREE_CODE (TREE_OPERAND (addr, 0)) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (addr, 0), 1))
== FIELD_DECL)
align = DECL_ALIGN_UNIT (TREE_OPERAND (TREE_OPERAND (addr, 0), 1));
else
align = TYPE_ALIGN_UNIT (type);
/* __sync builtins require strict data alignment. */ if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
if (exact_log2 (align) >= index) != GS_ALL_DONE)
{ return GS_ERROR;
/* When possible, use specialized atomic update functions. */
if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
{
gs = gimplify_omp_atomic_fetch_op (expr_p, addr, rhs, index);
if (gs != GS_UNHANDLED)
return gs;
}
/* If we don't have specialized __sync builtins, try and implement load = build2 (OMP_ATOMIC_LOAD, void_type_node, tmp_load, addr);
as a compare and swap loop. */ append_to_statement_list (load, pre_p);
gs = gimplify_omp_atomic_pipeline (expr_p, pre_p, addr, rhs, index); if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
if (gs != GS_UNHANDLED) != GS_ALL_DONE)
return gs; return GS_ERROR;
} store = build1 (OMP_ATOMIC_STORE, void_type_node, rhs);
} *expr_p = store;
return GS_ALL_DONE;
/* The ultimate fallback is wrapping the operation in a mutex. */
return gimplify_omp_atomic_mutex (expr_p, pre_p, addr, rhs);
} }
/* Gimplifies the expression tree pointed to by EXPR_P. Return 0 if /* Gimplifies the expression tree pointed to by EXPR_P. Return 0 if
...@@ -6057,6 +5840,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, ...@@ -6057,6 +5840,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
case OMP_RETURN: case OMP_RETURN:
case OMP_CONTINUE: case OMP_CONTINUE:
case OMP_ATOMIC_LOAD:
case OMP_ATOMIC_STORE:
ret = GS_ALL_DONE; ret = GS_ALL_DONE;
break; break;
......
...@@ -524,6 +524,13 @@ make_edges (void) ...@@ -524,6 +524,13 @@ make_edges (void)
fallthru = false; fallthru = false;
break; break;
case OMP_ATOMIC_LOAD:
case OMP_ATOMIC_STORE:
fallthru = true;
break;
case OMP_RETURN: case OMP_RETURN:
/* In the case of an OMP_SECTION, the edge will go somewhere /* In the case of an OMP_SECTION, the edge will go somewhere
other than the next block. This will be created later. */ other than the next block. This will be created later. */
......
...@@ -240,6 +240,8 @@ is_gimple_stmt (tree t) ...@@ -240,6 +240,8 @@ is_gimple_stmt (tree t)
case OMP_CRITICAL: case OMP_CRITICAL:
case OMP_RETURN: case OMP_RETURN:
case OMP_CONTINUE: case OMP_CONTINUE:
case OMP_ATOMIC_LOAD:
case OMP_ATOMIC_STORE:
/* These are always void. */ /* These are always void. */
return true; return true;
......
...@@ -2154,6 +2154,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) ...@@ -2154,6 +2154,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case OMP_RETURN: case OMP_RETURN:
case OMP_CONTINUE: case OMP_CONTINUE:
case OMP_SECTIONS_SWITCH: case OMP_SECTIONS_SWITCH:
case OMP_ATOMIC_STORE:
break; break;
/* We don't account constants for now. Assume that the cost is amortized /* We don't account constants for now. Assume that the cost is amortized
...@@ -2384,6 +2385,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) ...@@ -2384,6 +2385,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case OMP_ORDERED: case OMP_ORDERED:
case OMP_CRITICAL: case OMP_CRITICAL:
case OMP_ATOMIC: case OMP_ATOMIC:
case OMP_ATOMIC_LOAD:
/* OpenMP directives are generally very expensive. */ /* OpenMP directives are generally very expensive. */
d->count += d->weights->omp_cost; d->count += d->weights->omp_cost;
break; break;
......
...@@ -1941,6 +1941,23 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, ...@@ -1941,6 +1941,23 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
break; break;
case OMP_ATOMIC_LOAD:
pp_string (buffer, "#pragma omp atomic_load");
newline_and_indent (buffer, spc + 2);
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_space (buffer);
pp_character (buffer, '=');
pp_space (buffer);
pp_character (buffer, '*');
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
break;
case OMP_ATOMIC_STORE:
pp_string (buffer, "#pragma omp atomic_store (");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_character (buffer, ')');
break;
case OMP_SINGLE: case OMP_SINGLE:
pp_string (buffer, "#pragma omp single"); pp_string (buffer, "#pragma omp single");
dump_omp_clauses (buffer, OMP_SINGLE_CLAUSES (node), spc, flags); dump_omp_clauses (buffer, OMP_SINGLE_CLAUSES (node), spc, flags);
......
...@@ -1624,38 +1624,20 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags) ...@@ -1624,38 +1624,20 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
add_virtual_operand (var, s_ann, flags, NULL_TREE, 0, -1, false); add_virtual_operand (var, s_ann, flags, NULL_TREE, 0, -1, false);
} }
/* Subroutine of get_indirect_ref_operands. ADDR is the address
/* A subroutine of get_expr_operands to handle INDIRECT_REF, that is dereferenced, the meaning of the rest of the arguments
ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF. is the same as in get_indirect_ref_operands. */
STMT is the statement being processed, EXPR is the INDIRECT_REF
that got us here.
FLAGS is as in get_expr_operands.
FULL_REF contains the full pointer dereference expression, if we
have it, or NULL otherwise.
OFFSET and SIZE are the location of the access inside the
dereferenced pointer, if known.
RECURSE_ON_BASE should be set to true if we want to continue
calling get_expr_operands on the base pointer, and false if
something else will do it for us. */
static void static void
get_indirect_ref_operands (tree stmt, tree expr, int flags, get_addr_dereference_operands (tree stmt, tree *addr, int flags,
tree full_ref, tree full_ref,
HOST_WIDE_INT offset, HOST_WIDE_INT size, HOST_WIDE_INT offset, HOST_WIDE_INT size,
bool recurse_on_base) bool recurse_on_base)
{ {
tree *pptr = &TREE_OPERAND (expr, 0); tree ptr = *addr;
tree ptr = *pptr;
stmt_ann_t s_ann = stmt_ann (stmt); stmt_ann_t s_ann = stmt_ann (stmt);
s_ann->references_memory = true; s_ann->references_memory = true;
if (TREE_THIS_VOLATILE (expr))
s_ann->has_volatile_ops = true;
if (SSA_VAR_P (ptr)) if (SSA_VAR_P (ptr))
{ {
...@@ -1725,9 +1707,42 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags, ...@@ -1725,9 +1707,42 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags,
/* If requested, add a USE operand for the base pointer. */ /* If requested, add a USE operand for the base pointer. */
if (recurse_on_base) if (recurse_on_base)
get_expr_operands (stmt, pptr, opf_use); get_expr_operands (stmt, addr, opf_use);
} }
/* A subroutine of get_expr_operands to handle INDIRECT_REF,
ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF.
STMT is the statement being processed, EXPR is the INDIRECT_REF
that got us here.
FLAGS is as in get_expr_operands.
FULL_REF contains the full pointer dereference expression, if we
have it, or NULL otherwise.
OFFSET and SIZE are the location of the access inside the
dereferenced pointer, if known.
RECURSE_ON_BASE should be set to true if we want to continue
calling get_expr_operands on the base pointer, and false if
something else will do it for us. */
static void
get_indirect_ref_operands (tree stmt, tree expr, int flags,
tree full_ref,
HOST_WIDE_INT offset, HOST_WIDE_INT size,
bool recurse_on_base)
{
tree *pptr = &TREE_OPERAND (expr, 0);
stmt_ann_t s_ann = stmt_ann (stmt);
if (TREE_THIS_VOLATILE (expr))
s_ann->has_volatile_ops = true;
get_addr_dereference_operands (stmt, pptr, flags, full_ref,
offset, size, recurse_on_base);
}
/* A subroutine of get_expr_operands to handle TARGET_MEM_REF. */ /* A subroutine of get_expr_operands to handle TARGET_MEM_REF. */
...@@ -2334,6 +2349,25 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) ...@@ -2334,6 +2349,25 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
return; return;
} }
case OMP_ATOMIC_LOAD:
{
tree *addr = &TREE_OPERAND (expr, 1);
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_def);
if (TREE_CODE (*addr) == ADDR_EXPR)
get_expr_operands (stmt, &TREE_OPERAND (*addr, 0), opf_def);
else
get_addr_dereference_operands (stmt, addr, opf_def,
NULL_TREE, 0, -1, true);
return;
}
case OMP_ATOMIC_STORE:
{
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_use);
return;
}
case BLOCK: case BLOCK:
case FUNCTION_DECL: case FUNCTION_DECL:
case EXC_PTR_EXPR: case EXC_PTR_EXPR:
......
...@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3. If not see
#include "recog.h" #include "recog.h"
/* Main analysis functions. */ /* Main analysis functions. */
static loop_vec_info vect_analyze_loop_form (struct loop *);
static bool vect_analyze_data_refs (loop_vec_info); static bool vect_analyze_data_refs (loop_vec_info);
static bool vect_mark_stmts_to_be_vectorized (loop_vec_info); static bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
static void vect_analyze_scalar_cycles (loop_vec_info); static void vect_analyze_scalar_cycles (loop_vec_info);
...@@ -3998,7 +3997,7 @@ vect_analyze_loop_1 (struct loop *loop) ...@@ -3998,7 +3997,7 @@ vect_analyze_loop_1 (struct loop *loop)
- the loop exit condition is simple enough, and the number of iterations - the loop exit condition is simple enough, and the number of iterations
can be analyzed (a countable loop). */ can be analyzed (a countable loop). */
static loop_vec_info loop_vec_info
vect_analyze_loop_form (struct loop *loop) vect_analyze_loop_form (struct loop *loop)
{ {
loop_vec_info loop_vinfo; loop_vec_info loop_vinfo;
......
...@@ -666,7 +666,7 @@ extern stmt_vec_info new_stmt_vec_info (tree stmt, loop_vec_info); ...@@ -666,7 +666,7 @@ extern stmt_vec_info new_stmt_vec_info (tree stmt, loop_vec_info);
/* Driver for analysis stage. */ /* Driver for analysis stage. */
extern loop_vec_info vect_analyze_loop (struct loop *); extern loop_vec_info vect_analyze_loop (struct loop *);
extern void vect_free_slp_tree (slp_tree); extern void vect_free_slp_tree (slp_tree);
extern loop_vec_info vect_analyze_loop_form (struct loop *);
/** In tree-vect-patterns.c **/ /** In tree-vect-patterns.c **/
/* Pattern recognition functions. /* Pattern recognition functions.
......
...@@ -1059,6 +1059,18 @@ DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 2) ...@@ -1059,6 +1059,18 @@ DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 2)
build_fold_indirect_ref of the address. */ build_fold_indirect_ref of the address. */
DEFTREECODE (OMP_ATOMIC, "omp_atomic", tcc_statement, 2) DEFTREECODE (OMP_ATOMIC, "omp_atomic", tcc_statement, 2)
/* Codes used for lowering of OMP_ATOMIC. Although the form of the OMP_ATOMIC
statement is very simple (just in form mem op= expr), various implicit
conversions may cause the expression become more complex, so that it does
not fit the gimple grammar very well. To overcome this problem, OMP_ATOMIC
is rewritten as a sequence of two codes in gimplification:
OMP_LOAD (tmp, mem)
val = some computations involving tmp;
OMP_STORE (val) */
DEFTREECODE (OMP_ATOMIC_LOAD, "omp_atomic_load", tcc_statement, 2)
DEFTREECODE (OMP_ATOMIC_STORE, "omp_atomic_store", tcc_statement, 1)
/* OpenMP clauses. */ /* OpenMP clauses. */
DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0) DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
......
...@@ -195,6 +195,8 @@ extern const enum tree_code_class tree_code_type[]; ...@@ -195,6 +195,8 @@ extern const enum tree_code_class tree_code_type[];
|| TREE_CODE (NODE) == OMP_ORDERED \ || TREE_CODE (NODE) == OMP_ORDERED \
|| TREE_CODE (NODE) == OMP_CRITICAL \ || TREE_CODE (NODE) == OMP_CRITICAL \
|| TREE_CODE (NODE) == OMP_RETURN \ || TREE_CODE (NODE) == OMP_RETURN \
|| TREE_CODE (NODE) == OMP_ATOMIC_LOAD \
|| TREE_CODE (NODE) == OMP_ATOMIC_STORE \
|| TREE_CODE (NODE) == OMP_CONTINUE) || TREE_CODE (NODE) == OMP_CONTINUE)
/* Number of argument-words in each kind of tree-node. */ /* Number of argument-words in each kind of tree-node. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment