(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
simulate-thread/
atomic-load-int128.c
       1  /* { dg-do link } */
       2  /* { dg-require-effective-target sync_int_128_runtime } */
       3  /* { dg-options "-mcx16" { target { x86_64-*-* i?86-*-* } } } */
       4  /* { dg-final { simulate-thread } } */
       5  
       6  #include <stdio.h>
       7  #include "simulate-thread.h"
       8  
       9  
      10  /* Testing load for atomicity is a little trickier.  
      11  
      12     Set up the atomic value so that it changes value after every instruction 
      13     is executed.
      14  
      15     Simply alternating between 2 values wouldn't be sufficient since a load of
      16     one part, followed by the load of the second part 2 instructions later would
      17     appear to be valid.
      18  
      19     set up a table of 16 values which change a bit in every byte of the value 
      20     each time, this will give us a 16 instruction cycle before repetition
      21     kicks in, which should be sufficient to detect any issues.  Just to be sure,
      22     we also change the table cycle size during execution. 
      23     
      24     The end result is that all loads should always get one of the values from
      25     the table. Any other pattern means the load failed.  */
      26  
      27  __int128_t ret;
      28  __int128_t value = 0;
      29  __int128_t result = 0;
      30  __int128_t table[16] = {
      31  0x0000000000000000, 
      32  0x1111111111111111, 
      33  0x2222222222222222, 
      34  0x3333333333333333,
      35  0x4444444444444444,
      36  0x5555555555555555,
      37  0x6666666666666666,
      38  0x7777777777777777,
      39  0x8888888888888888,
      40  0x9999999999999999,
      41  0xAAAAAAAAAAAAAAAA,
      42  0xBBBBBBBBBBBBBBBB,
      43  0xCCCCCCCCCCCCCCCC,
      44  0xDDDDDDDDDDDDDDDD,
      45  0xEEEEEEEEEEEEEEEE,
      46  0xFFFFFFFFFFFFFFFF
      47  };
      48  
      49  int table_cycle_size = 16;
      50  
      51  /* Since we don't have 128 bit constants, we have to properly pad the table.  */
      52  void fill_table()
      53  {
      54    int x;
      55    for (x = 0; x < 16; x++)
      56      {
      57        ret = table[x];
      58        ret = (ret << 64) | ret;
      59        table[x] = ret;
      60      }
      61  }
      62  
      63  /* Return 0 if 'result' is a valid value to have loaded.  */
      64  int verify_result ()
      65  {
      66    int x;
      67    int found = 0;
      68  
      69    /* Check entire table for valid values.  */
      70    for (x = 0; x < 16; x++)
      71      if (result == table[x])
      72        {
      73  	found = 1;
      74  	break;
      75        }
      76  
      77    if (!found)
      78      printf("FAIL: Invalid result returned from fetch\n");
      79  
      80    return !found;
      81  }
      82  
      83  /* Iterate VALUE through the different valid values. */
      84  void simulate_thread_other_threads ()
      85  {
      86    static int current = 0;
      87  
      88    if (++current >= table_cycle_size)
      89      current = 0;
      90    value = table[current];
      91  }
      92  
      93  int simulate_thread_step_verify ()
      94  {
      95    return verify_result ();
      96  }
      97  
      98  int simulate_thread_final_verify ()
      99  {
     100    return verify_result ();
     101  }
     102  
     103  __attribute__((noinline))
     104  void simulate_thread_main()
     105  {
     106    int x;
     107  
     108    /* Execute loads with value changing at various cyclic values.  */
     109    for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--)
     110      {
     111        ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
     112        /* In order to verify the returned value (which is not atomic), it needs
     113  	 to be atomically stored into another variable and check that.  */
     114        __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
     115  
     116        /* Execute the fetch/store a couple of times just to ensure the cycles
     117           have a chance to be interesting.  */
     118        ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST);
     119        __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST);
     120      }
     121  }
     122  
     123  int
     124  main()
     125  {
     126    fill_table ();
     127  
     128    /* Make sure value starts with an atomic value from the table.  */
     129    __atomic_store_n (&value, table[0], __ATOMIC_SEQ_CST);
     130  
     131    simulate_thread_main ();
     132    simulate_thread_done ();
     133    return 0;
     134  }