openmp: Implement OpenMP 5.1 atomics, so far for C only
This patch implements OpenMP 5.1 atomics (with clarifications from upcoming 5.2). The most important changes are that it is now possible to write (for C/C++, for Fortran it was possible before already) min/max atomics and more importantly compare and exchange in various forms. Also, acq_rel is now allowed on read/write and acq_rel/acquire are allowed on update, and there are new compare, weak and fail clauses. 2021-09-10 Jakub Jelinek <jakub@redhat.com> gcc/ * tree-core.h (enum omp_memory_order): Add OMP_MEMORY_ORDER_MASK, OMP_FAIL_MEMORY_ORDER_UNSPECIFIED, OMP_FAIL_MEMORY_ORDER_RELAXED, OMP_FAIL_MEMORY_ORDER_ACQUIRE, OMP_FAIL_MEMORY_ORDER_RELEASE, OMP_FAIL_MEMORY_ORDER_ACQ_REL, OMP_FAIL_MEMORY_ORDER_SEQ_CST and OMP_FAIL_MEMORY_ORDER_MASK enumerators. (OMP_FAIL_MEMORY_ORDER_SHIFT): Define. * gimple-pretty-print.c (dump_gimple_omp_atomic_load, dump_gimple_omp_atomic_store): Print [weak] for weak atomic load/store. * gimple.h (enum gf_mask): Change GF_OMP_ATOMIC_MEMORY_ORDER to 6-bit mask, adjust GF_OMP_ATOMIC_NEED_VALUE value and add GF_OMP_ATOMIC_WEAK. (gimple_omp_atomic_weak_p, gimple_omp_atomic_set_weak): New inline functions. * tree.h (OMP_ATOMIC_WEAK): Define. * tree-pretty-print.c (dump_omp_atomic_memory_order): Adjust for fail memory order being encoded in the same enum and also print fail clause if present. (dump_generic_node): Print weak clause if OMP_ATOMIC_WEAK. * gimplify.c (goa_stabilize_expr): Add target_expr and rhs arguments, handle pre_p == NULL case as a test mode that only returns value but doesn't change gimplify nor change anything otherwise, adjust recursive calls, add MODIFY_EXPR, ADDR_EXPR, COND_EXPR, TARGET_EXPR and CALL_EXPR handling, adjust COMPOUND_EXPR handling for __builtin_clear_padding calls, for !rhs gimplify as lvalue rather than rvalue. (gimplify_omp_atomic): Adjust goa_stabilize_expr caller. Handle COND_EXPR rhs. Set weak flag on gimple load/store for OMP_ATOMIC_WEAK. * omp-expand.c (omp_memory_order_to_fail_memmodel): New function. (omp_memory_order_to_memmodel): Adjust for fail clause encoded in the same enum. (expand_omp_atomic_cas): New function. (expand_omp_atomic_pipeline): Use omp_memory_order_to_fail_memmodel function. (expand_omp_atomic): Attempt to optimize atomic compare and exchange using expand_omp_atomic_cas. gcc/c-family/ * c-common.h (c_finish_omp_atomic): Add r and weak arguments. * c-omp.c: Include gimple-fold.h. (c_finish_omp_atomic): Add r and weak arguments. Add support for OpenMP 5.1 atomics. gcc/c/ * c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs and cond.value is >, < or == with omp_atomic_lhs as one of the operands, don't call build_conditional_expr, instead build a COND_EXPR directly. (c_parser_binary_expression): Avoid calling parser_build_binary_op if omp_atomic_lhs even in more cases for >, < or ==. (c_parser_omp_atomic): Update function comment for OpenMP 5.1 atomics, parse OpenMP 5.1 atomics and fail, compare and weak clauses, allow acq_rel on atomic read/write and acq_rel/acquire clauses on update. * c-typeck.c (build_binary_op): For flag_openmp only handle MIN_EXPR/MAX_EXPR. gcc/cp/ * parser.c (cp_parser_omp_atomic): Allow acq_rel on atomic read/write and acq_rel/acquire clauses on update. * semantics.c (finish_omp_atomic): Adjust c_finish_omp_atomic caller. gcc/testsuite/ * c-c++-common/gomp/atomic-17.c (foo): Add tests for atomic read, write or update with acq_rel clause and atomic update with acquire clause. * c-c++-common/gomp/atomic-18.c (foo): Adjust expected diagnostics wording, remove tests moved to atomic-17.c. * c-c++-common/gomp/atomic-21.c: Expect only 2 omp atomic release and 2 omp atomic acq_rel directives instead of 4 omp atomic release. * c-c++-common/gomp/atomic-25.c: New test. * c-c++-common/gomp/atomic-26.c: New test. * c-c++-common/gomp/atomic-27.c: New test. * c-c++-common/gomp/atomic-28.c: New test. * c-c++-common/gomp/atomic-29.c: New test. * c-c++-common/gomp/atomic-30.c: New test. * c-c++-common/goacc-gomp/atomic.c: Expect 1 omp atomic release and 1 omp atomic_acq_rel instead of 2 omp atomic release directives. * gcc.dg/gomp/atomic-5.c: Adjust expected error diagnostic wording. * g++.dg/gomp/atomic-18.C:Expect 4 omp atomic release and 1 omp atomic_acq_rel instead of 5 omp atomic release directives. libgomp/ * testsuite/libgomp.c-c++-common/atomic-19.c: New test. * testsuite/libgomp.c-c++-common/atomic-20.c: New test. * testsuite/libgomp.c-c++-common/atomic-21.c: New test.
This commit is contained in:
parent
b7f84702b3
commit
8122fbff77
28 changed files with 2089 additions and 125 deletions
|
@ -1223,8 +1223,8 @@ extern tree c_finish_omp_critical (location_t, tree, tree, tree);
|
|||
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);
|
||||
|
|
|
@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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, enum tree_code code,
|
|||
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, enum tree_code code,
|
|||
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, enum tree_code code,
|
|||
{
|
||||
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, enum tree_code code,
|
|||
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, enum tree_code code,
|
|||
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, enum tree_code code,
|
|||
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, enum tree_code code,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
504
gcc/c/c-parser.c
504
gcc/c/c-parser.c
|
@ -7663,10 +7663,21 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
|
|||
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 *parser, struct c_expr *after,
|
|||
= 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_parser *parser)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
{
|
||||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
|
||||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
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_parser *parser, bool openacc)
|
|||
/* 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 %<;%>");
|
||||
}
|
||||
|
||||
|
|
|
@ -12426,6 +12426,13 @@ build_binary_op (location_t location, enum tree_code code,
|
|||
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 ();
|
||||
}
|
||||
|
|
|
@ -40193,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
|
|||
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, cp_token *pragma_tok, bool openacc)
|
|||
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;
|
||||
|
|
|
@ -9956,7 +9956,7 @@ finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode,
|
|||
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;
|
||||
|
|
|
@ -2563,6 +2563,8 @@ dump_gimple_omp_atomic_load (pretty_printer *buffer, const gomp_atomic_load *gs,
|
|||
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_printer *buffer,
|
|||
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);
|
||||
|
|
28
gcc/gimple.h
28
gcc/gimple.h
|
@ -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 *g)
|
|||
}
|
||||
|
||||
|
||||
/* 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
|
||||
|
|
161
gcc/gimplify.c
161
gcc/gimplify.c
|
@ -13859,14 +13859,15 @@ goa_lhs_expr_p (tree expr, tree addr)
|
|||
|
||||
static int
|
||||
goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr,
|
||||
tree lhs_var)
|
||||
tree lhs_var, tree &target_expr, bool rhs)
|
||||
{
|
||||
tree expr = *expr_p;
|
||||
int saw_lhs;
|
||||
|
||||
if (goa_lhs_expr_p (expr, lhs_addr))
|
||||
{
|
||||
*expr_p = lhs_var;
|
||||
if (pre_p)
|
||||
*expr_p = lhs_var;
|
||||
return 1;
|
||||
}
|
||||
if (is_gimple_val (expr))
|
||||
|
@ -13878,11 +13879,11 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr,
|
|||
case tcc_binary:
|
||||
case tcc_comparison:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr,
|
||||
lhs_var);
|
||||
lhs_var, target_expr, true);
|
||||
/* FALLTHRU */
|
||||
case tcc_unary:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr,
|
||||
lhs_var);
|
||||
lhs_var, target_expr, true);
|
||||
break;
|
||||
case tcc_expression:
|
||||
switch (TREE_CODE (expr))
|
||||
|
@ -13894,36 +13895,131 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr,
|
|||
case TRUTH_XOR_EXPR:
|
||||
case BIT_INSERT_EXPR:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
|
||||
lhs_addr, lhs_var);
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
/* FALLTHRU */
|
||||
case TRUTH_NOT_EXPR:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
|
||||
lhs_addr, lhs_var);
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
break;
|
||||
case MODIFY_EXPR:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
/* FALLTHRU */
|
||||
case ADDR_EXPR:
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
|
||||
lhs_addr, lhs_var, target_expr, false);
|
||||
break;
|
||||
case COMPOUND_EXPR:
|
||||
/* Special-case __builtin_clear_padding call before
|
||||
__builtin_memcmp. */
|
||||
if (TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR)
|
||||
{
|
||||
tree fndecl = get_callee_fndecl (TREE_OPERAND (expr, 0));
|
||||
if (fndecl
|
||||
&& fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING)
|
||||
&& VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))))
|
||||
{
|
||||
saw_lhs = goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
|
||||
lhs_addr, lhs_var,
|
||||
target_expr, true);
|
||||
if (!saw_lhs)
|
||||
{
|
||||
expr = TREE_OPERAND (expr, 1);
|
||||
if (!pre_p)
|
||||
return goa_stabilize_expr (&expr, pre_p, lhs_addr,
|
||||
lhs_var, target_expr, true);
|
||||
*expr_p = expr;
|
||||
return goa_stabilize_expr (expr_p, pre_p, lhs_addr,
|
||||
lhs_var, target_expr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1),
|
||||
pre_p, lhs_addr, lhs_var,
|
||||
target_expr, rhs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Break out any preevaluations from cp_build_modify_expr. */
|
||||
for (; TREE_CODE (expr) == COMPOUND_EXPR;
|
||||
expr = TREE_OPERAND (expr, 1))
|
||||
gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p);
|
||||
if (pre_p)
|
||||
gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p);
|
||||
if (!pre_p)
|
||||
return goa_stabilize_expr (&expr, pre_p, lhs_addr, lhs_var,
|
||||
target_expr, rhs);
|
||||
*expr_p = expr;
|
||||
return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var);
|
||||
return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var,
|
||||
target_expr, rhs);
|
||||
case COND_EXPR:
|
||||
if (!goa_stabilize_expr (&TREE_OPERAND (expr, 0), NULL, lhs_addr,
|
||||
lhs_var, target_expr, true))
|
||||
break;
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p,
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 2), pre_p,
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
break;
|
||||
case TARGET_EXPR:
|
||||
if (TARGET_EXPR_INITIAL (expr))
|
||||
{
|
||||
if (expr == target_expr)
|
||||
saw_lhs = 1;
|
||||
else
|
||||
{
|
||||
saw_lhs = goa_stabilize_expr (&TARGET_EXPR_INITIAL (expr),
|
||||
pre_p, lhs_addr, lhs_var,
|
||||
target_expr, true);
|
||||
if (saw_lhs && target_expr == NULL_TREE && pre_p)
|
||||
target_expr = expr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case tcc_reference:
|
||||
if (TREE_CODE (expr) == BIT_FIELD_REF)
|
||||
if (TREE_CODE (expr) == BIT_FIELD_REF
|
||||
|| TREE_CODE (expr) == VIEW_CONVERT_EXPR)
|
||||
saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p,
|
||||
lhs_addr, lhs_var);
|
||||
lhs_addr, lhs_var, target_expr, true);
|
||||
break;
|
||||
case tcc_vl_exp:
|
||||
if (TREE_CODE (expr) == CALL_EXPR)
|
||||
{
|
||||
if (tree fndecl = get_callee_fndecl (expr))
|
||||
if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING)
|
||||
|| fndecl_built_in_p (fndecl, BUILT_IN_MEMCMP))
|
||||
{
|
||||
int nargs = call_expr_nargs (expr);
|
||||
for (int i = 0; i < nargs; i++)
|
||||
saw_lhs |= goa_stabilize_expr (&CALL_EXPR_ARG (expr, i),
|
||||
pre_p, lhs_addr, lhs_var,
|
||||
target_expr, true);
|
||||
}
|
||||
if (saw_lhs == 0 && VOID_TYPE_P (TREE_TYPE (expr)))
|
||||
{
|
||||
if (pre_p)
|
||||
gimplify_stmt (&expr, pre_p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (saw_lhs == 0)
|
||||
if (saw_lhs == 0 && pre_p)
|
||||
{
|
||||
enum gimplify_status gs;
|
||||
gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue);
|
||||
if (rhs)
|
||||
gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue);
|
||||
else
|
||||
gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_lvalue, fb_lvalue);
|
||||
if (gs != GS_ALL_DONE)
|
||||
saw_lhs = -1;
|
||||
}
|
||||
|
@ -13943,9 +14039,12 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
|
|||
tree tmp_load;
|
||||
gomp_atomic_load *loadstmt;
|
||||
gomp_atomic_store *storestmt;
|
||||
tree target_expr = NULL_TREE;
|
||||
|
||||
tmp_load = create_tmp_reg (type);
|
||||
if (rhs && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
|
||||
if (rhs
|
||||
&& goa_stabilize_expr (&rhs, pre_p, addr, tmp_load, target_expr,
|
||||
true) < 0)
|
||||
return GS_ERROR;
|
||||
|
||||
if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
|
||||
|
@ -13959,11 +14058,14 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
|
|||
{
|
||||
/* BIT_INSERT_EXPR is not valid for non-integral bitfield
|
||||
representatives. Use BIT_FIELD_REF on the lhs instead. */
|
||||
if (TREE_CODE (rhs) == BIT_INSERT_EXPR
|
||||
tree rhsarg = rhs;
|
||||
if (TREE_CODE (rhs) == COND_EXPR)
|
||||
rhsarg = TREE_OPERAND (rhs, 1);
|
||||
if (TREE_CODE (rhsarg) == BIT_INSERT_EXPR
|
||||
&& !INTEGRAL_TYPE_P (TREE_TYPE (tmp_load)))
|
||||
{
|
||||
tree bitpos = TREE_OPERAND (rhs, 2);
|
||||
tree op1 = TREE_OPERAND (rhs, 1);
|
||||
tree bitpos = TREE_OPERAND (rhsarg, 2);
|
||||
tree op1 = TREE_OPERAND (rhsarg, 1);
|
||||
tree bitsize;
|
||||
tree tmp_store = tmp_load;
|
||||
if (TREE_CODE (*expr_p) == OMP_ATOMIC_CAPTURE_OLD)
|
||||
|
@ -13972,17 +14074,25 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
|
|||
bitsize = bitsize_int (TYPE_PRECISION (TREE_TYPE (op1)));
|
||||
else
|
||||
bitsize = TYPE_SIZE (TREE_TYPE (op1));
|
||||
gcc_assert (TREE_OPERAND (rhs, 0) == tmp_load);
|
||||
tree t = build2_loc (EXPR_LOCATION (rhs),
|
||||
gcc_assert (TREE_OPERAND (rhsarg, 0) == tmp_load);
|
||||
tree t = build2_loc (EXPR_LOCATION (rhsarg),
|
||||
MODIFY_EXPR, void_type_node,
|
||||
build3_loc (EXPR_LOCATION (rhs), BIT_FIELD_REF,
|
||||
TREE_TYPE (op1), tmp_store, bitsize,
|
||||
bitpos), op1);
|
||||
build3_loc (EXPR_LOCATION (rhsarg),
|
||||
BIT_FIELD_REF, TREE_TYPE (op1),
|
||||
tmp_store, bitsize, bitpos), op1);
|
||||
if (TREE_CODE (rhs) == COND_EXPR)
|
||||
t = build3_loc (EXPR_LOCATION (rhs), COND_EXPR, void_type_node,
|
||||
TREE_OPERAND (rhs, 0), t, void_node);
|
||||
gimplify_and_add (t, pre_p);
|
||||
rhs = tmp_store;
|
||||
}
|
||||
if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
|
||||
!= GS_ALL_DONE)
|
||||
bool save_allow_rhs_cond_expr = gimplify_ctxp->allow_rhs_cond_expr;
|
||||
if (TREE_CODE (rhs) == COND_EXPR)
|
||||
gimplify_ctxp->allow_rhs_cond_expr = true;
|
||||
enum gimplify_status gs = gimplify_expr (&rhs, pre_p, NULL,
|
||||
is_gimple_val, fb_rvalue);
|
||||
gimplify_ctxp->allow_rhs_cond_expr = save_allow_rhs_cond_expr;
|
||||
if (gs != GS_ALL_DONE)
|
||||
return GS_ERROR;
|
||||
}
|
||||
|
||||
|
@ -13990,6 +14100,11 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
|
|||
rhs = tmp_load;
|
||||
storestmt
|
||||
= gimple_build_omp_atomic_store (rhs, OMP_ATOMIC_MEMORY_ORDER (*expr_p));
|
||||
if (TREE_CODE (*expr_p) != OMP_ATOMIC_READ && OMP_ATOMIC_WEAK (*expr_p))
|
||||
{
|
||||
gimple_omp_atomic_set_weak (loadstmt);
|
||||
gimple_omp_atomic_set_weak (storestmt);
|
||||
}
|
||||
gimplify_seq_add_stmt (pre_p, storestmt);
|
||||
switch (TREE_CODE (*expr_p))
|
||||
{
|
||||
|
|
321
gcc/omp-expand.c
321
gcc/omp-expand.c
|
@ -8487,22 +8487,58 @@ expand_omp_synch (struct omp_region *region)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 load_bb,
|
|||
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 load_bb, basic_block store_bb,
|
|||
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 *region)
|
|||
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,
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" } */
|
||||
#pragma omp atomic acquire , write /* { dg-error "incompatible with 'acquire' clause" } */
|
||||
i = v;
|
||||
#pragma omp atomic acquire , write /* { dg-error "incompatible with 'acq_rel' or 'acquire' clauses" } */
|
||||
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 } */
|
||||
}
|
||||
|
|
|
@ -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" } } */
|
||||
|
||||
|
|
50
gcc/testsuite/c-c++-common/gomp/atomic-25.c
Normal file
50
gcc/testsuite/c-c++-common/gomp/atomic-25.c
Normal file
|
@ -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; } }
|
||||
}
|
63
gcc/testsuite/c-c++-common/gomp/atomic-26.c
Normal file
63
gcc/testsuite/c-c++-common/gomp/atomic-26.c
Normal file
|
@ -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;
|
||||
}
|
41
gcc/testsuite/c-c++-common/gomp/atomic-27.c
Normal file
41
gcc/testsuite/c-c++-common/gomp/atomic-27.c
Normal file
|
@ -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;
|
||||
}
|
43
gcc/testsuite/c-c++-common/gomp/atomic-28.c
Normal file
43
gcc/testsuite/c-c++-common/gomp/atomic-28.c
Normal file
|
@ -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;
|
||||
}
|
43
gcc/testsuite/c-c++-common/gomp/atomic-29.c
Normal file
43
gcc/testsuite/c-c++-common/gomp/atomic-29.c
Normal file
|
@ -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;
|
||||
}
|
137
gcc/testsuite/c-c++-common/gomp/atomic-30.c
Normal file
137
gcc/testsuite/c-c++-common/gomp/atomic-30.c
Normal file
|
@ -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; } }
|
||||
}
|
|
@ -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" } }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1492,7 +1492,7 @@ dump_block_node (pretty_printer *pp, tree block, int spc, dump_flags_t flags)
|
|||
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_printer *pp, enum omp_memory_order mo)
|
|||
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, tree node, int spc, dump_flags_t flags,
|
|||
|
||||
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, tree node, int spc, dump_flags_t flags,
|
|||
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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
274
libgomp/testsuite/libgomp.c-c++-common/atomic-19.c
Normal file
274
libgomp/testsuite/libgomp.c-c++-common/atomic-19.c
Normal file
|
@ -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;
|
||||
}
|
203
libgomp/testsuite/libgomp.c-c++-common/atomic-20.c
Normal file
203
libgomp/testsuite/libgomp.c-c++-common/atomic-20.c
Normal file
|
@ -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;
|
||||
}
|
49
libgomp/testsuite/libgomp.c-c++-common/atomic-21.c
Normal file
49
libgomp/testsuite/libgomp.c-c++-common/atomic-21.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue