From: Soumya AR <[email protected]>

This patch implements __atomic_fetch_{min,max} and __atomic_{min,max}_fetch
builtins in libatomic for both signed and unsigned integer types.

---

We introduce a new signed type (STYPE) for casting signed operands in fop_n.c.
Since all current libatomic operates on unsigned types (UTYPE), we need to
reinterpret the bits as 2's complement signed values when performing signed
min/max operations. For this, UTYPE is replaced with BUILTIN_TYPE, which
resolves to STYPE or UTYPE based on the type of the operation.

libatomic_i.h does define ITYPE, but never uses it, so I've dropped it in this
patch.

---

Some targets  have custom implementations of atomic_compare_exchange_n, where
the parameters are defined with UTYPE*. Therefore, when calling
atomic_compare_exchange_n for signed min/max operations, we need to cast
BUILTIN_TYPE* to UTYPE*.

Per C11 6.5p7, this should be OK?

---

The variation in signed and unsigned min/max is made by defining the following
operations: smin, smax, umax, and umin.

Similarly, we modify the configure scripts to check for __atomic_fetch_smax,
__atomic_fetch_smin, __atomic_fetch_umax, and __atomic_fetch_umin as this is
what libatomic uses.

This is why generic __atomic_fetch_{s/u}min/max builtins are needed to be
defined in GCC, as mentioned in Patch 1.

---

This naming convention (__atomic_fetch_{s,u}min/max_<size>) was also coordinated
with the LLVM community to ensure ABI compatibility across compilers.

https://discourse.llvm.org/t/abi-for-atomic-fetch-min-max-in-libatomic/87594

---

These operations are guarded under LIBAT_HAVE_ATOMIC_FETCH_MINMAX rather than
reusing the existing HAVE_ATOMIC_FETCH_OP_* macros so backends that do not
implement these operations don't reject all other libatomic implementations as
a result of the macro failing.

---

There is a fallback in libatomic that forces word-sized CAS for smaller sizes.
This is done by forcing OP for the entire word, and then extracting the required
bytes for the results. This does not work for min/max operations as surrounding
bytes can impact the result of the operation.

Therefore, we add a special case for min/max that extracts the required bytes
and then does the CAS.

---

Some surgery is also needed in libatomic_i.h to ensure that the signed min/max
fucntions are defined with the correct sign. This is done by extending the
DECLARE_ALL_SIZED macro to take an additional argument for STYPE.

---

Bootstrapped and regression tested on aarch64-linux-gnu and x86_64-linux-gnu.
Cross-compiled and regression tested for arm-linux-gnueabihf-armv7-a and
aarch64-linux-gnu without LSE.

Signed-off-by: Soumya AR <[email protected]>

libatomic/ChangeLog:

        * Makefile.am: Add min/max object files.
        * Makefile.in: Regenerate.
        * acinclude.m4: Add min/max configuration checks.
        * auto-config.h.in: Regenerate.
        * config/linux/aarch64/atomic_16.S: Add min/max support.
        * configure: Regenerate.
        * configure.ac: Add LIBAT_HAVE_ATOMIC_FETCH_MINMAX check.
        * fop_n.c (BUILTIN_TYPE): New macro to enable STYPE/UTYPE.
        Set UTYPE as BUILTIN_TYPE, which resolves to STYPE or UTYPE.
        Modified the calculation for word-sized CAS loop for types smaller than
        a word for min/max operations.
        Cast calls to atomic_compare_exchange_n to UTYPE*.
        * libatomic.map: Export new min/max symbols
        * libatomic_i.h (STYPE): New type.
        (ITYPE): Dropped.
        (DECLARE_ALL_SIZED): Modify to generate sized functions.
        (DECLARE_ALL_SIZED_): Likewise.
        * testsuite/libatomic.c/atomic-op-1.c: Add min/max tests.
        * testsuite/libatomic.c/atomic-op-2.c: Likewise.
        * testsuite/libatomic.c/atomic-op-3.c: Likewise.
        * testsuite/libatomic.c/atomic-op-4.c: Likewise.
        * testsuite/libatomic.c/atomic-op-5.c: Likewise.
        * fsmax_n.c: New file.
        * fsmin_n.c: New file.
        * fumax_n.c: New file.
        * fumin_n.c: New file.
---
 libatomic/Makefile.am                         |   3 +-
 libatomic/Makefile.in                         |   4 +-
 libatomic/acinclude.m4                        |  19 +
 libatomic/auto-config.h.in                    |  33 +-
 libatomic/config/linux/aarch64/atomic_16.S    | 126 +++++++
 libatomic/configure                           | 346 +++++++++++++++++
 libatomic/configure.ac                        |   1 +
 libatomic/fop_n.c                             | 117 +++++-
 libatomic/fsmax_n.c                           |  50 +++
 libatomic/fsmin_n.c                           |  50 +++
 libatomic/fumax_n.c                           |  49 +++
 libatomic/fumin_n.c                           |  49 +++
 libatomic/libatomic.map                       |  44 +++
 libatomic/libatomic_i.h                       |  26 +-
 libatomic/testsuite/libatomic.c/atomic-op-1.c | 353 +++++++++++++++++
 libatomic/testsuite/libatomic.c/atomic-op-2.c | 353 +++++++++++++++++
 libatomic/testsuite/libatomic.c/atomic-op-3.c | 353 +++++++++++++++++
 libatomic/testsuite/libatomic.c/atomic-op-4.c | 353 +++++++++++++++++
 libatomic/testsuite/libatomic.c/atomic-op-5.c | 355 ++++++++++++++++++
 19 files changed, 2656 insertions(+), 28 deletions(-)
 create mode 100644 libatomic/fsmax_n.c
 create mode 100644 libatomic/fsmin_n.c
 create mode 100644 libatomic/fumax_n.c
 create mode 100644 libatomic/fumin_n.c

diff --git a/libatomic/Makefile.am b/libatomic/Makefile.am
index 65dff6ece9f..a2509bf5978 100644
--- a/libatomic/Makefile.am
+++ b/libatomic/Makefile.am
@@ -79,7 +79,8 @@ else
 libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \
        fenv.c fence.c flag.c
 
-SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
+SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas fumax fumin \
+fsmax fsmin
 
 EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS))
 libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep)
diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in
index 4344ac4a2e8..ae634af3e2a 100644
--- a/libatomic/Makefile.in
+++ b/libatomic/Makefile.in
@@ -436,7 +436,9 @@ libatomic_la_LDFLAGS = $(libatomic_version_info) 
$(libatomic_version_script) \
 @PARTIAL_VXWORKS_FALSE@        fence.c flag.c $(am__append_5)
 @PARTIAL_VXWORKS_TRUE@libatomic_la_SOURCES = fenv.c fence.c flag.c \
 @PARTIAL_VXWORKS_TRUE@ $(am__append_5)
