[6/8,RFC] First attempt at testsuite

Message ID 20240919131204.3865854-7-mmalcomson@nvidia.com
State New
Headers
Series Introduce floating point fetch_add builtins |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Build failed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Test failed

Commit Message

Matthew Malcomson Sept. 19, 2024, 1:12 p.m. UTC
  From: Matthew Malcomson <mmalcomson@nvidia.com>

As it stands this doesn't fully pass.  However it passes *enough* to
convince me that it's of the "shape" that I would suggest (and hence
good enough for an RFC).

Signed-off-by: Matthew Malcomson <mmalcomson@nvidia.com>
---
 gcc/testsuite/gcc.dg/atomic-op-fp.c           | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf.c          | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf128.c       | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf16.c        | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf16b.c       | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf32.c        | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf32x.c       | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf64.c        | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpf64x.c       | 204 ++++++++
 gcc/testsuite/gcc.dg/atomic-op-fpl.c          | 204 ++++++++
 gcc/testsuite/lib/target-supports.exp         | 463 +++++++++++++++++-
 .../testsuite/libatomic.c/atomic-op-fp.c      | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf.c     | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf128.c  | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf16.c   | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf16b.c  | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf32.c   | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf32x.c  | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf64.c   | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpf64x.c  | 203 ++++++++
 .../testsuite/libatomic.c/atomic-op-fpl.c     | 203 ++++++++
 21 files changed, 4532 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fp.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf128.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf16.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf16b.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf32.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf32x.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf64.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpf64x.c
 create mode 100644 gcc/testsuite/gcc.dg/atomic-op-fpl.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fp.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf128.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf16.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf16b.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf32.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf32x.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf64.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpf64x.c
 create mode 100644 libatomic/testsuite/libatomic.c/atomic-op-fpl.c
  

Patch

diff --git a/gcc/testsuite/gcc.dg/atomic-op-fp.c b/gcc/testsuite/gcc.dg/atomic-op-fp.c
new file mode 100644
index 00000000000..8cb2a5d8290
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fp.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on double
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync_double } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a double.  */
+
+extern void abort(void);
+
+double v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf.c b/gcc/testsuite/gcc.dg/atomic-op-fpf.c
new file mode 100644
index 00000000000..dfeb173eeef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on float
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync_float } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a float.  */
+
+extern void abort(void);
+
+float v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf128.c b/gcc/testsuite/gcc.dg/atomic-op-fpf128.c
new file mode 100644
index 00000000000..93962953ef0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf128.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float128
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float128 } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float128.  */
+
+extern void abort(void);
+
+_Float128 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf16.c b/gcc/testsuite/gcc.dg/atomic-op-fpf16.c
new file mode 100644
index 00000000000..3e9e2f24180
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf16.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float16
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float16 } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float16.  */
+
+extern void abort(void);
+
+_Float16 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf16b.c b/gcc/testsuite/gcc.dg/atomic-op-fpf16b.c
new file mode 100644
index 00000000000..4800bc696cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf16b.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on __bf16
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync___bf16 } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a __bf16.  */
+
+extern void abort(void);
+
+__bf16 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf32.c b/gcc/testsuite/gcc.dg/atomic-op-fpf32.c
new file mode 100644
index 00000000000..87775a6f255
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf32.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float32
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float32 } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float32.  */
+
+extern void abort(void);
+
+_Float32 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf32x.c b/gcc/testsuite/gcc.dg/atomic-op-fpf32x.c
new file mode 100644
index 00000000000..eb4e9e5bac4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf32x.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float32x
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float32x } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float32x.  */
+
+extern void abort(void);
+
+_Float32x v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf64.c b/gcc/testsuite/gcc.dg/atomic-op-fpf64.c
new file mode 100644
index 00000000000..78137fddaf2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf64.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float64
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float64 } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float64.  */
+
+extern void abort(void);
+
+_Float64 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpf64x.c b/gcc/testsuite/gcc.dg/atomic-op-fpf64x.c
new file mode 100644
index 00000000000..30c0438491e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpf64x.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on _Float64x
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync__Float64x } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float64x.  */
+
+extern void abort(void);
+
+_Float64x v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/atomic-op-fpl.c b/gcc/testsuite/gcc.dg/atomic-op-fpl.c
new file mode 100644
index 00000000000..a3f0edeeb90
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/atomic-op-fpl.c
@@ -0,0 +1,204 @@ 
+/* Test __atomic routines for existence and proper execution on long double
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+/* { dg-require-effective-target sync_long_double } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a long double.  */
+
+extern void abort(void);
+
+long double v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index d368251ef9a..f2e96e87575 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -9747,7 +9747,468 @@  proc check_effective_target_sync_char_short { } {
 	     || [check_effective_target_mips_llsc] }}]
 }
 
