(root)/
gcc-13.2.0/
gcc/
testsuite/
jit.dg/
harness.h
       1  /*
       2    Code shared between multiple testcases.
       3  
       4    This file contains "main" and support code.
       5    Each testcase should implement the following hooks:
       6  
       7      extern void
       8      create_code (gcc_jit_context *ctxt, void * user_data);
       9  
      10    and, #ifndef TEST_COMPILING_TO_FILE,
      11  
      12      extern void
      13      verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
      14   */
      15  #include <stdlib.h>
      16  #include <stdio.h>
      17  #include <unistd.h>
      18  
      19  /* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
      20     shared "buffer", and the counts of passed/failed etc are globals.
      21  
      22     The solution is to use macros to rename "pass" and "fail", replacing them
      23     with mutex-guarded alternatives.  */
      24  #ifdef MAKE_DEJAGNU_H_THREADSAFE
      25  #define pass dejagnu_pass
      26  #define fail dejagnu_fail
      27  #define note dejagnu_note
      28  #endif
      29  
      30  #include "jit-dejagnu.h"
      31  
      32  #ifdef MAKE_DEJAGNU_H_THREADSAFE
      33  #undef pass
      34  #undef fail
      35  #undef note
      36  #endif
      37  
      38  static char test[1024];
      39  
      40  #define CHECK_NON_NULL(PTR) \
      41    do {                                       \
      42      if ((PTR) != NULL)                       \
      43        {                                      \
      44  	pass ("%s: %s: %s is non-null",	     \
      45  	      test, __func__, #PTR);	     \
      46        }                                      \
      47      else                                     \
      48        {                                      \
      49  	fail ("%s: %s: %s is NULL",	     \
      50  	      test, __func__, #PTR);	     \
      51  	abort ();                            \
      52      }                                        \
      53    } while (0)
      54  
      55  #define CHECK_VALUE(ACTUAL, EXPECTED) \
      56    do {                                       \
      57      if ((ACTUAL) == (EXPECTED))              \
      58        {                                      \
      59  	pass ("%s: %s: actual: %s == expected: %s", \
      60  	      test, __func__, #ACTUAL, #EXPECTED);  \
      61        }                                      \
      62      else                                     \
      63        {                                        \
      64  	fail ("%s: %s: actual: %s != expected: %s", \
      65  	      test, __func__, #ACTUAL, #EXPECTED);  \
      66  	fprintf (stderr, "incorrect value\n"); \
      67  	abort ();                              \
      68      }                                        \
      69    } while (0)
      70  
      71  #define CHECK_VECTOR_VALUE(LEN, ACTUAL, EXPECTED) \
      72    do {                                       \
      73      for (int __check_vector_it = 0; __check_vector_it < LEN; ++__check_vector_it) { \
      74        if ((ACTUAL)[__check_vector_it] != (EXPECTED)[__check_vector_it]) { \
      75            fail ("%s: %s: actual: %s != expected: %s (position %d)", \
      76                test, __func__, #ACTUAL, #EXPECTED, __check_vector_it);  \
      77          fprintf (stderr, "incorrect value\n"); \
      78          abort ();                              \
      79        } \
      80      } \
      81    pass ("%s: %s: actual: %s == expected: %s", \
      82          test, __func__, #ACTUAL, #EXPECTED);  \
      83    } while (0)
      84  
      85  
      86  #define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
      87    do {                                       \
      88      double expected = (EXPECTED);	     \
      89      double actual = (ACTUAL);		     \
      90      if (abs (actual - expected) < 0.00001)   \
      91        {                                      \
      92  	pass ("%s: %s: actual: %s == expected: %s", \
      93  	      __func__, test, #ACTUAL, #EXPECTED);  \
      94        }                                      \
      95      else                                     \
      96        {                                      \
      97  	fail ("%s: %s: actual: %s != expected: %s", \
      98  	      __func__, test, #ACTUAL, #EXPECTED);	   \
      99  	fprintf (stderr, "incorrect value: %f\n", actual); \
     100  	abort ();                            \
     101      }                                        \
     102    } while (0)
     103  
     104  #define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
     105    check_string_value (__func__, (ACTUAL), (EXPECTED));
     106  
     107  #define CHECK_STRING_STARTS_WITH(ACTUAL, EXPECTED_PREFIX) \
     108    check_string_starts_with (__func__, (ACTUAL), (EXPECTED_PREFIX));
     109  
     110  #define CHECK_STRING_CONTAINS(ACTUAL, EXPECTED_SUBSTRING) \
     111    check_string_contains (__func__, #ACTUAL, (ACTUAL), (EXPECTED_SUBSTRING));
     112  
     113  #define CHECK(COND) \
     114    do {					\
     115      if (COND)				\
     116        {				\
     117  	pass ("%s: %s: %s", test, __func__, #COND);	\
     118        }				\
     119      else				\
     120        {				\
     121  	fail ("%s: %s: %s", test, __func__, #COND);	\
     122  	abort ();			\
     123        }				\
     124    } while (0)
     125  
     126  #define CHECK_NO_ERRORS(CTXT) \
     127    do { \
     128      const char *err = gcc_jit_context_get_first_error (CTXT); \
     129      if (err) \
     130        fail ("%s: %s: error unexpectedly occurred: %s", test, __func__, err); \
     131      else \
     132        pass ("%s: %s: no errors occurred", test, __func__); \
     133    } while (0)
     134  
     135  /* Hooks that testcases should provide.  */
     136  extern void
     137  create_code (gcc_jit_context *ctxt, void * user_data);
     138  
     139  #ifndef TEST_COMPILING_TO_FILE
     140  extern void
     141  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
     142  #endif
     143  
     144  extern void check_string_value (const char *funcname,
     145  				const char *actual, const char *expected);
     146  
     147  extern void
     148  check_string_starts_with (const char *funcname,
     149  			  const char *actual,
     150  			  const char *expected_prefix);
     151  
     152  extern void
     153  check_string_contains (const char *funcname,
     154  		       const char *name,
     155  		       const char *actual,
     156  		       const char *expected_substring);
     157  
     158  /* Implement framework needed for turning the testcase hooks into an
     159     executable.  test-combination.c and test-threads.c each combine multiple
     160     testcases into larger testcases, so we have COMBINED_TEST as a way of
     161     temporarily turning off this part of harness.h.  */
     162  #ifndef COMBINED_TEST
     163  
     164  void check_string_value (const char *funcname,
     165  			 const char *actual, const char *expected)
     166  {
     167    if (actual && !expected)
     168      {
     169        fail ("%s: %s: actual: \"%s\" != expected: NULL",
     170  	    funcname, test, actual);
     171  	fprintf (stderr, "incorrect value\n");
     172  	abort ();
     173      }
     174      if (expected && !actual)
     175        {
     176  	fail ("%s: %s: actual: NULL != expected: \"%s\"",
     177  	      funcname, test, expected);
     178  	fprintf (stderr, "incorrect value\n");
     179  	abort ();
     180        }
     181      if (actual && expected)
     182        {
     183  	if (strcmp (actual, expected))
     184  	  {
     185  	    fail ("%s: %s: actual: \"%s\" != expected: \"%s\"",
     186  		  test, funcname, actual, expected);
     187  	    fprintf (stderr, "incorrect valuen");
     188  	    abort ();
     189  	  }
     190  	pass ("%s: %s: actual: \"%s\" == expected: \"%s\"",
     191  	      test, funcname, actual, expected);
     192        }
     193      else
     194        pass ("%s: actual: NULL == expected: NULL");
     195  }
     196  
     197  void
     198  check_string_starts_with (const char *funcname,
     199  			  const char *actual,
     200  			  const char *expected_prefix)
     201  {
     202    if (!actual)
     203      {
     204        fail ("%s: %s: actual: NULL != expected prefix: \"%s\"",
     205  	    test, funcname, expected_prefix);
     206        fprintf (stderr, "incorrect value\n");
     207        abort ();
     208      }
     209  
     210    if (strncmp (actual, expected_prefix, strlen (expected_prefix)))
     211      {
     212        fail ("%s: %s: actual: \"%s\" did not begin with expected prefix: \"%s\"",
     213  	    test, funcname, actual, expected_prefix);
     214        fprintf (stderr, "incorrect value\n");
     215        abort ();
     216      }
     217  
     218    pass ("%s: actual: \"%s\" begins with expected prefix: \"%s\"",
     219  	test, actual, expected_prefix);
     220  }
     221  
     222  void
     223  check_string_contains (const char *funcname,
     224  		       const char *name,
     225  		       const char *actual,
     226  		       const char *expected_substring)
     227  {
     228    if (!actual)
     229      {
     230        fail ("%s: %s, %s: actual: NULL does not contain expected substring: \"%s\"",
     231  	    test, funcname, name, expected_substring);
     232        fprintf (stderr, "incorrect value\n");
     233        abort ();
     234      }
     235  
     236    if (!strstr (actual, expected_substring))
     237      {
     238        fail ("%s: %s: %s: actual: \"%s\" did not contain expected substring: \"%s\"",
     239  	    test, funcname, name, actual, expected_substring);
     240        fprintf (stderr, "incorrect value\n");
     241        abort ();
     242      }
     243  
     244    pass ("%s: %s: %s: found substring: \"%s\"",
     245  	test, funcname, name, expected_substring);
     246  }
     247  
     248  #ifndef TEST_ESCHEWS_SET_OPTIONS
     249  static void set_options (gcc_jit_context *ctxt, const char *argv0)
     250  {
     251    /* Set up options.  */
     252    gcc_jit_context_set_str_option (
     253      ctxt,
     254      GCC_JIT_STR_OPTION_PROGNAME,
     255      argv0);
     256    gcc_jit_context_set_int_option (
     257      ctxt,
     258      GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
     259      3);
     260    gcc_jit_context_set_bool_option (
     261      ctxt,
     262      GCC_JIT_BOOL_OPTION_DEBUGINFO,
     263      1);
     264    gcc_jit_context_set_bool_option (
     265      ctxt,
     266      GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
     267      0);
     268    gcc_jit_context_set_bool_option (
     269      ctxt,
     270      GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
     271      0);
     272    gcc_jit_context_set_bool_option (
     273      ctxt,
     274      GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
     275      1);
     276    gcc_jit_context_set_bool_option (
     277      ctxt,
     278      GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
     279      0);
     280    /* Make it easier to compare error messages by disabling colorization,
     281       rather then have them be affected by whether stderr is going to a tty.  */
     282    gcc_jit_context_add_command_line_option
     283      (ctxt, "-fdiagnostics-color=never");
     284  }
     285  #endif /* #ifndef TEST_ESCHEWS_SET_OPTIONS */
     286  
     287  /* Concatenate two strings.  The result must be released using "free".  */
     288  
     289  char *
     290  concat_strings (const char *prefix, const char *suffix)
     291  {
     292    char *result = (char *)malloc (strlen (prefix) + strlen (suffix) + 1);
     293    if (!result)
     294      {
     295        fail ("malloc failure");
     296        return NULL;
     297      }
     298    strcpy (result, prefix);
     299    strcpy (result + strlen (prefix), suffix);
     300    result[strlen (prefix) + strlen (suffix)] = '\0';
     301    return result;
     302  }
     303  
     304  #ifndef TEST_ESCHEWS_TEST_JIT
     305  /* Set up logging to a logfile of the form "test-FOO.exe.log.txt".
     306  
     307     For example,
     308       SRCDIR/gcc/testsuite/jit.dg/test-hello-world.c
     309     is built as:
     310       BUILDDIR/gcc/testsuite/jit/test-hello-world.c.exe
     311     and is logged to
     312       BUILDDIR/gcc/testsuite/jit/test-hello-world.c.exe.log.txt
     313  
     314     The logfile must be closed by the caller.
     315  
     316     Note that not every testcase enables logging.  */
     317  static FILE *
     318  set_up_logging (gcc_jit_context *ctxt, const char *argv0)
     319  {
     320    const char *logfile_name_suffix = ".log.txt";
     321    char *logfile_name = NULL;
     322    FILE *logfile = NULL;
     323  
     324    /* Build a logfile name of the form "test-FOO.exe.log.txt".  */
     325    logfile_name = concat_strings (argv0, logfile_name_suffix);
     326    if (!logfile_name)
     327      return NULL;
     328    logfile = fopen (logfile_name, "w");
     329    CHECK_NON_NULL (logfile);
     330    free (logfile_name);
     331  
     332    if (logfile)
     333      gcc_jit_context_set_logfile (ctxt, logfile, 0, 0);
     334  
     335    return logfile;
     336  }
     337  
     338  /* Exercise the API entrypoint:
     339       gcc_jit_context_dump_reproducer_to_file
     340     by calling it on the context, using the path expected by jit.exp.  */
     341  static void
     342  dump_reproducer (gcc_jit_context *ctxt, const char *argv0)
     343  {
     344    char *reproducer_name;
     345    reproducer_name = concat_strings (argv0, ".reproducer.c");
     346    if (!reproducer_name)
     347      return;
     348    note ("%s: writing reproducer to %s", test, reproducer_name);
     349    gcc_jit_context_dump_reproducer_to_file (ctxt, reproducer_name);
     350    free (reproducer_name);
     351  }
     352  
     353  /* Run one iteration of the test.  */
     354  static void
     355  test_jit (const char *argv0, void *user_data)
     356  {
     357    gcc_jit_context *ctxt;
     358    FILE *logfile;
     359  #ifndef TEST_COMPILING_TO_FILE
     360    gcc_jit_result *result;
     361  #endif
     362  
     363  #ifdef TEST_COMPILING_TO_FILE
     364    unlink (OUTPUT_FILENAME);
     365  #endif
     366  
     367    ctxt = gcc_jit_context_acquire ();
     368    if (!ctxt)
     369      {
     370        fail ("gcc_jit_context_acquire failed");
     371        return;
     372      }
     373  
     374    logfile = set_up_logging (ctxt, argv0);
     375  
     376    set_options (ctxt, argv0);
     377  
     378    create_code (ctxt, user_data);
     379  
     380    dump_reproducer (ctxt, argv0);
     381  
     382  #ifdef TEST_COMPILING_TO_FILE
     383    gcc_jit_context_compile_to_file (ctxt,
     384  				   (OUTPUT_KIND),
     385  				   (OUTPUT_FILENAME));
     386    CHECK_NO_ERRORS (ctxt);
     387  #else /* #ifdef TEST_COMPILING_TO_FILE */
     388    /* This actually calls into GCC and runs the build, all
     389       in a mutex for now.  */
     390    result = gcc_jit_context_compile (ctxt);
     391  
     392    verify_code (ctxt, result);
     393  #endif
     394  
     395    gcc_jit_context_release (ctxt);
     396  
     397  #ifndef TEST_COMPILING_TO_FILE
     398    /* Once we're done with the code, this unloads the built .so file: */
     399    gcc_jit_result_release (result);
     400  #endif
     401  
     402    if (logfile)
     403      fclose (logfile);
     404  }
     405  #endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
     406  
     407  /* We want to prefix all unit test results with the test, but dejagnu.exp's
     408     host_execute appears to get confused by the leading "./" of argv0,
     409     leading to all tests simply reporting as a single period character ".".
     410  
     411     Hence strip out the final component of the path to the program name,
     412     so that we can use that in unittest reports.  */
     413  const char*
     414  extract_progname (const char *argv0)
     415  {
     416    const char *p;
     417  
     418    p = argv0 + strlen (argv0);
     419    while (p != argv0 && p[-1] != '/')
     420      --p;
     421    return p;
     422  }
     423  
     424  #ifndef TEST_PROVIDES_MAIN
     425  int
     426  main (int argc, char **argv)
     427  {
     428    int i;
     429  
     430    for (i = 1; i <= 5; i++)
     431      {
     432        snprintf (test, sizeof (test),
     433  		"%s iteration %d of %d",
     434                  extract_progname (argv[0]),
     435                  i, 5);
     436  
     437        //printf ("ITERATION %d\n", i);
     438        test_jit (argv[0], NULL);
     439        //printf ("\n");
     440      }
     441  
     442    totals ();
     443  
     444    return 0;
     445  }
     446  #endif /* #ifndef TEST_PROVIDES_MAIN */
     447  
     448  #endif /* #ifndef COMBINED_TEST */