-@PARTIAL_VXWORKS_FALSE@SIZEOBJS = load store cas exch fadd fsub fand fior fxor 
fnand tas
+@PARTIAL_VXWORKS_FALSE@SIZEOBJS = load store cas exch fadd fsub fand fior fxor 
fnand tas fumax fumin \
+@PARTIAL_VXWORKS_FALSE@fsmax fsmin
+
 @PARTIAL_VXWORKS_FALSE@EXTRA_libatomic_la_SOURCES = $(addsuffix 
_n.c,$(SIZEOBJS))
 @PARTIAL_VXWORKS_FALSE@libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) 
$(libatomic_version_dep)
 @PARTIAL_VXWORKS_FALSE@empty = 
diff --git a/libatomic/acinclude.m4 b/libatomic/acinclude.m4
index f35ab5b60a5..4607be2adc7 100644
--- a/libatomic/acinclude.m4
+++ b/libatomic/acinclude.m4
@@ -173,6 +173,25 @@ AC_DEFUN([LIBAT_HAVE_ATOMIC_FETCH_OP],[
   AH_BOTTOM([#define MAYBE_HAVE_ATOMIC_FETCH_OP_$2 HAVE_ATOMIC_FETCH_OP_$2])
 ])
 
+dnl
+dnl Test if we have __atomic_fetch_smin/smax/umin/umax for mode $1, size $2
+dnl We check the signed/unsigned specific versions because that's what 
libatomic
+dnl uses for min/max.
+dnl
+AC_DEFUN([LIBAT_HAVE_ATOMIC_FETCH_MINMAX],[
+  LIBAT_TEST_ATOMIC_BUILTIN([for __atomic_fetch_smin/smax/umin/umax for size 
$2],
+    [libat_cv_have_at_fminmax_$2],
+    [typedef int T __attribute__((mode($1))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);])
+  LIBAT_DEFINE_YESNO([HAVE_ATOMIC_FETCH_MINMAX_$2], 
[$libat_cv_have_at_fminmax_$2],
+       [Have __atomic_fetch_smin/smax/umin/umax for $2 byte integers.])
+  AH_BOTTOM([#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_$2 
HAVE_ATOMIC_FETCH_MINMAX_$2])
+])
+
 dnl
 dnl Test for the size of the target word.
 dnl
diff --git a/libatomic/auto-config.h.in b/libatomic/auto-config.h.in
index ab3424a759e..6798d41fda8 100644
--- a/libatomic/auto-config.h.in
+++ b/libatomic/auto-config.h.in
@@ -48,6 +48,21 @@
 /* Have __atomic_fetch_add for 8 byte integers. */
 #undef HAVE_ATOMIC_FETCH_ADD_8
 
+/* Have __atomic_fetch_smin/smax/umin/umax for 1 byte integers. */
+#undef HAVE_ATOMIC_FETCH_MINMAX_1
+
+/* Have __atomic_fetch_smin/smax/umin/umax for 16 byte integers. */
+#undef HAVE_ATOMIC_FETCH_MINMAX_16
+
+/* Have __atomic_fetch_smin/smax/umin/umax for 2 byte integers. */
+#undef HAVE_ATOMIC_FETCH_MINMAX_2
+
+/* Have __atomic_fetch_smin/smax/umin/umax for 4 byte integers. */
+#undef HAVE_ATOMIC_FETCH_MINMAX_4
+
+/* Have __atomic_fetch_smin/smax/umin/umax for 8 byte integers. */
+#undef HAVE_ATOMIC_FETCH_MINMAX_8
+
 /* Have __atomic_fetch_op for all op for 1 byte integers. */
 #undef HAVE_ATOMIC_FETCH_OP_1
 
@@ -259,6 +274,18 @@
 
 #define MAYBE_HAVE_ATOMIC_CAS_16 HAVE_ATOMIC_CAS_16
 
+#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_1 HAVE_ATOMIC_FETCH_MINMAX_1
+
+#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_2 HAVE_ATOMIC_FETCH_MINMAX_2
+
+#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_4 HAVE_ATOMIC_FETCH_MINMAX_4
+
+#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_8 HAVE_ATOMIC_FETCH_MINMAX_8
+
+#define MAYBE_HAVE_ATOMIC_LDST_2 HAVE_ATOMIC_LDST_2
+
+#define MAYBE_HAVE_ATOMIC_FETCH_MINMAX_16 HAVE_ATOMIC_FETCH_MINMAX_16
+
 #define MAYBE_HAVE_ATOMIC_FETCH_ADD_1 HAVE_ATOMIC_FETCH_ADD_1
 
 #define MAYBE_HAVE_ATOMIC_FETCH_ADD_2 HAVE_ATOMIC_FETCH_ADD_2
@@ -267,8 +294,6 @@
 
 #define MAYBE_HAVE_ATOMIC_FETCH_ADD_8 HAVE_ATOMIC_FETCH_ADD_8
 
-#define MAYBE_HAVE_ATOMIC_LDST_2 HAVE_ATOMIC_LDST_2
-
 #define MAYBE_HAVE_ATOMIC_FETCH_ADD_16 HAVE_ATOMIC_FETCH_ADD_16
 
 #define MAYBE_HAVE_ATOMIC_FETCH_OP_1 HAVE_ATOMIC_FETCH_OP_1
@@ -279,14 +304,14 @@
 
 #define MAYBE_HAVE_ATOMIC_FETCH_OP_8 HAVE_ATOMIC_FETCH_OP_8
 
+#define FAST_ATOMIC_LDST_2 HAVE_ATOMIC_LDST_2
+
 #define MAYBE_HAVE_ATOMIC_FETCH_OP_16 HAVE_ATOMIC_FETCH_OP_16
 
 #ifndef WORDS_BIGENDIAN
 #define WORDS_BIGENDIAN 0
 #endif
 
-#define FAST_ATOMIC_LDST_2 HAVE_ATOMIC_LDST_2
-
 #define MAYBE_HAVE_ATOMIC_LDST_4 HAVE_ATOMIC_LDST_4
 
 #define FAST_ATOMIC_LDST_4 HAVE_ATOMIC_LDST_4
diff --git a/libatomic/config/linux/aarch64/atomic_16.S 
b/libatomic/config/linux/aarch64/atomic_16.S
index eda4866bdaf..1cc059c38ce 100644
--- a/libatomic/config/linux/aarch64/atomic_16.S
+++ b/libatomic/config/linux/aarch64/atomic_16.S
@@ -102,6 +102,8 @@ NAME:                               \
 # define inhi  x2
 # define tmplo x7
 # define tmphi x6
+# define explo x9
+# define exphi x8
 #else
 # define reslo x0
 # define reshi x1
@@ -109,6 +111,8 @@ NAME:                               \
 # define inhi  x3
 # define tmplo x6
 # define tmphi x7
+# define explo x8
+# define exphi x9
 #endif
 
 #define RELAXED 0
@@ -500,6 +504,60 @@ ENTRY_ALIASED (nand_fetch_16)
        ret
 END (nand_fetch_16)
 
+#define MINMAX_FUNC_BASE(NAME, CMP, BRANCH, RETVAL) \
+ENTRY_ALIASED(NAME) \
+       mov     x5, x0; \
+       cbnz    w4, 2f; \
+\
+       /* RELAXED.  */; \
+1:     ldxp    res0, res1, [x5]; \
+       CMP     (reshi, inhi); \
+       BRANCH  5f; \
+       beq     4f; \
+3:     stxp    w4, res0, res1, [x5]; \
+       cbnz    w4, 1b; \
+       ret; \
+4:     CMP     (reslo, inlo); \
+       bls     3b; \
+5:     stxp    w4, in0, in1, [x5]; \
+       cbnz    w4, 1b; \
+    RETVAL     (in0, in1); \
+       ret; \
+\
+       /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST.  */; \
+2:     ldaxp   res0, res1, [x5]; \
+       CMP     (reshi, inhi); \
+       BRANCH  5f; \
+       beq     4f; \
+3:     stlxp   w4, res0, res1, [x5]; \
+       cbnz    w4, 2b; \
+       ret; \
+4:     CMP     (reslo, inlo); \
+       bls     3b; \
+5:     stlxp   w4, in0, in1, [x5]; \
+       cbnz    w4, 2b; \
+    RETVAL     (in0, in1); \
+       ret; \
+END (NAME)
+
+#define MIN_CMP(x, y) cmp x, y
+#define MAX_CMP(x, y) cmp y, x
+#define SIGNED_BRANCH bgt
+#define UNSIGNED_BRANCH bhi
+#define FETCH_OP_RET(x, y)
+#define OP_FETCH_RET(x, y) \
+    mov res0, x; \
+    mov res1, y
+
+MINMAX_FUNC_BASE (fetch_smin_16, MIN_CMP, SIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_BASE (smin_fetch_16, MIN_CMP, SIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_BASE (fetch_umin_16, MIN_CMP, UNSIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_BASE (umin_fetch_16, MIN_CMP, UNSIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_BASE (fetch_smax_16, MAX_CMP, SIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_BASE (smax_fetch_16, MAX_CMP, SIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_BASE (fetch_umax_16, MAX_CMP, UNSIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_BASE (umax_fetch_16, MAX_CMP, UNSIGNED_BRANCH, OP_FETCH_RET)
+
 
 /* __atomic_test_and_set is always inlined, so this entry is unused and
    only required for completeness.  */
@@ -769,6 +827,74 @@ ENTRY_FEAT (compare_exchange_16, LSE)
 4:     caspal  exp0, exp1, in0, in1, [x0]
        b       0b
 END_FEAT (compare_exchange_16, LSE)
+
+
+/* Always perform the second CAS in order to have the same memory ordering
+ * semantics.
+ * Even when not making any memory write, we perform the final CAS operation.
+ *  -- We have to do this due to the C/C++ semantics that we're attempting to
+ *     provide.  The C/C++ requirement is to provide a function that always
+ *     gives the same memory ordering semantics (i.e. in an analogy to
+ *     __atomic_compare_exchange_n, we would not use a different
+ *     SUCCESS_MEMORDER and FAILURE_MEMORDER depending on whether we need to
+ *     update the value in memory or not).  If this is the case then we must
+ *     use the special memory-ordering semantics in the last CAS instruction
+ *     whether or not we're updating the value.  */
+#define MINMAX_FUNC_LSE(NAME, CMP, BRANCH, RETVAL) \
+ENTRY_FEAT(NAME, LSE) \
+       mov     x5, x0; \
+       casp exp0, exp1, exp0, exp1, [x5]; \
+0:     mov     tmp0, exp0; \
+       mov     tmp1, exp1; \
+       CMP     (exphi, inhi); \
+       BRANCH  3f; \
+       beq     2f; \
+1:     mov     res0, exp0; \
+       mov     res1, exp1; \
+       b       4f; \
+2:     CMP     (explo, inlo); \
+       bls     1b; \
+3:     mov     res0, in0; \
+       mov     res1, in1; \
+\
+4:     cbz     w4, 5f; \
+       cmp     w4, RELEASE; \
+       b.hs    6f; \
+       /* ACQUIRE/CONSUME.  */; \
+       caspa   exp0, exp1, res0, res1, [x5]; \
+       b       8f; \
+       /* RELAXED.  */; \
+5:     casp    exp0, exp1, res0, res1, [x5]; \
+       b       8f; \
+       /* RELEASE.  */; \
+6:     b.hi    7f; \
+       caspl   exp0, exp1, res0, res1, [x5]; \
+       b       8f; \
+       /* ACQ_REL/SEQ_CST.  */; \
+7:     caspal  exp0, exp1, res0, res1, [x5]; \
+8:     cmp exp0, tmp0; \
+       ccmp exp1, tmp1, 0, eq; \
+       bne 0b; \
+       RETVAL (exp0, exp1); \
+       ret; \
+END_FEAT (NAME, LSE)
+
+#undef FETCH_OP_RET
+#undef OP_FETCH_RET
+#define OP_FETCH_RET(x, y)
+#define FETCH_OP_RET(x, y) \
+    mov res0, x; \
+    mov res1, y
+
+MINMAX_FUNC_LSE (fetch_smin_16, MIN_CMP, SIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_LSE (smin_fetch_16, MIN_CMP, SIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_LSE (fetch_umin_16, MIN_CMP, UNSIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_LSE (umin_fetch_16, MIN_CMP, UNSIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_LSE (fetch_smax_16, MAX_CMP, SIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_LSE (smax_fetch_16, MAX_CMP, SIGNED_BRANCH, OP_FETCH_RET)
+MINMAX_FUNC_LSE (fetch_umax_16, MAX_CMP, UNSIGNED_BRANCH, FETCH_OP_RET)
+MINMAX_FUNC_LSE (umax_fetch_16, MAX_CMP, UNSIGNED_BRANCH, OP_FETCH_RET)
+
 #endif
 
 /* GNU_PROPERTY_AARCH64_* macros from elf.h for use in asm code.  */
diff --git a/libatomic/configure b/libatomic/configure
index 67b3a6388d7..2af39bfc3a6 100755
--- a/libatomic/configure
+++ b/libatomic/configure
@@ -14018,6 +14018,352 @@ _ACEOF
 
 
 
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 
__atomic_fetch_smin/smax/umin/umax for size 1" >&5
+$as_echo_n "checking for __atomic_fetch_smin/smax/umin/umax for size 1... " 
>&6; }
+if ${libat_cv_have_at_fminmax_1+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+typedef int T __attribute__((mode(QI))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);
+  ;
+  return 0;
+}
+_ACEOF
+    if test x$atomic_builtins_link_tests = xyes; then
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        eval libat_cv_have_at_fminmax_1=yes
+      else
+        eval libat_cv_have_at_fminmax_1=no
+      fi
+    else
+      old_CFLAGS="$CFLAGS"
+      # Compile unoptimized.
+      CFLAGS="$CFLAGS -O0 -S"
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } 
>&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        if grep __atomic_ conftest.s >/dev/null 2>&1 ; then
+         eval libat_cv_have_at_fminmax_1=no
+        else
+         eval libat_cv_have_at_fminmax_1=yes
+        fi
+      else
+        eval libat_cv_have_at_fminmax_1=no
+      fi
+      CFLAGS="$old_CFLAGS"
+    fi
+    rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libat_cv_have_at_fminmax_1" 
>&5
+$as_echo "$libat_cv_have_at_fminmax_1" >&6; }
+
+
+  yesno=`echo $libat_cv_have_at_fminmax_1 | tr 'yesno' '1  0 '`
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATOMIC_FETCH_MINMAX_1 $yesno
+_ACEOF
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 
__atomic_fetch_smin/smax/umin/umax for size 2" >&5
+$as_echo_n "checking for __atomic_fetch_smin/smax/umin/umax for size 2... " 
>&6; }
+if ${libat_cv_have_at_fminmax_2+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+typedef int T __attribute__((mode(HI))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);
+  ;
+  return 0;
+}
+_ACEOF
+    if test x$atomic_builtins_link_tests = xyes; then
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        eval libat_cv_have_at_fminmax_2=yes
+      else
+        eval libat_cv_have_at_fminmax_2=no
+      fi
+    else
+      old_CFLAGS="$CFLAGS"
+      # Compile unoptimized.
+      CFLAGS="$CFLAGS -O0 -S"
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } 
>&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        if grep __atomic_ conftest.s >/dev/null 2>&1 ; then
+         eval libat_cv_have_at_fminmax_2=no
+        else
+         eval libat_cv_have_at_fminmax_2=yes
+        fi
+      else
+        eval libat_cv_have_at_fminmax_2=no
+      fi
+      CFLAGS="$old_CFLAGS"
+    fi
+    rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libat_cv_have_at_fminmax_2" 
>&5
+$as_echo "$libat_cv_have_at_fminmax_2" >&6; }
+
+
+  yesno=`echo $libat_cv_have_at_fminmax_2 | tr 'yesno' '1  0 '`
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATOMIC_FETCH_MINMAX_2 $yesno
+_ACEOF
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 
__atomic_fetch_smin/smax/umin/umax for size 4" >&5
+$as_echo_n "checking for __atomic_fetch_smin/smax/umin/umax for size 4... " 
>&6; }
+if ${libat_cv_have_at_fminmax_4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+typedef int T __attribute__((mode(SI))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);
+  ;
+  return 0;
+}
+_ACEOF
+    if test x$atomic_builtins_link_tests = xyes; then
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        eval libat_cv_have_at_fminmax_4=yes
+      else
+        eval libat_cv_have_at_fminmax_4=no
+      fi
+    else
+      old_CFLAGS="$CFLAGS"
+      # Compile unoptimized.
+      CFLAGS="$CFLAGS -O0 -S"
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } 
>&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        if grep __atomic_ conftest.s >/dev/null 2>&1 ; then
+         eval libat_cv_have_at_fminmax_4=no
+        else
+         eval libat_cv_have_at_fminmax_4=yes
+        fi
+      else
+        eval libat_cv_have_at_fminmax_4=no
+      fi
+      CFLAGS="$old_CFLAGS"
+    fi
+    rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libat_cv_have_at_fminmax_4" 
>&5
+$as_echo "$libat_cv_have_at_fminmax_4" >&6; }
+
+
+  yesno=`echo $libat_cv_have_at_fminmax_4 | tr 'yesno' '1  0 '`
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATOMIC_FETCH_MINMAX_4 $yesno
+_ACEOF
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 
__atomic_fetch_smin/smax/umin/umax for size 8" >&5
+$as_echo_n "checking for __atomic_fetch_smin/smax/umin/umax for size 8... " 
>&6; }
+if ${libat_cv_have_at_fminmax_8+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+typedef int T __attribute__((mode(DI))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);
+  ;
+  return 0;
+}
+_ACEOF
+    if test x$atomic_builtins_link_tests = xyes; then
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        eval libat_cv_have_at_fminmax_8=yes
+      else
+        eval libat_cv_have_at_fminmax_8=no
+      fi
+    else
+      old_CFLAGS="$CFLAGS"
+      # Compile unoptimized.
+      CFLAGS="$CFLAGS -O0 -S"
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } 
>&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        if grep __atomic_ conftest.s >/dev/null 2>&1 ; then
+         eval libat_cv_have_at_fminmax_8=no
+        else
+         eval libat_cv_have_at_fminmax_8=yes
+        fi
+      else
+        eval libat_cv_have_at_fminmax_8=no
+      fi
+      CFLAGS="$old_CFLAGS"
+    fi
+    rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libat_cv_have_at_fminmax_8" 
>&5
+$as_echo "$libat_cv_have_at_fminmax_8" >&6; }
+
+
+  yesno=`echo $libat_cv_have_at_fminmax_8 | tr 'yesno' '1  0 '`
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATOMIC_FETCH_MINMAX_8 $yesno
+_ACEOF
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 
__atomic_fetch_smin/smax/umin/umax for size 16" >&5
+$as_echo_n "checking for __atomic_fetch_smin/smax/umin/umax for size 16... " 
>&6; }
+if ${libat_cv_have_at_fminmax_16+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+typedef int T __attribute__((mode(TI))); T *x, y;
+     asm("" : "=g"(x), "=g"(y));
+     __atomic_fetch_smax (x, y, 0); __atomic_smax_fetch (x, y, 0);
+     __atomic_fetch_umax (x, y, 0); __atomic_umax_fetch (x, y, 0);
+     __atomic_fetch_smin (x, y, 0); __atomic_smin_fetch (x, y, 0);
+     __atomic_fetch_umin (x, y, 0); __atomic_umin_fetch (x, y, 0);
+  ;
+  return 0;
+}
+_ACEOF
+    if test x$atomic_builtins_link_tests = xyes; then
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        eval libat_cv_have_at_fminmax_16=yes
+      else
+        eval libat_cv_have_at_fminmax_16=no
+      fi
+    else
+      old_CFLAGS="$CFLAGS"
+      # Compile unoptimized.
+      CFLAGS="$CFLAGS -O0 -S"
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } 
>&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+        if grep __atomic_ conftest.s >/dev/null 2>&1 ; then
+         eval libat_cv_have_at_fminmax_16=no
+        else
+         eval libat_cv_have_at_fminmax_16=yes
+        fi
+      else
+        eval libat_cv_have_at_fminmax_16=no
+      fi
+      CFLAGS="$old_CFLAGS"
+    fi
+    rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libat_cv_have_at_fminmax_16" 
>&5
+$as_echo "$libat_cv_have_at_fminmax_16" >&6; }
+
+
+  yesno=`echo $libat_cv_have_at_fminmax_16 | tr 'yesno' '1  0 '`
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ATOMIC_FETCH_MINMAX_16 $yesno
+_ACEOF
+
+
+
+
+
+
+
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_fetch_add for 
size 1" >&5
 $as_echo_n "checking for __atomic_fetch_add for size 1... " >&6; }
 if ${libat_cv_have_at_fadd_1+:} false; then :
diff --git a/libatomic/configure.ac b/libatomic/configure.ac
index 01141f64376..e2825804143 100644
--- a/libatomic/configure.ac
+++ b/libatomic/configure.ac
@@ -206,6 +206,7 @@ LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_LOADSTORE])
 LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_TAS])
 LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_EXCHANGE])
 LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_CAS])
+LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_FETCH_MINMAX])
 LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_FETCH_ADD])
 LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_FETCH_OP])
 
diff --git a/libatomic/fop_n.c b/libatomic/fop_n.c
index 954194a7371..f1db0731433 100644
--- a/libatomic/fop_n.c
+++ b/libatomic/fop_n.c
@@ -31,11 +31,16 @@
      OP                a two-operand functional macro the implements the 
operation.
 */
 
+/* If BUILTIN_TYPE is defined, use that.  Otherwise, default to UTYPE.  */
+#ifndef BUILTIN_TYPE
+#define BUILTIN_TYPE UTYPE
+#endif
 
 /* If we support the builtin, just use it.  */
 #if !DONE && SIZE(HAVE_ATOMIC_FETCH_OP)
-UTYPE
-SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
+
+BUILTIN_TYPE
+SIZE(C2(libat_fetch_,NAME)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel)
 {
   if (maybe_specialcase_relaxed(smodel))
     return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_RELAXED);
