From: Soumya AR <[email protected]>

This patch adds tests to verify the correctness of atomic min/max builtins at
runtime and confirms CAS assembly on an actual target (in this case, aarch64).

  - atomic-minmax.c: Checks that we emit the correct libgcc calls that get
    resolved at runtime to determine if the system supports LSE or not. Also
    does a runtime check.
  - atomic-minmax-nolse.c: Checks for the correct non-LSE sequence using LL/SC
    instructions.
  - atomic-minmax-lse.c: Checks for the correct LSE instruction.

Currently, these 3 tests check for CAS calls, but once the aarch64 backend is
extended to support direct optabs for min/max, these tests will be overwritten
to min/max specific instructions.

Additionally, atomic-op-*.c tests are also extended with min/max for target
independent tests.

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]>

gcc/testsuite/ChangeLog:

        * gcc.dg/atomic-op-1.c: Add min/max.
        * 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.target/aarch64/atomic-minmax-lse.c: New test.
        * gcc.target/aarch64/atomic-minmax-nolse.c: New test.
        * gcc.target/aarch64/atomic-minmax.c: New test.
        * gcc.target/aarch64/atomic-minmax.x: New test.
---
 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.target/aarch64/atomic-minmax-lse.c    | 123 ++++++
 .../gcc.target/aarch64/atomic-minmax-nolse.c  | 183 +++++++++
 .../gcc.target/aarch64/atomic-minmax.c        | 129 +++++++
 .../gcc.target/aarch64/atomic-minmax.x        | 185 +++++++++
 9 files changed, 2387 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/atomic-minmax-lse.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/atomic-minmax-nolse.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/atomic-minmax.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/atomic-minmax.x

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 1407f3fe3b2..b0c4c16a7b4 100644
--- a/gcc/testsuite/gcc.dg/atomic-op-5.c
+++ b/gcc/testsuite/gcc.dg/atomic-op-5.c
@@ -8,6 +8,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;
 
