new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
@@ -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 {} {
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}