@@ -45,8 +50,8 @@ SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int 
smodel)
     return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_SEQ_CST);
 }
 
-UTYPE
-SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
+BUILTIN_TYPE
+SIZE(C3(libat_,NAME,_fetch)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel)
 {
   if (maybe_specialcase_relaxed(smodel))
     return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_RELAXED);
@@ -61,10 +66,10 @@ SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int 
smodel)
 
 
 #if !DONE && defined(atomic_compare_exchange_n)
-UTYPE
-SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
+BUILTIN_TYPE
+SIZE(C2(libat_fetch_,NAME)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel)
 {
-  UTYPE oldval, t;
+  BUILTIN_TYPE oldval, t;
 
   pre_barrier (smodel);
 
@@ -73,17 +78,17 @@ SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int 
smodel)
     {
       t = OP(oldval, opval);
     }
-  while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
+  while (!atomic_compare_exchange_n ((UTYPE *)mptr, (UTYPE *)&oldval, t, true,
                                     __ATOMIC_RELAXED, __ATOMIC_RELAXED));
 
   post_barrier (smodel);
   return oldval;
 }
 
-UTYPE
-SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
+BUILTIN_TYPE
+SIZE(C3(libat_,NAME,_fetch)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel)
 {
-  UTYPE oldval, t;
+  BUILTIN_TYPE oldval, t;
 
   pre_barrier (smodel);
 
@@ -92,7 +97,7 @@ SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int 
smodel)
     {
       t = OP(oldval, opval);
     }
