From: Soumya AR <[email protected]>
This patch introduces support for atomic fetch min/max operations through
a new internal function and gimple lowering pass. The implementation adds
four new generic builtins to sync-builtins.def:
- __atomic_fetch_min
- __atomic_fetch_max
- __atomic_min_fetch
- __atomic_max_fetch
These builtins are resolved to an internal function (IFN_ATOMIC_FETCH_MINMAX),
which encodes the operation type (min/max), signedness, and the fetch variant
(fetch_op vs op_fetch) as additional parameters.
The IFN is then lowered to a compare-and-swap loop by a new gimple pass
(pass_lower_ifn_atomic_minmax) that generates the following structure:
oldval = __atomic_load_n (ptr, memorder);
loop:
loop_oldval = PHI <oldval(initial), cas_oldval(backedge)>
newval = MIN_EXPR/MAX_EXPR (loop_oldval, value)
cas_result = __atomic_compare_exchange_n (ptr, &cas_expected,
newval, false, memorder,
MEMMODEL_RELAXED)
if (cas_result == 0)
goto loop;
exit:
result = loop_oldval (fetch_op) or newval (op_fetch)
---
If the backend supports the min/max optabs, the IFN should ideally be expanded
to those using expand_ATOMIC_FETCH_MINMAX. However, that functionality will be
covered in subsequent patches.
Signed-off-by: Soumya AR <[email protected]>
gcc/ChangeLog:
* Makefile.in: Add ifn-atomic-minmax-lowering.o.
* internal-fn.cc (expand_ATOMIC_FETCH_MINMAX): New function.
* internal-fn.def (ATOMIC_FETCH_MINMAX): New internal function.
* sync-builtins.def (BUILT_IN_ATOMIC_FETCH_MIN): New builtin.
(BUILT_IN_ATOMIC_FETCH_MAX): Likewise.
(BUILT_IN_ATOMIC_MIN_FETCH): Likewise.
(BUILT_IN_ATOMIC_MAX_FETCH): Likewise.
* passes.def: Add pass_lower_ifn_atomic_minmax after IPA.
* tree-pass.h (make_pass_lower_ifn_atomic_minmax): Declare.
* ifn-atomic-minmax-lowering.cc: New file implementing CAS lowering.
gcc/c-family/ChangeLog:
* c-common.cc (resolve_overloaded_builtin): Handle atomic min/max
builtins and lower to IFN_ATOMIC_FETCH_MINMAX.
gcc/testsuite/ChangeLog:
* gcc.dg/atomic-op-1.c: Add tests for atomic min/max operations.
* gcc.dg/atomic-op-2.c: Likewise.
* gcc.dg/atomic-op-3.c: Likewise.
* gcc.dg/atomic-op-4.c: Likewise.
* gcc.dg/atomic-op-5.c: Likewise.
---
gcc/Makefile.in | 1 +
gcc/c-family/c-common.cc | 43 +++-
gcc/ifn-atomic-minmax-lowering.cc | 372 +++++++++++++++++++++++++++++
gcc/internal-fn.cc | 12 +
gcc/internal-fn.def | 1 +
gcc/optabs.cc | 36 +++
gcc/optabs.def | 24 ++
gcc/passes.def | 1 +
gcc/sync-builtins.def | 15 ++
gcc/testsuite/gcc.dg/atomic-op-1.c | 353 +++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/atomic-op-2.c | 353 +++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/atomic-op-3.c | 353 +++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/atomic-op-4.c | 353 +++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/atomic-op-5.c | 355 +++++++++++++++++++++++++++
gcc/tree-pass.h | 1 +
15 files changed, 2271 insertions(+), 2 deletions(-)
create mode 100644 gcc/ifn-atomic-minmax-lowering.cc
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5c24a9aab00..e987918b8e6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1564,6 +1564,7 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+ ifn-atomic-minmax-lowering.o \
ipa-locality-cloning.o \
ipa-cp.o \
ipa-sra.o \
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f2eed033706..7109d4e26a8 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h"
#include "opts.h"
#include "gimplify.h"
+#include "internal-fn.h"
#include "substring-locations.h"
#include "spellcheck.h"
#include "c-spellcheck.h"
@@ -8708,6 +8709,10 @@ resolve_overloaded_builtin (location_t loc, tree
function,
case BUILT_IN_ATOMIC_FETCH_NAND_N:
case BUILT_IN_ATOMIC_FETCH_XOR_N:
case BUILT_IN_ATOMIC_FETCH_OR_N:
+ case BUILT_IN_ATOMIC_FETCH_MIN:
+ case BUILT_IN_ATOMIC_FETCH_MAX:
+ case BUILT_IN_ATOMIC_MIN_FETCH:
+ case BUILT_IN_ATOMIC_MAX_FETCH:
orig_format = false;
/* FALLTHRU */
case BUILT_IN_SYNC_FETCH_AND_ADD_N:
@@ -8737,8 +8742,9 @@ resolve_overloaded_builtin (location_t loc, tree function,
int n = sync_resolve_size (function, params, fetch_op, orig_format,
complain);
- tree new_function, first_param, result;
+ tree new_function, result;
enum built_in_function fncode;
+ tree first_param = (*params)[0];
if (n == 0)
return error_mark_node;
@@ -8758,13 +8764,46 @@ resolve_overloaded_builtin (location_t loc, tree
function,
params);
}
+ /* Atomic fetch min/max builtins are implemented through an IFN
+ that will be either lowered to a CAS loop or a direct builtin
+ depending on the target. */
+ if (orig_code == BUILT_IN_ATOMIC_FETCH_MIN
+ || orig_code == BUILT_IN_ATOMIC_FETCH_MAX
+ || orig_code == BUILT_IN_ATOMIC_MIN_FETCH
+ || orig_code == BUILT_IN_ATOMIC_MAX_FETCH)
+ {
+ bool is_min = (orig_code == BUILT_IN_ATOMIC_FETCH_MIN
+ || orig_code == BUILT_IN_ATOMIC_MIN_FETCH);
+ bool is_fetch_op = (orig_code == BUILT_IN_ATOMIC_FETCH_MIN
+ || orig_code == BUILT_IN_ATOMIC_FETCH_MAX);
+
+ tree datatype = TREE_TYPE (TREE_TYPE (first_param));
+ bool is_signed = !TYPE_UNSIGNED (datatype);
+
+ tree ptr = (*params)[0];
+ tree value = (*params)[1];
+ tree memorder = (*params)[2];
+ tree is_min_tree
+ = build_int_cst (integer_type_node, is_min ? 1 : 0);
+ tree is_fetch_op_tree
+ = build_int_cst (integer_type_node, is_fetch_op ? 1 : 0);
+ tree is_signed_tree
+ = build_int_cst (integer_type_node, is_signed ? 1 : 0);
+
+ tree ret
+ = build_call_expr_internal_loc (loc, IFN_ATOMIC_FETCH_MINMAX,
+ datatype, 6, ptr, value, memorder,
+ is_min_tree, is_fetch_op_tree,
+ is_signed_tree);
+
+ return sync_resolve_return (first_param, ret, orig_format);
+ }
fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1);
new_function = builtin_decl_explicit (fncode);
if (!sync_resolve_params (loc, function, new_function, params,
orig_format, complain))
return error_mark_node;
- first_param = (*params)[0];
result = build_function_call_vec (loc, vNULL, new_function, params,
NULL);
if (result == error_mark_node)
diff --git a/gcc/ifn-atomic-minmax-lowering.cc
b/gcc/ifn-atomic-minmax-lowering.cc
new file mode 100644
index 00000000000..eb989295789
--- /dev/null
+++ b/gcc/ifn-atomic-minmax-lowering.cc
@@ -0,0 +1,372 @@
+/* Lower internal function for atomic minmax to a CAS loop.
+ Copyright The GNU Toolchain Authors.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>.
+
+This pass lowers IFN_ATOMIC_FETCH_MINMAX calls to a Compare-and-Swap (CAS)
loop.
+
+A fetch_op call can be represented in the following manner:
+ oldval = atomic_load(ptr);
+ do {
+ newval = op (oldval, value);
+ } while (!atomic_compare_exchange(ptr, &oldval, newval));
+ return oldval;
+
+This pass transforms the IFN to the following pattern:
+
+ before_bb:
+ oldval_1 = atomic_load(ptr)
+ goto loop
+
+ loop_bb:
+ oldval_2 = PHI<oldval_1(before_bb), oldval_3(loop_bb)>
+ newval = MIN/MAX(oldval_2, value)
+ success = CAS(ptr, &oldval, newval)
+ oldval_3 = *(&oldval) // CAS updates oldval on failure
+ if (success) goto exit else goto loop
+
+ exit_bb:
+ // return oldval_2 (or newval if op_fetch)
+
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "ssa.h"
+#include "optabs-query.h"
+#include "tree-ssanames.h"
+#include "fold-const.h"
+#include "cfganal.h"
+#include "gimple-fold.h"
+#include "tree-cfg.h"
+#include "gimplify.h"
+#include "gimple-ssa.h"
+#include "tree-ssa-operands.h"
+#include "builtins.h"
+#include "internal-fn.h"
+#include "tree-into-ssa.h"
+
+/* Helper function to convert between types and insert into gimple sequence.
+ Returns the SSA name holding the converted value. */
+
+static tree
+insert_type_conversion (gimple_stmt_iterator *gsi, tree src_value,
+ tree dest_type, enum tree_code convert_code = NOP_EXPR,
+ bool insert_after = true)
+{
+ if (TREE_TYPE (src_value) == dest_type)
+ return src_value;
+
+ tree result = make_ssa_name (dest_type);
+ gassign *convert_stmt = gimple_build_assign (result, convert_code,
src_value);
+
+ if (insert_after)
+ gsi_insert_after (gsi, convert_stmt, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, convert_stmt, GSI_SAME_STMT);
+
+ return result;
+}
+
+/* Lower a single IFN_ATOMIC_FETCH_MINMAX call to a CAS loop. */
+
+static void
+lower_ifn_atomic_minmax_to_cas (gimple_stmt_iterator *iter, gcall *stmt)
+{
+ tree ptr = gimple_call_arg (stmt, 0);
+ tree value = gimple_call_arg (stmt, 1);
+ tree memorder = gimple_call_arg (stmt, 2);
+ tree is_min = gimple_call_arg (stmt, 3);
+ tree is_fetch_op = gimple_call_arg (stmt, 4);
+
+ tree datatype = TREE_TYPE (TREE_TYPE (ptr));
+
+ bool is_min_bool = tree_to_uhwi (is_min);
+ tree_code cmp_code = is_min_bool ? MIN_EXPR : MAX_EXPR;
+
+ /* Build the atomic builtins we need. */
+ int size_log2 = exact_log2 (tree_to_uhwi (TYPE_SIZE_UNIT (datatype)));
+ built_in_function load_builtin_fn
+ = (built_in_function) ((int) BUILT_IN_ATOMIC_LOAD_N + size_log2 + 1);
+ tree load_fn = builtin_decl_explicit (load_builtin_fn);
+
+ built_in_function cas_builtin_fn
+ = (built_in_function) ((int) BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N + size_log2
+ + 1);
+ tree cas_fn = builtin_decl_explicit (cas_builtin_fn);
+
+ /* Atomic operations expect unsigned values as arguments. Calcualte the
+ corresponding unsigned type. */
+ tree unsigned_type = unsigned_type_for (datatype);
+
+ /* Insert atomic load before the IFN. We will be using the IFN as a split
+ point later to insert the loop body. Since the load is not part of the
+ loop body, we insert it before the IFN. */
+ tree initial_oldval = make_ssa_name (unsigned_type);
+ gcall *load_call
+ = gimple_build_call (load_fn, 2, ptr,
+ build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+ gimple_call_set_lhs (load_call, initial_oldval);
+ gsi_insert_before (iter, load_call, GSI_SAME_STMT);
+
+ /* Save LHS before removing the IFN. Need it later to assign the result. */
+ tree lhs = gimple_call_lhs (stmt);
+
+ /* Build the loop body. We will be inserting this after the split point. */
+ gimple_seq loop_body = NULL;
+ gimple_stmt_iterator gsi_loop = gsi_last (loop_body);
+
+ /* Create a SSA name for the loop variable. This will be the PHI node in the
+ loop body. */
+ tree loop_oldval = make_ssa_name (unsigned_type);
+
+ /* Convert to original type for MIN/MAX if needed */
+ tree oldval_typed
+ = TYPE_UNSIGNED (datatype)
+ ? loop_oldval
+ : insert_type_conversion (&gsi_loop, loop_oldval, datatype);
+
+ /* Convert value to the same type as oldval_typed */
+ tree value_typed = value;
+ if (TREE_TYPE (value) != datatype)
+ value_typed = insert_type_conversion (&gsi_loop, value, datatype);
+
+ /* Compute newval = MIN/MAX(oldval, value) */
+ tree newval = make_ssa_name (datatype);
+ gassign *minmax_assign
+ = gimple_build_assign (newval, cmp_code, oldval_typed, value_typed);
+ gsi_insert_after (&gsi_loop, minmax_assign, GSI_NEW_STMT);
+
+ /* Convert newval to unsigned for CAS if needed. */
+ tree newval_unsigned
+ = TYPE_UNSIGNED (datatype)
+ ? newval
+ : insert_type_conversion (&gsi_loop, newval, unsigned_type);
+
+ /* For CAS, we need a temporary addressable variable. CAS expects oldval to
+ be addressable. Therefore, using the SSA name won't work. */
+ tree cas_expected = create_tmp_var (unsigned_type, "cas_expected");
+ TREE_ADDRESSABLE (cas_expected) = 1;
+
+ /* Store the current oldval into the addressable variable */
+ gsi_insert_after (&gsi_loop, gimple_build_assign (cas_expected, loop_oldval),
+ GSI_NEW_STMT);
+
+ tree cas_result = make_ssa_name (boolean_type_node);
+ tree cas_expected_addr = build_fold_addr_expr (cas_expected);
+
+ gcall *cas_call
+ = gimple_build_call (cas_fn, 6, ptr, /* address to update */
+ cas_expected_addr, /* expected value */
+ newval_unsigned, /* desired value */
+ boolean_false_node, /* weak */
+ memorder, /* success order */
+ build_int_cst (integer_type_node,
+ MEMMODEL_RELAXED)); /* failure order */
+ gimple_call_set_lhs (cas_call, cas_result);
+ gsi_insert_after (&gsi_loop, cas_call, GSI_NEW_STMT);
+
+ /* On failure (desired != expected), CAS updated the expected value. Read it
+ back into SSA form. */
+ tree cas_oldval_updated = make_ssa_name (unsigned_type);
+ gsi_insert_after (&gsi_loop,
+ gimple_build_assign (cas_oldval_updated, cas_expected),
+ GSI_NEW_STMT);
+
+ /* Add conditional to end of loop body. Currently, the conditional statement
+ has no successors. We will be adding loop_bb and exit_bb as successors
+ later. */
+ gcond *loop_cond = gimple_build_cond (NE_EXPR, cas_result,
+ build_int_cst (boolean_type_node, 0),
+ NULL_TREE, NULL_TREE);
+ gsi_insert_after (&gsi_loop, loop_cond, GSI_NEW_STMT);
+
+ /* Get the previous statement in the basic block. We will be using it to
split
+ the block after the atomic load.
+
+ Currently, the iter points to the IFN. The bb looks something like:
+
+ <previous_code>
+ |
+ atomic_load(ptr)
+ |
+ IFN_ATOMIC_FETCH_MINMAX <- gsi
+ |
+ <following_code>
+
+ We need to remove the IFN and replace it with the loop body. To do this,
+ we split at the IFN, and further split the resultant edge to insert the
+ loop body, resulting in:
+
+ before_bb (contains <previous_code> and atomic_load(ptr))
+ |
+ loop_bb (contains the MIN/MAX operation and the CAS operation)
+ |
+ after_bb (contains <following_code>)
+
+ */
+
+ gimple_stmt_iterator prev_gsi = *iter;
+ gsi_prev (&prev_gsi);
+
+ /* Remove the IFN */
+ gsi_remove (iter, true);
+
+ edge e = split_block (gsi_bb (prev_gsi), gsi_stmt (prev_gsi));
+ basic_block exit_bb = e->dest;
+ basic_block loop_bb = split_edge (e);
+
+ /* Create PHI node for oldval. One edge will come from the predecessor
+ (initial_oldval), and the other will come from the loop back
+ (cas_oldval_updated). */
+ gphi *loop_phi = create_phi_node (loop_oldval, loop_bb);
+ add_phi_arg (loop_phi, initial_oldval, single_pred_edge (loop_bb),
+ UNKNOWN_LOCATION);
+
+ /* Insert the loop body into loop_bb. */
+ set_bb_seq (loop_bb, loop_body);
+
+ /* Set the basic block for all statements in the loop body to ensure they
+ are correctly assigned to loop_bb. */
+ for (gimple_stmt_iterator si = gsi_start_bb (loop_bb); !gsi_end_p (si);
+ gsi_next (&si))
+ gimple_set_bb (gsi_stmt (si), loop_bb);
+
+ /* loop_bb currently has a fallthrough edge to exit_bb, due to split_edge.
+ We need to remove it and create two conditional edges */
+ remove_edge (single_succ_edge (loop_bb));
+ edge true_edge = make_edge (loop_bb, exit_bb, EDGE_TRUE_VALUE);
+ edge false_edge = make_edge (loop_bb, loop_bb, EDGE_FALSE_VALUE);
+
+ false_edge->probability = profile_probability::unlikely ();
+ true_edge->probability = false_edge->probability.invert ();
+
+ /* Add the loop-back phi argument */
+ add_phi_arg (loop_phi, cas_oldval_updated, false_edge, UNKNOWN_LOCATION);
+
+ bool is_fetch_op_bool = tree_to_uhwi (is_fetch_op);
+ if (lhs)
+ {
+ gimple_stmt_iterator exit_gsi = gsi_after_labels (exit_bb);
+ tree result;
+
+ if (is_fetch_op_bool)
+ {
+ /* fetch_min/fetch_max: return the old value. */
+ result = TYPE_UNSIGNED (datatype)
+ ? loop_oldval
+ : insert_type_conversion (&exit_gsi, loop_oldval, datatype,
+ NOP_EXPR, false);
+ }
+ else
+ {
+ /* min_fetch/max_fetch: return the new value. */
+ result = newval;
+ }
+
+ gassign *return_result = gimple_build_assign (lhs, result);
+ gsi_insert_before (&exit_gsi, return_result, GSI_SAME_STMT);
+ }
+}
+
+static unsigned int
+lower_ifn_atomic_minmax (void)
+{
+ basic_block bb;
+ bool changed = false;
+
+ /* Iterate through all basic blocks looking for IFN calls to lower */
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ if (is_gimple_call (stmt))
+ {
+ gcall *call_stmt = as_a<gcall *> (stmt);
+ if (gimple_call_internal_p (call_stmt)
+ && gimple_call_internal_fn (call_stmt)
+ == IFN_ATOMIC_FETCH_MINMAX)
+ {
+ lower_ifn_atomic_minmax_to_cas (&gsi, call_stmt);
+ changed = true;
+ continue;
+ }
+ }
+ gsi_next (&gsi);
+ }
+ }
+
+ return changed ? TODO_update_ssa | TODO_cleanup_cfg : 0;
+}
+
+static bool
+gate_lower_ifn_atomic_minmax (void)
+{
+ return true;
+}
+
+namespace {
+
+const pass_data pass_data_lower_ifn_atomic_minmax = {
+ GIMPLE_PASS, /* type */
+ "lower-ifn-atomic-minmax", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ (PROP_cfg | PROP_ssa), /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa /* todo_flags_finish */
+};
+
+class pass_lower_ifn_atomic_minmax : public gimple_opt_pass
+{
+public:
+ pass_lower_ifn_atomic_minmax (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_lower_ifn_atomic_minmax, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate (function *) final override
+ {
+ return gate_lower_ifn_atomic_minmax ();
+ }
+ unsigned int execute (function *) final override
+ {
+ return lower_ifn_atomic_minmax ();
+ }
+}; // class pass_lower_ifn_atomic_minmax
+
+} // namespace
+
+gimple_opt_pass *
+make_pass_lower_ifn_atomic_minmax (gcc::context *ctxt)
+{
+ return new pass_lower_ifn_atomic_minmax (ctxt);
+}
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 514fe98f40d..319c3c5b6f5 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -3632,6 +3632,18 @@ expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
expand_ifn_atomic_op_fetch_cmp_0 (call);
}
+/* Expand atomic fetch minmax. */
+
+static void
+expand_ATOMIC_FETCH_MINMAX (internal_fn, gcall *stmt)
+{
+ /* This should only be reached if the GIMPLE pass determined that
+ an optab exists for this operation.
+
+ TODO: Implement this. */
+
+}
+
/* Expand LAUNDER to assignment, lhs = arg0. */
static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 7874fcfb3df..5c7b39e756d 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -572,6 +572,7 @@ 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)
+DEF_INTERNAL_FN (ATOMIC_FETCH_MINMAX, ECF_LEAF, NULL)
/* To implement [[fallthrough]]. If the TREE_NOTHROW or GF_CALL_NOTHROW flag
is set on the call (normally redundant with ECF_NOTHROW), it marks
diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 0865fc2e19a..207ddac6c1c 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -7588,6 +7588,42 @@ get_atomic_op_for_code (struct atomic_op_functions *op,
enum rtx_code code)
op->no_result = sync_nand_optab;
op->reverse_code = UNKNOWN;
break;
+ case SMIN:
+ op->mem_fetch_before = atomic_fetch_smin_optab;
+ op->mem_fetch_after = atomic_smin_fetch_optab;
+ op->mem_no_result = atomic_smin_optab;
+ op->fetch_before = sync_old_smin_optab;
+ op->fetch_after = sync_new_smin_optab;
+ op->no_result = sync_smin_optab;
+ op->reverse_code = UNKNOWN;
+ break;
+ case SMAX:
+ op->mem_fetch_before = atomic_fetch_smax_optab;
+ op->mem_fetch_after = atomic_smax_fetch_optab;
+ op->mem_no_result = atomic_smax_optab;
+ op->fetch_before = sync_old_smax_optab;
+ op->fetch_after = sync_new_smax_optab;
+ op->no_result = sync_smax_optab;
+ op->reverse_code = UNKNOWN;
+ break;
+ case UMIN:
+ op->mem_fetch_before = atomic_fetch_umin_optab;
+ op->mem_fetch_after = atomic_umin_fetch_optab;
+ op->mem_no_result = atomic_umin_optab;
+ op->fetch_before = sync_old_umin_optab;
+ op->fetch_after = sync_new_umin_optab;
+ op->no_result = sync_umin_optab;
+ op->reverse_code = UNKNOWN;
+ break;
+ case UMAX:
+ op->mem_fetch_before = atomic_fetch_umax_optab;
+ op->mem_fetch_after = atomic_umax_fetch_optab;
+ op->mem_no_result = atomic_umax_optab;
+ op->fetch_before = sync_old_umax_optab;
+ op->fetch_after = sync_new_umax_optab;
+ op->no_result = sync_umax_optab;
+ op->reverse_code = UNKNOWN;
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/optabs.def b/gcc/optabs.def
index b6f290a9513..bd58650494c 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -213,12 +213,20 @@ OPTAB_NC(sync_old_ior_optab, "sync_old_ior$I$a", UNKNOWN)
OPTAB_NC(sync_old_and_optab, "sync_old_and$I$a", UNKNOWN)
OPTAB_NC(sync_old_xor_optab, "sync_old_xor$I$a", UNKNOWN)
OPTAB_NC(sync_old_nand_optab, "sync_old_nand$I$a", UNKNOWN)
+OPTAB_NC(sync_old_smin_optab, "sync_old_smin$I$a", UNKNOWN)
+OPTAB_NC(sync_old_smax_optab, "sync_old_smax$I$a", UNKNOWN)
+OPTAB_NC(sync_old_umin_optab, "sync_old_umin$I$a", UNKNOWN)
+OPTAB_NC(sync_old_umax_optab, "sync_old_umax$I$a", UNKNOWN)
OPTAB_NC(sync_new_add_optab, "sync_new_add$I$a", UNKNOWN)
OPTAB_NC(sync_new_sub_optab, "sync_new_sub$I$a", UNKNOWN)
OPTAB_NC(sync_new_ior_optab, "sync_new_ior$I$a", UNKNOWN)
OPTAB_NC(sync_new_and_optab, "sync_new_and$I$a", UNKNOWN)
OPTAB_NC(sync_new_xor_optab, "sync_new_xor$I$a", UNKNOWN)
OPTAB_NC(sync_new_nand_optab, "sync_new_nand$I$a", UNKNOWN)
+OPTAB_NC(sync_new_smin_optab, "sync_new_smin$I$a", UNKNOWN)
+OPTAB_NC(sync_new_smax_optab, "sync_new_smax$I$a", UNKNOWN)
+OPTAB_NC(sync_new_umin_optab, "sync_new_umin$I$a", UNKNOWN)
+OPTAB_NC(sync_new_umax_optab, "sync_new_umax$I$a", UNKNOWN)
OPTAB_NC(sync_compare_and_swap_optab, "sync_compare_and_swap$I$a", UNKNOWN)
OPTAB_NC(sync_lock_test_and_set_optab, "sync_lock_test_and_set$I$a", UNKNOWN)
@@ -506,6 +514,10 @@ OPTAB_D (sync_and_optab, "sync_and$I$a")
OPTAB_D (sync_ior_optab, "sync_ior$I$a")
OPTAB_D (sync_lock_release_optab, "sync_lock_release$I$a")
OPTAB_D (sync_nand_optab, "sync_nand$I$a")
+OPTAB_D (sync_smin_optab, "sync_smin$I$a")
+OPTAB_D (sync_smax_optab, "sync_smax$I$a")
+OPTAB_D (sync_umin_optab, "sync_umin$I$a")
+OPTAB_D (sync_umax_optab, "sync_umax$I$a")
OPTAB_D (sync_sub_optab, "sync_sub$I$a")
OPTAB_D (sync_xor_optab, "sync_xor$I$a")
@@ -524,6 +536,18 @@ OPTAB_D (atomic_fetch_nand_optab, "atomic_fetch_nand$I$a")
OPTAB_D (atomic_fetch_or_optab, "atomic_fetch_or$I$a")
OPTAB_D (atomic_fetch_sub_optab, "atomic_fetch_sub$I$a")
OPTAB_D (atomic_fetch_xor_optab, "atomic_fetch_xor$I$a")
+OPTAB_D (atomic_fetch_smax_optab, "atomic_fetch_smax$I$a")
+OPTAB_D (atomic_fetch_smin_optab, "atomic_fetch_smin$I$a")
+OPTAB_D (atomic_smax_fetch_optab, "atomic_smax_fetch$I$a")
+OPTAB_D (atomic_smin_fetch_optab, "atomic_smin_fetch$I$a")
+OPTAB_D (atomic_smax_optab, "atomic_smax$I$a")
+OPTAB_D (atomic_smin_optab, "atomic_smin$I$a")
+OPTAB_D (atomic_fetch_umax_optab, "atomic_fetch_umax$I$a")
+OPTAB_D (atomic_fetch_umin_optab, "atomic_fetch_umin$I$a")
+OPTAB_D (atomic_umax_fetch_optab, "atomic_umax_fetch$I$a")
+OPTAB_D (atomic_umin_fetch_optab, "atomic_umin_fetch$I$a")
+OPTAB_D (atomic_umax_optab, "atomic_umax$I$a")
+OPTAB_D (atomic_umin_optab, "atomic_umin$I$a")
OPTAB_D (atomic_load_optab, "atomic_load$I$a")
OPTAB_D (atomic_nand_fetch_optab, "atomic_nand_fetch$I$a")
OPTAB_D (atomic_nand_optab, "atomic_nand$I$a")
diff --git a/gcc/passes.def b/gcc/passes.def
index fac04cd86c7..d003cc0fb81 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -204,6 +204,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_omp_target_link);
NEXT_PASS (pass_adjust_alignment);
NEXT_PASS (pass_harden_control_flow_redundancy);
+ NEXT_PASS (pass_lower_ifn_atomic_minmax);
NEXT_PASS (pass_all_optimizations);
PUSH_INSERT_PASSES_WITHIN (pass_all_optimizations)
NEXT_PASS (pass_remove_cgraph_callee_edges);
diff --git a/gcc/sync-builtins.def b/gcc/sync-builtins.def
index 0f058187a20..3ae0570f23d 100644
--- a/gcc/sync-builtins.def
+++ b/gcc/sync-builtins.def
@@ -597,6 +597,21 @@ DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_IS_LOCK_FREE,
"__atomic_is_lock_free",
BT_FN_BOOL_SIZE_CONST_VPTR, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_MIN,
+ "__atomic_fetch_min",
+ BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
+
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_MAX,
+ "__atomic_fetch_max",
+ BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
+
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_MIN_FETCH,
+ "__atomic_min_fetch",
+ BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
+
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_MAX_FETCH,
+ "__atomic_max_fetch",
+ BT_FN_VOID_VAR, ATTR_NOTHROWCALL_LEAF_LIST)
DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_THREAD_FENCE,
"__atomic_thread_fence",
diff --git a/gcc/testsuite/gcc.dg/atomic-op-1.c
b/gcc/testsuite/gcc.dg/atomic-op-1.c
index a8a97c401b7..ed2fa629187 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-1.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-1.c
@@ -5,6 +5,8 @@
/* Test the execution of the __atomic_*OP builtin routines for a char. */
+#include "limits.h"
+
extern void abort(void);
char v, count, res;
@@ -167,6 +169,114 @@ test_fetch_or ()
abort ();
}
+void
+test_fetch_smin ()
+{
+ signed char sv = 10;
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -10, __ATOMIC_ACQUIRE) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE) != -10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SCHAR_MIN, __ATOMIC_ACQ_REL) != -20)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST) != SCHAR_MIN)
+ abort ();
+
+ if (sv != SCHAR_MIN)
+ abort ();
+}
+
+void
+test_fetch_umin ()
+{
+ unsigned char uv = 100;
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_RELAXED) != 100)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 0, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_fetch_smax ()
+{
+ signed char sv = -10;
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_RELAXED) != -10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 50, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST) != 50)
+ abort ();
+
+ if (sv != SCHAR_MAX)
+ abort ();
+}
+
+void
+test_fetch_umax ()
+{
+ unsigned char uv = 10;
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 200, __ATOMIC_ACQ_REL) != 100)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST) != 200)
+ abort ();
+
+ if (uv != UCHAR_MAX)
+ abort ();
+}
+
/* The OP_fetch routines return the new value after the operation. */
void
@@ -328,6 +438,113 @@ test_or_fetch ()
abort ();
}
+void
+test_smin_fetch ()
+{
+ signed char sv = 10;
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE) != -10)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -20, __ATOMIC_RELEASE) != -20)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SCHAR_MIN, __ATOMIC_ACQ_REL) != SCHAR_MIN)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST) != SCHAR_MIN)
+ abort ();
+
+ if (sv != SCHAR_MIN)
+ abort ();
+}
+
+void
+test_umin_fetch ()
+{
+ unsigned char uv = 100;
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax_fetch ()
+{
+ signed char sv = -10;
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST) != SCHAR_MAX)
+ abort ();
+
+ if (sv != SCHAR_MAX)
+ abort ();
+}
+
+void
+test_umax_fetch ()
+{
+ unsigned char uv = 10;
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 100, __ATOMIC_RELEASE) != 100)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL) != 200)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST) != UCHAR_MAX)
+ abort ();
+
+ if (uv != UCHAR_MAX)
+ abort ();
+}
/* Test the OP routines with a result which isn't used. Use both variations
within each function. */
@@ -527,6 +744,130 @@ test_or ()
abort ();
}
+void
+test_smin ()
+{
+ signed char sv = 10;
+
+ __atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED);
+ if (sv != 5)
+ abort ();
+
+ __atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME);
+ if (sv != 5)
+ abort ();
+
+ __atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE);
+ if (sv != -10)
+ abort ();
+
+ __atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE);
+ if (sv != -20)
+ abort ();
+
+ __atomic_min_fetch (&sv, SCHAR_MIN, __ATOMIC_ACQ_REL);
+ if (sv != SCHAR_MIN)
+ abort ();
+
+ __atomic_fetch_min (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SCHAR_MIN)
+ abort ();
+}
+
+void
+test_umin ()
+{
+ unsigned char uv = 100;
+
+ __atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE);
+ if (uv != 10)
+ abort ();
+
+ __atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL);
+ if (uv != 0)
+ abort ();
+
+ __atomic_fetch_min (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax ()
+{
+ signed char sv = -10;
+
+ __atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME);
+ if (sv != -5)
+ abort ();
+
+ __atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE);
+ if (sv != 10)
+ abort ();
+
+ __atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL);
+ if (sv != 50)
+ abort ();
+
+ __atomic_fetch_max (&sv, SCHAR_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SCHAR_MAX)
+ abort ();
+}
+
+void
+test_umax ()
+{
+ unsigned char uv = 10;
+
+ __atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE);
+ if (uv != 100)
+ abort ();
+
+ __atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL);
+ if (uv != 200)
+ abort ();
+
+ __atomic_fetch_max (&uv, UCHAR_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != UCHAR_MAX)
+ abort ();
+}
+
int
main ()
{
@@ -536,6 +877,10 @@ main ()
test_fetch_nand ();
test_fetch_xor ();
test_fetch_or ();
+ test_fetch_smin ();
+ test_fetch_umin ();
+ test_fetch_smax ();
+ test_fetch_umax ();
test_add_fetch ();
test_sub_fetch ();
@@ -543,6 +888,10 @@ main ()
test_nand_fetch ();
test_xor_fetch ();
test_or_fetch ();
+ test_smin_fetch ();
+ test_umin_fetch ();
+ test_smax_fetch ();
+ test_umax_fetch ();
test_add ();
test_sub ();
@@ -550,6 +899,10 @@ main ()
test_nand ();
test_xor ();
test_or ();
+ test_smin ();
+ test_umin ();
+ test_smax ();
+ test_umax ();
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-2.c
b/gcc/testsuite/gcc.dg/atomic-op-2.c
index 949850345b5..95dcdd02097 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-2.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-2.c
@@ -6,6 +6,8 @@
/* Test the execution of the __atomic_*OP builtin routines for a short. */
+#include "limits.h"
+
extern void abort(void);
short v, count, res;
@@ -168,6 +170,114 @@ test_fetch_or ()
abort ();
}
+void
+test_fetch_smin ()
+{
+ short sv = 10;
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -10, __ATOMIC_ACQUIRE) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE) != -10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SHRT_MIN, __ATOMIC_ACQ_REL) != -20)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SHRT_MAX, __ATOMIC_SEQ_CST) != SHRT_MIN)
+ abort ();
+
+ if (sv != SHRT_MIN)
+ abort ();
+}
+
+void
+test_fetch_umin ()
+{
+ unsigned short uv = 100;
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_RELAXED) != 100)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 0, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, USHRT_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_fetch_smax ()
+{
+ short sv = -10;
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_RELAXED) != -10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 50, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, SHRT_MAX, __ATOMIC_SEQ_CST) != 50)
+ abort ();
+
+ if (sv != SHRT_MAX)
+ abort ();
+}
+
+void
+test_fetch_umax ()
+{
+ unsigned short uv = 10;
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 200, __ATOMIC_ACQ_REL) != 100)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, USHRT_MAX, __ATOMIC_SEQ_CST) != 200)
+ abort ();
+
+ if (uv != USHRT_MAX)
+ abort ();
+}
+
/* The OP_fetch routines return the new value after the operation. */
void
@@ -329,6 +439,113 @@ test_or_fetch ()
abort ();
}
+void
+test_smin_fetch ()
+{
+ short sv = 10;
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE) != -10)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -20, __ATOMIC_RELEASE) != -20)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SHRT_MIN, __ATOMIC_ACQ_REL) != SHRT_MIN)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SHRT_MAX, __ATOMIC_SEQ_CST) != SHRT_MIN)
+ abort ();
+
+ if (sv != SHRT_MIN)
+ abort ();
+}
+
+void
+test_umin_fetch ()
+{
+ unsigned short uv = 100;
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, USHRT_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax_fetch ()
+{
+ short sv = -10;
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, SHRT_MAX, __ATOMIC_SEQ_CST) != SHRT_MAX)
+ abort ();
+
+ if (sv != SHRT_MAX)
+ abort ();
+}
+
+void
+test_umax_fetch ()
+{
+ unsigned short uv = 10;
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 100, __ATOMIC_RELEASE) != 100)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL) != 200)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, USHRT_MAX, __ATOMIC_SEQ_CST) != USHRT_MAX)
+ abort ();
+
+ if (uv != USHRT_MAX)
+ abort ();
+}
/* Test the OP routines with a result which isn't used. Use both variations
within each function. */
@@ -528,6 +745,130 @@ test_or ()
abort ();
}
+void
+test_smin ()
+{
+ short sv = 10;
+
+ __atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED);
+ if (sv != 5)
+ abort ();
+
+ __atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME);
+ if (sv != 5)
+ abort ();
+
+ __atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE);
+ if (sv != -10)
+ abort ();
+
+ __atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE);
+ if (sv != -20)
+ abort ();
+
+ __atomic_min_fetch (&sv, SHRT_MIN, __ATOMIC_ACQ_REL);
+ if (sv != SHRT_MIN)
+ abort ();
+
+ __atomic_fetch_min (&sv, SHRT_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SHRT_MIN)
+ abort ();
+}
+
+void
+test_umin ()
+{
+ unsigned short uv = 100;
+
+ __atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE);
+ if (uv != 10)
+ abort ();
+
+ __atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL);
+ if (uv != 0)
+ abort ();
+
+ __atomic_fetch_min (&uv, USHRT_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax ()
+{
+ short sv = -10;
+
+ __atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME);
+ if (sv != -5)
+ abort ();
+
+ __atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE);
+ if (sv != 10)
+ abort ();
+
+ __atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL);
+ if (sv != 50)
+ abort ();
+
+ __atomic_fetch_max (&sv, SHRT_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SHRT_MAX)
+ abort ();
+}
+
+void
+test_umax ()
+{
+ unsigned short uv = 10;
+
+ __atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE);
+ if (uv != 100)
+ abort ();
+
+ __atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL);
+ if (uv != 200)
+ abort ();
+
+ __atomic_fetch_max (&uv, USHRT_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != USHRT_MAX)
+ abort ();
+}
+
int
main ()
{
@@ -537,6 +878,10 @@ main ()
test_fetch_nand ();
test_fetch_xor ();
test_fetch_or ();
+ test_fetch_smin ();
+ test_fetch_umin ();
+ test_fetch_smax ();
+ test_fetch_umax ();
test_add_fetch ();
test_sub_fetch ();
@@ -544,6 +889,10 @@ main ()
test_nand_fetch ();
test_xor_fetch ();
test_or_fetch ();
+ test_smin_fetch ();
+ test_umin_fetch ();
+ test_smax_fetch ();
+ test_umax_fetch ();
test_add ();
test_sub ();
@@ -551,6 +900,10 @@ main ()
test_nand ();
test_xor ();
test_or ();
+ test_smin ();
+ test_umin ();
+ test_smax ();
+ test_umax ();
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-3.c
b/gcc/testsuite/gcc.dg/atomic-op-3.c
index 9a54a2a4178..d18cb582116 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-3.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-3.c
@@ -5,6 +5,8 @@
/* Test the execution of the __atomic_*OP builtin routines for an int. */
+#include "limits.h"
+
extern void abort(void);
int v, count, res;
@@ -167,6 +169,114 @@ test_fetch_or ()
abort ();
}
+void
+test_fetch_smin ()
+{
+ int sv = 10;
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -10, __ATOMIC_ACQUIRE) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE) != -10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, INT_MIN, __ATOMIC_ACQ_REL) != -20)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, INT_MAX, __ATOMIC_SEQ_CST) != INT_MIN)
+ abort ();
+
+ if (sv != INT_MIN)
+ abort ();
+}
+
+void
+test_fetch_umin ()
+{
+ unsigned int uv = 100;
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_RELAXED) != 100)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 0, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, UINT_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_fetch_smax ()
+{
+ int sv = -10;
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_RELAXED) != -10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 50, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, INT_MAX, __ATOMIC_SEQ_CST) != 50)
+ abort ();
+
+ if (sv != INT_MAX)
+ abort ();
+}
+
+void
+test_fetch_umax ()
+{
+ unsigned int uv = 10;
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 200, __ATOMIC_ACQ_REL) != 100)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, UINT_MAX, __ATOMIC_SEQ_CST) != 200)
+ abort ();
+
+ if (uv != UINT_MAX)
+ abort ();
+}
+
/* The OP_fetch routines return the new value after the operation. */
void
@@ -328,6 +438,113 @@ test_or_fetch ()
abort ();
}
+void
+test_smin_fetch ()
+{
+ int sv = 10;
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE) != -10)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -20, __ATOMIC_RELEASE) != -20)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, INT_MIN, __ATOMIC_ACQ_REL) != INT_MIN)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, INT_MAX, __ATOMIC_SEQ_CST) != INT_MIN)
+ abort ();
+
+ if (sv != INT_MIN)
+ abort ();
+}
+
+void
+test_umin_fetch ()
+{
+ unsigned int uv = 100;
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, UINT_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax_fetch ()
+{
+ int sv = -10;
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, INT_MAX, __ATOMIC_SEQ_CST) != INT_MAX)
+ abort ();
+
+ if (sv != INT_MAX)
+ abort ();
+}
+
+void
+test_umax_fetch ()
+{
+ unsigned int uv = 10;
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 100, __ATOMIC_RELEASE) != 100)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL) != 200)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, UINT_MAX, __ATOMIC_SEQ_CST) != UINT_MAX)
+ abort ();
+
+ if (uv != UINT_MAX)
+ abort ();
+}
/* Test the OP routines with a result which isn't used. Use both variations
within each function. */
@@ -527,6 +744,130 @@ test_or ()
abort ();
}
+void
+test_smin ()
+{
+ int sv = 10;
+
+ __atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED);
+ if (sv != 5)
+ abort ();
+
+ __atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME);
+ if (sv != 5)
+ abort ();
+
+ __atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE);
+ if (sv != -10)
+ abort ();
+
+ __atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE);
+ if (sv != -20)
+ abort ();
+
+ __atomic_min_fetch (&sv, INT_MIN, __ATOMIC_ACQ_REL);
+ if (sv != INT_MIN)
+ abort ();
+
+ __atomic_fetch_min (&sv, INT_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != INT_MIN)
+ abort ();
+}
+
+void
+test_umin ()
+{
+ unsigned int uv = 100;
+
+ __atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE);
+ if (uv != 10)
+ abort ();
+
+ __atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL);
+ if (uv != 0)
+ abort ();
+
+ __atomic_fetch_min (&uv, UINT_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax ()
+{
+ int sv = -10;
+
+ __atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME);
+ if (sv != -5)
+ abort ();
+
+ __atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE);
+ if (sv != 10)
+ abort ();
+
+ __atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL);
+ if (sv != 50)
+ abort ();
+
+ __atomic_fetch_max (&sv, INT_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != INT_MAX)
+ abort ();
+}
+
+void
+test_umax ()
+{
+ unsigned int uv = 10;
+
+ __atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE);
+ if (uv != 100)
+ abort ();
+
+ __atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL);
+ if (uv != 200)
+ abort ();
+
+ __atomic_fetch_max (&uv, UINT_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != UINT_MAX)
+ abort ();
+}
+
int
main ()
{
@@ -536,6 +877,10 @@ main ()
test_fetch_nand ();
test_fetch_xor ();
test_fetch_or ();
+ test_fetch_smin ();
+ test_fetch_umin ();
+ test_fetch_smax ();
+ test_fetch_umax ();
test_add_fetch ();
test_sub_fetch ();
@@ -543,6 +888,10 @@ main ()
test_nand_fetch ();
test_xor_fetch ();
test_or_fetch ();
+ test_smin_fetch ();
+ test_umin_fetch ();
+ test_smax_fetch ();
+ test_umax_fetch ();
test_add ();
test_sub ();
@@ -550,6 +899,10 @@ main ()
test_nand ();
test_xor ();
test_or ();
+ test_smin ();
+ test_umin ();
+ test_smax ();
+ test_umax ();
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-4.c
b/gcc/testsuite/gcc.dg/atomic-op-4.c
index 6990b0e2d75..bd5e8582b6a 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-4.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-4.c
@@ -7,6 +7,8 @@
/* Test the execution of the __atomic_*OP builtin routines for long long. */
+#include "limits.h"
+
extern void abort(void);
long long v, count, res;
@@ -169,6 +171,114 @@ test_fetch_or ()
abort ();
}
+void
+test_fetch_smin ()
+{
+ long long sv = 10;
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -10, __ATOMIC_ACQUIRE) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE) != -10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, LLONG_MIN, __ATOMIC_ACQ_REL) != -20)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, LLONG_MAX, __ATOMIC_SEQ_CST) != LLONG_MIN)
+ abort ();
+
+ if (sv != LLONG_MIN)
+ abort ();
+}
+
+void
+test_fetch_umin ()
+{
+ unsigned long long uv = 100;
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_RELAXED) != 100)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 0, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_fetch_smax ()
+{
+ long long sv = -10;
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_RELAXED) != -10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 50, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, LLONG_MAX, __ATOMIC_SEQ_CST) != 50)
+ abort ();
+
+ if (sv != LLONG_MAX)
+ abort ();
+}
+
+void
+test_fetch_umax ()
+{
+ unsigned long long uv = 10;
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 200, __ATOMIC_ACQ_REL) != 100)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST) != 200)
+ abort ();
+
+ if (uv != ULLONG_MAX)
+ abort ();
+}
+
/* The OP_fetch routines return the new value after the operation. */
void
@@ -330,6 +440,113 @@ test_or_fetch ()
abort ();
}
+void
+test_smin_fetch ()
+{
+ long long sv = 10;
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE) != -10)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -20, __ATOMIC_RELEASE) != -20)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, LLONG_MIN, __ATOMIC_ACQ_REL) != LLONG_MIN)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, LLONG_MAX, __ATOMIC_SEQ_CST) != LLONG_MIN)
+ abort ();
+
+ if (sv != LLONG_MIN)
+ abort ();
+}
+
+void
+test_umin_fetch ()
+{
+ unsigned long long uv = 100;
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax_fetch ()
+{
+ long long sv = -10;
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, LLONG_MAX, __ATOMIC_SEQ_CST) != LLONG_MAX)
+ abort ();
+
+ if (sv != LLONG_MAX)
+ abort ();
+}
+
+void
+test_umax_fetch ()
+{
+ unsigned long long uv = 10;
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 100, __ATOMIC_RELEASE) != 100)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL) != 200)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST) != ULLONG_MAX)
+ abort ();
+
+ if (uv != ULLONG_MAX)
+ abort ();
+}
/* Test the OP routines with a result which isn't used. Use both variations
within each function. */
@@ -529,6 +746,130 @@ test_or ()
abort ();
}
+void
+test_smin ()
+{
+ long long sv = 10;
+
+ __atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED);
+ if (sv != 5)
+ abort ();
+
+ __atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME);
+ if (sv != 5)
+ abort ();
+
+ __atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE);
+ if (sv != -10)
+ abort ();
+
+ __atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE);
+ if (sv != -20)
+ abort ();
+
+ __atomic_min_fetch (&sv, LLONG_MIN, __ATOMIC_ACQ_REL);
+ if (sv != LLONG_MIN)
+ abort ();
+
+ __atomic_fetch_min (&sv, LLONG_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != LLONG_MIN)
+ abort ();
+}
+
+void
+test_umin ()
+{
+ unsigned long long uv = 100;
+
+ __atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE);
+ if (uv != 10)
+ abort ();
+
+ __atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL);
+ if (uv != 0)
+ abort ();
+
+ __atomic_fetch_min (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax ()
+{
+ long long sv = -10;
+
+ __atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME);
+ if (sv != -5)
+ abort ();
+
+ __atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE);
+ if (sv != 10)
+ abort ();
+
+ __atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL);
+ if (sv != 50)
+ abort ();
+
+ __atomic_fetch_max (&sv, LLONG_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != LLONG_MAX)
+ abort ();
+}
+
+void
+test_umax ()
+{
+ unsigned long long uv = 10;
+
+ __atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE);
+ if (uv != 100)
+ abort ();
+
+ __atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL);
+ if (uv != 200)
+ abort ();
+
+ __atomic_fetch_max (&uv, ULLONG_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != ULLONG_MAX)
+ abort ();
+}
+
int
main ()
{
@@ -538,6 +879,10 @@ main ()
test_fetch_nand ();
test_fetch_xor ();
test_fetch_or ();
+ test_fetch_smin ();
+ test_fetch_umin ();
+ test_fetch_smax ();
+ test_fetch_umax ();
test_add_fetch ();
test_sub_fetch ();
@@ -545,6 +890,10 @@ main ()
test_nand_fetch ();
test_xor_fetch ();
test_or_fetch ();
+ test_smin_fetch ();
+ test_umin_fetch ();
+ test_smax_fetch ();
+ test_umax_fetch ();
test_add ();
test_sub ();
@@ -552,6 +901,10 @@ main ()
test_nand ();
test_xor ();
test_or ();
+ test_smin ();
+ test_umin ();
+ test_smax ();
+ test_umax ();
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-5.c
b/gcc/testsuite/gcc.dg/atomic-op-5.c
index 4c6dcef8bf2..08d3bd34816 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-5.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-5.c
@@ -9,6 +9,10 @@
extern void abort(void);
+#define SINT128_MIN ((__int128_t)((__uint128_t)1 << (sizeof(__int128_t) * 8 -
1)))
+#define SINT128_MAX ((__int128_t)~SINT128_MIN)
+#define UINT128_MAX ((__uint128_t)~0)
+
__int128_t v, count, res;
const __int128_t init = ~0;
@@ -169,6 +173,114 @@ test_fetch_or ()
abort ();
}
+void
+test_fetch_smin ()
+{
+ __int128_t sv = 10;
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -10, __ATOMIC_ACQUIRE) != 5)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE) != -10)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SINT128_MIN, __ATOMIC_ACQ_REL) != -20)
+ abort ();
+
+ if (__atomic_fetch_min (&sv, SINT128_MAX, __ATOMIC_SEQ_CST) != SINT128_MIN)
+ abort ();
+
+ if (sv != SINT128_MIN)
+ abort ();
+}
+
+void
+test_fetch_umin ()
+{
+ __uint128_t uv = 100;
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_RELAXED) != 100)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, 0, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_min (&uv, UINT128_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_fetch_smax ()
+{
+ __int128_t sv = -10;
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_RELAXED) != -10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE) != -5)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, 50, __ATOMIC_ACQ_REL) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&sv, SINT128_MAX, __ATOMIC_SEQ_CST) != 50)
+ abort ();
+
+ if (sv != SINT128_MAX)
+ abort ();
+}
+
+void
+test_fetch_umax ()
+{
+ __uint128_t uv = 10;
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_RELAXED) != 10)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE) != 50)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, 200, __ATOMIC_ACQ_REL) != 100)
+ abort ();
+
+ if (__atomic_fetch_max (&uv, UINT128_MAX, __ATOMIC_SEQ_CST) != 200)
+ abort ();
+
+ if (uv != UINT128_MAX)
+ abort ();
+}
+
/* The OP_fetch routines return the new value after the operation. */
void
@@ -330,6 +442,113 @@ test_or_fetch ()
abort ();
}
+void
+test_smin_fetch ()
+{
+ __int128_t sv = 10;
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, 5, __ATOMIC_CONSUME) != 5)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE) != -10)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, -20, __ATOMIC_RELEASE) != -20)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SINT128_MIN, __ATOMIC_ACQ_REL) != SINT128_MIN)
+ abort ();
+
+ if (__atomic_min_fetch (&sv, SINT128_MAX, __ATOMIC_SEQ_CST) != SINT128_MIN)
+ abort ();
+
+ if (sv != SINT128_MIN)
+ abort ();
+}
+
+void
+test_umin_fetch ()
+{
+ __uint128_t uv = 100;
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_min_fetch (&uv, UINT128_MAX, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax_fetch ()
+{
+ __int128_t sv = -10;
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -5, __ATOMIC_CONSUME) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE) != -5)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 10, __ATOMIC_RELEASE) != 10)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&sv, SINT128_MAX, __ATOMIC_SEQ_CST) != SINT128_MAX)
+ abort ();
+
+ if (sv != SINT128_MAX)
+ abort ();
+}
+
+void
+test_umax_fetch ()
+{
+ __uint128_t uv = 10;
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 50, __ATOMIC_CONSUME) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE) != 50)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 100, __ATOMIC_RELEASE) != 100)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL) != 200)
+ abort ();
+
+ if (__atomic_max_fetch (&uv, UINT128_MAX, __ATOMIC_SEQ_CST) != UINT128_MAX)
+ abort ();
+
+ if (uv != UINT128_MAX)
+ abort ();
+}
/* Test the OP routines with a result which isn't used. Use both variations
within each function. */
@@ -529,6 +748,130 @@ test_or ()
abort ();
}
+void
+test_smin ()
+{
+ __int128_t sv = 10;
+
+ __atomic_min_fetch (&sv, 5, __ATOMIC_RELAXED);
+ if (sv != 5)
+ abort ();
+
+ __atomic_fetch_min (&sv, 5, __ATOMIC_CONSUME);
+ if (sv != 5)
+ abort ();
+
+ __atomic_min_fetch (&sv, -10, __ATOMIC_ACQUIRE);
+ if (sv != -10)
+ abort ();
+
+ __atomic_fetch_min (&sv, -20, __ATOMIC_RELEASE);
+ if (sv != -20)
+ abort ();
+
+ __atomic_min_fetch (&sv, SINT128_MIN, __ATOMIC_ACQ_REL);
+ if (sv != SINT128_MIN)
+ abort ();
+
+ __atomic_fetch_min (&sv, SINT128_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SINT128_MIN)
+ abort ();
+}
+
+void
+test_umin ()
+{
+ __uint128_t uv = 100;
+
+ __atomic_min_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_min_fetch (&uv, 75, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_min (&uv, 10, __ATOMIC_RELEASE);
+ if (uv != 10)
+ abort ();
+
+ __atomic_min_fetch (&uv, 0, __ATOMIC_ACQ_REL);
+ if (uv != 0)
+ abort ();
+
+ __atomic_fetch_min (&uv, UINT128_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != 0)
+ abort ();
+}
+
+void
+test_smax ()
+{
+ __int128_t sv = -10;
+
+ __atomic_max_fetch (&sv, -5, __ATOMIC_RELAXED);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, -5, __ATOMIC_CONSUME);
+ if (sv != -5)
+ abort ();
+
+ __atomic_max_fetch (&sv, -20, __ATOMIC_ACQUIRE);
+ if (sv != -5)
+ abort ();
+
+ __atomic_fetch_max (&sv, 10, __ATOMIC_RELEASE);
+ if (sv != 10)
+ abort ();
+
+ __atomic_max_fetch (&sv, 50, __ATOMIC_ACQ_REL);
+ if (sv != 50)
+ abort ();
+
+ __atomic_fetch_max (&sv, SINT128_MAX, __ATOMIC_SEQ_CST);
+
+ if (sv != SINT128_MAX)
+ abort ();
+}
+
+void
+test_umax ()
+{
+ __uint128_t uv = 10;
+
+ __atomic_max_fetch (&uv, 50, __ATOMIC_RELAXED);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 50, __ATOMIC_CONSUME);
+ if (uv != 50)
+ abort ();
+
+ __atomic_max_fetch (&uv, 30, __ATOMIC_ACQUIRE);
+ if (uv != 50)
+ abort ();
+
+ __atomic_fetch_max (&uv, 100, __ATOMIC_RELEASE);
+ if (uv != 100)
+ abort ();
+
+ __atomic_max_fetch (&uv, 200, __ATOMIC_ACQ_REL);
+ if (uv != 200)
+ abort ();
+
+ __atomic_fetch_max (&uv, UINT128_MAX, __ATOMIC_SEQ_CST);
+
+ if (uv != UINT128_MAX)
+ abort ();
+}
+
int
main ()
{
@@ -538,6 +881,10 @@ main ()
test_fetch_nand ();
test_fetch_xor ();
test_fetch_or ();
+ test_fetch_smin ();
+ test_fetch_umin ();
+ test_fetch_smax ();
+ test_fetch_umax ();
test_add_fetch ();
test_sub_fetch ();
@@ -545,6 +892,10 @@ main ()
test_nand_fetch ();
test_xor_fetch ();
test_or_fetch ();
+ test_smin_fetch ();
+ test_umin_fetch ();
+ test_smax_fetch ();
+ test_umax_fetch ();
test_add ();
test_sub ();
@@ -552,6 +903,10 @@ main ()
test_nand ();
test_xor ();
test_or ();
+ test_smin ();
+ test_umin ();
+ test_smax ();
+ test_umax ();
return 0;
}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 410341d4711..fff96ac267c 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -422,6 +422,7 @@ extern gimple_opt_pass *make_pass_pre (gcc::context *ctxt);
extern unsigned int tail_merge_optimize (bool);
extern gimple_opt_pass *make_pass_profile (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_strip_predict_hints (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_lower_ifn_atomic_minmax (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_rebuild_frequencies (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_complex_O0 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_complex (gcc::context *ctxt);
--
2.44.0