(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.target/
s390/
htm-builtins-2.c
       1  /* Functional tests of the htm __TM_... macros.  */
       2  
       3  /* { dg-do run } */
       4  /* { dg-require-effective-target htm } */
       5  /* { dg-options "-O3 -march=zEC12 -mzarch" } */
       6  
       7  /* ---------------------------- included header files ---------------------- */
       8  
       9  #include <stdio.h>
      10  #include <string.h>
      11  #include <inttypes.h>
      12  #include <htmxlintrin.h>
      13  
      14  /* ---------------------------- local definitions -------------------------- */
      15  
      16  #define DEFAULT_MAX_REPETITIONS 7
      17  #define DEFAULT_REQUIRED_QUORUM 4
      18  #define DEFAULT_ABORT_ADDRESS (0x12345678u)
      19  
      20  /* ---------------------------- local macros ------------------------------- */
      21  
      22  #define TEST_DF_REP(name) \
      23    { #name, name, DEFAULT_MAX_REPETITIONS, DEFAULT_REQUIRED_QUORUM }
      24  #define TEST_NO_REP(name) { #name, name, 1, 1 }
      25  
      26  /* ---------------------------- local types -------------------------------- */
      27  
      28  typedef int (*test_func_t)(void);
      29  
      30  typedef struct
      31  {
      32    const char *name;
      33    test_func_t test_func;
      34    int max_repetitions;
      35    int required_quorum;
      36  } test_table_entry_t;
      37  
      38  typedef enum
      39  {
      40    ABORT_T_SYSTEM = 0,
      41    ABORT_T_USER = 1,
      42  } abort_user_t;
      43  
      44  typedef enum
      45  {
      46    ABORT_T_NONE = 0,
      47    ABORT_T_ILLEGAL,
      48    ABORT_T_FOOTPRINT_EXCEEDED,
      49    ABORT_T_NESTED_TOO_DEEP,
      50    ABORT_T_CONFLICT,
      51  
      52    ABORT_T_INVALID_ABORT_CODE
      53  } abort_t;
      54  
      55  /* ---------------------------- local variables ---------------------------- */
      56  
      57  __attribute__ ((aligned(256))) static struct __htm_tdb local_tdb256;
      58  static struct __htm_tdb local_tdb;
      59  
      60  static abort_t const abort_classes[] =
      61  {
      62    ABORT_T_INVALID_ABORT_CODE,
      63    ABORT_T_NONE,
      64    ABORT_T_NONE,
      65    ABORT_T_NONE,
      66  
      67    ABORT_T_ILLEGAL,
      68    ABORT_T_NONE,
      69    ABORT_T_NONE,
      70    ABORT_T_FOOTPRINT_EXCEEDED,
      71  
      72    ABORT_T_FOOTPRINT_EXCEEDED,
      73    ABORT_T_CONFLICT,
      74    ABORT_T_CONFLICT,
      75    ABORT_T_ILLEGAL,
      76  
      77    ABORT_T_NONE,
      78    ABORT_T_NESTED_TOO_DEEP,
      79    ABORT_T_NONE,
      80    ABORT_T_NONE,
      81  
      82    ABORT_T_NONE
      83  };
      84  
      85  static size_t num_abort_classes = sizeof(abort_classes) / sizeof(abort_t);
      86  
      87  /* ---------------------------- exported variables (globals) --------------- */
      88  
      89  int global_int = 0;
      90  uint64_t global_u64 = 0;
      91  float global_float_1 = 1.0;
      92  float global_float_2 = 2.5;
      93  float global_float_3 = 0.0;
      94  __attribute__ ((aligned(256))) struct
      95  {
      96    volatile uint64_t c1;
      97    volatile uint64_t c2;
      98    volatile uint64_t c3;
      99  } counters = { 0, 0, 0 };
     100  
     101  /* ---------------------------- local helper functions --------------------- */
     102  
     103  static void dump_tdb(struct __htm_tdb *tdb)
     104  {
     105    unsigned char *p;
     106    int i;
     107    int j;
     108  
     109    p = (unsigned char *)tdb;
     110    for (i = 0; i < 16; i++)
     111      {
     112        fprintf(stderr, "0x%02x  ", i * 16);
     113        for (j = 0; j < 16; j++)
     114  	{
     115  	  fprintf(stderr, "%02x", (int)p[i * 16 + j]);
     116  	  if (j < 15)
     117  	    {
     118  	      fprintf(stderr, " ");
     119  	    }
     120  	  if (j == 7)
     121  	    {
     122  	      fprintf(stderr, " ");
     123  	    }
     124  	}
     125        fprintf(stderr, "\n");
     126      }
     127  
     128    return;
     129  }
     130  
     131  static void make_fake_tdb(struct __htm_tdb *tdb)
     132  {
     133    memset(tdb, 0, sizeof(*tdb));
     134    tdb->format = 1;
     135    tdb->nesting_depth = 1;
     136    tdb->atia = DEFAULT_ABORT_ADDRESS;
     137    tdb->abort_code = 11;
     138  
     139    return;
     140  }
     141  
     142  static int check_abort_code_in_tdb(struct __htm_tdb *tdb, uint64_t abort_code)
     143  {
     144    long expect_rc;
     145    long rc;
     146  
     147    if (abort_code != 0)
     148      {
     149        long addr;
     150  
     151        addr = __TM_failure_address(&local_tdb);
     152        if (addr != DEFAULT_ABORT_ADDRESS)
     153  	{
     154  	  return 11;
     155  	}
     156      }
     157    {
     158      long long tdb_abort_code;
     159  
     160      tdb_abort_code = __TM_failure_code(tdb);
     161      if ((uint64_t)tdb_abort_code != abort_code)
     162        {
     163  	fprintf(
     164  		stderr, "tm_ac %" PRIu64 ", ac %" PRIu64
     165  		", tdb_ac %" PRIu64 "\n",
     166  		(uint64_t)tdb_abort_code, abort_code,
     167  		(uint64_t)tdb->abort_code);
     168  	return 10;
     169        }
     170    }
     171    expect_rc = (abort_code >= 256) ? 1 : 0;
     172    rc = __TM_is_user_abort(tdb);
     173    if (rc != expect_rc)
     174      {
     175        fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
     176        return 1;
     177      }
     178    {
     179      unsigned char code;
     180  
     181      code = 0xffu;
     182      rc = __TM_is_named_user_abort(tdb, &code);
     183      if (rc != expect_rc)
     184        {
     185  	fprintf(
     186  		stderr, "rc %ld, expect_rc %ld\n", rc,
     187  		expect_rc);
     188  	return 2;
     189        }
     190      if (expect_rc == 1 && code != abort_code - 256)
     191        {
     192  	return 3;
     193        }
     194    }
     195    if (abort_code > (uint64_t)num_abort_classes)
     196      {
     197        abort_code = (uint64_t)num_abort_classes;
     198      }
     199    expect_rc = (abort_classes[abort_code] == ABORT_T_ILLEGAL) ? 1 : 0;
     200    rc = __TM_is_illegal(tdb);
     201    if (rc != expect_rc)
     202      {
     203        dump_tdb(tdb);
     204        fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
     205        return 4;
     206      }
     207    expect_rc =
     208      (abort_classes[abort_code] == ABORT_T_FOOTPRINT_EXCEEDED) ?
     209      1 : 0;
     210    rc = __TM_is_footprint_exceeded(tdb);
     211    if (rc != expect_rc)
     212      {
     213        dump_tdb(tdb);
     214        fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
     215        return 5;
     216      }
     217    expect_rc =
     218      (abort_classes[abort_code] == ABORT_T_NESTED_TOO_DEEP) ? 1 : 0;
     219    rc = __TM_is_nested_too_deep(tdb);
     220    if (rc != expect_rc)
     221      {
     222        dump_tdb(tdb);
     223        fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
     224        return 6;
     225      }
     226    expect_rc = (abort_classes[abort_code] == ABORT_T_CONFLICT) ? 1 : 0;
     227    rc = __TM_is_conflict(tdb);
     228    if (rc != expect_rc)
     229      {
     230        dump_tdb(tdb);
     231        fprintf(stderr, "rc %ld, expect_rc %ld\n", rc, expect_rc);
     232        return 7;
     233      }
     234  
     235    return 0;
     236  }
     237  
     238  /* ---------------------------- local test functions ----------------------- */
     239  
     240  /* Not a test; make sure that the involved global cachelines are reserved for
     241   * writing.  */
     242  static int init_cache(void)
     243  {
     244    make_fake_tdb(&local_tdb);
     245    make_fake_tdb(&local_tdb256);
     246    global_int = 0;
     247    global_u64 = 0;
     248    global_float_1 = 1.0;
     249    global_float_2 = 2.5;
     250    global_float_3 = 0.0;
     251    counters.c1 = 0;
     252    counters.c2 = 0;
     253    counters.c3 = 0;
     254  
     255    return 0;
     256  }
     257  
     258  static int test_abort_classification(void)
     259  {
     260    int i;
     261  
     262    make_fake_tdb(&local_tdb);
     263    for (i = 0; i <= 256; i++)
     264      {
     265        int rc;
     266  
     267        local_tdb.abort_code = (uint64_t)i;
     268        rc = check_abort_code_in_tdb(&local_tdb, (uint64_t)i);
     269        if (rc != 0)
     270  	{
     271  	  return 100 * i + rc;
     272  	}
     273      }
     274  
     275    return 0;
     276  }
     277  
     278  static int test_cc_classification(void)
     279  {
     280    long rc;
     281  
     282    rc = __TM_is_failure_persistent(0);
     283    if (rc != 0)
     284      {
     285        return 1;
     286      }
     287    rc = __TM_is_failure_persistent(1);
     288    if (rc != 0)
     289      {
     290        return 2;
     291      }
     292    rc = __TM_is_failure_persistent(2);
     293    if (rc != 0)
     294      {
     295        return 3;
     296      }
     297    rc = __TM_is_failure_persistent(3);
     298    if (rc != 1)
     299      {
     300        return 4;
     301      }
     302  
     303    return 0;
     304  }
     305  
     306  static int test_tbegin_ntstg_tend(void)
     307  {
     308    long rc;
     309  
     310    counters.c1 = 0;
     311    counters.c2 = 0;
     312    if ((rc = __TM_simple_begin()) == 0)
     313      {
     314        __TM_non_transactional_store((uint64_t *)&counters.c1, 1);
     315        counters.c2 = 2;
     316        rc = __TM_end();
     317        if (rc != 0)
     318  	{
     319  	  return 100 * rc + 5;
     320  	}
     321        if (counters.c1 != 1)
     322  	{
     323  	  return 100 * counters.c1 + 2;
     324  	}
     325        if (counters.c2 != 2)
     326  	{
     327  	  return 100 * counters.c2 + 3;
     328  	}
     329      }
     330    else
     331      {
     332        return 100 * rc + 4;
     333      }
     334  
     335    return 0;
     336  }
     337  
     338  static int test_tbegin_ntstg_tabort(void)
     339  {
     340    register float f;
     341  
     342    counters.c1 = 0;
     343    counters.c2 = 0;
     344    f = 0;
     345    if (__TM_simple_begin() == 0)
     346      {
     347        __TM_non_transactional_store((uint64_t *)&counters.c1, 1);
     348        counters.c2 = 2;
     349        f = 1;
     350        __TM_named_abort(0);
     351        return 1;
     352      }
     353    if (counters.c1 != 1)
     354      {
     355        return 100 * counters.c1 + 2;
     356      }
     357    if (counters.c2 != 0)
     358      {
     359        return 100 * counters.c2 + 3;
     360      }
     361    if (f != 0)
     362      {
     363        return 100 * f + 4;
     364      }
     365  
     366    return 0;
     367  }
     368  
     369  static int test_tbegin_aborts(void)
     370  {
     371    float f;
     372    long rc;
     373  
     374    f = 77;
     375    if ((rc = __TM_simple_begin()) == 0)
     376      {
     377        f = 88;
     378        __TM_abort();
     379        return 2;
     380      }
     381    else if (rc != 2)
     382      {
     383        return 3;
     384      }
     385    if (f != 77)
     386      {
     387        return 4;
     388      }
     389    f = 66;
     390    if ((rc = __TM_simple_begin()) == 0)
     391      {
     392        f = 99;
     393        __TM_named_abort(3);
     394        return 5;
     395      }
     396    else if (rc != 3)
     397      {
     398        return 100 * rc + 6;
     399      }
     400    if (f != 66)
     401      {
     402        return 100 * f + 7;
     403      }
     404    if ((rc = __TM_simple_begin()) == 0)
     405      {
     406        global_float_3 = global_float_1 + global_float_2;
     407        rc = __TM_end();
     408        if (rc != 0)
     409  	{
     410  	  return 100 * rc + 8;
     411  	}
     412      }
     413    else
     414      {
     415        return 100 * rc + 9;
     416      }
     417    if (global_float_3 != global_float_1 + global_float_2)
     418      {
     419        return 100 * rc + 10;
     420      }
     421  
     422    return 0;
     423  }
     424  
     425  static int test_tbegin_tdb(void)
     426  {
     427    long rc;
     428  
     429    local_tdb.format = 0;
     430    if ((rc = __TM_begin(&local_tdb)) == 0)
     431      {
     432        rc = __TM_end();
     433        if (rc != 0)
     434  	{
     435  	  return 100 * rc + 1;
     436  	}
     437        if (local_tdb.format != 0)
     438  	{
     439  	  dump_tdb(&local_tdb);
     440  	  return 100 * local_tdb.format + 2;
     441  	}
     442      }
     443    else
     444      {
     445        return 100 * rc + 3;
     446      }
     447    local_tdb.format = 0;
     448    if ((rc = __TM_begin(&local_tdb)) == 0)
     449      {
     450        __TM_named_abort(1);
     451        return 4;
     452      }
     453    else
     454      {
     455        if (rc != 3)
     456  	{
     457  	  return 100 * rc + 5;
     458  	}
     459        if (local_tdb.format != 1)
     460  	{
     461  	  dump_tdb(&local_tdb);
     462  	  return 100 * local_tdb.format + 6;
     463  	}
     464      }
     465    local_tdb256.format = 0;
     466    if ((rc = __TM_begin(&local_tdb256)) == 0)
     467      {
     468        rc = __TM_end();
     469        if (rc != 0)
     470  	{
     471  	  return 1100 * rc + 1;
     472  	}
     473        if (local_tdb256.format != 0)
     474  	{
     475  	  dump_tdb(&local_tdb256);
     476  	  return 1100 * local_tdb256.format + 2;
     477  	}
     478      }
     479    else
     480      {
     481        return 1100 * rc + 3;
     482      }
     483  #if 1 /*!!!does not work*/
     484    local_tdb256.format = 0;
     485    if ((rc = __TM_begin(&local_tdb256)) == 0)
     486      {
     487        __TM_named_abort(1);
     488        return 2004;
     489      }
     490    else
     491      {
     492        if (rc != 3)
     493  	{
     494  	  return 2100 * rc + 5;
     495  	}
     496        if (local_tdb256.format != 1)
     497  	{
     498  	  dump_tdb(&local_tdb256);
     499  	  return 2100 * local_tdb256.format + 6;
     500  	}
     501      }
     502  #endif
     503  
     504    return 0;
     505  }
     506  
     507  static int test_etnd(void)
     508  {
     509    long rc;
     510  
     511    {
     512      long nd;
     513  
     514      make_fake_tdb(&local_tdb);
     515      local_tdb.nesting_depth = 0;
     516      nd = __TM_nesting_depth(&local_tdb);
     517      if (nd != 0)
     518        {
     519  	return 1;
     520        }
     521      local_tdb.nesting_depth = 7;
     522      nd = __TM_nesting_depth(&local_tdb);
     523      if (nd != 7)
     524        {
     525  	return 7;
     526        }
     527      local_tdb.format = 0;
     528      nd = __TM_nesting_depth(&local_tdb);
     529      if (nd != 0)
     530        {
     531  	return 2;
     532        }
     533    }
     534    counters.c1 = 0;
     535    counters.c1 = 0;
     536    counters.c2 = 0;
     537    counters.c3 = 0;
     538    if ((rc = __TM_simple_begin()) == 0)
     539      {
     540        counters.c1 = __TM_nesting_depth(0);
     541        if (__TM_simple_begin() == 0)
     542  	{
     543  	  counters.c2 = __TM_nesting_depth(0);
     544  	  if (__TM_simple_begin() == 0)
     545  	    {
     546  	      counters.c3 = __TM_nesting_depth(0);
     547  	      __TM_end();
     548  	    }
     549  	  __TM_end();
     550  	}
     551        __TM_end();
     552      }
     553    else
     554      {
     555        return 100 * rc + 1;
     556      }
     557    if (counters.c1 != 1)
     558      {
     559        return 100 * counters.c1 + 2;
     560      }
     561    if (counters.c2 != 2)
     562      {
     563        return 100 * counters.c2 + 3;
     564      }
     565    if (counters.c3 != 3)
     566      {
     567        return 100 * counters.c3 + 4;
     568      }
     569  
     570    return 0;
     571  }
     572  
     573  /* ---------------------------- local testing framework functions ---------- */
     574  
     575  static int run_one_test(const test_table_entry_t *test_entry)
     576  {
     577    int do_print_passes;
     578    int succeeded;
     579    int rc;
     580    int i;
     581  
     582    do_print_passes = (
     583  		     test_entry->required_quorum != 1 ||
     584  		     test_entry->max_repetitions != 1);
     585    printf("RRR RUN  %s\n", test_entry->name);
     586    if (do_print_passes == 1)
     587      {
     588        printf(
     589  	     "         (requires %d successful out of %d runs)\n",
     590  	     test_entry->required_quorum,
     591  	     test_entry->max_repetitions);
     592      }
     593    succeeded = 0;
     594    rc = 0;
     595    for (rc = 0, i = 0; i < test_entry->max_repetitions; i++)
     596      {
     597        if (do_print_passes == 1)
     598  	{
     599  	  if (i == 0)
     600  	    {
     601  	      printf("        ");
     602  	    }
     603  	  else
     604  	    {
     605  	      printf(",");
     606  	    }
     607  	}
     608        rc = test_entry->test_func();
     609        if (rc == 0)
     610  	{
     611  	  if (do_print_passes == 1)
     612  	    {
     613  	      printf(" success");
     614  	    }
     615  	  succeeded++;
     616  	  if (succeeded >= test_entry->required_quorum)
     617  	    {
     618  	      break;
     619  	    }
     620  	}
     621        else
     622  	{
     623  	  printf(" failed (rc = %d)", rc);
     624  	}
     625      }
     626    if (do_print_passes == 1 || rc != 0)
     627      {
     628        printf("\n");
     629      }
     630    if (succeeded >= test_entry->required_quorum)
     631      {
     632        printf("+++ OK   %s\n", test_entry->name);
     633  
     634        return 0;
     635      }
     636    else
     637      {
     638        printf("--- FAIL %s\n", test_entry->name);
     639  
     640        return (rc != 0) ? rc : -1;
     641      }
     642  }
     643  
     644  static int run_all_tests(const test_table_entry_t *test_table)
     645  {
     646    const test_table_entry_t *test;
     647    int rc;
     648  
     649    for (
     650         rc = 0, test = &test_table[0];
     651         test->test_func != NULL && rc == 0; test++)
     652      {
     653        rc = run_one_test(test);
     654      }
     655  
     656    return rc;
     657  }
     658  
     659  /* ---------------------------- interface functions ------------------------ */
     660  
     661  int main(void)
     662  {
     663    const test_table_entry_t test_table[] = {
     664      TEST_NO_REP(init_cache),
     665      TEST_NO_REP(test_abort_classification),
     666      TEST_NO_REP(test_cc_classification),
     667      TEST_DF_REP(test_tbegin_ntstg_tend),
     668      TEST_DF_REP(test_tbegin_ntstg_tabort),
     669      TEST_DF_REP(test_tbegin_aborts),
     670      TEST_DF_REP(test_tbegin_tdb),
     671      TEST_DF_REP(test_etnd),
     672      { (void *)0, 0, 0 }
     673    };
     674  
     675    {
     676      int rc;
     677  
     678      rc = run_all_tests(test_table);
     679  
     680      return rc;
     681    }
     682  }