-  while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
+  while (!atomic_compare_exchange_n ((UTYPE *)mptr, (UTYPE *)&oldval, t, true,
                                     __ATOMIC_RELAXED, __ATOMIC_RELAXED));
 
   post_barrier (smodel);
@@ -106,6 +111,75 @@ SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, 
int smodel)
 /* If this type is no larger than word-sized, fall back to a word-sized
    compare-and-swap loop.  */
 #if !DONE && N < WORDSIZE && defined(atomic_compare_exchange_w)
+
+/* Determine if this is a MIN/MAX operation that requires extraction.
+   MIN/MAX operations need to extract the actual values for comparison.
+   All other operations can operate on the whole word at once.  */
+#if defined(LAT_MINMAX_OP_N)
+
+BUILTIN_TYPE
+SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
+{
+  UWORD mask, shift, woldval, t, *wptr;
+  BUILTIN_TYPE oldval;
+
+  pre_barrier (smodel);
+
+  wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
+  shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
+  mask = SIZE(MASK) << shift;
+
+  woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
+  do
+    {
+      /* Extract the old value for comparison.  */
+      oldval = (BUILTIN_TYPE)((woldval >> shift) & SIZE(MASK));
+      /* Apply the operation on the extracted values.  */
+      BUILTIN_TYPE newval = OP(oldval, (BUILTIN_TYPE)opval);
+      /* Repack with the updated value.  */
+      t = (woldval & ~mask) | (((UWORD)(UTYPE)newval) << shift);
+    }
+  while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
+                                     __ATOMIC_RELAXED, __ATOMIC_RELAXED));
+
+  post_barrier (smodel);
+  /* Return the old value before the operation.  */
+  return oldval;
+}
+
+BUILTIN_TYPE
+SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
+{
+  UWORD mask, shift, woldval, t, *wptr;
+  BUILTIN_TYPE newval;
+
+  pre_barrier (smodel);
+
+  wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
+  shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
+  mask = SIZE(MASK) << shift;
+
+  woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
+  do
+    {
+      /* Extract the old value for comparison.  */
+      BUILTIN_TYPE oldval = (BUILTIN_TYPE)((woldval >> shift) & SIZE(MASK));
+      /* Apply the operation and save the result.  */
+      newval = OP(oldval, (BUILTIN_TYPE)opval);
+      /* Repack with the updated value.  */
+      t = (woldval & ~mask) | (((UWORD)(UTYPE)newval) << shift);
+    }
+  while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
+                                     __ATOMIC_RELAXED, __ATOMIC_RELAXED));
+
+  post_barrier (smodel);
+  /* Return the new value after the operation.  */
+  return newval;
+}
+
+#else
+/* For all other operations, we can operate on the whole word without the
+   extra cost of extraction.  */
 UTYPE
 SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
 {
@@ -154,16 +228,18 @@ SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, 
int smodel)
   return t >> shift;
 }
 
+#endif /* LAT_MINMAX_OP_N */
+
 #define DONE 1
 #endif /* atomic_compare_exchange_w */
 
 
 /* Otherwise, fall back to some sort of protection mechanism.  */
 #if !DONE
-UTYPE
-SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
+BUILTIN_TYPE
+SIZE(C2(libat_fetch_,NAME)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel UNUSED)
 {
-  UTYPE ret;
+  BUILTIN_TYPE ret;
   UWORD magic;
 
   pre_seq_barrier (smodel);
@@ -178,10 +254,10 @@ SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, 
int smodel UNUSED)
   return ret;
 }
 
