On Wed, Dec 15, 2021 at 10:23 AM Jakub Jelinek <ja...@redhat.com> wrote:
>
> On Wed, Jan 27, 2021 at 12:27:13PM +0100, Ulrich Drepper via Gcc-patches 
> wrote:
> > On 1/27/21 11:37 AM, Jakub Jelinek wrote:
> > > Would equality comparison against 0 handle the most common cases.
> > >
> > > The user can write it as
> > > __atomic_sub_fetch (x, y, z) == 0
> > > or
> > > __atomic_fetch_sub (x, y, z) - y == 0
> > > thouch, so the expansion code would need to be able to cope with both.
> >
> > Please also keep !=0, <0, <=0, >0, and >=0 in mind.  They all can be
> > useful and can be handled with the flags.
>
> <= 0 and > 0 don't really work well with lock {add,sub,inc,dec}, x86 doesn't
> have comparisons that would look solely at both SF and ZF and not at other
> flags (and emitting two separate conditional jumps or two setcc insns and
> oring them together looks awful).
>
> But the rest can work.
>
> Here is a patch that adds internal functions and optabs for these,
> recognizes them at the same spot as e.g. .ATOMIC_BIT_TEST_AND* internal
> functions (fold all builtins pass) and expands them appropriately (or for
> the <= 0 and > 0 cases of +/- FAILs and let's middle-end fall back).
>
> So far I have handled just the op_fetch builtins, IMHO instead of handling
> also __atomic_fetch_sub (x, y, z) - y == 0 etc. we should canonicalize
> __atomic_fetch_sub (x, y, z) - y to __atomic_sub_fetch (x, y, z) (and vice
> versa).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2021-12-15  Jakub Jelinek  <ja...@redhat.com>
>
>         PR target/98737
>         * internal-fn.def (ATOMIC_ADD_FETCH_CMP_0, ATOMIC_SUB_FETCH_CMP_0,
>         ATOMIC_AND_FETCH_CMP_0, ATOMIC_OR_FETCH_CMP_0, 
> ATOMIC_XOR_FETCH_CMP_0):
>         New internal fns.
>         * internal-fn.h (ATOMIC_OP_FETCH_CMP_0_EQ, ATOMIC_OP_FETCH_CMP_0_NE,
>         ATOMIC_OP_FETCH_CMP_0_LT, ATOMIC_OP_FETCH_CMP_0_LE,
>         ATOMIC_OP_FETCH_CMP_0_GT, ATOMIC_OP_FETCH_CMP_0_GE): New enumerators.
>         * internal-fn.c (expand_ATOMIC_ADD_FETCH_CMP_0,
>         expand_ATOMIC_SUB_FETCH_CMP_0, expand_ATOMIC_AND_FETCH_CMP_0,
>         expand_ATOMIC_OR_FETCH_CMP_0, expand_ATOMIC_XOR_FETCH_CMP_0): New
>         functions.
>         * optabs.def (atomic_add_fetch_cmp_0_optab,
>         atomic_sub_fetch_cmp_0_optab, atomic_and_fetch_cmp_0_optab,
>         atomic_or_fetch_cmp_0_optab, atomic_xor_fetch_cmp_0_optab): New
>         direct optabs.
>         * builtins.h (expand_ifn_atomic_op_fetch_cmp_0): Declare.
>         * builtins.c (expand_ifn_atomic_op_fetch_cmp_0): New function.
>         * tree-ssa-ccp.c: Include internal-fn.h.
>         (optimize_atomic_bit_test_and): Add . before internal fn call
>         in function comment.  Change return type from void to bool and
>         return true only if successfully replaced.
>         (optimize_atomic_op_fetch_cmp_0): New function.
>         (pass_fold_builtins::execute): Use optimize_atomic_op_fetch_cmp_0
>         for BUILT_IN_ATOMIC_{ADD,SUB,AND,OR,XOR}_FETCH_{1,2,4,8,16} and
>         BUILT_IN_SYNC_{ADD,SUB,AND,OR,XOR}_AND_FETCH_{1,2,4,8,16},
>         for *XOR* ones only if optimize_atomic_bit_test_and failed.
>         * config/i386/sync.md (atomic_<plusminus_mnemonic>_fetch_cmp_0<mode>,
>         atomic_<logic>_fetch_cmp_0<mode>): New define_expand patterns.
>         (atomic_<plusminus_mnemonic>_fetch_cmp_0<mode>_1,
>         atomic_<logic>_fetch_cmp_0<mode>_1): New define_insn patterns.
>
>         * gcc.target/i386/pr98737-1.c: New test.
>         * gcc.target/i386/pr98737-2.c: New test.
>         * gcc.target/i386/pr98737-3.c: New test.
>         * gcc.target/i386/pr98737-4.c: New test.
>         * gcc.target/i386/pr98737-5.c: New test.
>         * gcc.target/i386/pr98737-6.c: New test.
>         * gcc.target/i386/pr98737-7.c: New test.

OK (with a small adjustment) for the x86 part.

Thanks,
Uros.

>
> --- gcc/internal-fn.def.jj      2021-11-30 13:26:09.323329485 +0100
> +++ gcc/internal-fn.def 2021-12-13 12:12:10.947053554 +0100
> @@ -403,6 +403,11 @@ DEF_INTERNAL_FN (ATOMIC_BIT_TEST_AND_SET
>  DEF_INTERNAL_FN (ATOMIC_BIT_TEST_AND_COMPLEMENT, ECF_LEAF, NULL)
>  DEF_INTERNAL_FN (ATOMIC_BIT_TEST_AND_RESET, ECF_LEAF, NULL)
>  DEF_INTERNAL_FN (ATOMIC_COMPARE_EXCHANGE, ECF_LEAF, NULL)
> +DEF_INTERNAL_FN (ATOMIC_ADD_FETCH_CMP_0, ECF_LEAF, NULL)
> +DEF_INTERNAL_FN (ATOMIC_SUB_FETCH_CMP_0, ECF_LEAF, NULL)
> +DEF_INTERNAL_FN (ATOMIC_AND_FETCH_CMP_0, ECF_LEAF, NULL)
> +DEF_INTERNAL_FN (ATOMIC_OR_FETCH_CMP_0, ECF_LEAF, NULL)
> +DEF_INTERNAL_FN (ATOMIC_XOR_FETCH_CMP_0, ECF_LEAF, NULL)
>
>  /* To implement [[fallthrough]].  */
>  DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL)
> --- gcc/internal-fn.h.jj        2021-11-30 13:26:09.324329471 +0100
> +++ gcc/internal-fn.h   2021-12-13 19:17:03.491728748 +0100
> @@ -240,4 +240,13 @@ extern void expand_SHUFFLEVECTOR (intern
>
>  extern bool vectorized_internal_fn_supported_p (internal_fn, tree);
>
> +enum {
> +  ATOMIC_OP_FETCH_CMP_0_EQ = 0,
> +  ATOMIC_OP_FETCH_CMP_0_NE = 1,
> +  ATOMIC_OP_FETCH_CMP_0_LT = 2,
> +  ATOMIC_OP_FETCH_CMP_0_LE = 3,
> +  ATOMIC_OP_FETCH_CMP_0_GT = 4,
> +  ATOMIC_OP_FETCH_CMP_0_GE = 5
> +};
> +
>  #endif
> --- gcc/internal-fn.c.jj        2021-12-02 19:41:52.635552695 +0100
> +++ gcc/internal-fn.c   2021-12-13 12:19:51.504465053 +0100
> @@ -3238,6 +3238,46 @@ expand_ATOMIC_COMPARE_EXCHANGE (internal
>    expand_ifn_atomic_compare_exchange (call);
>  }
>
> +/* Expand atomic add fetch and cmp with 0.  */
> +
> +static void
> +expand_ATOMIC_ADD_FETCH_CMP_0 (internal_fn, gcall *call)
> +{
> +  expand_ifn_atomic_op_fetch_cmp_0 (call);
> +}
> +
> +/* Expand atomic sub fetch and cmp with 0.  */
> +
> +static void
> +expand_ATOMIC_SUB_FETCH_CMP_0 (internal_fn, gcall *call)
> +{
> +  expand_ifn_atomic_op_fetch_cmp_0 (call);
> +}
> +
> +/* Expand atomic and fetch and cmp with 0.  */
> +
> +static void
> +expand_ATOMIC_AND_FETCH_CMP_0 (internal_fn, gcall *call)
> +{
> +  expand_ifn_atomic_op_fetch_cmp_0 (call);
> +}
> +
> +/* Expand atomic or fetch and cmp with 0.  */
> +
> +static void
> +expand_ATOMIC_OR_FETCH_CMP_0 (internal_fn, gcall *call)
> +{
> +  expand_ifn_atomic_op_fetch_cmp_0 (call);
> +}
> +
> +/* Expand atomic xor fetch and cmp with 0.  */
> +
> +static void
> +expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
> +{
> +  expand_ifn_atomic_op_fetch_cmp_0 (call);
> +}
> +
>  /* Expand LAUNDER to assignment, lhs = arg0.  */
>
>  static void
> --- gcc/optabs.def.jj   2021-11-30 13:26:09.357328990 +0100
> +++ gcc/optabs.def      2021-12-13 14:52:40.180933731 +0100
> @@ -451,6 +451,11 @@ OPTAB_D (atomic_sub_fetch_optab, "atomic
>  OPTAB_D (atomic_sub_optab, "atomic_sub$I$a")
>  OPTAB_D (atomic_xor_fetch_optab, "atomic_xor_fetch$I$a")
>  OPTAB_D (atomic_xor_optab, "atomic_xor$I$a")
> +OPTAB_D (atomic_add_fetch_cmp_0_optab, "atomic_add_fetch_cmp_0$I$a")
> +OPTAB_D (atomic_sub_fetch_cmp_0_optab, "atomic_sub_fetch_cmp_0$I$a")
> +OPTAB_D (atomic_and_fetch_cmp_0_optab, "atomic_and_fetch_cmp_0$I$a")
> +OPTAB_D (atomic_or_fetch_cmp_0_optab, "atomic_or_fetch_cmp_0$I$a")
> +OPTAB_D (atomic_xor_fetch_cmp_0_optab, "atomic_xor_fetch_cmp_0$I$a")
>
>  OPTAB_D (get_thread_pointer_optab, "get_thread_pointer$I$a")
>  OPTAB_D (set_thread_pointer_optab, "set_thread_pointer$I$a")
> --- gcc/builtins.h.jj   2021-11-30 13:26:09.254330489 +0100
> +++ gcc/builtins.h      2021-12-13 15:00:29.585187247 +0100
> @@ -123,6 +123,7 @@ extern void std_expand_builtin_va_start
>  extern void expand_builtin_trap (void);
>  extern void expand_ifn_atomic_bit_test_and (gcall *);
>  extern void expand_ifn_atomic_compare_exchange (gcall *);
> +extern void expand_ifn_atomic_op_fetch_cmp_0 (gcall *);
>  extern rtx expand_builtin (tree, rtx, rtx, machine_mode, int);
>  extern enum built_in_function builtin_mathfn_code (const_tree);
>  extern tree fold_builtin_expect (location_t, tree, tree, tree, tree);
> --- gcc/builtins.c.jj   2021-11-30 13:26:09.254330489 +0100
> +++ gcc/builtins.c      2021-12-14 10:21:28.524814726 +0100
> @@ -6275,6 +6275,93 @@ expand_ifn_atomic_bit_test_and (gcall *c
>      emit_move_insn (target, result);
>  }
>
> +/* Expand IFN_ATOMIC_*_FETCH_CMP_0 internal function.  */
> +
> +void
> +expand_ifn_atomic_op_fetch_cmp_0 (gcall *call)
> +{
> +  tree cmp = gimple_call_arg (call, 0);
> +  tree ptr = gimple_call_arg (call, 1);
> +  tree arg = gimple_call_arg (call, 2);
> +  tree lhs = gimple_call_lhs (call);
> +  enum memmodel model = MEMMODEL_SYNC_SEQ_CST;
> +  machine_mode mode = TYPE_MODE (TREE_TYPE (cmp));
> +  optab optab;
> +  rtx_code code;
> +  class expand_operand ops[5];
> +
> +  gcc_assert (flag_inline_atomics);
> +
> +  if (gimple_call_num_args (call) == 4)
> +    model = get_memmodel (gimple_call_arg (call, 3));
> +
> +  rtx mem = get_builtin_sync_mem (ptr, mode);
> +  rtx op = expand_expr_force_mode (arg, mode);
> +
> +  switch (gimple_call_internal_fn (call))
> +    {
> +    case IFN_ATOMIC_ADD_FETCH_CMP_0:
> +      code = PLUS;
> +      optab = atomic_add_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_SUB_FETCH_CMP_0:
> +      code = MINUS;
> +      optab = atomic_sub_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_AND_FETCH_CMP_0:
> +      code = AND;
> +      optab = atomic_and_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_OR_FETCH_CMP_0:
> +      code = IOR;
> +      optab = atomic_or_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_XOR_FETCH_CMP_0:
> +      code = XOR;
> +      optab = atomic_xor_fetch_cmp_0_optab;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  enum rtx_code comp = UNKNOWN;
> +  switch (tree_to_uhwi (cmp))
> +    {
> +    case ATOMIC_OP_FETCH_CMP_0_EQ: comp = EQ; break;
> +    case ATOMIC_OP_FETCH_CMP_0_NE: comp = NE; break;
> +    case ATOMIC_OP_FETCH_CMP_0_GT: comp = GT; break;
> +    case ATOMIC_OP_FETCH_CMP_0_GE: comp = GE; break;
> +    case ATOMIC_OP_FETCH_CMP_0_LT: comp = LT; break;
> +    case ATOMIC_OP_FETCH_CMP_0_LE: comp = LE; break;
> +    default: gcc_unreachable ();
> +    }
> +
> +  rtx target;
> +  if (lhs == NULL_TREE)
> +    target = gen_reg_rtx (TYPE_MODE (boolean_type_node));
> +  else
> +    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +  enum insn_code icode = direct_optab_handler (optab, mode);
> +  gcc_assert (icode != CODE_FOR_nothing);
> +  create_output_operand (&ops[0], target, TYPE_MODE (boolean_type_node));
> +  create_fixed_operand (&ops[1], mem);
> +  create_convert_operand_to (&ops[2], op, mode, true);
> +  create_integer_operand (&ops[3], model);
> +  create_integer_operand (&ops[4], comp);
> +  if (maybe_expand_insn (icode, 5, ops))
> +    return;
> +
> +  rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, op,
> +                                      code, model, true);
> +  if (lhs)
> +    {
> +      result = emit_store_flag_force (target, comp, result, const0_rtx, mode,
> +                                     0, 1);
> +      if (result != target)
> +       emit_move_insn (target, result);
> +    }
> +}
> +
>  /* Expand an atomic clear operation.
>         void _atomic_clear (BOOL *obj, enum memmodel)
>     EXP is the call expression.  */
> --- gcc/tree-ssa-ccp.c.jj       2021-11-24 09:54:11.572737923 +0100
> +++ gcc/tree-ssa-ccp.c  2021-12-14 10:24:00.394632973 +0100
> @@ -151,6 +151,7 @@ along with GCC; see the file COPYING3.
>  #include "symbol-summary.h"
>  #include "ipa-utils.h"
>  #include "ipa-prop.h"
> +#include "internal-fn.h"
>
>  /* Possible lattice values.  */
>  typedef enum
> @@ -3333,7 +3334,7 @@ extern bool gimple_nop_convert (tree, tr
>       _4 = __atomic_fetch_or_* (ptr_6, mask_2, _3);
>       _5 = _4 & mask_2;
>     to
> -     _4 = ATOMIC_BIT_TEST_AND_SET (ptr_6, cnt_1, 0, _3);
> +     _4 = .ATOMIC_BIT_TEST_AND_SET (ptr_6, cnt_1, 0, _3);
>       _5 = _4;
>     If _5 is only used in _5 != 0 or _5 == 0 comparisons, 1
>     is passed instead of 0, and the builtin just returns a zero
> @@ -3345,7 +3346,7 @@ extern bool gimple_nop_convert (tree, tr
>     the second argument to the builtin needs to be one's complement
>     of the mask instead of mask.  */
>
> -static void
> +static bool
>  optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip,
>                               enum internal_fn fn, bool has_model_arg,
>                               bool after)
> @@ -3365,7 +3366,7 @@ optimize_atomic_bit_test_and (gimple_stm
>        || !single_imm_use (lhs, &use_p, &use_stmt)
>        || !is_gimple_assign (use_stmt)
>        || !gimple_vdef (call))
> -    return;
> +    return false;
>
>    switch (fn)
>      {
> @@ -3379,7 +3380,7 @@ optimize_atomic_bit_test_and (gimple_stm
>        optab = atomic_bit_test_and_reset_optab;
>        break;
>      default:
> -      return;
> +      return false;
>      }
>
>    tree bit = nullptr;
> @@ -3389,20 +3390,20 @@ optimize_atomic_bit_test_and (gimple_stm
>    if (rhs_code != BIT_AND_EXPR)
>      {
>        if (rhs_code != NOP_EXPR && rhs_code != BIT_NOT_EXPR)
> -       return;
> +       return false;
>
>        tree use_lhs = gimple_assign_lhs (use_stmt);
>        if (TREE_CODE (use_lhs) == SSA_NAME
>           && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs))
> -       return;
> +       return false;
>
>        tree use_rhs = gimple_assign_rhs1 (use_stmt);
>        if (lhs != use_rhs)
> -       return;
> +       return false;
>
>        if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
>           == CODE_FOR_nothing)
> -       return;
> +       return false;
>
>        gimple *g;
>        gimple_stmt_iterator gsi;
> @@ -3413,7 +3414,7 @@ optimize_atomic_bit_test_and (gimple_stm
>         {
>           g = convert_atomic_bit_not (fn, use_stmt, lhs, mask);
>           if (!g)
> -           return;
> +           return false;
>           use_stmt = g;
>           ibit = 0;
>         }
> @@ -3426,7 +3427,7 @@ optimize_atomic_bit_test_and (gimple_stm
>               if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs),
>                                                    ~HOST_WIDE_INT_1),
>                                     mask, 0))
> -               return;
> +               return false;
>
>               /* Convert
>                  _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
> @@ -3442,7 +3443,7 @@ optimize_atomic_bit_test_and (gimple_stm
>             {
>               and_mask = build_int_cst (TREE_TYPE (lhs), 1);
>               if (!operand_equal_p (and_mask, mask, 0))
> -               return;
> +               return false;
>
>               /* Convert
>                  _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
> @@ -3468,20 +3469,20 @@ optimize_atomic_bit_test_and (gimple_stm
>           gimple *use_nop_stmt;
>           if (!single_imm_use (use_lhs, &use_p, &use_nop_stmt)
>               || !is_gimple_assign (use_nop_stmt))
> -           return;
> +           return false;
>           tree use_nop_lhs = gimple_assign_lhs (use_nop_stmt);
>           rhs_code = gimple_assign_rhs_code (use_nop_stmt);
>           if (rhs_code != BIT_AND_EXPR)
>             {
>               if (TREE_CODE (use_nop_lhs) == SSA_NAME
>                   && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_nop_lhs))
> -               return;
> +               return false;
>               if (rhs_code == BIT_NOT_EXPR)
>                 {
>                   g = convert_atomic_bit_not (fn, use_nop_stmt, lhs,
>                                               mask);
>                   if (!g)
> -                   return;
> +                   return false;
>                   /* Convert
>                      _1 = __atomic_fetch_or_4 (ptr_6, 1, _3);
>                      _2 = (int) _1;
> @@ -3509,15 +3510,15 @@ optimize_atomic_bit_test_and (gimple_stm
>               else
>                 {
>                   if (TREE_CODE (TREE_TYPE (use_nop_lhs)) != BOOLEAN_TYPE)
> -                   return;
> +                   return false;
>                   if (rhs_code != GE_EXPR && rhs_code != LT_EXPR)
> -                   return;
> +                   return false;
>                   tree cmp_rhs1 = gimple_assign_rhs1 (use_nop_stmt);
>                   if (use_lhs != cmp_rhs1)
> -                   return;
> +                   return false;
>                   tree cmp_rhs2 = gimple_assign_rhs2 (use_nop_stmt);
>                   if (!integer_zerop (cmp_rhs2))
> -                   return;
> +                   return false;
>
>                   tree and_mask;
>
> @@ -3533,7 +3534,7 @@ optimize_atomic_bit_test_and (gimple_stm
>                       and_mask = build_int_cst (TREE_TYPE (use_rhs),
>                                                 highest - 1);
>                       if (!operand_equal_p (and_mask, mask, 0))
> -                       return;
> +                       return false;
>
>                       /* Convert
>                          _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
> @@ -3553,7 +3554,7 @@ optimize_atomic_bit_test_and (gimple_stm
>                       and_mask = build_int_cst (TREE_TYPE (use_rhs),
>                                                 highest);
>                       if (!operand_equal_p (and_mask, mask, 0))
> -                       return;
> +                       return false;
>
>                       /* Convert
>                          _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
> @@ -3592,7 +3593,7 @@ optimize_atomic_bit_test_and (gimple_stm
>                   || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (match_op[2])
>                   || !single_imm_use (match_op[2], &use_p, &g)
>                   || !is_gimple_assign (g))
> -               return;
> +               return false;
>               mask = match_op[0];
>               if (TREE_CODE (match_op[1]) == INTEGER_CST)
>                 {
> @@ -3650,7 +3651,7 @@ optimize_atomic_bit_test_and (gimple_stm
>             }
>         }
>        else
> -       return;
> +       return false;
>
>        if (!bit)
>         {
> @@ -3661,11 +3662,11 @@ optimize_atomic_bit_test_and (gimple_stm
>      }
>    else if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
>            == CODE_FOR_nothing)
> -    return;
> +    return false;
>
>    tree use_lhs = gimple_assign_lhs (use_stmt);
>    if (!use_lhs)
> -    return;
> +    return false;
>
>    if (!bit)
>      {
> @@ -3676,7 +3677,7 @@ optimize_atomic_bit_test_and (gimple_stm
>           mask = fold_convert (TREE_TYPE (lhs), mask);
>           int ibit = tree_log2 (mask);
>           if (ibit < 0)
> -           return;
> +           return false;
>           bit = build_int_cst (TREE_TYPE (lhs), ibit);
>         }
>        else if (TREE_CODE (mask) == SSA_NAME)
> @@ -3687,30 +3688,30 @@ optimize_atomic_bit_test_and (gimple_stm
>             {
>               mask = match_op;
>               if (TREE_CODE (mask) != SSA_NAME)
> -               return;
> +               return false;
>               g = SSA_NAME_DEF_STMT (mask);
>             }
>           if (!is_gimple_assign (g))
> -           return;
> +           return false;
>
>           if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
>             {
>               if (gimple_assign_rhs_code (g) != BIT_NOT_EXPR)
> -               return;
> +               return false;
>               mask = gimple_assign_rhs1 (g);
>               if (TREE_CODE (mask) != SSA_NAME)
> -               return;
> +               return false;
>               g = SSA_NAME_DEF_STMT (mask);
>             }
>
>           rhs_code = gimple_assign_rhs_code (g);
>           if (rhs_code != LSHIFT_EXPR
>               || !integer_onep (gimple_assign_rhs1 (g)))
> -           return;
> +           return false;
>           bit = gimple_assign_rhs2 (g);
>         }
>        else
> -       return;
> +       return false;
>
>        tree cmp_mask;
>        if (gimple_assign_rhs1 (use_stmt) == lhs)
> @@ -3723,7 +3724,7 @@ optimize_atomic_bit_test_and (gimple_stm
>         cmp_mask = match_op;
>
>        if (!operand_equal_p (cmp_mask, mask, 0))
> -       return;
> +       return false;
>      }
>
>    bool use_bool = true;
> @@ -3748,6 +3749,8 @@ optimize_atomic_bit_test_and (gimple_stm
>           case COND_EXPR:
>             op1 = gimple_assign_rhs1 (g);
>             code = TREE_CODE (op1);
> +           if (TREE_CODE_CLASS (code) != tcc_comparison)
> +             break;
>             op0 = TREE_OPERAND (op1, 0);
>             op1 = TREE_OPERAND (op1, 1);
>             break;
> @@ -3864,6 +3867,196 @@ optimize_atomic_bit_test_and (gimple_stm
>    release_defs (use_stmt);
>    gsi_remove (gsip, true);
>    release_ssa_name (lhs);
> +  return true;
> +}
> +
> +/* Optimize
> +     _4 = __atomic_add_fetch_* (ptr_6, arg_2, _3);
> +     _5 = _4 == 0;
> +   to
> +     _4 = .ATOMIC_ADD_FETCH_CMP_0 (EQ_EXPR, ptr_6, arg_2, _3);
> +     _5 = _4;
> +   Similarly for __sync_add_and_fetch_* (without the ", _3" part
> +   in there).  */
> +
> +static bool
> +optimize_atomic_op_fetch_cmp_0 (gimple_stmt_iterator *gsip,
> +                               enum internal_fn fn, bool has_model_arg)
> +{
> +  gimple *call = gsi_stmt (*gsip);
> +  tree lhs = gimple_call_lhs (call);
> +  use_operand_p use_p;
> +  gimple *use_stmt;
> +
> +  if (!flag_inline_atomics
> +      || optimize_debug
> +      || !gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> +      || !lhs
> +      || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
> +      || !single_imm_use (lhs, &use_p, &use_stmt)
> +      || !gimple_vdef (call))
> +    return false;
> +
> +  optab optab;
> +  switch (fn)
> +    {
> +    case IFN_ATOMIC_ADD_FETCH_CMP_0:
> +      optab = atomic_add_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_SUB_FETCH_CMP_0:
> +      optab = atomic_sub_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_AND_FETCH_CMP_0:
> +      optab = atomic_and_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_OR_FETCH_CMP_0:
> +      optab = atomic_or_fetch_cmp_0_optab;
> +      break;
> +    case IFN_ATOMIC_XOR_FETCH_CMP_0:
> +      optab = atomic_xor_fetch_cmp_0_optab;
> +      break;
> +    default:
> +      return false;
> +    }
> +
> +  if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
> +      == CODE_FOR_nothing)
> +    return false;
> +
> +  tree use_lhs = lhs;
> +  if (gimple_assign_cast_p (use_stmt))
> +    {
> +      use_lhs = gimple_assign_lhs (use_stmt);
> +      if (!tree_nop_conversion_p (TREE_TYPE (use_lhs), TREE_TYPE (lhs))
> +         || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
> +             && !POINTER_TYPE_P (TREE_TYPE (use_lhs)))
> +         || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs)
> +         || !single_imm_use (use_lhs, &use_p, &use_stmt))
> +       return false;
> +    }
> +  enum tree_code code = ERROR_MARK;
> +  tree op0 = NULL_TREE, op1 = NULL_TREE;
> +  if (is_gimple_assign (use_stmt))
> +    switch (gimple_assign_rhs_code (use_stmt))
> +      {
> +      case COND_EXPR:
> +       op1 = gimple_assign_rhs1 (use_stmt);
> +       code = TREE_CODE (op1);
> +       if (TREE_CODE_CLASS (code) == tcc_comparison)
> +         {
> +           op0 = TREE_OPERAND (op1, 0);
> +           op1 = TREE_OPERAND (op1, 1);
> +         }
> +       break;
> +      default:
> +       code = gimple_assign_rhs_code (use_stmt);
> +       if (TREE_CODE_CLASS (code) == tcc_comparison)
> +         {
> +           op0 = gimple_assign_rhs1 (use_stmt);
> +           op1 = gimple_assign_rhs2 (use_stmt);
> +         }
> +       break;
> +      }
> +  else if (gimple_code (use_stmt) == GIMPLE_COND)
> +    {
> +      code = gimple_cond_code (use_stmt);
> +      op0 = gimple_cond_lhs (use_stmt);
> +      op1 = gimple_cond_rhs (use_stmt);
> +    }
> +
> +  switch (code)
> +    {
> +    case LT_EXPR:
> +    case LE_EXPR:
> +    case GT_EXPR:
> +    case GE_EXPR:
> +      if (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
> +         || TREE_CODE (TREE_TYPE (use_lhs)) == BOOLEAN_TYPE
> +         || TYPE_UNSIGNED (TREE_TYPE (use_lhs)))
> +       return false;
> +      /* FALLTHRU */
> +    case EQ_EXPR:
> +    case NE_EXPR:
> +      if (op0 == use_lhs && integer_zerop (op1))
> +       break;
> +      return false;
> +    default:
> +      return false;
> +    }
> +
> +  int encoded;
> +  switch (code)
> +    {
> +    /* Use special encoding of the operation.  We want to also
> +       encode the mode in the first argument and for neither EQ_EXPR
> +       etc. nor EQ etc. we can rely it will fit into QImode.  */
> +    case EQ_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_EQ; break;
> +    case NE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_NE; break;
> +    case LT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LT; break;
> +    case LE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LE; break;
> +    case GT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GT; break;
> +    case GE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GE; break;
> +    default: gcc_unreachable ();
> +    }
> +
> +  tree new_lhs = make_ssa_name (boolean_type_node);
> +  gimple *g;
> +  tree flag = build_int_cst (TREE_TYPE (lhs), encoded);
> +  if (has_model_arg)
> +    g = gimple_build_call_internal (fn, 4, flag,
> +                                   gimple_call_arg (call, 0),
> +                                   gimple_call_arg (call, 1),
> +                                   gimple_call_arg (call, 2));
> +  else
> +    g = gimple_build_call_internal (fn, 3, flag,
> +                                   gimple_call_arg (call, 0),
> +                                   gimple_call_arg (call, 1));
> +  gimple_call_set_lhs (g, new_lhs);
> +  gimple_set_location (g, gimple_location (call));
> +  gimple_move_vops (g, call);
> +  bool throws = stmt_can_throw_internal (cfun, call);
> +  gimple_call_set_nothrow (as_a <gcall *> (g),
> +                          gimple_call_nothrow_p (as_a <gcall *> (call)));
> +  gimple_stmt_iterator gsi = *gsip;
> +  gsi_insert_after (&gsi, g, GSI_SAME_STMT);
> +  if (throws)
> +    maybe_clean_or_replace_eh_stmt (call, g);
> +  if (is_gimple_assign (use_stmt))
> +    switch (gimple_assign_rhs_code (use_stmt))
> +      {
> +      case COND_EXPR:
> +       gimple_assign_set_rhs1 (use_stmt, new_lhs);
> +       break;
> +      default:
> +       gsi = gsi_for_stmt (use_stmt);
> +       if (tree ulhs = gimple_assign_lhs (use_stmt))
> +         if (useless_type_conversion_p (TREE_TYPE (ulhs),
> +                                        boolean_type_node))
> +           {
> +             gimple_assign_set_rhs_with_ops (&gsi, SSA_NAME, new_lhs);
> +             break;
> +           }
> +       gimple_assign_set_rhs_with_ops (&gsi, NOP_EXPR, new_lhs);
> +       break;
> +      }
> +  else if (gimple_code (use_stmt) == GIMPLE_COND)
> +    {
> +      gcond *use_cond = as_a <gcond *> (use_stmt);
> +      gimple_cond_set_code (use_cond, NE_EXPR);
> +      gimple_cond_set_lhs (use_cond, new_lhs);
> +      gimple_cond_set_rhs (use_cond, boolean_false_node);
> +    }
> +
> +  update_stmt (use_stmt);
> +  if (use_lhs != lhs)
> +    {
> +      gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (use_lhs));
> +      gsi_remove (&gsi, true);
> +      release_ssa_name (use_lhs);
> +    }
> +  gsi_remove (gsip, true);
> +  release_ssa_name (lhs);
> +  return true;
>  }
>
>  /* Optimize
> @@ -4092,6 +4285,44 @@ pass_fold_builtins::execute (function *f
>                     cfg_changed = true;
>                   break;
>
> +               case BUILT_IN_ATOMIC_ADD_FETCH_1:
> +               case BUILT_IN_ATOMIC_ADD_FETCH_2:
> +               case BUILT_IN_ATOMIC_ADD_FETCH_4:
> +               case BUILT_IN_ATOMIC_ADD_FETCH_8:
> +               case BUILT_IN_ATOMIC_ADD_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_ADD_FETCH_CMP_0,
> +                                                 true);
> +                 break;
> +               case BUILT_IN_SYNC_ADD_AND_FETCH_1:
> +               case BUILT_IN_SYNC_ADD_AND_FETCH_2:
> +               case BUILT_IN_SYNC_ADD_AND_FETCH_4:
> +               case BUILT_IN_SYNC_ADD_AND_FETCH_8:
> +               case BUILT_IN_SYNC_ADD_AND_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_ADD_FETCH_CMP_0,
> +                                                 false);
> +                 break;
> +
> +               case BUILT_IN_ATOMIC_SUB_FETCH_1:
> +               case BUILT_IN_ATOMIC_SUB_FETCH_2:
> +               case BUILT_IN_ATOMIC_SUB_FETCH_4:
> +               case BUILT_IN_ATOMIC_SUB_FETCH_8:
> +               case BUILT_IN_ATOMIC_SUB_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_SUB_FETCH_CMP_0,
> +                                                 true);
> +                 break;
> +               case BUILT_IN_SYNC_SUB_AND_FETCH_1:
> +               case BUILT_IN_SYNC_SUB_AND_FETCH_2:
> +               case BUILT_IN_SYNC_SUB_AND_FETCH_4:
> +               case BUILT_IN_SYNC_SUB_AND_FETCH_8:
> +               case BUILT_IN_SYNC_SUB_AND_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_SUB_FETCH_CMP_0,
> +                                                 false);
> +                 break;
> +
>                 case BUILT_IN_ATOMIC_FETCH_OR_1:
>                 case BUILT_IN_ATOMIC_FETCH_OR_2:
>                 case BUILT_IN_ATOMIC_FETCH_OR_4:
> @@ -4133,16 +4364,24 @@ pass_fold_builtins::execute (function *f
>                 case BUILT_IN_ATOMIC_XOR_FETCH_4:
>                 case BUILT_IN_ATOMIC_XOR_FETCH_8:
>                 case BUILT_IN_ATOMIC_XOR_FETCH_16:
> -                 optimize_atomic_bit_test_and
> -                       (&i, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, true, true);
> +                 if (optimize_atomic_bit_test_and
> +                       (&i, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, true, true))
> +                   break;
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_XOR_FETCH_CMP_0,
> +                                                 true);
>                   break;
>                 case BUILT_IN_SYNC_XOR_AND_FETCH_1:
>                 case BUILT_IN_SYNC_XOR_AND_FETCH_2:
>                 case BUILT_IN_SYNC_XOR_AND_FETCH_4:
>                 case BUILT_IN_SYNC_XOR_AND_FETCH_8:
>                 case BUILT_IN_SYNC_XOR_AND_FETCH_16:
> -                 optimize_atomic_bit_test_and
> -                       (&i, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, false, true);
> +                 if (optimize_atomic_bit_test_and
> +                       (&i, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, false, true))
> +                   break;
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_XOR_FETCH_CMP_0,
> +                                                 false);
>                   break;
>
>                 case BUILT_IN_ATOMIC_FETCH_AND_1:
> @@ -4164,6 +4403,44 @@ pass_fold_builtins::execute (function *f
>                                                 false, false);
>                   break;
>
> +               case BUILT_IN_ATOMIC_AND_FETCH_1:
> +               case BUILT_IN_ATOMIC_AND_FETCH_2:
> +               case BUILT_IN_ATOMIC_AND_FETCH_4:
> +               case BUILT_IN_ATOMIC_AND_FETCH_8:
> +               case BUILT_IN_ATOMIC_AND_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_AND_FETCH_CMP_0,
> +                                                 true);
> +                 break;
> +               case BUILT_IN_SYNC_AND_AND_FETCH_1:
> +               case BUILT_IN_SYNC_AND_AND_FETCH_2:
> +               case BUILT_IN_SYNC_AND_AND_FETCH_4:
> +               case BUILT_IN_SYNC_AND_AND_FETCH_8:
> +               case BUILT_IN_SYNC_AND_AND_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_AND_FETCH_CMP_0,
> +                                                 false);
> +                 break;
> +
> +               case BUILT_IN_ATOMIC_OR_FETCH_1:
> +               case BUILT_IN_ATOMIC_OR_FETCH_2:
> +               case BUILT_IN_ATOMIC_OR_FETCH_4:
> +               case BUILT_IN_ATOMIC_OR_FETCH_8:
> +               case BUILT_IN_ATOMIC_OR_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_OR_FETCH_CMP_0,
> +                                                 true);
> +                 break;
> +               case BUILT_IN_SYNC_OR_AND_FETCH_1:
> +               case BUILT_IN_SYNC_OR_AND_FETCH_2:
> +               case BUILT_IN_SYNC_OR_AND_FETCH_4:
> +               case BUILT_IN_SYNC_OR_AND_FETCH_8:
> +               case BUILT_IN_SYNC_OR_AND_FETCH_16:
> +                 optimize_atomic_op_fetch_cmp_0 (&i,
> +                                                 IFN_ATOMIC_OR_FETCH_CMP_0,
> +                                                 false);
> +                 break;
> +
>                 case BUILT_IN_MEMCPY:
>                   if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
>                       && TREE_CODE (gimple_call_arg (stmt, 0)) == ADDR_EXPR
> --- gcc/config/i386/sync.md.jj  2021-11-15 13:19:07.347900863 +0100
> +++ gcc/config/i386/sync.md     2021-12-13 19:06:24.123913074 +0100
> @@ -938,3 +938,84 @@ (define_insn "atomic_bit_test_and_reset<
>         (const_int 0))]
>    ""
>    "lock{%;} %K2btr{<imodesuffix>}\t{%1, %0|%0, %1}")
> +
> +(define_expand "atomic_<plusminus_mnemonic>_fetch_cmp_0<mode>"
> +  [(match_operand:QI 0 "register_operand")
> +   (plusminus:SWI (match_operand:SWI 1 "memory_operand")
> +                 (match_operand:SWI 2 "nonmemory_operand"))
> +   (match_operand:SI 3 "const_int_operand") ;; model
> +   (match_operand:SI 4 "const_int_operand")]
> +  ""
> +{
> +  if (INTVAL (operands[4]) == GT || INTVAL (operands[4]) == LE)
> +    FAIL;
> +  emit_insn (gen_atomic_<plusminus_mnemonic>_fetch_cmp_0<mode>_1 
> (operands[1],
> +                                                                 operands[2],
> +                                                                 
> operands[3]));
> +  ix86_expand_setcc (operands[0], (enum rtx_code) INTVAL (operands[4]),
> +                    gen_rtx_REG (CCGOCmode, FLAGS_REG), const0_rtx);
> +  DONE;
> +})
> +
> +(define_insn "atomic_<plusminus_mnemonic>_fetch_cmp_0<mode>_1"

Please split this to a separate plus and minus pattern.

> +  [(set (reg:CCGOC FLAGS_REG)
> +       (compare:CCGOC
> +         (plusminus:SWI
> +           (unspec_volatile:SWI
> +             [(match_operand:SWI 0 "memory_operand" "+m")
> +              (match_operand:SI 2 "const_int_operand")]                ;; 
> model
> +             UNSPECV_XCHG)
> +           (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
> +         (const_int 0)))
> +   (set (match_dup 0)
> +       (plusminus:SWI (match_dup 0) (match_dup 1)))]
> +  ""
> +{
> +  if (incdec_operand (operands[1], <MODE>mode))
> +    {
> +      if ((operands[1] == const1_rtx) ^ (<CODE> != PLUS))
> +       return "lock{%;} %K2inc{<imodesuffix>}\t%0";
> +      else
> +       return "lock{%;} %K2dec{<imodesuffix>}\t%0";
> +    }
> +
> +  if (x86_maybe_negate_const_int (&operands[1], <MODE>mode))
> +    {
> +      if (<CODE> == PLUS)
> +       return "lock{%;} %K2sub{<imodesuffix>}\t{%1, %0|%0, %1}";
> +      else
> +       return "lock{%;} %K2add{<imodesuffix>}\t{%1, %0|%0, %1}";
> +    }
> +
> +  return "lock{%;} %K2<plusminus_mnemonic>{<imodesuffix>}\t{%1, %0|%0, %1}";
> +})
> +
> +(define_expand "atomic_<logic>_fetch_cmp_0<mode>"
> +  [(match_operand:QI 0 "register_operand")
> +   (any_logic:SWI (match_operand:SWI 1 "memory_operand")
> +                 (match_operand:SWI 2 "nonmemory_operand"))
> +   (match_operand:SI 3 "const_int_operand") ;; model
> +   (match_operand:SI 4 "const_int_operand")]
> +  ""
> +{
> +  emit_insn (gen_atomic_<logic>_fetch_cmp_0<mode>_1 (operands[1], 
> operands[2],
> +                                                    operands[3]));
> +  ix86_expand_setcc (operands[0], (enum rtx_code) INTVAL (operands[4]),
> +                    gen_rtx_REG (CCNOmode, FLAGS_REG), const0_rtx);
> +  DONE;
> +})
> +
> +(define_insn "atomic_<logic>_fetch_cmp_0<mode>_1"
> +  [(set (reg:CCNO FLAGS_REG)
> +       (compare:CCNO
> +         (any_logic:SWI
> +           (unspec_volatile:SWI
> +             [(match_operand:SWI 0 "memory_operand" "+m")
> +              (match_operand:SI 2 "const_int_operand")]                ;; 
> model
> +             UNSPECV_XCHG)
> +           (match_operand:SWI 1 "nonmemory_operand" "<r><i>"))
> +         (const_int 0)))
> +   (set (match_dup 0)
> +       (any_logic:SWI (match_dup 0) (match_dup 1)))]
> +  ""
> +  "lock{%;} %K2<logic>{<imodesuffix>}\t{%1, %0|%0, %1}")
> --- gcc/testsuite/gcc.target/i386/pr98737-1.c.jj        2021-12-14 
> 10:32:11.150582805 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-1.c   2021-12-14 10:32:05.211668125 
> +0100
> @@ -0,0 +1,207 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*subq\t" { target lp64 } } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*subl\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*subw\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*subb\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f17 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) == 0;
> +}
> +
> +int
> +f18 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) == 0;
> +}
> +
> +int
> +f19 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) == 0;
> +}
> +
> +int
> +f20 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) == 0;
> +}
> +
> +int
> +f21 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) != 0;
> +}
> +
> +int
> +f22 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) != 0;
> +}
> +
> +int
> +f23 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) != 0;
> +}
> +
> +int
> +f24 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) != 0;
> +}
> +
> +int
> +f25 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) < 0;
> +}
> +
> +int
> +f26 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) < 0;
> +}
> +
> +int
> +f27 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) < 0;
> +}
> +
> +int
> +f28 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) < 0;
> +}
> +
> +int
> +f29 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) >= 0;
> +}
> +
> +int
> +f30 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) >= 0;
> +}
> +
> +int
> +f31 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) >= 0;
> +}
> +
> +int
> +f32 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) >= 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-2.c.jj        2021-12-14 
> 10:32:26.619360582 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-2.c   2021-12-14 10:34:16.927782344 
> +0100
> @@ -0,0 +1,111 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*subq\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*subl\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*subw\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*subb\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_sub_fetch (&a, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_sub_fetch (&b, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_sub_fetch (&c, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_sub_fetch (&d, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) <= 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) <= 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) <= 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) <= 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __sync_sub_and_fetch (&a, x) > 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __sync_sub_and_fetch (&b, x) > 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __sync_sub_and_fetch (&c, x) > 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __sync_sub_and_fetch (&d, x) > 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-3.c.jj        2021-12-14 
> 10:34:31.544573270 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-3.c   2021-12-14 10:34:46.086365265 
> +0100
> @@ -0,0 +1,207 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*addq\t" { target lp64 } } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*addl\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*addw\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*addb\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f17 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) == 0;
> +}
> +
> +int
> +f18 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) == 0;
> +}
> +
> +int
> +f19 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) == 0;
> +}
> +
> +int
> +f20 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) == 0;
> +}
> +
> +int
> +f21 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) != 0;
> +}
> +
> +int
> +f22 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) != 0;
> +}
> +
> +int
> +f23 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) != 0;
> +}
> +
> +int
> +f24 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) != 0;
> +}
> +
> +int
> +f25 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) < 0;
> +}
> +
> +int
> +f26 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) < 0;
> +}
> +
> +int
> +f27 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) < 0;
> +}
> +
> +int
> +f28 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) < 0;
> +}
> +
> +int
> +f29 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) >= 0;
> +}
> +
> +int
> +f30 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) >= 0;
> +}
> +
> +int
> +f31 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) >= 0;
> +}
> +
> +int
> +f32 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) >= 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-4.c.jj        2021-12-14 
> 10:34:55.005237694 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-4.c   2021-12-14 10:36:54.492528580 
> +0100
> @@ -0,0 +1,111 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\rx]\*addq\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\rx]\*addl\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\rx]\*addw\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\rx]\*addb\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_add_fetch (&a, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_add_fetch (&b, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_add_fetch (&c, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_add_fetch (&d, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) <= 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) <= 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) <= 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) <= 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __sync_add_and_fetch (&a, x) > 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __sync_add_and_fetch (&b, x) > 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __sync_add_and_fetch (&c, x) > 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __sync_add_and_fetch (&d, x) > 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-5.c.jj        2021-12-14 
> 10:39:26.256357792 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-5.c   2021-12-14 10:39:22.027418280 
> +0100
> @@ -0,0 +1,303 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*andq\t" { target lp64 } } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*andl\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*andw\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*andb\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f17 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) == 0;
> +}
> +
> +int
> +f18 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) == 0;
> +}
> +
> +int
> +f19 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) == 0;
> +}
> +
> +int
> +f20 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) == 0;
> +}
> +
> +int
> +f21 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) != 0;
> +}
> +
> +int
> +f22 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) != 0;
> +}
> +
> +int
> +f23 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) != 0;
> +}
> +
> +int
> +f24 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) != 0;
> +}
> +
> +int
> +f25 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) < 0;
> +}
> +
> +int
> +f26 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) < 0;
> +}
> +
> +int
> +f27 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) < 0;
> +}
> +
> +int
> +f28 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) < 0;
> +}
> +
> +int
> +f29 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) >= 0;
> +}
> +
> +int
> +f30 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) >= 0;
> +}
> +
> +int
> +f31 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) >= 0;
> +}
> +
> +int
> +f32 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) >= 0;
> +}
> +
> +int
> +f33 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f34 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f35 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f36 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f37 (long x)
> +{
> +  return __atomic_and_fetch (&a, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f38 (int x)
> +{
> +  return __atomic_and_fetch (&b, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f39 (short x)
> +{
> +  return __atomic_and_fetch (&c, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f40 (char x)
> +{
> +  return __atomic_and_fetch (&d, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f41 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) <= 0;
> +}
> +
> +int
> +f42 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) <= 0;
> +}
> +
> +int
> +f43 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) <= 0;
> +}
> +
> +int
> +f44 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) <= 0;
> +}
> +
> +int
> +f45 (long x)
> +{
> +  return __sync_and_and_fetch (&a, x) > 0;
> +}
> +
> +int
> +f46 (int x)
> +{
> +  return __sync_and_and_fetch (&b, x) > 0;
> +}
> +
> +int
> +f47 (short x)
> +{
> +  return __sync_and_and_fetch (&c, x) > 0;
> +}
> +
> +int
> +f48 (char x)
> +{
> +  return __sync_and_and_fetch (&d, x) > 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-6.c.jj        2021-12-14 
> 10:39:40.076160115 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-6.c   2021-12-14 10:40:15.013660380 
> +0100
> @@ -0,0 +1,303 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*orq\t" { target lp64 } } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*orl\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*orw\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*orb\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f17 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) == 0;
> +}
> +
> +int
> +f18 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) == 0;
> +}
> +
> +int
> +f19 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) == 0;
> +}
> +
> +int
> +f20 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) == 0;
> +}
> +
> +int
> +f21 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) != 0;
> +}
> +
> +int
> +f22 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) != 0;
> +}
> +
> +int
> +f23 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) != 0;
> +}
> +
> +int
> +f24 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) != 0;
> +}
> +
> +int
> +f25 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) < 0;
> +}
> +
> +int
> +f26 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) < 0;
> +}
> +
> +int
> +f27 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) < 0;
> +}
> +
> +int
> +f28 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) < 0;
> +}
> +
> +int
> +f29 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) >= 0;
> +}
> +
> +int
> +f30 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) >= 0;
> +}
> +
> +int
> +f31 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) >= 0;
> +}
> +
> +int
> +f32 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) >= 0;
> +}
> +
> +int
> +f33 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f34 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f35 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f36 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f37 (long x)
> +{
> +  return __atomic_or_fetch (&a, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f38 (int x)
> +{
> +  return __atomic_or_fetch (&b, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f39 (short x)
> +{
> +  return __atomic_or_fetch (&c, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f40 (char x)
> +{
> +  return __atomic_or_fetch (&d, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f41 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) <= 0;
> +}
> +
> +int
> +f42 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) <= 0;
> +}
> +
> +int
> +f43 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) <= 0;
> +}
> +
> +int
> +f44 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) <= 0;
> +}
> +
> +int
> +f45 (long x)
> +{
> +  return __sync_or_and_fetch (&a, x) > 0;
> +}
> +
> +int
> +f46 (int x)
> +{
> +  return __sync_or_and_fetch (&b, x) > 0;
> +}
> +
> +int
> +f47 (short x)
> +{
> +  return __sync_or_and_fetch (&c, x) > 0;
> +}
> +
> +int
> +f48 (char x)
> +{
> +  return __sync_or_and_fetch (&d, x) > 0;
> +}
> --- gcc/testsuite/gcc.target/i386/pr98737-7.c.jj        2021-12-14 
> 10:40:23.587537740 +0100
> +++ gcc/testsuite/gcc.target/i386/pr98737-7.c   2021-12-14 10:40:59.445024845 
> +0100
> @@ -0,0 +1,303 @@
> +/* PR target/98737 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -masm=att" } */
> +/* { dg-additional-options "-march=i686" { target ia32 } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xorq\t" { target lp64 } } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xorl\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xorw\t" } } */
> +/* { dg-final { scan-assembler "lock\[^\n\r]\*xorb\t" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*xadd" } } */
> +/* { dg-final { scan-assembler-not "lock\[^\n\r]\*cmpxchg" } } */
> +
> +long a;
> +int b;
> +short c;
> +char d;
> +
> +int
> +f1 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f2 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f3 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f4 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) == 0;
> +}
> +
> +int
> +f5 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f6 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f7 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f8 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) != 0;
> +}
> +
> +int
> +f9 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f10 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f11 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f12 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) < 0;
> +}
> +
> +int
> +f13 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f14 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f15 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f16 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) >= 0;
> +}
> +
> +int
> +f17 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) == 0;
> +}
> +
> +int
> +f18 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) == 0;
> +}
> +
> +int
> +f19 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) == 0;
> +}
> +
> +int
> +f20 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) == 0;
> +}
> +
> +int
> +f21 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) != 0;
> +}
> +
> +int
> +f22 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) != 0;
> +}
> +
> +int
> +f23 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) != 0;
> +}
> +
> +int
> +f24 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) != 0;
> +}
> +
> +int
> +f25 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) < 0;
> +}
> +
> +int
> +f26 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) < 0;
> +}
> +
> +int
> +f27 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) < 0;
> +}
> +
> +int
> +f28 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) < 0;
> +}
> +
> +int
> +f29 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) >= 0;
> +}
> +
> +int
> +f30 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) >= 0;
> +}
> +
> +int
> +f31 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) >= 0;
> +}
> +
> +int
> +f32 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) >= 0;
> +}
> +
> +int
> +f33 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f34 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f35 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f36 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) <= 0;
> +}
> +
> +int
> +f37 (long x)
> +{
> +  return __atomic_xor_fetch (&a, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f38 (int x)
> +{
> +  return __atomic_xor_fetch (&b, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f39 (short x)
> +{
> +  return __atomic_xor_fetch (&c, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f40 (char x)
> +{
> +  return __atomic_xor_fetch (&d, x, __ATOMIC_RELEASE) > 0;
> +}
> +
> +int
> +f41 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) <= 0;
> +}
> +
> +int
> +f42 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) <= 0;
> +}
> +
> +int
> +f43 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) <= 0;
> +}
> +
> +int
> +f44 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) <= 0;
> +}
> +
> +int
> +f45 (long x)
> +{
> +  return __sync_xor_and_fetch (&a, x) > 0;
> +}
> +
> +int
> +f46 (int x)
> +{
> +  return __sync_xor_and_fetch (&b, x) > 0;
> +}
> +
> +int
> +f47 (short x)
> +{
> +  return __sync_xor_and_fetch (&c, x) > 0;
> +}
> +
> +int
> +f48 (char x)
> +{
> +  return __sync_xor_and_fetch (&d, x) > 0;
> +}
>
>
>         Jakub
>

Reply via email to