summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/simulate-thread
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/gcc.dg/simulate-thread')
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c116
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c132
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c117
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c116
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c118
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c116
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c117
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c117
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c57
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c52
-rw-r--r--gcc/testsuite/gcc.dg/simulate-thread/subfields.c93
11 files changed, 1151 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c
new file mode 100644
index 00000000000..d03e8318108
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c
@@ -0,0 +1,116 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_int_long } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+
+/* Testing load for atomicity is a little trickier.
+
+ Set up the atomic value so that it changes value after every instruction
+ is executed.
+
+ Simply alternating between 2 values wouldn't be sufficient since a load of
+ one part, followed by the load of the second part 2 instructions later would
+ appear to be valid.
+
+ set up a table of 16 values which change a bit in every byte of the value
+ each time, this will give us a 16 instruction cycle before repetition
+ kicks in, which should be sufficient to detect any issues. Just to be sure,
+ we also change the table cycle size during execution.
+
+ The end result is that all loads should always get one of the values from
+ the table. Any other pattern means the load failed. */
+
+unsigned int ret;
+unsigned int value = 0;
+unsigned int result = 0;
+unsigned int table[16] = {
+0x00000000,
+0x11111111,
+0x22222222,
+0x33333333,
+0x44444444,
+0x55555555,
+0x66666666,
+0x77777777,
+0x88888888,
+0x99999999,
+0xAAAAAAAA,
+0xBBBBBBBB,
+0xCCCCCCCC,
+0xDDDDDDDD,
+0xEEEEEEEE,
+0xFFFFFFFF
+};
+
+int table_cycle_size = 16;
+
+/* Return 0 if 'result' is a valid value to have loaded. */
+int verify_result ()
+{
+ int x;
+ int found = 0;
+
+ /* Check entire table for valid values. */
+ for (x = 0; x < 16 ; x++)
+ if (result == table[x])
+ {
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ printf("FAIL: Invalid result returned from fetch\n");
+
+ return !found;
+}
+
+/* Iterate VALUE through the different valid values. */
+void simulate_thread_other_threads ()
+{
+ static int current = 0;
+
+ if (++current >= table_cycle_size)
+ current = 0;
+ value = table[current];
+}
+
+int simulate_thread_step_verify ()
+{
+ return verify_result ();
+}
+
+int simulate_thread_final_verify ()
+{
+ return verify_result ();
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ int x;
+
+ /* Execute loads with value changing at various cyclic values. */
+ for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
+ {
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ /* In order to verify the returned value (which is not atomic), it needs
+ to be atomically stored into another variable and check that. */
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+
+ /* Execute the fetch/store a couple of times just to ensure the cycles
+ have a chance to be interesting. */
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+ }
+}
+
+main()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c
new file mode 100644
index 00000000000..3ade0d6fad3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c
@@ -0,0 +1,132 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_int_128 } */
+/* { dg-options "-mcx16" { target { x86_64-*-* i?86-*-* } } } */
+/* { dg-final { simulate-thread } } */
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+
+/* Testing load for atomicity is a little trickier.
+
+ Set up the atomic value so that it changes value after every instruction
+ is executed.
+
+ Simply alternating between 2 values wouldn't be sufficient since a load of
+ one part, followed by the load of the second part 2 instructions later would
+ appear to be valid.
+
+ set up a table of 16 values which change a bit in every byte of the value
+ each time, this will give us a 16 instruction cycle before repetition
+ kicks in, which should be sufficient to detect any issues. Just to be sure,
+ we also change the table cycle size during execution.
+
+ The end result is that all loads should always get one of the values from
+ the table. Any other pattern means the load failed. */
+
+__int128_t ret;
+__int128_t value = 0;
+__int128_t result = 0;
+__int128_t table[16] = {
+0x0000000000000000,
+0x1111111111111111,
+0x2222222222222222,
+0x3333333333333333,
+0x4444444444444444,
+0x5555555555555555,
+0x6666666666666666,
+0x7777777777777777,
+0x8888888888888888,
+0x9999999999999999,
+0xAAAAAAAAAAAAAAAA,
+0xBBBBBBBBBBBBBBBB,
+0xCCCCCCCCCCCCCCCC,
+0xDDDDDDDDDDDDDDDD,
+0xEEEEEEEEEEEEEEEE,
+0xFFFFFFFFFFFFFFFF
+};
+
+int table_cycle_size = 16;
+
+/* Since we don't have 128 bit constants, we have to properly pad the table. */
+void fill_table()
+{
+ int x;
+ for (x = 0; x < 16; x++)
+ {
+ ret = table[x];
+ ret = (ret << 64) | ret;
+ table[x] = ret;
+ }
+}
+
+/* Return 0 if 'result' is a valid value to have loaded. */
+int verify_result ()
+{
+ int x;
+ int found = 0;
+
+ /* Check entire table for valid values. */
+ for (x = 0; x < 16; x++)
+ if (result == table[x])
+ {
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ printf("FAIL: Invalid result returned from fetch\n");
+
+ return !found;
+}
+
+/* Iterate VALUE through the different valid values. */
+void simulate_thread_other_threads ()
+{
+ static int current = 0;
+
+ if (++current >= table_cycle_size)
+ current = 0;
+ value = table[current];
+}
+
+int simulate_thread_step_verify ()
+{
+ return verify_result ();
+}
+
+int simulate_thread_final_verify ()
+{
+ return verify_result ();
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ int x;
+
+ /* Make sure value starts with an atomic value now. */
+ __atomic_store_n (&value, ret, __ATOMIC_SEQ_CST);
+
+ /* Execute loads with value changing at various cyclic values. */
+ for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
+ {
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ /* In order to verify the returned value (which is not atomic), it needs
+ to be atomically stored into another variable and check that. */
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+
+ /* Execute the fetch/store a couple of times just to ensure the cycles
+ have a chance to be interesting. */
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+ }
+}
+
+main()
+{
+ fill_table ();
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c
new file mode 100644
index 00000000000..8bc2eaace65
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c
@@ -0,0 +1,117 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_long_long } */
+/* { dg-options "" } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+
+/* Testing load for atomicity is a little trickier.
+
+ Set up the atomic value so that it changes value after every instruction
+ is executed.
+
+ Simply alternating between 2 values wouldn't be sufficient since a load of
+ one part, followed by the load of the second part 2 instructions later would
+ appear to be valid.
+
+ set up a table of 16 values which change a bit in every byte of the value
+ each time, this will give us a 16 instruction cycle before repetition
+ kicks in, which should be sufficient to detect any issues. Just to be sure,
+ we also change the table cycle size during execution.
+
+ The end result is that all loads should always get one of the values from
+ the table. Any other pattern means the load failed. */
+
+unsigned long long ret;
+unsigned long long value = 0;
+unsigned long long result = 0;
+unsigned long long table[16] = {
+0x0000000000000000,
+0x1111111111111111,
+0x2222222222222222,
+0x3333333333333333,
+0x4444444444444444,
+0x5555555555555555,
+0x6666666666666666,
+0x7777777777777777,
+0x8888888888888888,
+0x9999999999999999,
+0xAAAAAAAAAAAAAAAA,
+0xBBBBBBBBBBBBBBBB,
+0xCCCCCCCCCCCCCCCC,
+0xDDDDDDDDDDDDDDDD,
+0xEEEEEEEEEEEEEEEE,
+0xFFFFFFFFFFFFFFFF
+};
+
+int table_cycle_size = 16;
+
+/* Return 0 if 'result' is a valid value to have loaded. */
+int verify_result ()
+{
+ int x;
+ int found = 0;
+
+ /* Check entire table for valid values. */
+ for (x = 0; x < 16 ; x++)
+ if (result == table[x])
+ {
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ printf("FAIL: Invalid result returned from fetch\n");
+
+ return !found;
+}
+
+/* Iterate VALUE through the different valid values. */
+void simulate_thread_other_threads ()
+{
+ static int current = 0;
+
+ if (++current >= table_cycle_size)
+ current = 0;
+ value = table[current];
+}
+
+int simulate_thread_step_verify ()
+{
+ return verify_result ();
+}
+
+int simulate_thread_final_verify ()
+{
+ return verify_result ();
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ int x;
+
+ /* Execute loads with value changing at various cyclic values. */
+ for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
+ {
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ /* In order to verify the returned value (which is not atomic), it needs
+ to be atomically stored into another variable and check that. */
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+
+ /* Execute the fetch/store a couple of times just to ensure the cycles
+ have a chance to be interesting. */
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+ }
+}
+
+main()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c
new file mode 100644
index 00000000000..e7b54c46bef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c
@@ -0,0 +1,116 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_char_short } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+
+/* Testing load for atomicity is a little trickier.
+
+ Set up the atomic value so that it changes value after every instruction
+ is executed.
+
+ Simply alternating between 2 values wouldn't be sufficient since a load of
+ one part, followed by the load of the second part 2 instructions later would
+ appear to be valid.
+
+ set up a table of 16 values which change a bit in every byte of the value
+ each time, this will give us a 16 instruction cycle before repetition
+ kicks in, which should be sufficient to detect any issues. Just to be sure,
+ we also change the table cycle size during execution.
+
+ The end result is that all loads should always get one of the values from
+ the table. Any other pattern means the load failed. */
+
+unsigned short ret;
+unsigned short value = 0;
+unsigned short result = 0;
+unsigned short table[16] = {
+0x0000,
+0x1111,
+0x2222,
+0x3333,
+0x4444,
+0x5555,
+0x6666,
+0x7777,
+0x8888,
+0x9999,
+0xAAAA,
+0xBBBB,
+0xCCCC,
+0xDDDD,
+0xEEEE,
+0xFFFF
+};
+
+int table_cycle_size = 16;
+
+/* Return 0 if 'result' is a valid value to have loaded. */
+int verify_result ()
+{
+ int x;
+ int found = 0;
+
+ /* Check entire table for valid values. */
+ for (x = 0; x < 16 ; x++)
+ if (result == table[x])
+ {
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ printf("FAIL: Invalid result returned from fetch\n");
+
+ return !found;
+}
+
+/* Iterate VALUE through the different valid values. */
+void simulate_thread_other_threads ()
+{
+ static int current = 0;
+
+ if (++current >= table_cycle_size)
+ current = 0;
+ value = table[current];
+}
+
+int simulate_thread_step_verify ()
+{
+ return verify_result ();
+}
+
+int simulate_thread_final_verify ()
+{
+ return verify_result ();
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ int x;
+
+ /* Execute loads with value changing at various cyclic values. */
+ for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
+ {
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ /* In order to verify the returned value (which is not atomic), it needs
+ to be atomically stored into another variable and check that. */
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+
+ /* Execute the fetch/store a couple of times just to ensure the cycles
+ have a chance to be interesting. */
+ ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
+ __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
+ }
+}
+
+main()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c
new file mode 100644
index 00000000000..990310c0f0e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c
@@ -0,0 +1,118 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_int_long } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* Test all the __sync routines for proper atomicity on 4 byte values. */
+
+unsigned int zero = 0;
+unsigned int max = ~0;
+
+unsigned int changing_value = 0;
+unsigned int value = 0;
+unsigned int ret;
+
+void test_abort()
+{
+ static int reported = 0;
+ if (!reported)
+ {
+ printf ("FAIL: improper execution of __sync builtin.\n");
+ reported = 1;
+ }
+}
+
+void simulate_thread_other_threads ()
+{
+}
+
+int simulate_thread_step_verify ()
+{
+ if (value != zero && value != max)
+ {
+ printf ("FAIL: invalid intermediate result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+int simulate_thread_final_verify ()
+{
+ if (value != 0)
+ {
+ printf ("FAIL: invalid final result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* All values written to 'value' alternate between 'zero' and
+ 'max'. Any other value detected by simulate_thread_step_verify()
+ between instructions would indicate that the value was only
+ partially written, and would thus fail this atomicity test.
+
+ This function tests each different __atomic routine once, with
+ the exception of the load instruction which requires special
+ testing. */
+__attribute__((noinline))
+void simulate_thread_main()
+{
+
+ ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST);
+ if (ret != zero || value != max)
+ test_abort();
+
+ __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST);
+ if (value != zero)
+ test_abort();
+
+ ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+
+ ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+}
+
+main ()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c
new file mode 100644
index 00000000000..67f84a14a00
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c
@@ -0,0 +1,116 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_int_128 } */
+/* { dg-options "-mcx16" { target { x86_64-*-* i?86-*-*] } } } */
+/* { dg-final { simulate-thread } } */
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* Test all the __sync routines for proper atomicity on 16 byte values. */
+
+__int128_t zero = 0;
+__int128_t max = ~0;
+__int128_t changing_value = 0;
+__int128_t value = 0;
+__int128_t ret;
+
+void test_abort()
+{
+ static int reported = 0;
+ if (!reported)
+ {
+ printf ("FAIL: improper execution of __sync builtin.\n");
+ reported = 1;
+ }
+}
+
+void simulate_thread_other_threads ()
+{
+}
+
+int simulate_thread_step_verify ()
+{
+ if (value != zero && value != max)
+ {
+ printf ("FAIL: invalid intermediate result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+int simulate_thread_final_verify ()
+{
+ if (value != 0)
+ {
+ printf ("FAIL: invalid final result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* All values written to 'value' alternate between 'zero' and 'max'. Any other
+ value detected by simulate_thread_step_verify() between instructions would indicate
+ that the value was only partially written, and would thus fail this
+ atomicity test.
+
+ This function tests each different __atomic routine once, with the
+ exception of the load instruction which requires special testing. */
+__attribute__((noinline))
+void simulate_thread_main()
+{
+
+ ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST);
+ if (ret != zero || value != max)
+ test_abort();
+
+ __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST);
+ if (value != zero)
+ test_abort();
+
+ ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+
+ ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+}
+
+int main()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c
new file mode 100644
index 00000000000..ac4330bd8a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c
@@ -0,0 +1,117 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_long_long } */
+/* { dg-options "" } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* Test all the __sync routines for proper atomicity on 8 byte values. */
+
+unsigned long long zero = 0;
+unsigned long long max = ~0;
+
+unsigned long long changing_value = 0;
+unsigned long long value = 0;
+unsigned long long ret;
+
+void test_abort()
+{
+ static int reported = 0;
+ if (!reported)
+ {
+ printf ("FAIL: improper execution of __sync builtin.\n");
+ reported = 1;
+ }
+}
+
+void simulate_thread_other_threads ()
+{
+}
+
+int simulate_thread_step_verify ()
+{
+ if (value != zero && value != max)
+ {
+ printf ("FAIL: invalid intermediate result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+int simulate_thread_final_verify ()
+{
+ if (value != 0)
+ {
+ printf ("FAIL: invalid final result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* All values written to 'value' alternate between 'zero' and 'max'. Any other
+ value detected by simulate_thread_step_verify() between instructions would indicate
+ that the value was only partially written, and would thus fail this
+ atomicity test.
+
+ This function tests each different __atomic routine once, with the
+ exception of the load instruction which requires special testing. */
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST);
+ if (ret != zero || value != max)
+ test_abort();
+
+ __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST);
+ if (value != zero)
+ test_abort();
+
+ ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+
+ ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+}
+
+int main ()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c
new file mode 100644
index 00000000000..d823e02fb47
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c
@@ -0,0 +1,117 @@
+/* { dg-do link } */
+/* { dg-require-effective-target sync_char_short } */
+/* { dg-final { simulate-thread } } */
+
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* Test all the __sync routines for proper atomicity on 2 byte values. */
+
+unsigned short zero = 0;
+unsigned short max = ~0;
+
+unsigned short changing_value = 0;
+unsigned short value = 0;
+unsigned short ret;
+
+void test_abort()
+{
+ static int reported = 0;
+ if (!reported)
+ {
+ printf ("FAIL: improper execution of __sync builtin.\n");
+ reported = 1;
+ }
+}
+
+void simulate_thread_other_threads ()
+{
+}
+
+int simulate_thread_step_verify ()
+{
+ if (value != zero && value != max)
+ {
+ printf ("FAIL: invalid intermediate result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+int simulate_thread_final_verify ()
+{
+ if (value != 0)
+ {
+ printf ("FAIL: invalid final result for value.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* All values written to 'value' alternate between 'zero' and
+ 'max'. Any other value detected by simulate_thread_step_verify()
+ between instructions would indicate that the value was only
+ partially written, and would thus fail this atomicity test.
+
+ This function tests each different __atomic routine once, with
+ the exception of the load instruction which requires special
+ testing. */
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST);
+ if (ret != zero || value != max)
+ test_abort();
+
+ __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST);
+ if (value != zero)
+ test_abort();
+
+ ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != zero)
+ test_abort ();
+
+ ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != max)
+ test_abort ();
+
+ ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+
+ ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != max || ret != max)
+ test_abort ();
+
+ ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST);
+ if (value != zero || ret != zero)
+ test_abort ();
+}
+
+int main ()
+{
+ simulate_thread_main ();
+ simulate_thread_done ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c b/gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c
new file mode 100644
index 00000000000..71d1cca9dda
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c
@@ -0,0 +1,57 @@
+/* { dg-do link } */
+/* { dg-options "--param allow-store-data-races=0" } */
+/* { dg-final { simulate-thread } } */
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* This file tests that speculative store movement out of a loop doesn't
+ happen. This is disallowed when --param allow-store-data-races is 0. */
+
+int global = 100;
+
+/* Other thread makes sure global is 100 before the next instruction is
+ * exceuted. */
+void simulate_thread_other_threads()
+{
+ global = 100;
+}
+
+int simulate_thread_step_verify()
+{
+ if (global != 100)
+ {
+ printf("FAIL: global variable was assigned to. \n");
+ return 1;
+ }
+}
+
+int simulate_thread_final_verify()
+{
+ return 0;
+}
+
+/* The variable global should never be assigned if func(0) is called.
+ This tests store movement out of loop thats never executed. */
+void test (int y)
+{
+ int x;
+ for (x=0; x< y; x++)
+ {
+ global = y; /* This should never speculatively execute. */
+ }
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ test(0);
+ simulate_thread_done();
+}
+
+__attribute__((noinline))
+int main()
+{
+ simulate_thread_main();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c b/gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c
new file mode 100644
index 00000000000..fdcd7f46af7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c
@@ -0,0 +1,52 @@
+/* { dg-do link } */
+/* { dg-options "--param allow-packed-store-data-races=0" } */
+/* { dg-final { simulate-thread } } */
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* This test verifies writes to globals do not write to adjacent
+ globals. This mostly happens on strict-align targets that are not
+ byte addressable (old Alphas, etc). */
+
+char a = 0;
+char b = 77;
+
+void simulate_thread_other_threads()
+{
+}
+
+int simulate_thread_step_verify()
+{
+ if (b != 77)
+ {
+ printf("FAIL: Unexpected value. <b> is %d, should be 77\n", b);
+ return 1;
+ }
+ return 0;
+}
+
+/* Verify that every variable has the correct value. */
+int simulate_thread_final_verify()
+{
+ int ret = simulate_thread_step_verify ();
+ if (a != 66)
+ {
+ printf("FAIL: Unexpected value. <a> is %d, should be 66\n", a);
+ return 1;
+ }
+ return ret;
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ a = 66;
+}
+
+int main ()
+{
+ simulate_thread_main();
+ simulate_thread_done();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/simulate-thread/subfields.c b/gcc/testsuite/gcc.dg/simulate-thread/subfields.c
new file mode 100644
index 00000000000..2d931176e7d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/simulate-thread/subfields.c
@@ -0,0 +1,93 @@
+/* { dg-do link } */
+/* { dg-options "--param allow-packed-store-data-races=0" } */
+/* { dg-final { simulate-thread } } */
+
+#include <stdio.h>
+#include "simulate-thread.h"
+
+/* This test verifies that data races aren't introduced by structure subfield
+ stores. */
+
+struct test_struct {
+ char a;
+ char b;
+ char c;
+ char d;
+} var = {0,0,0,0};
+
+
+/* This routine sets field a to 'x'. If executed properly, it will
+ not affect any of the other fields in the structure. An improper
+ implementation may load an entire word, change the 8 bits for field
+ 'a' and write the entire word back out. */
+__attribute__((noinline))
+void set_a(char x)
+{
+ var.a = x;
+}
+
+static int global = 0;
+
+/* The other thread increments the value of each of the other fields
+ in the structure every cycle. If the store to the 'a' field does
+ an incorrect full or partial word load, mask and store, it will
+ write back an incorrect value to one or more of the other
+ fields. */
+void simulate_thread_other_threads()
+{
+ global++;
+ var.b = global;
+ var.c = global;
+ var.d = global;
+}
+
+
+/* Make sure that none of the other fields have been changed. */
+int simulate_thread_step_verify()
+{
+ int ret = 0;
+ if (var.b != global)
+ {
+ printf("FAIL: Unexpected value. var.b is %d, should be %d\n",
+ var.b, global);
+ ret = 1;
+ }
+ if (var.c != global)
+ {
+ printf("FAIL: Unexpected value. var.c is %d, should be %d\n",
+ var.c, global);
+ ret = 1;
+ }
+ if (var.d != global)
+ {
+ printf("FAIL: Unexpected value. var.d is %d, should be %d\n",
+ var.d, global);
+ ret = 1;
+ }
+ return ret;
+}
+
+/* Verify that every variable has the correct value. */
+int simulate_thread_final_verify()
+{
+ int ret = simulate_thread_step_verify();
+ if (var.a != 1)
+ {
+ printf("FAIL: Unexpected value. var.a is %d, should be %d\n", var.a, 1);
+ ret = 1;
+ }
+ return ret;
+}
+
+__attribute__((noinline))
+void simulate_thread_main()
+{
+ set_a(1);
+}
+
+int main ()
+{
+ simulate_thread_main();
+ simulate_thread_done();
+ return 0;
+}