Viewing file: test-quadratic.c (12.64 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#include <stdlib.h> #include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
struct quadratic { double a; double b; double c; double discriminant; };
/* Let's try to inject the equivalent of:
extern double sqrt (double);
static void calc_discriminant (struct quadratic *q) { // (b^2 - 4ac) q->discriminant = (q->b * q->b) - (4 * q->a * q->c); }
int test_quadratic (double a, double b, double c, double *r1, double *r2) { struct quadratic q; q.a = a; q.b = b; q.c = c; calc_discriminant (&q); if (q.discriminant > 0) { double s = sqrt (q.discriminant); *r1 = (-b + s) / (2 * a); *r2 = (-b - s) / (2 * a); return 2; } else if (q.discriminant == 0) { *r1 = -b / (2 * a); return 1; } else return 0; } */
struct quadratic_test { gcc_jit_context *ctxt;
/* "double" and "(double *)". */ gcc_jit_type *numeric_type; gcc_jit_type *numeric_type_ptr;
/* The value (double)0. */ gcc_jit_rvalue *zero;
gcc_jit_type *int_type; gcc_jit_type *void_type;
/* "struct quadratic" */ gcc_jit_type *quadratic; gcc_jit_field *a; gcc_jit_field *b; gcc_jit_field *c; gcc_jit_field *discriminant;
/* "(struct quadratic *)" */ gcc_jit_type *quadratic_ptr;
gcc_jit_function *calc_discriminant;
gcc_jit_function *sqrt;
};
static void make_types (struct quadratic_test *testcase) { testcase->numeric_type = gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE); testcase->numeric_type_ptr = gcc_jit_type_get_pointer (testcase->numeric_type); testcase->zero = gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
testcase->int_type = gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
testcase->void_type = gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
testcase->a = gcc_jit_context_new_field (testcase->ctxt, NULL, testcase->numeric_type, "a"); testcase->b = gcc_jit_context_new_field (testcase->ctxt, NULL, testcase->numeric_type, "b"); testcase->c = gcc_jit_context_new_field (testcase->ctxt, NULL, testcase->numeric_type, "c"); testcase->discriminant = gcc_jit_context_new_field (testcase->ctxt, NULL, testcase->numeric_type, "discriminant"); gcc_jit_field *fields[] = {testcase->a, testcase->b, testcase->c, testcase->discriminant}; testcase->quadratic = gcc_jit_struct_as_type ( gcc_jit_context_new_struct_type (testcase->ctxt, NULL, "quadratic", 4, fields)); testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic); }
static void make_sqrt (struct quadratic_test *testcase) { gcc_jit_param *param_x = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type, "x"); testcase->sqrt = gcc_jit_context_new_function (testcase->ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, testcase->numeric_type, "sqrt", 1, ¶m_x, 0); }
static void make_calc_discriminant (struct quadratic_test *testcase) { /* Build "calc_discriminant". */ gcc_jit_param *param_q = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->quadratic_ptr, "q"); testcase->calc_discriminant = gcc_jit_context_new_function (testcase->ctxt, NULL, GCC_JIT_FUNCTION_INTERNAL, testcase->void_type, "calc_discriminant", 1, ¶m_q, 0); gcc_jit_block *blk = gcc_jit_function_new_block (testcase->calc_discriminant, NULL); gcc_jit_block_add_comment ( blk, NULL, "(b^2 - 4ac)");
gcc_jit_rvalue *q_a = gcc_jit_lvalue_as_rvalue ( gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_q), NULL, testcase->a)); gcc_jit_rvalue *q_b = gcc_jit_lvalue_as_rvalue ( gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_q), NULL, testcase->b)); gcc_jit_rvalue *q_c = gcc_jit_lvalue_as_rvalue ( gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_q), NULL, testcase->c));
/* (q->b * q->b) - (4 * q->a * q->c) */ gcc_jit_rvalue *rhs = gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MINUS, testcase->numeric_type,
/* (q->b * q->b) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MULT, testcase->numeric_type, q_b, q_b),
/* (4 * (q->a * q->c)) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MULT, testcase->numeric_type, /* 4.0 */ gcc_jit_context_new_rvalue_from_int ( testcase->ctxt, testcase->numeric_type, 4), /* (q->a * q->c) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MULT, testcase->numeric_type, q_a, q_c)));
CHECK_STRING_VALUE ( gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (rhs)), "q->b * q->b - (double)4 * q->a * q->c");
gcc_jit_block_add_assignment ( blk, NULL,
/* q->discriminant =... */ gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_q), NULL, testcase->discriminant), rhs);
gcc_jit_block_end_with_void_return (blk, NULL); }
static void make_test_quadratic (struct quadratic_test *testcase) { gcc_jit_param *a = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type, "a"); gcc_jit_param *b = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type, "b"); gcc_jit_param *c = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type, "c"); gcc_jit_param *r1 = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type_ptr, "r1"); gcc_jit_param *r2 = gcc_jit_context_new_param (testcase->ctxt, NULL, testcase->numeric_type_ptr, "r2"); gcc_jit_param *params[] = {a, b, c, r1, r2}; gcc_jit_function *test_quadratic = gcc_jit_context_new_function (testcase->ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, testcase->int_type, "test_quadratic", 5, params, 0); /* struct quadratic q; */ gcc_jit_lvalue *q = gcc_jit_function_new_local ( test_quadratic, NULL, testcase->quadratic, "q");
gcc_jit_block *initial = gcc_jit_function_new_block (test_quadratic, "initial"); gcc_jit_block *on_positive_discriminant = gcc_jit_function_new_block (test_quadratic, "positive_discriminant");
gcc_jit_block *on_nonpositive_discriminant = gcc_jit_function_new_block (test_quadratic, "nonpositive_discriminant");
gcc_jit_block *on_zero_discriminant = gcc_jit_function_new_block (test_quadratic, "zero_discriminant");
gcc_jit_block *on_negative_discriminant = gcc_jit_function_new_block (test_quadratic, "negative_discriminant");
/* Initial block. */ /* q.a = a; */ gcc_jit_block_add_assignment ( initial, NULL, gcc_jit_lvalue_access_field (q, NULL, testcase->a), gcc_jit_param_as_rvalue (a)); /* q.b = b; */ gcc_jit_block_add_assignment ( initial, NULL, gcc_jit_lvalue_access_field (q, NULL, testcase->b), gcc_jit_param_as_rvalue (b)); /* q.c = c; */ gcc_jit_block_add_assignment ( initial, NULL, gcc_jit_lvalue_access_field (q, NULL, testcase->c), gcc_jit_param_as_rvalue (c)); /* calc_discriminant (&q); */ gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL); gcc_jit_block_add_eval ( initial, NULL, gcc_jit_context_new_call ( testcase->ctxt, NULL, testcase->calc_discriminant, 1, &address_of_q));
gcc_jit_block_add_comment ( initial, NULL, "if (q.discriminant > 0)"); gcc_jit_block_end_with_conditional ( initial, NULL, gcc_jit_context_new_comparison ( testcase->ctxt, NULL, GCC_JIT_COMPARISON_GT, gcc_jit_rvalue_access_field ( gcc_jit_lvalue_as_rvalue (q), NULL, testcase->discriminant), testcase->zero), on_positive_discriminant, on_nonpositive_discriminant);
/* Block: "on_positive_discriminant" */ /* double s = sqrt (q.discriminant); */ gcc_jit_lvalue *s = gcc_jit_function_new_local ( test_quadratic, NULL, testcase->numeric_type, "s"); gcc_jit_rvalue *discriminant_of_q = gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q), NULL, testcase->discriminant); gcc_jit_block_add_assignment ( on_positive_discriminant, NULL, s, gcc_jit_context_new_call ( testcase->ctxt, NULL, testcase->sqrt, 1, &discriminant_of_q));
gcc_jit_rvalue *minus_b = gcc_jit_context_new_unary_op ( testcase->ctxt, NULL, GCC_JIT_UNARY_OP_MINUS, testcase->numeric_type, gcc_jit_param_as_rvalue (b)); gcc_jit_rvalue *two_a = gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MULT, testcase->numeric_type, gcc_jit_context_new_rvalue_from_int ( testcase->ctxt, testcase->numeric_type, 2), gcc_jit_param_as_rvalue (a));
gcc_jit_block_add_comment ( on_positive_discriminant, NULL, "*r1 = (-b + s) / (2 * a);"); gcc_jit_block_add_assignment ( on_positive_discriminant, NULL,
/* "*r1 = ..." */ gcc_jit_rvalue_dereference ( gcc_jit_param_as_rvalue (r1), NULL),
/* (-b + s) / (2 * a) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_DIVIDE, testcase->numeric_type, gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_PLUS, testcase->numeric_type, minus_b, gcc_jit_lvalue_as_rvalue (s)), two_a));
gcc_jit_block_add_comment ( on_positive_discriminant, NULL, "*r2 = (-b - s) / (2 * a)"); gcc_jit_block_add_assignment ( on_positive_discriminant, NULL,
/* "*r2 = ..." */ gcc_jit_rvalue_dereference ( gcc_jit_param_as_rvalue (r2), NULL),
/* (-b - s) / (2 * a) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_DIVIDE, testcase->numeric_type, gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_MINUS, testcase->numeric_type, minus_b, gcc_jit_lvalue_as_rvalue (s)), two_a));
/* "return 2;" */ gcc_jit_block_end_with_return ( on_positive_discriminant, NULL, gcc_jit_context_new_rvalue_from_int ( testcase->ctxt, testcase->int_type, 2));
/* Block: "on_nonpositive_discriminant" */ gcc_jit_block_add_comment ( on_nonpositive_discriminant, NULL, "else if (q.discriminant == 0)"); gcc_jit_block_end_with_conditional ( on_nonpositive_discriminant, NULL, gcc_jit_context_new_comparison ( testcase->ctxt, NULL, GCC_JIT_COMPARISON_EQ, gcc_jit_rvalue_access_field ( gcc_jit_lvalue_as_rvalue (q), NULL, testcase->discriminant), testcase->zero), on_zero_discriminant, on_negative_discriminant);
/* Block: "on_zero_discriminant" */ gcc_jit_block_add_comment ( on_zero_discriminant, NULL, "*r1 = -b / (2 * a);"); gcc_jit_block_add_assignment ( on_zero_discriminant, NULL,
/* "*r1 = ..." */ gcc_jit_rvalue_dereference ( gcc_jit_param_as_rvalue (r1), NULL),
/* -b / (2 * a) */ gcc_jit_context_new_binary_op ( testcase->ctxt, NULL, GCC_JIT_BINARY_OP_DIVIDE, testcase->numeric_type, minus_b, two_a)); gcc_jit_block_end_with_return ( /* "return 1;" */ on_zero_discriminant, NULL, gcc_jit_context_one (testcase->ctxt, testcase->int_type));
/* Block: "on_negative_discriminant" */ gcc_jit_block_end_with_return ( /* "else return 0;" */ on_negative_discriminant, NULL, gcc_jit_context_zero (testcase->ctxt, testcase->int_type)); }
void create_code (gcc_jit_context *ctxt, void *user_data) { struct quadratic_test testcase; memset (&testcase, 0, sizeof (testcase)); testcase.ctxt = ctxt; make_types (&testcase); make_sqrt (&testcase); make_calc_discriminant (&testcase); make_test_quadratic (&testcase); }
void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*fn_type) (double a, double b, double c, double *r1, double *r2);
CHECK_NON_NULL (result);
fn_type test_quadratic = (fn_type)gcc_jit_result_get_code (result, "test_quadratic"); CHECK_NON_NULL (test_quadratic);
/* Verify that the code correctly solves quadratic equations. */ double r1, r2;
/* This one has two solutions: */ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2); CHECK_VALUE (r1, 1); CHECK_VALUE (r2, -4);
/* This one has one solution: */ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1); CHECK_VALUE (r1, -0.5);
/* This one has no real solutions: */ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0); }
|