diff options
author | Jakub Jelinek <jakub@redhat.com> | 2021-09-10 20:41:33 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2021-09-10 20:41:33 +0200 |
commit | 8122fbff770bcff183a9c3c72e8092c0ca32150b (patch) | |
tree | ce01fc417dc7920da04a312ab2abcd350adec6c0 /gcc/gimplify.c | |
parent | b7f84702b364d49824ca97d4a2fc01567301d784 (diff) | |
download | gcc-8122fbff770bcff183a9c3c72e8092c0ca32150b.zip gcc-8122fbff770bcff183a9c3c72e8092c0ca32150b.tar.gz gcc-8122fbff770bcff183a9c3c72e8092c0ca32150b.tar.bz2 |
openmp: Implement OpenMP 5.1 atomics, so far for C only
This patch implements OpenMP 5.1 atomics (with clarifications from upcoming 5.2).
The most important changes are that it is now possible to write (for C/C++,
for Fortran it was possible before already) min/max atomics and more importantly
compare and exchange in various forms.
Also, acq_rel is now allowed on read/write and acq_rel/acquire are allowed on
update, and there are new compare, weak and fail clauses.
2021-09-10 Jakub Jelinek <jakub@redhat.com>
gcc/
* tree-core.h (enum omp_memory_order): Add OMP_MEMORY_ORDER_MASK,
OMP_FAIL_MEMORY_ORDER_UNSPECIFIED, OMP_FAIL_MEMORY_ORDER_RELAXED,
OMP_FAIL_MEMORY_ORDER_ACQUIRE, OMP_FAIL_MEMORY_ORDER_RELEASE,
OMP_FAIL_MEMORY_ORDER_ACQ_REL, OMP_FAIL_MEMORY_ORDER_SEQ_CST and
OMP_FAIL_MEMORY_ORDER_MASK enumerators.
(OMP_FAIL_MEMORY_ORDER_SHIFT): Define.
* gimple-pretty-print.c (dump_gimple_omp_atomic_load,
dump_gimple_omp_atomic_store): Print [weak] for weak atomic
load/store.
* gimple.h (enum gf_mask): Change GF_OMP_ATOMIC_MEMORY_ORDER
to 6-bit mask, adjust GF_OMP_ATOMIC_NEED_VALUE value and add
GF_OMP_ATOMIC_WEAK.
(gimple_omp_atomic_weak_p, gimple_omp_atomic_set_weak): New inline
functions.
* tree.h (OMP_ATOMIC_WEAK): Define.
* tree-pretty-print.c (dump_omp_atomic_memory_order): Adjust for
fail memory order being encoded in the same enum and also print
fail clause if present.
(dump_generic_node): Print weak clause if OMP_ATOMIC_WEAK.
* gimplify.c (goa_stabilize_expr): Add target_expr and rhs arguments,
handle pre_p == NULL case as a test mode that only returns value
but doesn't change gimplify nor change anything otherwise, adjust
recursive calls, add MODIFY_EXPR, ADDR_EXPR, COND_EXPR, TARGET_EXPR
and CALL_EXPR handling, adjust COMPOUND_EXPR handling for
__builtin_clear_padding calls, for !rhs gimplify as lvalue rather
than rvalue.
(gimplify_omp_atomic): Adjust goa_stabilize_expr caller. Handle
COND_EXPR rhs. Set weak flag on gimple load/store for
OMP_ATOMIC_WEAK.
* omp-expand.c (omp_memory_order_to_fail_memmodel): New function.
(omp_memory_order_to_memmodel): Adjust for fail clause encoded
in the same enum.
(expand_omp_atomic_cas): New function.
(expand_omp_atomic_pipeline): Use omp_memory_order_to_fail_memmodel
function.
(expand_omp_atomic): Attempt to optimize atomic compare and exchange
using expand_omp_atomic_cas.
gcc/c-family/
* c-common.h (c_finish_omp_atomic): Add r and weak arguments.
* c-omp.c: Include gimple-fold.h.
(c_finish_omp_atomic): Add r and weak arguments. Add support for
OpenMP 5.1 atomics.
gcc/c/
* c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs and
cond.value is >, < or == with omp_atomic_lhs as one of the operands,
don't call build_conditional_expr, instead build a COND_EXPR directly.
(c_parser_binary_expression): Avoid calling parser_build_binary_op
if omp_atomic_lhs even in more cases for >, < or ==.
(c_parser_omp_atomic): Update function comment for OpenMP 5.1 atomics,
parse OpenMP 5.1 atomics and fail, compare and weak clauses, allow
acq_rel on atomic read/write and acq_rel/acquire clauses on update.
* c-typeck.c (build_binary_op): For flag_openmp only handle
MIN_EXPR/MAX_EXPR.
gcc/cp/
* parser.c (cp_parser_omp_atomic): Allow acq_rel on atomic read/write
and acq_rel/acquire clauses on update.
* semantics.c (finish_omp_atomic): Adjust c_finish_omp_atomic caller.
gcc/testsuite/
* c-c++-common/gomp/atomic-17.c (foo): Add tests for atomic read,
write or update with acq_rel clause and atomic update with acquire clause.
* c-c++-common/gomp/atomic-18.c (foo): Adjust expected diagnostics
wording, remove tests moved to atomic-17.c.
* c-c++-common/gomp/atomic-21.c: Expect only 2 omp atomic release and
2 omp atomic acq_rel directives instead of 4 omp atomic release.
* c-c++-common/gomp/atomic-25.c: New test.
* c-c++-common/gomp/atomic-26.c: New test.
* c-c++-common/gomp/atomic-27.c: New test.
* c-c++-common/gomp/atomic-28.c: New test.
* c-c++-common/gomp/atomic-29.c: New test.
* c-c++-common/gomp/atomic-30.c: New test.
* c-c++-common/goacc-gomp/atomic.c: Expect 1 omp atomic release and
1 omp atomic_acq_rel instead of 2 omp atomic release directives.
* gcc.dg/gomp/atomic-5.c: Adjust expected error diagnostic wording.
* g++.dg/gomp/atomic-18.C:Expect 4 omp atomic release and
1 omp atomic_acq_rel instead of 5 omp atomic release directives.
libgomp/
* testsuite/libgomp.c-c++-common/atomic-19.c: New test.
* testsuite/libgomp.c-c++-common/atomic-20.c: New test.
* testsuite/libgomp.c-c++-common/atomic-21.c: New test.
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 161 |
1 files changed, 138 insertions, 23 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 8820f87..66dfd25 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -13859,14 +13859,15 @@ goa_lhs_expr_p (tree expr, tree addr) static int goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, - tree lhs_var) + tree lhs_var, tree &target_expr, bool rhs) { tree expr = *expr_p; int saw_lhs; if (goa_lhs_expr_p (expr, lhs_addr)) { - *expr_p = lhs_var; + if (pre_p) + *expr_p = lhs_var; return 1; } if (is_gimple_val (expr)) @@ -13878,11 +13879,11 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, case tcc_binary: case tcc_comparison: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr, - lhs_var); + lhs_var, target_expr, true); /* FALLTHRU */ case tcc_unary: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr, - lhs_var); + lhs_var, target_expr, true); break; case tcc_expression: switch (TREE_CODE (expr)) @@ -13894,36 +13895,131 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, case TRUTH_XOR_EXPR: case BIT_INSERT_EXPR: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, - lhs_addr, lhs_var); + lhs_addr, lhs_var, target_expr, true); /* FALLTHRU */ case TRUTH_NOT_EXPR: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var); + lhs_addr, lhs_var, target_expr, true); + break; + case MODIFY_EXPR: + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, + lhs_addr, lhs_var, target_expr, true); + /* FALLTHRU */ + case ADDR_EXPR: + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, + lhs_addr, lhs_var, target_expr, false); break; case COMPOUND_EXPR: + /* Special-case __builtin_clear_padding call before + __builtin_memcmp. */ + if (TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR) + { + tree fndecl = get_callee_fndecl (TREE_OPERAND (expr, 0)); + if (fndecl + && fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) + && VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))) + { + saw_lhs = goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, + lhs_addr, lhs_var, + target_expr, true); + if (!saw_lhs) + { + expr = TREE_OPERAND (expr, 1); + if (!pre_p) + return goa_stabilize_expr (&expr, pre_p, lhs_addr, + lhs_var, target_expr, true); + *expr_p = expr; + return goa_stabilize_expr (expr_p, pre_p, lhs_addr, + lhs_var, target_expr, true); + } + else + { + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), + pre_p, lhs_addr, lhs_var, + target_expr, rhs); + break; + } + } + } /* Break out any preevaluations from cp_build_modify_expr. */ for (; TREE_CODE (expr) == COMPOUND_EXPR; expr = TREE_OPERAND (expr, 1)) - gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p); + if (pre_p) + gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p); + if (!pre_p) + return goa_stabilize_expr (&expr, pre_p, lhs_addr, lhs_var, + target_expr, rhs); *expr_p = expr; - return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var); + return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var, + target_expr, rhs); + case COND_EXPR: + if (!goa_stabilize_expr (&TREE_OPERAND (expr, 0), NULL, lhs_addr, + lhs_var, target_expr, true)) + break; + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, + lhs_addr, lhs_var, target_expr, true); + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, + lhs_addr, lhs_var, target_expr, true); + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 2), pre_p, + lhs_addr, lhs_var, target_expr, true); + break; + case TARGET_EXPR: + if (TARGET_EXPR_INITIAL (expr)) + { + if (expr == target_expr) + saw_lhs = 1; + else + { + saw_lhs = goa_stabilize_expr (&TARGET_EXPR_INITIAL (expr), + pre_p, lhs_addr, lhs_var, + target_expr, true); + if (saw_lhs && target_expr == NULL_TREE && pre_p) + target_expr = expr; + } + } + break; default: break; } break; case tcc_reference: - if (TREE_CODE (expr) == BIT_FIELD_REF) + if (TREE_CODE (expr) == BIT_FIELD_REF + || TREE_CODE (expr) == VIEW_CONVERT_EXPR) saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, - lhs_addr, lhs_var); + lhs_addr, lhs_var, target_expr, true); + break; + case tcc_vl_exp: + if (TREE_CODE (expr) == CALL_EXPR) + { + if (tree fndecl = get_callee_fndecl (expr)) + if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) + || fndecl_built_in_p (fndecl, BUILT_IN_MEMCMP)) + { + int nargs = call_expr_nargs (expr); + for (int i = 0; i < nargs; i++) + saw_lhs |= goa_stabilize_expr (&CALL_EXPR_ARG (expr, i), + pre_p, lhs_addr, lhs_var, + target_expr, true); + } + if (saw_lhs == 0 && VOID_TYPE_P (TREE_TYPE (expr))) + { + if (pre_p) + gimplify_stmt (&expr, pre_p); + return 0; + } + } break; default: break; } - if (saw_lhs == 0) + if (saw_lhs == 0 && pre_p) { enum gimplify_status gs; - gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue); + if (rhs) + gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue); + else + gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_lvalue, fb_lvalue); if (gs != GS_ALL_DONE) saw_lhs = -1; } @@ -13943,9 +14039,12 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) tree tmp_load; gomp_atomic_load *loadstmt; gomp_atomic_store *storestmt; + tree target_expr = NULL_TREE; tmp_load = create_tmp_reg (type); - if (rhs && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0) + if (rhs + && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load, target_expr, + true) < 0) return GS_ERROR; if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue) @@ -13959,11 +14058,14 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) { /* BIT_INSERT_EXPR is not valid for non-integral bitfield representatives. Use BIT_FIELD_REF on the lhs instead. */ - if (TREE_CODE (rhs) == BIT_INSERT_EXPR + tree rhsarg = rhs; + if (TREE_CODE (rhs) == COND_EXPR) + rhsarg = TREE_OPERAND (rhs, 1); + if (TREE_CODE (rhsarg) == BIT_INSERT_EXPR && !INTEGRAL_TYPE_P (TREE_TYPE (tmp_load))) { - tree bitpos = TREE_OPERAND (rhs, 2); - tree op1 = TREE_OPERAND (rhs, 1); + tree bitpos = TREE_OPERAND (rhsarg, 2); + tree op1 = TREE_OPERAND (rhsarg, 1); tree bitsize; tree tmp_store = tmp_load; if (TREE_CODE (*expr_p) == OMP_ATOMIC_CAPTURE_OLD) @@ -13972,17 +14074,25 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) bitsize = bitsize_int (TYPE_PRECISION (TREE_TYPE (op1))); else bitsize = TYPE_SIZE (TREE_TYPE (op1)); - gcc_assert (TREE_OPERAND (rhs, 0) == tmp_load); - tree t = build2_loc (EXPR_LOCATION (rhs), + gcc_assert (TREE_OPERAND (rhsarg, 0) == tmp_load); + tree t = build2_loc (EXPR_LOCATION (rhsarg), MODIFY_EXPR, void_type_node, - build3_loc (EXPR_LOCATION (rhs), BIT_FIELD_REF, - TREE_TYPE (op1), tmp_store, bitsize, - bitpos), op1); + build3_loc (EXPR_LOCATION (rhsarg), + BIT_FIELD_REF, TREE_TYPE (op1), + tmp_store, bitsize, bitpos), op1); + if (TREE_CODE (rhs) == COND_EXPR) + t = build3_loc (EXPR_LOCATION (rhs), COND_EXPR, void_type_node, + TREE_OPERAND (rhs, 0), t, void_node); gimplify_and_add (t, pre_p); rhs = tmp_store; } - if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue) - != GS_ALL_DONE) + bool save_allow_rhs_cond_expr = gimplify_ctxp->allow_rhs_cond_expr; + if (TREE_CODE (rhs) == COND_EXPR) + gimplify_ctxp->allow_rhs_cond_expr = true; + enum gimplify_status gs = gimplify_expr (&rhs, pre_p, NULL, + is_gimple_val, fb_rvalue); + gimplify_ctxp->allow_rhs_cond_expr = save_allow_rhs_cond_expr; + if (gs != GS_ALL_DONE) return GS_ERROR; } @@ -13990,6 +14100,11 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p) rhs = tmp_load; storestmt = gimple_build_omp_atomic_store (rhs, OMP_ATOMIC_MEMORY_ORDER (*expr_p)); + if (TREE_CODE (*expr_p) != OMP_ATOMIC_READ && OMP_ATOMIC_WEAK (*expr_p)) + { + gimple_omp_atomic_set_weak (loadstmt); + gimple_omp_atomic_set_weak (storestmt); + } gimplify_seq_add_stmt (pre_p, storestmt); switch (TREE_CODE (*expr_p)) { |