From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-io1-xd31.google.com (mail-io1-xd31.google.com [IPv6:2607:f8b0:4864:20::d31]) by sourceware.org (Postfix) with ESMTPS id 084953858C60 for ; Mon, 13 Sep 2021 11:58:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 084953858C60 Received: by mail-io1-xd31.google.com with SMTP id q3so11638292iot.3 for ; Mon, 13 Sep 2021 04:58:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=UvP9pDKjqvnpoAUz+jszSBRWCAqkI8WJgXBeUM+qmWE=; b=up2jcK6kWf1iJj8k4UGwCwFEcYNi3PW2NAW9ukuO6zTkHS0dcvkTKclqH3ovrMPQ1d +Gf2X7TQFinTvYBi4U6Y7qnYLEQq7Yj2G4u1il0OsX8pf90BqW/1kmDmGUjLJDvL3FSf YyjI3mu5Zq9wZ3jlLET5/BGQAUURnjT0vebRu0bHStw5OUlvcxmIheeAFj7ItF5xJ59V Hxq+XOz0n1QB3tFQkbJuM0JtMDvNwNkaTVSqd6W5K2eEN7V/zoVFUpey6/aj70DKd0q9 CbWZWa86MUfpJVmBlaEjUBAdDG5psGvE/9b9baPAWZ+bG6v8nCrGHDjIDiV82ExGm4Rr OsNw== X-Gm-Message-State: AOAM532cRy9u3obzykPysxkEgZk+gA5ZzT7JE4GYXc66Mxyrcer8U8gS dfc9ZpwdOKV0KcGxhL6GPjbfkX8TFliqCbh8ZaEv2Si8UkA= X-Google-Smtp-Source: ABdhPJzZSzP8YKeEZp9Jr7MDp/vigd6Z8OWEX2W9yzvN6AQnrP/qe0I03FMY0XjYZKffuOS7bdZ0IAJvEzqa5NI6YOs= X-Received: by 2002:a6b:dc1a:: with SMTP id s26mr5044437ioc.191.1631534283764; Mon, 13 Sep 2021 04:58:03 -0700 (PDT) MIME-Version: 1.0 References: <20210910184619.GD920497@tucnak> In-Reply-To: <20210910184619.GD920497@tucnak> From: Christophe Lyon Date: Mon, 13 Sep 2021 13:57:52 +0200 Message-ID: Subject: Re: openmp: Implement OpenMP 5.1 atomics, so far for C only To: Jakub Jelinek Cc: GCC Patches , Tobias Burnus X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org Content-Type: text/plain; charset="UTF-8" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Sep 2021 11:58:12 -0000 On Fri, Sep 10, 2021 at 8:47 PM Jakub Jelinek via Gcc-patches < gcc-patches@gcc.gnu.org> wrote: > Hi! > > This patch implements OpenMP 5.1 atomics (with clarifications from > upcoming 5.2). > The most important changes are that it is now possible to write (for C/C++, > for Fortran it was possible before already) min/max atomics and more > importantly > compare and exchange in various forms. > Also, acq_rel is now allowed on read/write and acq_rel/acquire are allowed > on > update, and there are new compare, weak and fail clauses. > > Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. > > C++ support will follow next week hopefully. Various new tests in > c-c++-common are now with { target c }, that is temporary until the C++ > support is there. > > 2021-09-10 Jakub Jelinek > > gcc/ > * tree-core.h (enum omp_memory_order): Add OMP_MEMORY_ORDER_MASK, > OMP_FAIL_MEMORY_ORDER_UNSPECIFIED, OMP_FAIL_MEMORY_ORDER_RELAXED, > OMP_FAIL_MEMORY_ORDER_ACQUIRE, OMP_FAIL_MEMORY_ORDER_RELEASE, > OMP_FAIL_MEMORY_ORDER_ACQ_REL, OMP_FAIL_MEMORY_ORDER_SEQ_CST and > OMP_FAIL_MEMORY_ORDER_MASK enumerators. > (OMP_FAIL_MEMORY_ORDER_SHIFT): Define. > * gimple-pretty-print.c (dump_gimple_omp_atomic_load, > dump_gimple_omp_atomic_store): Print [weak] for weak atomic > load/store. > * gimple.h (enum gf_mask): Change GF_OMP_ATOMIC_MEMORY_ORDER > to 6-bit mask, adjust GF_OMP_ATOMIC_NEED_VALUE value and add > GF_OMP_ATOMIC_WEAK. > (gimple_omp_atomic_weak_p, gimple_omp_atomic_set_weak): New inline > functions. > * tree.h (OMP_ATOMIC_WEAK): Define. > * tree-pretty-print.c (dump_omp_atomic_memory_order): Adjust for > fail memory order being encoded in the same enum and also print > fail clause if present. > (dump_generic_node): Print weak clause if OMP_ATOMIC_WEAK. > * gimplify.c (goa_stabilize_expr): Add target_expr and rhs > arguments, > handle pre_p == NULL case as a test mode that only returns value > but doesn't change gimplify nor change anything otherwise, adjust > recursive calls, add MODIFY_EXPR, ADDR_EXPR, COND_EXPR, TARGET_EXPR > and CALL_EXPR handling, adjust COMPOUND_EXPR handling for > __builtin_clear_padding calls, for !rhs gimplify as lvalue rather > than rvalue. > (gimplify_omp_atomic): Adjust goa_stabilize_expr caller. Handle > COND_EXPR rhs. Set weak flag on gimple load/store for > OMP_ATOMIC_WEAK. > * omp-expand.c (omp_memory_order_to_fail_memmodel): New function. > (omp_memory_order_to_memmodel): Adjust for fail clause encoded > in the same enum. > (expand_omp_atomic_cas): New function. > (expand_omp_atomic_pipeline): Use omp_memory_order_to_fail_memmodel > function. > (expand_omp_atomic): Attempt to optimize atomic compare and > exchange > using expand_omp_atomic_cas. > gcc/c-family/ > * c-common.h (c_finish_omp_atomic): Add r and weak arguments. > * c-omp.c: Include gimple-fold.h. > (c_finish_omp_atomic): Add r and weak arguments. Add support for > OpenMP 5.1 atomics. > gcc/c/ > * c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs > and > cond.value is >, < or == with omp_atomic_lhs as one of the > operands, > don't call build_conditional_expr, instead build a COND_EXPR > directly. > (c_parser_binary_expression): Avoid calling parser_build_binary_op > if omp_atomic_lhs even in more cases for >, < or ==. > (c_parser_omp_atomic): Update function comment for OpenMP 5.1 > atomics, > parse OpenMP 5.1 atomics and fail, compare and weak clauses, allow > acq_rel on atomic read/write and acq_rel/acquire clauses on update. > * c-typeck.c (build_binary_op): For flag_openmp only handle > MIN_EXPR/MAX_EXPR. > gcc/cp/ > * parser.c (cp_parser_omp_atomic): Allow acq_rel on atomic > read/write > and acq_rel/acquire clauses on update. > * semantics.c (finish_omp_atomic): Adjust c_finish_omp_atomic > caller. > gcc/testsuite/ > * c-c++-common/gomp/atomic-17.c (foo): Add tests for atomic read, > write or update with acq_rel clause and atomic update with acquire > clause. > * c-c++-common/gomp/atomic-18.c (foo): Adjust expected diagnostics > wording, remove tests moved to atomic-17.c. > * c-c++-common/gomp/atomic-21.c: Expect only 2 omp atomic release > and > 2 omp atomic acq_rel directives instead of 4 omp atomic release. > * c-c++-common/gomp/atomic-25.c: New test. > * c-c++-common/gomp/atomic-26.c: New test. > * c-c++-common/gomp/atomic-27.c: New test. > * c-c++-common/gomp/atomic-28.c: New test. > * c-c++-common/gomp/atomic-29.c: New test. > * c-c++-common/gomp/atomic-30.c: New test. > * c-c++-common/goacc-gomp/atomic.c: Expect 1 omp atomic release and > 1 omp atomic_acq_rel instead of 2 omp atomic release directives. > * gcc.dg/gomp/atomic-5.c: Adjust expected error diagnostic wording. > * g++.dg/gomp/atomic-18.C:Expect 4 omp atomic release and > 1 omp atomic_acq_rel instead of 5 omp atomic release directives. > libgomp/ > * testsuite/libgomp.c-c++-common/atomic-19.c: New test. > * testsuite/libgomp.c-c++-common/atomic-20.c: New test. > * testsuite/libgomp.c-c++-common/atomic-21.c: New test. > > --- gcc/tree-core.h.jj 2021-09-09 10:40:20.116260919 +0200 > +++ gcc/tree-core.h 2021-09-09 10:41:42.631084540 +0200 > @@ -583,8 +583,17 @@ enum omp_memory_order { > OMP_MEMORY_ORDER_ACQUIRE, > OMP_MEMORY_ORDER_RELEASE, > OMP_MEMORY_ORDER_ACQ_REL, > - OMP_MEMORY_ORDER_SEQ_CST > + OMP_MEMORY_ORDER_SEQ_CST, > + OMP_MEMORY_ORDER_MASK = 7, > + OMP_FAIL_MEMORY_ORDER_UNSPECIFIED = OMP_MEMORY_ORDER_UNSPECIFIED * 8, > + OMP_FAIL_MEMORY_ORDER_RELAXED = OMP_MEMORY_ORDER_RELAXED * 8, > + OMP_FAIL_MEMORY_ORDER_ACQUIRE = OMP_MEMORY_ORDER_ACQUIRE * 8, > + OMP_FAIL_MEMORY_ORDER_RELEASE = OMP_MEMORY_ORDER_RELEASE * 8, > + OMP_FAIL_MEMORY_ORDER_ACQ_REL = OMP_MEMORY_ORDER_ACQ_REL * 8, > + OMP_FAIL_MEMORY_ORDER_SEQ_CST = OMP_MEMORY_ORDER_SEQ_CST * 8, > + OMP_FAIL_MEMORY_ORDER_MASK = OMP_MEMORY_ORDER_MASK * 8 > }; > +#define OMP_FAIL_MEMORY_ORDER_SHIFT 3 > > /* There is a TYPE_QUAL value for each type qualifier. They can be > combined by bitwise-or to form the complete set of qualifiers for a > --- gcc/gimple-pretty-print.c.jj 2021-09-09 10:40:20.032262117 +0200 > +++ gcc/gimple-pretty-print.c 2021-09-09 10:41:42.625084625 +0200 > @@ -2563,6 +2563,8 @@ dump_gimple_omp_atomic_load (pretty_prin > gimple_omp_atomic_memory_order (gs)); > if (gimple_omp_atomic_need_value_p (gs)) > pp_string (buffer, " [needed]"); > + if (gimple_omp_atomic_weak_p (gs)) > + pp_string (buffer, " [weak]"); > newline_and_indent (buffer, spc + 2); > dump_generic_node (buffer, gimple_omp_atomic_load_lhs (gs), > spc, flags, false); > @@ -2597,6 +2599,8 @@ dump_gimple_omp_atomic_store (pretty_pri > pp_space (buffer); > if (gimple_omp_atomic_need_value_p (gs)) > pp_string (buffer, "[needed] "); > + if (gimple_omp_atomic_weak_p (gs)) > + pp_string (buffer, "[weak] "); > pp_left_paren (buffer); > dump_generic_node (buffer, gimple_omp_atomic_store_val (gs), > spc, flags, false); > --- gcc/gimple.h.jj 2021-09-09 10:40:20.041261988 +0200 > +++ gcc/gimple.h 2021-09-09 10:41:42.625084625 +0200 > @@ -194,8 +194,9 @@ enum gf_mask { > GF_OMP_RETURN_NOWAIT = 1 << 0, > > GF_OMP_SECTION_LAST = 1 << 0, > - GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 3) - 1, > - GF_OMP_ATOMIC_NEED_VALUE = 1 << 3, > + GF_OMP_ATOMIC_MEMORY_ORDER = (1 << 6) - 1, > + GF_OMP_ATOMIC_NEED_VALUE = 1 << 6, > + GF_OMP_ATOMIC_WEAK = 1 << 7, > GF_PREDICT_TAKEN = 1 << 15 > }; > > @@ -2446,6 +2447,29 @@ gimple_omp_atomic_set_need_value (gimple > } > > > +/* Return true if OMP atomic load/store statement G has the > + GF_OMP_ATOMIC_WEAK flag set. */ > + > +static inline bool > +gimple_omp_atomic_weak_p (const gimple *g) > +{ > + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) > + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); > + return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_WEAK) != 0; > +} > + > + > +/* Set the GF_OMP_ATOMIC_WEAK flag on G. */ > + > +static inline void > +gimple_omp_atomic_set_weak (gimple *g) > +{ > + if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD) > + GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE); > + g->subcode |= GF_OMP_ATOMIC_WEAK; > +} > + > + > /* Return the memory order of the OMP atomic load/store statement G. */ > > static inline enum omp_memory_order > --- gcc/tree.h.jj 2021-09-09 10:40:20.132260691 +0200 > +++ gcc/tree.h 2021-09-09 10:41:42.626084611 +0200 > @@ -1529,6 +1529,11 @@ class auto_suppress_location_wrappers > (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ > > OMP_ATOMIC_CAPTURE_NEW)->base.u.omp_atomic_memory_order) > > +/* Weak clause on OMP_ATOMIC*. */ > +#define OMP_ATOMIC_WEAK(NODE) \ > + (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ > + OMP_ATOMIC_CAPTURE_NEW)->base.public_flag) > + > /* True on a PRIVATE clause if its decl is kept around for debugging > information only and its DECL_VALUE_EXPR is supposed to point > to what it has been remapped to. */ > --- gcc/tree-pretty-print.c.jj 2021-09-09 10:40:20.131260705 +0200 > +++ gcc/tree-pretty-print.c 2021-09-09 10:41:42.626084611 +0200 > @@ -1492,7 +1492,7 @@ dump_block_node (pretty_printer *pp, tre > void > dump_omp_atomic_memory_order (pretty_printer *pp, enum omp_memory_order > mo) > { > - switch (mo) > + switch (mo & OMP_MEMORY_ORDER_MASK) > { > case OMP_MEMORY_ORDER_RELAXED: > pp_string (pp, " relaxed"); > @@ -1514,6 +1514,22 @@ dump_omp_atomic_memory_order (pretty_pri > default: > gcc_unreachable (); > } > + switch (mo & OMP_FAIL_MEMORY_ORDER_MASK) > + { > + case OMP_FAIL_MEMORY_ORDER_RELAXED: > + pp_string (pp, " fail(relaxed)"); > + break; > + case OMP_FAIL_MEMORY_ORDER_SEQ_CST: > + pp_string (pp, " fail(seq_cst)"); > + break; > + case OMP_FAIL_MEMORY_ORDER_ACQUIRE: > + pp_string (pp, " fail(acquire)"); > + break; > + case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED: > + break; > + default: > + gcc_unreachable (); > + } > } > > /* Helper to dump a MEM_REF node. */ > @@ -3629,6 +3645,8 @@ dump_generic_node (pretty_printer *pp, t > > case OMP_ATOMIC: > pp_string (pp, "#pragma omp atomic"); > + if (OMP_ATOMIC_WEAK (node)) > + pp_string (pp, " weak"); > dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node)); > newline_and_indent (pp, spc + 2); > dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false); > @@ -3649,6 +3667,8 @@ dump_generic_node (pretty_printer *pp, t > case OMP_ATOMIC_CAPTURE_OLD: > case OMP_ATOMIC_CAPTURE_NEW: > pp_string (pp, "#pragma omp atomic capture"); > + if (OMP_ATOMIC_WEAK (node)) > + pp_string (pp, " weak"); > dump_omp_atomic_memory_order (pp, OMP_ATOMIC_MEMORY_ORDER (node)); > newline_and_indent (pp, spc + 2); > dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false); > --- gcc/gimplify.c.jj 2021-09-09 10:40:20.057261760 +0200 > +++ gcc/gimplify.c 2021-09-10 18:29:35.243673591 +0200 > @@ -13725,14 +13725,15 @@ goa_lhs_expr_p (tree expr, tree addr) > > static int > goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, > - tree lhs_var) > + tree lhs_var, tree &target_expr, bool rhs) > { > tree expr = *expr_p; > int saw_lhs; > > if (goa_lhs_expr_p (expr, lhs_addr)) > { > - *expr_p = lhs_var; > + if (pre_p) > + *expr_p = lhs_var; > return 1; > } > if (is_gimple_val (expr)) > @@ -13744,11 +13745,11 @@ goa_stabilize_expr (tree *expr_p, gimple > case tcc_binary: > case tcc_comparison: > saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, > lhs_addr, > - lhs_var); > + lhs_var, target_expr, true); > /* FALLTHRU */ > case tcc_unary: > saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, > lhs_addr, > - lhs_var); > + lhs_var, target_expr, true); > break; > case tcc_expression: > switch (TREE_CODE (expr)) > @@ -13760,36 +13761,131 @@ goa_stabilize_expr (tree *expr_p, gimple > case TRUTH_XOR_EXPR: > case BIT_INSERT_EXPR: > saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, > - lhs_addr, lhs_var); > + lhs_addr, lhs_var, target_expr, > true); > /* FALLTHRU */ > case TRUTH_NOT_EXPR: > saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, > - lhs_addr, lhs_var); > + lhs_addr, lhs_var, target_expr, > true); > + break; > + case MODIFY_EXPR: > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, > + lhs_addr, lhs_var, target_expr, > true); > + /* FALLTHRU */ > + case ADDR_EXPR: > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, > + lhs_addr, lhs_var, target_expr, > false); > break; > case COMPOUND_EXPR: > + /* Special-case __builtin_clear_padding call before > + __builtin_memcmp. */ > + if (TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR) > + { > + tree fndecl = get_callee_fndecl (TREE_OPERAND (expr, 0)); > + if (fndecl > + && fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) > + && VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))) > + { > + saw_lhs = goa_stabilize_expr (&TREE_OPERAND (expr, 0), > pre_p, > + lhs_addr, lhs_var, > + target_expr, true); > + if (!saw_lhs) > + { > + expr = TREE_OPERAND (expr, 1); > + if (!pre_p) > + return goa_stabilize_expr (&expr, pre_p, lhs_addr, > + lhs_var, target_expr, > true); > + *expr_p = expr; > + return goa_stabilize_expr (expr_p, pre_p, lhs_addr, > + lhs_var, target_expr, > true); > + } > + else > + { > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, > 1), > + pre_p, lhs_addr, > lhs_var, > + target_expr, rhs); > + break; > + } > + } > + } > /* Break out any preevaluations from cp_build_modify_expr. */ > for (; TREE_CODE (expr) == COMPOUND_EXPR; > expr = TREE_OPERAND (expr, 1)) > - gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p); > + if (pre_p) > + gimplify_stmt (&TREE_OPERAND (expr, 0), pre_p); > + if (!pre_p) > + return goa_stabilize_expr (&expr, pre_p, lhs_addr, lhs_var, > + target_expr, rhs); > *expr_p = expr; > - return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var); > + return goa_stabilize_expr (expr_p, pre_p, lhs_addr, lhs_var, > + target_expr, rhs); > + case COND_EXPR: > + if (!goa_stabilize_expr (&TREE_OPERAND (expr, 0), NULL, lhs_addr, > + lhs_var, target_expr, true)) > + break; > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, > + lhs_addr, lhs_var, target_expr, > true); > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, > + lhs_addr, lhs_var, target_expr, > true); > + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 2), pre_p, > + lhs_addr, lhs_var, target_expr, > true); > + break; > + case TARGET_EXPR: > + if (TARGET_EXPR_INITIAL (expr)) > + { > + if (expr == target_expr) > + saw_lhs = 1; > + else > + { > + saw_lhs = goa_stabilize_expr (&TARGET_EXPR_INITIAL > (expr), > + pre_p, lhs_addr, lhs_var, > + target_expr, true); > + if (saw_lhs && target_expr == NULL_TREE && pre_p) > + target_expr = expr; > + } > + } > + break; > default: > break; > } > break; > case tcc_reference: > - if (TREE_CODE (expr) == BIT_FIELD_REF) > + if (TREE_CODE (expr) == BIT_FIELD_REF > + || TREE_CODE (expr) == VIEW_CONVERT_EXPR) > saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, > - lhs_addr, lhs_var); > + lhs_addr, lhs_var, target_expr, > true); > + break; > + case tcc_vl_exp: > + if (TREE_CODE (expr) == CALL_EXPR) > + { > + if (tree fndecl = get_callee_fndecl (expr)) > + if (fndecl_built_in_p (fndecl, BUILT_IN_CLEAR_PADDING) > + || fndecl_built_in_p (fndecl, BUILT_IN_MEMCMP)) > + { > + int nargs = call_expr_nargs (expr); > + for (int i = 0; i < nargs; i++) > + saw_lhs |= goa_stabilize_expr (&CALL_EXPR_ARG (expr, i), > + pre_p, lhs_addr, lhs_var, > + target_expr, true); > + } > + if (saw_lhs == 0 && VOID_TYPE_P (TREE_TYPE (expr))) > + { > + if (pre_p) > + gimplify_stmt (&expr, pre_p); > + return 0; > + } > + } > break; > default: > break; > } > > - if (saw_lhs == 0) > + if (saw_lhs == 0 && pre_p) > { > enum gimplify_status gs; > - gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue); > + if (rhs) > + gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_val, fb_rvalue); > + else > + gs = gimplify_expr (expr_p, pre_p, NULL, is_gimple_lvalue, > fb_lvalue); > if (gs != GS_ALL_DONE) > saw_lhs = -1; > } > @@ -13809,9 +13905,12 @@ gimplify_omp_atomic (tree *expr_p, gimpl > tree tmp_load; > gomp_atomic_load *loadstmt; > gomp_atomic_store *storestmt; > + tree target_expr = NULL_TREE; > > tmp_load = create_tmp_reg (type); > - if (rhs && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0) > + if (rhs > + && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load, target_expr, > + true) < 0) > return GS_ERROR; > > if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue) > @@ -13825,11 +13924,14 @@ gimplify_omp_atomic (tree *expr_p, gimpl > { > /* BIT_INSERT_EXPR is not valid for non-integral bitfield > representatives. Use BIT_FIELD_REF on the lhs instead. */ > - if (TREE_CODE (rhs) == BIT_INSERT_EXPR > + tree rhsarg = rhs; > + if (TREE_CODE (rhs) == COND_EXPR) > + rhsarg = TREE_OPERAND (rhs, 1); > + if (TREE_CODE (rhsarg) == BIT_INSERT_EXPR > && !INTEGRAL_TYPE_P (TREE_TYPE (tmp_load))) > { > - tree bitpos = TREE_OPERAND (rhs, 2); > - tree op1 = TREE_OPERAND (rhs, 1); > + tree bitpos = TREE_OPERAND (rhsarg, 2); > + tree op1 = TREE_OPERAND (rhsarg, 1); > tree bitsize; > tree tmp_store = tmp_load; > if (TREE_CODE (*expr_p) == OMP_ATOMIC_CAPTURE_OLD) > @@ -13838,17 +13940,25 @@ gimplify_omp_atomic (tree *expr_p, gimpl > bitsize = bitsize_int (TYPE_PRECISION (TREE_TYPE (op1))); > else > bitsize = TYPE_SIZE (TREE_TYPE (op1)); > - gcc_assert (TREE_OPERAND (rhs, 0) == tmp_load); > - tree t = build2_loc (EXPR_LOCATION (rhs), > + gcc_assert (TREE_OPERAND (rhsarg, 0) == tmp_load); > + tree t = build2_loc (EXPR_LOCATION (rhsarg), > MODIFY_EXPR, void_type_node, > - build3_loc (EXPR_LOCATION (rhs), > BIT_FIELD_REF, > - TREE_TYPE (op1), tmp_store, > bitsize, > - bitpos), op1); > + build3_loc (EXPR_LOCATION (rhsarg), > + BIT_FIELD_REF, TREE_TYPE (op1), > + tmp_store, bitsize, bitpos), > op1); > + if (TREE_CODE (rhs) == COND_EXPR) > + t = build3_loc (EXPR_LOCATION (rhs), COND_EXPR, void_type_node, > + TREE_OPERAND (rhs, 0), t, void_node); > gimplify_and_add (t, pre_p); > rhs = tmp_store; > } > - if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue) > - != GS_ALL_DONE) > + bool save_allow_rhs_cond_expr = gimplify_ctxp->allow_rhs_cond_expr; > + if (TREE_CODE (rhs) == COND_EXPR) > + gimplify_ctxp->allow_rhs_cond_expr = true; > + enum gimplify_status gs = gimplify_expr (&rhs, pre_p, NULL, > + is_gimple_val, fb_rvalue); > + gimplify_ctxp->allow_rhs_cond_expr = save_allow_rhs_cond_expr; > + if (gs != GS_ALL_DONE) > return GS_ERROR; > } > > @@ -13856,6 +13966,11 @@ gimplify_omp_atomic (tree *expr_p, gimpl > rhs = tmp_load; > storestmt > = gimple_build_omp_atomic_store (rhs, OMP_ATOMIC_MEMORY_ORDER > (*expr_p)); > + if (TREE_CODE (*expr_p) != OMP_ATOMIC_READ && OMP_ATOMIC_WEAK (*expr_p)) > + { > + gimple_omp_atomic_set_weak (loadstmt); > + gimple_omp_atomic_set_weak (storestmt); > + } > gimplify_seq_add_stmt (pre_p, storestmt); > switch (TREE_CODE (*expr_p)) > { > --- gcc/omp-expand.c.jj 2021-09-09 10:40:20.072261546 +0200 > +++ gcc/omp-expand.c 2021-09-10 15:05:47.315510567 +0200 > @@ -8487,22 +8487,58 @@ expand_omp_synch (struct omp_region *reg > } > } > > +/* Translate enum omp_memory_order to enum memmodel for the embedded > + fail clause in there. */ > + > +static enum memmodel > +omp_memory_order_to_fail_memmodel (enum omp_memory_order mo) > +{ > + switch (mo & OMP_FAIL_MEMORY_ORDER_MASK) > + { > + case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED: > + switch (mo & OMP_MEMORY_ORDER_MASK) > + { > + case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED; > + case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE; > + case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELAXED; > + case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQUIRE; > + case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST; > + default: break; > + } > + gcc_unreachable (); > + case OMP_FAIL_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED; > + case OMP_FAIL_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE; > + case OMP_FAIL_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST; > + default: gcc_unreachable (); > + } > +} > + > /* Translate enum omp_memory_order to enum memmodel. The two enums > are using different numbers so that OMP_MEMORY_ORDER_UNSPECIFIED > - is 0. */ > + is 0 and omp_memory_order has the fail mode encoded in it too. */ > > static enum memmodel > omp_memory_order_to_memmodel (enum omp_memory_order mo) > { > - switch (mo) > + enum memmodel ret, fail_ret; > + switch (mo & OMP_MEMORY_ORDER_MASK) > { > - case OMP_MEMORY_ORDER_RELAXED: return MEMMODEL_RELAXED; > - case OMP_MEMORY_ORDER_ACQUIRE: return MEMMODEL_ACQUIRE; > - case OMP_MEMORY_ORDER_RELEASE: return MEMMODEL_RELEASE; > - case OMP_MEMORY_ORDER_ACQ_REL: return MEMMODEL_ACQ_REL; > - case OMP_MEMORY_ORDER_SEQ_CST: return MEMMODEL_SEQ_CST; > + case OMP_MEMORY_ORDER_RELAXED: ret = MEMMODEL_RELAXED; break; > + case OMP_MEMORY_ORDER_ACQUIRE: ret = MEMMODEL_ACQUIRE; break; > + case OMP_MEMORY_ORDER_RELEASE: ret = MEMMODEL_RELEASE; break; > + case OMP_MEMORY_ORDER_ACQ_REL: ret = MEMMODEL_ACQ_REL; break; > + case OMP_MEMORY_ORDER_SEQ_CST: ret = MEMMODEL_SEQ_CST; break; > default: gcc_unreachable (); > } > + /* If we drop the -Winvalid-memory-model warning for C++17 P0418R2, > + we can just return ret here unconditionally. Otherwise, work around > + it here and make sure fail memmodel is not stronger. */ > + if ((mo & OMP_FAIL_MEMORY_ORDER_MASK) == > OMP_FAIL_MEMORY_ORDER_UNSPECIFIED) > + return ret; > + fail_ret = omp_memory_order_to_fail_memmodel (mo); > + if (fail_ret > ret) > + return fail_ret; > + return ret; > } > > /* A subroutine of expand_omp_atomic. Attempt to implement the atomic > @@ -8782,6 +8818,261 @@ expand_omp_atomic_fetch_op (basic_block > return true; > } > > +/* A subroutine of expand_omp_atomic. Attempt to implement the atomic > + compare and exchange as an ATOMIC_COMPARE_EXCHANGE internal function. > + Returns false if the expression is not of the proper form. */ > + > +static bool > +expand_omp_atomic_cas (basic_block load_bb, tree addr, > + tree loaded_val, tree stored_val, int index) > +{ > + /* We expect to find the following sequences: > + > + load_bb: > + GIMPLE_OMP_ATOMIC_LOAD (tmp, mem) > + > + store_bb: > + val = tmp == e ? d : tmp; > + GIMPLE_OMP_ATOMIC_STORE (val) > + > + or in store_bb instead: > + tmp2 = tmp == e; > + val = tmp2 ? d : tmp; > + GIMPLE_OMP_ATOMIC_STORE (val) > + > + or: > + tmp3 = VIEW_CONVERT_EXPR(tmp); > + val = e == tmp3 ? d : tmp; > + GIMPLE_OMP_ATOMIC_STORE (val) > + > + etc. */ > + > + > + basic_block store_bb = single_succ (load_bb); > + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (store_bb); > + gimple *store_stmt = gsi_stmt (gsi); > + if (!store_stmt || gimple_code (store_stmt) != GIMPLE_OMP_ATOMIC_STORE) > + return false; > + gsi_prev_nondebug (&gsi); > + if (gsi_end_p (gsi)) > + return false; > + gimple *condexpr_stmt = gsi_stmt (gsi); > + if (!is_gimple_assign (condexpr_stmt) > + || gimple_assign_rhs_code (condexpr_stmt) != COND_EXPR) > + return false; > + if (!operand_equal_p (gimple_assign_lhs (condexpr_stmt), stored_val, 0)) > + return false; > + gimple *cond_stmt = NULL; > + gimple *vce_stmt = NULL; > + gsi_prev_nondebug (&gsi); > + if (!gsi_end_p (gsi)) > + { > + cond_stmt = gsi_stmt (gsi); > + if (!is_gimple_assign (cond_stmt)) > + return false; > + if (gimple_assign_rhs_code (cond_stmt) == EQ_EXPR) > + { > + gsi_prev_nondebug (&gsi); > + if (!gsi_end_p (gsi)) > + { > + vce_stmt = gsi_stmt (gsi); > + if (!is_gimple_assign (vce_stmt) > + || gimple_assign_rhs_code (vce_stmt) != > VIEW_CONVERT_EXPR) > + return false; > + } > + } > + else if (gimple_assign_rhs_code (cond_stmt) == VIEW_CONVERT_EXPR) > + std::swap (vce_stmt, cond_stmt); > + else > + return false; > + if (vce_stmt) > + { > + tree vce_rhs = gimple_assign_rhs1 (vce_stmt); > + if (TREE_CODE (vce_rhs) != VIEW_CONVERT_EXPR > + || !operand_equal_p (TREE_OPERAND (vce_rhs, 0), loaded_val)) > + return false; > + if (!INTEGRAL_TYPE_P (TREE_TYPE (vce_rhs)) > + || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (loaded_val)) > + || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vce_rhs)), > + TYPE_SIZE (TREE_TYPE (loaded_val)))) > + return false; > + gsi_prev_nondebug (&gsi); > + if (!gsi_end_p (gsi)) > + return false; > + } > + } > + tree cond = gimple_assign_rhs1 (condexpr_stmt); > + tree cond_op1, cond_op2; > + if (cond_stmt) > + { > + if (!operand_equal_p (cond, gimple_assign_lhs (cond_stmt))) > + return false; > + cond_op1 = gimple_assign_rhs1 (cond_stmt); > + cond_op2 = gimple_assign_rhs2 (cond_stmt); > + } > + else if (TREE_CODE (cond) != EQ_EXPR && TREE_CODE (cond) != NE_EXPR) > + return false; > + else > + { > + cond_op1 = TREE_OPERAND (cond, 0); > + cond_op2 = TREE_OPERAND (cond, 1); > + } > + tree d; > + if (TREE_CODE (cond) == NE_EXPR) > + { > + if (!operand_equal_p (gimple_assign_rhs2 (condexpr_stmt), > loaded_val)) > + return false; > + d = gimple_assign_rhs3 (condexpr_stmt); > + } > + else if (!operand_equal_p (gimple_assign_rhs3 (condexpr_stmt), > loaded_val)) > + return false; > + else > + d = gimple_assign_rhs2 (condexpr_stmt); > + tree e = vce_stmt ? gimple_assign_lhs (vce_stmt) : loaded_val; > + if (operand_equal_p (e, cond_op1)) > + e = cond_op2; > + else if (operand_equal_p (e, cond_op2)) > + e = cond_op1; > + else > + return false; > + > + location_t loc = gimple_location (store_stmt); > + gimple *load_stmt = last_stmt (load_bb); > + bool need_new = gimple_omp_atomic_need_value_p (store_stmt); > + bool need_old = gimple_omp_atomic_need_value_p (load_stmt); > + bool weak = gimple_omp_atomic_weak_p (load_stmt); > + enum omp_memory_order omo = gimple_omp_atomic_memory_order (load_stmt); > + tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); > + tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel > (omo)); > + gcc_checking_assert (!need_old || !need_new); > + > + enum built_in_function fncode > + = (enum built_in_function) ((int) BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N > + + index + 1); > + tree cmpxchg = builtin_decl_explicit (fncode); > + if (cmpxchg == NULL_TREE) > + return false; > + tree itype = TREE_TYPE (TREE_TYPE (cmpxchg)); > + > + if (!can_compare_and_swap_p (TYPE_MODE (itype), true) > + || !can_atomic_load_p (TYPE_MODE (itype))) > + return false; > + > + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (loaded_val)); > + if (SCALAR_FLOAT_TYPE_P (type) && !vce_stmt) > + return false; > + > + gsi = gsi_for_stmt (store_stmt); > + if (!useless_type_conversion_p (itype, TREE_TYPE (e))) > + { > + tree ne = create_tmp_reg (itype); > + gimple *g = gimple_build_assign (ne, NOP_EXPR, e); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + e = ne; > + } > + if (!useless_type_conversion_p (itype, TREE_TYPE (d))) > + { > + tree nd = create_tmp_reg (itype); > + enum tree_code code; > + if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (d))) > + { > + code = VIEW_CONVERT_EXPR; > + d = build1 (VIEW_CONVERT_EXPR, itype, d); > + } > + else > + code = NOP_EXPR; > + gimple *g = gimple_build_assign (nd, code, d); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + d = nd; > + } > + > + tree ctype = build_complex_type (itype); > + int flag = int_size_in_bytes (itype) + (weak ? 256 : 0); > + gimple *g > + = gimple_build_call_internal (IFN_ATOMIC_COMPARE_EXCHANGE, 6, addr, > e, d, > + build_int_cst (integer_type_node, flag), > + mo, fmo); > + tree cres = create_tmp_reg (ctype); > + gimple_call_set_lhs (g, cres); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + > + if (cond_stmt || need_old || need_new) > + { > + tree im = create_tmp_reg (itype); > + g = gimple_build_assign (im, IMAGPART_EXPR, > + build1 (IMAGPART_EXPR, itype, cres)); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + > + tree re = NULL_TREE; > + if (need_old || need_new) > + { > + re = create_tmp_reg (itype); > + g = gimple_build_assign (re, REALPART_EXPR, > + build1 (REALPART_EXPR, itype, cres)); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + } > + > + if (cond_stmt) > + { > + g = gimple_build_assign (gimple_assign_lhs (cond_stmt), > + NOP_EXPR, im); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + } > + else if (need_new) > + { > + g = gimple_build_assign (create_tmp_reg (itype), COND_EXPR, > + build2 (NE_EXPR, boolean_type_node, > + im, build_zero_cst (itype)), > + d, re); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + re = gimple_assign_lhs (g); > + } > + > + if (need_old || need_new) > + { > + tree v = need_old ? loaded_val : stored_val; > + enum tree_code code; > + if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (v))) > + { > + code = VIEW_CONVERT_EXPR; > + re = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (v), re); > + } > + else if (!useless_type_conversion_p (TREE_TYPE (v), itype)) > + code = NOP_EXPR; > + else > + code = TREE_CODE (re); > + g = gimple_build_assign (v, code, re); > + gimple_set_location (g, loc); > + gsi_insert_before (&gsi, g, GSI_SAME_STMT); > + } > + } > + > + gsi_remove (&gsi, true); > + gsi = gsi_for_stmt (load_stmt); > + gsi_remove (&gsi, true); > + gsi = gsi_for_stmt (condexpr_stmt); > + gsi_remove (&gsi, true); > + if (cond_stmt) > + { > + gsi = gsi_for_stmt (cond_stmt); > + gsi_remove (&gsi, true); > + } > + if (vce_stmt) > + { > + gsi = gsi_for_stmt (vce_stmt); > + gsi_remove (&gsi, true); > + } > + > + return true; > +} > + > /* A subroutine of expand_omp_atomic. Implement the atomic operation as: > > oldval = *addr; > @@ -8825,13 +9116,8 @@ expand_omp_atomic_pipeline (basic_block > gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD); > location_t loc = gimple_location (gsi_stmt (si)); > enum omp_memory_order omo = gimple_omp_atomic_memory_order (gsi_stmt > (si)); > - enum memmodel imo = omp_memory_order_to_memmodel (omo); > - tree mo = build_int_cst (NULL, imo); > - if (imo == MEMMODEL_RELEASE) > - imo = MEMMODEL_RELAXED; > - else if (imo == MEMMODEL_ACQ_REL) > - imo = MEMMODEL_ACQUIRE; > - tree fmo = build_int_cst (NULL, imo); > + tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); > + tree fmo = build_int_cst (NULL, omp_memory_order_to_fail_memmodel > (omo)); > > /* For floating-point values, we'll need to view-convert them to > integers > so that we can perform the atomic compare and swap. Simplify the > @@ -9114,6 +9400,13 @@ expand_omp_atomic (struct omp_region *re > loaded_val, stored_val, > index)) > return; > > + /* When possible, use ATOMIC_COMPARE_EXCHANGE ifn without a > loop. */ > + if (store_bb == single_succ (load_bb) > + && !gimple_in_ssa_p (cfun) > + && expand_omp_atomic_cas (load_bb, addr, loaded_val, > stored_val, > + index)) > + return; > + > /* If we don't have specialized __sync builtins, try and > implement > as a compare and swap loop. */ > if (expand_omp_atomic_pipeline (load_bb, store_bb, addr, > --- gcc/c-family/c-common.h.jj 2021-09-09 10:40:19.928263599 +0200 > +++ gcc/c-family/c-common.h 2021-09-09 10:42:11.865667757 +0200 > @@ -1223,8 +1223,8 @@ extern tree c_finish_omp_critical (locat > extern tree c_finish_omp_ordered (location_t, tree, tree); > extern void c_finish_omp_barrier (location_t); > extern tree c_finish_omp_atomic (location_t, enum tree_code, enum > tree_code, > - tree, tree, tree, tree, tree, bool, > - enum omp_memory_order, bool = false); > + tree, tree, tree, tree, tree, tree, bool, > + enum omp_memory_order, bool, bool = > false); > extern bool c_omp_depend_t_p (tree); > extern void c_finish_omp_depobj (location_t, tree, enum > omp_clause_depend_kind, > tree); > --- gcc/c-family/c-omp.c.jj 2021-09-09 10:40:19.937263471 +0200 > +++ gcc/c-family/c-omp.c 2021-09-10 17:59:26.574281430 +0200 > @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. > #include "gimplify.h" > #include "langhooks.h" > #include "bitmap.h" > +#include "gimple-fold.h" > > > /* Complete a #pragma oacc wait construct. LOC is the location of > @@ -215,15 +216,17 @@ c_finish_omp_taskyield (location_t loc) > tree > c_finish_omp_atomic (location_t loc, enum tree_code code, > enum tree_code opcode, tree lhs, tree rhs, > - tree v, tree lhs1, tree rhs1, bool swapped, > - enum omp_memory_order memory_order, bool test) > + tree v, tree lhs1, tree rhs1, tree r, bool swapped, > + enum omp_memory_order memory_order, bool weak, > + bool test) > { > - tree x, type, addr, pre = NULL_TREE; > + tree x, type, addr, pre = NULL_TREE, rtmp = NULL_TREE, vtmp = NULL_TREE; > HOST_WIDE_INT bitpos = 0, bitsize = 0; > + enum tree_code orig_opcode = opcode; > > if (lhs == error_mark_node || rhs == error_mark_node > || v == error_mark_node || lhs1 == error_mark_node > - || rhs1 == error_mark_node) > + || rhs1 == error_mark_node || r == error_mark_node) > return error_mark_node; > > /* ??? According to one reading of the OpenMP spec, complex type are > @@ -243,6 +246,12 @@ c_finish_omp_atomic (location_t loc, enu > error_at (loc, "%<_Atomic%> expression in %<#pragma omp atomic%>"); > return error_mark_node; > } > + if (r && r != void_list_node && !INTEGRAL_TYPE_P (TREE_TYPE (r))) > + { > + error_at (loc, "%<#pragma omp atomic compare capture%> with > non-integral " > + "comparison result"); > + return error_mark_node; > + } > > if (opcode == RDIV_EXPR) > opcode = TRUNC_DIV_EXPR; > @@ -299,6 +308,7 @@ c_finish_omp_atomic (location_t loc, enu > x = build1 (OMP_ATOMIC_READ, type, addr); > SET_EXPR_LOCATION (x, loc); > OMP_ATOMIC_MEMORY_ORDER (x) = memory_order; > + gcc_assert (!weak); > if (blhs) > x = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), x, > bitsize_int (bitsize), bitsize_int (bitpos)); > @@ -313,12 +323,29 @@ c_finish_omp_atomic (location_t loc, enu > { > lhs = build3_loc (loc, BIT_FIELD_REF, TREE_TYPE (blhs), lhs, > bitsize_int (bitsize), bitsize_int (bitpos)); > - if (swapped) > + if (opcode == COND_EXPR) > + { > + bool save = in_late_binary_op; > + in_late_binary_op = true; > + std::swap (rhs, rhs1); > + rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true); > + in_late_binary_op = save; > + } > + else if (swapped) > rhs = build_binary_op (loc, opcode, rhs, lhs, true); > else if (opcode != NOP_EXPR) > rhs = build_binary_op (loc, opcode, lhs, rhs, true); > opcode = NOP_EXPR; > } > + else if (opcode == COND_EXPR) > + { > + bool save = in_late_binary_op; > + in_late_binary_op = true; > + std::swap (rhs, rhs1); > + rhs1 = build_binary_op (loc, EQ_EXPR, lhs, rhs1, true); > + in_late_binary_op = save; > + opcode = NOP_EXPR; > + } > else if (swapped) > { > rhs = build_binary_op (loc, opcode, rhs, lhs, true); > @@ -343,6 +370,100 @@ c_finish_omp_atomic (location_t loc, enu > if (blhs) > rhs = build3_loc (loc, BIT_INSERT_EXPR, type, new_lhs, > rhs, bitsize_int (bitpos)); > + if (orig_opcode == COND_EXPR) > + { > + if (error_operand_p (rhs1)) > + return error_mark_node; > + gcc_assert (TREE_CODE (rhs1) == EQ_EXPR); > + tree cmptype = TREE_TYPE (TREE_OPERAND (rhs1, 0)); > + if (SCALAR_FLOAT_TYPE_P (cmptype)) > + { > + bool clear_padding = false; > + if (BITS_PER_UNIT == 8 && CHAR_BIT == 8) > + { > + HOST_WIDE_INT sz = int_size_in_bytes (cmptype), i; > + gcc_assert (sz > 0); > + unsigned char *buf = XALLOCAVEC (unsigned char, sz); > + memset (buf, ~0, sz); > + clear_type_padding_in_mask (cmptype, buf); > + for (i = 0; i < sz; i++) > + if (buf[i] != (unsigned char) ~0) > + { > + clear_padding = true; > + break; > + } > + } > + tree inttype = NULL_TREE; > + if (!clear_padding && tree_fits_uhwi_p (TYPE_SIZE (cmptype))) > + { > + HOST_WIDE_INT prec = tree_to_uhwi (TYPE_SIZE (cmptype)); > + inttype = c_common_type_for_size (prec, 1); > + if (inttype > + && (!tree_int_cst_equal (TYPE_SIZE (cmptype), > + TYPE_SIZE (inttype)) > + || TYPE_PRECISION (inttype) != prec)) > + inttype = NULL_TREE; > + } > + if (inttype) > + { > + TREE_OPERAND (rhs1, 0) > + = build1_loc (loc, VIEW_CONVERT_EXPR, inttype, > + TREE_OPERAND (rhs1, 0)); > + TREE_OPERAND (rhs1, 1) > + = build1_loc (loc, VIEW_CONVERT_EXPR, inttype, > + TREE_OPERAND (rhs1, 1)); > + } > + else > + { > + tree pcmptype = build_pointer_type (cmptype); > + tree tmp1 = create_tmp_var_raw (cmptype); > + TREE_ADDRESSABLE (tmp1) = 1; > + DECL_CONTEXT (tmp1) = current_function_decl; > + tmp1 = build4 (TARGET_EXPR, cmptype, tmp1, > + TREE_OPERAND (rhs1, 0), NULL, NULL); > + tmp1 = build1 (ADDR_EXPR, pcmptype, tmp1); > + tree tmp2 = create_tmp_var_raw (cmptype); > + TREE_ADDRESSABLE (tmp2) = 1; > + DECL_CONTEXT (tmp2) = current_function_decl; > + tmp2 = build4 (TARGET_EXPR, cmptype, tmp2, > + TREE_OPERAND (rhs1, 1), NULL, NULL); > + tmp2 = build1 (ADDR_EXPR, pcmptype, tmp2); > + tree fndecl = builtin_decl_explicit (BUILT_IN_MEMCMP); > + rhs1 = build_call_expr_loc (loc, fndecl, 3, tmp1, tmp2, > + TYPE_SIZE_UNIT (cmptype)); > + rhs1 = build2 (EQ_EXPR, boolean_type_node, rhs1, > + integer_zero_node); > + if (clear_padding) > + { > + fndecl = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING); > + tree cp1 = build_call_expr_loc (loc, fndecl, 1, tmp1); > + tree cp2 = build_call_expr_loc (loc, fndecl, 1, tmp2); > + rhs1 = omit_two_operands_loc (loc, boolean_type_node, > + rhs1, cp2, cp1); > + } > + } > + } > + if (r) > + { > + tree var = create_tmp_var (boolean_type_node); > + DECL_CONTEXT (var) = current_function_decl; > + rtmp = build4 (TARGET_EXPR, boolean_type_node, var, > + NULL, NULL, NULL); > + save = in_late_binary_op; > + in_late_binary_op = true; > + x = build_modify_expr (loc, var, NULL_TREE, NOP_EXPR, > + loc, rhs1, NULL_TREE); > + in_late_binary_op = save; > + if (x == error_mark_node) > + return error_mark_node; > + gcc_assert (TREE_CODE (x) == MODIFY_EXPR > + && TREE_OPERAND (x, 0) == var); > + TREE_OPERAND (x, 0) = rtmp; > + rhs1 = omit_one_operand_loc (loc, boolean_type_node, x, rtmp); > + } > + rhs = build3_loc (loc, COND_EXPR, type, rhs1, rhs, new_lhs); > + rhs1 = NULL_TREE; > + } > > /* Punt the actual generation of atomic operations to common code. */ > if (code == OMP_ATOMIC) > @@ -350,6 +471,7 @@ c_finish_omp_atomic (location_t loc, enu > x = build2 (code, type, addr, rhs); > SET_EXPR_LOCATION (x, loc); > OMP_ATOMIC_MEMORY_ORDER (x) = memory_order; > + OMP_ATOMIC_WEAK (x) = weak; > > /* Generally it is hard to prove lhs1 and lhs are the same memory > location, just diagnose different variables. */ > @@ -412,8 +534,25 @@ c_finish_omp_atomic (location_t loc, enu > bitsize_int (bitsize), bitsize_int (bitpos)); > type = TREE_TYPE (blhs); > } > - x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, > + if (r) > + { > + vtmp = create_tmp_var (TREE_TYPE (x)); > + DECL_CONTEXT (vtmp) = current_function_decl; > + } > + else > + vtmp = v; > + x = build_modify_expr (loc, vtmp, NULL_TREE, NOP_EXPR, > loc, x, NULL_TREE); > + if (x == error_mark_node) > + return error_mark_node; > + if (r) > + { > + vtmp = build4 (TARGET_EXPR, boolean_type_node, vtmp, > + NULL, NULL, NULL); > + gcc_assert (TREE_CODE (x) == MODIFY_EXPR > + && TREE_OPERAND (x, 0) == TARGET_EXPR_SLOT (vtmp)); > + TREE_OPERAND (x, 0) = vtmp; > + } > if (rhs1 && rhs1 != orig_lhs) > { > tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, false); > @@ -446,6 +585,28 @@ c_finish_omp_atomic (location_t loc, enu > > if (pre) > x = omit_one_operand_loc (loc, type, x, pre); > + if (r && r != void_list_node) > + { > + in_late_binary_op = true; > + tree x2 = build_modify_expr (loc, r, NULL_TREE, NOP_EXPR, > + loc, rtmp, NULL_TREE); > + in_late_binary_op = save; > + if (x2 == error_mark_node) > + return error_mark_node; > + x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x); > + } > + if (v && vtmp != v) > + { > + in_late_binary_op = true; > + tree x2 = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR, > + loc, vtmp, NULL_TREE); > + in_late_binary_op = save; > + if (x2 == error_mark_node) > + return error_mark_node; > + x2 = build3_loc (loc, COND_EXPR, void_type_node, rtmp, > + void_node, x2); > + x = omit_one_operand_loc (loc, TREE_TYPE (x2), x2, x); > + } > return x; > } > > --- gcc/c/c-parser.c.jj 2021-09-09 10:40:19.956263200 +0200 > +++ gcc/c/c-parser.c 2021-09-10 17:06:10.966650277 +0200 > @@ -7663,10 +7663,21 @@ c_parser_conditional_expression (c_parse > c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; > location_t loc1 = make_location (exp1.get_start (), exp1.src_range); > location_t loc2 = make_location (exp2.get_start (), exp2.src_range); > - ret.value = build_conditional_expr (colon_loc, cond.value, > - cond.original_code == > C_MAYBE_CONST_EXPR, > - exp1.value, exp1.original_type, loc1, > - exp2.value, exp2.original_type, > loc2); > + if (__builtin_expect (omp_atomic_lhs != NULL, 0) > + && (TREE_CODE (cond.value) == GT_EXPR > + || TREE_CODE (cond.value) == LT_EXPR > + || TREE_CODE (cond.value) == EQ_EXPR) > + && c_tree_equal (exp2.value, omp_atomic_lhs) > + && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) > + || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) > + ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE > (omp_atomic_lhs), > + cond.value, exp1.value, exp2.value); > + else > + ret.value > + = build_conditional_expr (colon_loc, cond.value, > + cond.original_code == C_MAYBE_CONST_EXPR, > + exp1.value, exp1.original_type, loc1, > + exp2.value, exp2.original_type, loc2); > ret.original_code = ERROR_MARK; > if (exp1.value == error_mark_node || exp2.value == error_mark_node) > ret.original_type = NULL; > @@ -7849,15 +7860,27 @@ c_parser_binary_expression (c_parser *pa > = convert_lvalue_to_rvalue (stack[sp].loc, > \ > stack[sp].expr, true, true); > \ > if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 > \ > - && c_parser_peek_token (parser)->type == CPP_SEMICOLON > \ > - && ((1 << stack[sp].prec) > \ > - & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << > PREC_BITAND) \ > - | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT))) > \ > + && ((c_parser_next_token_is (parser, CPP_SEMICOLON) > \ > + && ((1 << stack[sp].prec) > \ > + & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) > \ > + | (1 << PREC_BITAND) | (1 << PREC_SHIFT) > \ > + | (1 << PREC_ADD) | (1 << PREC_MULT) > \ > + | (1 << PREC_EQ)))) > \ > + || ((c_parser_next_token_is (parser, CPP_QUERY) > \ > + || (omp_atomic_lhs == void_list_node > \ > + && c_parser_next_token_is (parser, > CPP_CLOSE_PAREN))) \ > + && (stack[sp].prec == PREC_REL || stack[sp].prec == > PREC_EQ)))\ > && stack[sp].op != TRUNC_MOD_EXPR > \ > + && stack[sp].op != GE_EXPR > \ > + && stack[sp].op != LE_EXPR > \ > + && stack[sp].op != NE_EXPR > \ > && stack[0].expr.value != error_mark_node > \ > && stack[1].expr.value != error_mark_node > \ > - && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs) > \ > - || c_tree_equal (stack[1].expr.value, omp_atomic_lhs))) > \ > + && (omp_atomic_lhs == void_list_node > \ > + || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) > \ > + || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) > \ > + || (stack[sp].op == EQ_EXPR > \ > + && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) > \ > { > \ > tree t = make_node (stack[1].op); > \ > TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); > \ > @@ -17655,14 +17678,45 @@ c_parser_omp_allocate (location_t loc, c > capture-block: > { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = > expr; } > > - where x and v are lvalue expressions with scalar type. > + OpenMP 5.1: > + # pragma omp atomic compare new-line > + conditional-update-atomic > + > + # pragma omp atomic compare capture new-line > + conditional-update-capture-atomic > + > + conditional-update-atomic: > + cond-expr-stmt | cond-update-stmt > + cond-expr-stmt: > + x = expr ordop x ? expr : x; > + x = x ordop expr ? expr : x; > + x = x == e ? d : x; > + cond-update-stmt: > + if (expr ordop x) { x = expr; } > + if (x ordop expr) { x = expr; } > + if (x == e) { x = d; } > + ordop: > + <, > > + conditional-update-capture-atomic: > + v = cond-expr-stmt > + { v = x; cond-expr-stmt } > + { cond-expr-stmt v = x; } > + { v = x; cond-update-stmt } > + { cond-update-stmt v = x; } > + if (x == e) { x = d; } else { v = x; } > + { r = x == e; if (r) { x = d; } } > + { r = x == e; if (r) { x = d; } else { v = x; } } > + > + where x, r and v are lvalue expressions with scalar type, > + expr, e and d are expressions with scalar type and e might be > + the same as v. > > LOC is the location of the #pragma token. */ > > static void > c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) > { > - tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE; > + tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; > tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; > tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = > NULL_TREE; > enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; > @@ -17674,6 +17728,12 @@ c_parser_omp_atomic (location_t loc, c_p > bool non_lvalue_p; > bool first = true; > tree clauses = NULL_TREE; > + bool capture = false; > + bool compare = false; > + bool weak = false; > + enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; > + bool no_semicolon = false; > + bool extra_scope = false; > > while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) > { > @@ -17692,6 +17752,10 @@ c_parser_omp_atomic (location_t loc, c_p > enum tree_code new_code = ERROR_MARK; > enum omp_memory_order new_memory_order > = OMP_MEMORY_ORDER_UNSPECIFIED; > + bool new_capture = false; > + bool new_compare = false; > + bool new_weak = false; > + enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; > > if (!strcmp (p, "read")) > new_code = OMP_ATOMIC_READ; > @@ -17699,7 +17763,7 @@ c_parser_omp_atomic (location_t loc, c_p > new_code = NOP_EXPR; > else if (!strcmp (p, "update")) > new_code = OMP_ATOMIC; > - else if (!strcmp (p, "capture")) > + else if (openacc && !strcmp (p, "capture")) > new_code = OMP_ATOMIC_CAPTURE_NEW; > else if (openacc) > { > @@ -17707,6 +17771,47 @@ c_parser_omp_atomic (location_t loc, c_p > error_at (cloc, "expected %, %, %, " > "or % 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 %, % > " > + "or %"); > + parens.skip_until_found_close (parser); > + continue; > + } > else if (!strcmp (p, "seq_cst")) > new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; > else if (!strcmp (p, "acq_rel")) > @@ -17727,8 +17832,9 @@ c_parser_omp_atomic (location_t loc, c_p > { > p = NULL; > error_at (cloc, "expected %, %, %, " > - "%, %, %, " > - "%, % or % > clause"); > + "%, %, %, > %, " > + "%, %, %, " > + "% or % clause"); > } > if (p) > { > @@ -17751,6 +17857,27 @@ c_parser_omp_atomic (location_t loc, c_p > else > memory_order = new_memory_order; > } > + else if (new_capture) > + { > + if (capture) > + error_at (cloc, "too many %qs clauses", "capture"); > + else > + capture = true; > + } > + else if (new_compare) > + { > + if (compare) > + error_at (cloc, "too many %qs clauses", "compare"); > + else > + compare = true; > + } > + else if (new_weak) > + { > + if (weak) > + error_at (cloc, "too many %qs clauses", "weak"); > + else > + weak = true; > + } > c_parser_consume_token (parser); > continue; > } > @@ -17761,6 +17888,30 @@ c_parser_omp_atomic (location_t loc, c_p > > if (code == ERROR_MARK) > code = OMP_ATOMIC; > + if (capture) > + { > + if (code != OMP_ATOMIC) > + error_at (loc, "%qs clause is incompatible with % or > % " > + "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 % or > % " > + "clauses", "compare"); > + compare = false; > + } > + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) > + { > + error_at (loc, "%qs clause requires %qs clause", "fail", "compare"); > + fail = OMP_MEMORY_ORDER_UNSPECIFIED; > + } > + if (weak && !compare) > + { > + error_at (loc, "%qs clause requires %qs clause", "weak", "compare"); > + weak = false; > + } > if (openacc) > memory_order = OMP_MEMORY_ORDER_RELAXED; > else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) > @@ -17785,7 +17936,6 @@ c_parser_omp_atomic (location_t loc, c_p > memory_order = OMP_MEMORY_ORDER_ACQUIRE; > break; > case NOP_EXPR: /* atomic write */ > - case OMP_ATOMIC: > memory_order = OMP_MEMORY_ORDER_RELEASE; > break; > default: > @@ -17801,36 +17951,32 @@ c_parser_omp_atomic (location_t loc, c_p > switch (code) > { > case OMP_ATOMIC_READ: > - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL > - || memory_order == OMP_MEMORY_ORDER_RELEASE) > + if (memory_order == OMP_MEMORY_ORDER_RELEASE) > { > error_at (loc, "%<#pragma omp atomic read%> incompatible with " > - "% or % clauses"); > + "% 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 > " > - "% or % 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 " > - "% or % clauses"); > + "% clause"); > memory_order = OMP_MEMORY_ORDER_SEQ_CST; > } > + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) > + memory_order = OMP_MEMORY_ORDER_RELEASE; > break; > default: > break; > } > + if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) > + memory_order > + = (enum omp_memory_order) (memory_order > + | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); > > switch (code) > { > @@ -17879,6 +18025,9 @@ c_parser_omp_atomic (location_t loc, c_p > c_parser_consume_token (parser); > structured_block = true; > } > + else if (compare > + && c_parser_next_token_is_keyword (parser, RID_IF)) > + break; > else > { > v = c_parser_cast_expression (parser, NULL).value; > @@ -17890,6 +18039,12 @@ c_parser_omp_atomic (location_t loc, c_p > v = non_lvalue (v); > if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) > goto saw_error; > + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) > + { > + eloc = c_parser_peek_token (parser)->location; > + error_at (eloc, "expected expression"); > + goto saw_error; > + } > } > break; > default: > @@ -17899,6 +18054,179 @@ c_parser_omp_atomic (location_t loc, c_p > /* For structured_block case we don't know yet whether > old or new x should be captured. */ > restart: > + if (compare && c_parser_next_token_is_keyword (parser, RID_IF)) > + { > + c_parser_consume_token (parser); > + > + matching_parens parens; > + if (!parens.require_open (parser)) > + goto saw_error; > + eloc = c_parser_peek_token (parser)->location; > + c_expr cmp_expr; > + if (r) > + { > + cmp_expr = c_parser_cast_expression (parser, NULL); > + cmp_expr = default_function_array_conversion (eloc, cmp_expr); > + } > + else > + cmp_expr = c_parser_binary_expression (parser, NULL, > void_list_node); > + parens.skip_until_found_close (parser); > + if (cmp_expr.value == error_mark_node) > + goto saw_error; > + if (r) > + { > + if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) > + goto bad_if; > + cmp_expr.value = rhs1; > + rhs1 = NULL_TREE; > + gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); > + } > + if (TREE_CODE (cmp_expr.value) == EQ_EXPR) > + ; > + else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) > + { > + error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), > + "expected %<==%> comparison in % 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 % " > + "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 %"); > + 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 %"); > + 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 %"); > + /* 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, "% clause requires atomic equality > comparison"); > + weak = false; > + } > if (unfolded_lhs && unfolded_lhs1 > && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) > { > @@ -18147,12 +18575,12 @@ done: > stmt = error_mark_node; > } > else > - stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, > rhs1, > - swapped, memory_order); > + stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, > rhs1, r, > + swapped, memory_order, weak); > if (stmt != error_mark_node) > add_stmt (stmt); > > - if (!structured_block) > + if (!structured_block && !no_semicolon) > c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); > } > > --- gcc/c/c-typeck.c.jj 2021-09-09 10:40:19.979262872 +0200 > +++ gcc/c/c-typeck.c 2021-09-09 10:41:42.630084554 +0200 > @@ -12426,6 +12426,13 @@ build_binary_op (location_t location, en > maybe_warn_bool_compare (location, code, orig_op0, orig_op1); > break; > > + case MIN_EXPR: > + case MAX_EXPR: > + /* Used for OpenMP atomics. */ > + gcc_assert (flag_openmp); > + common = 1; > + break; > + > default: > gcc_unreachable (); > } > --- gcc/cp/parser.c.jj 2021-09-09 10:40:19.996262630 +0200 > +++ gcc/cp/parser.c 2021-09-09 10:41:42.623084654 +0200 > @@ -40193,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser, > memory_order = OMP_MEMORY_ORDER_ACQUIRE; > break; > case NOP_EXPR: /* atomic write */ > - case OMP_ATOMIC: > memory_order = OMP_MEMORY_ORDER_RELEASE; > break; > default: > @@ -40209,31 +40208,24 @@ cp_parser_omp_atomic (cp_parser *parser, > switch (code) > { > case OMP_ATOMIC_READ: > - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL > - || memory_order == OMP_MEMORY_ORDER_RELEASE) > + if (memory_order == OMP_MEMORY_ORDER_RELEASE) > { > error_at (loc, "%<#pragma omp atomic read%> incompatible with " > - "% or % clauses"); > + "% 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 > " > - "% or % 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 " > - "% or % clauses"); > + "% clause"); > memory_order = OMP_MEMORY_ORDER_SEQ_CST; > } > + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) > + memory_order = OMP_MEMORY_ORDER_RELEASE; > break; > default: > break; > --- gcc/cp/semantics.c.jj 2021-09-09 10:40:26.093175709 +0200 > +++ gcc/cp/semantics.c 2021-09-09 10:59:17.762032066 +0200 > @@ -9956,7 +9956,7 @@ finish_omp_atomic (location_t loc, enum > return; > } > stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, > - v, lhs1, rhs1, swapped, mo, > + v, lhs1, rhs1, NULL_TREE, swapped, mo, > false, > processing_template_decl != 0); > if (stmt == error_mark_node) > return; > --- gcc/testsuite/c-c++-common/gomp/atomic-17.c.jj 2021-09-09 > 10:40:20.088261318 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-17.c 2021-09-09 > 10:41:42.624084639 +0200 > @@ -22,8 +22,18 @@ foo () > v = i = i + 1; > #pragma omp atomic read acquire > v = i; > + #pragma omp atomic acq_rel read > + v = i; > #pragma omp atomic release,write > i = v; > + #pragma omp atomic write,acq_rel > + i = v; > #pragma omp atomic hint(1),update,release > f = f + 2.0; > + #pragma omp atomic update ,acquire > + i = i + 1; > + #pragma omp atomic acq_rel update > + i = i + 1; > + #pragma omp atomic acq_rel,hint(0) > + i = i + 1; > } > --- gcc/testsuite/c-c++-common/gomp/atomic-18.c.jj 2021-09-09 > 10:40:20.088261318 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-18.c 2021-09-09 > 10:41:42.624084639 +0200 > @@ -8,28 +8,18 @@ foo (int j) > i = i + 1; > #pragma omp atomic seq_cst release /* { dg-error "too many memory > order clauses" } */ > i = i + 1; > - #pragma omp atomic read,release /* { dg-error "incompatible with > 'acq_rel' or 'release' clauses" } */ > + #pragma omp atomic read,release /* { dg-error "incompatible with > 'release' clause" } */ > v = i; > - #pragma omp atomic acq_rel read /* { dg-error "incompatible with > 'acq_rel' or 'release' clauses" } */ > - v = i; > - #pragma omp atomic write acq_rel /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > - i = v; > - #pragma omp atomic acquire , write /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > + #pragma omp atomic acquire , write /* { dg-error "incompatible with > 'acquire' clause" } */ > i = v; > - #pragma omp atomic update ,acquire /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > - i = i + 1; > - #pragma omp atomic acq_rel update /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > - i = i + 1; > - #pragma omp atomic acq_rel,hint(0) /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > - i = i + 1; > - #pragma omp atomic acquire /* { dg-error "incompatible with > 'acq_rel' or 'acquire' clauses" } */ > - i = i + 1; > - #pragma omp atomic capture hint (0) capture /* { dg-error "too many > atomic clauses" } */ > + #pragma omp atomic capture hint (0) capture /* { dg-error "too many > 'capture' clauses" "" { target c } } */ > + /* { dg-error "too many atomic > clauses" "" { target c++ } .-1 } */ > v = i = i + 1; > #pragma omp atomic hint(j + 2) /* { dg-error "constant integer > expression" } */ > i = i + 1; > #pragma omp atomic hint(f) /* { dg-error "integ" } */ > i = i + 1; > - #pragma omp atomic foobar /* { dg-error "expected 'read', > 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or > 'hint' clause" } */ > - i = i + 1; /* { dg-error "expected end of > line before" "" { target *-*-* } .-1 } */ > + #pragma omp atomic foobar /* { dg-error "expected 'read', > 'write', 'update', 'capture', 'compare', 'weak', 'fail', 'seq_cst', > 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" { target c } } */ > + /* { dg-error "expected 'read', > 'write', 'update', 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or > 'hint' clause" "" { target c++ } .-1 } */ > + i = i + 1; /* { dg-error "expected end of > line before" "" { target *-*-* } .-2 } */ > } > --- gcc/testsuite/c-c++-common/gomp/atomic-21.c.jj 2020-04-15 > 09:58:30.369649495 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-21.c 2021-09-09 > 17:25:18.782025085 +0200 > @@ -1,6 +1,7 @@ > /* { dg-do compile } */ > /* { dg-additional-options "-fdump-tree-original" } */ > -/* { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" } > } */ > +/* { dg-final { scan-tree-dump-times "omp atomic release" 2 "original" } > } */ > +/* { dg-final { scan-tree-dump-times "omp atomic acq_rel" 2 "original" } > } */ > /* { dg-final { scan-tree-dump-times "omp atomic read acquire" 1 > "original" } } */ > /* { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 1 > "original" } } */ > > --- gcc/testsuite/c-c++-common/gomp/atomic-25.c.jj 2021-09-09 > 10:41:42.624084639 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-25.c 2021-09-10 > 13:18:43.096258564 +0200 > @@ -0,0 +1,50 @@ > +/* { dg-do compile { target c } } */ > + > +int x, r, z; > +double d, v; > +long double ld; > + > +void > +foo (int y, double e, long double f) > +{ > + #pragma omp atomic compare update seq_cst > + x = x > y ? y : x; > + #pragma omp atomic compare relaxed > + d = e > d ? e : d; > + #pragma omp atomic compare > + d = f < d ? f : d; > + #pragma omp atomic compare seq_cst fail(relaxed) > + x = 12U < x ? 12U : x; > + #pragma omp atomic compare > + x = x == 7 ? 24 : x; > + #pragma omp atomic compare > + x = x == 123UL ? 256LL : x; > + #pragma omp atomic compare > + ld = ld == f ? f + 5.0L : ld; > + #pragma omp atomic compare > + if (x == 9) { x = 5; } > + #pragma omp atomic compare > + if (x > 5) { x = 5; } > + #pragma omp atomic compare > + if (7 > x) { x = 7; } > + #pragma omp atomic compare update capture seq_cst fail(acquire) > + v = d = f > d ? f : d; > + #pragma omp atomic update capture compare > + v = x = x < 24ULL ? 24ULL : x; > + #pragma omp atomic compare, capture, update > + v = x = x == e ? f : x; > + #pragma omp atomic capture compare > + { v = d; if (d > e) { d = e; } } > + #pragma omp atomic compare capture > + { if (e < d) { d = e; } v = d; } > + #pragma omp atomic compare capture > + { y = x; if (x == 42) { x = 7; } } > + #pragma omp atomic capture compare weak > + { if (x == 42) { x = 7; } y = x; } > + #pragma omp atomic capture compare fail(seq_cst) > + if (d == 8.0) { d = 16.0; } else { v = d; } > + #pragma omp atomic capture compare > + { r = x == 8; if (r) { x = 24; } } > + #pragma omp atomic compare capture > + { r = x == y; if (r) { x = y + 6; } else { z = x; } } > +} > --- gcc/testsuite/c-c++-common/gomp/atomic-26.c.jj 2021-09-09 > 10:41:42.624084639 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-26.c 2021-09-10 > 15:16:10.111808506 +0200 > @@ -0,0 +1,63 @@ > +/* { dg-do compile { target c } } */ > + > +int x; > +double d; > + > +double > +foo (int y, double e, long double f) > +{ > + double v; > + #pragma omp atomic compare compare /* { dg-error "too many 'compare' > clauses" } */ > + x = x > y ? y : x; > + #pragma omp atomic compare fail(seq_cst) fail(seq_cst) /* { > dg-error "too many 'fail' clauses" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare,fail(seq_cst),fail(relaxed) /* { > dg-error "too many 'fail' clauses" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare weak weak /* { dg-error "too many 'weak' > clauses" } */ > + d = d == e ? e + 1.0 : d; > + #pragma omp atomic read capture /* { dg-error "'capture' clause is > incompatible with 'read' or 'write' clauses" } */ > + v = d; > + #pragma omp atomic capture, write /* { dg-error "'capture' clause is > incompatible with 'read' or 'write' clauses" } */ > + d = v; > + #pragma omp atomic read compare /* { dg-error "'compare' clause is > incompatible with 'read' or 'write' clauses" } */ > + v = d; > + #pragma omp atomic compare, write /* { dg-error "'compare' clause is > incompatible with 'read' or 'write' clauses" } */ > + d = v; > + #pragma omp atomic read fail(seq_cst) /* { dg-error "'fail' > clause requires 'compare' clause" } */ > + v = d; > + #pragma omp atomic fail(relaxed), write /* { dg-error "'fail' > clause requires 'compare' clause" } */ > + d = v; > + #pragma omp atomic fail(relaxed) update /* { dg-error "'fail' > clause requires 'compare' clause" } */ > + d += 3.0; > + #pragma omp atomic fail(relaxed) /* { dg-error "'fail' clause > requires 'compare' clause" } */ > + d += 3.0; > + #pragma omp atomic capture fail(relaxed) /* { dg-error "'fail' > clause requires 'compare' clause" } */ > + v = d += 3.0; > + #pragma omp atomic read weak /* { dg-error "'weak' clause > requires 'compare' clause" } */ > + v = d; > + #pragma omp atomic weak, write /* { dg-error "'weak' clause > requires 'compare' clause" } */ > + d = v; > + #pragma omp atomic weak update /* { dg-error "'weak' clause > requires 'compare' clause" } */ > + d += 3.0; > + #pragma omp atomic weak /* { dg-error "'weak' clause > requires 'compare' clause" } */ > + d += 3.0; > + #pragma omp atomic capture weak /* { dg-error "'weak' clause > requires 'compare' clause" } */ > + v = d += 3.0; > + #pragma omp atomic compare,weak /* { dg-error "'weak' clause > requires atomic equality comparison" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail /* { dg-error "expected '\\\(' > before end of line" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail( /* { dg-error "expected 'seq_cst', > 'acquire' or 'relaxed' before end of line" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail() /* { dg-error "expected 'seq_cst', > 'acquire' or 'relaxed' before '\\\)' token" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail(foobar) /* { dg-error "expected > 'seq_cst', 'acquire' or 'relaxed' before 'foobar'" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail(acq_rel) /* { dg-error "expected > 'seq_cst', 'acquire' or 'relaxed' before 'acq_rel'" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail(release) /* { dg-error "expected > 'seq_cst', 'acquire' or 'relaxed' before 'release'" } */ > + d = e > d ? e : d; > + #pragma omp atomic compare fail(seq_cst /* { dg-error "expected > '\\\)' before end of line" } */ > + d = e > d ? e : d; > + return v; > +} > --- gcc/testsuite/c-c++-common/gomp/atomic-27.c.jj 2021-09-09 > 16:58:07.052709219 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-27.c 2021-09-09 > 17:05:13.271786779 +0200 > @@ -0,0 +1,41 @@ > +/* PR middle-end/88968 */ > +/* { dg-do compile { target c } } */ > + > +struct __attribute__((packed)) S { > + unsigned int a : 16; > + unsigned int b : 1; > +} s; > + > +void > +foo (int y, int z) > +{ > + #pragma omp atomic compare > + s.a = s.a == y ? z : s.a; > +} > + > +int > +bar (int y, int z) > +{ > + int r; > + #pragma omp atomic compare capture > + { r = s.a == y; if (r) { s.a = z; } } > + return r; > +} > + > +int > +baz (int y, int z) > +{ > + int v; > + #pragma omp atomic compare capture > + if (s.a == y) { s.a = z; } else { v = s.a; } > + return v; > +} > + > +int > +qux (int y, int z) > +{ > + int v; > + #pragma omp atomic compare capture > + v = s.a = s.a == y ? z : s.a; > + return v; > +} > --- gcc/testsuite/c-c++-common/gomp/atomic-28.c.jj 2021-09-10 > 11:47:09.193274972 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-28.c 2021-09-10 > 11:52:05.398115961 +0200 > @@ -0,0 +1,43 @@ > +/* { dg-do compile { target c } } */ > +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 4, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 4, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 260, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 4, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-not "__atomic_load_4 \\\(" "ompexp" { > target sync_int_long } } } */ > + > +int x; > + > +void > +foo (int y, int z) > +{ > + #pragma omp atomic compare seq_cst > + x = x == y ? z : x; > +} > + > +int > +bar (int y, int z) > +{ > + int r; > + #pragma omp atomic compare capture acq_rel fail (acquire) > + { r = x == y; if (r) { x = z; } } > + return r; > +} > + > +int > +baz (int y, int z) > +{ > + int v; > + #pragma omp atomic compare capture seq_cst fail (relaxed) weak > + if (x == y) { x = z; } else { v = x; } > + return v; > +} > + > +int > +qux (int y, int z) > +{ > + int v; > + #pragma omp atomic compare capture > + v = x = x == y ? z : x; > + return v; > +} > --- gcc/testsuite/c-c++-common/gomp/atomic-29.c.jj 2021-09-10 > 11:47:17.093164041 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-29.c 2021-09-10 > 11:52:33.428722747 +0200 > @@ -0,0 +1,43 @@ > +/* { dg-do compile { target c } } */ > +/* { dg-additional-options "-O2 -fdump-tree-ompexp" } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 8, 5, 5\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 8, 4, 2\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 264, 5, 0\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-times "\.ATOMIC_COMPARE_EXCHANGE > \\\(\[^\n\r]*, 8, 0, 0\\\);" 1 "ompexp" { target sync_int_long } } } */ > +/* { dg-final { scan-tree-dump-not "__atomic_load_8 \\\(" "ompexp" { > target sync_int_long } } } */ > + > This test fails on arm*linux when forcing old CPU/ARCH (eg -march=armv5t). Not sure how easy it is to fix? sync_int_long returns true for arm*-*-linux-*, but for other arm targets, it depends on the result of check_effective_target_arm_acq_rel. Is it just a matter of removing arm*-*-linux-* from sync_int_long and always rely on arm_acq_rel? Christophe +double x; > + > +void > +foo (double y, double z) > +{ > + #pragma omp atomic compare seq_cst > + x = x == y ? z : x; > +} > + > +double > +bar (double y, double z) > +{ > + int r; > + #pragma omp atomic compare capture acq_rel fail (acquire) > + { r = x == y; if (r) { x = z; } } > + return r; > +} > + > +double > +baz (double y, double z) > +{ > + double v; > + #pragma omp atomic compare capture seq_cst fail (relaxed) weak > + if (x == y) { x = z; } else { v = x; } > + return v; > +} > + > +double > +qux (double y, double z) > +{ > + double v; > + #pragma omp atomic compare capture > + v = x = x == y ? z : x; > + return v; > +} > --- gcc/testsuite/c-c++-common/gomp/atomic-30.c.jj 2021-09-10 > 15:25:01.955425201 +0200 > +++ gcc/testsuite/c-c++-common/gomp/atomic-30.c 2021-09-10 > 18:02:50.229520066 +0200 > @@ -0,0 +1,137 @@ > +/* { dg-do compile { target c } } */ > + > +int x; > +double d, g; > + > +double > +foo (int y, double e, long double f) > +{ > + double v; > + int r, r2 = 0; > + #pragma omp atomic capture compare > + v = if (d == e) { d = f; }; /* { dg-error "expected expression" } */ > + #pragma omp atomic compare > + if; /* { dg-error "expected '\\\(' before ';' > token" } */ > + #pragma omp atomic compare > + if (d >= e) { d = e; } /* { dg-error "expected '==', '<' or '>' > comparison in 'if' condition" } */ > + #pragma omp atomic compare > + if (d <= e) { d = e; } /* { dg-error "expected '==', '<' or '>' > comparison in 'if' condition" } */ > + #pragma omp atomic compare > + if (d != e) { d = e; } /* { dg-error "expected '==', '<' or '>' > comparison in 'if' condition" } */ > + #pragma omp atomic compare > + if (d + e) { d = e; } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d >= e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d <= e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d > e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d < e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d != e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d + e; if (r) { d = f; } } /* { dg-error "expected '==', '<' > or '>' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + { r = d == e; if (r2) { d = f; } } /* { dg-error "invalid form of > '#pragma omp atomic compare' before '\{' token" } */ > + #pragma omp atomic capture compare > + if (d > e) { d = e; } /* { dg-error "expected > '==' comparison in 'if' condition" } */ > + #pragma omp atomic capture compare > + if (d < e) { d = e; } /* { dg-error "expected > '==' comparison in 'if' condition" } */ > + #pragma omp atomic compare > + if (d < e) d = e; /* { dg-error "expected '\{' > before 'd'" } */ > + #pragma omp atomic compare > + if (d == e) d = e + 1.0; /* { dg-error "expected '\{' > before 'd'" } */ > + #pragma omp atomic compare > + if (d < e) { d += e; } /* { dg-error "expected '=' before > '\\\+=' token" } */ > + #pragma omp atomic compare > + if (d < e) { d = e }; /* { dg-error "expected > ';' before '\}' token" } */ > + #pragma omp atomic compare > + if (d < e) { d = e; e = 1.0; } /* { dg-error "expected '\}' > before 'e'" } */ > + #pragma omp atomic compare > + if (e == d) { d = f; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (e == d) { g = f; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (d < e) { g = e; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (d > e) { g = e; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (d < e) { d = g; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (d > e) { d = g; }; /* { dg-error "invalid form of > '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare > + if (d == e) { d = f; } else ; /* { dg-error "unexpected > 'else'" } */ > + #pragma omp atomic compare capture > + { if (d == e) { d = f; } else { v = d; } v = d; } /* { > dg-error "unexpected 'else'" } */ > + #pragma omp atomic compare > + if (d < e) { d = e; } else { v = d; } /* { dg-error "unexpected > 'else'" } */ > + #pragma omp atomic compare capture > + if (d == e) { d = f; } else v = d; /* { dg-error "expected '\{' > before 'v'" } */ > + #pragma omp atomic compare capture > + if (d == e) { d = f; } else { v += d; } /* { dg-error > "expected '=' before '\\\+=' token" } */ > + #pragma omp atomic compare capture > + if (d == e) { d = f; } else { v = e; } /* { dg-error "invalid > form of '#pragma omp atomic compare' before ';' token" } */ > + #pragma omp atomic compare capture > + if (d == e) { d = f; } else { v = d }; /* { dg-error "expected > ';' before '\}' token" } */ > + #pragma omp atomic compare capture > + if (d == e) { d = f; }; /* { dg-error "expected 'else' > before ';' token" } */ > + #pragma omp atomic compare > + x++; /* { dg-error "invalid form of > 'pragma omp atomic compare'" } */ > + #pragma omp atomic compare > + x--; /* { dg-error "invalid form of > 'pragma omp atomic compare'" } */ > + #pragma omp atomic compare > + ++x; /* { dg-error "invalid form of > 'pragma omp atomic compare'" } */ > + #pragma omp atomic compare > + --x; /* { dg-error "invalid form of > 'pragma omp atomic compare'" } */ > + #pragma omp atomic compare > + x += 3; /* { dg-error "expected '=' before > '\\\+=' token" } */ > + #pragma omp atomic compare > + x -= 5; /* { dg-error "expected '=' before > '-=' token" } */ > + #pragma omp atomic compare > + x *= 2; /* { dg-error "expected '=' before > '\\\*=' token" } */ > + #pragma omp atomic compare > + x |= 5; /* { dg-error "expected '=' before > '\\\|=' token" } */ > + #pragma omp atomic compare > + x &= ~5; /* { dg-error "expected '=' before > '\\\&=' token" } */ > + #pragma omp atomic compare > + x ^= 5; /* { dg-error "expected '=' before > '\\\^=' token" } */ > + #pragma omp atomic compare > + x = x + 3; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x - 5; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = 2 * x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = 5 | x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x & ~5; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x | 5; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x >= 5 ? 5 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x <= 5 ? 5 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x != 5 ? 7 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = 5 == x ? 7 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x == 5 ? x : 7; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x == 5 ? 9 : 7; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x > 5 ? 6 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x < 5 ? 6 : x; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x > 5 ? x : 6; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic compare > + x = x < 5 ? x : 6; /* { dg-error "invalid form of > '#pragma omp atomic' before ';' token" } */ > + #pragma omp atomic capture > + r = x == 5; /* { dg-error "invalid operator > for '#pragma omp atomic' before '==' token" } */ > + #pragma omp atomic capture compare > + r = x == 5; /* { dg-error "expected '=' before > '==' token" } */ > + #pragma omp atomic capture compare /* { dg-error "'#pragma omp atomic > compare capture' with non-integral comparison result" } */ > + { v = x == 5; if (v) { x = 6; } } > +} > --- gcc/testsuite/c-c++-common/goacc-gomp/atomic.c.jj 2020-11-06 > 11:14:19.942201229 +0100 > +++ gcc/testsuite/c-c++-common/goacc-gomp/atomic.c 2021-09-09 > 17:10:58.686986511 +0200 > @@ -37,7 +37,8 @@ foo () > > /* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read > acquire" 1 "original" } } */ > /* { dg-final { scan-tree-dump-times "i = #pragma omp atomic read > relaxed" 1 "original" } } */ > -/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 2 > "original" } } */ > +/* { dg-final { scan-tree-dump-times "#pragma omp atomic acq_rel" 1 > "original" } } */ > +/* { dg-final { scan-tree-dump-times "#pragma omp atomic release" 1 > "original" } } */ > /* { dg-final { scan-tree-dump-times "#pragma omp atomic relaxed" 2 > "original" } } */ > /* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture > acq_rel" 1 "original" } } */ > /* { dg-final { scan-tree-dump-times "v = #pragma omp atomic capture > relaxed" 2 "original" } } */ > --- gcc/testsuite/gcc.dg/gomp/atomic-5.c.jj 2021-09-09 > 10:40:20.099261161 +0200 > +++ gcc/testsuite/gcc.dg/gomp/atomic-5.c 2021-09-09 > 10:41:42.625084625 +0200 > @@ -27,7 +27,7 @@ void f1(void) > #pragma omp atomic > bar() += 1; /* { dg-error "lvalue required" } */ > #pragma omp atomic a /* { dg-error "expected end of line" } */ > - x++; /* { dg-error "expected 'read', 'write', 'update', > 'capture', 'seq_cst', 'acq_rel', 'release', 'relaxed' or 'hint' clause" "" > { target *-*-* } .-1 } */ > + x++; /* { dg-error "expected 'read', 'write', 'update', > 'capture', 'compare', 'weak', 'fail', 'seq_cst', 'acq_rel', 'release', > 'relaxed' or 'hint' clause" "" { target *-*-* } .-1 } */ > #pragma omp atomic > ; /* { dg-error "expected expression" } */ > #pragma omp atomic > --- gcc/testsuite/g++.dg/gomp/atomic-18.C.jj 2020-04-15 > 09:58:30.372649450 +0200 > +++ gcc/testsuite/g++.dg/gomp/atomic-18.C 2021-09-09 > 17:27:28.671222445 +0200 > @@ -1,6 +1,7 @@ > // { dg-do compile } > // { dg-additional-options "-fdump-tree-original" } > -// { dg-final { scan-tree-dump-times "omp atomic release" 5 "original" } } > +// { dg-final { scan-tree-dump-times "omp atomic release" 4 "original" } } > +// { dg-final { scan-tree-dump-times "omp atomic acq_rel" 1 "original" } } > // { dg-final { scan-tree-dump-times "omp atomic seq_cst" 1 "original" } } > // { dg-final { scan-tree-dump-times "omp atomic relaxed" 2 "original" } } > // { dg-final { scan-tree-dump-times "omp atomic capture acq_rel" 3 > "original" } } > --- libgomp/testsuite/libgomp.c-c++-common/atomic-19.c.jj 2021-09-10 > 12:09:43.320275112 +0200 > +++ libgomp/testsuite/libgomp.c-c++-common/atomic-19.c 2021-09-10 > 14:24:03.200540163 +0200 > @@ -0,0 +1,274 @@ > +// { dg-do run { target c } } > + > +extern > +#ifdef __cplusplus > +"C" > +#endif > +void abort (void); > +int x = 6; > +int w, y; > + > +int * > +foo (void) > +{ > + if (w) > + abort (); > + return &y; > +} > + > +int > +main () > +{ > + int v, r; > + #pragma omp atomic compare > + x = x > 8 ? 8 : x; > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + #pragma omp atomic compare > + x = x > 4 ? 4 : x; > + #pragma omp atomic read > + v = x; > + if (v != 4) > + abort (); > + #pragma omp atomic compare capture > + v = x = x < 8 ? 8 : x; > + if (v != 8) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 8) > + abort (); > + #pragma omp atomic capture compare > + { v = x; x = x < 12 ? 12 : x; } > + if (v != 8) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic capture compare > + { v = x; x = x < 4 ? 4 : x; } > + if (v != 12) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic write > + x = -32; > + #pragma omp atomic capture compare seq_cst fail(relaxed) > + { x = 12U < x ? 12U : x; v = x; } > + if (v != 12) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic compare > + x = x == 12 ? 16 : x; > + #pragma omp atomic read > + v = x; > + if (v != 16) > + abort (); > + r = 57; > + #pragma omp atomic compare capture > + v = x = x == 15 ? r + 7 : x; > + if (v != 16) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 16) > + abort (); > + #pragma omp atomic capture, update, compare seq_cst fail(acquire) > + { v = x; x = x == 73ULL - r ? 12LL : x; } > + if (v != 16) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic update, compare, capture > + { x = x == 69LL - r ? (unsigned char) 6 : x; v = x; } > + if (v != 6) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + #pragma omp atomic compare > + if (x > 8) { x = 8; } > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + #pragma omp atomic compare > + if (x > 4) { x = 4; } > + #pragma omp atomic read > + v = x; > + if (v != 4) > + abort (); > + #pragma omp atomic compare capture > + { if (x < 8) { x = 8; } v = x; } > + if (v != 8) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 8) > + abort (); > + #pragma omp atomic capture compare > + { v = x; if (x < 12) { x = 12; } } > + if (v != 8) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic capture compare > + { v = x; if (x < 4) { x = 4; } } > + if (v != 12) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic write > + x = -32; > + #pragma omp atomic capture compare seq_cst fail(relaxed) > + { if (12U < x) { x = 12U; } v = x; } > + if (v != 12) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic compare > + if (x == 12) { x = 16; } > + #pragma omp atomic read > + v = x; > + if (v != 16) > + abort (); > + r = 57; > + #pragma omp atomic compare capture > + { if (x == 15) { x = r + 7; } v = x; } > + if (v != 16) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 16) > + abort (); > + #pragma omp atomic capture, update, compare seq_cst fail(acquire) > + { v = x; if (x == 73ULL - r) { x = 12LL; } } > + if (v != 16) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12) > + abort (); > + #pragma omp atomic update, compare, capture > + { if (x == 69LL - r) { x = (unsigned char) 6; } v = x; } > + if (v != 6) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + v = 24; > + #pragma omp atomic compare capture > + if (x == 12) { x = 16; } else { v = x; } > + if (v != 6) > + abort (); > + v = 32; > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + v = 147; > + #pragma omp atomic capture compare > + if (x == 6) { x = 57; } else { v = x; } > + if (v != 147) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 57) > + abort (); > + #pragma omp atomic update, capture, compare, weak, seq_cst, fail > (relaxed) > + { r = x == 137; if (r) { x = 174; } } > + if (r) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 57) > + abort (); > + #pragma omp atomic compare capture fail (relaxed) > + { r = x == 57; if (r) { x = 6; } } > + if (r != 1) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + v = -5; > + #pragma omp atomic capture compare > + { r = x == 17; if (r) { x = 25; } else { v = x; } } > + if (r || v != 6) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6) > + abort (); > + v = 15; > + #pragma omp atomic capture compare > + { r = x == 6; if (r) { x = 23; } else { v = x; } } > + if (r != 1 || v != 15) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 23) > + abort (); > + w = 1; > + #pragma omp atomic compare capture > + if (x == 23) { x = 57; } else { foo ()[0] = x; } > + #pragma omp atomic read > + v = x; > + if (v != 57) > + abort (); > + #pragma omp atomic capture update compare > + { r = x == 57; if (r) { x = 23; } else { foo ()[0] = x; } } > + if (r != 1) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 23) > + abort (); > + w = 0; > + #pragma omp atomic compare capture > + if (x == 24) { x = 57; } else { foo ()[0] = x; } > + if (y != 23) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 23) > + abort (); > + y = -5; > + #pragma omp atomic capture update compare > + { > + r = x == 57; > + if (r) > + { > + x = 27; > + } > + else > + { > + foo ()[0] = x; > + } > + } > + if (r || y != 23) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 23) > + abort (); > + return 0; > +} > --- libgomp/testsuite/libgomp.c-c++-common/atomic-20.c.jj 2021-09-10 > 14:08:45.330336955 +0200 > +++ libgomp/testsuite/libgomp.c-c++-common/atomic-20.c 2021-09-10 > 14:27:14.746865949 +0200 > @@ -0,0 +1,203 @@ > +// { dg-do run { target c } } > + > +extern > +#ifdef __cplusplus > +"C" > +#endif > +void abort (void); > +float x = 6.0f; > + > +int > +main () > +{ > + float v; > + int r; > + #pragma omp atomic compare > + x = x > 8.0f ? 8.0f : x; > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + #pragma omp atomic compare > + x = x > 4.0f ? 4.0f : x; > + #pragma omp atomic read > + v = x; > + if (v != 4.0f) > + abort (); > + #pragma omp atomic compare capture > + v = x = x < 8.0f ? 8.0f : x; > + if (v != 8.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 8) > + abort (); > + #pragma omp atomic capture compare > + { v = x; x = x < 12.0f ? 12.0f : x; } > + if (v != 8.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic capture compare > + { v = x; x = x < 4.0f ? 4.0f : x; } > + if (v != 12.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic compare > + x = x == 12.0 ? 16.0L : x; > + #pragma omp atomic read > + v = x; > + if (v != 16.0) > + abort (); > + r = 57; > + #pragma omp atomic compare capture > + v = x = x == 15.0f ? r + 7.0f : x; > + if (v != 16.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 16.0f) > + abort (); > + #pragma omp atomic capture, update, compare seq_cst fail(acquire) > + { v = x; x = x == 73.0L - r ? 12.0f : x; } > + if (v != 16.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic update, compare, capture > + { x = x == 69.0 - r ? 6.0f : x; v = x; } > + if (v != 6.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + #pragma omp atomic compare > + if (x > 8.0f) { x = 8.0f; } > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + #pragma omp atomic compare > + if (x > 4.0) { x = 4.0; } > + #pragma omp atomic read > + v = x; > + if (v != 4.0f) > + abort (); > + #pragma omp atomic compare capture > + { if (x < 8.0f) { x = 8.0f; } v = x; } > + if (v != 8.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 8.0f) > + abort (); > + #pragma omp atomic capture compare > + { v = x; if (x < 12.0f) { x = 12.0f; } } > + if (v != 8.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic capture compare > + { v = x; if (x < 4.0L) { x = 4.0L; } } > + if (v != 12.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic compare > + if (x == 12.0f) { x = 16.0L; } > + #pragma omp atomic read > + v = x; > + if (v != 16.0f) > + abort (); > + r = 57.0; > + #pragma omp atomic compare capture > + { if (x == 15.0f) { x = r + 7.0f; } v = x; } > + if (v != 16.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 16.0f) > + abort (); > + #pragma omp atomic capture, update, compare seq_cst fail(acquire) > + { v = x; if (x == 73.0L - r) { x = 12.0L; } } > + if (v != 16.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 12.0f) > + abort (); > + #pragma omp atomic update, compare, capture > + { if (x == 69.0L - r) { x = 6.0; } v = x; } > + if (v != 6.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + v = 24; > + #pragma omp atomic compare capture > + if (x == 12.0f) { x = 16.0f; } else { v = x; } > + if (v != 6.0f) > + abort (); > + v = 32.0f; > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + v = 147.0f; > + #pragma omp atomic capture compare > + if (x == 6.0f) { x = 57.0f; } else { v = x; } > + if (v != 147.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 57.0f) > + abort (); > + #pragma omp atomic update, capture, compare, weak, seq_cst, fail > (relaxed) > + { r = x == 137.0f; if (r) { x = 174.0f; } } > + if (r) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 57.0f) > + abort (); > + #pragma omp atomic compare capture fail (relaxed) > + { r = x == 57.0f; if (r) { x = 6.0f; } } > + if (r != 1) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + v = -5.0f; > + #pragma omp atomic capture compare > + { r = x == 17.0L; if (r) { x = 25.0; } else { v = x; } } > + if (r || v != 6.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 6.0f) > + abort (); > + v = 15.0f; > + #pragma omp atomic capture compare > + { r = x == 6.0f; if (r) { x = 23.0f; } else { v = x; } } > + if (r != 1 || v != 15.0f) > + abort (); > + #pragma omp atomic read > + v = x; > + if (v != 23.0f) > + abort (); > + return 0; > +} > --- libgomp/testsuite/libgomp.c-c++-common/atomic-21.c.jj 2021-09-10 > 14:27:19.051805671 +0200 > +++ libgomp/testsuite/libgomp.c-c++-common/atomic-21.c 2021-09-10 > 15:05:47.316510552 +0200 > @@ -0,0 +1,49 @@ > +// { dg-do run { target c } } > + > +double d; > +long double ld; > + > +int > +main () > +{ > + double e = __builtin_copysign (0.0, -1.0), v; > + long double le = __builtin_copysignl (0.0L, -1.0L), lv; > + if (__builtin_memcmp (&d, &e, sizeof (d)) != 0) > + { > + /* Verify == comparison for atomics is done as with memcmp. */ > + #pragma omp atomic compare > + d = d == e ? 5.0 : d; > + #pragma omp atomic read > + v = d; > + if (v != 0.0) > + __builtin_abort (); > + #pragma omp atomic compare > + d = d == 0.0 ? 5.0 : d; > + #pragma omp atomic read > + v = d; > + if (v != 5.0) > + __builtin_abort (); > + } > + if (__builtin_memcmp (&ld, &le, sizeof (ld)) != 0) > + { > + __builtin_memset (&ld, 0xff, sizeof (ld)); > + #pragma omp atomic write > + ld = 0.0L; > + __asm volatile ("" : : "g" (&ld) : "memory"); > + /* Verify == comparison for atomics is done as with memcmp > + with __builtin_clear_padding if needed. */ > + #pragma omp atomic compare > + ld = ld == le ? 5.0L : ld; > + #pragma omp atomic read > + lv = ld; > + if (lv != 0.0L) > + __builtin_abort (); > + #pragma omp atomic compare > + ld = ld == 0.0L ? 5.0L : ld; > + #pragma omp atomic read > + lv = ld; > + if (lv != 5.0L) > + __builtin_abort (); > + } > + return 0; > +} > > Jakub > >