-UTYPE
-SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
+BUILTIN_TYPE
+SIZE(C3(libat_,NAME,_fetch)) (BUILTIN_TYPE *mptr, BUILTIN_TYPE opval, int 
smodel UNUSED)
 {
-  UTYPE ret;
+  BUILTIN_TYPE ret;
   UWORD magic;
 
   pre_seq_barrier (smodel);
@@ -199,4 +275,9 @@ SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int 
smodel UNUSED)
 
 EXPORT_ALIAS (SIZE(C2(fetch_,NAME)));
 EXPORT_ALIAS (SIZE(C2(NAME,_fetch)));
+
+#ifdef BUILTIN_TYPE
+#undef BUILTIN_TYPE
+#endif
+
 #undef LAT_FOP_N
diff --git a/libatomic/fsmax_n.c b/libatomic/fsmax_n.c
new file mode 100644
index 00000000000..1f606ec528b
--- /dev/null
+++ b/libatomic/fsmax_n.c
@@ -0,0 +1,50 @@
+/* Copyright The GNU Toolchain Authors.
+
+   Libatomic 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 of the License, or
+   (at your option) any later version.
+
+   Libatomic 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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define LAT_FSMAX_N
+#include "libatomic_i.h"
+
+#define NAME   smax
+/* In case of equality, choose first value.  */
+#define OP(X,Y) \
+  ({ __typeof__ (X) _X = (X); \
+     __typeof__ (Y) _Y = (Y); \
+     _X >= _Y ? _X : _Y; })
+
+/* MIN/MAX operations require special handling.  */
+#define BUILTIN_TYPE   STYPE
+#define LAT_MINMAX_OP_N
+
+/* Redirect the generic HAVE_ATOMIC_FETCH_OP_* macros to check for
+   min/max-specific availability.  */
+# undef HAVE_ATOMIC_FETCH_OP_1
+# undef HAVE_ATOMIC_FETCH_OP_2
+# undef HAVE_ATOMIC_FETCH_OP_4
+# undef HAVE_ATOMIC_FETCH_OP_8
+# undef HAVE_ATOMIC_FETCH_OP_16
+# define HAVE_ATOMIC_FETCH_OP_1   HAVE_ATOMIC_FETCH_MINMAX_1
+# define HAVE_ATOMIC_FETCH_OP_2   HAVE_ATOMIC_FETCH_MINMAX_2
+# define HAVE_ATOMIC_FETCH_OP_4   HAVE_ATOMIC_FETCH_MINMAX_4
+# define HAVE_ATOMIC_FETCH_OP_8   HAVE_ATOMIC_FETCH_MINMAX_8
+# define HAVE_ATOMIC_FETCH_OP_16  HAVE_ATOMIC_FETCH_MINMAX_16
+
+#include "fop_n.c"
+#undef LAT_FSMAX_N
\ No newline at end of file
diff --git a/libatomic/fsmin_n.c b/libatomic/fsmin_n.c
new file mode 100644
index 00000000000..df5e3ecd094
--- /dev/null
+++ b/libatomic/fsmin_n.c
@@ -0,0 +1,50 @@
+/* Copyright The GNU Toolchain Authors.
+
+   Libatomic 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 of the License, or
+   (at your option) any later version.
+
+   Libatomic 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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+   
+#define LAT_FSMIN_N
+#include "libatomic_i.h"
+
+#define NAME   smin
+/* In case of equality, choose first value.  */
+#define OP(X,Y) \
+  ({ __typeof__ (X) _X = (X); \
+     __typeof__ (Y) _Y = (Y); \
+     _X <= _Y ? _X : _Y; })
+
+/* MIN/MAX operations require special handling.  */
+#define BUILTIN_TYPE   STYPE
+#define LAT_MINMAX_OP_N
+
+/* Redirect the generic HAVE_ATOMIC_FETCH_OP_* macros to check for
+   min/max-specific availability.  */
+# undef HAVE_ATOMIC_FETCH_OP_1
+# undef HAVE_ATOMIC_FETCH_OP_2
+# undef HAVE_ATOMIC_FETCH_OP_4
+# undef HAVE_ATOMIC_FETCH_OP_8
+# undef HAVE_ATOMIC_FETCH_OP_16
+# define HAVE_ATOMIC_FETCH_OP_1   HAVE_ATOMIC_FETCH_MINMAX_1
+# define HAVE_ATOMIC_FETCH_OP_2   HAVE_ATOMIC_FETCH_MINMAX_2
+# define HAVE_ATOMIC_FETCH_OP_4   HAVE_ATOMIC_FETCH_MINMAX_4
+# define HAVE_ATOMIC_FETCH_OP_8   HAVE_ATOMIC_FETCH_MINMAX_8
+# define HAVE_ATOMIC_FETCH_OP_16  HAVE_ATOMIC_FETCH_MINMAX_16
+
+#include "fop_n.c"
+#undef LAT_FSMIN_N
\ No newline at end of file
diff --git a/libatomic/fumax_n.c b/libatomic/fumax_n.c
new file mode 100644
index 00000000000..224f574c868
--- /dev/null
+++ b/libatomic/fumax_n.c
@@ -0,0 +1,49 @@
+/* Copyright The GNU Toolchain Authors.
+
+   Libatomic 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 of the License, or
+   (at your option) any later version.
+
+   Libatomic 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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define LAT_FUMAX_N
+#include "libatomic_i.h"
+
+#define NAME   umax
+/* In case of equality, choose first value.  */
+#define OP(X,Y) \
+  ({ __typeof__ (X) _X = (X); \
+     __typeof__ (Y) _Y = (Y); \
+     _X >= _Y ? _X : _Y; })
+
+/* MIN/MAX operations require special handling.  */
+#define LAT_MINMAX_OP_N
+
+/* Redirect the generic HAVE_ATOMIC_FETCH_OP_* macros to check for
+   min/max-specific availability.  */
+# undef HAVE_ATOMIC_FETCH_OP_1
+# undef HAVE_ATOMIC_FETCH_OP_2
+# undef HAVE_ATOMIC_FETCH_OP_4
+# undef HAVE_ATOMIC_FETCH_OP_8
+# undef HAVE_ATOMIC_FETCH_OP_16
+# define HAVE_ATOMIC_FETCH_OP_1   HAVE_ATOMIC_FETCH_MINMAX_1
+# define HAVE_ATOMIC_FETCH_OP_2   HAVE_ATOMIC_FETCH_MINMAX_2
+# define HAVE_ATOMIC_FETCH_OP_4   HAVE_ATOMIC_FETCH_MINMAX_4
+# define HAVE_ATOMIC_FETCH_OP_8   HAVE_ATOMIC_FETCH_MINMAX_8
+# define HAVE_ATOMIC_FETCH_OP_16  HAVE_ATOMIC_FETCH_MINMAX_16
+
+#include "fop_n.c"
+#undef LAT_FUMAX_N
\ No newline at end of file
diff --git a/libatomic/fumin_n.c b/libatomic/fumin_n.c
new file mode 100644
index 00000000000..7ad44dfef8f
--- /dev/null
+++ b/libatomic/fumin_n.c
@@ -0,0 +1,49 @@
+/* Copyright The GNU Toolchain Authors.
+
+   Libatomic 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 of the License, or
+   (at your option) any later version.
+
+   Libatomic 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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define LAT_FUMIN_N
+#include "libatomic_i.h"
+
+#define NAME   umin
+/* In case of equality, choose first value.  */
+#define OP(X,Y) \
+  ({ __typeof__ (X) _X = (X); \
+     __typeof__ (Y) _Y = (Y); \
+     _X <= _Y ? _X : _Y; })
+
+/* MIN/MAX operations require special handling.  */
+#define LAT_MINMAX_OP_N
+
+/* Redirect the generic HAVE_ATOMIC_FETCH_OP_* macros to check for
+   min/max-specific availability.  */
+# undef HAVE_ATOMIC_FETCH_OP_1
+# undef HAVE_ATOMIC_FETCH_OP_2
+# undef HAVE_ATOMIC_FETCH_OP_4
+# undef HAVE_ATOMIC_FETCH_OP_8
+# undef HAVE_ATOMIC_FETCH_OP_16
+# define HAVE_ATOMIC_FETCH_OP_1   HAVE_ATOMIC_FETCH_MINMAX_1
+# define HAVE_ATOMIC_FETCH_OP_2   HAVE_ATOMIC_FETCH_MINMAX_2
+# define HAVE_ATOMIC_FETCH_OP_4   HAVE_ATOMIC_FETCH_MINMAX_4
+# define HAVE_ATOMIC_FETCH_OP_8   HAVE_ATOMIC_FETCH_MINMAX_8
+# define HAVE_ATOMIC_FETCH_OP_16  HAVE_ATOMIC_FETCH_MINMAX_16
+
+#include "fop_n.c"
+#undef LAT_FUMIN_N
\ No newline at end of file
diff --git a/libatomic/libatomic.map b/libatomic/libatomic.map
index 39e7c2c6b9a..3666627eea0 100644
--- a/libatomic/libatomic.map
+++ b/libatomic/libatomic.map
@@ -108,3 +108,47 @@ LIBATOMIC_1.2 {
        atomic_flag_clear;
        atomic_flag_clear_explicit;
 } LIBATOMIC_1.1;
