* openmp: Implement OpenMP 5.1 atomics, so far for C only
@ 2021-09-10 18:46 Jakub Jelinek
2021-09-13 11:57 ` Christophe Lyon
0 siblings, 1 reply; 4+ messages in thread
From: Jakub Jelinek @ 2021-09-10 18:46 UTC (permalink / raw)
To: gcc-patches; +Cc: Tobias Burnus
Hi!
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.
Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.
C++ support will follow next week hopefully. Various new tests in
c-c++-common are now with { target c }, that is temporary until the C++
support is there.
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.
--- gcc/tree-core.h.jj 2021-09-09 10:40:20.116260919 +0200
+++ gcc/tree-core.h 2021-09-09 10:41:42.631084540 +0200
@@ -583,8 +583,17 @@ enum omp_memory_order {
OMP_MEMORY_ORDER_ACQUIRE,
OMP_MEMORY_ORDER_RELEASE,
OMP_MEMORY_ORDER_ACQ_REL,
- OMP_MEMORY_ORDER_SEQ_CST
+ OMP_MEMORY_ORDER_SEQ_CST,
+ OMP_MEMORY_ORDER_MASK = 7,
+ OMP_FAIL_MEMORY_ORDER_UNSPECIFIED = OMP_MEMORY_ORDER_UNSPECIFIED * 8,
+ OMP_FAIL_MEMORY_ORDER_RELAXED = OMP_MEMORY_ORDER_RELAXED * 8,
+ OMP_FAIL_MEMORY_ORDER_ACQUIRE = OMP_MEMORY_ORDER_ACQUIRE * 8,
+ OMP_FAIL_MEMORY_ORDER_RELEASE = OMP_MEMORY_ORDER_RELEASE * 8,
+ OMP_FAIL_MEMORY_ORDER_ACQ_REL = OMP_MEMORY_ORDER_ACQ_REL * 8,
+ OMP_FAIL_MEMORY_ORDER_SEQ_CST = OMP_MEMORY_ORDER_SEQ_CST * 8,
+ OMP_FAIL_MEMORY_ORDER_MASK = OMP_MEMORY_ORDER_MASK * 8
};
+#define OMP_FAIL_MEMORY_ORDER_SHIFT 3
/* There is a TYPE_QUAL value for each type qualifier. They can be
combined by bitwise-or to form the complete set of qualifiers for a
--- gcc/gimple-pretty-print.c.jj 2021-09-09 10:40:20.032262117 +0200
+++ gcc/gimple-pretty-print.c 2021-09-09 10:41:42.625084625 +0200
@@ -2563,6 +2563,8 @@ dump_gimple_omp_atomic_load (pretty_prin
gimple_omp_atomic_memory_order (gs));
if (gimple_omp_atomic_need_value_p (gs))
pp_string (buffer, " [needed]");
+ if (gimple_omp_atomic_weak_p (gs))
+ pp_string (buffer, " [weak]");
newline_and_indent (buffer, spc + 2);
dump_generic_node (buffer, gimple_omp_atomic_load_lhs (gs),
spc, flags, false);
@@ -2597,6 +2599,8 @@ dump_gimple_omp_atomic_store (pretty_pri
pp_space (buffer);
if (gimple_omp_atomic_need_value_p (gs))
pp_string (buffer, "[needed] ");
+ if (gimple_omp_atomic_weak_p (gs))
+ pp_string (buffer, "[weak] ");
pp_left_paren (buffer);
dump_generic_node (buffer, gimple_omp_atomic_store_val (gs),
spc, flags, false);
--- gcc/gimple.h.jj 2021-09-09 10:40:20.041261988 +0200
+++ gcc/gimple.h 2021-09-09 10:41:42.625084625 +0200
@@ -194,8 +194,9 @@ enum gf_mask {
GF_OMP_RETURN_NOWAIT = 1 << 0,
GF_OMP_SECTION_LAST = 1 << 0,
- GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 3) - 1,
- GF_OMP_ATOMIC_NEED_VALUE = 1 << 3,
+ GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 6) - 1,
+ GF_OMP_ATOMIC_NEED_VALUE = 1 << 6,
+ GF_OMP_ATOMIC_WEAK = 1 << 7,
GF_PREDICT_TAKEN = 1 << 15
};
@@ -2446,6 +2447,29 @@ gimple_omp_atomic_set_need_value (gimple
}
+/* Return true if OMP atomic load/store statement G has the
+ GF_OMP_ATOMIC_WEAK flag set. */
+
+static inline bool
+gimple_omp_atomic_weak_p (const gimple *g)
+{
+ if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+ GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+ return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_WEAK) != 0;
+}
+
+
+/* Set the GF_OMP_ATOMIC_WEAK flag on G. */
+
+static inline void
+gimple_omp_atomic_set_weak (gimple *g)
+{
+ if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+ GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+ g->subcode |= GF_OMP_ATOMIC_WEAK;
+}
+
+
/* Return the memory order of the OMP atomic load/store statement G. */
static inline enum omp_memory_order
--- gcc/tree.h.jj 2021-09-09 10:40:20.132260691 +0200
+++ gcc/tree.h 2021-09-09 10:41:42.626084611 +0200
@@ -1529,6 +1529,11 @@ class auto_suppress_location_wrappers
(TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
OMP_ATOMIC_CAPTURE_NEW)->base.u.omp_atomic_memory_order)
+/* Weak clause on OMP_ATOMIC*. */
+#define OMP_ATOMIC_WEAK(NODE) \
+ (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
+ OMP_ATOMIC_CAPTURE_NEW)->base.public_flag)
+
/* True on a PRIVATE clause if its decl is kept around for debugging
information only and its DECL_VALUE_EXPR is supposed to point
to what it has been remapped to. */
--- gcc/tree-pretty-print.c.jj 2021-09-09 10:40:20.131260705 +0200
+++ gcc/tree-pretty-print.c 2021-09-09 10:41:42.626084611 +0200
@@ -1492,7 +1492,7 @@ dump_block_node (pretty_printer *pp, tre
void
dump_omp_atomic_memory_order (pretty_printer *pp, enum omp_memory_order mo)
{
- switch (mo)
+ switch (mo & OMP_MEMORY_ORDER_MASK)
{
case OMP_MEMORY_ORDER_RELAXED:
pp_string (pp, " relaxed");
@@ -1514,6 +1514,22 @@ dump_omp_atomic_memory_order (pretty_pri
default:
gcc_unreachable ();
}
+ switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
+ {
+ case OMP_FAIL_MEMORY_ORDER_RELAXED:
+ pp_string (pp, " fail(relaxed)");
+ break;
+ case OMP_FAIL_MEMORY_ORDER_SEQ_CST:
+ pp_string (pp, " fail(seq_cst)");
+ break;
+ case OMP_FAIL_MEMORY_ORDER_ACQUIRE:
+ pp_string (pp, " fail(acquire)");
+ break;
+ case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
/* Helper to dump a MEM_REF node. */
@@ -3629,6 +3645,8 @@ dump_generic_node (pretty_printer *pp, t
case OMP_ATOMIC:
pp_string (pp, "#pragma omp atomic");
+ if (OMP_ATOMIC_WEAK (node))
+ pp_string (pp, " weak");
dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node));
newline_and_indent (pp, spc + 2);
dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false);
@@ -3649,6 +3667,8 @@ dump_generic_node (pretty_printer *pp, t
case OMP_ATOMIC_CAPTURE_OLD:
case OMP_ATOMIC_CAPTURE_NEW:
pp_string (pp, "#pragma omp atomic capture");
+ if (OMP_ATOMIC_WEAK (node))
+ pp_string (pp, " weak");
dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node));
newline_and_indent (pp, spc + 2);
dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false);
--- gcc/gimplify.c.jj 2021-09-09 10:40:20.057261760 +0200
+++ gcc/gimplify.c 2021-09-10 18:29:35.243673591 +0200
@@ -13725,14 +13725,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))
@@ -13744,11 +13745,11 @@ goa_stabilize_expr (tree *expr_p, gimple
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))
@@ -13760,36 +13761,131 @@ goa_stabilize_expr (tree *expr_p, gimple
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;
}
@@ -13809,9 +13905,12 @@ gimplify_omp_atomic (tree *expr_p, gimpl
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)
@@ -13825,11 +13924,14 @@ gimplify_omp_atomic (tree *expr_p, gimpl
{
/* 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)
@@ -13838,17 +13940,25 @@ gimplify_omp_atomic (tree *expr_p, gimpl
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;
}
@@ -13856,6 +13966,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl
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))
{
--- gcc/omp-expand.c.jj 2021-09-09 10:40:20.072261546 +0200
+++ gcc/omp-expand.c 2021-09-10 15:05:47.315510567 +0200
@@ -8487,22 +8487,58 @@ expand_omp_synch (struct omp_region *reg
}
}
+/* Translate enum omp_memory_order to enum memmodel for the embedded
+ fail clause in there. */
+
+static enum memmodel
+omp_memory_order_to_fail_memmodel (enum omp_memory_order mo)
+{
+ switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
+ {
+ case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
+ switch (mo & OMP_MEMORY_ORDER_MASK)
+ {
+ case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
+ case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
+ case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELAXED;
+ case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQUIRE;
+ case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
+ default: break;
+ }
+ gcc_unreachable ();
+ case OMP_FAIL_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
+ case OMP_FAIL_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
+ case OMP_FAIL_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
+ default: gcc_unreachable ();
+ }
+}
+
/* Translate enum omp_memory_order to enum memmodel. The two enums
are using different numbers so that OMP_MEMORY_ORDER_UNSPECIFIED
- is 0. */
+ is 0 and omp_memory_order has the fail mode encoded in it too. */
static enum memmodel
omp_memory_order_to_memmodel (enum omp_memory_order mo)
{
- switch (mo)
+ enum memmodel ret, fail_ret;
+ switch (mo & OMP_MEMORY_ORDER_MASK)
{
- case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
- case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
- case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELEASE;
- case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQ_REL;
- case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
+ case OMP_MEMORY_ORDER_RELAXED: ret = MEMMODEL_RELAXED; break;
+ case OMP_MEMORY_ORDER_ACQUIRE: ret = MEMMODEL_ACQUIRE; break;
+ case OMP_MEMORY_ORDER_RELEASE: ret = MEMMODEL_RELEASE; break;
+ case OMP_MEMORY_ORDER_ACQ_REL: ret = MEMMODEL_ACQ_REL; break;
+ case OMP_MEMORY_ORDER_SEQ_CST: ret = MEMMODEL_SEQ_CST; break;
default: gcc_unreachable ();
}
+ /* If we drop the -Winvalid-memory-model warning for C++17 P0418R2,
+ we can just return ret here unconditionally. Otherwise, work around
+ it here and make sure fail memmodel is not stronger. */
+ if ((mo & OMP_FAIL_MEMORY_ORDER_MASK) == OMP_FAIL_MEMORY_ORDER_UNSPECIFIED)
+ return ret;
+ fail_ret = omp_memory_order_to_fail_memmodel (mo);
+ if (fail_ret > ret)
+ return fail_ret;
+ return ret;
}
/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
@@ -8782,6 +8818,261 @@ expand_omp_atomic_fetch_op (basic_block
return true;
}
+/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
+ compare and exchange as an ATOMIC_COMPARE_EXCHANGE internal function.
+ Returns false if the expression is not of the proper form. */
+
+static bool
+expand_omp_atomic_cas (basic_block load_bb, tree addr,
+ tree loaded_val, tree stored_val, int index)
+{
+ /* We expect to find the following sequences:
+
+ load_bb:
+ GIMPLE_OMP_ATOMIC_LOAD (tmp, mem)
+
+ store_bb:
+ val = tmp == e ? d : tmp;
+ GIMPLE_OMP_ATOMIC_STORE (val)
+
+ or in store_bb instead:
+ tmp2 = tmp == e;
+ val = tmp2 ? d : tmp;
+ GIMPLE_OMP_ATOMIC_STORE (val)
+
+ or:
+ tmp3 = VIEW_CONVERT_EXPR<integral_type>(tmp);
+ val = e == tmp3 ? d : tmp;
+ GIMPLE_OMP_ATOMIC_STORE (val)
+
+ etc. */
+
+
+ basic_block store_bb = single_succ (load_bb);
+ gimple_stmt_iterator gsi = gsi_last_nondebug_bb (store_bb);
+ gimple *store_stmt = gsi_stmt (gsi);
+ if (!store_stmt || gimple_code (store_stmt) != GIMPLE_OMP_ATOMIC_STORE)
+ return false;
+ gsi_prev_nondebug (&gsi);
+ if (gsi_end_p (gsi))
+ return false;
+ gimple *condexpr_stmt = gsi_stmt (gsi);
+ if (!is_gimple_assign (condexpr_stmt)
+ || gimple_assign_rhs_code (condexpr_stmt) != COND_EXPR)
+ return false;
+ if (!operand_equal_p (gimple_assign_lhs (condexpr_stmt), stored_val, 0))
+ return false;
+ gimple *cond_stmt = NULL;
+ gimple *vce_stmt = NULL;
+ gsi_prev_nondebug (&gsi);
+ if (!gsi_end_p (gsi))
+ {
+ cond_stmt = gsi_stmt (gsi);
+ if (!is_gimple_assign (cond_stmt))
+ return false;
+ if (gimple_assign_rhs_code (cond_stmt) == EQ_EXPR)
+ {
+ gsi_prev_nondebug (&gsi);
+ if (!gsi_end_p (gsi))
+ {
+ vce_stmt = gsi_stmt (gsi);
+ if (!is_gimple_assign (vce_stmt)
+ || gimple_assign_rhs_code (vce_stmt) != VIEW_CONVERT_EXPR)
+ return false;
+ }
+ }
+ else if (gimple_assign_rhs_code (cond_stmt) == VIEW_CONVERT_EXPR)
+ std::swap (vce_stmt, cond_stmt);
+ else
+ return false;
+ if (vce_stmt)
+ {
+ tree vce_rhs = gimple_assign_rhs1 (vce_stmt);
+ if (TREE_CODE (vce_rhs) != VIEW_CONVERT_EXPR
+ || !operand_equal_p (TREE_OPERAND (vce_rhs, 0), loaded_val))
+ return false;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (vce_rhs))
+ || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (loaded_val))
+ || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vce_rhs)),
+ TYPE_SIZE (TREE_TYPE (loaded_val))))
+ return false;
+ gsi_prev_nondebug (&gsi);
+ if (!gsi_end_p (gsi))
+ return false;
+ }
+ }
+ tree cond = gimple_assign_rhs1 (condexpr_stmt);
+ tree cond_op1, cond_op2;
+ if (cond_stmt)
+ {
+ if (!operand_equal_p (cond, gimple_assign_lhs (cond_stmt)))
+ return false;
+ cond_op1 = gimple_assign_rhs1 (cond_stmt);
+ cond_op2 = gimple_assign_rhs2 (cond_stmt);
+ }
+ else if (TREE_CODE (cond) != EQ_EXPR && TREE_CODE (cond) != NE_EXPR)
+ return false;
+ else
+ {
+ cond_op1 = TREE_OPERAND (cond, 0);
+ cond_op2 = TREE_OPERAND (cond, 1);
+ }
+ tree d;
+ if (TREE_CODE (cond) == NE_EXPR)
+ {
+ if (!operand_equal_p (gimple_assign_rhs2 (condexpr_stmt), loaded_val))
+ return false;
+ d = gimple_assign_rhs3 (condexpr_stmt);
+ }
+ else if (!operand_equal_p (gimple_assign_rhs3 (condexpr_stmt), loaded_val))
+ return false;
+ else
+ d = gimple_assign_rhs2 (condexpr_stmt);
+ tree e = vce_stmt ? gimple_assign_lhs (vce_stmt) : loaded_val;
+ if (operand_equal_p (e, cond_op1))
+ e = cond_op2;
+ else if (operand_equal_p (e, cond_op2))
+ e = cond_op1;
+ else
+ return false;
+
+ location_t loc = gimple_location (store_stmt);
+ gimple *load_stmt = last_stmt (load_bb);
+ bool need_new = gimple_omp_atomic_need_value_p (store_stmt);
+ bool need_old = gimple_omp_atomic_need_value_p (load_stmt);
+ bool weak = gimple_omp_atomic_weak_p (load_stmt);
+ enum omp_memory_order omo = gimple_omp_atomic_memory_order (load_stmt);
+ tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo));
+ tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel (omo));
+ gcc_checking_assert (!need_old || !need_new);
+
+ enum built_in_function fncode
+ = (enum built_in_function) ((int) BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+ + index + 1);
+ tree cmpxchg = builtin_decl_explicit (fncode);
+ if (cmpxchg == NULL_TREE)
+ return false;
+ tree itype = TREE_TYPE (TREE_TYPE (cmpxchg));
+
+ if (!can_compare_and_swap_p (TYPE_MODE (itype), true)
+ || !can_atomic_load_p (TYPE_MODE (itype)))
+ return false;
+
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (loaded_val));
+ if (SCALAR_FLOAT_TYPE_P (type) && !vce_stmt)
+ return false;
+
+ gsi = gsi_for_stmt (store_stmt);
+ if (!useless_type_conversion_p (itype, TREE_TYPE (e)))
+ {
+ tree ne = create_tmp_reg (itype);
+ gimple *g = gimple_build_assign (ne, NOP_EXPR, e);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ e = ne;
+ }
+ if (!useless_type_conversion_p (itype, TREE_TYPE (d)))
+ {
+ tree nd = create_tmp_reg (itype);
+ enum tree_code code;
+ if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (d)))
+ {
+ code = VIEW_CONVERT_EXPR;
+ d = build1 (VIEW_CONVERT_EXPR, itype, d);
+ }
+ else
+ code = NOP_EXPR;
+ gimple *g = gimple_build_assign (nd, code, d);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ d = nd;
+ }
+
+ tree ctype = build_complex_type (itype);
+ int flag = int_size_in_bytes (itype) + (weak ? 256 : 0);
+ gimple *g
+ = gimple_build_call_internal (IFN_ATOMIC_COMPARE_EXCHANGE, 6, addr, e, d,
+ build_int_cst (integer_type_node, flag),
+ mo, fmo);
+ tree cres = create_tmp_reg (ctype);
+ gimple_call_set_lhs (g, cres);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+
+ if (cond_stmt || need_old || need_new)
+ {
+ tree im = create_tmp_reg (itype);
+ g = gimple_build_assign (im, IMAGPART_EXPR,
+ build1 (IMAGPART_EXPR, itype, cres));
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+
+ tree re = NULL_TREE;
+ if (need_old || need_new)
+ {
+ re = create_tmp_reg (itype);
+ g = gimple_build_assign (re, REALPART_EXPR,
+ build1 (REALPART_EXPR, itype, cres));
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ }
+
+ if (cond_stmt)
+ {
+ g = gimple_build_assign (gimple_assign_lhs (cond_stmt),
+ NOP_EXPR, im);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ }
+ else if (need_new)
+ {
+ g = gimple_build_assign (create_tmp_reg (itype), COND_EXPR,
+ build2 (NE_EXPR, boolean_type_node,
+ im, build_zero_cst (itype)),
+ d, re);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ re = gimple_assign_lhs (g);
+ }
+
+ if (need_old || need_new)
+ {
+ tree v = need_old ? loaded_val : stored_val;
+ enum tree_code code;
+ if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (v)))
+ {
+ code = VIEW_CONVERT_EXPR;
+ re = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (v), re);
+ }
+ else if (!useless_type_conversion_p (TREE_TYPE (v), itype))
+ code = NOP_EXPR;
+ else
+ code = TREE_CODE (re);
+ g = gimple_build_assign (v, code, re);
+ gimple_set_location (g, loc);
+ gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+ }
+ }
+
+ gsi_remove (&gsi, true);
+ gsi = gsi_for_stmt (load_stmt);
+ gsi_remove (&gsi, true);
+ gsi = gsi_for_stmt (condexpr_stmt);
+ gsi_remove (&gsi, true);
+ if (cond_stmt)
+ {
+ gsi = gsi_for_stmt (cond_stmt);
+ gsi_remove (&gsi, true);
+ }
+ if (vce_stmt)
+ {
+ gsi = gsi_for_stmt (vce_stmt);
+ gsi_remove (&gsi, true);
+ }
+
+ return true;
+}
+
/* A subroutine of expand_omp_atomic. Implement the atomic operation as:
oldval = *addr;
@@ -8825,13 +9116,8 @@ expand_omp_atomic_pipeline (basic_block
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
location_t loc = gimple_location (gsi_stmt (si));
enum omp_memory_order omo = gimple_omp_atomic_memory_order (gsi_stmt (si));
- enum memmodel imo = omp_memory_order_to_memmodel (omo);
- tree mo = build_int_cst (NULL, imo);
- if (imo == MEMMODEL_RELEASE)
- imo = MEMMODEL_RELAXED;
- else if (imo == MEMMODEL_ACQ_REL)
- imo = MEMMODEL_ACQUIRE;
- tree fmo = build_int_cst (NULL, imo);
+ tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo));
+ tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel (omo));
/* 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
@@ -9114,6 +9400,13 @@ expand_omp_atomic (struct omp_region *re
loaded_val, stored_val, index))
return;
+ /* When possible, use ATOMIC_COMPARE_EXCHANGE ifn without a loop. */
+ if (store_bb == single_succ (load_bb)
+ && !gimple_in_ssa_p (cfun)
+ && expand_omp_atomic_cas (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. */
if (expand_omp_atomic_pipeline (load_bb, store_bb, addr,
--- gcc/c-family/c-common.h.jj 2021-09-09 10:40:19.928263599 +0200
+++ gcc/c-family/c-common.h 2021-09-09 10:42:11.865667757 +0200
@@ -1223,8 +1223,8 @@ extern tree c_finish_omp_critical (locat
extern tree c_finish_omp_ordered (location_t, tree, tree);
extern void c_finish_omp_barrier (location_t);
extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
- tree, tree, tree, tree, tree, bool,
- enum omp_memory_order, bool = false);
+ tree, tree, tree, tree, tree, tree, bool,
+ enum omp_memory_order, bool, bool = false);
extern bool c_omp_depend_t_p (tree);
extern void c_finish_omp_depobj (location_t, tree, enum omp_clause_depend_kind,
tree);
--- gcc/c-family/c-omp.c.jj 2021-09-09 10:40:19.937263471 +0200
+++ gcc/c-family/c-omp.c 2021-09-10 17:59:26.574281430 +0200
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.
#include "gimplify.h"
#include "langhooks.h"
#include "bitmap.h"
+#include "gimple-fold.h"
/* Complete a #pragma oacc wait construct. LOC is the location of
@@ -215,15 +216,17 @@ c_finish_omp_taskyield (location_t loc)
tree
c_finish_omp_atomic (location_t loc, enum tree_code code,
enum tree_code opcode, tree lhs, tree rhs,
- tree v, tree lhs1, tree rhs1, bool swapped,
- enum omp_memory_order memory_order, bool test)
+ tree v, tree lhs1, tree rhs1, tree r, bool swapped,
+ enum omp_memory_order memory_order, bool weak,
+ bool test)
{
- tree x, type, addr, pre = NULL_TREE;
+ tree x, type, addr, pre = NULL_TREE, rtmp = NULL_TREE, vtmp = NULL_TREE;
HOST_WIDE_INT bitpos = 0, bitsize = 0;
+ enum tree_code orig_opcode = opcode;
if (lhs == error_mark_node || rhs == error_mark_node
|| v == error_mark_node || lhs1 == error_mark_node
- || rhs1 == error_mark_node)
+ || rhs1 == error_mark_node || r == error_mark_node)
return error_mark_node;
/* ??? According to one reading of the OpenMP spec, complex type are
@@ -243,6 +246,12 @@ c_finish_omp_atomic (location_t loc, enu
error_at (loc, "%<_Atomic%> expression in %<#pragma omp atomic%>");
return error_mark_node;
}
+ if (r && r != void_list_node && !INTEGRAL_TYPE_P (TREE_TYPE (r)))
+ {
+ error_at (loc, "%<#pragma omp atomic compare capture%> with non-integral "
+ "comparison result");
+ return error_mark_node;
+ }
if (opcode == RDIV_EXPR)
opcode = TRUNC_DIV_EXPR;
@@ -299,6 +308,7 @@ c_finish_omp_atomic (location_t loc, enu
x = build1 (OMP_ATOMIC_READ, type, addr);
SET_EXPR_LOCATION (x, loc);
OMP_ATOMIC_MEMORY_ORDER (x) = memory_order;
+ gcc_assert (!weak);
if (blhs)
x = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), x,
bitsize_int (bitsize), bitsize_int (bitpos));
@@ -313,12 +323,29 @@ c_finish_omp_atomic (location_t loc, enu
{
lhs = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), lhs,
bitsize_int (bitsize), bitsize_int (bitpos));
- if (swapped)
+ if (opcode == COND_EXPR)
+ {
+ bool save = in_late_binary_op;
+ in_late_binary_op = true;
+ std::swap (rhs, rhs1);
+ rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true);
+ in_late_binary_op = save;
+ }
+ else if (swapped)
rhs = build_binary_op (loc, opcode, rhs, lhs, true);
else if (opcode != NOP_EXPR)
rhs = build_binary_op (loc, opcode, lhs, rhs, true);
opcode = NOP_EXPR;
}
+ else if (opcode == COND_EXPR)
+ {
+ bool save = in_late_binary_op;
+ in_late_binary_op = true;
+ std::swap (rhs, rhs1);
+ rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true);
+ in_late_binary_op = save;
+ opcode = NOP_EXPR;
+ }
else if (swapped)
{
rhs = build_binary_op (loc, opcode, rhs, lhs, true);
@@ -343,6 +370,100 @@ c_finish_omp_atomic (location_t loc, enu
if (blhs)
rhs = build3_loc (loc, BIT_INSERT_EXPR, type, new_lhs,
rhs, bitsize_int (bitpos));
+ if (orig_opcode == COND_EXPR)
+ {
+ if (error_operand_p (rhs1))
+ return error_mark_node;
+ gcc_assert (TREE_CODE (rhs1) == EQ_EXPR);
+ tree cmptype = TREE_TYPE (TREE_OPERAND (rhs1, 0));
+ if (SCALAR_FLOAT_TYPE_P (cmptype))
+ {
+ bool clear_padding = false;
+ if (BITS_PER_UNIT == 8 && CHAR_BIT == 8)
+ {
+ HOST_WIDE_INT sz = int_size_in_bytes (cmptype), i;
+ gcc_assert (sz > 0);
+ unsigned char *buf = XALLOCAVEC (unsigned char, sz);
+ memset (buf, ~0, sz);
+ clear_type_padding_in_mask (cmptype, buf);
+ for (i = 0; i < sz; i++)
+ if (buf[i] != (unsigned char) ~0)
+ {
+ clear_padding = true;
+ break;
+ }
+ }
+ tree inttype = NULL_TREE;
+ if (!clear_padding && tree_fits_uhwi_p (TYPE_SIZE (cmptype)))
+ {
+ HOST_WIDE_INT prec = tree_to_uhwi (TYPE_SIZE (cmptype));
+ inttype = c_common_type_for_size (prec, 1);
+ if (inttype
+ && (!tree_int_cst_equal (TYPE_SIZE (cmptype),
+ TYPE_SIZE (inttype))
+ || TYPE_PRECISION (inttype) != prec))
+ inttype = NULL_TREE;
+ }
+ if (inttype)
+ {
+ TREE_OPERAND (rhs1, 0)
+ = build1_loc (loc, VIEW_CONVERT_EXPR, inttype,
+ TREE_OPERAND (rhs1, 0));
+ TREE_OPERAND (rhs1, 1)
+ = build1_loc (loc, VIEW_CONVERT_EXPR, inttype,
+ TREE_OPERAND (rhs1, 1));
+ }
+ else
+ {
+ tree pcmptype = build_pointer_type (cmptype);
+ tree tmp1 = create_tmp_var_raw (cmptype);
+ TREE_ADDRESSABLE (tmp1) = 1;
+ DECL_CONTEXT (tmp1) = current_function_decl;
+ tmp1 = build4 (TARGET_EXPR, cmptype, tmp1,
+ TREE_OPERAND (rhs1, 0), NULL, NULL);
+ tmp1 = build1 (ADDR_EXPR, pcmptype, tmp1);
+ tree tmp2 = create_tmp_var_raw (cmptype);
+ TREE_ADDRESSABLE (tmp2) = 1;
+ DECL_CONTEXT (tmp2) = current_function_decl;
+ tmp2 = build4 (TARGET_EXPR, cmptype, tmp2,
+ TREE_OPERAND (rhs1, 1), NULL, NULL);
+ tmp2 = build1 (ADDR_EXPR, pcmptype, tmp2);
+ tree fndecl = builtin_decl_explicit (BUILT_IN_MEMCMP);
+ rhs1 = build_call_expr_loc (loc, fndecl, 3, tmp1, tmp2,
+ TYPE_SIZE_UNIT (cmptype));
+ rhs1 = build2 (EQ_EXPR, boolean_type_node, rhs1,
+ integer_zero_node);
+ if (clear_padding)
+ {
+ fndecl = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING);
+ tree cp1 = build_call_expr_loc (loc, fndecl, 1, tmp1);
+ tree cp2 = build_call_expr_loc (loc, fndecl, 1, tmp2);
+ rhs1 = omit_two_operands_loc (loc, boolean_type_node,
+ rhs1, cp2, cp1);
+ }
+ }
+ }
+ if (r)
+ {
+ tree var = create_tmp_var (boolean_type_node);
+ DECL_CONTEXT (var) = current_function_decl;
+ rtmp = build4 (TARGET_EXPR, boolean_type_node, var,
+ NULL, NULL, NULL);
+ save = in_late_binary_op;
+ in_late_binary_op = true;
+ x = build_modify_expr (loc, var, NULL_TREE, NOP_EXPR,
+ loc, rhs1, NULL_TREE);
+ in_late_binary_op = save;
+ if (x == error_mark_node)
+ return error_mark_node;
+ gcc_assert (TREE_CODE (x) == MODIFY_EXPR
+ && TREE_OPERAND (x, 0) == var);
+ TREE_OPERAND (x, 0) = rtmp;
+ rhs1 = omit_one_operand_loc (loc, boolean_type_node, x, rtmp);
+ }
+ rhs = build3_loc (loc, COND_EXPR, type, rhs1, rhs, new_lhs);
+ rhs1 = NULL_TREE;
+ }
/* Punt the actual generation of atomic operations to common code. */
if (code == OMP_ATOMIC)
@@ -350,6 +471,7 @@ c_finish_omp_atomic (location_t loc, enu
x = build2 (code, type, addr, rhs);
SET_EXPR_LOCATION (x, loc);
OMP_ATOMIC_MEMORY_ORDER (x) = memory_order;
+ OMP_ATOMIC_WEAK (x) = weak;
/* Generally it is hard to prove lhs1 and lhs are the same memory
location, just diagnose different variables. */
@@ -412,8 +534,25 @@ c_finish_omp_atomic (location_t loc, enu
bitsize_int (bitsize), bitsize_int (bitpos));
type = TREE_TYPE (blhs);
}
- x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
+ if (r)
+ {
+ vtmp = create_tmp_var (TREE_TYPE (x));
+ DECL_CONTEXT (vtmp) = current_function_decl;
+ }
+ else
+ vtmp = v;
+ x = build_modify_expr (loc, vtmp, NULL_TREE, NOP_EXPR,
loc, x, NULL_TREE);
+ if (x == error_mark_node)
+ return error_mark_node;
+ if (r)
+ {
+ vtmp = build4 (TARGET_EXPR, boolean_type_node, vtmp,
+ NULL, NULL, NULL);
+ gcc_assert (TREE_CODE (x) == MODIFY_EXPR
+ && TREE_OPERAND (x, 0) == TARGET_EXPR_SLOT (vtmp));
+ TREE_OPERAND (x, 0) = vtmp;
+ }
if (rhs1 && rhs1 != orig_lhs)
{
tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, false);
@@ -446,6 +585,28 @@ c_finish_omp_atomic (location_t loc, enu
if (pre)
x = omit_one_operand_loc (loc, type, x, pre);
+ if (r && r != void_list_node)
+ {
+ in_late_binary_op = true;
+ tree x2 = build_modify_expr (loc, r, NULL_TREE, NOP_EXPR,
+ loc, rtmp, NULL_TREE);
+ in_late_binary_op = save;
+ if (x2 == error_mark_node)
+ return error_mark_node;
+ x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x);
+ }
+ if (v && vtmp != v)
+ {
+ in_late_binary_op = true;
+ tree x2 = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
+ loc, vtmp, NULL_TREE);
+ in_late_binary_op = save;
+ if (x2 == error_mark_node)
+ return error_mark_node;
+ x2 = build3_loc (loc, COND_EXPR, void_type_node, rtmp,
+ void_node, x2);
+ x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x);
+ }
return x;
}
--- gcc/c/c-parser.c.jj 2021-09-09 10:40:19.956263200 +0200
+++ gcc/c/c-parser.c 2021-09-10 17:06:10.966650277 +0200
@@ -7663,10 +7663,21 @@ c_parser_conditional_expression (c_parse
c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
location_t loc1 = make_location (exp1.get_start (), exp1.src_range);
location_t loc2 = make_location (exp2.get_start (), exp2.src_range);
- ret.value = build_conditional_expr (colon_loc, cond.value,
- cond.original_code == C_MAYBE_CONST_EXPR,
- exp1.value, exp1.original_type, loc1,
- exp2.value, exp2.original_type, loc2);
+ if (__builtin_expect (omp_atomic_lhs != NULL, 0)
+ && (TREE_CODE (cond.value) == GT_EXPR
+ || TREE_CODE (cond.value) == LT_EXPR
+ || TREE_CODE (cond.value) == EQ_EXPR)
+ && c_tree_equal (exp2.value, omp_atomic_lhs)
+ && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs)
+ || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs)))
+ ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE (omp_atomic_lhs),
+ cond.value, exp1.value, exp2.value);
+ else
+ ret.value
+ = build_conditional_expr (colon_loc, cond.value,
+ cond.original_code == C_MAYBE_CONST_EXPR,
+ exp1.value, exp1.original_type, loc1,
+ exp2.value, exp2.original_type, loc2);
ret.original_code = ERROR_MARK;
if (exp1.value == error_mark_node || exp2.value == error_mark_node)
ret.original_type = NULL;
@@ -7849,15 +7860,27 @@ c_parser_binary_expression (c_parser *pa
= convert_lvalue_to_rvalue (stack[sp].loc, \
stack[sp].expr, true, true); \
if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \
- && c_parser_peek_token (parser)->type == CPP_SEMICOLON \
- && ((1 << stack[sp].prec) \
- & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND) \
- | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT))) \
+ && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \
+ && ((1 << stack[sp].prec) \
+ & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \
+ | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \
+ | (1 << PREC_ADD) | (1 << PREC_MULT) \
+ | (1 << PREC_EQ)))) \
+ || ((c_parser_next_token_is (parser, CPP_QUERY) \
+ || (omp_atomic_lhs == void_list_node \
+ && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \
+ && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\
&& stack[sp].op != TRUNC_MOD_EXPR \
+ && stack[sp].op != GE_EXPR \
+ && stack[sp].op != LE_EXPR \
+ && stack[sp].op != NE_EXPR \
&& stack[0].expr.value != error_mark_node \
&& stack[1].expr.value != error_mark_node \
- && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \
- || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) \
+ && (omp_atomic_lhs == void_list_node \
+ || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \
+ || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \
+ || (stack[sp].op == EQ_EXPR \
+ && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \
{ \
tree t = make_node (stack[1].op); \
TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \
@@ -17655,14 +17678,45 @@ c_parser_omp_allocate (location_t loc, c
capture-block:
{ v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
- where x and v are lvalue expressions with scalar type.
+ OpenMP 5.1:
+ # pragma omp atomic compare new-line
+ conditional-update-atomic
+
+ # pragma omp atomic compare capture new-line
+ conditional-update-capture-atomic
+
+ conditional-update-atomic:
+ cond-expr-stmt | cond-update-stmt
+ cond-expr-stmt:
+ x = expr ordop x ? expr : x;
+ x = x ordop expr ? expr : x;
+ x = x == e ? d : x;
+ cond-update-stmt:
+ if (expr ordop x) { x = expr; }
+ if (x ordop expr) { x = expr; }
+ if (x == e) { x = d; }
+ ordop:
+ <, >
+ conditional-update-capture-atomic:
+ v = cond-expr-stmt
+ { v = x; cond-expr-stmt }
+ { cond-expr-stmt v = x; }
+ { v = x; cond-update-stmt }
+ { cond-update-stmt v = x; }
+ if (x == e) { x = d; } else { v = x; }
+ { r = x == e; if (r) { x = d; } }
+ { r = x == e; if (r) { x = d; } else { v = x; } }
+
+ where x, r and v are lvalue expressions with scalar type,
+ expr, e and d are expressions with scalar type and e might be
+ the same as v.
LOC is the location of the #pragma token. */
static void
c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc)
{
- tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE;
tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
enum tree_code code = ERROR_MARK, opcode = NOP_EXPR;
@@ -17674,6 +17728,12 @@ c_parser_omp_atomic (location_t loc, c_p
bool non_lvalue_p;
bool first = true;
tree clauses = NULL_TREE;
+ bool capture = false;
+ bool compare = false;
+ bool weak = false;
+ enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool no_semicolon = false;
+ bool extra_scope = false;
while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
{
@@ -17692,6 +17752,10 @@ c_parser_omp_atomic (location_t loc, c_p
enum tree_code new_code = ERROR_MARK;
enum omp_memory_order new_memory_order
= OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool new_capture = false;
+ bool new_compare = false;
+ bool new_weak = false;
+ enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED;
if (!strcmp (p, "read"))
new_code = OMP_ATOMIC_READ;
@@ -17699,7 +17763,7 @@ c_parser_omp_atomic (location_t loc, c_p
new_code = NOP_EXPR;
else if (!strcmp (p, "update"))
new_code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
+ else if (openacc && !strcmp (p, "capture"))
new_code = OMP_ATOMIC_CAPTURE_NEW;
else if (openacc)
{
@@ -17707,6 +17771,47 @@ c_parser_omp_atomic (location_t loc, c_p
error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
"or %<capture%> clause");
}
+ else if (!strcmp (p, "capture"))
+ new_capture = true;
+ else if (!strcmp (p, "compare"))
+ new_compare = true;
+ else if (!strcmp (p, "weak"))
+ new_weak = true;
+ else if (!strcmp (p, "fail"))
+ {
+ matching_parens parens;
+
+ c_parser_consume_token (parser);
+ if (!parens.require_open (parser))
+ continue;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *q
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (q, "seq_cst"))
+ new_fail = OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (q, "acquire"))
+ new_fail = OMP_MEMORY_ORDER_ACQUIRE;
+ else if (!strcmp (q, "relaxed"))
+ new_fail = OMP_MEMORY_ORDER_RELAXED;
+ }
+
+ if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ c_parser_consume_token (parser);
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ error_at (cloc, "too many %qs clauses", "fail");
+ else
+ fail = new_fail;
+ }
+ else
+ c_parser_error (parser, "expected %<seq_cst%>, %<acquire%> "
+ "or %<relaxed%>");
+ parens.skip_until_found_close (parser);
+ continue;
+ }
else if (!strcmp (p, "seq_cst"))
new_memory_order = OMP_MEMORY_ORDER_SEQ_CST;
else if (!strcmp (p, "acq_rel"))
@@ -17727,8 +17832,9 @@ c_parser_omp_atomic (location_t loc, c_p
{
p = NULL;
error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
- "%<capture%>, %<seq_cst%>, %<acq_rel%>, "
- "%<release%>, %<relaxed%> or %<hint%> clause");
+ "%<capture%>, %<compare%>, %<weak%>, %<fail%>, "
+ "%<seq_cst%>, %<acq_rel%>, %<release%>, "
+ "%<relaxed%> or %<hint%> clause");
}
if (p)
{
@@ -17751,6 +17857,27 @@ c_parser_omp_atomic (location_t loc, c_p
else
memory_order = new_memory_order;
}
+ else if (new_capture)
+ {
+ if (capture)
+ error_at (cloc, "too many %qs clauses", "capture");
+ else
+ capture = true;
+ }
+ else if (new_compare)
+ {
+ if (compare)
+ error_at (cloc, "too many %qs clauses", "compare");
+ else
+ compare = true;
+ }
+ else if (new_weak)
+ {
+ if (weak)
+ error_at (cloc, "too many %qs clauses", "weak");
+ else
+ weak = true;
+ }
c_parser_consume_token (parser);
continue;
}
@@ -17761,6 +17888,30 @@ c_parser_omp_atomic (location_t loc, c_p
if (code == ERROR_MARK)
code = OMP_ATOMIC;
+ if (capture)
+ {
+ if (code != OMP_ATOMIC)
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "capture");
+ else
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ }
+ if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "compare");
+ compare = false;
+ }
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "fail", "compare");
+ fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ }
+ if (weak && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "weak", "compare");
+ weak = false;
+ }
if (openacc)
memory_order = OMP_MEMORY_ORDER_RELAXED;
else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED)
@@ -17785,7 +17936,6 @@ c_parser_omp_atomic (location_t loc, c_p
memory_order = OMP_MEMORY_ORDER_ACQUIRE;
break;
case NOP_EXPR: /* atomic write */
- case OMP_ATOMIC:
memory_order = OMP_MEMORY_ORDER_RELEASE;
break;
default:
@@ -17801,36 +17951,32 @@ c_parser_omp_atomic (location_t loc, c_p
switch (code)
{
case OMP_ATOMIC_READ:
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_RELEASE)
+ if (memory_order == OMP_MEMORY_ORDER_RELEASE)
{
error_at (loc, "%<#pragma omp atomic read%> incompatible with "
- "%<acq_rel%> or %<release%> clauses");
+ "%<release%> clause");
memory_order = OMP_MEMORY_ORDER_SEQ_CST;
}
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_ACQUIRE;
break;
case NOP_EXPR: /* atomic write */
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
+ if (memory_order == OMP_MEMORY_ORDER_ACQUIRE)
{
error_at (loc, "%<#pragma omp atomic write%> incompatible with "
- "%<acq_rel%> or %<acquire%> clauses");
- memory_order = OMP_MEMORY_ORDER_SEQ_CST;
- }
- break;
- case OMP_ATOMIC:
- /* case OMP_ATOMIC_CAPTURE_NEW: - or update to OpenMP 5.1 */
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
- {
- error_at (loc, "%<#pragma omp atomic update%> incompatible with "
- "%<acq_rel%> or %<acquire%> clauses");
+ "%<acquire%> clause");
memory_order = OMP_MEMORY_ORDER_SEQ_CST;
}
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_RELEASE;
break;
default:
break;
}
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ memory_order
+ = (enum omp_memory_order) (memory_order
+ | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT));
switch (code)
{
@@ -17879,6 +18025,9 @@ c_parser_omp_atomic (location_t loc, c_p
c_parser_consume_token (parser);
structured_block = true;
}
+ else if (compare
+ && c_parser_next_token_is_keyword (parser, RID_IF))
+ break;
else
{
v = c_parser_cast_expression (parser, NULL).value;
@@ -17890,6 +18039,12 @@ c_parser_omp_atomic (location_t loc, c_p
v = non_lvalue (v);
if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
goto saw_error;
+ if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
+ {
+ eloc = c_parser_peek_token (parser)->location;
+ error_at (eloc, "expected expression");
+ goto saw_error;
+ }
}
break;
default:
@@ -17899,6 +18054,179 @@ c_parser_omp_atomic (location_t loc, c_p
/* For structured_block case we don't know yet whether
old or new x should be captured. */
restart:
+ if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ goto saw_error;
+ eloc = c_parser_peek_token (parser)->location;
+ c_expr cmp_expr;
+ if (r)
+ {
+ cmp_expr = c_parser_cast_expression (parser, NULL);
+ cmp_expr = default_function_array_conversion (eloc, cmp_expr);
+ }
+ else
+ cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node);
+ parens.skip_until_found_close (parser);
+ if (cmp_expr.value == error_mark_node)
+ goto saw_error;
+ if (r)
+ {
+ if (!c_tree_equal (cmp_expr.value, unfolded_lhs))
+ goto bad_if;
+ cmp_expr.value = rhs1;
+ rhs1 = NULL_TREE;
+ gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR);
+ }
+ if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ ;
+ else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
+ "expected %<==%> comparison in %<if%> condition");
+ goto saw_error;
+ }
+ else if (TREE_CODE (cmp_expr.value) != GT_EXPR
+ && TREE_CODE (cmp_expr.value) != LT_EXPR)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
+ "expected %<==%>, %<<%> or %<>%> comparison in %<if%> "
+ "condition");
+ goto saw_error;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ goto saw_error;
+
+ extra_scope = true;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ lhs = expr.value;
+ expr = default_function_array_conversion (eloc, expr);
+ unfolded_lhs = expr.value;
+ lhs = c_fully_fold (lhs, false, NULL, true);
+ orig_lhs = lhs;
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (!lvalue_p (unfolded_lhs))
+ lhs = non_lvalue (lhs);
+ if (!c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ rhs1 = expr.value;
+
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+
+ if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
+ goto saw_error;
+
+ extra_scope = false;
+ no_semicolon = true;
+
+ if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs))
+ {
+ if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
+ false, NULL, true);
+ rhs1 = c_fully_fold (rhs1, false, NULL, true);
+ }
+ else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
+ ? MIN_EXPR : MAX_EXPR);
+ rhs = c_fully_fold (rhs1, false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0),
+ false, NULL, true);
+ }
+ else
+ goto bad_if;
+ }
+ else if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ goto bad_if;
+ else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs)
+ && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
+ ? MAX_EXPR : MIN_EXPR);
+ rhs = c_fully_fold (rhs1, false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
+ false, NULL, true);
+ }
+ else
+ {
+ bad_if:
+ c_parser_error (parser,
+ "invalid form of %<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
+
+ if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ if (code != OMP_ATOMIC_CAPTURE_NEW
+ || (structured_block && r == NULL_TREE)
+ || TREE_CODE (cmp_expr.value) != EQ_EXPR)
+ {
+ eloc = c_parser_peek_token (parser)->location;
+ error_at (eloc, "unexpected %<else%>");
+ goto saw_error;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ goto saw_error;
+
+ extra_scope = true;
+ v = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (v);
+ v = c_fully_fold (v, false, NULL, true);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ v = non_lvalue (v);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+
+ expr = c_parser_expr_no_commas (parser, NULL);
+
+ if (!c_tree_equal (expr.value, unfolded_lhs))
+ goto bad_if;
+
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+
+ if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
+ goto saw_error;
+
+ extra_scope = false;
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ if (r == NULL_TREE)
+ /* Signal to c_finish_omp_atomic that in
+ if (x == e) { x = d; } else { v = x; }
+ case the store to v should be conditional. */
+ r = void_list_node;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ {
+ c_parser_require_keyword (parser, RID_ELSE, "expected %<else%>");
+ goto saw_error;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW
+ && r != NULL_TREE
+ && v == NULL_TREE)
+ code = OMP_ATOMIC;
+ goto stmt_done;
+ }
eloc = c_parser_peek_token (parser)->location;
expr = c_parser_cast_expression (parser, NULL);
lhs = expr.value;
@@ -17908,9 +18236,14 @@ restart:
orig_lhs = lhs;
switch (TREE_CODE (lhs))
{
+ invalid_compare:
+ error_at (eloc, "invalid form of %<pragma omp atomic compare%>");
+ /* FALLTHRU */
case ERROR_MARK:
saw_error:
c_parser_skip_to_end_of_block_or_statement (parser);
+ if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
if (structured_block)
{
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
@@ -17933,6 +18266,8 @@ restart:
unfolded_lhs = NULL_TREE;
opcode = PLUS_EXPR;
rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
break;
case POSTDECREMENT_EXPR:
@@ -17944,6 +18279,8 @@ restart:
unfolded_lhs = NULL_TREE;
opcode = MINUS_EXPR;
rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
break;
case COMPOUND_EXPR:
@@ -17973,6 +18310,8 @@ restart:
&& !structured_block
&& TREE_CODE (orig_lhs) == COMPOUND_EXPR)
code = OMP_ATOMIC_CAPTURE_OLD;
+ if (compare)
+ goto invalid_compare;
break;
}
if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
@@ -17988,6 +18327,8 @@ restart:
&& !structured_block
&& TREE_CODE (orig_lhs) == COMPOUND_EXPR)
code = OMP_ATOMIC_CAPTURE_OLD;
+ if (compare)
+ goto invalid_compare;
break;
}
}
@@ -17995,6 +18336,11 @@ restart:
default:
if (!lvalue_p (unfolded_lhs))
lhs = non_lvalue (lhs);
+ if (compare && !c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
switch (c_parser_peek_token (parser)->type)
{
case CPP_MULT_EQ:
@@ -18041,6 +18387,8 @@ restart:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
+ if (compare)
+ break;
if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
{
opcode = TREE_CODE (rhs1);
@@ -18061,6 +18409,78 @@ restart:
goto stmt_done;
}
break;
+ case COND_EXPR:
+ if (!compare)
+ break;
+ if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR)
+ break;
+ if (!TREE_OPERAND (rhs1, 1))
+ break;
+ if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs))
+ break;
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0),
+ unfolded_lhs))
+ {
+ if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 1),
+ false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false,
+ NULL, true);
+ goto stmt_done;
+ }
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1),
+ TREE_OPERAND (rhs1, 1)))
+ {
+ opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR
+ ? MIN_EXPR : MAX_EXPR);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 0),
+ false, NULL, true);
+ goto stmt_done;
+ }
+ }
+ else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
+ break;
+ else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1),
+ unfolded_lhs))
+ {
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0),
+ TREE_OPERAND (rhs1, 1)))
+ {
+ opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR
+ ? MAX_EXPR : MIN_EXPR);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 1),
+ false, NULL, true);
+ goto stmt_done;
+ }
+ }
+ break;
+ case EQ_EXPR:
+ if (!compare
+ || code != OMP_ATOMIC_CAPTURE_NEW
+ || !structured_block
+ || v
+ || r)
+ break;
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ && c_parser_peek_2nd_token (parser)->keyword == RID_IF)
+ {
+ r = lhs;
+ lhs = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ break;
case ERROR_MARK:
goto saw_error;
default:
@@ -18109,10 +18529,12 @@ restart:
break;
}
stmt_done:
- if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE)
{
- if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ if (!no_semicolon
+ && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
goto saw_error;
+ no_semicolon = false;
v = c_parser_cast_expression (parser, NULL).value;
non_lvalue_p = !lvalue_p (v);
v = c_fully_fold (v, false, NULL, true);
@@ -18135,10 +18557,16 @@ stmt_done:
}
if (structured_block)
{
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ if (!no_semicolon)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
}
done:
+ if (weak && opcode != COND_EXPR)
+ {
+ error_at (loc, "%<weak%> clause requires atomic equality comparison");
+ weak = false;
+ }
if (unfolded_lhs && unfolded_lhs1
&& !c_tree_equal (unfolded_lhs, unfolded_lhs1))
{
@@ -18147,12 +18575,12 @@ done:
stmt = error_mark_node;
}
else
- stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1,
- swapped, memory_order);
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r,
+ swapped, memory_order, weak);
if (stmt != error_mark_node)
add_stmt (stmt);
- if (!structured_block)
+ if (!structured_block && !no_semicolon)
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
--- gcc/c/c-typeck.c.jj 2021-09-09 10:40:19.979262872 +0200
+++ gcc/c/c-typeck.c 2021-09-09 10:41:42.630084554 +0200
@@ -12426,6 +12426,13 @@ build_binary_op (location_t location, en
maybe_warn_bool_compare (location, code, orig_op0, orig_op1);
break;
+ case MIN_EXPR:
+ case MAX_EXPR:
+ /* Used for OpenMP atomics. */
+ gcc_assert (flag_openmp);
+ common = 1;
+ break;
+
default:
gcc_unreachable ();
}
--- gcc/cp/parser.c.jj 2021-09-09 10:40:19.996262630 +0200
+++ gcc/cp/parser.c 2021-09-09 10:41:42.623084654 +0200
@@ -40193,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser,
memory_order = OMP_MEMORY_ORDER_ACQUIRE;
break;
case NOP_EXPR: /* atomic write */
- case OMP_ATOMIC:
memory_order = OMP_MEMORY_ORDER_RELEASE;
break;
default:
@@ -40209,31 +40208,24 @@ cp_parser_omp_atomic (cp_parser *parser,
switch (code)
{
case OMP_ATOMIC_READ:
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_RELEASE)
+ if (memory_order == OMP_MEMORY_ORDER_RELEASE)
{
error_at (loc, "%<#pragma omp atomic read%> incompatible with "
- "%<acq_rel%> or %<release%> clauses");
+ "%<release%> clause");
memory_order = OMP_MEMORY_ORDER_SEQ_CST;
}
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_ACQUIRE;
break;
case NOP_EXPR: /* atomic write */
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
+ if (memory_order == OMP_MEMORY_ORDER_ACQUIRE)
{
error_at (loc, "%<#pragma omp atomic write%> incompatible with "
- "%<acq_rel%> or %<acquire%> clauses");
- memory_order = OMP_MEMORY_ORDER_SEQ_CST;
- }
- break;
- case OMP_ATOMIC:
- if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
- || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
- {
- error_at (loc, "%<#pragma omp atomic update%> incompatible with "
- "%<acq_rel%> or %<acquire%> clauses");
+ "%<acquire%> clause");
memory_order = OMP_MEMORY_ORDER_SEQ_CST;
}
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_RELEASE;
break;
default:
break;
--- gcc/cp/semantics.c.jj 2021-09-09 10:40:26.093175709 +0200
+++ gcc/cp/semantics.c 2021-09-09 10:59:17.762032066 +0200
@@ -9956,7 +9956,7 @@ finish_omp_atomic (location_t loc, enum
return;
}
stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs,
- v, lhs1, rhs1, swapped, mo,
+ v, lhs1, rhs1, NULL_TREE, swapped, mo, false,
processing_template_decl != 0);
if (stmt == error_mark_node)
return;
--- gcc/testsuite/c-c++-common/gomp/atomic-17.c.jj 2021-09-09 10:40:20.088261318 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-17.c 2021-09-09 10:41:42.624084639 +0200
@@ -22,8 +22,18 @@ foo ()
v = i = i + 1;
#pragma omp atomic read acquire
v = i;
+ #pragma omp atomic acq_rel read
+ v = i;
#pragma omp atomic release,write
i = v;
+ #pragma omp atomic write,acq_rel
+ i = v;
#pragma omp atomic hint(1),update,release
f = f + 2.0;
+ #pragma omp atomic update ,acquire
+ i = i + 1;
+ #pragma omp atomic acq_rel update
+ i = i + 1;
+ #pragma omp atomic acq_rel,hint(0)
+ i = i + 1;
}
--- gcc/testsuite/c-c++-common/gomp/atomic-18.c.jj 2021-09-09 10:40:20.088261318 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-18.c 2021-09-09 10:41:42.624084639 +0200
@@ -8,28 +8,18 @@ foo (int j)
i = i + 1;
#pragma omp atomic seq_cst release /* { dg-error "too many memory order clauses" } */
i = i + 1;
- #pragma omp atomic read,release /* { dg-error "incompatible with 'acq_rel' or 'release' clauses" } */
+ #pragma omp atomic read,release /* { dg-error "incompatible with 'release' clause" } */
v = i;
- #pragma omp atomic acq_rel read /* { dg-error "incompatible with 'acq_rel' or 'release' clauses" } */
- v = i;
- #pragma omp atomic write acq_rel /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
- i = v;
- #pragma omp atomic acquire , write /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
+ #pragma omp atomic acquire , write /* { dg-error "incompatible with 'acquire' clause" } */
i = v;
- #pragma omp atomic update ,acquire /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
- i = i + 1;
- #pragma omp atomic acq_rel update /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
- i = i + 1;
- #pragma omp atomic acq_rel,hint(0) /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
- i = i + 1;
- #pragma omp atomic acquire /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
- i = i + 1;
- #pragma omp atomic capture hint (0) capture /* { dg-error "too many atomic clauses" } */
+ #pragma omp atomic capture hint (0) capture /* { dg-error "too many 'capture' clauses" "" { target c } } */
+ /* { dg-error "too many atomic clauses" "" { target c++ } .-1 } */
v = i = i + 1;
#pragma omp atomic hint(j + 2) /* { dg-error "constant integer expression" } */
i = i + 1;
#pragma omp atomic hint(f) /* { dg-error "integ" } */
i = i + 1;
- #pragma omp atomic foobar /* { dg-error "expected 'read', 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" } */
- i = i + 1; /* { dg-error "expected end of line before" "" { target *-*-* } .-1 } */
+ #pragma omp atomic foobar /* { dg-error "expected 'read', 'write', 'update', 'capture', 'compare', 'weak', 'fail', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target c } } */
+ /* { dg-error "expected 'read', 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target c++ } .-1 } */
+ i = i + 1; /* { dg-error "expected end of line before" "" { target *-*-* } .-2 } */
}
--- gcc/testsuite/c-c++-common/gomp/atomic-21.c.jj 2020-04-15 09:58:30.369649495 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-21.c 2021-09-09 17:25:18.782025085 +0200
@@ -1,6 +1,7 @@
/* { dg-do compile } */
/* { dg-additional-options "-fdump-tree-original" } */
-/* { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" } } */
+/* { dg-final { scan-tree-dump-times "omp atomic release" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "omp atomic acq_rel" 2 "original" } } */
/* { dg-final { scan-tree-dump-times "omp atomic read acquire" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 1 "original" } } */
--- gcc/testsuite/c-c++-common/gomp/atomic-25.c.jj 2021-09-09 10:41:42.624084639 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-25.c 2021-09-10 13:18:43.096258564 +0200
@@ -0,0 +1,50 @@
+/* { dg-do compile { target c } } */
+
+int x, r, z;
+double d, v;
+long double ld;
+
+void
+foo (int y, double e, long double f)
+{
+ #pragma omp atomic compare update seq_cst
+ x = x > y ? y : x;
+ #pragma omp atomic compare relaxed
+ d = e > d ? e : d;
+ #pragma omp atomic compare
+ d = f < d ? f : d;
+ #pragma omp atomic compare seq_cst fail(relaxed)
+ x = 12U < x ? 12U : x;
+ #pragma omp atomic compare
+ x = x == 7 ? 24 : x;
+ #pragma omp atomic compare
+ x = x == 123UL ? 256LL : x;
+ #pragma omp atomic compare
+ ld = ld == f ? f + 5.0L : ld;
+ #pragma omp atomic compare
+ if (x == 9) { x = 5; }
+ #pragma omp atomic compare
+ if (x > 5) { x = 5; }
+ #pragma omp atomic compare
+ if (7 > x) { x = 7; }
+ #pragma omp atomic compare update capture seq_cst fail(acquire)
+ v = d = f > d ? f : d;
+ #pragma omp atomic update capture compare
+ v = x = x < 24ULL ? 24ULL : x;
+ #pragma omp atomic compare, capture, update
+ v = x = x == e ? f : x;
+ #pragma omp atomic capture compare
+ { v = d; if (d > e) { d = e; } }
+ #pragma omp atomic compare capture
+ { if (e < d) { d = e; } v = d; }
+ #pragma omp atomic compare capture
+ { y = x; if (x == 42) { x = 7; } }
+ #pragma omp atomic capture compare weak
+ { if (x == 42) { x = 7; } y = x; }
+ #pragma omp atomic capture compare fail(seq_cst)
+ if (d == 8.0) { d = 16.0; } else { v = d; }
+ #pragma omp atomic capture compare
+ { r = x == 8; if (r) { x = 24; } }
+ #pragma omp atomic compare capture
+ { r = x == y; if (r) { x = y + 6; } else { z = x; } }
+}
--- gcc/testsuite/c-c++-common/gomp/atomic-26.c.jj 2021-09-09 10:41:42.624084639 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-26.c 2021-09-10 15:16:10.111808506 +0200
@@ -0,0 +1,63 @@
+/* { dg-do compile { target c } } */
+
+int x;
+double d;
+
+double
+foo (int y, double e, long double f)
+{
+ double v;
+ #pragma omp atomic compare compare /* { dg-error "too many 'compare' clauses" } */
+ x = x > y ? y : x;
+ #pragma omp atomic compare fail(seq_cst) fail(seq_cst) /* { dg-error "too many 'fail' clauses" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare,fail(seq_cst),fail(relaxed) /* { dg-error "too many 'fail' clauses" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare weak weak /* { dg-error "too many 'weak' clauses" } */
+ d = d == e ? e + 1.0 : d;
+ #pragma omp atomic read capture /* { dg-error "'capture' clause is incompatible with 'read' or 'write' clauses" } */
+ v = d;
+ #pragma omp atomic capture, write /* { dg-error "'capture' clause is incompatible with 'read' or 'write' clauses" } */
+ d = v;
+ #pragma omp atomic read compare /* { dg-error "'compare' clause is incompatible with 'read' or 'write' clauses" } */
+ v = d;
+ #pragma omp atomic compare, write /* { dg-error "'compare' clause is incompatible with 'read' or 'write' clauses" } */
+ d = v;
+ #pragma omp atomic read fail(seq_cst) /* { dg-error "'fail' clause requires 'compare' clause" } */
+ v = d;
+ #pragma omp atomic fail(relaxed), write /* { dg-error "'fail' clause requires 'compare' clause" } */
+ d = v;
+ #pragma omp atomic fail(relaxed) update /* { dg-error "'fail' clause requires 'compare' clause" } */
+ d += 3.0;
+ #pragma omp atomic fail(relaxed) /* { dg-error "'fail' clause requires 'compare' clause" } */
+ d += 3.0;
+ #pragma omp atomic capture fail(relaxed) /* { dg-error "'fail' clause requires 'compare' clause" } */
+ v = d += 3.0;
+ #pragma omp atomic read weak /* { dg-error "'weak' clause requires 'compare' clause" } */
+ v = d;
+ #pragma omp atomic weak, write /* { dg-error "'weak' clause requires 'compare' clause" } */
+ d = v;
+ #pragma omp atomic weak update /* { dg-error "'weak' clause requires 'compare' clause" } */
+ d += 3.0;
+ #pragma omp atomic weak /* { dg-error "'weak' clause requires 'compare' clause" } */
+ d += 3.0;
+ #pragma omp atomic capture weak /* { dg-error "'weak' clause requires 'compare' clause" } */
+ v = d += 3.0;
+ #pragma omp atomic compare,weak /* { dg-error "'weak' clause requires atomic equality comparison" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail /* { dg-error "expected '\\\(' before end of line" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail( /* { dg-error "expected 'seq_cst', 'acquire' or 'relaxed' before end of line" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail() /* { dg-error "expected 'seq_cst', 'acquire' or 'relaxed' before '\\\)' token" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail(foobar) /* { dg-error "expected 'seq_cst', 'acquire' or 'relaxed' before 'foobar'" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail(acq_rel) /* { dg-error "expected 'seq_cst', 'acquire' or 'relaxed' before 'acq_rel'" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail(release) /* { dg-error "expected 'seq_cst', 'acquire' or 'relaxed' before 'release'" } */
+ d = e > d ? e : d;
+ #pragma omp atomic compare fail(seq_cst /* { dg-error "expected '\\\)' before end of line" } */
+ d = e > d ? e : d;
+ return v;
+}
--- gcc/testsuite/c-c++-common/gomp/atomic-27.c.jj 2021-09-09 16:58:07.052709219 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-27.c 2021-09-09 17:05:13.271786779 +0200
@@ -0,0 +1,41 @@
+/* PR middle-end/88968 */
+/* { dg-do compile { target c } } */
+
+struct __attribute__((packed)) S {
+ unsigned int a : 16;
+ unsigned int b : 1;
+} s;
+
+void
+foo (int y, int z)
+{
+ #pragma omp atomic compare
+ s.a = s.a == y ? z : s.a;
+}
+
+int
+bar (int y, int z)
+{
+ int r;
+ #pragma omp atomic compare capture
+ { r = s.a == y; if (r) { s.a = z; } }
+ return r;
+}
+
+int
+baz (int y, int z)
+{
+ int v;
+ #pragma omp atomic compare capture
+ if (s.a == y) { s.a = z; } else { v = s.a; }
+ return v;
+}
+
+int
+qux (int y, int z)
+{
+ int v;
+ #pragma omp atomic compare capture
+ v = s.a = s.a == y ? z : s.a;
+ return v;
+}
--- gcc/testsuite/c-c++-common/gomp/atomic-28.c.jj 2021-09-10 11:47:09.193274972 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-28.c 2021-09-10 11:52:05.398115961 +0200
@@ -0,0 +1,43 @@
+/* { dg-do compile { target c } } */
+/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 4, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 4, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 260, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 4, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-not "__atomic_load_4 \\\(" "ompexp" { target sync_int_long } } } */
+
+int x;
+
+void
+foo (int y, int z)
+{
+ #pragma omp atomic compare seq_cst
+ x = x == y ? z : x;
+}
+
+int
+bar (int y, int z)
+{
+ int r;
+ #pragma omp atomic compare capture acq_rel fail (acquire)
+ { r = x == y; if (r) { x = z; } }
+ return r;
+}
+
+int
+baz (int y, int z)
+{
+ int v;
+ #pragma omp atomic compare capture seq_cst fail (relaxed) weak
+ if (x == y) { x = z; } else { v = x; }
+ return v;
+}
+
+int
+qux (int y, int z)
+{
+ int v;
+ #pragma omp atomic compare capture
+ v = x = x == y ? z : x;
+ return v;
+}
--- gcc/testsuite/c-c++-common/gomp/atomic-29.c.jj 2021-09-10 11:47:17.093164041 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-29.c 2021-09-10 11:52:33.428722747 +0200
@@ -0,0 +1,43 @@
+/* { dg-do compile { target c } } */
+/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 8, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 8, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 264, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE \\\(\[^\n\r]*, 8, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
+/* { dg-final { scan-tree-dump-not "__atomic_load_8 \\\(" "ompexp" { target sync_int_long } } } */
+
+double x;
+
+void
+foo (double y, double z)
+{
+ #pragma omp atomic compare seq_cst
+ x = x == y ? z : x;
+}
+
+double
+bar (double y, double z)
+{
+ int r;
+ #pragma omp atomic compare capture acq_rel fail (acquire)
+ { r = x == y; if (r) { x = z; } }
+ return r;
+}
+
+double
+baz (double y, double z)
+{
+ double v;
+ #pragma omp atomic compare capture seq_cst fail (relaxed) weak
+ if (x == y) { x = z; } else { v = x; }
+ return v;
+}
+
+double
+qux (double y, double z)
+{
+ double v;
+ #pragma omp atomic compare capture
+ v = x = x == y ? z : x;
+ return v;
+}
--- gcc/testsuite/c-c++-common/gomp/atomic-30.c.jj 2021-09-10 15:25:01.955425201 +0200
+++ gcc/testsuite/c-c++-common/gomp/atomic-30.c 2021-09-10 18:02:50.229520066 +0200
@@ -0,0 +1,137 @@
+/* { dg-do compile { target c } } */
+
+int x;
+double d, g;
+
+double
+foo (int y, double e, long double f)
+{
+ double v;
+ int r, r2 = 0;
+ #pragma omp atomic capture compare
+ v = if (d == e) { d = f; }; /* { dg-error "expected expression" } */
+ #pragma omp atomic compare
+ if; /* { dg-error "expected '\\\(' before ';' token" } */
+ #pragma omp atomic compare
+ if (d >= e) { d = e; } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic compare
+ if (d <= e) { d = e; } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic compare
+ if (d != e) { d = e; } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic compare
+ if (d + e) { d = e; } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d >= e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d <= e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d > e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d < e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d != e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d + e; if (r) { d = f; } } /* { dg-error "expected '==', '<' or '>' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ { r = d == e; if (r2) { d = f; } } /* { dg-error "invalid form of '#pragma omp atomic compare' before '\{' token" } */
+ #pragma omp atomic capture compare
+ if (d > e) { d = e; } /* { dg-error "expected '==' comparison in 'if' condition" } */
+ #pragma omp atomic capture compare
+ if (d < e) { d = e; } /* { dg-error "expected '==' comparison in 'if' condition" } */
+ #pragma omp atomic compare
+ if (d < e) d = e; /* { dg-error "expected '\{' before 'd'" } */
+ #pragma omp atomic compare
+ if (d == e) d = e + 1.0; /* { dg-error "expected '\{' before 'd'" } */
+ #pragma omp atomic compare
+ if (d < e) { d += e; } /* { dg-error "expected '=' before '\\\+=' token" } */
+ #pragma omp atomic compare
+ if (d < e) { d = e }; /* { dg-error "expected ';' before '\}' token" } */
+ #pragma omp atomic compare
+ if (d < e) { d = e; e = 1.0; } /* { dg-error "expected '\}' before 'e'" } */
+ #pragma omp atomic compare
+ if (e == d) { d = f; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (e == d) { g = f; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (d < e) { g = e; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (d > e) { g = e; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (d < e) { d = g; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (d > e) { d = g; }; /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare
+ if (d == e) { d = f; } else ; /* { dg-error "unexpected 'else'" } */
+ #pragma omp atomic compare capture
+ { if (d == e) { d = f; } else { v = d; } v = d; } /* { dg-error "unexpected 'else'" } */
+ #pragma omp atomic compare
+ if (d < e) { d = e; } else { v = d; } /* { dg-error "unexpected 'else'" } */
+ #pragma omp atomic compare capture
+ if (d == e) { d = f; } else v = d; /* { dg-error "expected '\{' before 'v'" } */
+ #pragma omp atomic compare capture
+ if (d == e) { d = f; } else { v += d; } /* { dg-error "expected '=' before '\\\+=' token" } */
+ #pragma omp atomic compare capture
+ if (d == e) { d = f; } else { v = e; } /* { dg-error "invalid form of '#pragma omp atomic compare' before ';' token" } */
+ #pragma omp atomic compare capture
+ if (d == e) { d = f; } else { v = d }; /* { dg-error "expected ';' before '\}' token" } */
+ #pragma omp atomic compare capture
+ if (d == e) { d = f; }; /* { dg-error "expected 'else' before ';' token" } */
+ #pragma omp atomic compare
+ x++; /* { dg-error "invalid form of 'pragma omp atomic compare'" } */
+ #pragma omp atomic compare
+ x--; /* { dg-error "invalid form of 'pragma omp atomic compare'" } */
+ #pragma omp atomic compare
+ ++x; /* { dg-error "invalid form of 'pragma omp atomic compare'" } */
+ #pragma omp atomic compare
+ --x; /* { dg-error "invalid form of 'pragma omp atomic compare'" } */
+ #pragma omp atomic compare
+ x += 3; /* { dg-error "expected '=' before '\\\+=' token" } */
+ #pragma omp atomic compare
+ x -= 5; /* { dg-error "expected '=' before '-=' token" } */
+ #pragma omp atomic compare
+ x *= 2; /* { dg-error "expected '=' before '\\\*=' token" } */
+ #pragma omp atomic compare
+ x |= 5; /* { dg-error "expected '=' before '\\\|=' token" } */
+ #pragma omp atomic compare
+ x &= ~5; /* { dg-error "expected '=' before '\\\&=' token" } */
+ #pragma omp atomic compare
+ x ^= 5; /* { dg-error "expected '=' before '\\\^=' token" } */
+ #pragma omp atomic compare
+ x = x + 3; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x - 5; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = 2 * x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = 5 | x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x & ~5; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x | 5; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x >= 5 ? 5 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x <= 5 ? 5 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x != 5 ? 7 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = 5 == x ? 7 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x == 5 ? x : 7; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x == 5 ? 9 : 7; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x > 5 ? 6 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x < 5 ? 6 : x; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x > 5 ? x : 6; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic compare
+ x = x < 5 ? x : 6; /* { dg-error "invalid form of '#pragma omp atomic' before ';' token" } */
+ #pragma omp atomic capture
+ r = x == 5; /* { dg-error "invalid operator for '#pragma omp atomic' before '==' token" } */
+ #pragma omp atomic capture compare
+ r = x == 5; /* { dg-error "expected '=' before '==' token" } */
+ #pragma omp atomic capture compare /* { dg-error "'#pragma omp atomic compare capture' with non-integral comparison result" } */
+ { v = x == 5; if (v) { x = 6; } }
+}
--- gcc/testsuite/c-c++-common/goacc-gomp/atomic.c.jj 2020-11-06 11:14:19.942201229 +0100
+++ gcc/testsuite/c-c++-common/goacc-gomp/atomic.c 2021-09-09 17:10:58.686986511 +0200
@@ -37,7 +37,8 @@ foo ()
/* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read acquire" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read relaxed" 1 "original" } } */
-/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp atomic acq_rel" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "#pragma omp atomic relaxed" 2 "original" } } */
/* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture acq_rel" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture relaxed" 2 "original" } } */
--- gcc/testsuite/gcc.dg/gomp/atomic-5.c.jj 2021-09-09 10:40:20.099261161 +0200
+++ gcc/testsuite/gcc.dg/gomp/atomic-5.c 2021-09-09 10:41:42.625084625 +0200
@@ -27,7 +27,7 @@ void f1(void)
#pragma omp atomic
bar() += 1; /* { dg-error "lvalue required" } */
#pragma omp atomic a /* { dg-error "expected end of line" } */
- x++; /* { dg-error "expected 'read', 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target *-*-* } .-1 } */
+ x++; /* { dg-error "expected 'read', 'write', 'update', 'capture', 'compare', 'weak', 'fail', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target *-*-* } .-1 } */
#pragma omp atomic
; /* { dg-error "expected expression" } */
#pragma omp atomic
--- gcc/testsuite/g++.dg/gomp/atomic-18.C.jj 2020-04-15 09:58:30.372649450 +0200
+++ gcc/testsuite/g++.dg/gomp/atomic-18.C 2021-09-09 17:27:28.671222445 +0200
@@ -1,6 +1,7 @@
// { dg-do compile }
// { dg-additional-options "-fdump-tree-original" }
-// { dg-final { scan-tree-dump-times "omp atomic release" 5 "original" } }
+// { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" } }
+// { dg-final { scan-tree-dump-times "omp atomic acq_rel" 1 "original" } }
// { dg-final { scan-tree-dump-times "omp atomic seq_cst" 1 "original" } }
// { dg-final { scan-tree-dump-times "omp atomic relaxed" 2 "original" } }
// { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 3 "original" } }
--- libgomp/testsuite/libgomp.c-c++-common/atomic-19.c.jj 2021-09-10 12:09:43.320275112 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/atomic-19.c 2021-09-10 14:24:03.200540163 +0200
@@ -0,0 +1,274 @@
+// { dg-do run { target c } }
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+int x = 6;
+int w, y;
+
+int *
+foo (void)
+{
+ if (w)
+ abort ();
+ return &y;
+}
+
+int
+main ()
+{
+ int v, r;
+ #pragma omp atomic compare
+ x = x > 8 ? 8 : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic compare
+ x = x > 4 ? 4 : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 4)
+ abort ();
+ #pragma omp atomic compare capture
+ v = x = x < 8 ? 8 : x;
+ if (v != 8)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 8)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; x = x < 12 ? 12 : x; }
+ if (v != 8)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; x = x < 4 ? 4 : x; }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic write
+ x = -32;
+ #pragma omp atomic capture compare seq_cst fail(relaxed)
+ { x = 12U < x ? 12U : x; v = x; }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic compare
+ x = x == 12 ? 16 : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ r = 57;
+ #pragma omp atomic compare capture
+ v = x = x == 15 ? r + 7 : x;
+ if (v != 16)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ #pragma omp atomic capture, update, compare seq_cst fail(acquire)
+ { v = x; x = x == 73ULL - r ? 12LL : x; }
+ if (v != 16)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic update, compare, capture
+ { x = x == 69LL - r ? (unsigned char) 6 : x; v = x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic compare
+ if (x > 8) { x = 8; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic compare
+ if (x > 4) { x = 4; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 4)
+ abort ();
+ #pragma omp atomic compare capture
+ { if (x < 8) { x = 8; } v = x; }
+ if (v != 8)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 8)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; if (x < 12) { x = 12; } }
+ if (v != 8)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; if (x < 4) { x = 4; } }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic write
+ x = -32;
+ #pragma omp atomic capture compare seq_cst fail(relaxed)
+ { if (12U < x) { x = 12U; } v = x; }
+ if (v != 12)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic compare
+ if (x == 12) { x = 16; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ r = 57;
+ #pragma omp atomic compare capture
+ { if (x == 15) { x = r + 7; } v = x; }
+ if (v != 16)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ #pragma omp atomic capture, update, compare seq_cst fail(acquire)
+ { v = x; if (x == 73ULL - r) { x = 12LL; } }
+ if (v != 16)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic update, compare, capture
+ { if (x == 69LL - r) { x = (unsigned char) 6; } v = x; }
+ if (v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ v = 24;
+ #pragma omp atomic compare capture
+ if (x == 12) { x = 16; } else { v = x; }
+ if (v != 6)
+ abort ();
+ v = 32;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ v = 147;
+ #pragma omp atomic capture compare
+ if (x == 6) { x = 57; } else { v = x; }
+ if (v != 147)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 57)
+ abort ();
+ #pragma omp atomic update, capture, compare, weak, seq_cst, fail (relaxed)
+ { r = x == 137; if (r) { x = 174; } }
+ if (r)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 57)
+ abort ();
+ #pragma omp atomic compare capture fail (relaxed)
+ { r = x == 57; if (r) { x = 6; } }
+ if (r != 1)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ v = -5;
+ #pragma omp atomic capture compare
+ { r = x == 17; if (r) { x = 25; } else { v = x; } }
+ if (r || v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ v = 15;
+ #pragma omp atomic capture compare
+ { r = x == 6; if (r) { x = 23; } else { v = x; } }
+ if (r != 1 || v != 15)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 23)
+ abort ();
+ w = 1;
+ #pragma omp atomic compare capture
+ if (x == 23) { x = 57; } else { foo ()[0] = x; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 57)
+ abort ();
+ #pragma omp atomic capture update compare
+ { r = x == 57; if (r) { x = 23; } else { foo ()[0] = x; } }
+ if (r != 1)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 23)
+ abort ();
+ w = 0;
+ #pragma omp atomic compare capture
+ if (x == 24) { x = 57; } else { foo ()[0] = x; }
+ if (y != 23)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 23)
+ abort ();
+ y = -5;
+ #pragma omp atomic capture update compare
+ {
+ r = x == 57;
+ if (r)
+ {
+ x = 27;
+ }
+ else
+ {
+ foo ()[0] = x;
+ }
+ }
+ if (r || y != 23)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 23)
+ abort ();
+ return 0;
+}
--- libgomp/testsuite/libgomp.c-c++-common/atomic-20.c.jj 2021-09-10 14:08:45.330336955 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/atomic-20.c 2021-09-10 14:27:14.746865949 +0200
@@ -0,0 +1,203 @@
+// { dg-do run { target c } }
+
+extern
+#ifdef __cplusplus
+"C"
+#endif
+void abort (void);
+float x = 6.0f;
+
+int
+main ()
+{
+ float v;
+ int r;
+ #pragma omp atomic compare
+ x = x > 8.0f ? 8.0f : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ #pragma omp atomic compare
+ x = x > 4.0f ? 4.0f : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 4.0f)
+ abort ();
+ #pragma omp atomic compare capture
+ v = x = x < 8.0f ? 8.0f : x;
+ if (v != 8.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 8)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; x = x < 12.0f ? 12.0f : x; }
+ if (v != 8.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; x = x < 4.0f ? 4.0f : x; }
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic compare
+ x = x == 12.0 ? 16.0L : x;
+ #pragma omp atomic read
+ v = x;
+ if (v != 16.0)
+ abort ();
+ r = 57;
+ #pragma omp atomic compare capture
+ v = x = x == 15.0f ? r + 7.0f : x;
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic capture, update, compare seq_cst fail(acquire)
+ { v = x; x = x == 73.0L - r ? 12.0f : x; }
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic update, compare, capture
+ { x = x == 69.0 - r ? 6.0f : x; v = x; }
+ if (v != 6.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ #pragma omp atomic compare
+ if (x > 8.0f) { x = 8.0f; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ #pragma omp atomic compare
+ if (x > 4.0) { x = 4.0; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 4.0f)
+ abort ();
+ #pragma omp atomic compare capture
+ { if (x < 8.0f) { x = 8.0f; } v = x; }
+ if (v != 8.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 8.0f)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; if (x < 12.0f) { x = 12.0f; } }
+ if (v != 8.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic capture compare
+ { v = x; if (x < 4.0L) { x = 4.0L; } }
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic compare
+ if (x == 12.0f) { x = 16.0L; }
+ #pragma omp atomic read
+ v = x;
+ if (v != 16.0f)
+ abort ();
+ r = 57.0;
+ #pragma omp atomic compare capture
+ { if (x == 15.0f) { x = r + 7.0f; } v = x; }
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic capture, update, compare seq_cst fail(acquire)
+ { v = x; if (x == 73.0L - r) { x = 12.0L; } }
+ if (v != 16.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12.0f)
+ abort ();
+ #pragma omp atomic update, compare, capture
+ { if (x == 69.0L - r) { x = 6.0; } v = x; }
+ if (v != 6.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ v = 24;
+ #pragma omp atomic compare capture
+ if (x == 12.0f) { x = 16.0f; } else { v = x; }
+ if (v != 6.0f)
+ abort ();
+ v = 32.0f;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ v = 147.0f;
+ #pragma omp atomic capture compare
+ if (x == 6.0f) { x = 57.0f; } else { v = x; }
+ if (v != 147.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 57.0f)
+ abort ();
+ #pragma omp atomic update, capture, compare, weak, seq_cst, fail (relaxed)
+ { r = x == 137.0f; if (r) { x = 174.0f; } }
+ if (r)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 57.0f)
+ abort ();
+ #pragma omp atomic compare capture fail (relaxed)
+ { r = x == 57.0f; if (r) { x = 6.0f; } }
+ if (r != 1)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ v = -5.0f;
+ #pragma omp atomic capture compare
+ { r = x == 17.0L; if (r) { x = 25.0; } else { v = x; } }
+ if (r || v != 6.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 6.0f)
+ abort ();
+ v = 15.0f;
+ #pragma omp atomic capture compare
+ { r = x == 6.0f; if (r) { x = 23.0f; } else { v = x; } }
+ if (r != 1 || v != 15.0f)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 23.0f)
+ abort ();
+ return 0;
+}
--- libgomp/testsuite/libgomp.c-c++-common/atomic-21.c.jj 2021-09-10 14:27:19.051805671 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/atomic-21.c 2021-09-10 15:05:47.316510552 +0200
@@ -0,0 +1,49 @@
+// { dg-do run { target c } }
+
+double d;
+long double ld;
+
+int
+main ()
+{
+ double e = __builtin_copysign (0.0, -1.0), v;
+ long double le = __builtin_copysignl (0.0L, -1.0L), lv;
+ if (__builtin_memcmp (&d, &e, sizeof (d)) != 0)
+ {
+ /* Verify == comparison for atomics is done as with memcmp. */
+ #pragma omp atomic compare
+ d = d == e ? 5.0 : d;
+ #pragma omp atomic read
+ v = d;
+ if (v != 0.0)
+ __builtin_abort ();
+ #pragma omp atomic compare
+ d = d == 0.0 ? 5.0 : d;
+ #pragma omp atomic read
+ v = d;
+ if (v != 5.0)
+ __builtin_abort ();
+ }
+ if (__builtin_memcmp (&ld, &le, sizeof (ld)) != 0)
+ {
+ __builtin_memset (&ld, 0xff, sizeof (ld));
+ #pragma omp atomic write
+ ld = 0.0L;
+ __asm volatile ("" : : "g" (&ld) : "memory");
+ /* Verify == comparison for atomics is done as with memcmp
+ with __builtin_clear_padding if needed. */
+ #pragma omp atomic compare
+ ld = ld == le ? 5.0L : ld;
+ #pragma omp atomic read
+ lv = ld;
+ if (lv != 0.0L)
+ __builtin_abort ();
+ #pragma omp atomic compare
+ ld = ld == 0.0L ? 5.0L : ld;
+ #pragma omp atomic read
+ lv = ld;
+ if (lv != 5.0L)
+ __builtin_abort ();
+ }
+ return 0;
+}
Jakub
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: openmp: Implement OpenMP 5.1 atomics, so far for C only
2021-09-10 18:46 openmp: Implement OpenMP 5.1 atomics, so far for C only Jakub Jelinek
@ 2021-09-13 11:57 ` Christophe Lyon
2021-09-13 14:40 ` Jakub Jelinek
0 siblings, 1 reply; 4+ messages in thread
From: Christophe Lyon @ 2021-09-13 11:57 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: GCC Patches, Tobias Burnus
On Fri, Sep 10, 2021 at 8:47 PM Jakub Jelinek via Gcc-patches <
gcc-patches@gcc.gnu.org> wrote:
> Hi!
>
> 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.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.
>
> C++ support will follow next week hopefully. Various new tests in
> c-c++-common are now with { target c }, that is temporary until the C++
> support is there.
>
> 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.
>
> --- gcc/tree-core.h.jj 2021-09-09 10:40:20.116260919 +0200
> +++ gcc/tree-core.h 2021-09-09 10:41:42.631084540 +0200
> @@ -583,8 +583,17 @@ enum omp_memory_order {
> OMP_MEMORY_ORDER_ACQUIRE,
> OMP_MEMORY_ORDER_RELEASE,
> OMP_MEMORY_ORDER_ACQ_REL,
> - OMP_MEMORY_ORDER_SEQ_CST
> + OMP_MEMORY_ORDER_SEQ_CST,
> + OMP_MEMORY_ORDER_MASK = 7,
> + OMP_FAIL_MEMORY_ORDER_UNSPECIFIED = OMP_MEMORY_ORDER_UNSPECIFIED * 8,
> + OMP_FAIL_MEMORY_ORDER_RELAXED = OMP_MEMORY_ORDER_RELAXED * 8,
> + OMP_FAIL_MEMORY_ORDER_ACQUIRE = OMP_MEMORY_ORDER_ACQUIRE * 8,
> + OMP_FAIL_MEMORY_ORDER_RELEASE = OMP_MEMORY_ORDER_RELEASE * 8,
> + OMP_FAIL_MEMORY_ORDER_ACQ_REL = OMP_MEMORY_ORDER_ACQ_REL * 8,
> + OMP_FAIL_MEMORY_ORDER_SEQ_CST = OMP_MEMORY_ORDER_SEQ_CST * 8,
> + OMP_FAIL_MEMORY_ORDER_MASK = OMP_MEMORY_ORDER_MASK * 8
> };
> +#define OMP_FAIL_MEMORY_ORDER_SHIFT 3
>
> /* There is a TYPE_QUAL value for each type qualifier. They can be
> combined by bitwise-or to form the complete set of qualifiers for a
> --- gcc/gimple-pretty-print.c.jj 2021-09-09 10:40:20.032262117 +0200
> +++ gcc/gimple-pretty-print.c 2021-09-09 10:41:42.625084625 +0200
> @@ -2563,6 +2563,8 @@ dump_gimple_omp_atomic_load (pretty_prin
> gimple_omp_atomic_memory_order (gs));
> if (gimple_omp_atomic_need_value_p (gs))
> pp_string (buffer, " [needed]");
> + if (gimple_omp_atomic_weak_p (gs))
> + pp_string (buffer, " [weak]");
> newline_and_indent (buffer, spc + 2);
> dump_generic_node (buffer, gimple_omp_atomic_load_lhs (gs),
> spc, flags, false);
> @@ -2597,6 +2599,8 @@ dump_gimple_omp_atomic_store (pretty_pri
> pp_space (buffer);
> if (gimple_omp_atomic_need_value_p (gs))
> pp_string (buffer, "[needed] ");
> + if (gimple_omp_atomic_weak_p (gs))
> + pp_string (buffer, "[weak] ");
> pp_left_paren (buffer);
> dump_generic_node (buffer, gimple_omp_atomic_store_val (gs),
> spc, flags, false);
> --- gcc/gimple.h.jj 2021-09-09 10:40:20.041261988 +0200
> +++ gcc/gimple.h 2021-09-09 10:41:42.625084625 +0200
> @@ -194,8 +194,9 @@ enum gf_mask {
> GF_OMP_RETURN_NOWAIT = 1 << 0,
>
> GF_OMP_SECTION_LAST = 1 << 0,
> - GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 3) - 1,
> - GF_OMP_ATOMIC_NEED_VALUE = 1 << 3,
> + GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 6) - 1,
> + GF_OMP_ATOMIC_NEED_VALUE = 1 << 6,
> + GF_OMP_ATOMIC_WEAK = 1 << 7,
> GF_PREDICT_TAKEN = 1 << 15
> };
>
> @@ -2446,6 +2447,29 @@ gimple_omp_atomic_set_need_value (gimple
> }
>
>
> +/* Return true if OMP atomic load/store statement G has the
> + GF_OMP_ATOMIC_WEAK flag set. */
> +
> +static inline bool
> +gimple_omp_atomic_weak_p (const gimple *g)
> +{
> + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
> + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
> + return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_WEAK) != 0;
> +}
> +
> +
> +/* Set the GF_OMP_ATOMIC_WEAK flag on G. */
> +
> +static inline void
> +gimple_omp_atomic_set_weak (gimple *g)
> +{
> + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
> + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
> + g->subcode |= GF_OMP_ATOMIC_WEAK;
> +}
> +
> +
> /* Return the memory order of the OMP atomic load/store statement G. */
>
> static inline enum omp_memory_order
> --- gcc/tree.h.jj 2021-09-09 10:40:20.132260691 +0200
> +++ gcc/tree.h 2021-09-09 10:41:42.626084611 +0200
> @@ -1529,6 +1529,11 @@ class auto_suppress_location_wrappers
> (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
>
> OMP_ATOMIC_CAPTURE_NEW)->base.u.omp_atomic_memory_order)
>
> +/* Weak clause on OMP_ATOMIC*. */
> +#define OMP_ATOMIC_WEAK(NODE) \
> + (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
> + OMP_ATOMIC_CAPTURE_NEW)->base.public_flag)
> +
> /* True on a PRIVATE clause if its decl is kept around for debugging
> information only and its DECL_VALUE_EXPR is supposed to point
> to what it has been remapped to. */
> --- gcc/tree-pretty-print.c.jj 2021-09-09 10:40:20.131260705 +0200
> +++ gcc/tree-pretty-print.c 2021-09-09 10:41:42.626084611 +0200
> @@ -1492,7 +1492,7 @@ dump_block_node (pretty_printer *pp, tre
> void
> dump_omp_atomic_memory_order (pretty_printer *pp, enum omp_memory_order
> mo)
> {
> - switch (mo)
> + switch (mo & OMP_MEMORY_ORDER_MASK)
> {
> case OMP_MEMORY_ORDER_RELAXED:
> pp_string (pp, " relaxed");
> @@ -1514,6 +1514,22 @@ dump_omp_atomic_memory_order (pretty_pri
> default:
> gcc_unreachable ();
> }
> + switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
> + {
> + case OMP_FAIL_MEMORY_ORDER_RELAXED:
> + pp_string (pp, " fail(relaxed)");
> + break;
> + case OMP_FAIL_MEMORY_ORDER_SEQ_CST:
> + pp_string (pp, " fail(seq_cst)");
> + break;
> + case OMP_FAIL_MEMORY_ORDER_ACQUIRE:
> + pp_string (pp, " fail(acquire)");
> + break;
> + case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
> + break;
> + default:
> + gcc_unreachable ();
> + }
> }
>
> /* Helper to dump a MEM_REF node. */
> @@ -3629,6 +3645,8 @@ dump_generic_node (pretty_printer *pp, t
>
> case OMP_ATOMIC:
> pp_string (pp, "#pragma omp atomic");
> + if (OMP_ATOMIC_WEAK (node))
> + pp_string (pp, " weak");
> dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node));
> newline_and_indent (pp, spc + 2);
> dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false);
> @@ -3649,6 +3667,8 @@ dump_generic_node (pretty_printer *pp, t
> case OMP_ATOMIC_CAPTURE_OLD:
> case OMP_ATOMIC_CAPTURE_NEW:
> pp_string (pp, "#pragma omp atomic capture");
> + if (OMP_ATOMIC_WEAK (node))
> + pp_string (pp, " weak");
> dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node));
> newline_and_indent (pp, spc + 2);
> dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false);
> --- gcc/gimplify.c.jj 2021-09-09 10:40:20.057261760 +0200
> +++ gcc/gimplify.c 2021-09-10 18:29:35.243673591 +0200
> @@ -13725,14 +13725,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))
> @@ -13744,11 +13745,11 @@ goa_stabilize_expr (tree *expr_p, gimple
> 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))
> @@ -13760,36 +13761,131 @@ goa_stabilize_expr (tree *expr_p, gimple
> 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;
> }
> @@ -13809,9 +13905,12 @@ gimplify_omp_atomic (tree *expr_p, gimpl
> 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)
> @@ -13825,11 +13924,14 @@ gimplify_omp_atomic (tree *expr_p, gimpl
> {
> /* 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)
> @@ -13838,17 +13940,25 @@ gimplify_omp_atomic (tree *expr_p, gimpl
> 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;
> }
>
> @@ -13856,6 +13966,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl
> 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))
> {
> --- gcc/omp-expand.c.jj 2021-09-09 10:40:20.072261546 +0200
> +++ gcc/omp-expand.c 2021-09-10 15:05:47.315510567 +0200
> @@ -8487,22 +8487,58 @@ expand_omp_synch (struct omp_region *reg
> }
> }
>
> +/* Translate enum omp_memory_order to enum memmodel for the embedded
> + fail clause in there. */
> +
> +static enum memmodel
> +omp_memory_order_to_fail_memmodel (enum omp_memory_order mo)
> +{
> + switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
> + {
> + case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
> + switch (mo & OMP_MEMORY_ORDER_MASK)
> + {
> + case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
> + case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
> + case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELAXED;
> + case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQUIRE;
> + case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
> + default: break;
> + }
> + gcc_unreachable ();
> + case OMP_FAIL_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
> + case OMP_FAIL_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
> + case OMP_FAIL_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
> + default: gcc_unreachable ();
> + }
> +}
> +
> /* Translate enum omp_memory_order to enum memmodel. The two enums
> are using different numbers so that OMP_MEMORY_ORDER_UNSPECIFIED
> - is 0. */
> + is 0 and omp_memory_order has the fail mode encoded in it too. */
>
> static enum memmodel
> omp_memory_order_to_memmodel (enum omp_memory_order mo)
> {
> - switch (mo)
> + enum memmodel ret, fail_ret;
> + switch (mo & OMP_MEMORY_ORDER_MASK)
> {
> - case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED;
> - case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE;
> - case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELEASE;
> - case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQ_REL;
> - case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST;
> + case OMP_MEMORY_ORDER_RELAXED: ret = MEMMODEL_RELAXED; break;
> + case OMP_MEMORY_ORDER_ACQUIRE: ret = MEMMODEL_ACQUIRE; break;
> + case OMP_MEMORY_ORDER_RELEASE: ret = MEMMODEL_RELEASE; break;
> + case OMP_MEMORY_ORDER_ACQ_REL: ret = MEMMODEL_ACQ_REL; break;
> + case OMP_MEMORY_ORDER_SEQ_CST: ret = MEMMODEL_SEQ_CST; break;
> default: gcc_unreachable ();
> }
> + /* If we drop the -Winvalid-memory-model warning for C++17 P0418R2,
> + we can just return ret here unconditionally. Otherwise, work around
> + it here and make sure fail memmodel is not stronger. */
> + if ((mo & OMP_FAIL_MEMORY_ORDER_MASK) ==
> OMP_FAIL_MEMORY_ORDER_UNSPECIFIED)
> + return ret;
> + fail_ret = omp_memory_order_to_fail_memmodel (mo);
> + if (fail_ret > ret)
> + return fail_ret;
> + return ret;
> }
>
> /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
> @@ -8782,6 +8818,261 @@ expand_omp_atomic_fetch_op (basic_block
> return true;
> }
>
> +/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
> + compare and exchange as an ATOMIC_COMPARE_EXCHANGE internal function.
> + Returns false if the expression is not of the proper form. */
> +
> +static bool
> +expand_omp_atomic_cas (basic_block load_bb, tree addr,
> + tree loaded_val, tree stored_val, int index)
> +{
> + /* We expect to find the following sequences:
> +
> + load_bb:
> + GIMPLE_OMP_ATOMIC_LOAD (tmp, mem)
> +
> + store_bb:
> + val = tmp == e ? d : tmp;
> + GIMPLE_OMP_ATOMIC_STORE (val)
> +
> + or in store_bb instead:
> + tmp2 = tmp == e;
> + val = tmp2 ? d : tmp;
> + GIMPLE_OMP_ATOMIC_STORE (val)
> +
> + or:
> + tmp3 = VIEW_CONVERT_EXPR<integral_type>(tmp);
> + val = e == tmp3 ? d : tmp;
> + GIMPLE_OMP_ATOMIC_STORE (val)
> +
> + etc. */
> +
> +
> + basic_block store_bb = single_succ (load_bb);
> + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (store_bb);
> + gimple *store_stmt = gsi_stmt (gsi);
> + if (!store_stmt || gimple_code (store_stmt) != GIMPLE_OMP_ATOMIC_STORE)
> + return false;
> + gsi_prev_nondebug (&gsi);
> + if (gsi_end_p (gsi))
> + return false;
> + gimple *condexpr_stmt = gsi_stmt (gsi);
> + if (!is_gimple_assign (condexpr_stmt)
> + || gimple_assign_rhs_code (condexpr_stmt) != COND_EXPR)
> + return false;
> + if (!operand_equal_p (gimple_assign_lhs (condexpr_stmt), stored_val, 0))
> + return false;
> + gimple *cond_stmt = NULL;
> + gimple *vce_stmt = NULL;
> + gsi_prev_nondebug (&gsi);
> + if (!gsi_end_p (gsi))
> + {
> + cond_stmt = gsi_stmt (gsi);
> + if (!is_gimple_assign (cond_stmt))
> + return false;
> + if (gimple_assign_rhs_code (cond_stmt) == EQ_EXPR)
> + {
> + gsi_prev_nondebug (&gsi);
> + if (!gsi_end_p (gsi))
> + {
> + vce_stmt = gsi_stmt (gsi);
> + if (!is_gimple_assign (vce_stmt)
> + || gimple_assign_rhs_code (vce_stmt) !=
> VIEW_CONVERT_EXPR)
> + return false;
> + }
> + }
> + else if (gimple_assign_rhs_code (cond_stmt) == VIEW_CONVERT_EXPR)
> + std::swap (vce_stmt, cond_stmt);
> + else
> + return false;
> + if (vce_stmt)
> + {
> + tree vce_rhs = gimple_assign_rhs1 (vce_stmt);
> + if (TREE_CODE (vce_rhs) != VIEW_CONVERT_EXPR
> + || !operand_equal_p (TREE_OPERAND (vce_rhs, 0), loaded_val))
> + return false;
> + if (!INTEGRAL_TYPE_P (TREE_TYPE (vce_rhs))
> + || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (loaded_val))
> + || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vce_rhs)),
> + TYPE_SIZE (TREE_TYPE (loaded_val))))
> + return false;
> + gsi_prev_nondebug (&gsi);
> + if (!gsi_end_p (gsi))
> + return false;
> + }
> + }
> + tree cond = gimple_assign_rhs1 (condexpr_stmt);
> + tree cond_op1, cond_op2;
> + if (cond_stmt)
> + {
> + if (!operand_equal_p (cond, gimple_assign_lhs (cond_stmt)))
> + return false;
> + cond_op1 = gimple_assign_rhs1 (cond_stmt);
> + cond_op2 = gimple_assign_rhs2 (cond_stmt);
> + }
> + else if (TREE_CODE (cond) != EQ_EXPR && TREE_CODE (cond) != NE_EXPR)
> + return false;
> + else
> + {
> + cond_op1 = TREE_OPERAND (cond, 0);
> + cond_op2 = TREE_OPERAND (cond, 1);
> + }
> + tree d;
> + if (TREE_CODE (cond) == NE_EXPR)
> + {
> + if (!operand_equal_p (gimple_assign_rhs2 (condexpr_stmt),
> loaded_val))
> + return false;
> + d = gimple_assign_rhs3 (condexpr_stmt);
> + }
> + else if (!operand_equal_p (gimple_assign_rhs3 (condexpr_stmt),
> loaded_val))
> + return false;
> + else
> + d = gimple_assign_rhs2 (condexpr_stmt);
> + tree e = vce_stmt ? gimple_assign_lhs (vce_stmt) : loaded_val;
> + if (operand_equal_p (e, cond_op1))
> + e = cond_op2;
> + else if (operand_equal_p (e, cond_op2))
> + e = cond_op1;
> + else
> + return false;
> +
> + location_t loc = gimple_location (store_stmt);
> + gimple *load_stmt = last_stmt (load_bb);
> + bool need_new = gimple_omp_atomic_need_value_p (store_stmt);
> + bool need_old = gimple_omp_atomic_need_value_p (load_stmt);
> + bool weak = gimple_omp_atomic_weak_p (load_stmt);
> + enum omp_memory_order omo = gimple_omp_atomic_memory_order (load_stmt);
> + tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo));
> + tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel
> (omo));
> + gcc_checking_assert (!need_old || !need_new);
> +
> + enum built_in_function fncode
> + = (enum built_in_function) ((int) BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
> + + index + 1);
> + tree cmpxchg = builtin_decl_explicit (fncode);
> + if (cmpxchg == NULL_TREE)
> + return false;
> + tree itype = TREE_TYPE (TREE_TYPE (cmpxchg));
> +
> + if (!can_compare_and_swap_p (TYPE_MODE (itype), true)
> + || !can_atomic_load_p (TYPE_MODE (itype)))
> + return false;
> +
> + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (loaded_val));
> + if (SCALAR_FLOAT_TYPE_P (type) && !vce_stmt)
> + return false;
> +
> + gsi = gsi_for_stmt (store_stmt);
> + if (!useless_type_conversion_p (itype, TREE_TYPE (e)))
> + {
> + tree ne = create_tmp_reg (itype);
> + gimple *g = gimple_build_assign (ne, NOP_EXPR, e);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + e = ne;
> + }
> + if (!useless_type_conversion_p (itype, TREE_TYPE (d)))
> + {
> + tree nd = create_tmp_reg (itype);
> + enum tree_code code;
> + if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (d)))
> + {
> + code = VIEW_CONVERT_EXPR;
> + d = build1 (VIEW_CONVERT_EXPR, itype, d);
> + }
> + else
> + code = NOP_EXPR;
> + gimple *g = gimple_build_assign (nd, code, d);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + d = nd;
> + }
> +
> + tree ctype = build_complex_type (itype);
> + int flag = int_size_in_bytes (itype) + (weak ? 256 : 0);
> + gimple *g
> + = gimple_build_call_internal (IFN_ATOMIC_COMPARE_EXCHANGE, 6, addr,
> e, d,
> + build_int_cst (integer_type_node, flag),
> + mo, fmo);
> + tree cres = create_tmp_reg (ctype);
> + gimple_call_set_lhs (g, cres);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +
> + if (cond_stmt || need_old || need_new)
> + {
> + tree im = create_tmp_reg (itype);
> + g = gimple_build_assign (im, IMAGPART_EXPR,
> + build1 (IMAGPART_EXPR, itype, cres));
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +
> + tree re = NULL_TREE;
> + if (need_old || need_new)
> + {
> + re = create_tmp_reg (itype);
> + g = gimple_build_assign (re, REALPART_EXPR,
> + build1 (REALPART_EXPR, itype, cres));
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + }
> +
> + if (cond_stmt)
> + {
> + g = gimple_build_assign (gimple_assign_lhs (cond_stmt),
> + NOP_EXPR, im);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + }
> + else if (need_new)
> + {
> + g = gimple_build_assign (create_tmp_reg (itype), COND_EXPR,
> + build2 (NE_EXPR, boolean_type_node,
> + im, build_zero_cst (itype)),
> + d, re);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + re = gimple_assign_lhs (g);
> + }
> +
> + if (need_old || need_new)
> + {
> + tree v = need_old ? loaded_val : stored_val;
> + enum tree_code code;
> + if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (v)))
> + {
> + code = VIEW_CONVERT_EXPR;
> + re = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (v), re);
> + }
> + else if (!useless_type_conversion_p (TREE_TYPE (v), itype))
> + code = NOP_EXPR;
> + else
> + code = TREE_CODE (re);
> + g = gimple_build_assign (v, code, re);
> + gimple_set_location (g, loc);
> + gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> + }
> + }
> +
> + gsi_remove (&gsi, true);
> + gsi = gsi_for_stmt (load_stmt);
> + gsi_remove (&gsi, true);
> + gsi = gsi_for_stmt (condexpr_stmt);
> + gsi_remove (&gsi, true);
> + if (cond_stmt)
> + {
> + gsi = gsi_for_stmt (cond_stmt);
> + gsi_remove (&gsi, true);
> + }
> + if (vce_stmt)
> + {
> + gsi = gsi_for_stmt (vce_stmt);
> + gsi_remove (&gsi, true);
> + }
> +
> + return true;
> +}
> +
> /* A subroutine of expand_omp_atomic. Implement the atomic operation as:
>
> oldval = *addr;
> @@ -8825,13 +9116,8 @@ expand_omp_atomic_pipeline (basic_block
> gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
> location_t loc = gimple_location (gsi_stmt (si));
> enum omp_memory_order omo = gimple_omp_atomic_memory_order (gsi_stmt
> (si));
> - enum memmodel imo = omp_memory_order_to_memmodel (omo);
> - tree mo = build_int_cst (NULL, imo);
> - if (imo == MEMMODEL_RELEASE)
> - imo = MEMMODEL_RELAXED;
> - else if (imo == MEMMODEL_ACQ_REL)
> - imo = MEMMODEL_ACQUIRE;
> - tree fmo = build_int_cst (NULL, imo);
> + tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo));
> + tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel
> (omo));
>
> /* 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
> @@ -9114,6 +9400,13 @@ expand_omp_atomic (struct omp_region *re
> loaded_val, stored_val,
> index))
> return;
>
> + /* When possible, use ATOMIC_COMPARE_EXCHANGE ifn without a
> loop. */
> + if (store_bb == single_succ (load_bb)
> + && !gimple_in_ssa_p (cfun)
> + && expand_omp_atomic_cas (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. */
> if (expand_omp_atomic_pipeline (load_bb, store_bb, addr,
> --- gcc/c-family/c-common.h.jj 2021-09-09 10:40:19.928263599 +0200
> +++ gcc/c-family/c-common.h 2021-09-09 10:42:11.865667757 +0200
> @@ -1223,8 +1223,8 @@ extern tree c_finish_omp_critical (locat
> extern tree c_finish_omp_ordered (location_t, tree, tree);
> extern void c_finish_omp_barrier (location_t);
> extern tree c_finish_omp_atomic (location_t, enum tree_code, enum
> tree_code,
> - tree, tree, tree, tree, tree, bool,
> - enum omp_memory_order, bool = false);
> + tree, tree, tree, tree, tree, tree, bool,
> + enum omp_memory_order, bool, bool =
> false);
> extern bool c_omp_depend_t_p (tree);
> extern void c_finish_omp_depobj (location_t, tree, enum
> omp_clause_depend_kind,
> tree);
> --- gcc/c-family/c-omp.c.jj 2021-09-09 10:40:19.937263471 +0200
> +++ gcc/c-family/c-omp.c 2021-09-10 17:59:26.574281430 +0200
> @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.
> #include "gimplify.h"
> #include "langhooks.h"
> #include "bitmap.h"
> +#include "gimple-fold.h"
>
>
> /* Complete a #pragma oacc wait construct. LOC is the location of
> @@ -215,15 +216,17 @@ c_finish_omp_taskyield (location_t loc)
> tree
> c_finish_omp_atomic (location_t loc, enum tree_code code,
> enum tree_code opcode, tree lhs, tree rhs,
> - tree v, tree lhs1, tree rhs1, bool swapped,
> - enum omp_memory_order memory_order, bool test)
> + tree v, tree lhs1, tree rhs1, tree r, bool swapped,
> + enum omp_memory_order memory_order, bool weak,
> + bool test)
> {
> - tree x, type, addr, pre = NULL_TREE;
> + tree x, type, addr, pre = NULL_TREE, rtmp = NULL_TREE, vtmp = NULL_TREE;
> HOST_WIDE_INT bitpos = 0, bitsize = 0;
> + enum tree_code orig_opcode = opcode;
>
> if (lhs == error_mark_node || rhs == error_mark_node
> || v == error_mark_node || lhs1 == error_mark_node
> - || rhs1 == error_mark_node)
> + || rhs1 == error_mark_node || r == error_mark_node)
> return error_mark_node;
>
> /* ??? According to one reading of the OpenMP spec, complex type are
> @@ -243,6 +246,12 @@ c_finish_omp_atomic (location_t loc, enu
> error_at (loc, "%<_Atomic%> expression in %<#pragma omp atomic%>");
> return error_mark_node;
> }
> + if (r && r != void_list_node && !INTEGRAL_TYPE_P (TREE_TYPE (r)))
> + {
> + error_at (loc, "%<#pragma omp atomic compare capture%> with
> non-integral "
> + "comparison result");
> + return error_mark_node;
> + }
>
> if (opcode == RDIV_EXPR)
> opcode = TRUNC_DIV_EXPR;
> @@ -299,6 +308,7 @@ c_finish_omp_atomic (location_t loc, enu
> x = build1 (OMP_ATOMIC_READ, type, addr);
> SET_EXPR_LOCATION (x, loc);
> OMP_ATOMIC_MEMORY_ORDER (x) = memory_order;
> + gcc_assert (!weak);
> if (blhs)
> x = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), x,
> bitsize_int (bitsize), bitsize_int (bitpos));
> @@ -313,12 +323,29 @@ c_finish_omp_atomic (location_t loc, enu
> {
> lhs = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), lhs,
> bitsize_int (bitsize), bitsize_int (bitpos));
> - if (swapped)
> + if (opcode == COND_EXPR)
> + {
> + bool save = in_late_binary_op;
> + in_late_binary_op = true;
> + std::swap (rhs, rhs1);
> + rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true);
> + in_late_binary_op = save;
> + }
> + else if (swapped)
> rhs = build_binary_op (loc, opcode, rhs, lhs, true);
> else if (opcode != NOP_EXPR)
> rhs = build_binary_op (loc, opcode, lhs, rhs, true);
> opcode = NOP_EXPR;
> }
> + else if (opcode == COND_EXPR)
> + {
> + bool save = in_late_binary_op;
> + in_late_binary_op = true;
> + std::swap (rhs, rhs1);
> + rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true);
> + in_late_binary_op = save;
> + opcode = NOP_EXPR;
> + }
> else if (swapped)
> {
> rhs = build_binary_op (loc, opcode, rhs, lhs, true);
> @@ -343,6 +370,100 @@ c_finish_omp_atomic (location_t loc, enu
> if (blhs)
> rhs = build3_loc (loc, BIT_INSERT_EXPR, type, new_lhs,
> rhs, bitsize_int (bitpos));
> + if (orig_opcode == COND_EXPR)
> + {
> + if (error_operand_p (rhs1))
> + return error_mark_node;
> + gcc_assert (TREE_CODE (rhs1) == EQ_EXPR);
> + tree cmptype = TREE_TYPE (TREE_OPERAND (rhs1, 0));
> + if (SCALAR_FLOAT_TYPE_P (cmptype))
> + {
> + bool clear_padding = false;
> + if (BITS_PER_UNIT == 8 && CHAR_BIT == 8)
> + {
> + HOST_WIDE_INT sz = int_size_in_bytes (cmptype), i;
> + gcc_assert (sz > 0);
> + unsigned char *buf = XALLOCAVEC (unsigned char, sz);
> + memset (buf, ~0, sz);
> + clear_type_padding_in_mask (cmptype, buf);
> + for (i = 0; i < sz; i++)
> + if (buf[i] != (unsigned char) ~0)
> + {
> + clear_padding = true;
> + break;
> + }
> + }
> + tree inttype = NULL_TREE;
> + if (!clear_padding && tree_fits_uhwi_p (TYPE_SIZE (cmptype)))
> + {
> + HOST_WIDE_INT prec = tree_to_uhwi (TYPE_SIZE (cmptype));
> + inttype = c_common_type_for_size (prec, 1);
> + if (inttype
> + && (!tree_int_cst_equal (TYPE_SIZE (cmptype),
> + TYPE_SIZE (inttype))
> + || TYPE_PRECISION (inttype) != prec))
> + inttype = NULL_TREE;
> + }
> + if (inttype)
> + {
> + TREE_OPERAND (rhs1, 0)
> + = build1_loc (loc, VIEW_CONVERT_EXPR, inttype,
> + TREE_OPERAND (rhs1, 0));
> + TREE_OPERAND (rhs1, 1)
> + = build1_loc (loc, VIEW_CONVERT_EXPR, inttype,
> + TREE_OPERAND (rhs1, 1));
> + }
> + else
> + {
> + tree pcmptype = build_pointer_type (cmptype);
> + tree tmp1 = create_tmp_var_raw (cmptype);
> + TREE_ADDRESSABLE (tmp1) = 1;
> + DECL_CONTEXT (tmp1) = current_function_decl;
> + tmp1 = build4 (TARGET_EXPR, cmptype, tmp1,
> + TREE_OPERAND (rhs1, 0), NULL, NULL);
> + tmp1 = build1 (ADDR_EXPR, pcmptype, tmp1);
> + tree tmp2 = create_tmp_var_raw (cmptype);
> + TREE_ADDRESSABLE (tmp2) = 1;
> + DECL_CONTEXT (tmp2) = current_function_decl;
> + tmp2 = build4 (TARGET_EXPR, cmptype, tmp2,
> + TREE_OPERAND (rhs1, 1), NULL, NULL);
> + tmp2 = build1 (ADDR_EXPR, pcmptype, tmp2);
> + tree fndecl = builtin_decl_explicit (BUILT_IN_MEMCMP);
> + rhs1 = build_call_expr_loc (loc, fndecl, 3, tmp1, tmp2,
> + TYPE_SIZE_UNIT (cmptype));
> + rhs1 = build2 (EQ_EXPR, boolean_type_node, rhs1,
> + integer_zero_node);
> + if (clear_padding)
> + {
> + fndecl = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING);
> + tree cp1 = build_call_expr_loc (loc, fndecl, 1, tmp1);
> + tree cp2 = build_call_expr_loc (loc, fndecl, 1, tmp2);
> + rhs1 = omit_two_operands_loc (loc, boolean_type_node,
> + rhs1, cp2, cp1);
> + }
> + }
> + }
> + if (r)
> + {
> + tree var = create_tmp_var (boolean_type_node);
> + DECL_CONTEXT (var) = current_function_decl;
> + rtmp = build4 (TARGET_EXPR, boolean_type_node, var,
> + NULL, NULL, NULL);
> + save = in_late_binary_op;
> + in_late_binary_op = true;
> + x = build_modify_expr (loc, var, NULL_TREE, NOP_EXPR,
> + loc, rhs1, NULL_TREE);
> + in_late_binary_op = save;
> + if (x == error_mark_node)
> + return error_mark_node;
> + gcc_assert (TREE_CODE (x) == MODIFY_EXPR
> + && TREE_OPERAND (x, 0) == var);
> + TREE_OPERAND (x, 0) = rtmp;
> + rhs1 = omit_one_operand_loc (loc, boolean_type_node, x, rtmp);
> + }
> + rhs = build3_loc (loc, COND_EXPR, type, rhs1, rhs, new_lhs);
> + rhs1 = NULL_TREE;
> + }
>
> /* Punt the actual generation of atomic operations to common code. */
> if (code == OMP_ATOMIC)
> @@ -350,6 +471,7 @@ c_finish_omp_atomic (location_t loc, enu
> x = build2 (code, type, addr, rhs);
> SET_EXPR_LOCATION (x, loc);
> OMP_ATOMIC_MEMORY_ORDER (x) = memory_order;
> + OMP_ATOMIC_WEAK (x) = weak;
>
> /* Generally it is hard to prove lhs1 and lhs are the same memory
> location, just diagnose different variables. */
> @@ -412,8 +534,25 @@ c_finish_omp_atomic (location_t loc, enu
> bitsize_int (bitsize), bitsize_int (bitpos));
> type = TREE_TYPE (blhs);
> }
> - x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
> + if (r)
> + {
> + vtmp = create_tmp_var (TREE_TYPE (x));
> + DECL_CONTEXT (vtmp) = current_function_decl;
> + }
> + else
> + vtmp = v;
> + x = build_modify_expr (loc, vtmp, NULL_TREE, NOP_EXPR,
> loc, x, NULL_TREE);
> + if (x == error_mark_node)
> + return error_mark_node;
> + if (r)
> + {
> + vtmp = build4 (TARGET_EXPR, boolean_type_node, vtmp,
> + NULL, NULL, NULL);
> + gcc_assert (TREE_CODE (x) == MODIFY_EXPR
> + && TREE_OPERAND (x, 0) == TARGET_EXPR_SLOT (vtmp));
> + TREE_OPERAND (x, 0) = vtmp;
> + }
> if (rhs1 && rhs1 != orig_lhs)
> {
> tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, false);
> @@ -446,6 +585,28 @@ c_finish_omp_atomic (location_t loc, enu
>
> if (pre)
> x = omit_one_operand_loc (loc, type, x, pre);
> + if (r && r != void_list_node)
> + {
> + in_late_binary_op = true;
> + tree x2 = build_modify_expr (loc, r, NULL_TREE, NOP_EXPR,
> + loc, rtmp, NULL_TREE);
> + in_late_binary_op = save;
> + if (x2 == error_mark_node)
> + return error_mark_node;
> + x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x);
> + }
> + if (v && vtmp != v)
> + {
> + in_late_binary_op = true;
> + tree x2 = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
> + loc, vtmp, NULL_TREE);
> + in_late_binary_op = save;
> + if (x2 == error_mark_node)
> + return error_mark_node;
> + x2 = build3_loc (loc, COND_EXPR, void_type_node, rtmp,
> + void_node, x2);
> + x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x);
> + }
> return x;
> }
>
> --- gcc/c/c-parser.c.jj 2021-09-09 10:40:19.956263200 +0200
> +++ gcc/c/c-parser.c 2021-09-10 17:06:10.966650277 +0200
> @@ -7663,10 +7663,21 @@ c_parser_conditional_expression (c_parse
> c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
> location_t loc1 = make_location (exp1.get_start (), exp1.src_range);
> location_t loc2 = make_location (exp2.get_start (), exp2.src_range);
> - ret.value = build_conditional_expr (colon_loc, cond.value,
> - cond.original_code ==
> C_MAYBE_CONST_EXPR,
> - exp1.value, exp1.original_type, loc1,
> - exp2.value, exp2.original_type,
> loc2);
> + if (__builtin_expect (omp_atomic_lhs != NULL, 0)
> + && (TREE_CODE (cond.value) == GT_EXPR
> + || TREE_CODE (cond.value) == LT_EXPR
> + || TREE_CODE (cond.value) == EQ_EXPR)
> + && c_tree_equal (exp2.value, omp_atomic_lhs)
> + && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs)
> + || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs)))
> + ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE
> (omp_atomic_lhs),
> + cond.value, exp1.value, exp2.value);
> + else
> + ret.value
> + = build_conditional_expr (colon_loc, cond.value,
> + cond.original_code == C_MAYBE_CONST_EXPR,
> + exp1.value, exp1.original_type, loc1,
> + exp2.value, exp2.original_type, loc2);
> ret.original_code = ERROR_MARK;
> if (exp1.value == error_mark_node || exp2.value == error_mark_node)
> ret.original_type = NULL;
> @@ -7849,15 +7860,27 @@ c_parser_binary_expression (c_parser *pa
> = convert_lvalue_to_rvalue (stack[sp].loc,
> \
> stack[sp].expr, true, true);
> \
> if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1
> \
> - && c_parser_peek_token (parser)->type == CPP_SEMICOLON
> \
> - && ((1 << stack[sp].prec)
> \
> - & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 <<
> PREC_BITAND) \
> - | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT)))
> \
> + && ((c_parser_next_token_is (parser, CPP_SEMICOLON)
> \
> + && ((1 << stack[sp].prec)
> \
> + & ((1 << PREC_BITOR) | (1 << PREC_BITXOR)
> \
> + | (1 << PREC_BITAND) | (1 << PREC_SHIFT)
> \
> + | (1 << PREC_ADD) | (1 << PREC_MULT)
> \
> + | (1 << PREC_EQ))))
> \
> + || ((c_parser_next_token_is (parser, CPP_QUERY)
> \
> + || (omp_atomic_lhs == void_list_node
> \
> + && c_parser_next_token_is (parser,
> CPP_CLOSE_PAREN))) \
> + && (stack[sp].prec == PREC_REL || stack[sp].prec ==
> PREC_EQ)))\
> && stack[sp].op != TRUNC_MOD_EXPR
> \
> + && stack[sp].op != GE_EXPR
> \
> + && stack[sp].op != LE_EXPR
> \
> + && stack[sp].op != NE_EXPR
> \
> && stack[0].expr.value != error_mark_node
> \
> && stack[1].expr.value != error_mark_node
> \
> - && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs)
> \
> - || c_tree_equal (stack[1].expr.value, omp_atomic_lhs)))
> \
> + && (omp_atomic_lhs == void_list_node
> \
> + || c_tree_equal (stack[0].expr.value, omp_atomic_lhs)
> \
> + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs)
> \
> + || (stack[sp].op == EQ_EXPR
> \
> + && c_parser_peek_2nd_token (parser)->keyword == RID_IF)))
> \
> {
> \
> tree t = make_node (stack[1].op);
> \
> TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value);
> \
> @@ -17655,14 +17678,45 @@ c_parser_omp_allocate (location_t loc, c
> capture-block:
> { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x =
> expr; }
>
> - where x and v are lvalue expressions with scalar type.
> + OpenMP 5.1:
> + # pragma omp atomic compare new-line
> + conditional-update-atomic
> +
> + # pragma omp atomic compare capture new-line
> + conditional-update-capture-atomic
> +
> + conditional-update-atomic:
> + cond-expr-stmt | cond-update-stmt
> + cond-expr-stmt:
> + x = expr ordop x ? expr : x;
> + x = x ordop expr ? expr : x;
> + x = x == e ? d : x;
> + cond-update-stmt:
> + if (expr ordop x) { x = expr; }
> + if (x ordop expr) { x = expr; }
> + if (x == e) { x = d; }
> + ordop:
> + <, >
> + conditional-update-capture-atomic:
> + v = cond-expr-stmt
> + { v = x; cond-expr-stmt }
> + { cond-expr-stmt v = x; }
> + { v = x; cond-update-stmt }
> + { cond-update-stmt v = x; }
> + if (x == e) { x = d; } else { v = x; }
> + { r = x == e; if (r) { x = d; } }
> + { r = x == e; if (r) { x = d; } else { v = x; } }
> +
> + where x, r and v are lvalue expressions with scalar type,
> + expr, e and d are expressions with scalar type and e might be
> + the same as v.
>
> LOC is the location of the #pragma token. */
>
> static void
> c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc)
> {
> - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
> + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE;
> tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
> tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 =
> NULL_TREE;
> enum tree_code code = ERROR_MARK, opcode = NOP_EXPR;
> @@ -17674,6 +17728,12 @@ c_parser_omp_atomic (location_t loc, c_p
> bool non_lvalue_p;
> bool first = true;
> tree clauses = NULL_TREE;
> + bool capture = false;
> + bool compare = false;
> + bool weak = false;
> + enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED;
> + bool no_semicolon = false;
> + bool extra_scope = false;
>
> while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
> {
> @@ -17692,6 +17752,10 @@ c_parser_omp_atomic (location_t loc, c_p
> enum tree_code new_code = ERROR_MARK;
> enum omp_memory_order new_memory_order
> = OMP_MEMORY_ORDER_UNSPECIFIED;
> + bool new_capture = false;
> + bool new_compare = false;
> + bool new_weak = false;
> + enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED;
>
> if (!strcmp (p, "read"))
> new_code = OMP_ATOMIC_READ;
> @@ -17699,7 +17763,7 @@ c_parser_omp_atomic (location_t loc, c_p
> new_code = NOP_EXPR;
> else if (!strcmp (p, "update"))
> new_code = OMP_ATOMIC;
> - else if (!strcmp (p, "capture"))
> + else if (openacc && !strcmp (p, "capture"))
> new_code = OMP_ATOMIC_CAPTURE_NEW;
> else if (openacc)
> {
> @@ -17707,6 +17771,47 @@ c_parser_omp_atomic (location_t loc, c_p
> error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
> "or %<capture%> clause");
> }
> + else if (!strcmp (p, "capture"))
> + new_capture = true;
> + else if (!strcmp (p, "compare"))
> + new_compare = true;
> + else if (!strcmp (p, "weak"))
> + new_weak = true;
> + else if (!strcmp (p, "fail"))
> + {
> + matching_parens parens;
> +
> + c_parser_consume_token (parser);
> + if (!parens.require_open (parser))
> + continue;
> +
> + if (c_parser_next_token_is (parser, CPP_NAME))
> + {
> + const char *q
> + = IDENTIFIER_POINTER (c_parser_peek_token
> (parser)->value);
> +
> + if (!strcmp (q, "seq_cst"))
> + new_fail = OMP_MEMORY_ORDER_SEQ_CST;
> + else if (!strcmp (q, "acquire"))
> + new_fail = OMP_MEMORY_ORDER_ACQUIRE;
> + else if (!strcmp (q, "relaxed"))
> + new_fail = OMP_MEMORY_ORDER_RELAXED;
> + }
> +
> + if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED)
> + {
> + c_parser_consume_token (parser);
> + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
> + error_at (cloc, "too many %qs clauses", "fail");
> + else
> + fail = new_fail;
> + }
> + else
> + c_parser_error (parser, "expected %<seq_cst%>, %<acquire%>
> "
> + "or %<relaxed%>");
> + parens.skip_until_found_close (parser);
> + continue;
> + }
> else if (!strcmp (p, "seq_cst"))
> new_memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> else if (!strcmp (p, "acq_rel"))
> @@ -17727,8 +17832,9 @@ c_parser_omp_atomic (location_t loc, c_p
> {
> p = NULL;
> error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
> - "%<capture%>, %<seq_cst%>, %<acq_rel%>, "
> - "%<release%>, %<relaxed%> or %<hint%>
> clause");
> + "%<capture%>, %<compare%>, %<weak%>,
> %<fail%>, "
> + "%<seq_cst%>, %<acq_rel%>, %<release%>, "
> + "%<relaxed%> or %<hint%> clause");
> }
> if (p)
> {
> @@ -17751,6 +17857,27 @@ c_parser_omp_atomic (location_t loc, c_p
> else
> memory_order = new_memory_order;
> }
> + else if (new_capture)
> + {
> + if (capture)
> + error_at (cloc, "too many %qs clauses", "capture");
> + else
> + capture = true;
> + }
> + else if (new_compare)
> + {
> + if (compare)
> + error_at (cloc, "too many %qs clauses", "compare");
> + else
> + compare = true;
> + }
> + else if (new_weak)
> + {
> + if (weak)
> + error_at (cloc, "too many %qs clauses", "weak");
> + else
> + weak = true;
> + }
> c_parser_consume_token (parser);
> continue;
> }
> @@ -17761,6 +17888,30 @@ c_parser_omp_atomic (location_t loc, c_p
>
> if (code == ERROR_MARK)
> code = OMP_ATOMIC;
> + if (capture)
> + {
> + if (code != OMP_ATOMIC)
> + error_at (loc, "%qs clause is incompatible with %<read%> or
> %<write%> "
> + "clauses", "capture");
> + else
> + code = OMP_ATOMIC_CAPTURE_NEW;
> + }
> + if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW)
> + {
> + error_at (loc, "%qs clause is incompatible with %<read%> or
> %<write%> "
> + "clauses", "compare");
> + compare = false;
> + }
> + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare)
> + {
> + error_at (loc, "%qs clause requires %qs clause", "fail", "compare");
> + fail = OMP_MEMORY_ORDER_UNSPECIFIED;
> + }
> + if (weak && !compare)
> + {
> + error_at (loc, "%qs clause requires %qs clause", "weak", "compare");
> + weak = false;
> + }
> if (openacc)
> memory_order = OMP_MEMORY_ORDER_RELAXED;
> else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED)
> @@ -17785,7 +17936,6 @@ c_parser_omp_atomic (location_t loc, c_p
> memory_order = OMP_MEMORY_ORDER_ACQUIRE;
> break;
> case NOP_EXPR: /* atomic write */
> - case OMP_ATOMIC:
> memory_order = OMP_MEMORY_ORDER_RELEASE;
> break;
> default:
> @@ -17801,36 +17951,32 @@ c_parser_omp_atomic (location_t loc, c_p
> switch (code)
> {
> case OMP_ATOMIC_READ:
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_RELEASE)
> + if (memory_order == OMP_MEMORY_ORDER_RELEASE)
> {
> error_at (loc, "%<#pragma omp atomic read%> incompatible with "
> - "%<acq_rel%> or %<release%> clauses");
> + "%<release%> clause");
> memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> }
> + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
> + memory_order = OMP_MEMORY_ORDER_ACQUIRE;
> break;
> case NOP_EXPR: /* atomic write */
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> {
> error_at (loc, "%<#pragma omp atomic write%> incompatible with
> "
> - "%<acq_rel%> or %<acquire%> clauses");
> - memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> - }
> - break;
> - case OMP_ATOMIC:
> - /* case OMP_ATOMIC_CAPTURE_NEW: - or update to OpenMP 5.1 */
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> - {
> - error_at (loc, "%<#pragma omp atomic update%> incompatible
> with "
> - "%<acq_rel%> or %<acquire%> clauses");
> + "%<acquire%> clause");
> memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> }
> + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
> + memory_order = OMP_MEMORY_ORDER_RELEASE;
> break;
> default:
> break;
> }
> + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
> + memory_order
> + = (enum omp_memory_order) (memory_order
> + | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT));
>
> switch (code)
> {
> @@ -17879,6 +18025,9 @@ c_parser_omp_atomic (location_t loc, c_p
> c_parser_consume_token (parser);
> structured_block = true;
> }
> + else if (compare
> + && c_parser_next_token_is_keyword (parser, RID_IF))
> + break;
> else
> {
> v = c_parser_cast_expression (parser, NULL).value;
> @@ -17890,6 +18039,12 @@ c_parser_omp_atomic (location_t loc, c_p
> v = non_lvalue (v);
> if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
> goto saw_error;
> + if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
> + {
> + eloc = c_parser_peek_token (parser)->location;
> + error_at (eloc, "expected expression");
> + goto saw_error;
> + }
> }
> break;
> default:
> @@ -17899,6 +18054,179 @@ c_parser_omp_atomic (location_t loc, c_p
> /* For structured_block case we don't know yet whether
> old or new x should be captured. */
> restart:
> + if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
> + {
> + c_parser_consume_token (parser);
> +
> + matching_parens parens;
> + if (!parens.require_open (parser))
> + goto saw_error;
> + eloc = c_parser_peek_token (parser)->location;
> + c_expr cmp_expr;
> + if (r)
> + {
> + cmp_expr = c_parser_cast_expression (parser, NULL);
> + cmp_expr = default_function_array_conversion (eloc, cmp_expr);
> + }
> + else
> + cmp_expr = c_parser_binary_expression (parser, NULL,
> void_list_node);
> + parens.skip_until_found_close (parser);
> + if (cmp_expr.value == error_mark_node)
> + goto saw_error;
> + if (r)
> + {
> + if (!c_tree_equal (cmp_expr.value, unfolded_lhs))
> + goto bad_if;
> + cmp_expr.value = rhs1;
> + rhs1 = NULL_TREE;
> + gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR);
> + }
> + if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
> + ;
> + else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
> + {
> + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
> + "expected %<==%> comparison in %<if%> condition");
> + goto saw_error;
> + }
> + else if (TREE_CODE (cmp_expr.value) != GT_EXPR
> + && TREE_CODE (cmp_expr.value) != LT_EXPR)
> + {
> + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
> + "expected %<==%>, %<<%> or %<>%> comparison in %<if%> "
> + "condition");
> + goto saw_error;
> + }
> + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> + goto saw_error;
> +
> + extra_scope = true;
> + eloc = c_parser_peek_token (parser)->location;
> + expr = c_parser_cast_expression (parser, NULL);
> + lhs = expr.value;
> + expr = default_function_array_conversion (eloc, expr);
> + unfolded_lhs = expr.value;
> + lhs = c_fully_fold (lhs, false, NULL, true);
> + orig_lhs = lhs;
> + if (lhs == error_mark_node)
> + goto saw_error;
> + if (!lvalue_p (unfolded_lhs))
> + lhs = non_lvalue (lhs);
> + if (!c_parser_next_token_is (parser, CPP_EQ))
> + {
> + c_parser_error (parser, "expected %<=%>");
> + goto saw_error;
> + }
> + c_parser_consume_token (parser);
> + eloc = c_parser_peek_token (parser)->location;
> + expr = c_parser_expr_no_commas (parser, NULL);
> + rhs1 = expr.value;
> +
> + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> + goto saw_error;
> +
> + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
> + goto saw_error;
> +
> + extra_scope = false;
> + no_semicolon = true;
> +
> + if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs))
> + {
> + if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
> + {
> + opcode = COND_EXPR;
> + rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
> + false, NULL, true);
> + rhs1 = c_fully_fold (rhs1, false, NULL, true);
> + }
> + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1))
> + {
> + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
> + ? MIN_EXPR : MAX_EXPR);
> + rhs = c_fully_fold (rhs1, false, NULL, true);
> + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0),
> + false, NULL, true);
> + }
> + else
> + goto bad_if;
> + }
> + else if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
> + goto bad_if;
> + else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1),
> unfolded_lhs)
> + && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1))
> + {
> + opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
> + ? MAX_EXPR : MIN_EXPR);
> + rhs = c_fully_fold (rhs1, false, NULL, true);
> + rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
> + false, NULL, true);
> + }
> + else
> + {
> + bad_if:
> + c_parser_error (parser,
> + "invalid form of %<#pragma omp atomic
> compare%>");
> + goto saw_error;
> + }
> +
> + if (c_parser_next_token_is_keyword (parser, RID_ELSE))
> + {
> + if (code != OMP_ATOMIC_CAPTURE_NEW
> + || (structured_block && r == NULL_TREE)
> + || TREE_CODE (cmp_expr.value) != EQ_EXPR)
> + {
> + eloc = c_parser_peek_token (parser)->location;
> + error_at (eloc, "unexpected %<else%>");
> + goto saw_error;
> + }
> +
> + c_parser_consume_token (parser);
> +
> + if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> + goto saw_error;
> +
> + extra_scope = true;
> + v = c_parser_cast_expression (parser, NULL).value;
> + non_lvalue_p = !lvalue_p (v);
> + v = c_fully_fold (v, false, NULL, true);
> + if (v == error_mark_node)
> + goto saw_error;
> + if (non_lvalue_p)
> + v = non_lvalue (v);
> + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
> + goto saw_error;
> +
> + expr = c_parser_expr_no_commas (parser, NULL);
> +
> + if (!c_tree_equal (expr.value, unfolded_lhs))
> + goto bad_if;
> +
> + if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> + goto saw_error;
> +
> + if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected
> %<}%>"))
> + goto saw_error;
> +
> + extra_scope = false;
> + code = OMP_ATOMIC_CAPTURE_OLD;
> + if (r == NULL_TREE)
> + /* Signal to c_finish_omp_atomic that in
> + if (x == e) { x = d; } else { v = x; }
> + case the store to v should be conditional. */
> + r = void_list_node;
> + }
> + else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
> + {
> + c_parser_require_keyword (parser, RID_ELSE, "expected %<else%>");
> + goto saw_error;
> + }
> + else if (code == OMP_ATOMIC_CAPTURE_NEW
> + && r != NULL_TREE
> + && v == NULL_TREE)
> + code = OMP_ATOMIC;
> + goto stmt_done;
> + }
> eloc = c_parser_peek_token (parser)->location;
> expr = c_parser_cast_expression (parser, NULL);
> lhs = expr.value;
> @@ -17908,9 +18236,14 @@ restart:
> orig_lhs = lhs;
> switch (TREE_CODE (lhs))
> {
> + invalid_compare:
> + error_at (eloc, "invalid form of %<pragma omp atomic compare%>");
> + /* FALLTHRU */
> case ERROR_MARK:
> saw_error:
> c_parser_skip_to_end_of_block_or_statement (parser);
> + if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
> + c_parser_consume_token (parser);
> if (structured_block)
> {
> if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
> @@ -17933,6 +18266,8 @@ restart:
> unfolded_lhs = NULL_TREE;
> opcode = PLUS_EXPR;
> rhs = integer_one_node;
> + if (compare)
> + goto invalid_compare;
> break;
>
> case POSTDECREMENT_EXPR:
> @@ -17944,6 +18279,8 @@ restart:
> unfolded_lhs = NULL_TREE;
> opcode = MINUS_EXPR;
> rhs = integer_one_node;
> + if (compare)
> + goto invalid_compare;
> break;
>
> case COMPOUND_EXPR:
> @@ -17973,6 +18310,8 @@ restart:
> && !structured_block
> && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
> code = OMP_ATOMIC_CAPTURE_OLD;
> + if (compare)
> + goto invalid_compare;
> break;
> }
> if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
> @@ -17988,6 +18327,8 @@ restart:
> && !structured_block
> && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
> code = OMP_ATOMIC_CAPTURE_OLD;
> + if (compare)
> + goto invalid_compare;
> break;
> }
> }
> @@ -17995,6 +18336,11 @@ restart:
> default:
> if (!lvalue_p (unfolded_lhs))
> lhs = non_lvalue (lhs);
> + if (compare && !c_parser_next_token_is (parser, CPP_EQ))
> + {
> + c_parser_error (parser, "expected %<=%>");
> + goto saw_error;
> + }
> switch (c_parser_peek_token (parser)->type)
> {
> case CPP_MULT_EQ:
> @@ -18041,6 +18387,8 @@ restart:
> case BIT_AND_EXPR:
> case BIT_IOR_EXPR:
> case BIT_XOR_EXPR:
> + if (compare)
> + break;
> if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
> {
> opcode = TREE_CODE (rhs1);
> @@ -18061,6 +18409,78 @@ restart:
> goto stmt_done;
> }
> break;
> + case COND_EXPR:
> + if (!compare)
> + break;
> + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR
> + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR
> + && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR)
> + break;
> + if (!TREE_OPERAND (rhs1, 1))
> + break;
> + if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs))
> + break;
> + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0),
> + unfolded_lhs))
> + {
> + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
> + {
> + opcode = COND_EXPR;
> + rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
> + 0),
> 1),
> + false, NULL, true);
> + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false,
> + NULL, true);
> + goto stmt_done;
> + }
> + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0),
> 1),
> + TREE_OPERAND (rhs1, 1)))
> + {
> + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) ==
> GT_EXPR
> + ? MIN_EXPR : MAX_EXPR);
> + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false,
> NULL,
> + true);
> + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND
> (rhs1,
> + 0),
> 0),
> + false, NULL, true);
> + goto stmt_done;
> + }
> + }
> + else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
> + break;
> + else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0),
> 1),
> + unfolded_lhs))
> + {
> + if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0),
> 0),
> + TREE_OPERAND (rhs1, 1)))
> + {
> + opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) ==
> GT_EXPR
> + ? MAX_EXPR : MIN_EXPR);
> + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false,
> NULL,
> + true);
> + rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND
> (rhs1,
> + 0),
> 1),
> + false, NULL, true);
> + goto stmt_done;
> + }
> + }
> + break;
> + case EQ_EXPR:
> + if (!compare
> + || code != OMP_ATOMIC_CAPTURE_NEW
> + || !structured_block
> + || v
> + || r)
> + break;
> + if (c_parser_next_token_is (parser, CPP_SEMICOLON)
> + && c_parser_peek_2nd_token (parser)->keyword == RID_IF)
> + {
> + r = lhs;
> + lhs = NULL_TREE;
> + c_parser_consume_token (parser);
> + goto restart;
> + }
> + break;
> case ERROR_MARK:
> goto saw_error;
> default:
> @@ -18109,10 +18529,12 @@ restart:
> break;
> }
> stmt_done:
> - if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
> + if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r ==
> NULL_TREE)
> {
> - if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> + if (!no_semicolon
> + && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> goto saw_error;
> + no_semicolon = false;
> v = c_parser_cast_expression (parser, NULL).value;
> non_lvalue_p = !lvalue_p (v);
> v = c_fully_fold (v, false, NULL, true);
> @@ -18135,10 +18557,16 @@ stmt_done:
> }
> if (structured_block)
> {
> - c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
> + if (!no_semicolon)
> + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected
> %<;%>");
> c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
> }
> done:
> + if (weak && opcode != COND_EXPR)
> + {
> + error_at (loc, "%<weak%> clause requires atomic equality
> comparison");
> + weak = false;
> + }
> if (unfolded_lhs && unfolded_lhs1
> && !c_tree_equal (unfolded_lhs, unfolded_lhs1))
> {
> @@ -18147,12 +18575,12 @@ done:
> stmt = error_mark_node;
> }
> else
> - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1,
> rhs1,
> - swapped, memory_order);
> + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1,
> rhs1, r,
> + swapped, memory_order, weak);
> if (stmt != error_mark_node)
> add_stmt (stmt);
>
> - if (!structured_block)
> + if (!structured_block && !no_semicolon)
> c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
> }
>
> --- gcc/c/c-typeck.c.jj 2021-09-09 10:40:19.979262872 +0200
> +++ gcc/c/c-typeck.c 2021-09-09 10:41:42.630084554 +0200
> @@ -12426,6 +12426,13 @@ build_binary_op (location_t location, en
> maybe_warn_bool_compare (location, code, orig_op0, orig_op1);
> break;
>
> + case MIN_EXPR:
> + case MAX_EXPR:
> + /* Used for OpenMP atomics. */
> + gcc_assert (flag_openmp);
> + common = 1;
> + break;
> +
> default:
> gcc_unreachable ();
> }
> --- gcc/cp/parser.c.jj 2021-09-09 10:40:19.996262630 +0200
> +++ gcc/cp/parser.c 2021-09-09 10:41:42.623084654 +0200
> @@ -40193,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser,
> memory_order = OMP_MEMORY_ORDER_ACQUIRE;
> break;
> case NOP_EXPR: /* atomic write */
> - case OMP_ATOMIC:
> memory_order = OMP_MEMORY_ORDER_RELEASE;
> break;
> default:
> @@ -40209,31 +40208,24 @@ cp_parser_omp_atomic (cp_parser *parser,
> switch (code)
> {
> case OMP_ATOMIC_READ:
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_RELEASE)
> + if (memory_order == OMP_MEMORY_ORDER_RELEASE)
> {
> error_at (loc, "%<#pragma omp atomic read%> incompatible with "
> - "%<acq_rel%> or %<release%> clauses");
> + "%<release%> clause");
> memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> }
> + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
> + memory_order = OMP_MEMORY_ORDER_ACQUIRE;
> break;
> case NOP_EXPR: /* atomic write */
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> {
> error_at (loc, "%<#pragma omp atomic write%> incompatible with
> "
> - "%<acq_rel%> or %<acquire%> clauses");
> - memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> - }
> - break;
> - case OMP_ATOMIC:
> - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL
> - || memory_order == OMP_MEMORY_ORDER_ACQUIRE)
> - {
> - error_at (loc, "%<#pragma omp atomic update%> incompatible
> with "
> - "%<acq_rel%> or %<acquire%> clauses");
> + "%<acquire%> clause");
> memory_order = OMP_MEMORY_ORDER_SEQ_CST;
> }
> + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
> + memory_order = OMP_MEMORY_ORDER_RELEASE;
> break;
> default:
> break;
> --- gcc/cp/semantics.c.jj 2021-09-09 10:40:26.093175709 +0200
> +++ gcc/cp/semantics.c 2021-09-09 10:59:17.762032066 +0200
> @@ -9956,7 +9956,7 @@ finish_omp_atomic (location_t loc, enum
> return;
> }
> stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs,
> - v, lhs1, rhs1, swapped, mo,
> + v, lhs1, rhs1, NULL_TREE, swapped, mo,
> false,
> processing_template_decl != 0);
> if (stmt == error_mark_node)
> return;
> --- gcc/testsuite/c-c++-common/gomp/atomic-17.c.jj 2021-09-09
> 10:40:20.088261318 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-17.c 2021-09-09
> 10:41:42.624084639 +0200
> @@ -22,8 +22,18 @@ foo ()
> v = i = i + 1;
> #pragma omp atomic read acquire
> v = i;
> + #pragma omp atomic acq_rel read
> + v = i;
> #pragma omp atomic release,write
> i = v;
> + #pragma omp atomic write,acq_rel
> + i = v;
> #pragma omp atomic hint(1),update,release
> f = f + 2.0;
> + #pragma omp atomic update ,acquire
> + i = i + 1;
> + #pragma omp atomic acq_rel update
> + i = i + 1;
> + #pragma omp atomic acq_rel,hint(0)
> + i = i + 1;
> }
> --- gcc/testsuite/c-c++-common/gomp/atomic-18.c.jj 2021-09-09
> 10:40:20.088261318 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-18.c 2021-09-09
> 10:41:42.624084639 +0200
> @@ -8,28 +8,18 @@ foo (int j)
> i = i + 1;
> #pragma omp atomic seq_cst release /* { dg-error "too many memory
> order clauses" } */
> i = i + 1;
> - #pragma omp atomic read,release /* { dg-error "incompatible with
> 'acq_rel' or 'release' clauses" } */
> + #pragma omp atomic read,release /* { dg-error "incompatible with
> 'release' clause" } */
> v = i;
> - #pragma omp atomic acq_rel read /* { dg-error "incompatible with
> 'acq_rel' or 'release' clauses" } */
> - v = i;
> - #pragma omp atomic write acq_rel /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> - i = v;
> - #pragma omp atomic acquire , write /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> + #pragma omp atomic acquire , write /* { dg-error "incompatible with
> 'acquire' clause" } */
> i = v;
> - #pragma omp atomic update ,acquire /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> - i = i + 1;
> - #pragma omp atomic acq_rel update /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> - i = i + 1;
> - #pragma omp atomic acq_rel,hint(0) /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> - i = i + 1;
> - #pragma omp atomic acquire /* { dg-error "incompatible with
> 'acq_rel' or 'acquire' clauses" } */
> - i = i + 1;
> - #pragma omp atomic capture hint (0) capture /* { dg-error "too many
> atomic clauses" } */
> + #pragma omp atomic capture hint (0) capture /* { dg-error "too many
> 'capture' clauses" "" { target c } } */
> + /* { dg-error "too many atomic
> clauses" "" { target c++ } .-1 } */
> v = i = i + 1;
> #pragma omp atomic hint(j + 2) /* { dg-error "constant integer
> expression" } */
> i = i + 1;
> #pragma omp atomic hint(f) /* { dg-error "integ" } */
> i = i + 1;
> - #pragma omp atomic foobar /* { dg-error "expected 'read',
> 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or
> 'hint' clause" } */
> - i = i + 1; /* { dg-error "expected end of
> line before" "" { target *-*-* } .-1 } */
> + #pragma omp atomic foobar /* { dg-error "expected 'read',
> 'write', 'update', 'capture', 'compare', 'weak', 'fail', 'seq_cst',
> 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target c } } */
> + /* { dg-error "expected 'read',
> 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or
> 'hint' clause" "" { target c++ } .-1 } */
> + i = i + 1; /* { dg-error "expected end of
> line before" "" { target *-*-* } .-2 } */
> }
> --- gcc/testsuite/c-c++-common/gomp/atomic-21.c.jj 2020-04-15
> 09:58:30.369649495 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-21.c 2021-09-09
> 17:25:18.782025085 +0200
> @@ -1,6 +1,7 @@
> /* { dg-do compile } */
> /* { dg-additional-options "-fdump-tree-original" } */
> -/* { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" }
> } */
> +/* { dg-final { scan-tree-dump-times "omp atomic release" 2 "original" }
> } */
> +/* { dg-final { scan-tree-dump-times "omp atomic acq_rel" 2 "original" }
> } */
> /* { dg-final { scan-tree-dump-times "omp atomic read acquire" 1
> "original" } } */
> /* { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 1
> "original" } } */
>
> --- gcc/testsuite/c-c++-common/gomp/atomic-25.c.jj 2021-09-09
> 10:41:42.624084639 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-25.c 2021-09-10
> 13:18:43.096258564 +0200
> @@ -0,0 +1,50 @@
> +/* { dg-do compile { target c } } */
> +
> +int x, r, z;
> +double d, v;
> +long double ld;
> +
> +void
> +foo (int y, double e, long double f)
> +{
> + #pragma omp atomic compare update seq_cst
> + x = x > y ? y : x;
> + #pragma omp atomic compare relaxed
> + d = e > d ? e : d;
> + #pragma omp atomic compare
> + d = f < d ? f : d;
> + #pragma omp atomic compare seq_cst fail(relaxed)
> + x = 12U < x ? 12U : x;
> + #pragma omp atomic compare
> + x = x == 7 ? 24 : x;
> + #pragma omp atomic compare
> + x = x == 123UL ? 256LL : x;
> + #pragma omp atomic compare
> + ld = ld == f ? f + 5.0L : ld;
> + #pragma omp atomic compare
> + if (x == 9) { x = 5; }
> + #pragma omp atomic compare
> + if (x > 5) { x = 5; }
> + #pragma omp atomic compare
> + if (7 > x) { x = 7; }
> + #pragma omp atomic compare update capture seq_cst fail(acquire)
> + v = d = f > d ? f : d;
> + #pragma omp atomic update capture compare
> + v = x = x < 24ULL ? 24ULL : x;
> + #pragma omp atomic compare, capture, update
> + v = x = x == e ? f : x;
> + #pragma omp atomic capture compare
> + { v = d; if (d > e) { d = e; } }
> + #pragma omp atomic compare capture
> + { if (e < d) { d = e; } v = d; }
> + #pragma omp atomic compare capture
> + { y = x; if (x == 42) { x = 7; } }
> + #pragma omp atomic capture compare weak
> + { if (x == 42) { x = 7; } y = x; }
> + #pragma omp atomic capture compare fail(seq_cst)
> + if (d == 8.0) { d = 16.0; } else { v = d; }
> + #pragma omp atomic capture compare
> + { r = x == 8; if (r) { x = 24; } }
> + #pragma omp atomic compare capture
> + { r = x == y; if (r) { x = y + 6; } else { z = x; } }
> +}
> --- gcc/testsuite/c-c++-common/gomp/atomic-26.c.jj 2021-09-09
> 10:41:42.624084639 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-26.c 2021-09-10
> 15:16:10.111808506 +0200
> @@ -0,0 +1,63 @@
> +/* { dg-do compile { target c } } */
> +
> +int x;
> +double d;
> +
> +double
> +foo (int y, double e, long double f)
> +{
> + double v;
> + #pragma omp atomic compare compare /* { dg-error "too many 'compare'
> clauses" } */
> + x = x > y ? y : x;
> + #pragma omp atomic compare fail(seq_cst) fail(seq_cst) /* {
> dg-error "too many 'fail' clauses" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare,fail(seq_cst),fail(relaxed) /* {
> dg-error "too many 'fail' clauses" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare weak weak /* { dg-error "too many 'weak'
> clauses" } */
> + d = d == e ? e + 1.0 : d;
> + #pragma omp atomic read capture /* { dg-error "'capture' clause is
> incompatible with 'read' or 'write' clauses" } */
> + v = d;
> + #pragma omp atomic capture, write /* { dg-error "'capture' clause is
> incompatible with 'read' or 'write' clauses" } */
> + d = v;
> + #pragma omp atomic read compare /* { dg-error "'compare' clause is
> incompatible with 'read' or 'write' clauses" } */
> + v = d;
> + #pragma omp atomic compare, write /* { dg-error "'compare' clause is
> incompatible with 'read' or 'write' clauses" } */
> + d = v;
> + #pragma omp atomic read fail(seq_cst) /* { dg-error "'fail'
> clause requires 'compare' clause" } */
> + v = d;
> + #pragma omp atomic fail(relaxed), write /* { dg-error "'fail'
> clause requires 'compare' clause" } */
> + d = v;
> + #pragma omp atomic fail(relaxed) update /* { dg-error "'fail'
> clause requires 'compare' clause" } */
> + d += 3.0;
> + #pragma omp atomic fail(relaxed) /* { dg-error "'fail' clause
> requires 'compare' clause" } */
> + d += 3.0;
> + #pragma omp atomic capture fail(relaxed) /* { dg-error "'fail'
> clause requires 'compare' clause" } */
> + v = d += 3.0;
> + #pragma omp atomic read weak /* { dg-error "'weak' clause
> requires 'compare' clause" } */
> + v = d;
> + #pragma omp atomic weak, write /* { dg-error "'weak' clause
> requires 'compare' clause" } */
> + d = v;
> + #pragma omp atomic weak update /* { dg-error "'weak' clause
> requires 'compare' clause" } */
> + d += 3.0;
> + #pragma omp atomic weak /* { dg-error "'weak' clause
> requires 'compare' clause" } */
> + d += 3.0;
> + #pragma omp atomic capture weak /* { dg-error "'weak' clause
> requires 'compare' clause" } */
> + v = d += 3.0;
> + #pragma omp atomic compare,weak /* { dg-error "'weak' clause
> requires atomic equality comparison" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail /* { dg-error "expected '\\\('
> before end of line" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail( /* { dg-error "expected 'seq_cst',
> 'acquire' or 'relaxed' before end of line" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail() /* { dg-error "expected 'seq_cst',
> 'acquire' or 'relaxed' before '\\\)' token" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail(foobar) /* { dg-error "expected
> 'seq_cst', 'acquire' or 'relaxed' before 'foobar'" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail(acq_rel) /* { dg-error "expected
> 'seq_cst', 'acquire' or 'relaxed' before 'acq_rel'" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail(release) /* { dg-error "expected
> 'seq_cst', 'acquire' or 'relaxed' before 'release'" } */
> + d = e > d ? e : d;
> + #pragma omp atomic compare fail(seq_cst /* { dg-error "expected
> '\\\)' before end of line" } */
> + d = e > d ? e : d;
> + return v;
> +}
> --- gcc/testsuite/c-c++-common/gomp/atomic-27.c.jj 2021-09-09
> 16:58:07.052709219 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-27.c 2021-09-09
> 17:05:13.271786779 +0200
> @@ -0,0 +1,41 @@
> +/* PR middle-end/88968 */
> +/* { dg-do compile { target c } } */
> +
> +struct __attribute__((packed)) S {
> + unsigned int a : 16;
> + unsigned int b : 1;
> +} s;
> +
> +void
> +foo (int y, int z)
> +{
> + #pragma omp atomic compare
> + s.a = s.a == y ? z : s.a;
> +}
> +
> +int
> +bar (int y, int z)
> +{
> + int r;
> + #pragma omp atomic compare capture
> + { r = s.a == y; if (r) { s.a = z; } }
> + return r;
> +}
> +
> +int
> +baz (int y, int z)
> +{
> + int v;
> + #pragma omp atomic compare capture
> + if (s.a == y) { s.a = z; } else { v = s.a; }
> + return v;
> +}
> +
> +int
> +qux (int y, int z)
> +{
> + int v;
> + #pragma omp atomic compare capture
> + v = s.a = s.a == y ? z : s.a;
> + return v;
> +}
> --- gcc/testsuite/c-c++-common/gomp/atomic-28.c.jj 2021-09-10
> 11:47:09.193274972 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-28.c 2021-09-10
> 11:52:05.398115961 +0200
> @@ -0,0 +1,43 @@
> +/* { dg-do compile { target c } } */
> +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 4, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 4, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 260, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 4, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-not "__atomic_load_4 \\\(" "ompexp" {
> target sync_int_long } } } */
> +
> +int x;
> +
> +void
> +foo (int y, int z)
> +{
> + #pragma omp atomic compare seq_cst
> + x = x == y ? z : x;
> +}
> +
> +int
> +bar (int y, int z)
> +{
> + int r;
> + #pragma omp atomic compare capture acq_rel fail (acquire)
> + { r = x == y; if (r) { x = z; } }
> + return r;
> +}
> +
> +int
> +baz (int y, int z)
> +{
> + int v;
> + #pragma omp atomic compare capture seq_cst fail (relaxed) weak
> + if (x == y) { x = z; } else { v = x; }
> + return v;
> +}
> +
> +int
> +qux (int y, int z)
> +{
> + int v;
> + #pragma omp atomic compare capture
> + v = x = x == y ? z : x;
> + return v;
> +}
> --- gcc/testsuite/c-c++-common/gomp/atomic-29.c.jj 2021-09-10
> 11:47:17.093164041 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-29.c 2021-09-10
> 11:52:33.428722747 +0200
> @@ -0,0 +1,43 @@
> +/* { dg-do compile { target c } } */
> +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 8, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 8, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 264, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> \\\(\[^\n\r]*, 8, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> +/* { dg-final { scan-tree-dump-not "__atomic_load_8 \\\(" "ompexp" {
> target sync_int_long } } } */
> +
>
This test fails on arm*linux when forcing old CPU/ARCH (eg -march=armv5t).
Not sure how easy it is to fix?
sync_int_long returns true for arm*-*-linux-*,
but for other arm targets, it depends on the result
of check_effective_target_arm_acq_rel.
Is it just a matter of removing arm*-*-linux-* from sync_int_long and
always rely on arm_acq_rel?
Christophe
+double x;
> +
> +void
> +foo (double y, double z)
> +{
> + #pragma omp atomic compare seq_cst
> + x = x == y ? z : x;
> +}
> +
> +double
> +bar (double y, double z)
> +{
> + int r;
> + #pragma omp atomic compare capture acq_rel fail (acquire)
> + { r = x == y; if (r) { x = z; } }
> + return r;
> +}
> +
> +double
> +baz (double y, double z)
> +{
> + double v;
> + #pragma omp atomic compare capture seq_cst fail (relaxed) weak
> + if (x == y) { x = z; } else { v = x; }
> + return v;
> +}
> +
> +double
> +qux (double y, double z)
> +{
> + double v;
> + #pragma omp atomic compare capture
> + v = x = x == y ? z : x;
> + return v;
> +}
> --- gcc/testsuite/c-c++-common/gomp/atomic-30.c.jj 2021-09-10
> 15:25:01.955425201 +0200
> +++ gcc/testsuite/c-c++-common/gomp/atomic-30.c 2021-09-10
> 18:02:50.229520066 +0200
> @@ -0,0 +1,137 @@
> +/* { dg-do compile { target c } } */
> +
> +int x;
> +double d, g;
> +
> +double
> +foo (int y, double e, long double f)
> +{
> + double v;
> + int r, r2 = 0;
> + #pragma omp atomic capture compare
> + v = if (d == e) { d = f; }; /* { dg-error "expected expression" } */
> + #pragma omp atomic compare
> + if; /* { dg-error "expected '\\\(' before ';'
> token" } */
> + #pragma omp atomic compare
> + if (d >= e) { d = e; } /* { dg-error "expected '==', '<' or '>'
> comparison in 'if' condition" } */
> + #pragma omp atomic compare
> + if (d <= e) { d = e; } /* { dg-error "expected '==', '<' or '>'
> comparison in 'if' condition" } */
> + #pragma omp atomic compare
> + if (d != e) { d = e; } /* { dg-error "expected '==', '<' or '>'
> comparison in 'if' condition" } */
> + #pragma omp atomic compare
> + if (d + e) { d = e; } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d >= e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d <= e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d > e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d < e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d != e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d + e; if (r) { d = f; } } /* { dg-error "expected '==', '<'
> or '>' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + { r = d == e; if (r2) { d = f; } } /* { dg-error "invalid form of
> '#pragma omp atomic compare' before '\{' token" } */
> + #pragma omp atomic capture compare
> + if (d > e) { d = e; } /* { dg-error "expected
> '==' comparison in 'if' condition" } */
> + #pragma omp atomic capture compare
> + if (d < e) { d = e; } /* { dg-error "expected
> '==' comparison in 'if' condition" } */
> + #pragma omp atomic compare
> + if (d < e) d = e; /* { dg-error "expected '\{'
> before 'd'" } */
> + #pragma omp atomic compare
> + if (d == e) d = e + 1.0; /* { dg-error "expected '\{'
> before 'd'" } */
> + #pragma omp atomic compare
> + if (d < e) { d += e; } /* { dg-error "expected '=' before
> '\\\+=' token" } */
> + #pragma omp atomic compare
> + if (d < e) { d = e }; /* { dg-error "expected
> ';' before '\}' token" } */
> + #pragma omp atomic compare
> + if (d < e) { d = e; e = 1.0; } /* { dg-error "expected '\}'
> before 'e'" } */
> + #pragma omp atomic compare
> + if (e == d) { d = f; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (e == d) { g = f; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (d < e) { g = e; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (d > e) { g = e; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (d < e) { d = g; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (d > e) { d = g; }; /* { dg-error "invalid form of
> '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare
> + if (d == e) { d = f; } else ; /* { dg-error "unexpected
> 'else'" } */
> + #pragma omp atomic compare capture
> + { if (d == e) { d = f; } else { v = d; } v = d; } /* {
> dg-error "unexpected 'else'" } */
> + #pragma omp atomic compare
> + if (d < e) { d = e; } else { v = d; } /* { dg-error "unexpected
> 'else'" } */
> + #pragma omp atomic compare capture
> + if (d == e) { d = f; } else v = d; /* { dg-error "expected '\{'
> before 'v'" } */
> + #pragma omp atomic compare capture
> + if (d == e) { d = f; } else { v += d; } /* { dg-error
> "expected '=' before '\\\+=' token" } */
> + #pragma omp atomic compare capture
> + if (d == e) { d = f; } else { v = e; } /* { dg-error "invalid
> form of '#pragma omp atomic compare' before ';' token" } */
> + #pragma omp atomic compare capture
> + if (d == e) { d = f; } else { v = d }; /* { dg-error "expected
> ';' before '\}' token" } */
> + #pragma omp atomic compare capture
> + if (d == e) { d = f; }; /* { dg-error "expected 'else'
> before ';' token" } */
> + #pragma omp atomic compare
> + x++; /* { dg-error "invalid form of
> 'pragma omp atomic compare'" } */
> + #pragma omp atomic compare
> + x--; /* { dg-error "invalid form of
> 'pragma omp atomic compare'" } */
> + #pragma omp atomic compare
> + ++x; /* { dg-error "invalid form of
> 'pragma omp atomic compare'" } */
> + #pragma omp atomic compare
> + --x; /* { dg-error "invalid form of
> 'pragma omp atomic compare'" } */
> + #pragma omp atomic compare
> + x += 3; /* { dg-error "expected '=' before
> '\\\+=' token" } */
> + #pragma omp atomic compare
> + x -= 5; /* { dg-error "expected '=' before
> '-=' token" } */
> + #pragma omp atomic compare
> + x *= 2; /* { dg-error "expected '=' before
> '\\\*=' token" } */
> + #pragma omp atomic compare
> + x |= 5; /* { dg-error "expected '=' before
> '\\\|=' token" } */
> + #pragma omp atomic compare
> + x &= ~5; /* { dg-error "expected '=' before
> '\\\&=' token" } */
> + #pragma omp atomic compare
> + x ^= 5; /* { dg-error "expected '=' before
> '\\\^=' token" } */
> + #pragma omp atomic compare
> + x = x + 3; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x - 5; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = 2 * x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = 5 | x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x & ~5; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x | 5; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x >= 5 ? 5 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x <= 5 ? 5 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x != 5 ? 7 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = 5 == x ? 7 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x == 5 ? x : 7; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x == 5 ? 9 : 7; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x > 5 ? 6 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x < 5 ? 6 : x; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x > 5 ? x : 6; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic compare
> + x = x < 5 ? x : 6; /* { dg-error "invalid form of
> '#pragma omp atomic' before ';' token" } */
> + #pragma omp atomic capture
> + r = x == 5; /* { dg-error "invalid operator
> for '#pragma omp atomic' before '==' token" } */
> + #pragma omp atomic capture compare
> + r = x == 5; /* { dg-error "expected '=' before
> '==' token" } */
> + #pragma omp atomic capture compare /* { dg-error "'#pragma omp atomic
> compare capture' with non-integral comparison result" } */
> + { v = x == 5; if (v) { x = 6; } }
> +}
> --- gcc/testsuite/c-c++-common/goacc-gomp/atomic.c.jj 2020-11-06
> 11:14:19.942201229 +0100
> +++ gcc/testsuite/c-c++-common/goacc-gomp/atomic.c 2021-09-09
> 17:10:58.686986511 +0200
> @@ -37,7 +37,8 @@ foo ()
>
> /* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read
> acquire" 1 "original" } } */
> /* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read
> relaxed" 1 "original" } } */
> -/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 2
> "original" } } */
> +/* { dg-final { scan-tree-dump-times "#pragma omp atomic acq_rel" 1
> "original" } } */
> +/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 1
> "original" } } */
> /* { dg-final { scan-tree-dump-times "#pragma omp atomic relaxed" 2
> "original" } } */
> /* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture
> acq_rel" 1 "original" } } */
> /* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture
> relaxed" 2 "original" } } */
> --- gcc/testsuite/gcc.dg/gomp/atomic-5.c.jj 2021-09-09
> 10:40:20.099261161 +0200
> +++ gcc/testsuite/gcc.dg/gomp/atomic-5.c 2021-09-09
> 10:41:42.625084625 +0200
> @@ -27,7 +27,7 @@ void f1(void)
> #pragma omp atomic
> bar() += 1; /* { dg-error "lvalue required" } */
> #pragma omp atomic a /* { dg-error "expected end of line" } */
> - x++; /* { dg-error "expected 'read', 'write', 'update',
> 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" ""
> { target *-*-* } .-1 } */
> + x++; /* { dg-error "expected 'read', 'write', 'update',
> 'capture', 'compare', 'weak', 'fail', 'seq_cst', 'acq_rel', 'release',
> 'relaxed' or 'hint' clause" "" { target *-*-* } .-1 } */
> #pragma omp atomic
> ; /* { dg-error "expected expression" } */
> #pragma omp atomic
> --- gcc/testsuite/g++.dg/gomp/atomic-18.C.jj 2020-04-15
> 09:58:30.372649450 +0200
> +++ gcc/testsuite/g++.dg/gomp/atomic-18.C 2021-09-09
> 17:27:28.671222445 +0200
> @@ -1,6 +1,7 @@
> // { dg-do compile }
> // { dg-additional-options "-fdump-tree-original" }
> -// { dg-final { scan-tree-dump-times "omp atomic release" 5 "original" } }
> +// { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" } }
> +// { dg-final { scan-tree-dump-times "omp atomic acq_rel" 1 "original" } }
> // { dg-final { scan-tree-dump-times "omp atomic seq_cst" 1 "original" } }
> // { dg-final { scan-tree-dump-times "omp atomic relaxed" 2 "original" } }
> // { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 3
> "original" } }
> --- libgomp/testsuite/libgomp.c-c++-common/atomic-19.c.jj 2021-09-10
> 12:09:43.320275112 +0200
> +++ libgomp/testsuite/libgomp.c-c++-common/atomic-19.c 2021-09-10
> 14:24:03.200540163 +0200
> @@ -0,0 +1,274 @@
> +// { dg-do run { target c } }
> +
> +extern
> +#ifdef __cplusplus
> +"C"
> +#endif
> +void abort (void);
> +int x = 6;
> +int w, y;
> +
> +int *
> +foo (void)
> +{
> + if (w)
> + abort ();
> + return &y;
> +}
> +
> +int
> +main ()
> +{
> + int v, r;
> + #pragma omp atomic compare
> + x = x > 8 ? 8 : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + #pragma omp atomic compare
> + x = x > 4 ? 4 : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 4)
> + abort ();
> + #pragma omp atomic compare capture
> + v = x = x < 8 ? 8 : x;
> + if (v != 8)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 8)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; x = x < 12 ? 12 : x; }
> + if (v != 8)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; x = x < 4 ? 4 : x; }
> + if (v != 12)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic write
> + x = -32;
> + #pragma omp atomic capture compare seq_cst fail(relaxed)
> + { x = 12U < x ? 12U : x; v = x; }
> + if (v != 12)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic compare
> + x = x == 12 ? 16 : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 16)
> + abort ();
> + r = 57;
> + #pragma omp atomic compare capture
> + v = x = x == 15 ? r + 7 : x;
> + if (v != 16)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 16)
> + abort ();
> + #pragma omp atomic capture, update, compare seq_cst fail(acquire)
> + { v = x; x = x == 73ULL - r ? 12LL : x; }
> + if (v != 16)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic update, compare, capture
> + { x = x == 69LL - r ? (unsigned char) 6 : x; v = x; }
> + if (v != 6)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + #pragma omp atomic compare
> + if (x > 8) { x = 8; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + #pragma omp atomic compare
> + if (x > 4) { x = 4; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 4)
> + abort ();
> + #pragma omp atomic compare capture
> + { if (x < 8) { x = 8; } v = x; }
> + if (v != 8)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 8)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; if (x < 12) { x = 12; } }
> + if (v != 8)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; if (x < 4) { x = 4; } }
> + if (v != 12)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic write
> + x = -32;
> + #pragma omp atomic capture compare seq_cst fail(relaxed)
> + { if (12U < x) { x = 12U; } v = x; }
> + if (v != 12)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic compare
> + if (x == 12) { x = 16; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 16)
> + abort ();
> + r = 57;
> + #pragma omp atomic compare capture
> + { if (x == 15) { x = r + 7; } v = x; }
> + if (v != 16)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 16)
> + abort ();
> + #pragma omp atomic capture, update, compare seq_cst fail(acquire)
> + { v = x; if (x == 73ULL - r) { x = 12LL; } }
> + if (v != 16)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12)
> + abort ();
> + #pragma omp atomic update, compare, capture
> + { if (x == 69LL - r) { x = (unsigned char) 6; } v = x; }
> + if (v != 6)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + v = 24;
> + #pragma omp atomic compare capture
> + if (x == 12) { x = 16; } else { v = x; }
> + if (v != 6)
> + abort ();
> + v = 32;
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + v = 147;
> + #pragma omp atomic capture compare
> + if (x == 6) { x = 57; } else { v = x; }
> + if (v != 147)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 57)
> + abort ();
> + #pragma omp atomic update, capture, compare, weak, seq_cst, fail
> (relaxed)
> + { r = x == 137; if (r) { x = 174; } }
> + if (r)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 57)
> + abort ();
> + #pragma omp atomic compare capture fail (relaxed)
> + { r = x == 57; if (r) { x = 6; } }
> + if (r != 1)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + v = -5;
> + #pragma omp atomic capture compare
> + { r = x == 17; if (r) { x = 25; } else { v = x; } }
> + if (r || v != 6)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6)
> + abort ();
> + v = 15;
> + #pragma omp atomic capture compare
> + { r = x == 6; if (r) { x = 23; } else { v = x; } }
> + if (r != 1 || v != 15)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 23)
> + abort ();
> + w = 1;
> + #pragma omp atomic compare capture
> + if (x == 23) { x = 57; } else { foo ()[0] = x; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 57)
> + abort ();
> + #pragma omp atomic capture update compare
> + { r = x == 57; if (r) { x = 23; } else { foo ()[0] = x; } }
> + if (r != 1)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 23)
> + abort ();
> + w = 0;
> + #pragma omp atomic compare capture
> + if (x == 24) { x = 57; } else { foo ()[0] = x; }
> + if (y != 23)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 23)
> + abort ();
> + y = -5;
> + #pragma omp atomic capture update compare
> + {
> + r = x == 57;
> + if (r)
> + {
> + x = 27;
> + }
> + else
> + {
> + foo ()[0] = x;
> + }
> + }
> + if (r || y != 23)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 23)
> + abort ();
> + return 0;
> +}
> --- libgomp/testsuite/libgomp.c-c++-common/atomic-20.c.jj 2021-09-10
> 14:08:45.330336955 +0200
> +++ libgomp/testsuite/libgomp.c-c++-common/atomic-20.c 2021-09-10
> 14:27:14.746865949 +0200
> @@ -0,0 +1,203 @@
> +// { dg-do run { target c } }
> +
> +extern
> +#ifdef __cplusplus
> +"C"
> +#endif
> +void abort (void);
> +float x = 6.0f;
> +
> +int
> +main ()
> +{
> + float v;
> + int r;
> + #pragma omp atomic compare
> + x = x > 8.0f ? 8.0f : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + #pragma omp atomic compare
> + x = x > 4.0f ? 4.0f : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 4.0f)
> + abort ();
> + #pragma omp atomic compare capture
> + v = x = x < 8.0f ? 8.0f : x;
> + if (v != 8.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 8)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; x = x < 12.0f ? 12.0f : x; }
> + if (v != 8.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; x = x < 4.0f ? 4.0f : x; }
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic compare
> + x = x == 12.0 ? 16.0L : x;
> + #pragma omp atomic read
> + v = x;
> + if (v != 16.0)
> + abort ();
> + r = 57;
> + #pragma omp atomic compare capture
> + v = x = x == 15.0f ? r + 7.0f : x;
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic capture, update, compare seq_cst fail(acquire)
> + { v = x; x = x == 73.0L - r ? 12.0f : x; }
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic update, compare, capture
> + { x = x == 69.0 - r ? 6.0f : x; v = x; }
> + if (v != 6.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + #pragma omp atomic compare
> + if (x > 8.0f) { x = 8.0f; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + #pragma omp atomic compare
> + if (x > 4.0) { x = 4.0; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 4.0f)
> + abort ();
> + #pragma omp atomic compare capture
> + { if (x < 8.0f) { x = 8.0f; } v = x; }
> + if (v != 8.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 8.0f)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; if (x < 12.0f) { x = 12.0f; } }
> + if (v != 8.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic capture compare
> + { v = x; if (x < 4.0L) { x = 4.0L; } }
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic compare
> + if (x == 12.0f) { x = 16.0L; }
> + #pragma omp atomic read
> + v = x;
> + if (v != 16.0f)
> + abort ();
> + r = 57.0;
> + #pragma omp atomic compare capture
> + { if (x == 15.0f) { x = r + 7.0f; } v = x; }
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic capture, update, compare seq_cst fail(acquire)
> + { v = x; if (x == 73.0L - r) { x = 12.0L; } }
> + if (v != 16.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 12.0f)
> + abort ();
> + #pragma omp atomic update, compare, capture
> + { if (x == 69.0L - r) { x = 6.0; } v = x; }
> + if (v != 6.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + v = 24;
> + #pragma omp atomic compare capture
> + if (x == 12.0f) { x = 16.0f; } else { v = x; }
> + if (v != 6.0f)
> + abort ();
> + v = 32.0f;
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + v = 147.0f;
> + #pragma omp atomic capture compare
> + if (x == 6.0f) { x = 57.0f; } else { v = x; }
> + if (v != 147.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 57.0f)
> + abort ();
> + #pragma omp atomic update, capture, compare, weak, seq_cst, fail
> (relaxed)
> + { r = x == 137.0f; if (r) { x = 174.0f; } }
> + if (r)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 57.0f)
> + abort ();
> + #pragma omp atomic compare capture fail (relaxed)
> + { r = x == 57.0f; if (r) { x = 6.0f; } }
> + if (r != 1)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + v = -5.0f;
> + #pragma omp atomic capture compare
> + { r = x == 17.0L; if (r) { x = 25.0; } else { v = x; } }
> + if (r || v != 6.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 6.0f)
> + abort ();
> + v = 15.0f;
> + #pragma omp atomic capture compare
> + { r = x == 6.0f; if (r) { x = 23.0f; } else { v = x; } }
> + if (r != 1 || v != 15.0f)
> + abort ();
> + #pragma omp atomic read
> + v = x;
> + if (v != 23.0f)
> + abort ();
> + return 0;
> +}
> --- libgomp/testsuite/libgomp.c-c++-common/atomic-21.c.jj 2021-09-10
> 14:27:19.051805671 +0200
> +++ libgomp/testsuite/libgomp.c-c++-common/atomic-21.c 2021-09-10
> 15:05:47.316510552 +0200
> @@ -0,0 +1,49 @@
> +// { dg-do run { target c } }
> +
> +double d;
> +long double ld;
> +
> +int
> +main ()
> +{
> + double e = __builtin_copysign (0.0, -1.0), v;
> + long double le = __builtin_copysignl (0.0L, -1.0L), lv;
> + if (__builtin_memcmp (&d, &e, sizeof (d)) != 0)
> + {
> + /* Verify == comparison for atomics is done as with memcmp. */
> + #pragma omp atomic compare
> + d = d == e ? 5.0 : d;
> + #pragma omp atomic read
> + v = d;
> + if (v != 0.0)
> + __builtin_abort ();
> + #pragma omp atomic compare
> + d = d == 0.0 ? 5.0 : d;
> + #pragma omp atomic read
> + v = d;
> + if (v != 5.0)
> + __builtin_abort ();
> + }
> + if (__builtin_memcmp (&ld, &le, sizeof (ld)) != 0)
> + {
> + __builtin_memset (&ld, 0xff, sizeof (ld));
> + #pragma omp atomic write
> + ld = 0.0L;
> + __asm volatile ("" : : "g" (&ld) : "memory");
> + /* Verify == comparison for atomics is done as with memcmp
> + with __builtin_clear_padding if needed. */
> + #pragma omp atomic compare
> + ld = ld == le ? 5.0L : ld;
> + #pragma omp atomic read
> + lv = ld;
> + if (lv != 0.0L)
> + __builtin_abort ();
> + #pragma omp atomic compare
> + ld = ld == 0.0L ? 5.0L : ld;
> + #pragma omp atomic read
> + lv = ld;
> + if (lv != 5.0L)
> + __builtin_abort ();
> + }
> + return 0;
> +}
>
> Jakub
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: openmp: Implement OpenMP 5.1 atomics, so far for C only
2021-09-13 11:57 ` Christophe Lyon
@ 2021-09-13 14:40 ` Jakub Jelinek
2021-09-13 14:53 ` Christophe Lyon
0 siblings, 1 reply; 4+ messages in thread
From: Jakub Jelinek @ 2021-09-13 14:40 UTC (permalink / raw)
To: Christophe Lyon; +Cc: GCC Patches, Tobias Burnus
On Mon, Sep 13, 2021 at 01:57:52PM +0200, Christophe Lyon wrote:
> > --- gcc/testsuite/c-c++-common/gomp/atomic-29.c.jj 2021-09-10
> > 11:47:17.093164041 +0200
> > +++ gcc/testsuite/c-c++-common/gomp/atomic-29.c 2021-09-10
> > 11:52:33.428722747 +0200
> > @@ -0,0 +1,43 @@
> > +/* { dg-do compile { target c } } */
> > +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
> > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > \\\(\[^\n\r]*, 8, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
> > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > \\\(\[^\n\r]*, 8, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
> > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > \\\(\[^\n\r]*, 264, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > \\\(\[^\n\r]*, 8, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> > +/* { dg-final { scan-tree-dump-not "__atomic_load_8 \\\(" "ompexp" {
> > target sync_int_long } } } */
> > +
> >
>
> This test fails on arm*linux when forcing old CPU/ARCH (eg -march=armv5t).
> Not sure how easy it is to fix?
> sync_int_long returns true for arm*-*-linux-*,
> but for other arm targets, it depends on the result
> of check_effective_target_arm_acq_rel.
>
> Is it just a matter of removing arm*-*-linux-* from sync_int_long and
> always rely on arm_acq_rel?
So, atomic-28.c passes and just atomic-29.c fails?
atomic-29.c tests for double atomics aka 64-bit, so probably I should use
sync_long_long effective target instead of sync_int_long.
But, it is unclear how would that help for arm because sync_long_long is
enabled for all arm targets...
There is also sync_long_long_runtime effective target, but this is a compile
test, so it would be weird to rely on that when it ought to test the runtime
behavior of that.
Jakub
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: openmp: Implement OpenMP 5.1 atomics, so far for C only
2021-09-13 14:40 ` Jakub Jelinek
@ 2021-09-13 14:53 ` Christophe Lyon
0 siblings, 0 replies; 4+ messages in thread
From: Christophe Lyon @ 2021-09-13 14:53 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: GCC Patches, Tobias Burnus
On Mon, Sep 13, 2021 at 4:40 PM Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Sep 13, 2021 at 01:57:52PM +0200, Christophe Lyon wrote:
> > > --- gcc/testsuite/c-c++-common/gomp/atomic-29.c.jj 2021-09-10
> > > 11:47:17.093164041 +0200
> > > +++ gcc/testsuite/c-c++-common/gomp/atomic-29.c 2021-09-10
> > > 11:52:33.428722747 +0200
> > > @@ -0,0 +1,43 @@
> > > +/* { dg-do compile { target c } } */
> > > +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */
> > > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > > \\\(\[^\n\r]*, 8, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */
> > > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > > \\\(\[^\n\r]*, 8, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */
> > > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > > \\\(\[^\n\r]*, 264, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } }
> */
> > > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE
> > > \\\(\[^\n\r]*, 8, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */
> > > +/* { dg-final { scan-tree-dump-not "__atomic_load_8 \\\(" "ompexp" {
> > > target sync_int_long } } } */
> > > +
> > >
> >
> > This test fails on arm*linux when forcing old CPU/ARCH (eg
> -march=armv5t).
> > Not sure how easy it is to fix?
> > sync_int_long returns true for arm*-*-linux-*,
> > but for other arm targets, it depends on the result
> > of check_effective_target_arm_acq_rel.
> >
> > Is it just a matter of removing arm*-*-linux-* from sync_int_long and
> > always rely on arm_acq_rel?
>
> So, atomic-28.c passes and just atomic-29.c fails?
>
Yes.
> atomic-29.c tests for double atomics aka 64-bit, so probably I should use
> sync_long_long effective target instead of sync_int_long.
> But, it is unclear how would that help for arm because sync_long_long is
> enabled for all arm targets...
>
Indeed :-(
> There is also sync_long_long_runtime effective target, but this is a
> compile
> test, so it would be weird to rely on that when it ought to test the
> runtime
> behavior of that.
>
Agreed
>
> Jakub
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-09-13 14:53 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-10 18:46 openmp: Implement OpenMP 5.1 atomics, so far for C only Jakub Jelinek
2021-09-13 11:57 ` Christophe Lyon
2021-09-13 14:40 ` Jakub Jelinek
2021-09-13 14:53 ` Christophe Lyon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).