(root)/
gcc-13.2.0/
gcc/
testsuite/
jit.dg/
test-quadratic.c
       1  #include <stdlib.h>
       2  #include <stdio.h>
       3  
       4  #include "libgccjit.h"
       5  
       6  #include "harness.h"
       7  
       8  struct quadratic
       9  {
      10    double a;
      11    double b;
      12    double c;
      13    double discriminant;
      14  };
      15  
      16  /* Let's try to inject the equivalent of:
      17  
      18       extern double sqrt (double);
      19  
      20       static void
      21       calc_discriminant (struct quadratic *q)
      22       {
      23         // (b^2 - 4ac)
      24         q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
      25       }
      26  
      27       int
      28       test_quadratic (double a, double b, double c, double *r1, double *r2)
      29       {
      30         struct quadratic q;
      31         q.a = a;
      32         q.b = b;
      33         q.c = c;
      34         calc_discriminant (&q);
      35         if (q.discriminant > 0)
      36  	 {
      37  	    double s = sqrt (q.discriminant);
      38  	    *r1 = (-b + s) / (2 * a);
      39  	    *r2 = (-b - s) / (2 * a);
      40  	    return 2;
      41  	 }
      42         else if (q.discriminant == 0)
      43  	 {
      44  	    *r1 = -b / (2 * a);
      45  	    return 1;
      46  	 }
      47  	 else return 0;
      48       }
      49  */
      50  
      51  struct quadratic_test
      52  {
      53    gcc_jit_context *ctxt;
      54  
      55    /* "double" and "(double *)".  */
      56    gcc_jit_type *numeric_type;
      57    gcc_jit_type *numeric_type_ptr;
      58  
      59    /* The value (double)0.  */
      60    gcc_jit_rvalue *zero;
      61  
      62    gcc_jit_type *int_type;
      63    gcc_jit_type *void_type;
      64  
      65    /* "struct quadratic" */
      66    gcc_jit_type *quadratic;
      67    gcc_jit_field *a;
      68    gcc_jit_field *b;
      69    gcc_jit_field *c;
      70    gcc_jit_field *discriminant;
      71  
      72    /* "(struct quadratic *)" */
      73    gcc_jit_type *quadratic_ptr;
      74  
      75    gcc_jit_function *calc_discriminant;
      76  
      77    gcc_jit_function *sqrt;
      78  
      79  };
      80  
      81  static void
      82  make_types (struct quadratic_test *testcase)
      83  {
      84    testcase->numeric_type =
      85      gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
      86    testcase->numeric_type_ptr =
      87      gcc_jit_type_get_pointer (testcase->numeric_type);
      88    testcase->zero =
      89      gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
      90  
      91    testcase->int_type =
      92      gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
      93  
      94    testcase->void_type =
      95      gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
      96  
      97    testcase->a =
      98      gcc_jit_context_new_field (testcase->ctxt,
      99  			       NULL,
     100  			       testcase->numeric_type,
     101  			       "a");
     102    testcase->b =
     103      gcc_jit_context_new_field (testcase->ctxt,
     104  			       NULL,
     105  			       testcase->numeric_type,
     106  			       "b");
     107    testcase->c =
     108      gcc_jit_context_new_field (testcase->ctxt,
     109  			       NULL,
     110  			       testcase->numeric_type,
     111  			       "c");
     112    testcase->discriminant =
     113      gcc_jit_context_new_field (testcase->ctxt,
     114  			       NULL,
     115  			       testcase->numeric_type,
     116  			       "discriminant");
     117    gcc_jit_field *fields[] = {testcase->a,
     118  			     testcase->b,
     119  			     testcase->c,
     120  			     testcase->discriminant};
     121    testcase->quadratic =
     122      gcc_jit_struct_as_type (
     123        gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
     124  				       "quadratic", 4, fields));
     125    testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
     126  }
     127  
     128  static void
     129  make_sqrt (struct quadratic_test *testcase)
     130  {
     131    gcc_jit_param *param_x =
     132      gcc_jit_context_new_param (testcase->ctxt, NULL,
     133  			       testcase->numeric_type, "x");
     134    testcase->sqrt =
     135      gcc_jit_context_new_function (testcase->ctxt, NULL,
     136  				  GCC_JIT_FUNCTION_IMPORTED,
     137  				  testcase->numeric_type,
     138  				  "sqrt",
     139  				  1, &param_x,
     140  				  0);
     141  }
     142  
     143  static void
     144  make_calc_discriminant (struct quadratic_test *testcase)
     145  {
     146    /* Build "calc_discriminant".  */
     147    gcc_jit_param *param_q =
     148      gcc_jit_context_new_param (testcase->ctxt, NULL,
     149  			       testcase->quadratic_ptr, "q");
     150    testcase->calc_discriminant =
     151      gcc_jit_context_new_function (testcase->ctxt, NULL,
     152  				  GCC_JIT_FUNCTION_INTERNAL,
     153  				  testcase->void_type,
     154  				  "calc_discriminant",
     155  				  1, &param_q,
     156  				  0);
     157    gcc_jit_block *blk =
     158      gcc_jit_function_new_block (testcase->calc_discriminant, NULL);
     159    gcc_jit_block_add_comment (
     160      blk, NULL,
     161      "(b^2 - 4ac)");
     162  
     163    gcc_jit_rvalue *q_a =
     164      gcc_jit_lvalue_as_rvalue (
     165  	gcc_jit_rvalue_dereference_field (
     166  	  gcc_jit_param_as_rvalue (param_q),
     167  	  NULL, testcase->a));
     168    gcc_jit_rvalue *q_b =
     169      gcc_jit_lvalue_as_rvalue (
     170  	gcc_jit_rvalue_dereference_field (
     171  	  gcc_jit_param_as_rvalue (param_q),
     172  	  NULL, testcase->b));
     173    gcc_jit_rvalue *q_c =
     174      gcc_jit_lvalue_as_rvalue (
     175  	gcc_jit_rvalue_dereference_field (
     176  	  gcc_jit_param_as_rvalue (param_q),
     177  	  NULL, testcase->c));
     178  
     179    /* (q->b * q->b) - (4 * q->a * q->c) */
     180    gcc_jit_rvalue *rhs =
     181      gcc_jit_context_new_binary_op (
     182        testcase->ctxt, NULL,
     183        GCC_JIT_BINARY_OP_MINUS,
     184        testcase->numeric_type,
     185  
     186        /* (q->b * q->b) */
     187        gcc_jit_context_new_binary_op (
     188  	testcase->ctxt, NULL,
     189  	GCC_JIT_BINARY_OP_MULT,
     190  	testcase->numeric_type,
     191  	q_b, q_b),
     192  
     193        /* (4 * (q->a * q->c)) */
     194        gcc_jit_context_new_binary_op (
     195  	testcase->ctxt, NULL,
     196  	GCC_JIT_BINARY_OP_MULT,
     197  	testcase->numeric_type,
     198  	/* 4.0 */
     199  	gcc_jit_context_new_rvalue_from_int (
     200  	  testcase->ctxt,
     201  	  testcase->numeric_type,
     202  	  4),
     203  	/* (q->a * q->c) */
     204  	gcc_jit_context_new_binary_op (
     205  	  testcase->ctxt, NULL,
     206  	  GCC_JIT_BINARY_OP_MULT,
     207  	  testcase->numeric_type,
     208  	  q_a, q_c)));
     209  
     210    CHECK_STRING_VALUE (
     211       gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (rhs)),
     212       "q->b * q->b - (double)4 * q->a * q->c");
     213  
     214    gcc_jit_block_add_assignment (
     215      blk, NULL,
     216  
     217      /* q->discriminant =...  */
     218      gcc_jit_rvalue_dereference_field (
     219        gcc_jit_param_as_rvalue (param_q),
     220        NULL,
     221        testcase->discriminant),
     222      rhs);
     223  
     224    gcc_jit_block_end_with_void_return (blk, NULL);
     225  }
     226  
     227  static void
     228  make_test_quadratic (struct quadratic_test *testcase)
     229  {
     230    gcc_jit_param *a =
     231      gcc_jit_context_new_param (testcase->ctxt, NULL,
     232  			       testcase->numeric_type, "a");
     233    gcc_jit_param *b =
     234      gcc_jit_context_new_param (testcase->ctxt, NULL,
     235  			       testcase->numeric_type, "b");
     236    gcc_jit_param *c =
     237      gcc_jit_context_new_param (testcase->ctxt, NULL,
     238  			       testcase->numeric_type, "c");
     239    gcc_jit_param *r1 =
     240      gcc_jit_context_new_param (testcase->ctxt, NULL,
     241  			       testcase->numeric_type_ptr, "r1");
     242    gcc_jit_param *r2 =
     243      gcc_jit_context_new_param (testcase->ctxt, NULL,
     244  			       testcase->numeric_type_ptr, "r2");
     245    gcc_jit_param *params[] = {a, b, c, r1, r2};
     246    gcc_jit_function *test_quadratic =
     247      gcc_jit_context_new_function (testcase->ctxt, NULL,
     248  				  GCC_JIT_FUNCTION_EXPORTED,
     249  				  testcase->int_type,
     250  				  "test_quadratic",
     251  				  5, params,
     252  				  0);
     253    /* struct quadratic q; */
     254    gcc_jit_lvalue *q =
     255      gcc_jit_function_new_local (
     256        test_quadratic, NULL,
     257        testcase->quadratic,
     258        "q");
     259  
     260    gcc_jit_block *initial =
     261      gcc_jit_function_new_block (test_quadratic,
     262  				"initial");
     263    gcc_jit_block *on_positive_discriminant
     264      = gcc_jit_function_new_block (test_quadratic,
     265  				  "positive_discriminant");
     266  
     267    gcc_jit_block *on_nonpositive_discriminant
     268      = gcc_jit_function_new_block (test_quadratic,
     269  				  "nonpositive_discriminant");
     270  
     271    gcc_jit_block *on_zero_discriminant
     272      = gcc_jit_function_new_block (test_quadratic,
     273  				  "zero_discriminant");
     274  
     275    gcc_jit_block *on_negative_discriminant
     276      = gcc_jit_function_new_block (test_quadratic,
     277  				  "negative_discriminant");
     278  
     279    /* Initial block.  */
     280    /* q.a = a; */
     281    gcc_jit_block_add_assignment (
     282      initial, NULL,
     283      gcc_jit_lvalue_access_field (q, NULL, testcase->a),
     284      gcc_jit_param_as_rvalue (a));
     285    /* q.b = b; */
     286    gcc_jit_block_add_assignment (
     287      initial, NULL,
     288      gcc_jit_lvalue_access_field (q, NULL, testcase->b),
     289      gcc_jit_param_as_rvalue (b));
     290    /* q.c = c; */
     291    gcc_jit_block_add_assignment (
     292      initial, NULL,
     293      gcc_jit_lvalue_access_field (q, NULL, testcase->c),
     294      gcc_jit_param_as_rvalue (c));
     295    /* calc_discriminant (&q); */
     296    gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
     297    gcc_jit_block_add_eval (
     298      initial, NULL,
     299      gcc_jit_context_new_call (
     300        testcase->ctxt, NULL,
     301        testcase->calc_discriminant,
     302        1, &address_of_q));
     303  
     304    gcc_jit_block_add_comment (
     305      initial, NULL,
     306      "if (q.discriminant > 0)");
     307    gcc_jit_block_end_with_conditional (
     308      initial, NULL,
     309      gcc_jit_context_new_comparison (
     310        testcase->ctxt, NULL,
     311        GCC_JIT_COMPARISON_GT,
     312        gcc_jit_rvalue_access_field (
     313  	gcc_jit_lvalue_as_rvalue (q),
     314  	NULL,
     315  	testcase->discriminant),
     316        testcase->zero),
     317      on_positive_discriminant,
     318      on_nonpositive_discriminant);
     319  
     320    /* Block: "on_positive_discriminant" */
     321    /* double s = sqrt (q.discriminant); */
     322    gcc_jit_lvalue *s = gcc_jit_function_new_local (
     323      test_quadratic, NULL,
     324      testcase->numeric_type,
     325      "s");
     326    gcc_jit_rvalue *discriminant_of_q =
     327      gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
     328  				 NULL,
     329  				 testcase->discriminant);
     330    gcc_jit_block_add_assignment (
     331      on_positive_discriminant, NULL,
     332      s,
     333      gcc_jit_context_new_call (
     334        testcase->ctxt, NULL,
     335        testcase->sqrt,
     336        1, &discriminant_of_q));
     337  
     338    gcc_jit_rvalue *minus_b =
     339      gcc_jit_context_new_unary_op (
     340        testcase->ctxt, NULL,
     341        GCC_JIT_UNARY_OP_MINUS,
     342        testcase->numeric_type,
     343        gcc_jit_param_as_rvalue (b));
     344    gcc_jit_rvalue *two_a =
     345      gcc_jit_context_new_binary_op (
     346        testcase->ctxt, NULL,
     347        GCC_JIT_BINARY_OP_MULT,
     348        testcase->numeric_type,
     349        gcc_jit_context_new_rvalue_from_int (
     350  	testcase->ctxt,
     351  	testcase->numeric_type,
     352  	2),
     353        gcc_jit_param_as_rvalue (a));
     354  
     355    gcc_jit_block_add_comment (
     356      on_positive_discriminant, NULL,
     357      "*r1 = (-b + s) / (2 * a);");
     358    gcc_jit_block_add_assignment (
     359      on_positive_discriminant, NULL,
     360  
     361      /* "*r1 = ..." */
     362      gcc_jit_rvalue_dereference (
     363        gcc_jit_param_as_rvalue (r1), NULL),
     364  
     365      /* (-b + s) / (2 * a) */
     366      gcc_jit_context_new_binary_op (
     367        testcase->ctxt, NULL,
     368        GCC_JIT_BINARY_OP_DIVIDE,
     369        testcase->numeric_type,
     370        gcc_jit_context_new_binary_op (
     371  	testcase->ctxt, NULL,
     372  	GCC_JIT_BINARY_OP_PLUS,
     373  	testcase->numeric_type,
     374  	minus_b,
     375  	gcc_jit_lvalue_as_rvalue (s)),
     376        two_a));
     377  
     378    gcc_jit_block_add_comment (
     379      on_positive_discriminant, NULL,
     380      "*r2 = (-b - s) / (2 * a)");
     381    gcc_jit_block_add_assignment (
     382      on_positive_discriminant, NULL,
     383  
     384      /* "*r2 = ..." */
     385      gcc_jit_rvalue_dereference (
     386        gcc_jit_param_as_rvalue (r2), NULL),
     387  
     388      /* (-b - s) / (2 * a) */
     389      gcc_jit_context_new_binary_op (
     390        testcase->ctxt, NULL,
     391        GCC_JIT_BINARY_OP_DIVIDE,
     392        testcase->numeric_type,
     393        gcc_jit_context_new_binary_op (
     394  	testcase->ctxt, NULL,
     395  	GCC_JIT_BINARY_OP_MINUS,
     396  	testcase->numeric_type,
     397  	minus_b,
     398  	gcc_jit_lvalue_as_rvalue (s)),
     399        two_a));
     400  
     401    /* "return 2;" */
     402    gcc_jit_block_end_with_return (
     403      on_positive_discriminant, NULL,
     404      gcc_jit_context_new_rvalue_from_int (
     405        testcase->ctxt,
     406        testcase->int_type,
     407        2));
     408  
     409    /* Block: "on_nonpositive_discriminant" */
     410    gcc_jit_block_add_comment (
     411      on_nonpositive_discriminant, NULL,
     412      "else if (q.discriminant == 0)");
     413    gcc_jit_block_end_with_conditional (
     414      on_nonpositive_discriminant, NULL,
     415      gcc_jit_context_new_comparison (
     416        testcase->ctxt, NULL,
     417        GCC_JIT_COMPARISON_EQ,
     418        gcc_jit_rvalue_access_field (
     419  	gcc_jit_lvalue_as_rvalue (q),
     420  	NULL,
     421  	testcase->discriminant),
     422        testcase->zero),
     423      on_zero_discriminant,
     424      on_negative_discriminant);
     425  
     426    /* Block: "on_zero_discriminant" */
     427    gcc_jit_block_add_comment (
     428      on_zero_discriminant, NULL,
     429      "*r1 = -b / (2 * a);");
     430    gcc_jit_block_add_assignment (
     431      on_zero_discriminant, NULL,
     432  
     433      /* "*r1 = ..." */
     434      gcc_jit_rvalue_dereference (
     435        gcc_jit_param_as_rvalue (r1), NULL),
     436  
     437      /* -b / (2 * a) */
     438      gcc_jit_context_new_binary_op (
     439        testcase->ctxt, NULL,
     440        GCC_JIT_BINARY_OP_DIVIDE,
     441        testcase->numeric_type,
     442        minus_b,
     443        two_a));
     444    gcc_jit_block_end_with_return (
     445      /* "return 1;" */
     446      on_zero_discriminant, NULL,
     447        gcc_jit_context_one (testcase->ctxt, testcase->int_type));
     448  
     449    /* Block: "on_negative_discriminant" */
     450    gcc_jit_block_end_with_return (
     451      /* "else return 0;" */
     452      on_negative_discriminant, NULL,
     453      gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
     454  }
     455  
     456  void
     457  create_code (gcc_jit_context *ctxt, void *user_data)
     458  {
     459    struct quadratic_test testcase;
     460    memset (&testcase, 0, sizeof (testcase));
     461    testcase.ctxt = ctxt;
     462    make_types (&testcase);
     463    make_sqrt (&testcase);
     464    make_calc_discriminant (&testcase);
     465    make_test_quadratic (&testcase);
     466  }
     467  
     468  void
     469  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
     470  {
     471    typedef int (*fn_type) (double a, double b, double c,
     472  			  double *r1, double *r2);
     473  
     474    CHECK_NON_NULL (result);
     475  
     476    fn_type test_quadratic =
     477      (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
     478    CHECK_NON_NULL (test_quadratic);
     479  
     480    /* Verify that the code correctly solves quadratic equations.  */
     481    double r1, r2;
     482  
     483    /* This one has two solutions: */
     484    CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
     485    CHECK_VALUE (r1, 1);
     486    CHECK_VALUE (r2, -4);
     487  
     488    /* This one has one solution: */
     489    CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
     490    CHECK_VALUE (r1, -0.5);
     491  
     492    /* This one has no real solutions: */
     493    CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
     494  }