+
+LIBATOMIC_1.3 {
+  global:
+       __atomic_fetch_smin_1;
+       __atomic_fetch_smin_2;
+       __atomic_fetch_smin_4;
+       __atomic_fetch_smin_8;
+       __atomic_fetch_smin_16;
+       __atomic_fetch_smax_1;
+       __atomic_fetch_smax_2;
+       __atomic_fetch_smax_4;
+       __atomic_fetch_smax_8;
+       __atomic_fetch_smax_16;
+       __atomic_fetch_umin_1;
+       __atomic_fetch_umin_2;
+       __atomic_fetch_umin_4;
+       __atomic_fetch_umin_8;
+       __atomic_fetch_umin_16;
+       __atomic_fetch_umax_1;
+       __atomic_fetch_umax_2;
+       __atomic_fetch_umax_4;
+       __atomic_fetch_umax_8;
+       __atomic_fetch_umax_16;
+       __atomic_smin_fetch_1;
+       __atomic_smin_fetch_2;
+       __atomic_smin_fetch_4;
+       __atomic_smin_fetch_8;
+       __atomic_smin_fetch_16;
+       __atomic_smax_fetch_1;
+       __atomic_smax_fetch_2;
+       __atomic_smax_fetch_4;
+       __atomic_smax_fetch_8;
+       __atomic_smax_fetch_16;
+       __atomic_umin_fetch_1;
+       __atomic_umin_fetch_2;
+       __atomic_umin_fetch_4;
+       __atomic_umin_fetch_8;
+       __atomic_umin_fetch_16;
+       __atomic_umax_fetch_1;
+       __atomic_umax_fetch_2;
+       __atomic_umax_fetch_4;
+       __atomic_umax_fetch_8;
+       __atomic_umax_fetch_16;
+} LIBATOMIC_1.2;
\ No newline at end of file
diff --git a/libatomic/libatomic_i.h b/libatomic/libatomic_i.h
index e59dd412e17..65b998d0081 100644
--- a/libatomic/libatomic_i.h
+++ b/libatomic/libatomic_i.h
@@ -50,17 +50,22 @@
 
 /* All of the primitive types on which we operate.  */
 typedef unsigned U_1 __attribute__((mode(QI)));
+typedef signed S_1 __attribute__((mode(QI)));
 #if HAVE_INT2
 typedef unsigned U_2 __attribute__((mode(HI)));
+typedef signed S_2 __attribute__((mode(HI)));
 #endif
 #if HAVE_INT4
 typedef unsigned U_4 __attribute__((mode(SI)));
+typedef signed S_4 __attribute__((mode(SI)));
 #endif
 #if HAVE_INT8
 typedef unsigned U_8 __attribute__((mode(DI)));
+typedef signed S_8 __attribute__((mode(DI)));
 #endif
 #if HAVE_INT16
 typedef unsigned U_16 __attribute__((mode(TI)));
+typedef signed S_16 __attribute__((mode(TI)));
 #endif
 
 /* The widest type that we support.  */
@@ -76,21 +81,26 @@ typedef unsigned U_16 __attribute__((mode(TI)));
 # define MAX_SIZE      1
 #endif
 typedef C2(U_,MAX_SIZE) U_MAX;
+typedef C2(S_,MAX_SIZE) S_MAX;
 
 /* Provide dummy fallback types so that stuff is syntactically correct
    without having to overdo the ifdefs.  The code using these should
    always be protected with the HAVE_INT{n} macros.  */
 #if !HAVE_INT2
 typedef U_MAX U_2;
+typedef S_MAX S_2;
 #endif
 #if !HAVE_INT4
 typedef U_MAX U_4;
+typedef S_MAX S_4;
 #endif
 #if !HAVE_INT8
 typedef U_MAX U_8;
+typedef S_MAX S_8;
 #endif
 #if !HAVE_INT16
 typedef U_MAX U_16;
+typedef S_MAX S_16;
 #endif
 
 union max_size_u
@@ -123,8 +133,8 @@ typedef unsigned UWORD __attribute__((mode(word)));
 #define PTR(N,X)       ((C2(U_,N) *)X)
 
 /* And thus, the type on which this compilation will be operating.  */
-#define ITYPE          SIZE(I)
 #define UTYPE          SIZE(U)