@@ -168,6 +172,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
@@ -329,6 +441,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.  */
@@ -528,6 +747,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 ()
 {
@@ -537,6 +880,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 +891,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 +902,10 @@ main ()
   test_nand ();
   test_xor ();
   test_or ();
+  test_smin ();
+  test_umin ();
+  test_smax ();
+  test_umax ();
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-minmax-lse.c 
b/gcc/testsuite/gcc.target/aarch64/atomic-minmax-lse.c
new file mode 100644
index 00000000000..19e078d0ee9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/atomic-minmax-lse.c
@@ -0,0 +1,123 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target aarch64_asm_lse_ok } */
+/* { dg-options "-march=armv8-a+lse" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "atomic-minmax.x"
+
+/* { dg-final { scan-assembler-not "\tldxr*" } } */
+/* { dg-final { scan-assembler-not "\tldaxr*" } } */
+/* { dg-final { scan-assembler-not "\tstxr*" } } */
+/* { dg-final { scan-assembler-not "\tstlxr*" } } */
+
+/*
+** test_smin_s8:
+**     ...
+**     casalb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smax_s8:
+**     ...
+**     casalb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smin_s16:
+**     ...
+**     casalh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smax_s16:
+**     ...
+**     casalh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smin_s32:
+**     ...
+**     casal   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smax_s32:
+**     ...
+**     casal   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smin_s64:
+**     ...
+**     casal   x[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_smax_s64:
+**     ...
+**     casal   x[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umin_u8:
+**     ...
+**     casalb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umax_u8:
+**     ...
+**     casalb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umin_u16:
+**     ...
+**     casalh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umax_u16:
+**     ...
+**     casalh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umin_u32:
+**     ...
+**     casal   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umax_u32:
+**     ...
+**     casal   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umin_u64:
+**     ...
+**     casal   x[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     ...
+*/
+
+/*
+** test_umax_u64:
+**     ...
+**     casal   x[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     ...
+*/
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-minmax-nolse.c 
b/gcc/testsuite/gcc.target/aarch64/atomic-minmax-nolse.c
new file mode 100644
index 00000000000..74ec877adce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/atomic-minmax-nolse.c
@@ -0,0 +1,183 @@
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+nolse -mno-outline-atomics" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "atomic-minmax.x"
+
+/* { dg-final { scan-assembler-not "\tcas*" } } */
+/* { dg-final { scan-assembler-not "__aarch64_*" } } */
+
+/*
+** test_smin_s8:
+**     ...
+**     ldxrb   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxtb
+**     bne     .*
+**     stlxrb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smax_s8:
+**     ...
+**     ldxrb   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxtb
+**     bne     .*
+**     stlxrb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smin_s16:
+**     ...
+**     ldxrh   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxth
+**     bne     .*
+**     stlxrh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smax_s16:
+**     ...
+**     ldxrh   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxth
+**     bne     .*
+**     stlxrh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+/*
+** test_smin_s32:
+**     ...
+**     ldxr    w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smax_s32:
+**     ...
+**     ldxr    w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smin_s64:
+**     ...
+**     ldxr    x[0-9]+, \[x[0-9]+\]
+**     cmp     x[0-9]+, x[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_smin_s64:
+**     ...
+**     ldxr    x[0-9]+, \[x[0-9]+\]
+**     cmp     x[0-9]+, x[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umin_u8:
+**     ...
+**     ldxrb   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxtb
+**     bne     .*
+**     stlxrb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umax_u8:
+**     ...
+**     ldxrb   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxtb
+**     bne     .*
+**     stlxrb  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umin_u16:
+**     ...
+**     ldxrh   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxth
+**     bne     .*
+**     stlxrh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umax_u16:
+**     ...
+**     ldxrh   w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+, uxth
+**     bne     .*
+**     stlxrh  w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umin_u32:
+**     ...
+**     ldxr    w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umax_u32:
+**     ...
+**     ldxr    w[0-9]+, \[x[0-9]+\]
+**     cmp     w[0-9]+, w[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, w[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umin_u64:
+**     ...
+**     ldxr    x[0-9]+, \[x[0-9]+\]
+**     cmp     x[0-9]+, x[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
+
+/*
+** test_umax_u64:
+**     ...
+**     ldxr    x[0-9]+, \[x[0-9]+\]
+**     cmp     x[0-9]+, x[0-9]+
+**     bne     .*
+**     stlxr   w[0-9]+, x[0-9]+, \[x[0-9]+\]
+**     cbnz    w[0-9]+, .*
+**     ...
+*/
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-minmax.c 
b/gcc/testsuite/gcc.target/aarch64/atomic-minmax.c
new file mode 100644
index 00000000000..f61082e288b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/atomic-minmax.c
@@ -0,0 +1,129 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "atomic-minmax.x"
+
+int main ()
+{
+  run_tests();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "\tcas*" } } */
+/* { dg-final { scan-assembler-not "\tldxr*" } } */
+/* { dg-final { scan-assembler-not "\tldaxr*" } } */
+/* { dg-final { scan-assembler-not "\tstxr*" } } */
+/* { dg-final { scan-assembler-not "\tstlxr*" } } */
+
+/*
+** test_smin_s8:
+**     ...
+**     bl      __aarch64_cas1_sync
+**     ...
+*/
+
+/*
+** test_smax_s8:
+**     ...
+**     bl      __aarch64_cas1_sync
+**     ...
+*/
+
+/*
+** test_smin_s16:
+**     ...
+**     bl      __aarch64_cas2_sync
+**     ...
+*/
+
+/*
+** test_smax_s16:
+**     ...
+**     bl      __aarch64_cas2_sync
+**     ...
+*/
+
+/*
+** test_smin_s32:
+**     ...
+**     bl      __aarch64_cas4_sync
+**     ...
+*/
+
+/*
+** test_smax_s32:
+**     ...
+**     bl      __aarch64_cas4_sync
+**     ...
+*/
+
+/*
+** test_smin_s64:
+**     ...
+**     bl      __aarch64_cas8_sync
+**     ...
+*/
+
+/*
+** test_smax_s64:
+**     ...
+**     bl      __aarch64_cas8_sync
+**     ...     
+*/
+
+/*
+** test_umin_u8:
+**     ...
+**     bl      __aarch64_cas1_sync
+**     ...
+*/
+
+/*
+** test_umax_u8:
+**     ...
+**     bl      __aarch64_cas1_sync
+**     ...
+*/
+
+/*
+** test_umin_u16:
+**     ...
+**     bl      __aarch64_cas2_sync
+**     ...
+*/
+
+/*
+** test_umax_u16:
+**     ...
+**     bl      __aarch64_cas2_sync
+**     ...
+*/
+
+/*
+** test_umin_u32:
+**     ...
+**     bl      __aarch64_cas4_sync
+**     ...
+*/
+
+/*
+** test_umax_u32:
+**     ...
+**     bl      __aarch64_cas4_sync
+**     ...
+*/
+
+/*
+** test_umin_u64:
+**     ...
+**     bl      __aarch64_cas8_sync
+**     ...
+*/
+
+/*
+** test_umax_u64:
+**     ...
+**     bl      __aarch64_cas8_sync
+**     ...     
+*/
diff --git a/gcc/testsuite/gcc.target/aarch64/atomic-minmax.x 
b/gcc/testsuite/gcc.target/aarch64/atomic-minmax.x
new file mode 100644
index 00000000000..e9e21d3f2db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/atomic-minmax.x
@@ -0,0 +1,185 @@
+#include <stdint.h>
+
+extern void abort(void);
+
+#define TEST_FETCH_OP(TYPE, VAR, OP, INIT, ARG, EXPECTED_OLD, EXPECTED_NEW, 
MEM_ORDER) \
+  do { \
+    VAR = INIT; \
+    TYPE old_val = __atomic_fetch_##OP(&VAR, ARG, MEM_ORDER); \
+    TYPE new_val = VAR; \
+    if (old_val != EXPECTED_OLD) { \
+      abort(); \
+    } \
+    if (new_val != EXPECTED_NEW) { \
+      abort(); \
+    } \
+  } while (0)
+
+#define TEST_OP_FETCH(TYPE, VAR, OP, INIT, ARG, EXPECTED_OLD, EXPECTED_NEW, 
MEM_ORDER) \
+  do { \
+    VAR = INIT; \
+    TYPE result = __atomic_##OP##_fetch(&VAR, ARG, MEM_ORDER); \
+    TYPE new_val = VAR; \
+    if (result != EXPECTED_NEW) { \
+      abort(); \
+    } \
+    if (new_val != EXPECTED_NEW) { \
+      abort(); \
+    } \
+  } while (0)
+
+#define GEN_TYPE_TESTS(TYPE, VAR, SUFFIX, IS_SIGNED) \
+  TYPE VAR; \
+  void test_##SUFFIX() { \
+    TEST_FETCH_OP(TYPE, VAR, min, 10, 5, 10, 5, __ATOMIC_RELAXED); \
+    TEST_FETCH_OP(TYPE, VAR, min, 10, 20, 10, 10, __ATOMIC_SEQ_CST); \
+    TEST_FETCH_OP(TYPE, VAR, max, 10, 20, 10, 20, __ATOMIC_ACQUIRE); \
+    TEST_FETCH_OP(TYPE, VAR, max, 10, 5, 10, 10, __ATOMIC_RELEASE); \
+    \
+    TEST_OP_FETCH(TYPE, VAR, min, 10, 5, 10, 5, __ATOMIC_CONSUME); \
+    TEST_OP_FETCH(TYPE, VAR, min, 10, 20, 10, 10, __ATOMIC_ACQ_REL); \
+    TEST_OP_FETCH(TYPE, VAR, max, 10, 20, 10, 20, __ATOMIC_RELAXED); \
+    TEST_OP_FETCH(TYPE, VAR, max, 10, 5, 10, 10, __ATOMIC_SEQ_CST); \
+    \
+    if (IS_SIGNED) { \
+      TEST_FETCH_OP(TYPE, VAR, min, -10, -20, -10, -20, __ATOMIC_ACQUIRE); \
+      TEST_FETCH_OP(TYPE, VAR, max, -10, 5, -10, 5, __ATOMIC_RELEASE); \
+      TEST_FETCH_OP(TYPE, VAR, min, -5, -3, -5, -5, __ATOMIC_RELAXED); \
+      TEST_FETCH_OP(TYPE, VAR, max, -20, -10, -20, -10, __ATOMIC_SEQ_CST); \
+      TEST_OP_FETCH(TYPE, VAR, min, -100, 50, -100, -100, __ATOMIC_ACQ_REL); \
+      TEST_OP_FETCH(TYPE, VAR, max, -50, -60, -50, -50, __ATOMIC_CONSUME); \
+    } \
+  }
+
+GEN_TYPE_TESTS(int8_t, s8_var_test, s8, 1)
+GEN_TYPE_TESTS(int16_t, s16_var_test, s16, 1)
+GEN_TYPE_TESTS(int32_t, s32_var_test, s32, 1)
+GEN_TYPE_TESTS(int64_t, s64_var_test, s64, 1)
+
+GEN_TYPE_TESTS(uint8_t, u8_var_test, u8, 0)
+GEN_TYPE_TESTS(uint16_t, u16_var_test, u16, 0)
+GEN_TYPE_TESTS(uint32_t, u32_var_test, u32, 0)
+GEN_TYPE_TESTS(uint64_t, u64_var_test, u64, 0)
+
+void run_tests() {
+  test_s8();
+  test_s16();
+  test_s32();
+  test_s64();
+  test_u8();
+  test_u16();
+  test_u32();
+  test_u64();
+}
+
+int8_t s8_var = 0;
+
+int8_t
+test_smin_s8 (int8_t a)
+{
+  return __atomic_fetch_min (&s8_var, a, __ATOMIC_RELAXED);
+}
+
+int8_t
+test_smax_s8 (int8_t a)
+{
+  return __atomic_fetch_max (&s8_var, a, __ATOMIC_RELEASE);
+}
+
+int16_t s16_var = 0;
+
+int16_t
+test_smin_s16 (int16_t a)
+{
+  return __atomic_fetch_min (&s16_var, a, __ATOMIC_ACQUIRE);
+}
+
+int16_t
+test_smax_s16 (int16_t a)
+{
+  return __atomic_fetch_max (&s16_var, a, __ATOMIC_ACQ_REL);
+}
+
+int32_t s32_var = 0;
+
+int32_t
+test_smin_s32 (int32_t a)
+{
+  return __atomic_fetch_min (&s32_var, a, __ATOMIC_RELAXED);
+}
+
+int32_t
+test_smax_s32 (int32_t a)
+{
+  return __atomic_fetch_max (&s32_var, a, __ATOMIC_SEQ_CST);
+}
+
+int64_t s64_var = 0;
+
+int64_t
+test_smin_s64 (int64_t a)
+{
+  return __atomic_fetch_min (&s64_var, a, __ATOMIC_ACQUIRE);
+}
+
+int64_t
+test_smax_s64 (int64_t a)
+{
+  return __atomic_fetch_max (&s64_var, a, __ATOMIC_RELAXED);
+}
+
+uint8_t u8_var = 0;
+
+uint8_t
+test_umin_u8 (uint8_t a)
+{
+  return __atomic_fetch_min (&u8_var, a, __ATOMIC_RELAXED);
+}
+
+uint8_t
+test_umax_u8 (uint8_t a)
+{
+  return __atomic_fetch_max (&u8_var, a, __ATOMIC_CONSUME);
+}
+
+uint16_t u16_var = 0;
+
+uint16_t
+test_umin_u16 (uint16_t a)
+{
+  return __atomic_fetch_min (&u16_var, a, __ATOMIC_ACQUIRE);
+}
+
+uint16_t
+test_umax_u16 (uint16_t a)
+{
+  return __atomic_fetch_max (&u16_var, a, __ATOMIC_RELEASE);
+}
+
+uint32_t u32_var = 0;
+
+uint32_t
+test_umin_u32 (uint32_t a)
+{
+  return __atomic_fetch_min (&u32_var, a, __ATOMIC_ACQ_REL);
+}
+
+uint32_t
+test_umax_u32 (uint32_t a)
+{
+  return __atomic_fetch_max (&u32_var, a, __ATOMIC_RELAXED);
+}
+
+uint64_t u64_var = 0;
+
+uint64_t
+test_umin_u64 (uint64_t a)
+{
+  return __atomic_fetch_min (&u64_var, a, __ATOMIC_RELAXED);
+}
+
+uint64_t
+test_umax_u64 (uint64_t a)
+{
+  return __atomic_fetch_max (&u64_var, a, __ATOMIC_ACQ_REL);
+}
\ No newline at end of file
-- 
2.44.0

Reply via email to