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

Reply via email to