+#define STYPE          SIZE(S)
 
 /* Utility macros for GCC attributes.  */
 #define UNUSED         __attribute__((unused))
@@ -159,8 +169,8 @@ void libat_lock_n (void *ptr, size_t n);
 void libat_unlock_n (void *ptr, size_t n);
 
 /* We'll need to declare all of the sized functions a few times...  */
-#define DECLARE_ALL_SIZED(N)  DECLARE_ALL_SIZED_(N,C2(U_,N))
-#define DECLARE_ALL_SIZED_(N,T)                                                
\
+#define DECLARE_ALL_SIZED(N)  DECLARE_ALL_SIZED_(N,C2(U_,N),C2(S_,N))
+#define DECLARE_ALL_SIZED_(N,T,S)                                              
\
   DECLARE_1(T,    C2(load_,N), (T *mptr, int));                                
\
   DECLARE_1(void, C2(store_,N), (T *mptr, T val, int));                        
\
   DECLARE_1(T,    C2(exchange_,N), (T *mptr, T, int));                 \
@@ -172,12 +182,20 @@ void libat_unlock_n (void *ptr, size_t n);
   DECLARE_1(T,    C2(fetch_xor_,N), (T *mptr, T, int));                        
\
   DECLARE_1(T,    C2(fetch_or_,N), (T *mptr, T, int));                 \
   DECLARE_1(T,    C2(fetch_nand_,N), (T *mptr, T, int));               \
+  DECLARE_1(S,    C2(fetch_smax_,N), (S *mptr, S, int));               \
+  DECLARE_1(T,    C2(fetch_umax_,N), (T *mptr, T, int));               \
+  DECLARE_1(S,    C2(fetch_smin_,N), (S *mptr, S, int));               \
+  DECLARE_1(T,    C2(fetch_umin_,N), (T *mptr, T, int));               \
   DECLARE_1(T,    C2(add_fetch_,N), (T *mptr, T, int));                        
\
   DECLARE_1(T,    C2(sub_fetch_,N), (T *mptr, T, int));                        
\
   DECLARE_1(T,    C2(and_fetch_,N), (T *mptr, T, int));                        
\
   DECLARE_1(T,    C2(xor_fetch_,N), (T *mptr, T, int));                        
\
   DECLARE_1(T,    C2(or_fetch_,N), (T *mptr, T, int));                 \
-  DECLARE_1(T,    C2(nand_fetch_,N), (T *mptr, T, int))
+  DECLARE_1(T,    C2(nand_fetch_,N), (T *mptr, T, int));               \
+  DECLARE_1(S,    C2(smax_fetch_,N), (S *mptr, S, int));               \
+  DECLARE_1(T,    C2(umax_fetch_,N), (T *mptr, T, int));               \
+  DECLARE_1(S,    C2(smin_fetch_,N), (S *mptr, S, int));               \
+  DECLARE_1(T,    C2(umin_fetch_,N), (T *mptr, T, int))
 
 /* All sized operations are implemented in hidden functions prefixed with
    "libat_".  These are either renamed or aliased to the expected prefix
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-1.c 
b/libatomic/testsuite/libatomic.c/atomic-op-1.c
index 56632291489..cffaa6d7be6 100644
--- a/libatomic/testsuite/libatomic.c/atomic-op-1.c
+++ b/libatomic/testsuite/libatomic.c/atomic-op-1.c
@@ -4,6 +4,8 @@
 
 /* Test the execution of the __atomic_*OP builtin routines for a char.  */
 
+#include "limits.h"
+
 extern void abort(void);
 
 char v, count, res;
@@ -166,6 +168,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
@@ -327,6 +437,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.  */
@@ -526,6 +743,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 ()
 {
@@ -535,6 +876,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 ();
@@ -542,6 +887,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 ();
@@ -549,6 +898,10 @@ main ()
   test_nand ();
   test_xor ();
   test_or ();
+  test_smin ();
+  test_umin ();
+  test_smax ();
+  test_umax ();
 
   return 0;
 }
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-2.c 
b/libatomic/testsuite/libatomic.c/atomic-op-2.c
index 436b206b422..ee6422cd6e7 100644
--- a/libatomic/testsuite/libatomic.c/atomic-op-2.c
+++ b/libatomic/testsuite/libatomic.c/atomic-op-2.c
@@ -5,6 +5,8 @@
 
 /* Test the execution of the __atomic_*OP builtin routines for a short.  */
 
+#include "limits.h"
+
 extern void abort(void);
 
 short v, count, res;
@@ -167,6 +169,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
@@ -328,6 +438,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.  */
@@ -527,6 +744,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 ()
 {
@@ -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/libatomic/testsuite/libatomic.c/atomic-op-3.c 
b/libatomic/testsuite/libatomic.c/atomic-op-3.c
index d72be2e9d30..fcc9cdb5898 100644
--- a/libatomic/testsuite/libatomic.c/atomic-op-3.c
+++ b/libatomic/testsuite/libatomic.c/atomic-op-3.c
@@ -4,6 +4,8 @@
 
 /* Test the execution of the __atomic_*OP builtin routines for an int.  */
 
+#include "limits.h"
+
 extern void abort(void);
 
 int v, count, res;
@@ -166,6 +168,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
@@ -327,6 +437,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.  */
@@ -526,6 +743,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 ()
 {
@@ -535,6 +876,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 ();
@@ -542,6 +887,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 ();
@@ -549,6 +898,10 @@ main ()
   test_nand ();
   test_xor ();
   test_or ();
+  test_smin ();
+  test_umin ();
+  test_smax ();
+  test_umax ();
 
   return 0;
 }
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-4.c 
b/libatomic/testsuite/libatomic.c/atomic-op-4.c
index 0998c3a6548..ddf5a7d6715 100644
--- a/libatomic/testsuite/libatomic.c/atomic-op-4.c
+++ b/libatomic/testsuite/libatomic.c/atomic-op-4.c
@@ -5,6 +5,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;
@@ -167,6 +169,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
@@ -328,6 +438,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.  */
@@ -527,6 +744,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 ()
 {
@@ -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/libatomic/testsuite/libatomic.c/atomic-op-5.c 
b/libatomic/testsuite/libatomic.c/atomic-op-5.c
index 763880da0fc..749cc66cd37 100644
--- a/libatomic/testsuite/libatomic.c/atomic-op-5.c
+++ b/libatomic/testsuite/libatomic.c/atomic-op-5.c
@@ -7,6 +7,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;
 
@@ -167,6 +171,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
@@ -328,6 +440,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.  */
@@ -527,6 +746,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 ()
 {
@@ -536,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 ();
@@ -543,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 ();
@@ -550,6 +901,10 @@ main ()
   test_nand ();
   test_xor ();
   test_or ();
+  test_smin ();
+  test_umin ();
+  test_smax ();
+  test_umax ();
 
   return 0;
 }
-- 
2.44.0

Reply via email to