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