-# Return 1 if thread_fence does not rely on __sync_synchronize
+# proc check_effective_target_sync_<type-id> {} {
+#     set template_string {
+#         extern int printf(const char *, ...);
+#         int main () {
+#             _Static_assert (sizeof(<type>) == 1
+#                             || sizeof(<type>) == 2
+#                             || sizeof(<type>) == 4
+#                             || sizeof(<type>) == 8
+#                             || sizeof(<type>) == 16
+#                             , "<type> size not found");
+#             if (sizeof(<type>) == 1 || sizeof(<type>) == 2) {
+#                 printf("sync_char_short");
+#             } else if (sizeof(<type>) == 4) {
+#                 printf("sync_int_long");
+#             } else if (sizeof(<type>) == 8) {
+#                 printf("sync_long_long_runtime");
+#             } else if (sizeof(<type>) == 16) {
+#                 printf("sync_int_128_runtime");
+#             }
+#             return 0;
+#         }
+#     }
+#     proc atomic_<type-id>_evalcheck {template} {
+#         set tempvar [check_compile size_<type-id> executable \
+#             $template ""]
+#         # If failed to compile then the type isn't available this floating type
+#         # is certainly not atomic on this target.
+#         if { ![string match "" [lindex $tempvar 0]] } {
+#             return 0;
+#         }
+#         # Now want to run the binary and see what it prints out.
+#         set output [gcc_load "./[lindex $tempvar 1]"]
+#         remote_file build delete [lindex $tempvar 1]
+#         if { [lindex $output 0] != "pass" } {
+#             return 0;
+#         }
+#         return [check_effective_target_[lindex $output 1]]
+#     }
+#     return [check_cached_effective_target sync_<type-id> \
+#             "atomic_<type-id>_evalcheck {$template_string}"]
+# }
+
+proc check_effective_target_sync_float {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(float) == 1
+                            || sizeof(float) == 2
+                            || sizeof(float) == 4
+                            || sizeof(float) == 8
+                            || sizeof(float) == 16
+                            , "float size not found");
+            if (sizeof(float) == 1 || sizeof(float) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(float) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(float) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(float) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic_float_evalcheck {template} {
+        set tempvar [check_compile size_float executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync_float \
+            "atomic_float_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync_double {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(double) == 1
+                            || sizeof(double) == 2
+                            || sizeof(double) == 4
+                            || sizeof(double) == 8
+                            || sizeof(double) == 16
+                            , "double size not found");
+            if (sizeof(double) == 1 || sizeof(double) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(double) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(double) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(double) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic_double_evalcheck {template} {
+        set tempvar [check_compile size_double executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync_double \
+            "atomic_double_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync_long_double {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(long double) == 1
+                            || sizeof(long double) == 2
+                            || sizeof(long double) == 4
+                            || sizeof(long double) == 8
+                            || sizeof(long double) == 16
+                            , "long double size not found");
+            if (sizeof(long double) == 1 || sizeof(long double) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(long double) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(long double) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(long double) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic_long_double_evalcheck {template} {
+        set tempvar [check_compile size_long_double executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync_long_double \
+            "atomic_long_double_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync___bf16 {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(__bf16) == 1
+                            || sizeof(__bf16) == 2
+                            || sizeof(__bf16) == 4
+                            || sizeof(__bf16) == 8
+                            || sizeof(__bf16) == 16
+                            , "__bf16 size not found");
+            if (sizeof(__bf16) == 1 || sizeof(__bf16) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(__bf16) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(__bf16) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(__bf16) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic___bf16_evalcheck {template} {
+        set tempvar [check_compile size___bf16 executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync___bf16 \
+            "atomic___bf16_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float16 {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float16) == 1
+                            || sizeof(_Float16) == 2
+                            || sizeof(_Float16) == 4
+                            || sizeof(_Float16) == 8
+                            || sizeof(_Float16) == 16
+                            , "_Float16 size not found");
+            if (sizeof(_Float16) == 1 || sizeof(_Float16) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float16) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float16) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float16) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float16_evalcheck {template} {
+        set tempvar [check_compile size__Float16 executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float16 \
+            "atomic__Float16_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float32 {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float32) == 1
+                            || sizeof(_Float32) == 2
+                            || sizeof(_Float32) == 4
+                            || sizeof(_Float32) == 8
+                            || sizeof(_Float32) == 16
+                            , "_Float32 size not found");
+            if (sizeof(_Float32) == 1 || sizeof(_Float32) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float32) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float32) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float32) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float32_evalcheck {template} {
+        set tempvar [check_compile size__Float32 executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float32 \
+            "atomic__Float32_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float64 {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float64) == 1
+                            || sizeof(_Float64) == 2
+                            || sizeof(_Float64) == 4
+                            || sizeof(_Float64) == 8
+                            || sizeof(_Float64) == 16
+                            , "_Float64 size not found");
+            if (sizeof(_Float64) == 1 || sizeof(_Float64) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float64) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float64) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float64) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float64_evalcheck {template} {
+        set tempvar [check_compile size__Float64 executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float64 \
+            "atomic__Float64_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float128 {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float128) == 1
+                            || sizeof(_Float128) == 2
+                            || sizeof(_Float128) == 4
+                            || sizeof(_Float128) == 8
+                            || sizeof(_Float128) == 16
+                            , "_Float128 size not found");
+            if (sizeof(_Float128) == 1 || sizeof(_Float128) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float128) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float128) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float128) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float128_evalcheck {template} {
+        set tempvar [check_compile size__Float128 executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float128 \
+            "atomic__Float128_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float32x {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float32x) == 1
+                            || sizeof(_Float32x) == 2
+                            || sizeof(_Float32x) == 4
+                            || sizeof(_Float32x) == 8
+                            || sizeof(_Float32x) == 16
+                            , "_Float32x size not found");
+            if (sizeof(_Float32x) == 1 || sizeof(_Float32x) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float32x) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float32x) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float32x) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float32x_evalcheck {template} {
+        set tempvar [check_compile size__Float32x executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float32x \
+            "atomic__Float32x_evalcheck {$template_string}"]
+}
+
+proc check_effective_target_sync__Float64x {} {
+    set template_string {
+        extern int printf(const char *, ...);
+        int main () {
+            _Static_assert (sizeof(_Float64x) == 1
+                            || sizeof(_Float64x) == 2
+                            || sizeof(_Float64x) == 4
+                            || sizeof(_Float64x) == 8
+                            || sizeof(_Float64x) == 16
+                            , "_Float64x size not found");
+            if (sizeof(_Float64x) == 1 || sizeof(_Float64x) == 2) {
+                printf("sync_char_short");
+            } else if (sizeof(_Float64x) == 4) {
+                printf("sync_int_long");
+            } else if (sizeof(_Float64x) == 8) {
+                printf("sync_long_long_runtime");
+            } else if (sizeof(_Float64x) == 16) {
+                printf("sync_int_128_runtime");
+            }
+            return 0;
+        }
+    }
+    proc atomic__Float64x_evalcheck {template} {
+        set tempvar [check_compile size__Float64x executable \
+            $template ""]
+        # If failed to compile then the type isn't available this floating type
+        # is certainly not atomic on this target.
+        if { ![string match "" [lindex $tempvar 0]] } {
+            return 0;
+        }
+        # Now want to run the binary and see what it prints out.
+        set output [gcc_load "./[lindex $tempvar 1]"]
+        remote_file build delete [lindex $tempvar 1]
+        if { [lindex $output 0] != "pass" } {
+            return 0;
+        }
+        return [check_effective_target_[lindex $output 1]]
+    }
+    return [check_cached_effective_target sync__Float64x \
+            "atomic__Float64x_evalcheck {$template_string}"]
+}
+
 # library function
 
 proc check_effective_target_thread_fence {} {
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fp.c b/libatomic/testsuite/libatomic.c/atomic-op-fp.c
new file mode 100644
index 00000000000..70ebb2767d0
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fp.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on double
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a double.  */
+
+extern void abort(void);
+
+double v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf.c
new file mode 100644
index 00000000000..9a9abecbd77
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on float
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a float.  */
+
+extern void abort(void);
+
+float v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf128.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf128.c
new file mode 100644
index 00000000000..892c8cdd4ac
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf128.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float128
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float128.  */
+
+extern void abort(void);
+
+_Float128 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf16.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf16.c
new file mode 100644
index 00000000000..c88e32b18e7
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf16.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float16
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float16.  */
+
+extern void abort(void);
+
+_Float16 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf16b.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf16b.c
new file mode 100644
index 00000000000..23f026788da
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf16b.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on __bf16
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a __bf16.  */
+
+extern void abort(void);
+
+__bf16 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf32.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf32.c
new file mode 100644
index 00000000000..2987a1b5151
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf32.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float32
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float32.  */
+
+extern void abort(void);
+
+_Float32 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf32x.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf32x.c
new file mode 100644
index 00000000000..7d6adc49f16
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf32x.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float32x
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float32x.  */
+
+extern void abort(void);
+
+_Float32x v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf64.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf64.c
new file mode 100644
index 00000000000..478a78ef15c
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf64.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float64
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float64.  */
+
+extern void abort(void);
+
+_Float64 v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpf64x.c b/libatomic/testsuite/libatomic.c/atomic-op-fpf64x.c
new file mode 100644
index 00000000000..fdfaa177197
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpf64x.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on _Float64x
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a _Float64x.  */
+
+extern void abort(void);
+
+_Float64x v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}
diff --git a/libatomic/testsuite/libatomic.c/atomic-op-fpl.c b/libatomic/testsuite/libatomic.c/atomic-op-fpl.c
new file mode 100644
index 00000000000..cb9c35b44f5
--- /dev/null
+++ b/libatomic/testsuite/libatomic.c/atomic-op-fpl.c
@@ -0,0 +1,203 @@ 
+/* Test __atomic routines for existence and proper execution on long double
+   values with each valid memory model.  */
+/* { dg-do run } */
+/* { dg-additional-options "-std=c23" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a long double.  */
+
+extern void abort(void);
+
+long double v, count, res;
+
+/* The fetch_op routines return the original value before the operation.
+ * TODO N.b. I don't *believe* the checking against integral values and
+ * addition/subtraction of integral values could trigger any floating point
+ * confusion, and the testcases seem to pass, but haven't yet gotten confident
+ * that it could never happen (though I guess if we're following ieee standards
+ * then the behaviour on one architecture and at one time should match that on
+ * other architectures -- so I guess I should be fine).  */
+
+void
+test_fetch_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2)
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) 
+    abort ();
+
+  if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) 
+    abort ();
+}
+
+
+void
+test_fetch_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) !=  res--) 
+    abort ();
+
+  if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) !=  res--) 
+    abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation.  */
+
+void
+test_add_fetch ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3)
+    abort ();
+
+  if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) 
+    abort ();
+
+  if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) 
+    abort ();
+}
+
+
+void
+test_sub_fetch ()
+{
+  v = res = 20;
+  count = 0.0;
+
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) !=  --res) 
+    abort ();
+
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) !=  --res) 
+    abort ();                                                  
+                                                               
+  if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) !=  --res) 
+    abort ();
+}
+
+/* Test the OP routines with a result which isn't used. Use both variations
+   within each function.  */
+
+void
+test_add ()
+{
+  v = res = 0.0;
+  count = 1.0;
+
+  __atomic_add_fetch (&v, count, __ATOMIC_RELAXED);
+  if (v != 1)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_CONSUME);
+  if (v != 2)
+    abort ();
+
+  __atomic_add_fetch (&v, 1.0 , __ATOMIC_ACQUIRE);
+  if (v != 3)
+    abort ();
+
+  __atomic_fetch_add (&v, 1.0, __ATOMIC_RELEASE);
+  if (v != 4)
+    abort ();
+
+  __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL);
+  if (v != 5)
+    abort ();
+
+  __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST);
+  if (v != 6)
+    abort ();
+}
+
+
+void
+test_sub()
+{
+  v = res = 20;
+  count = 0.0;
+
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED);
+  if (v != --res)
+    abort ();
+
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL);
+  if (v != --res)
+    abort ();                                                  
+                                                               
+  __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST);
+  if (v != --res)
+    abort ();
+}
+
+int
+main ()
+{
+  test_fetch_add ();
+  test_fetch_sub ();
+
+  test_add_fetch ();
+  test_sub_fetch ();
+
+  test_add ();
+  test_sub ();
+
+  return 0;
+}