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 >