diff options
Diffstat (limited to 'gcc/testsuite/jit.dg')
60 files changed, 8677 insertions, 0 deletions
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h new file mode 100644 index 00000000000..10d71993613 --- /dev/null +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -0,0 +1,166 @@ +/* This file is used by test-combination.c and test-threads.c to + bring all of the non-failing test cases into one source file, + renaming each "create_code" and "verify_code" hook so that they + each have unique name. */ + +/* Include various other test cases, defining COMBINED_TEST so that + harness.h doesn't duplicate copes of e.g. main, and renaming the + hooks provided by each test case. */ +#define COMBINED_TEST + +/* test-accessing-struct.c */ +#define create_code create_code_accessing_struct +#define verify_code verify_code_accessing_struct +#include "test-accessing-struct.c" +#undef create_code +#undef verify_code + +/* test-accessing-union.c */ +#define create_code create_code_accessing_union +#define verify_code verify_code_accessing_union +#include "test-accessing-union.c" +#undef create_code +#undef verify_code + +/* test-array-as-pointer.c */ +#define create_code create_code_array_as_pointer +#define verify_code verify_code_array_as_pointer +#include "test-array-as-pointer.c" +#undef create_code +#undef verify_code + +/* test-arrays.c */ +#define create_code create_code_arrays +#define verify_code verify_code_arrays +#include "test-arrays.c" +#undef create_code +#undef verify_code + +/* test-calling-external-function.c */ +#define create_code create_code_calling_external_function +#define verify_code verify_code_calling_external_function +#include "test-calling-external-function.c" +#undef create_code +#undef verify_code + +/* test-calling-function-ptr.c */ +#define create_code create_code_calling_function_ptr +#define verify_code verify_code_calling_function_ptr +#include "test-calling-function-ptr.c" +#undef create_code +#undef verify_code + +/* test-dot-product.c */ +#define create_code create_code_dot_product +#define verify_code verify_code_dot_product +#include "test-dot-product.c" +#undef create_code +#undef verify_code + +/* test-error-*.c: We don't use these test cases, since they deliberately + introduce errors, which we don't want here. */ + +/* test-expressions.c */ +#define create_code create_code_expressions +#define verify_code verify_code_expressions +#include "test-expressions.c" +#undef create_code +#undef verify_code + +/* test-factorial.c */ +#define create_code create_code_factorial +#define verify_code verify_code_factorial +#include "test-factorial.c" +#undef create_code +#undef verify_code + +/* test-fibonacci.c */ +#define create_code create_code_fibonacci +#define verify_code verify_code_fibonacci +#include "test-fibonacci.c" +#undef create_code +#undef verify_code + +/* test-functions.c */ +#define create_code create_code_functions +#define verify_code verify_code_functions +#include "test-functions.c" +#undef create_code +#undef verify_code + +/* test-hello-world.c */ +#define create_code create_code_hello_world +#define verify_code verify_code_hello_world +#include "test-hello-world.c" +#undef create_code +#undef verify_code + +/* test-linked-list.c */ +#define create_code create_code_linked_list +#define verify_code verify_code_linked_list +#include "test-linked-list.c" +#undef create_code +#undef verify_code + +/* test-long-names.c */ +#define create_code create_code_long_names +#define verify_code verify_code_long_names +#include "test-long-names.c" +#undef create_code +#undef verify_code + +/* test-quadratic.c */ +#define create_code create_code_quadratic +#define verify_code verify_code_quadratic +#include "test-quadratic.c" +#undef create_code +#undef verify_code + +/* test-nested-loops.c */ +#define create_code create_code_nested_loop +#define verify_code verify_code_nested_loop +#include "test-nested-loops.c" +#undef create_code +#undef verify_code + +/* test-reading-struct.c */ +#define create_code create_code_reading_struct +#define verify_code verify_code_reading_struct +#include "test-reading-struct.c" +#undef create_code +#undef verify_code + +/* test-string-literal.c */ +#define create_code create_code_string_literal +#define verify_code verify_code_string_literal +#include "test-string-literal.c" +#undef create_code +#undef verify_code + +/* test-sum-of-squares.c */ +#define create_code create_code_sum_of_squares +#define verify_code verify_code_sum_of_squares +#include "test-sum-of-squares.c" +#undef create_code +#undef verify_code + +/* test-types.c */ +#define create_code create_code_types +#define verify_code verify_code_types +#include "test-types.c" +#undef create_code +#undef verify_code + +/* test-using-global.c */ +#define create_code create_code_using_global +#define verify_code verify_code_using_global +#include "test-using-global.c" +#undef create_code +#undef verify_code + +/* test-volatile.c */ +#define create_code create_code_volatile +#define verify_code verify_code_volatile +#include "test-volatile.c" +#undef create_code +#undef verify_code diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h new file mode 100644 index 00000000000..f326891c56d --- /dev/null +++ b/gcc/testsuite/jit.dg/harness.h @@ -0,0 +1,242 @@ +/* + Code shared between multiple testcases. + + This file contains "main" and support code. + Each testcase should implement the following hooks: + + extern void + create_code (gcc_jit_context *ctxt, void * user_data); + + extern void + verify_code (gcc_jit_context *ctxt, gcc_jit_result *result); + + */ +#include <stdlib.h> +#include <stdio.h> + +/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a + shared "buffer", and the counts of passed/failed etc are globals. + + The solution is to use macros to rename "pass" and "fail", replacing them + with mutex-guarded alternatives. */ +#ifdef MAKE_DEJAGNU_H_THREADSAFE +#define pass dejagnu_pass +#define fail dejagnu_fail +#define note dejagnu_note +#endif + +#include <dejagnu.h> + +#ifdef MAKE_DEJAGNU_H_THREADSAFE +#undef pass +#undef fail +#undef note +#endif + +static char test[1024]; + +#define CHECK_NON_NULL(PTR) \ + do { \ + if ((PTR) != NULL) \ + { \ + pass ("%s: %s is non-null", test, #PTR); \ + } \ + else \ + { \ + fail ("%s: %s is NULL", test, #PTR); \ + abort (); \ + } \ + } while (0) + +#define CHECK_VALUE(ACTUAL, EXPECTED) \ + do { \ + if ((ACTUAL) == (EXPECTED)) \ + { \ + pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \ + } \ + else \ + { \ + fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \ + fprintf (stderr, "incorrect value\n"); \ + abort (); \ + } \ + } while (0) + +#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \ + do { \ + double expected = (EXPECTED); \ + double actual = (ACTUAL); \ + if (abs (actual - expected) < 0.00001) \ + { \ + pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \ + } \ + else \ + { \ + fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \ + fprintf (stderr, "incorrect value: %f\n", actual); \ + abort (); \ + } \ + } while (0) + +#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \ + check_string_value ((ACTUAL), (EXPECTED)); + +#define CHECK(COND) \ + do { \ + if (COND) \ + { \ + pass ("%s: %s", test, #COND); \ + } \ + else \ + { \ + fail ("%s: %s", test, #COND); \ + abort (); \ + } \ + } while (0) + +/* Hooks that testcases should provide. */ +extern void +create_code (gcc_jit_context *ctxt, void * user_data); + +extern void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result); + +extern void check_string_value (const char *actual, const char *expected); + +/* Implement framework needed for turning the testcase hooks into an + executable. test-combination.c and test-threads.c each combine multiple + testcases into larger testcases, so we have COMBINED_TEST as a way of + temporarily turning off this part of harness.h. */ +#ifndef COMBINED_TEST + +void check_string_value (const char *actual, const char *expected) +{ + if (actual && !expected) + { + fail ("%s: actual: \"%s\" != expected: NULL", test, actual); + fprintf (stderr, "incorrect value\n"); + abort (); + } + if (expected && !actual) + { + fail ("%s: actual: NULL != expected: \"%s\"", test, expected); + fprintf (stderr, "incorrect value\n"); + abort (); + } + if (actual && expected) + { + if (strcmp (actual, expected)) + { + fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected); + fprintf (stderr, "incorrect valuen"); + abort (); + } + pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected); + } + else + pass ("%s: actual: NULL == expected: NULL"); +} + +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ + /* Set up options. */ + gcc_jit_context_set_str_option ( + ctxt, + GCC_JIT_STR_OPTION_PROGNAME, + argv0); + gcc_jit_context_set_int_option ( + ctxt, + GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, + 3); + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DEBUGINFO, + 1); + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE, + 0); + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, + 0); + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_SELFCHECK_GC, + 1); + gcc_jit_context_set_bool_option ( + ctxt, + GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, + 0); +} + +#ifndef TEST_ESCHEWS_TEST_JIT +/* Run one iteration of the test. */ +static void +test_jit (const char *argv0, void *user_data) +{ + gcc_jit_context *ctxt; + gcc_jit_result *result; + + ctxt = gcc_jit_context_acquire (); + /* FIXME: error-handling */ + + set_options (ctxt, argv0); + + create_code (ctxt, user_data); + + /* This actually calls into GCC and runs the build, all + in a mutex for now. */ + result = gcc_jit_context_compile (ctxt); + + verify_code (ctxt, result); + + gcc_jit_context_release (ctxt); + + /* Once we're done with the code, this unloads the built .so file: */ + gcc_jit_result_release (result); +} +#endif /* #ifndef TEST_ESCHEWS_TEST_JIT */ + +/* We want to prefix all unit test results with the test, but dejagnu.exp's + host_execute appears to get confused by the leading "./" of argv0, + leading to all tests simply reporting as a single period character ".". + + Hence strip out the final component of the path to the program name, + so that we can use that in unittest reports. */ +const char* +extract_progname (const char *argv0) +{ + const char *p; + + p = argv0 + strlen (argv0); + while (p != argv0 && p[-1] != '/') + --p; + return p; +} + +#ifndef TEST_PROVIDES_MAIN +int +main (int argc, char **argv) +{ + int i; + + for (i = 1; i <= 5; i++) + { + snprintf (test, sizeof (test), + "%s iteration %d of %d", + extract_progname (argv[0]), + i, 5); + + //printf ("ITERATION %d\n", i); + test_jit (argv[0], NULL); + //printf ("\n"); + } + + totals (); + + return 0; +} +#endif /* #ifndef TEST_PROVIDES_MAIN */ + +#endif /* #ifndef COMBINED_TEST */ diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp new file mode 100644 index 00000000000..531e92971fb --- /dev/null +++ b/gcc/testsuite/jit.dg/jit.exp @@ -0,0 +1,293 @@ +# Test code for libgccjit.so +# +# We will compile each of jit.dg/test-*.c into an executable +# dynamically linked against libgccjit.so, and then run each +# such executable. +# +# These executables call into the libgccjit.so API to create +# code, compile it, and run it, verifying that the results +# are as expected. See harness.h for shared code used by all +# such executables. +# +# The executables call into DejaGnu's unit testing C API to +# report PASS/FAIL results, which this script gathers back +# up into the Tcl world, reporting a summary of all results +# across all of the executables. + +load_lib dg.exp +load_lib prune.exp +load_lib target-supports.exp +load_lib gcc-defs.exp +load_lib timeout.exp +load_lib target-libpath.exp +load_lib gcc.exp +load_lib dejagnu.exp + +# This is host_execute from dejagnu.exp commit +# 126a089777158a7891ff975473939f08c0e31a1c +# with the following patch applied, and renaming to "fixed_host_execute". +# See the discussion at +# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html +# +# --- /usr/share/dejagnu/dejagnu.exp.old 2014-10-08 13:38:57.274068541 -0400 +# +++ /usr/share/dejagnu/dejagnu.exp 2014-10-10 12:27:51.113813659 -0400 +# @@ -113,8 +113,6 @@ proc host_execute {args} { +# set timetol 0 +# set arguments "" +# +# - expect_before buffer_full { perror "Buffer full" } +# - +# if { [llength $args] == 0} { +# set executable $args +# } else { + + +# Execute the executable file, and anaylyse the output for the +# test state keywords. +# Returns: +# A "" (empty) string if everything worked, or an error message +# if there was a problem. +# +proc fixed_host_execute {args} { + global text + global spawn_id + + set timeoutmsg "Timed out: Never got started, " + set timeout 100 + set file all + set timetol 0 + set arguments "" + + if { [llength $args] == 0} { + set executable $args + } else { + set executable [string trimleft [lindex [split $args " "] 0] "\{"] + set params [string trimleft [lindex [split $args " "] 1] "\{"] + set params [string trimright $params "\}"] + } + + verbose "The executable is $executable" 2 + if {![file exists ${executable}]} { + perror "The executable, \"$executable\" is missing" 0 + return "No source file found" + } + + # spawn the executable and look for the DejaGnu output messages from the + # test case. + # spawn -noecho -open [open "|./${executable}" "r"] + spawn -noecho "./${executable}" ${params} + expect_after full_buffer { error "got full_buffer" } + + set prefix "\[^\r\n\]*" + expect { + -re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" { + regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output + verbose "$output" 3 + set timetol 0 + exp_continue + } + -re "^$prefix\tNOTE:${text}*" { + regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output + set output [string range $output 6 end] + verbose "$output" 2 + set timetol 0 + exp_continue + } + -re "^$prefix\tPASSED:${text}*" { + regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output + set output [string range $output 8 end] + pass "$output" + set timetol 0 + exp_continue + } + -re "^$prefix\tFAILED:${text}*" { + regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output + set output [string range $output 8 end] + fail "$output" + set timetol 0 + exp_continue + } + -re "^$prefix\tUNTESTED:${text}*" { + regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output + set output [string range $output 8 end] + untested "$output" + set timetol 0 + exp_continue + } + -re "^$prefix\tUNRESOLVED:${text}*" { + regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output + set output [string range $output 8 end] + unresolved "$output" + set timetol 0 + exp_continue + } + -re "^Totals" { + verbose "All done" 2 + } + eof { + # unresolved "${executable} died prematurely" + # catch close + # return "${executable} died prematurely" + } + timeout { + warning "Timed out executing test case" + if { $timetol <= 2 } { + incr timetol + exp_continue + } else { + - catch close + return "Timed out executing test case" + } + } + -re "^$prefix\r\n" { + exp_continue + } + } + + # force a close of the executable to be safe. + catch close + + return "" +} + +# (end of code from dejagnu.exp) + +# GCC_UNDER_TEST is needed by gcc_target_compile +global GCC_UNDER_TEST +if ![info exists GCC_UNDER_TEST] { + set GCC_UNDER_TEST "[find_gcc]" +} + +# Initialize dg. +dg-init + +# Gather a list of all tests. + +# Tests within the testsuite: gcc/testsuite/jit.dg/test-*.c +set tests [lsort [find $srcdir/$subdir test-*.c]] + +# We also test the examples within the documentation, to ensure that +# they compile: +set tests [lsort [concat $tests [find $srcdir/../jit/docs/examples *.c]]] + +verbose "tests: $tests" + +# libgloss has found the driver (as "xgcc" or "gcc) and stored +# its full path as GCC_UNDER_TEST. +proc get_path_of_driver {} { + global GCC_UNDER_TEST + + verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST" + set binary [lindex $GCC_UNDER_TEST 0] + verbose "binary: $binary" + + return [file dirname $binary] +} + +proc jit-dg-test { prog do_what extra_tool_flags } { + verbose "within jit-dg-test..." + verbose " prog: $prog" + verbose " do_what: $do_what" + verbose " extra_tool_flags: $extra_tool_flags" + + # test-threads.c needs to be linked against pthreads + if {[string match "*test-threads.c" $prog]} { + append extra_tool_flags " -lpthread" + } + + # Determine what to name the built executable. + set output_file "[file rootname [file tail $prog]].exe" + verbose "output_file: $output_file" + + # Create the test executable: + set comp_output [gcc_target_compile $prog $output_file $do_what \ + "{additional_flags=$extra_tool_flags}"] + if ![jit_check_compile "$prog" "initial compilation" \ + $output_file $comp_output] then { + return + } + + # Run the test executable, capturing the PASS/FAIL textual output + # from the C API, converting it into the Tcl API. + + # We need to set LD_LIBRARY_PATH so that the test files can find + # libgccjit.so + # Do this using set_ld_library_path_env_vars from target-libpath.exp + global ld_library_path + global base_dir + set ld_library_path "$base_dir/../../" + set_ld_library_path_env_vars + + # libgccjit uses the driver to convert .s files to .so libraries + # via its *installed* name, FULL_DRIVER_NAME + # ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext} + # e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0" + # looking for it on PATH. Hence we need to prepend the location of + # that executable to PATH when running the tests + set dir_containing_driver [get_path_of_driver ] + verbose "dir_containing_driver: $dir_containing_driver" + global env + set old_path $env(PATH) + setenv "PATH" $dir_containing_driver:$old_path + verbose -log "PATH=[getenv PATH]" + + # We have: + # test-executables + # linked to -> libgccjit.so + # -> invokes driver: + # -> invokes the assembler + # -> invokes the linker + # We want to be able to run this from the builddir without installing + # but the linker needs to be able to locate various libraries, or we + # get: + # ld: cannot find crtbeginS.o: No such file or directory + # ld: cannot find -lgcc + # ld: cannot find -lgcc_s + # These can be found in the "gcc" subdir of the build. + # Hence to be able to run the testsuite without installing, we need + # to set or prepend the "gcc" subdir of the build to LIBRARY_PATH: + if { [info exists env(LIBRARY_PATH) ] } { + set old_library_path $env(LIBRARY_PATH) + setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path + } else { + setenv "LIBRARY_PATH" $dir_containing_driver + } + verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]" + + # dejagnu.exp's host_execute has code to scrape out test results + # from the DejaGnu C API and bring back into the tcl world, so we + # use that to invoke the built code. + # However, it appears to be buggy; see: + # http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html + # We instead call a patched local copy, "fixed_host_execute", defined + # above. + set result [fixed_host_execute $output_file] + verbose "result: $result" + + # Restore PATH + setenv "PATH" $old_path + + # Restore LIBRARY_PATH + if { [info exists old_library_path] } { + setenv "LIBRARY_PATH" $old_library_path + } else { + unsetenv "LIBRARY_PATH" + } + + restore_ld_library_path_env_vars +} + +# We need to link with --export-dynamic for test-calling-external-function.c +# so that the JIT-built code can call into functions from the main program. +set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic" + +# <dejagnu.h> assumes -fgnu89-inline +# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613 +# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html +append DEFAULT_CFLAGS " -fgnu89-inline" + +# Main loop. This will invoke jig-dg-test on each test-*.c file. +dg-runtest $tests "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c new file mode 100644 index 00000000000..109a0d7f2cd --- /dev/null +++ b/gcc/testsuite/jit.dg/test-accessing-struct.c @@ -0,0 +1,112 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +struct foo +{ + int x; + int y; + int z; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_access (struct foo *f) + { + f->z = f->x * f->y; + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_field *x = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "x"); + gcc_jit_field *y = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "y"); + gcc_jit_field *z = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "z"); + gcc_jit_field *fields[] = {x, y, z}; + gcc_jit_struct *struct_type = + gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields); + gcc_jit_type *ptr_type = + gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type)); + + /* Build the test function. */ + gcc_jit_param *param_f = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_access", + 1, ¶m_f, + 0); + + /* f->x * f->y */ + gcc_jit_rvalue *sum = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + int_type, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + x)), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + y))); + + /* f->z = ... */ + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_assignment ( + block, + NULL, + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + z), + sum); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (struct foo *); + CHECK_NON_NULL (result); + + fn_type test_access = + (fn_type)gcc_jit_result_get_code (result, "test_access"); + CHECK_NON_NULL (test_access); + + struct foo tmp; + tmp.x = 5; + tmp.y = 7; + tmp.z = 0; + + /* Call the JIT-generated function. */ + test_access (&tmp); + + /* Verify that the code correctly modified the field "z". */ + CHECK_VALUE (tmp.z, 35); +} + diff --git a/gcc/testsuite/jit.dg/test-accessing-union.c b/gcc/testsuite/jit.dg/test-accessing-union.c new file mode 100644 index 00000000000..658d1bc2eee --- /dev/null +++ b/gcc/testsuite/jit.dg/test-accessing-union.c @@ -0,0 +1,97 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +union int_or_float +{ + int as_int; + float as_float; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + float + test_union (int i) + { + union int_or_float u; + u.as_int = i; + return u.as_float; + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *float_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT); + gcc_jit_field *as_int = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "as_int"); + gcc_jit_field *as_float = + gcc_jit_context_new_field (ctxt, + NULL, + float_type, + "as_float"); + gcc_jit_field *fields[] = {as_int, as_float}; + gcc_jit_type *union_type = + gcc_jit_context_new_union_type (ctxt, NULL, + "int_or_float", 2, fields); + + /* Build the test function. */ + gcc_jit_param *param_i = + gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + float_type, + "test_union", + 1, ¶m_i, + 0); + + gcc_jit_lvalue *u = + gcc_jit_function_new_local (test_fn, NULL, + union_type, "u"); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + /* u.as_int = i; */ + gcc_jit_block_add_assignment ( + block, + NULL, + /* "u.as_int = ..." */ + gcc_jit_lvalue_access_field (u, + NULL, + as_int), + gcc_jit_param_as_rvalue (param_i)); + + /* return u.as_float; */ + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u), + NULL, + as_float)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef float (*fn_type) (int i); + CHECK_NON_NULL (result); + + fn_type test_union = + (fn_type)gcc_jit_result_get_code (result, "test_union"); + CHECK_NON_NULL (test_union); + + /* Call the JIT-generated function. */ + float f_result = test_union (42); + + union int_or_float u; + u.as_float = f_result; + + CHECK_VALUE (u.as_int, 42); +} diff --git a/gcc/testsuite/jit.dg/test-array-as-pointer.c b/gcc/testsuite/jit.dg/test-array-as-pointer.c new file mode 100644 index 00000000000..1a240ac552c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-array-as-pointer.c @@ -0,0 +1,101 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> + +#include "libgccjit.h" + +#include "harness.h" + +#define BUFFER_SIZE (1024) + +char test_buffer[1024]; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void test_of_array_as_pointer (const char *name) + { + snprintf (test_buffer, sizeof (test_buffer), + "hello %s", name); + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *const_char_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); + gcc_jit_type *char_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR); + gcc_jit_type *char_ptr_type = + gcc_jit_type_get_pointer (char_type); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *size_t_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T); + gcc_jit_type *buf_type = + gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE); + + /* extern int snprintf(char *str, size_t size, const char *format, ...); */ + gcc_jit_param *param_s = + gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s"); + gcc_jit_param *param_n = + gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n"); + gcc_jit_param *param_format = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format"); + gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format}; + gcc_jit_function *snprintf = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "snprintf", + 3, snprintf_params, + 1); + + gcc_jit_param *param_name = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_of_array_as_pointer", + 1, ¶m_name, + 0); + + gcc_jit_lvalue *buffer = + gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer"); + + gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry"); + + /* snprintf(buffer, sizeof(buffer), "hello %s", name); */ + gcc_jit_rvalue *args[4]; + args[0] = gcc_jit_context_new_cast ( + ctxt, NULL, + /* Here's the difference with test-error-array-as-pointer.c: */ + gcc_jit_lvalue_get_address (buffer, + NULL), + char_ptr_type); + args[1] = gcc_jit_context_new_rvalue_from_int (ctxt, + size_t_type, + BUFFER_SIZE); + args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s"); + args[3] = gcc_jit_param_as_rvalue (param_name); + + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + typedef void (*fn_type) (const char *); + fn_type test_of_array_as_pointer = + (fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer"); + CHECK_NON_NULL (test_of_array_as_pointer); + + test_of_array_as_pointer ("world"); + CHECK_STRING_VALUE (test_buffer, "hello world"); +} diff --git a/gcc/testsuite/jit.dg/test-arrays.c b/gcc/testsuite/jit.dg/test-arrays.c new file mode 100644 index 00000000000..378a2a31e96 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-arrays.c @@ -0,0 +1,165 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> + +#include "libgccjit.h" + +#include "harness.h" + +#define ARRAY_SIZE (4) + +/* Verify that struct layout works properly when adding an array field. */ +struct array_holder +{ + float m_before; + int m_ints[ARRAY_SIZE]; + float m_after; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_array (struct array_holder *ah) + { + ah->m_before = 4.0f; + for i in 0 to (ARRAY_SIZE - 1): + ah->m_ints[i] = (i * i); + ah->m_after = 2.0f; + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *float_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_field *field_m_before = + gcc_jit_context_new_field (ctxt, NULL, float_type, "m_before"); + gcc_jit_field *field_m_ints = + gcc_jit_context_new_field ( + ctxt, NULL, + gcc_jit_context_new_array_type (ctxt, NULL, int_type, ARRAY_SIZE), + "m_ints"); + gcc_jit_field *field_m_after = + gcc_jit_context_new_field (ctxt, NULL, float_type, "m_after"); + + gcc_jit_field *fields[] = { + field_m_before, + field_m_ints, + field_m_after, + }; + + gcc_jit_struct *struct_type = + gcc_jit_context_new_struct_type ( + ctxt, + NULL, + "array_holder", + 3, fields); + + gcc_jit_type *struct_ptr_type = + gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type)); + + /* Build the test_fn. */ + gcc_jit_param *param_ah = + gcc_jit_context_new_param (ctxt, NULL, struct_ptr_type, "ah"); + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_array", + 1, ¶m_ah, + 0); + + gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial"); + gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test"); + gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body"); + gcc_jit_block *final = gcc_jit_function_new_block (func, "final"); + + /* "ah->m_before = 4.0f;" */ + gcc_jit_block_add_assignment ( + initial, NULL, + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_ah), NULL, field_m_before), + gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 4)); + + gcc_jit_block_add_comment (initial, NULL, + "for i in 0 to (ARRAY_SIZE - 1):"); + gcc_jit_lvalue *i = + gcc_jit_function_new_local (func, NULL, int_type, "i"); + gcc_jit_block_add_assignment (initial, NULL, + i, + gcc_jit_context_zero (ctxt, int_type)); + + gcc_jit_block_end_with_jump (initial, NULL, loop_test); + + gcc_jit_block_end_with_conditional (loop_test, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_LT, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, ARRAY_SIZE)), + loop_body, + final); + + gcc_jit_block_add_comment (loop_body, NULL, "ah->m_ints[i] = (i * i);"); + gcc_jit_block_add_assignment ( + loop_body, NULL, + gcc_jit_context_new_array_access ( + ctxt, NULL, + gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_ah), + NULL, + field_m_ints)), + gcc_jit_lvalue_as_rvalue (i)), + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + int_type, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_lvalue_as_rvalue (i))); + + /* "i++" */ + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + i, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + + gcc_jit_block_end_with_jump (loop_body, NULL, loop_test); + + /* ah->m_after = 2.0f; */ + gcc_jit_block_add_assignment ( + final, NULL, + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_ah), NULL, field_m_after), + gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 2)); + gcc_jit_block_end_with_void_return (final, NULL); + +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (struct array_holder *ah); + + CHECK_NON_NULL (result); + fn_type test_array = + (fn_type)gcc_jit_result_get_code (result, "test_array"); + CHECK_NON_NULL (test_array); + + struct array_holder ah; + memset (&ah, 0xf0, sizeof (ah)); + + test_array (&ah); + CHECK_VALUE (ah.m_before, 4.0f); + CHECK_VALUE (ah.m_ints[0], 0); + CHECK_VALUE (ah.m_ints[1], 1); + CHECK_VALUE (ah.m_ints[2], 4); + CHECK_VALUE (ah.m_ints[3], 9); + CHECK_VALUE (ah.m_after, 2.0f); + +} diff --git a/gcc/testsuite/jit.dg/test-calling-external-function.c b/gcc/testsuite/jit.dg/test-calling-external-function.c new file mode 100644 index 00000000000..177f3296ac5 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-calling-external-function.c @@ -0,0 +1,118 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (int i, int j, int k); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern void called_function (int i, int j, int k); + + void + test_caller (int a) + { + called_function (a * 3, a * 4, a * 5); + } + */ + int i; + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Declare the imported function. */ + gcc_jit_param *params[3]; + params[0] = + gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); + params[1] = + gcc_jit_context_new_param (ctxt, NULL, int_type, "j"); + params[2] = + gcc_jit_context_new_param (ctxt, NULL, int_type, "k"); + gcc_jit_function *called_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 3, params, + 0); + + /* Build the test_fn. */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, int_type, "a"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_caller", + 1, ¶m_a, + 0); + /* "a * 3, a * 4, a * 5" */ + gcc_jit_rvalue *args[3]; + for (i = 0; i < 3; i++) + args[i] = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + int_type, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + int_type, + (i + 3) )); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + called_fn, + 3, args)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +static int called_with[3]; + +extern void +called_function (int i, int j, int k) +{ + called_with[0] = i; + called_with[1] = j; + called_with[2] = k; +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (int); + CHECK_NON_NULL (result); + + fn_type test_caller = + (fn_type)gcc_jit_result_get_code (result, "test_caller"); + CHECK_NON_NULL (test_caller); + + called_with[0] = 0; + called_with[1] = 0; + called_with[2] = 0; + + /* Call the JIT-generated function. */ + test_caller (5); + + /* Verify that it correctly called "called_function". */ + CHECK_VALUE (called_with[0], 15); + CHECK_VALUE (called_with[1], 20); + CHECK_VALUE (called_with[2], 25); +} + diff --git a/gcc/testsuite/jit.dg/test-calling-function-ptr.c b/gcc/testsuite/jit.dg/test-calling-function-ptr.c new file mode 100644 index 00000000000..e21bd15e303 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-calling-function-ptr.c @@ -0,0 +1,118 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr, + int a) + { + fn_ptr (a * 3, a * 4, a * 5); + } + */ + + int i; + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the function ptr type. */ + gcc_jit_type *param_types[3]; + param_types[0] = int_type; + param_types[1] = int_type; + param_types[2] = int_type; + + gcc_jit_type *fn_ptr_type = + gcc_jit_context_new_function_ptr_type (ctxt, NULL, + void_type, + 3, param_types, 0); + + /* Ensure that function ptr types have sane debug strings. */ + + CHECK_STRING_VALUE ( + gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)), + "void (*) (int, int, int)"); + + /* Build the test_fn. */ + gcc_jit_param *param_fn_ptr = + gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr"); + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, int_type, "a"); + + gcc_jit_param *params[2]; + params[0] = param_fn_ptr; + params[1] = param_a; + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_calling_function_ptr", + 2, params, + 0); + /* "a * 3, a * 4, a * 5" */ + gcc_jit_rvalue *args[3]; + for (i = 0; i < 3; i++) + args[i] = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + int_type, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + int_type, + (i + 3) )); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + gcc_jit_param_as_rvalue (param_fn_ptr), + 3, args)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +static int called_through_ptr_with[3]; + +static void +function_called_through_fn_ptr (int i, int j, int k) +{ + called_through_ptr_with[0] = i; + called_through_ptr_with[1] = j; + called_through_ptr_with[2] = k; +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (void (*fn_ptr) (int, int, int), + int); + CHECK_NON_NULL (result); + + fn_type test_caller = + (fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr"); + CHECK_NON_NULL (test_caller); + + called_through_ptr_with[0] = 0; + called_through_ptr_with[1] = 0; + called_through_ptr_with[2] = 0; + + /* Call the JIT-generated function. */ + test_caller (function_called_through_fn_ptr, 5); + + /* Verify that it correctly called "function_called_through_fn_ptr". */ + CHECK_VALUE (called_through_ptr_with[0], 15); + CHECK_VALUE (called_through_ptr_with[1], 20); + CHECK_VALUE (called_through_ptr_with[2], 25); +} + diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c new file mode 100644 index 00000000000..06ba90242a3 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-combination.c @@ -0,0 +1,67 @@ +/* Construct a test case by combining other test cases, to try to shake + out state issues: all of the test cases are run in one process, inside + one gcc_jit_context (per iteration). */ + +#include "all-non-failing-tests.h" + +/* Now construct a test case from all the other test cases. + + We undefine COMBINED_TEST so that we can now include harness.h + "for real". */ +#undef COMBINED_TEST +#include "harness.h" + +/* Our testing hooks are the combination of the other test cases. */ +void +create_code (gcc_jit_context *ctxt, void * user_data) +{ + create_code_accessing_struct (ctxt, user_data); + create_code_accessing_union (ctxt, user_data); + create_code_array_as_pointer (ctxt, user_data); + create_code_arrays (ctxt, user_data); + create_code_calling_external_function (ctxt, user_data); + create_code_calling_function_ptr (ctxt, user_data); + create_code_dot_product (ctxt, user_data); + create_code_expressions (ctxt, user_data); + create_code_factorial (ctxt, user_data); + create_code_fibonacci (ctxt, user_data); + create_code_functions (ctxt, user_data); + create_code_hello_world (ctxt, user_data); + create_code_linked_list (ctxt, user_data); + create_code_long_names (ctxt, user_data); + create_code_quadratic (ctxt, user_data); + create_code_nested_loop (ctxt, user_data); + create_code_reading_struct (ctxt, user_data); + create_code_string_literal (ctxt, user_data); + create_code_sum_of_squares (ctxt, user_data); + create_code_types (ctxt, user_data); + create_code_using_global (ctxt, user_data); + create_code_volatile (ctxt, user_data); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_code_accessing_struct (ctxt, result); + verify_code_accessing_union (ctxt, result); + verify_code_array_as_pointer (ctxt, result); + verify_code_arrays (ctxt, result); + verify_code_calling_external_function (ctxt, result); + verify_code_calling_function_ptr (ctxt, result); + verify_code_dot_product (ctxt, result); + verify_code_expressions (ctxt, result); + verify_code_factorial (ctxt, result); + verify_code_fibonacci (ctxt, result); + verify_code_functions (ctxt, result); + verify_code_hello_world (ctxt, result); + verify_code_linked_list (ctxt, result); + verify_code_long_names (ctxt, result); + verify_code_quadratic (ctxt, result); + verify_code_nested_loop (ctxt, result); + verify_code_reading_struct (ctxt, result); + verify_code_string_literal (ctxt, result); + verify_code_sum_of_squares (ctxt, result); + verify_code_types (ctxt, result); + verify_code_using_global (ctxt, result); + verify_code_volatile (ctxt, result); +} diff --git a/gcc/testsuite/jit.dg/test-dot-product.c b/gcc/testsuite/jit.dg/test-dot-product.c new file mode 100644 index 00000000000..a41109a5d9f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-dot-product.c @@ -0,0 +1,129 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + double + my_dot_product (int n, double *a, double *b) + { + double result = 0.; + for (int i = 0; i < n; i++) + result += a[i] * b[i]; + return result + } + + and see what the optimizer can do. */ + gcc_jit_type *val_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_type *return_type = val_type; + gcc_jit_param *param_n = + gcc_jit_context_new_param (ctxt, NULL, int_type, "n"); + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b"); + gcc_jit_param *params[3] = {param_n, param_a, param_b}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + return_type, + "my_dot_product", + 3, params, 0); + + gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial"); + gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test"); + gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body"); + gcc_jit_block *final = gcc_jit_function_new_block (func, "final"); + + /* Build: "double result = 0.;" */ + gcc_jit_lvalue *result = + gcc_jit_function_new_local (func, NULL, val_type, "result"); + + gcc_jit_block_add_assignment (initial, NULL, + result, gcc_jit_context_zero (ctxt, val_type)); + + /* Build: "for (int i = 0; i < n; i++)" */ + gcc_jit_lvalue *i = + gcc_jit_function_new_local (func, NULL, int_type, "i"); + gcc_jit_block_add_assignment (initial, NULL, + i, gcc_jit_context_zero (ctxt, int_type)); + + gcc_jit_block_end_with_jump (initial, NULL, loop_test); + + gcc_jit_block_end_with_conditional ( + loop_test, NULL, + + /* (i < n) */ + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_LT, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_param_as_rvalue (param_n)), + + loop_body, + final); + + /* Build: "result += a[i] * b[i];" */ + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + result, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + val_type, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_context_new_array_access ( + ctxt, NULL, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_lvalue_as_rvalue (i))), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_context_new_array_access ( + ctxt, NULL, + gcc_jit_param_as_rvalue (param_b), + gcc_jit_lvalue_as_rvalue (i))))); + + /* Build: "i++" */ + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + i, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + + gcc_jit_block_end_with_jump (loop_body, NULL, loop_test); + + /* Build: "return result;" */ + gcc_jit_block_end_with_return ( + final, + NULL, + gcc_jit_lvalue_as_rvalue (result)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef double (*my_dot_product_fn_type) (int n, double *a, double *b); + CHECK_NON_NULL (result); + + my_dot_product_fn_type my_dot_product = + (my_dot_product_fn_type)gcc_jit_result_get_code (result, + "my_dot_product"); + CHECK_NON_NULL (my_dot_product); + double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}; + double val = my_dot_product (10, test_array, test_array); + note ("my_dot_product returned: %f", val); + CHECK_VALUE (val, 385.0); +} + diff --git a/gcc/testsuite/jit.dg/test-empty.c b/gcc/testsuite/jit.dg/test-empty.c new file mode 100644 index 00000000000..820f232dfee --- /dev/null +++ b/gcc/testsuite/jit.dg/test-empty.c @@ -0,0 +1,20 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Do nothing. */ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* We should have a non-NULL result, albeit one with nothing in it. */ + CHECK_NON_NULL (result); +} + diff --git a/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c b/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c new file mode 100644 index 00000000000..f10954b434c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c @@ -0,0 +1,114 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +struct foo +{ + int x; + int y; +}; + +struct bar +{ + int p; + int q; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_bogus_access (struct foo *f) + { + f->p = f->q; + } + i.e. using the wrong struct. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Map "struct foo". */ + gcc_jit_field *x = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "x"); + gcc_jit_field *y = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "y"); + gcc_jit_field *foo_fields[] = {x, y}; + gcc_jit_struct *struct_foo = + gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields); + + /* Map "struct bar". */ + gcc_jit_field *p = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "p"); + gcc_jit_field *q = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "q"); + /* We don't actually need a gcc_jit_type for "struct bar" for the test. */ + gcc_jit_field *bar_fields[] = {p, q}; + (void)gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, bar_fields); + + gcc_jit_type *foo_ptr = + gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo)); + + /* Build the test function. */ + gcc_jit_param *param_f = + gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "f"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_bogus_access", + 1, ¶m_f, + 0); + + /* Erroneous: f->p = ... */ + gcc_jit_lvalue *lvalue = + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + p); + + /* Erroneous: ... = f->q; */ + gcc_jit_rvalue *rvalue = + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + q)); + + gcc_jit_block *block = + gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_assignment ( + block, + NULL, + lvalue, rvalue); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_rvalue_dereference_field:" + " p is not a field of struct foo"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c b/gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c new file mode 100644 index 00000000000..9c39dd6a9fb --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c @@ -0,0 +1,48 @@ +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_fn () + { + return; + return; + } + */ + gcc_jit_type *void_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "test_fn", + 0, NULL, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "initial"); + + gcc_jit_block_end_with_void_return (initial, NULL); + /* Error: "initial" has already been terminated. */ + gcc_jit_block_end_with_void_return (initial, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_end_with_void_return:" + " adding to terminated block:" + " initial (already terminated by: return;)"); +} diff --git a/gcc/testsuite/jit.dg/test-error-array-as-pointer.c b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c new file mode 100644 index 00000000000..cd2b7f8c57c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c @@ -0,0 +1,99 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> + +#include "libgccjit.h" + +#include "harness.h" + +#define BUFFER_SIZE (1024) + +char test_buffer[1024]; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void test_of_array_as_pointer (const char *name) + { + snprintf (test_buffer, sizeof (test_buffer), + "hello %s", name); + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *const_char_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); + gcc_jit_type *char_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR); + gcc_jit_type *char_ptr_type = + gcc_jit_type_get_pointer (char_type); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *size_t_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T); + gcc_jit_type *buf_type = + gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE); + + /* extern int snprintf(char *str, size_t size, const char *format, ...); */ + gcc_jit_param *param_s = + gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s"); + gcc_jit_param *param_n = + gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n"); + gcc_jit_param *param_format = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format"); + gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format}; + gcc_jit_function *snprintf = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "snprintf", + 3, snprintf_params, + 1); + + gcc_jit_param *param_name = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_of_array_as_pointer", + 1, ¶m_name, + 0); + + gcc_jit_lvalue *buffer = + gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer"); + + gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry"); + + /* snprintf(buffer, sizeof(buffer), "hello %s", name); */ + gcc_jit_rvalue *args[4]; + args[0] = gcc_jit_context_new_cast ( + ctxt, NULL, + /* Here's the difference with test-array-as-pointer.c: */ + gcc_jit_lvalue_as_rvalue (buffer), + char_ptr_type); + args[1] = gcc_jit_context_new_rvalue_from_int (ctxt, + size_t_type, + BUFFER_SIZE); + args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s"); + args[3] = gcc_jit_param_as_rvalue (param_name); + + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_cast:" + " cannot cast test_buffer" + " from type: char[1024]" + " to type: char *"); +} diff --git a/gcc/testsuite/jit.dg/test-error-bad-cast.c b/gcc/testsuite/jit.dg/test-error-bad-cast.c new file mode 100644 index 00000000000..a0ab4137a5c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-bad-cast.c @@ -0,0 +1,63 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + int + test_fn () + { + struct foo f; + return (int)f; + } + + and verify that the API complains about the bad cast. + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + + gcc_jit_struct *struct_foo = + gcc_jit_context_new_struct_type (ctxt, NULL, "foo", + 0, NULL); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_fn", + 0, NULL, + 0); + gcc_jit_lvalue *f = + gcc_jit_function_new_local ( + test_fn, + NULL, + gcc_jit_struct_as_type (struct_foo), "f"); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_context_new_cast (ctxt, NULL, + gcc_jit_lvalue_as_rvalue (f), + int_type)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_cast:" + " cannot cast f from type: struct foo" + " to type: int"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c b/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c new file mode 100644 index 00000000000..b7342a3a055 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c @@ -0,0 +1,65 @@ +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_fn () + { + goto label; + } + + void + other_fn () + { + label: + }; + where the destination block is in another function. + */ + gcc_jit_type *void_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "test_fn", + 0, NULL, + 0); + /* Build the other_fn. */ + gcc_jit_function *other_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "other_fn", + 0, NULL, + 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block *block_within_other_fn = + gcc_jit_function_new_block (other_fn, "block_within_other_fn"); + + gcc_jit_block_end_with_jump (initial, NULL, block_within_other_fn); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_end_with_jump:" + " target block is not in same function:" + " source block initial is in function test_fn" + " whereas target block block_within_other_fn" + " is in function other_fn"); +} diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c new file mode 100644 index 00000000000..afe5a7c970c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c @@ -0,0 +1,74 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_fn (void (*some_fn_ptr) (void *)) + { + some_fn_ptr (42); + } + + and verify that the API complains about the mismatching argument + type ("int" vs "void *"). */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *void_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the function ptr type. */ + gcc_jit_type *fn_ptr_type = + gcc_jit_context_new_function_ptr_type (ctxt, NULL, + void_type, + 1, &void_ptr_type, 0); + + /* Build the test_fn. */ + gcc_jit_param *param_fn_ptr = + gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr"); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 1, ¶m_fn_ptr, + 0); + /* some_fn_ptr (42); */ + gcc_jit_rvalue *arg = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + gcc_jit_param_as_rvalue (param_fn_ptr), + 1, &arg)); + /* the above has the wrong type for argument 1. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call_through_ptr:" + " mismatching types for argument 1 of fn_ptr:" + " some_fn_ptr:" + " assignment to param 1 (type: void *)" + " from (int)42 (type: int)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c new file mode 100644 index 00000000000..513e3d39896 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c @@ -0,0 +1,65 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_fn (void *some_ptr) + { + ((some_unspecified_fn_ptr_type)some_ptr) (42); + } + + and verify that the API complains about the 42 not being a + function pointer. */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *void_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the test_fn. */ + gcc_jit_param *some_ptr = + gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "some_ptr"); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 1, &some_ptr, + 0); + gcc_jit_rvalue *arg = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42); + + /* ((some_unspecified_fn_ptr_type)some_ptr) (42); */ + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + /* This is not a function pointer. */ + gcc_jit_param_as_rvalue (some_ptr), + 1, &arg)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call_through_ptr:" + " fn_ptr is not a function ptr: some_ptr type: void *")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c new file mode 100644 index 00000000000..8bb50d97203 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c @@ -0,0 +1,62 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_fn () + { + ((some_unspecified_fn_ptr_type)42) (43); + } + + and verify that the API complains about the 42 not being a + function pointer. */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + gcc_jit_rvalue *not_a_function = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42); + gcc_jit_rvalue *arg = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 43); + + /* ((some_unspecified_fn_ptr_type)42) (43); */ + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + /* This is not even a pointer, let alone a function pointer. */ + not_a_function, + 1, &arg)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call_through_ptr:" + " fn_ptr is not a ptr: (int)42 type: int")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c new file mode 100644 index 00000000000..3e160f4c441 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c @@ -0,0 +1,70 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_caller (void (*some_fn_ptr) (int p)) + { + called_function (); // missing arg + } + + and verify that the API complains about the missing argument. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the function ptr type. */ + gcc_jit_type *fn_ptr_type = + gcc_jit_context_new_function_ptr_type (ctxt, NULL, + void_type, + 1, &int_type, 0); + + /* Build the test_fn. */ + gcc_jit_param *param_fn_ptr = + gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr"); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_caller", + 1, ¶m_fn_ptr, + 0); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + /* called_function (); */ + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + gcc_jit_param_as_rvalue (param_fn_ptr), + 0, NULL)); + /* the above has not enough args. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that mismatching arg count leads to the API giving a NULL + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call_through_ptr:" + " not enough arguments to fn_ptr: some_fn_ptr" + " (got 0 args, expected 1)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c new file mode 100644 index 00000000000..b8cb2f47e8a --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c @@ -0,0 +1,87 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (void); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_caller (void (*some_fn_ptr) (void), int a) + { + some_fn_ptr (a); + } + + and verify that the API complains about the mismatching arg + counts. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the function ptr type. */ + gcc_jit_type *fn_ptr_type = + gcc_jit_context_new_function_ptr_type (ctxt, NULL, + void_type, + 0, NULL, 0); + + /* Build the test_fn. */ + gcc_jit_param *param_fn_ptr = + gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr"); + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, int_type, "a"); + gcc_jit_param *params[2]; + params[0] = param_fn_ptr; + params[1] = param_a; + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_caller", + 2, params, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + /* some_fn_ptr (a); */ + gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call_through_ptr ( + ctxt, + NULL, + gcc_jit_param_as_rvalue (param_fn_ptr), + 1, &arg)); + /* the above has too many args. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that mismatching arg count leads to the API giving a NULL + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_call_through_ptr:" + " too many arguments to fn_ptr:" + " some_fn_ptr (got 1 args, expected 0)"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c b/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c new file mode 100644 index 00000000000..7306ffd0cbc --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c @@ -0,0 +1,87 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (void *ptr); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern void called_function (void *ptr); + + void + test_fn () + { + called_function (42); + } + + and verify that the API complains about the mismatching argument + type ("int" vs "void *"). */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *void_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Declare the imported function. */ + gcc_jit_param *param = + gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr"); + gcc_jit_function *called_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 1, ¶m, + 0); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + /* called_function (42); */ + gcc_jit_rvalue *arg = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + called_fn, + 1, &arg)); + /* the above has the wrong type for argument 1. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call:" + " mismatching types for argument 1" + " of function \"called_function\":" + " assignment to param ptr (type: void *)" + " from (int)42 (type: int)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c b/gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c new file mode 100644 index 00000000000..1e8dbbc54e7 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c @@ -0,0 +1,87 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (void); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern void called_function (int p); + + void + test_caller () + { + called_function (); // missing arg + } + + and verify that the API complains about the missing argument. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Declare the imported function. */ + gcc_jit_param *param_p = + gcc_jit_context_new_param (ctxt, NULL, int_type, "p"); + gcc_jit_function *called_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 1, ¶m_p, + 0); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_caller", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + /* called_function (); */ + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + called_fn, + 0, NULL)); + /* the above has the wrong arg count. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +extern void +called_function (void) +{ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that mismatching arg count leads to the API giving a NULL + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call:" + " not enough arguments to function \"called_function\"" + " (got 0 args, expected 1)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c b/gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c new file mode 100644 index 00000000000..a50fc975318 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c @@ -0,0 +1,89 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (void); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern void called_function (); + + void + test_caller (int a) + { + called_function (a); + } + + and verify that the API complains about the mismatching arg + counts. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Declare the imported function. */ + gcc_jit_function *called_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 0, NULL, + 0); + + /* Build the test_fn. */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, int_type, "a"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_caller", + 1, ¶m_a, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + /* called_function (a); */ + gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a); + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + called_fn, + 1, &arg)); + /* the above has the wrong arg count. */ + gcc_jit_block_end_with_void_return (block, NULL); +} + +extern void +called_function (void) +{ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that mismatching arg count leads to the API giving a NULL + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_call:" + " too many arguments to function \"called_function\"" + " (got 1 args, expected 0)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c new file mode 100644 index 00000000000..75171d72218 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c @@ -0,0 +1,95 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +struct foo +{ + int x; + int y; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_bogus_dereference () + { + struct foo tmp; + tmp->x = tmp->y; + } + i.e. where tmp is *not* a pointer. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Map "struct foo". */ + gcc_jit_field *x = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "x"); + gcc_jit_field *y = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "y"); + gcc_jit_field *foo_fields[] = {x, y}; + gcc_jit_struct *struct_foo = + gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields); + + /* Build the test function. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_bogus_dereference", + 0, NULL, + 0); + gcc_jit_lvalue *tmp = + gcc_jit_function_new_local (test_fn, NULL, + gcc_jit_struct_as_type (struct_foo), + "tmp"); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + /* Erroneous: tmp->x = ... */ + gcc_jit_lvalue *lvalue = + gcc_jit_rvalue_dereference_field ( + gcc_jit_lvalue_as_rvalue (tmp), + NULL, + x); + + /* Erroneous: ... = tmp->y; */ + gcc_jit_rvalue *rvalue = + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_lvalue_as_rvalue (tmp), + NULL, + y)); + + gcc_jit_block_add_assignment ( + block, + NULL, + lvalue, rvalue); + + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_rvalue_dereference_field:" + " dereference of non-pointer tmp (type: struct foo)" + " when accessing ->x")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c new file mode 100644 index 00000000000..7b97ab16658 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c @@ -0,0 +1,55 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + int test_bogus_dereference_read (int i) + { + return *i; + } + i.e. where i is *not* a pointer. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the test function. */ + gcc_jit_param *param_i = + gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_bogus_dereference_read", + 1, ¶m_i, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + /* Erroneous: "return *i;" */ + gcc_jit_block_end_with_return ( + block, + NULL, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference ( + gcc_jit_param_as_rvalue (param_i), + NULL))); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_rvalue_dereference:" + " dereference of non-pointer i (type: int)")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c b/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c new file mode 100644 index 00000000000..67b712ee185 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c @@ -0,0 +1,27 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Trigger an API error by passing bad data. */ + gcc_jit_context_get_type (ctxt, 42); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_get_type:" + " unrecognized value for enum gcc_jit_types: 42")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c b/gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c new file mode 100644 index 00000000000..a3540b2cb37 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c @@ -0,0 +1,34 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to access an array at an index that isn't of a numeric + type and verify that the API complains about the bad type. + */ + gcc_jit_rvalue *string = + gcc_jit_context_new_string_literal (ctxt, + "hello world"); + + (void)gcc_jit_context_new_array_access ( + ctxt, NULL, + string, /* ptr */ + string /* index, not of numeric type */); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_array_access:" + " index: \"hello world\" (type: const char *)" + " is not of numeric type"); +} diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c new file mode 100644 index 00000000000..83d212d0985 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c @@ -0,0 +1,61 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_fn () + { + int i; + i = "this is not an int"; + } + + and verify that the API complains about the mismatching types + in the assignment. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + gcc_jit_lvalue *i = + gcc_jit_function_new_local ( + test_fn, NULL, int_type, "i"); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + gcc_jit_block_add_assignment ( + block, NULL, + i, /* of type int */ + gcc_jit_context_new_string_literal ( + ctxt, "this is not an int")); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_add_assignment:" + " mismatching types:" + " assignment to i (type: int)" + " from \"this is not an int\" (type: const char *)"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c new file mode 100644 index 00000000000..203c4cae532 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c @@ -0,0 +1,80 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + struct foo; + + extern void called_function (struct foo *ptr); + + void + test_fn () + { + struct foo f; + called_function (f); + } + + and verify that we get a type error (foo * vs foo). + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_struct *struct_foo = + gcc_jit_context_new_opaque_struct (ctxt, NULL, "foo"); + gcc_jit_type *foo_ptr = + gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo)); + gcc_jit_param *param = + gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "ptr"); + + gcc_jit_function *called_function = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 1, ¶m, + 0); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + gcc_jit_lvalue *f = + gcc_jit_function_new_local ( + test_fn, NULL, gcc_jit_struct_as_type (struct_foo), "f"); + + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (f); + + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call ( + ctxt, NULL, + called_function, + 1, &arg)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_call:" + " mismatching types for argument 1" + " of function \"called_function\":" + " assignment to param ptr (type: struct foo *)" + " from f (type: struct foo)"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-missing-return.c b/gcc/testsuite/jit.dg/test-error-missing-return.c new file mode 100644 index 00000000000..5e2434671a1 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-missing-return.c @@ -0,0 +1,40 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + int + test_fn () + { + } + and verify that the API complains about the lack of + a returned value. + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + (void)gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_fn", + 0, NULL, + 0); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "function test_fn returns non-void (type: int)" + " but has no blocks"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c new file mode 100644 index 00000000000..0592f55cffd --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c @@ -0,0 +1,37 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Trigger an API error by passing bad data. */ + (void)gcc_jit_context_new_binary_op ( + ctxt, + NULL, + + /* Non-valid enum value: */ + (enum gcc_jit_binary_op) 42, + + /* These aren't valid either: */ + NULL, /* gcc_jit_type *result_type, */ + NULL, NULL); /* gcc_jit_rvalue *a, gcc_jit_rvalue *b */ + +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_binary_op:" + " unrecognized value for enum gcc_jit_binary_op: 42")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c b/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c new file mode 100644 index 00000000000..f9772de2b6f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c @@ -0,0 +1,41 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Trigger an API error by passing bad data. */ + (void)gcc_jit_context_new_function ( + ctxt, + NULL, + + /* Non-valid enum value: */ + (enum gcc_jit_function_kind)42, + + int_type, /* gcc_jit_type *return_type, */ + "foo", /* const char *name, */ + 0, /* int num_params, */ + NULL, /* gcc_jit_param **params, */ + 0); /* int is_variadic */ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_function:" + " unrecognized value for enum gcc_jit_function_kind: 42")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c new file mode 100644 index 00000000000..faab139c685 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c @@ -0,0 +1,36 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Trigger an API error by passing bad data. */ + (void)gcc_jit_context_new_unary_op ( + ctxt, + NULL, + + /* Non-valid enum value: */ + (enum gcc_jit_unary_op) 42, + + /* These aren't valid either: */ + NULL, /* gcc_jit_type *result_type, */ + NULL); /* gcc_jit_rvalue *rvalue */ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_context_new_unary_op:" + " unrecognized value for enum gcc_jit_unary_op: 42")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c new file mode 100644 index 00000000000..ea4390b2b07 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c @@ -0,0 +1,31 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Trigger an API error by passing bad data. */ + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + NULL, /* error: this must be non-NULL */ + "hello_world", + 0, NULL, + 0); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_function: NULL return_type"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-return-within-void-function.c b/gcc/testsuite/jit.dg/test-error-return-within-void-function.c new file mode 100644 index 00000000000..1b0e9c839d2 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-return-within-void-function.c @@ -0,0 +1,54 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_fn () + { + return 42; + } + + and verify that the API complains about the return + of a value within a function with "void" return. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, /* "void" return */ + "test_fn", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + /* "return 42;" (i.e. non-void) */ + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the "return 42" leads to the API giving a NULL + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_end_with_return:" + " mismatching types: return of (int)42 (type: int)" + " in function test_fn (return type: void)"); +} + diff --git a/gcc/testsuite/jit.dg/test-error-unreachable-block.c b/gcc/testsuite/jit.dg/test-error-unreachable-block.c new file mode 100644 index 00000000000..10806bd6986 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-unreachable-block.c @@ -0,0 +1,50 @@ +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_fn () + { + return; + + return; + } + where the second block is unreachable. + */ + gcc_jit_type *void_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "test_fn", + 0, NULL, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "a"); + gcc_jit_block *unreachable = + gcc_jit_function_new_block (test_fn, "b"); + + gcc_jit_block_end_with_void_return (initial, NULL); + + gcc_jit_block_end_with_void_return (unreachable, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "unreachable block: b"); +} diff --git a/gcc/testsuite/jit.dg/test-error-unterminated-block.c b/gcc/testsuite/jit.dg/test-error-unterminated-block.c new file mode 100644 index 00000000000..491f09f12a3 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-unterminated-block.c @@ -0,0 +1,42 @@ +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + test_fn () + { + initial: + } + with an unterminated block. + */ + gcc_jit_type *void_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "test_fn", + 0, NULL, + 0); + (void)gcc_jit_function_new_block (test_fn, "initial"); + /* Error: the above block isn't terminated. */ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "unterminated block in test_fn: initial"); +} diff --git a/gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c b/gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c new file mode 100644 index 00000000000..46f4f4863d8 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c @@ -0,0 +1,29 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to build an rvalue from a double with a non-numeric type + and verify that the API complains about the bad type. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + (void)gcc_jit_context_new_rvalue_from_double (ctxt, void_type, 42.0); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_context_new_rvalue_from_double:" + " not a numeric type: void"); +} diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c new file mode 100644 index 00000000000..eb986f38e25 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-expressions.c @@ -0,0 +1,896 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> +#include <stdbool.h> + +#include "libgccjit.h" + +#include "harness.h" + +/********************************************************************** + Unary ops + **********************************************************************/ + +static const char * +make_test_of_unary_op (gcc_jit_context *ctxt, + gcc_jit_type *type, + enum gcc_jit_unary_op op, + const char *funcname) +{ + /* Make a test function of the form: + T test_unary_op (T a) + { + return OP a; + } + and return a debug dump of the OP so that + the caller can sanity-check the debug dump implementation. + */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, type, "a"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + type, + funcname, + 1, ¶m_a, + 0); + gcc_jit_rvalue *unary_op = gcc_jit_context_new_unary_op ( + ctxt, + NULL, + op, + type, + gcc_jit_param_as_rvalue (param_a)); + + gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, unary_op); + + return gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (unary_op)); +} + + +static void +make_tests_of_unary_ops (gcc_jit_context *ctxt) +{ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + CHECK_STRING_VALUE ( + make_test_of_unary_op (ctxt, + int_type, + GCC_JIT_UNARY_OP_MINUS, + "test_UNARY_OP_MINUS_on_int"), + "-(a)"); + CHECK_STRING_VALUE ( + make_test_of_unary_op (ctxt, + int_type, + GCC_JIT_UNARY_OP_BITWISE_NEGATE, + "test_UNARY_OP_BITWISE_NEGATE_on_int"), + "~(a)"); + CHECK_STRING_VALUE ( + make_test_of_unary_op (ctxt, + int_type, + GCC_JIT_UNARY_OP_LOGICAL_NEGATE, + "test_UNARY_OP_LOGICAL_NEGATE_on_int"), + "!(a)"); +} + +static void +verify_unary_ops (gcc_jit_result *result) +{ + typedef int (*test_fn) (int); + + test_fn test_UNARY_OP_MINUS_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_UNARY_OP_MINUS_on_int"); + CHECK_NON_NULL (test_UNARY_OP_MINUS_on_int); + CHECK_VALUE (test_UNARY_OP_MINUS_on_int (0), 0); + CHECK_VALUE (test_UNARY_OP_MINUS_on_int (42), -42); + CHECK_VALUE (test_UNARY_OP_MINUS_on_int (-5), 5); + + test_fn test_UNARY_OP_BITWISE_NEGATE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_UNARY_OP_BITWISE_NEGATE_on_int"); + CHECK_NON_NULL (test_UNARY_OP_BITWISE_NEGATE_on_int); + CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (0), ~0); + CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (42), ~42); + CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (-5), ~-5); + + test_fn test_UNARY_OP_LOGICAL_NEGATE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_UNARY_OP_LOGICAL_NEGATE_on_int"); + CHECK_NON_NULL (test_UNARY_OP_LOGICAL_NEGATE_on_int); + CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (0), 1); + CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (42), 0); + CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (-5), 0); + +} + +/********************************************************************** + Binary ops + **********************************************************************/ + +static const char * +make_test_of_binary_op (gcc_jit_context *ctxt, + gcc_jit_type *type, + enum gcc_jit_binary_op op, + const char *funcname) +{ + /* Make a test function of the form: + T test_binary_op (T a, T b) + { + return a OP b; + } + */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, type, "b"); + gcc_jit_param *params[] = {param_a, param_b}; + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + type, + funcname, + 2, params, + 0); + gcc_jit_rvalue *binary_op = + gcc_jit_context_new_binary_op ( + ctxt, + NULL, + op, + type, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_param_as_rvalue (param_b)); + + gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, binary_op); + + return gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (binary_op)); +} + + +static void +make_tests_of_binary_ops (gcc_jit_context *ctxt) +{ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Test binary ops. */ + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_PLUS, + "test_BINARY_OP_PLUS_on_int"), + "a + b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_MINUS, + "test_BINARY_OP_MINUS_on_int"), + "a - b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_MULT, + "test_BINARY_OP_MULT_on_int"), + "a * b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_DIVIDE, + "test_BINARY_OP_DIVIDE_on_int"), + "a / b"); + /* TODO: test for DIVIDE on float or double */ + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_MODULO, + "test_BINARY_OP_MODULO_on_int"), + "a % b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_BITWISE_AND, + "test_BINARY_OP_BITWISE_AND_on_int"), + "a & b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_BITWISE_XOR, + "test_BINARY_OP_BITWISE_XOR_on_int"), + "a ^ b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_BITWISE_OR, + "test_BINARY_OP_BITWISE_OR_on_int"), + "a | b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_LOGICAL_AND, + "test_BINARY_OP_LOGICAL_AND_on_int"), + "a && b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_LOGICAL_OR, + "test_BINARY_OP_LOGICAL_OR_on_int"), + "a || b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_LSHIFT, + "test_BINARY_OP_LSHIFT_on_int"), + "a << b"); + CHECK_STRING_VALUE ( + make_test_of_binary_op (ctxt, + int_type, + GCC_JIT_BINARY_OP_RSHIFT, + "test_BINARY_OP_RSHIFT_on_int"), + "a >> b"); +} + +static void +verify_binary_ops (gcc_jit_result *result) +{ + typedef int (*test_fn) (int, int); + + test_fn test_BINARY_OP_PLUS_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_PLUS_on_int"); + CHECK_NON_NULL (test_BINARY_OP_PLUS_on_int); + CHECK_VALUE (test_BINARY_OP_PLUS_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_PLUS_on_int (1, 2), 3); + CHECK_VALUE (test_BINARY_OP_PLUS_on_int (100, -1), 99); + CHECK_VALUE (test_BINARY_OP_PLUS_on_int (-1, -4), -5); + + test_fn test_BINARY_OP_MINUS_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_MINUS_on_int"); + CHECK_NON_NULL (test_BINARY_OP_MINUS_on_int); + CHECK_VALUE (test_BINARY_OP_MINUS_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_MINUS_on_int (1, 2), -1); + CHECK_VALUE (test_BINARY_OP_MINUS_on_int (100, -1), 101); + CHECK_VALUE (test_BINARY_OP_MINUS_on_int (-1, -4), 3); + + test_fn test_BINARY_OP_MULT_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_MULT_on_int"); + CHECK_NON_NULL (test_BINARY_OP_MULT_on_int); + CHECK_VALUE (test_BINARY_OP_MULT_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_MULT_on_int (1, 2), 2); + CHECK_VALUE (test_BINARY_OP_MULT_on_int (100, -1), -100); + CHECK_VALUE (test_BINARY_OP_MULT_on_int (-1, -4), 4); + CHECK_VALUE (test_BINARY_OP_MULT_on_int (7, 10), 70); + + test_fn test_BINARY_OP_DIVIDE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_DIVIDE_on_int"); + CHECK_NON_NULL (test_BINARY_OP_DIVIDE_on_int); + CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (7, 2), 3); + CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (100, -1), (100 / -1)); + CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (-1, -4), (-1 / -4)); + CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (60, 5), 12); + + /* TODO: test for DIVIDE on float or double */ + + test_fn test_BINARY_OP_MODULO_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_MODULO_on_int"); + CHECK_NON_NULL (test_BINARY_OP_MODULO_on_int); + CHECK_VALUE (test_BINARY_OP_MODULO_on_int (7, 2), 1); + CHECK_VALUE (test_BINARY_OP_MODULO_on_int (100, -1), (100 % -1)); + CHECK_VALUE (test_BINARY_OP_MODULO_on_int (-1, -4), (-1 % -4)); + CHECK_VALUE (test_BINARY_OP_MODULO_on_int (60, 5), 0); + + test_fn test_BINARY_OP_BITWISE_AND_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_BITWISE_AND_on_int"); + CHECK_NON_NULL (test_BINARY_OP_BITWISE_AND_on_int); + CHECK_VALUE (test_BINARY_OP_BITWISE_AND_on_int (0xf0f0, 0x7777), 0x7070); + + test_fn test_BINARY_OP_BITWISE_XOR_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_BITWISE_XOR_on_int"); + CHECK_NON_NULL (test_BINARY_OP_BITWISE_XOR_on_int); + CHECK_VALUE (test_BINARY_OP_BITWISE_XOR_on_int (0xf0f0, 0x7777), 0x8787); + + test_fn test_BINARY_OP_BITWISE_OR_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_BITWISE_OR_on_int"); + CHECK_NON_NULL (test_BINARY_OP_BITWISE_OR_on_int); + CHECK_VALUE (test_BINARY_OP_BITWISE_OR_on_int (0xf0f0, 0x7777), 0xf7f7); + + test_fn test_BINARY_OP_LOGICAL_AND_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_LOGICAL_AND_on_int"); + CHECK_NON_NULL (test_BINARY_OP_LOGICAL_AND_on_int); + CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (42, 0), 0); + CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, -13), 0); + CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (1997, 1998), 1); + + test_fn test_BINARY_OP_LOGICAL_OR_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_LOGICAL_OR_on_int"); + CHECK_NON_NULL (test_BINARY_OP_LOGICAL_OR_on_int); + CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (42, 0), 1); + CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, -13), 1); + CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (1997, 1998), 1); + + test_fn test_BINARY_OP_LSHIFT_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_LSHIFT_on_int"); + CHECK_NON_NULL (test_BINARY_OP_LSHIFT_on_int); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 1), 0); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 2), 0); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 0), 1); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 1), 2); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 2), 4); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 3), 8); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 0), 3); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 1), 6); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 5), 3 * 32); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 0), 42); + CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 1), 84); + + test_fn test_BINARY_OP_RSHIFT_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_BINARY_OP_RSHIFT_on_int"); + CHECK_NON_NULL (test_BINARY_OP_RSHIFT_on_int); + CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (0, 0), 0); + CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 0), 42); + CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 1), 21); + CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 2), 10); +} + +/********************************************************************** + Comparisons + **********************************************************************/ + +static const char * +make_test_of_comparison (gcc_jit_context *ctxt, + gcc_jit_type *type, + enum gcc_jit_comparison op, + const char *funcname) +{ + /* Make a test function of the form: + bool test_comparison_op (T a, T b) + { + return a OP b; + } + */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, type, "b"); + gcc_jit_param *params[] = {param_a, param_b}; + gcc_jit_type *bool_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + bool_type, + funcname, + 2, params, + 0); + gcc_jit_rvalue *comparison = + gcc_jit_context_new_comparison ( + ctxt, + NULL, + op, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_param_as_rvalue (param_b)); + + gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, comparison); + + return gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (comparison)); +} + +static void +make_tests_of_comparisons (gcc_jit_context *ctxt) +{ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_EQ, + "test_COMPARISON_EQ_on_int"), + "a == b"); + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_NE, + "test_COMPARISON_NE_on_int"), + "a != b"); + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_LT, + "test_COMPARISON_LT_on_int"), + "a < b"); + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_LE, + "test_COMPARISON_LE_on_int"), + "a <= b"); + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_GT, + "test_COMPARISON_GT_on_int"), + "a > b"); + CHECK_STRING_VALUE ( + make_test_of_comparison (ctxt, + int_type, + GCC_JIT_COMPARISON_GE, + "test_COMPARISON_GE_on_int"), + "a >= b"); +} + +static void +verify_comparisons (gcc_jit_result *result) +{ + typedef bool (*test_fn) (int, int); + + test_fn test_COMPARISON_EQ_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_EQ_on_int"); + CHECK_NON_NULL (test_COMPARISON_EQ_on_int); + CHECK_VALUE (test_COMPARISON_EQ_on_int (0, 0), 1); + CHECK_VALUE (test_COMPARISON_EQ_on_int (1, 2), 0); + + test_fn test_COMPARISON_NE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_NE_on_int"); + CHECK_NON_NULL (test_COMPARISON_NE_on_int); + CHECK_VALUE (test_COMPARISON_NE_on_int (0, 0), 0); + CHECK_VALUE (test_COMPARISON_NE_on_int (1, 2), 1); + + test_fn test_COMPARISON_LT_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_LT_on_int"); + CHECK_NON_NULL (test_COMPARISON_LT_on_int); + CHECK_VALUE (test_COMPARISON_LT_on_int (0, 0), 0); + CHECK_VALUE (test_COMPARISON_LT_on_int (1, 2), 1); + CHECK_VALUE (test_COMPARISON_LT_on_int (2, 1), 0); + CHECK_VALUE (test_COMPARISON_LT_on_int (-2, 1), 1); + + test_fn test_COMPARISON_LE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_LE_on_int"); + CHECK_NON_NULL (test_COMPARISON_LE_on_int); + CHECK_VALUE (test_COMPARISON_LE_on_int (0, 0), 1); + CHECK_VALUE (test_COMPARISON_LE_on_int (1, 2), 1); + CHECK_VALUE (test_COMPARISON_LE_on_int (2, 1), 0); + + test_fn test_COMPARISON_GT_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_GT_on_int"); + CHECK_NON_NULL (test_COMPARISON_GT_on_int); + CHECK_VALUE (test_COMPARISON_GT_on_int (0, 0), 0); + CHECK_VALUE (test_COMPARISON_GT_on_int (1, 2), 0); + CHECK_VALUE (test_COMPARISON_GT_on_int (2, 1), 1); + + test_fn test_COMPARISON_GE_on_int = + (test_fn)gcc_jit_result_get_code (result, + "test_COMPARISON_GE_on_int"); + CHECK_NON_NULL (test_COMPARISON_GE_on_int); + CHECK_VALUE (test_COMPARISON_GE_on_int (0, 0), 1); + CHECK_VALUE (test_COMPARISON_GE_on_int (1, 2), 0); + CHECK_VALUE (test_COMPARISON_GE_on_int (2, 1), 1); +} + +/********************************************************************** + Casts + **********************************************************************/ + +static const char* +make_test_of_cast (gcc_jit_context *ctxt, + gcc_jit_type *input_type, + gcc_jit_type *output_type, + const char *funcname) +{ + /* Make a test function of the form: + OUTPUT_TYPE test_cast_* (INPUT_TYPE a) + { + return (OUTPUT_TYPE)a; + } + */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, input_type, "a"); + gcc_jit_param *params[] = {param_a}; + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + output_type, + funcname, + 1, params, + 0); + gcc_jit_rvalue *cast = + gcc_jit_context_new_cast ( + ctxt, + NULL, + gcc_jit_param_as_rvalue (param_a), + output_type); + gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, cast); + + return gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (cast)); +} + +/* For use by test_cast_from_array_of_ints_to_int_ptr. */ +extern int called_pointer_checking_function (int *ints) +{ + CHECK_VALUE (ints[0], 10); + CHECK_VALUE (ints[1], 4); + return ints[0] * ints[1]; +} + +static void +make_tests_of_casts (gcc_jit_context *ctxt) +{ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *float_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT); + gcc_jit_type *bool_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + gcc_jit_type *array_int_type = + gcc_jit_context_new_array_type (ctxt, NULL, + int_type, + 2); + gcc_jit_type *int_ptr_type = + gcc_jit_type_get_pointer (int_type); + + /* float/int conversions */ + CHECK_STRING_VALUE ( + make_test_of_cast (ctxt, + float_type, + int_type, + "test_cast_from_float_to_int"), + "(int)a"); + CHECK_STRING_VALUE ( + make_test_of_cast (ctxt, + int_type, + float_type, + "test_cast_from_int_to_float"), + "(float)a"); + + /* bool/int conversions */ + CHECK_STRING_VALUE ( + make_test_of_cast (ctxt, + bool_type, + int_type, + "test_cast_from_bool_to_int"), + "(int)a"); + CHECK_STRING_VALUE ( + make_test_of_cast (ctxt, + int_type, + bool_type, + "test_cast_from_int_to_bool"), + "(bool)a"); + + /* array/ptr conversions */ + { + gcc_jit_function *test_fn = + gcc_jit_context_new_function ( + ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_cast_from_array_of_ints_to_int_ptr", + 0, NULL, + 0); + /* Equivalent to: + int test_cast_from_array_of_ints_to_int_ptr (void) + { + int array[2]; + array[0] = 10; + array[1] = 4; + return called_pointer_checking_function (array); + } + */ + + gcc_jit_param *param_ints = + gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ints"); + gcc_jit_function *called_fn = + gcc_jit_context_new_function ( + ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "called_pointer_checking_function", + 1, ¶m_ints, + 0); + + gcc_jit_lvalue *array = + gcc_jit_function_new_local (test_fn, NULL, + array_int_type, + "array"); + gcc_jit_block *block = + gcc_jit_function_new_block (test_fn, "block"); + /* array[0] = 10; */ + gcc_jit_block_add_assignment ( + block, NULL, + gcc_jit_context_new_array_access ( + ctxt, NULL, + gcc_jit_lvalue_as_rvalue (array), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 10)); + /* array[1] = 4; */ + gcc_jit_block_add_assignment ( + block, NULL, + gcc_jit_context_new_array_access ( + ctxt, NULL, + gcc_jit_lvalue_as_rvalue (array), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 4)); + gcc_jit_rvalue *cast = + gcc_jit_context_new_cast ( + ctxt, + NULL, + /* We need a get_address here. */ + gcc_jit_lvalue_get_address (array, NULL), + int_ptr_type); + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_context_new_call ( + ctxt, NULL, + called_fn, + 1, &cast)); + + CHECK_STRING_VALUE ( + gcc_jit_object_get_debug_string ( + gcc_jit_rvalue_as_object (cast)), + "(int *)&array"); + } +} + +static void +verify_casts (gcc_jit_result *result) +{ + /* float to int */ + { + typedef int (*fn_type) (float); + fn_type test_cast_from_float_to_int = + (fn_type)gcc_jit_result_get_code (result, + "test_cast_from_float_to_int"); + CHECK_NON_NULL (test_cast_from_float_to_int); + CHECK_VALUE (test_cast_from_float_to_int (4.2), 4); + } + + /* int to float */ + { + typedef float (*fn_type) (int); + fn_type test_cast_from_int_to_float = + (fn_type)gcc_jit_result_get_code (result, + "test_cast_from_int_to_float"); + CHECK_NON_NULL (test_cast_from_int_to_float); + CHECK_VALUE (test_cast_from_int_to_float (4), 4.0); + } + + /* bool to int */ + { + typedef int (*fn_type) (bool); + fn_type test_cast_from_bool_to_int = + (fn_type)gcc_jit_result_get_code (result, + "test_cast_from_bool_to_int"); + CHECK_NON_NULL (test_cast_from_bool_to_int); + CHECK_VALUE (test_cast_from_bool_to_int (0), 0); + CHECK_VALUE (test_cast_from_bool_to_int (1), 1); + } + + /* int to bool */ + { + typedef bool (*fn_type) (int); + fn_type test_cast_from_int_to_bool = + (fn_type)gcc_jit_result_get_code (result, + "test_cast_from_int_to_bool"); + CHECK_NON_NULL (test_cast_from_int_to_bool); + CHECK_VALUE (test_cast_from_int_to_bool (0), 0); + CHECK_VALUE (test_cast_from_int_to_bool (1), 1); + } + + /* array to ptr */ + { + typedef int (*fn_type) (void); + fn_type test_cast_from_array_of_ints_to_int_ptr = + (fn_type)gcc_jit_result_get_code ( + result, + "test_cast_from_array_of_ints_to_int_ptr"); + CHECK_NON_NULL (test_cast_from_array_of_ints_to_int_ptr); + CHECK_VALUE (test_cast_from_array_of_ints_to_int_ptr (), 40); + } +} + +/********************************************************************** + Dereferences + **********************************************************************/ + +static void +make_tests_of_dereferences (gcc_jit_context *ctxt) +{ + /* + int test_dereference_read (int *ptr) + { + return *ptr; + } + void test_dereference_write (int *ptr, int i) + { + *ptr = i; + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *int_ptr_type = + gcc_jit_type_get_pointer (int_type); + { + gcc_jit_param *param_ptr = + gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr"); + gcc_jit_function *test_dereference_read = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_dereference_read", + 1, ¶m_ptr, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_dereference_read, "initial"); + gcc_jit_block_end_with_return ( + initial, + NULL, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference ( + gcc_jit_param_as_rvalue (param_ptr), + NULL))); + } + + { + gcc_jit_param *param_ptr = + gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr"); + gcc_jit_param *param_i = + gcc_jit_context_new_param (ctxt, NULL, int_type, "i"); + gcc_jit_param *params[] = {param_ptr, param_i}; + gcc_jit_function *test_dereference_write = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_dereference_write", + 2, params, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_dereference_write, "initial"); + gcc_jit_block_add_assignment ( + initial, + NULL, + gcc_jit_rvalue_dereference ( + gcc_jit_param_as_rvalue (param_ptr), + NULL), + gcc_jit_param_as_rvalue (param_i)); + gcc_jit_block_end_with_void_return (initial, NULL); + } +} + +static void +verify_dereferences (gcc_jit_result *result) +{ + int a = 42; + int b = -99; + + { + typedef int (*test_read) (int *); + test_read test_dereference_read = + (test_read)gcc_jit_result_get_code (result, + "test_dereference_read"); + CHECK_NON_NULL (test_dereference_read); + CHECK_VALUE (test_dereference_read (&a), 42); + CHECK_VALUE (test_dereference_read (&b), -99); + } + + { + typedef void (*test_write) (int *, int); + test_write test_dereference_write = + (test_write)gcc_jit_result_get_code (result, + "test_dereference_write"); + CHECK_NON_NULL (test_dereference_write); + test_dereference_write (&a, -55); + CHECK_VALUE (a, -55); + + test_dereference_write (&b, 404); + CHECK_VALUE (b, 404); + } +} + +/********************************************************************** + gcc_jit_lvalue_get_address + **********************************************************************/ + +int test_global; +static void +make_test_of_get_address (gcc_jit_context *ctxt) +{ + /* + void *test_get_address (void) + { + return &test_global; + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_lvalue *test_global = + gcc_jit_context_new_global ( + ctxt, + NULL, + int_type, + "test_global"); + + gcc_jit_type *void_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + + gcc_jit_function *test_get_address = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_ptr_type, + "test_get_address", + 0, NULL, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_get_address, "initial"); + gcc_jit_block_end_with_return ( + initial, + NULL, + gcc_jit_lvalue_get_address ( + test_global, + NULL)); +} + +static void +verify_get_address (gcc_jit_result *result) +{ + typedef void *(*test_fn) (void); + test_fn test_get_address = + (test_fn)gcc_jit_result_get_code (result, + "test_get_address"); + CHECK_NON_NULL (test_get_address); + CHECK_VALUE (test_get_address (), &test_global); +} + +/********************************************************************** + Code for harness + **********************************************************************/ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + make_tests_of_unary_ops (ctxt); + make_tests_of_binary_ops (ctxt); + make_tests_of_comparisons (ctxt); + make_tests_of_casts (ctxt); + make_tests_of_dereferences (ctxt); + make_test_of_get_address (ctxt); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + verify_unary_ops (result); + verify_binary_ops (result); + verify_comparisons (result); + verify_casts (result); + verify_dereferences (result); + verify_get_address (result); +} diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c new file mode 100644 index 00000000000..b2aaece25e4 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-factorial.c @@ -0,0 +1,103 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + int + my_factorial (int x) + { + if (x < 2) + return x; + else + return x * my_factorial (x - 1); + } + + and see if the optimizer eliminates the recursion (it does). + */ + gcc_jit_type *the_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *return_type = the_type; + + gcc_jit_param *x = + gcc_jit_context_new_param (ctxt, NULL, the_type, "x"); + gcc_jit_param *params[1] = {x}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + return_type, + "my_factorial", + 1, params, 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + gcc_jit_block *on_true = + gcc_jit_function_new_block (func, "on_true"); + gcc_jit_block *on_false = + gcc_jit_function_new_block (func, "on_false"); + + /* if (x < 2) */ + gcc_jit_block_end_with_conditional ( + initial, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_LT, + gcc_jit_param_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 2)), + on_true, + on_false); + + /* true branch: */ + /* return x */ + gcc_jit_block_end_with_return ( + on_true, + NULL, + gcc_jit_param_as_rvalue (x)); + + /* false branch: */ + gcc_jit_rvalue *x_minus_1 = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MINUS, the_type, + gcc_jit_param_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 1)); + gcc_jit_block_end_with_return ( + on_false, + NULL, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, the_type, + gcc_jit_param_as_rvalue (x), + /* my_factorial (x - 1) */ + gcc_jit_context_new_call ( + ctxt, NULL, + func, + 1, &x_minus_1))); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_factorial_fn_type) (int); + CHECK_NON_NULL (result); + my_factorial_fn_type my_factorial = + (my_factorial_fn_type)gcc_jit_result_get_code (result, "my_factorial"); + CHECK_NON_NULL (my_factorial); + int val = my_factorial (10); + note ("my_factorial returned: %d", val); + CHECK_VALUE (val, 3628800); +} + diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c new file mode 100644 index 00000000000..607bd564221 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-fibonacci.c @@ -0,0 +1,136 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + const int FIRST_LINE = __LINE__ + 4; + /* Let's try to inject the equivalent of: +0000000001111111111222222222233333333334444444444555555555566666666667 +1234567890123456789012345678901234567890123456789012345678901234567890 +FIRST_LINE + 0: int +FIRST_LINE + 1: my_fibonacci (int x) +FIRST_LINE + 2: { +FIRST_LINE + 3: if (x < 2) +FIRST_LINE + 4: return x; +FIRST_LINE + 5: else +FIRST_LINE + 6: return my_fibonacci (x - 1) + my_fibonacci (x - 2); +FIRST_LINE + 7: } +0000000001111111111222222222233333333334444444444555555555566666666667 +1234567890123456789012345678901234567890123456789012345678901234567890 + + where the source locations are set up to point to the commented-out + code above. + It should therefore be possible to step through the generated code + in the debugger, stepping through the above commented-out code + fragement. + */ + gcc_jit_type *the_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *return_type = the_type; + + gcc_jit_param *x = + gcc_jit_context_new_param ( + ctxt, + gcc_jit_context_new_location ( + ctxt, __FILE__, FIRST_LINE + 1, 35), + the_type, "x"); + gcc_jit_param *params[1] = {x}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, + gcc_jit_context_new_location ( + ctxt, __FILE__, FIRST_LINE, 17), + GCC_JIT_FUNCTION_EXPORTED, + return_type, + "my_fibonacci", + 1, params, 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + gcc_jit_block *on_true = + gcc_jit_function_new_block (func, "on_true"); + gcc_jit_block *on_false = + gcc_jit_function_new_block (func, "on_false"); + + /* if (x < 2) */ + gcc_jit_block_end_with_conditional ( + initial, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 19), + gcc_jit_context_new_comparison ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 25), + GCC_JIT_COMPARISON_LT, + gcc_jit_param_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 2)), + on_true, + on_false); + + /* true branch: */ + /* return x */ + gcc_jit_block_end_with_return ( + on_true, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 4, 21), + gcc_jit_param_as_rvalue (x)); + + /* false branch: */ + gcc_jit_rvalue *x_minus_1 = + gcc_jit_context_new_binary_op ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 44), + GCC_JIT_BINARY_OP_MINUS, the_type, + gcc_jit_param_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 1)); + gcc_jit_rvalue *x_minus_2 = + gcc_jit_context_new_binary_op ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 67), + GCC_JIT_BINARY_OP_MINUS, the_type, + gcc_jit_param_as_rvalue (x), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 2)); + gcc_jit_block_end_with_return ( + on_false, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 21), + gcc_jit_context_new_binary_op ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 49), + GCC_JIT_BINARY_OP_PLUS, the_type, + /* my_fibonacci (x - 1) */ + gcc_jit_context_new_call ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 28), + func, + 1, &x_minus_1), + /* my_fibonacci (x - 2) */ + gcc_jit_context_new_call ( + ctxt, + gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 51), + func, + 1, &x_minus_2))); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_fibonacci_fn_type) (int); + CHECK_NON_NULL (result); + my_fibonacci_fn_type my_fibonacci = + (my_fibonacci_fn_type)gcc_jit_result_get_code (result, "my_fibonacci"); + CHECK_NON_NULL (my_fibonacci); + int val = my_fibonacci (10); + note ("my_fibonacci returned: %d", val); + CHECK_VALUE (val, 55); +} diff --git a/gcc/testsuite/jit.dg/test-functions.c b/gcc/testsuite/jit.dg/test-functions.c new file mode 100644 index 00000000000..3d03adae821 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-functions.c @@ -0,0 +1,356 @@ +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +/********************************************************************** + GCC_JIT_FUNCTION_ALWAYS_INLINE and GCC_JIT_FUNCTION_INTERNAL + **********************************************************************/ +static void +create_test_of_hidden_function (gcc_jit_context *ctxt, + enum gcc_jit_function_kind hidden_kind, + const char *hidden_func_name, + const char *visible_func_name) +{ + /* Let's try to inject the equivalent of: + static double hidden_mult (double a, double b) + { + return x * x; + } + double my_square (double x) + { + return my_mult (x, x); + } + + where hidden_mult can potentially be + inline __attribute__((always_inline)). */ + gcc_jit_type *double_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + + /* Create "my_mult" */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, double_type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, double_type, "b"); + gcc_jit_param *params[2] = {param_a, param_b}; + gcc_jit_function *my_mult = + gcc_jit_context_new_function (ctxt, NULL, + hidden_kind, + double_type, + hidden_func_name, + 2, params, + 0); + gcc_jit_block *body_of_my_mult = + gcc_jit_function_new_block (my_mult, NULL); + gcc_jit_block_end_with_return ( + body_of_my_mult, NULL, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + double_type, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_param_as_rvalue (param_b))); + + /* Create "my_square" */ + gcc_jit_param *param_x = + gcc_jit_context_new_param (ctxt, NULL, double_type, "x"); + gcc_jit_function *my_square = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + double_type, + visible_func_name, + 1, ¶m_x, + 0); + gcc_jit_block *body_of_my_square = + gcc_jit_function_new_block (my_square, NULL); + gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_x), + gcc_jit_param_as_rvalue (param_x)}; + gcc_jit_block_end_with_return ( + body_of_my_square, NULL, + gcc_jit_context_new_call ( + ctxt, NULL, + my_mult, + 2, args)); +} + +static void +create_tests_of_hidden_functions (gcc_jit_context *ctxt) +{ + create_test_of_hidden_function (ctxt, + GCC_JIT_FUNCTION_INTERNAL, + "my_internal_mult", + "my_square_with_internal"); + create_test_of_hidden_function (ctxt, + GCC_JIT_FUNCTION_ALWAYS_INLINE, + "my_always_inline_mult", + "my_square_with_always_inline"); +} + +static void +verify_hidden_functions (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + /* GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE + functions should not be accessible in the result. */ + CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_internal_mult")); + CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_always_inline_mult")); + + typedef double (*fn_type) (double); + fn_type my_square_with_internal = + (fn_type)gcc_jit_result_get_code (result, "my_square_with_internal"); + CHECK_NON_NULL (my_square_with_internal); + CHECK_VALUE (my_square_with_internal (5.0), 25.0); + + fn_type my_square_with_always_inline = + (fn_type)gcc_jit_result_get_code (result, "my_square_with_always_inline"); + CHECK_NON_NULL (my_square_with_always_inline); + CHECK_VALUE (my_square_with_always_inline (5.0), 25.0); +} + +/********************************************************************** + Builtin functions + **********************************************************************/ + +static void +create_test_of_builtin_strcmp (gcc_jit_context *ctxt) +{ + /* Let's try to inject the equivalent of: + int + test_of_builtin_strcmp (const char *a, const char *b) + { + return __builtin_strcmp (a, b); + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *const_char_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); + + /* Get the built-in function. */ + gcc_jit_function *builtin_fn = + gcc_jit_context_get_builtin_function (ctxt, "strcmp"); + + CHECK_STRING_VALUE ( + gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)), + "strcmp"); + + /* Build the test_fn. */ + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b"); + gcc_jit_param *params[2] = {param_a, param_b}; + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_of_builtin_strcmp", + 2, params, + 0); + gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a), + gcc_jit_param_as_rvalue (param_b)}; + gcc_jit_rvalue *call = + gcc_jit_context_new_call (ctxt, + NULL, + builtin_fn, + 2, args); + CHECK_STRING_VALUE ( + gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)), + "strcmp (a, b)"); + + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, call); +} + +static void +create_test_of_builtin_trig (gcc_jit_context *ctxt) +{ + /* Let's try to inject the equivalent of: + int + test_of_builtin_trig (double theta) + { + return 2 * sin (theta) * cos (theta); + } + (in theory, optimizable to sin (2 * theta)) + */ + gcc_jit_type *double_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + + /* Get the built-in functions. */ + gcc_jit_function *builtin_sin = + gcc_jit_context_get_builtin_function (ctxt, "sin"); + gcc_jit_function *builtin_cos = + gcc_jit_context_get_builtin_function (ctxt, "cos"); + + /* Build the test_fn. */ + gcc_jit_param *param_theta = + gcc_jit_context_new_param (ctxt, NULL, double_t, "theta"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + double_t, + "test_of_builtin_trig", + 1, ¶m_theta, + 0); + gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)}; + gcc_jit_rvalue *two = + gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2); + gcc_jit_rvalue *ret = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + double_t, + two, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + double_t, + gcc_jit_context_new_call (ctxt, NULL, + builtin_sin, + 1, args), + gcc_jit_context_new_call (ctxt, NULL, + builtin_cos, + 1, args))); + CHECK_STRING_VALUE ( + gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)), + "(double)2 * sin (theta) * cos (theta)"); + + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "initial"); + gcc_jit_block_end_with_return (initial, NULL, ret); +} + +static void +create_use_of_builtins (gcc_jit_context *ctxt) +{ + create_test_of_builtin_strcmp (ctxt); + create_test_of_builtin_trig (ctxt); +} + +static void +verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*fn_type) (const char *, const char *); + CHECK_NON_NULL (result); + + fn_type test_of_builtin_strcmp = + (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp"); + CHECK_NON_NULL (test_of_builtin_strcmp); + + /* Verify that it correctly called strcmp. */ + CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0); + CHECK (test_of_builtin_strcmp ("foo", "bar") > 0); + CHECK (test_of_builtin_strcmp ("bar", "foo") < 0); +} + +static void +verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef double (*fn_type) (double); + CHECK_NON_NULL (result); + + fn_type test_of_builtin_trig = + (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig"); + CHECK_NON_NULL (test_of_builtin_trig); + + /* Verify that it correctly computes + sin (2 * theta) + (perhaps calling sin and cos). */ + CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0 ), 0.0); + CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 ), 1.0); + CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2 ), 0.0); + CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0); + CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI ), 0.0); +} + +static void +verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_test_of_builtin_strcmp (ctxt, result); + verify_test_of_builtin_trig (ctxt, result); +} + +/********************************************************************** + "void" return + **********************************************************************/ + +static void +create_use_of_void_return (gcc_jit_context *ctxt) +{ + /* Let's try to inject the equivalent of: + void + test_of_void_return (int *out) + { + *out = 1; + return; + } + */ + gcc_jit_type *void_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_t = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *int_ptr_t = + gcc_jit_type_get_pointer (int_t); + + /* Build the test_fn. */ + gcc_jit_param *param_out = + gcc_jit_context_new_param (ctxt, NULL, int_ptr_t, "out"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_t, + "test_of_void_return", + 1, ¶m_out, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (test_fn, "initial"); + + gcc_jit_block_add_assignment ( + initial, NULL, + /* "*out = ..." */ + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (param_out), + NULL), + gcc_jit_context_one (ctxt, int_t)); + gcc_jit_block_end_with_void_return (initial, NULL); +} + +static void +verify_void_return (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (int *); + CHECK_NON_NULL (result); + + fn_type test_of_void_return = + (fn_type)gcc_jit_result_get_code (result, "test_of_void_return"); + CHECK_NON_NULL (test_of_void_return); + + int i; + test_of_void_return (&i); + CHECK_VALUE (i, 1); /* ensure correct value was written back */ +} + +/********************************************************************** + Code for harness + **********************************************************************/ + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + create_tests_of_hidden_functions (ctxt); + create_use_of_builtins (ctxt); + create_use_of_void_return (ctxt); +} + + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_hidden_functions (ctxt, result); + verify_use_of_builtins (ctxt, result); + verify_void_return (ctxt, result); +} diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c new file mode 100644 index 00000000000..f363f8f29a5 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-fuzzer.c @@ -0,0 +1,462 @@ +/* Fuzz-testing of libgccjit API. + Currently this triggers internal compiler errors, typically due to type + mismatches. */ +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +#include "libgccjit.h" + +#define TEST_PROVIDES_MAIN +#include "harness.h" + +typedef struct fuzzer +{ + gcc_jit_context *ctxt; + + unsigned int seed; + + int num_types; + gcc_jit_type **types; + + int num_globals; + gcc_jit_lvalue **globals; + + int num_funcs; + gcc_jit_function **funcs; + +} fuzzer; + +static void +fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed); + +static int +fuzzer_randrange (fuzzer *f, int min, int max); + +static gcc_jit_location * +get_random_location (fuzzer *f); + +static gcc_jit_type * +get_random_type (fuzzer *f); + +static gcc_jit_type * +make_random_type (fuzzer *f); + +static gcc_jit_lvalue * +make_random_global (fuzzer *f); + +static gcc_jit_function * +make_random_function (fuzzer *f); + +typedef struct function_fuzzer +{ + fuzzer *f; + + int num_params; + gcc_jit_param **params; + + gcc_jit_function *fn; + + int num_locals; + gcc_jit_lvalue **locals; + + gcc_jit_block *block; + +} function_fuzzer; + +static void +function_fuzzer_add_stmt (function_fuzzer *ff); + +static gcc_jit_lvalue * +get_random_lvalue (function_fuzzer *ff, int max_depth); + +static gcc_jit_rvalue * +get_random_rvalue (function_fuzzer *ff, int max_depth); + +/* fuzzer defns. */ + +static void +fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed) +{ + int i; + memset (f, 0, sizeof (*f)); + f->ctxt = ctxt; + f->seed = seed; + + int num_types = fuzzer_randrange (f, 5, 10); + f->types = malloc (num_types * sizeof (gcc_jit_type *)); + + int num_funcs = fuzzer_randrange (f, 3, 5); + f->funcs = malloc (num_funcs * sizeof (gcc_jit_function *)); + + int num_globals = fuzzer_randrange (f, 5, 10); + f->globals = malloc (num_globals * sizeof (gcc_jit_lvalue *)); + + for (i = 0; i < num_types; i++) + { + gcc_jit_type *type = make_random_type (f); + assert (type); + f->types[f->num_types++] = type; + } + + for (i = 0; i < num_globals; i++) + f->globals[f->num_globals++] = make_random_global (f); + + for (i = 0; i < num_funcs; i++) + f->funcs[f->num_funcs++] = make_random_function (f); +} + +/* Get random int in inclusive range [min, max]. */ + +static int fuzzer_randrange (fuzzer *f, int min, int max) +{ + assert (min <= max); + int i = rand_r (&f->seed); + int result = (i % (max + 1 - min)) + min; + assert (result >= min); + assert (result <= max); + return result; +} + +static gcc_jit_location * +get_random_location (fuzzer *f) +{ + const char *filename = NULL; + + if (fuzzer_randrange (f, 0, 1)) + return NULL; + + switch (fuzzer_randrange (f, 1, 2)) + { + case 1: + filename = "foo.c"; + break; + case 2: + filename = "bar.c"; + break; + } + + return gcc_jit_context_new_location (f->ctxt, + filename, + fuzzer_randrange (f, 1, 1000), + fuzzer_randrange (f, 1, 1000)); +} + +const enum gcc_jit_types types[] = { + GCC_JIT_TYPE_VOID, + + GCC_JIT_TYPE_VOID_PTR, + + GCC_JIT_TYPE_CHAR, + GCC_JIT_TYPE_SIGNED_CHAR, + GCC_JIT_TYPE_UNSIGNED_CHAR, + + GCC_JIT_TYPE_SHORT, + GCC_JIT_TYPE_UNSIGNED_SHORT, + + GCC_JIT_TYPE_INT, + GCC_JIT_TYPE_UNSIGNED_INT, + + GCC_JIT_TYPE_LONG, + GCC_JIT_TYPE_UNSIGNED_LONG, + + GCC_JIT_TYPE_LONG_LONG, + GCC_JIT_TYPE_UNSIGNED_LONG_LONG, + + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_LONG_DOUBLE, + + GCC_JIT_TYPE_CONST_CHAR_PTR, + + GCC_JIT_TYPE_SIZE_T, + + GCC_JIT_TYPE_FILE_PTR +}; +#define NUM_TYPES (sizeof(types)/sizeof(types[0])) + +static gcc_jit_type * +get_random_type (fuzzer *f) +{ + int i = fuzzer_randrange (f, 0, (NUM_TYPES - 1) + f->num_types); + if (i < NUM_TYPES) + return gcc_jit_context_get_type (f->ctxt, types[i]); + assert ((i - NUM_TYPES) < f->num_types); + assert (f->types[i - NUM_TYPES]); + return f->types[i - NUM_TYPES]; +} + +static gcc_jit_type * +make_random_type (fuzzer *f) +{ + switch (fuzzer_randrange (f, 0, 5)) + { + case 0: + return gcc_jit_type_get_pointer (get_random_type (f)); + case 1: + return gcc_jit_type_get_const (get_random_type (f)); + default: + { + /* Create a struct. */ + int num_fields = fuzzer_randrange (f, 0, 10); + gcc_jit_field **fields = \ + malloc (num_fields * sizeof (gcc_jit_field *)); + int i; + for (i = 0; i < num_fields ; i++) + { + char field_name[256]; + sprintf (field_name, "field%i", i); + fields[i] = gcc_jit_context_new_field (f->ctxt, + get_random_location (f), + get_random_type (f), + field_name); + } + char struct_name[256]; + sprintf (struct_name, "s%i", f->num_types); + gcc_jit_struct *struct_ = \ + gcc_jit_context_new_struct_type (f->ctxt, + get_random_location (f), + struct_name, + num_fields, + fields); + free (fields); + return gcc_jit_struct_as_type (struct_); + } + } +} + +static gcc_jit_lvalue * +make_random_global (fuzzer *f) +{ + char global_name[256]; + sprintf (global_name, "g%i", f->num_globals); + return gcc_jit_context_new_global (f->ctxt, + get_random_location (f), + get_random_type (f), + global_name); +} + +static gcc_jit_function * +make_random_function (fuzzer *f) +{ + char func_name[256]; + sprintf (func_name, "fn%i", f->num_funcs); + + function_fuzzer *ff = malloc (sizeof (function_fuzzer)); + memset (ff, 0, sizeof (*ff)); + + ff->f = f; + + ff->num_params = fuzzer_randrange (f, 0, 10); + ff->params = malloc (ff->num_params * sizeof (gcc_jit_param *)); + int i; + for (i = 0; i < ff->num_params; i++) + { + char param_name[256]; + sprintf (param_name, "param%i", i); + ff->params[i] = \ + gcc_jit_context_new_param (f->ctxt, + get_random_location (f), + get_random_type (f), + param_name); + } + + enum gcc_jit_function_kind kind = + ((enum gcc_jit_function_kind) + fuzzer_randrange (f, 0, GCC_JIT_FUNCTION_IMPORTED)); + + ff->fn = \ + gcc_jit_context_new_function ( + f->ctxt, + get_random_location (f), + kind, + get_random_type (f), + func_name, + ff->num_params, + ff->params, + fuzzer_randrange (f, 0, 1)); + ff->block = gcc_jit_function_new_block (ff->fn, NULL); + + /* Create locals. */ + if (kind != GCC_JIT_FUNCTION_IMPORTED) + { + ff->num_locals = fuzzer_randrange (f, 0, 10); + ff->locals = malloc (ff->num_locals * sizeof (gcc_jit_lvalue *)); + for (i = 0; i < ff->num_locals; i++) + { + char local_name[256]; + sprintf (local_name, "local%i", i); + ff->locals[i] = + gcc_jit_function_new_local (ff->fn, + get_random_location (f), + get_random_type (f), + local_name); + } + } + /* TODO: use locals. */ + + if (kind != GCC_JIT_FUNCTION_IMPORTED) + { + /* TODO: create body */ + int num_stmts = fuzzer_randrange (f, 0, 10); + for (i = 0; i < num_stmts; i++) + function_fuzzer_add_stmt (ff); + } + + gcc_jit_block_end_with_return (ff->block, NULL, get_random_rvalue (ff, 3)); + + + gcc_jit_function *result = ff->fn; + + free (ff->params); + free (ff); + + return result; +} + +/* function_fuzzer defns. */ + +static void function_fuzzer_add_stmt (function_fuzzer *ff) +{ + gcc_jit_block_add_eval (ff->block, + get_random_location (ff->f), + get_random_rvalue (ff, 4)); + gcc_jit_block_add_assignment (ff->block, + get_random_location (ff->f), + get_random_lvalue (ff, 4), + get_random_rvalue (ff, 4)); + /* TODO: place more kinds of statement */ + /* TODO: labels */ +} + +static gcc_jit_lvalue *get_random_lvalue (function_fuzzer *ff, int max_depth) +{ + int choice = fuzzer_randrange (ff->f, 0, + ff->num_params + + ff->num_locals + + ff->f->num_globals - 1); + if (choice < ff->num_params) + return gcc_jit_param_as_lvalue (ff->params[choice]); + choice -= ff->num_params; + + if (choice < ff->num_locals) + return ff->locals[choice]; + choice -= ff->num_locals; + + assert (choice < ff->f->num_globals); + return ff->f->globals[choice]; +} + +static gcc_jit_rvalue *get_random_rvalue (function_fuzzer *ff, int max_depth) +{ + int use_lvalue = fuzzer_randrange (ff->f, 0, 1); + if (use_lvalue) + return gcc_jit_lvalue_as_rvalue (get_random_lvalue (ff, max_depth)); + + int choice = fuzzer_randrange (ff->f, 0, 1); + + /* Compound op: */ + switch (choice) + { + case 0: + return gcc_jit_context_new_string_literal (ff->f->ctxt, "hello"); + case 1: + return gcc_jit_context_new_rvalue_from_int ( + ff->f->ctxt, + get_random_type (ff->f), + fuzzer_randrange (ff->f, 0, INT_MAX)); + case 2: + return gcc_jit_context_new_rvalue_from_double ( + ff->f->ctxt, + get_random_type (ff->f), + ((double)fuzzer_randrange (ff->f, 0, INT_MAX)) + / (double)fuzzer_randrange (ff->f, 0, INT_MAX)); + case 3: + return gcc_jit_context_new_unary_op ( + ff->f->ctxt, + get_random_location (ff->f), + ((enum gcc_jit_unary_op) + fuzzer_randrange (ff->f, 0, GCC_JIT_UNARY_OP_LOGICAL_NEGATE)), + get_random_type (ff->f), + get_random_rvalue (ff, max_depth - 1)); + case 4: + return gcc_jit_context_new_binary_op ( + ff->f->ctxt, + get_random_location (ff->f), + ((enum gcc_jit_binary_op) + fuzzer_randrange (ff->f, 0, GCC_JIT_BINARY_OP_LOGICAL_OR)), + get_random_type (ff->f), + get_random_rvalue (ff, max_depth - 1), + get_random_rvalue (ff, max_depth - 1)); + case 5: + return gcc_jit_lvalue_get_address ( + get_random_lvalue (ff, max_depth - 1), + get_random_location (ff->f)); + + /* TODO: + - comparisons + - calls + - array lookup + - fields + - dereferencing */ + } + return NULL; +} + + +/* Top-level defns for use by harness. */ +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + fuzzer f; + int seed = *(int*)user_data; + + fuzzer_init (&f, ctxt, seed); +} + +static int num_completed_compilations = 0; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* We can make no guarantees about whether we built something + valid or not, and the result might have an infinite loop, + so we can't execute it. + + If we survive to reach here, note the fact for DejaGnu. */ + pass ("%s: survived compilation", test); + if (result) + num_completed_compilations++; +} + +static void +test_fuzzer (const char *argv0, int seed) +{ + test_jit (argv0, &seed); +} + +int +main (int argc, char **argv) +{ + int i, seed; + const int NUM_ITERATIONS = 2; + const int NUM_SEEDS = 100; + for (i = 1; i <= NUM_ITERATIONS; i++) + { + for (seed = 0; seed < NUM_SEEDS ; seed++) + { + snprintf (test, sizeof (test), + "%s iteration %d of %d; seed %d of %d", + extract_progname (argv[0]), + i, NUM_ITERATIONS, seed, NUM_SEEDS); + test_fuzzer (argv[0], seed); + } + } + pass ("%s: survived running all tests", extract_progname (argv[0])); + note ("%s: num completed compilations: %d", extract_progname (argv[0]), + num_completed_compilations); + totals (); + + return 0; +} diff --git a/gcc/testsuite/jit.dg/test-hello-world.c b/gcc/testsuite/jit.dg/test-hello-world.c new file mode 100644 index 00000000000..93f737b0624 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-hello-world.c @@ -0,0 +1,72 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + void + hello_world (const char *name) + { + // a test comment + printf ("hello %s\n", name); + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *const_char_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); + gcc_jit_param *param_name = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name"); + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "hello_world", + 1, ¶m_name, + 0); + + gcc_jit_param *param_format = + gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format"); + gcc_jit_function *printf_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + gcc_jit_context_get_type ( + ctxt, GCC_JIT_TYPE_INT), + "printf", + 1, ¶m_format, + 1); + gcc_jit_rvalue *args[2]; + args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n"); + args[1] = gcc_jit_param_as_rvalue (param_name); + + gcc_jit_block *block = gcc_jit_function_new_block (func, NULL); + + gcc_jit_block_add_comment ( + block, NULL, + "a test comment"); + + gcc_jit_block_add_eval ( + block, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + printf_func, + 2, args)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +extern void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (const char *); + CHECK_NON_NULL (result); + fn_type hello_world = + (fn_type)gcc_jit_result_get_code (result, "hello_world"); + CHECK_NON_NULL (hello_world); + hello_world ("world"); + fflush (stdout); +} diff --git a/gcc/testsuite/jit.dg/test-linked-list.c b/gcc/testsuite/jit.dg/test-linked-list.c new file mode 100644 index 00000000000..28871d9f00a --- /dev/null +++ b/gcc/testsuite/jit.dg/test-linked-list.c @@ -0,0 +1,141 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +/* A doubly-linked list, to ensure that the JIT API can cope with + self-referential types. */ +struct node +{ + struct node *prev; + struct node *next; + int value; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + int + test_linked_list (struct node *n) + { + int total = 0; + while (n) + { + total += n->value; + n = n->next; + } + return total; + } + */ + gcc_jit_type *t_int = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_struct *t_node = + gcc_jit_context_new_opaque_struct (ctxt, NULL, "node"); + gcc_jit_type *t_node_ptr = + gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node)); + + gcc_jit_field *f_prev = + gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev"); + gcc_jit_field *f_next = + gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next"); + gcc_jit_field *f_value = + gcc_jit_context_new_field (ctxt, NULL, t_int, "value"); + gcc_jit_field *fields[] = {f_prev, f_next, f_value}; + gcc_jit_struct_set_fields (t_node, NULL, 3, fields); + + /* Build the test function. */ + gcc_jit_param *param_n = + gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n"); + gcc_jit_function *fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + t_int, + "test_linked_list", + 1, ¶m_n, + 0); + /* int total; */ + gcc_jit_lvalue *total = + gcc_jit_function_new_local (fn, NULL, t_int, "total"); + + gcc_jit_block *initial = gcc_jit_function_new_block (fn, "initial"); + gcc_jit_block *loop_test = gcc_jit_function_new_block (fn, "loop_test"); + gcc_jit_block *loop_body = gcc_jit_function_new_block (fn, "loop_body"); + gcc_jit_block *final = gcc_jit_function_new_block (fn, "final"); + + /* total = 0; */ + gcc_jit_block_add_assignment ( + initial, NULL, + total, + gcc_jit_context_zero (ctxt, t_int)); + gcc_jit_block_end_with_jump (initial, NULL, loop_test); + + /* while (n) */ + gcc_jit_block_end_with_conditional ( + loop_test, NULL, + gcc_jit_context_new_comparison (ctxt, NULL, + GCC_JIT_COMPARISON_NE, + gcc_jit_param_as_rvalue (param_n), + gcc_jit_context_null (ctxt, t_node_ptr)), + loop_body, + final); + + /* total += n->value; */ + gcc_jit_block_add_assignment_op ( + loop_body, NULL, + total, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_n), + NULL, + f_value))); + + /* n = n->next; */ + gcc_jit_block_add_assignment ( + loop_body, NULL, + gcc_jit_param_as_lvalue (param_n), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_n), + NULL, + f_next))); + + gcc_jit_block_end_with_jump (loop_body, NULL, loop_test); + + /* return total; */ + gcc_jit_block_end_with_return ( + final, NULL, gcc_jit_lvalue_as_rvalue (total)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + struct node a, b, c; + typedef int (*fn_type) (struct node *n); + CHECK_NON_NULL (result); + + fn_type test_linked_list = + (fn_type)gcc_jit_result_get_code (result, "test_linked_list"); + CHECK_NON_NULL (test_linked_list); + + /* Construct a simple linked-list on the stack: a->b->c: */ + a.prev = NULL; + a.next = &b; + a.value = 5; + + b.prev = &a; + b.next = &c; + b.value = 3; + + c.prev = &b; + c.next = NULL; + c.value = 7; + + CHECK_VALUE (test_linked_list (NULL), 0); + CHECK_VALUE (test_linked_list (&a), 15); + CHECK_VALUE (test_linked_list (&b), 10); + CHECK_VALUE (test_linked_list (&c), 7); +} diff --git a/gcc/testsuite/jit.dg/test-long-names.c b/gcc/testsuite/jit.dg/test-long-names.c new file mode 100644 index 00000000000..0fc7e676b39 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-long-names.c @@ -0,0 +1,112 @@ +/* Test of using the API with very long names. */ + +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +/* 65KB */ +#define NAME_LENGTH (65 * 1024) + +static struct long_names +{ + char struct_name[NAME_LENGTH]; + char fn_name[NAME_LENGTH]; + char local_name[NAME_LENGTH]; + char block_name[NAME_LENGTH]; +} long_names; + +static void +populate_name (const char *prefix, char *buffer) +{ + int i; + + /* Begin with the given prefix: */ + sprintf (buffer, prefix); + + /* Populate the rest of the buffer with 0123456789 repeatedly: */ + for (i = strlen (prefix); i < NAME_LENGTH - 1; i++) + buffer[i] = '0' + (i % 10); + + /* NIL-terminate the buffer: */ + buffer[NAME_LENGTH - 1] = '\0'; +} + +static void +populate_names (void) +{ + populate_name ("struct_", long_names.struct_name); + populate_name ("test_fn_", long_names.fn_name); + populate_name ("local_", long_names.local_name); + populate_name ("block_", long_names.block_name); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Where "ETC" is a very long suffix, let's try to inject the + equivalent of: + + struct struct_ETC; + + int + test_fn_ETC () + { + int local_ETC; + local_ETC = 42; + return local_ETC; + } + + to verify that the API copes with such long names. */ + + populate_names (); + + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* We don't yet use this struct. */ + (void)gcc_jit_context_new_opaque_struct (ctxt, NULL, + long_names.struct_name); + + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + long_names.fn_name, + 0, NULL, + 0); + gcc_jit_lvalue *local = + gcc_jit_function_new_local (test_fn, + NULL, + int_type, + long_names.local_name); + + gcc_jit_block *block = + gcc_jit_function_new_block (test_fn, long_names.block_name); + + gcc_jit_block_add_assignment ( + block, + NULL, + local, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42)); + + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_lvalue_as_rvalue (local)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + typedef int (*my_fn_type) (void); + CHECK_NON_NULL (result); + my_fn_type my_fn = + (my_fn_type)gcc_jit_result_get_code (result, long_names.fn_name); + CHECK_NON_NULL (my_fn); + int val = my_fn (); + CHECK_VALUE (val, 42); +} diff --git a/gcc/testsuite/jit.dg/test-nested-contexts.c b/gcc/testsuite/jit.dg/test-nested-contexts.c new file mode 100644 index 00000000000..16bc63f3e9d --- /dev/null +++ b/gcc/testsuite/jit.dg/test-nested-contexts.c @@ -0,0 +1,641 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#define TEST_ESCHEWS_TEST_JIT +#define TEST_PROVIDES_MAIN +#include "harness.h" + +struct quadratic +{ + double a; + double b; + double c; + double discriminant; +}; + +/* This is an adapted version of test-quadratic.c + + Like that test, we'll try to inject the following code, but we'll + split it up into some nested contexts, in 3 levels, to test + how nested contexts work. + + ***** In top-level context: ***** + + (shared type declarations, for int, double, struct quadratic); + extern double sqrt (double); + + ***** In mid-level context: ***** + + void + calc_discriminant (struct quadratic *q) + { + // (b^2 - 4ac) + q->discriminant = (q->b * q->b) - (4 * q->a * q->c); + } + + ***** In bottom context: ***** + + 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 top_level +{ + 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 *struct_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 *sqrt; +}; + +struct middle_level +{ + gcc_jit_context *ctxt; + gcc_jit_function *calc_discriminant; +}; + +struct bottom_level +{ + gcc_jit_context *ctxt; +}; + +static void +make_types (struct top_level *top_level) +{ + top_level->numeric_type = + gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_DOUBLE); + top_level->numeric_type_ptr = + gcc_jit_type_get_pointer (top_level->numeric_type); + top_level->zero = + gcc_jit_context_zero (top_level->ctxt, top_level->numeric_type); + + top_level->int_type = + gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_INT); + top_level->void_type = + gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_VOID); + + top_level->a = + gcc_jit_context_new_field (top_level->ctxt, + NULL, + top_level->numeric_type, + "a"); + top_level->b = + gcc_jit_context_new_field (top_level->ctxt, + NULL, + top_level->numeric_type, + "b"); + top_level->c = + gcc_jit_context_new_field (top_level->ctxt, + NULL, + top_level->numeric_type, + "c"); + top_level->discriminant = + gcc_jit_context_new_field (top_level->ctxt, + NULL, + top_level->numeric_type, + "discriminant"); + gcc_jit_field *fields[] = {top_level->a, + top_level->b, + top_level->c, + top_level->discriminant}; + top_level->struct_quadratic = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type (top_level->ctxt, NULL, + "quadratic", 4, fields)); + top_level->quadratic_ptr = + gcc_jit_type_get_pointer (top_level->struct_quadratic); +} + +static void +make_sqrt (struct top_level *top_level) +{ + gcc_jit_param *param_x = + gcc_jit_context_new_param (top_level->ctxt, NULL, + top_level->numeric_type, "x"); + top_level->sqrt = + gcc_jit_context_new_function (top_level->ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + top_level->numeric_type, + "sqrt", + 1, ¶m_x, + 0); +} + +static void +make_calc_discriminant (struct top_level *top_level, + struct middle_level *middle_level) +{ + /* Build "calc_discriminant". */ + gcc_jit_param *param_q = + gcc_jit_context_new_param (middle_level->ctxt, NULL, + top_level->quadratic_ptr, "q"); + middle_level->calc_discriminant = + gcc_jit_context_new_function (middle_level->ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + top_level->void_type, + "calc_discriminant", + 1, ¶m_q, + 0); + gcc_jit_block *blk = + gcc_jit_function_new_block (middle_level->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, top_level->a)); + gcc_jit_rvalue *q_b = + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_q), + NULL, top_level->b)); + gcc_jit_rvalue *q_c = + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_q), + NULL, top_level->c)); + + gcc_jit_block_add_assignment ( + blk, NULL, + + /* q->discriminant =... */ + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_q), + NULL, + top_level->discriminant), + + /* (q->b * q->b) - (4 * q->a * q->c) */ + gcc_jit_context_new_binary_op ( + middle_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MINUS, + top_level->numeric_type, + + /* (q->b * q->b) */ + gcc_jit_context_new_binary_op ( + middle_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + top_level->numeric_type, + q_b, q_b), + + /* (4 * (q->a * q->c)) */ + gcc_jit_context_new_binary_op ( + middle_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + top_level->numeric_type, + /* 4.0 */ + gcc_jit_context_new_rvalue_from_int ( + middle_level->ctxt, + top_level->numeric_type, + 4), + /* (q->a * q->c) */ + gcc_jit_context_new_binary_op ( + middle_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + top_level->numeric_type, + q_a, q_c)))); /* end of gcc_jit_function_add_assignment call. */ + + gcc_jit_block_end_with_void_return (blk, NULL); +} + +static void +make_test_quadratic (struct top_level *top_level, + struct middle_level *middle_level, + struct bottom_level *bottom_level) +{ + gcc_jit_param *a = + gcc_jit_context_new_param (bottom_level->ctxt, NULL, + top_level->numeric_type, "a"); + gcc_jit_param *b = + gcc_jit_context_new_param (bottom_level->ctxt, NULL, + top_level->numeric_type, "b"); + gcc_jit_param *c = + gcc_jit_context_new_param (bottom_level->ctxt, NULL, + top_level->numeric_type, "c"); + gcc_jit_param *r1 = + gcc_jit_context_new_param (bottom_level->ctxt, NULL, + top_level->numeric_type_ptr, "r1"); + gcc_jit_param *r2 = + gcc_jit_context_new_param (bottom_level->ctxt, NULL, + top_level->numeric_type_ptr, "r2"); + gcc_jit_param *params[] = {a, b, c, r1, r2}; + gcc_jit_function *test_quadratic = + gcc_jit_context_new_function (bottom_level->ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + top_level->int_type, + "test_quadratic", + 5, params, + 0); + + /* struct quadratic q; */ + gcc_jit_lvalue *q = + gcc_jit_function_new_local ( + test_quadratic, NULL, + top_level->struct_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, top_level->a), + gcc_jit_param_as_rvalue (a)); + /* q.b = b; */ + gcc_jit_block_add_assignment ( + initial, NULL, + gcc_jit_lvalue_access_field (q, NULL, top_level->b), + gcc_jit_param_as_rvalue (b)); + /* q.c = c; */ + gcc_jit_block_add_assignment ( + initial, NULL, + gcc_jit_lvalue_access_field (q, NULL, top_level->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 ( + bottom_level->ctxt, NULL, + middle_level->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 ( + bottom_level->ctxt, NULL, + GCC_JIT_COMPARISON_GT, + gcc_jit_rvalue_access_field ( + gcc_jit_lvalue_as_rvalue (q), + NULL, + top_level->discriminant), + top_level->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, + top_level->numeric_type, + "s"); + gcc_jit_rvalue *discriminant_of_q = + gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q), + NULL, + top_level->discriminant); + gcc_jit_block_add_assignment ( + on_positive_discriminant, NULL, + s, + gcc_jit_context_new_call ( + bottom_level->ctxt, NULL, + top_level->sqrt, + 1, &discriminant_of_q)); + + gcc_jit_rvalue *minus_b = + gcc_jit_context_new_unary_op ( + bottom_level->ctxt, NULL, + GCC_JIT_UNARY_OP_MINUS, + top_level->numeric_type, + gcc_jit_param_as_rvalue (b)); + gcc_jit_rvalue *two_a = + gcc_jit_context_new_binary_op ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + top_level->numeric_type, + gcc_jit_context_new_rvalue_from_int ( + bottom_level->ctxt, + top_level->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 ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_DIVIDE, + top_level->numeric_type, + gcc_jit_context_new_binary_op ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_PLUS, + top_level->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 ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_DIVIDE, + top_level->numeric_type, + gcc_jit_context_new_binary_op ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_MINUS, + top_level->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 ( + bottom_level->ctxt, + top_level->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 ( + bottom_level->ctxt, NULL, + GCC_JIT_COMPARISON_EQ, + gcc_jit_rvalue_access_field ( + gcc_jit_lvalue_as_rvalue (q), + NULL, + top_level->discriminant), + top_level->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 ( + bottom_level->ctxt, NULL, + GCC_JIT_BINARY_OP_DIVIDE, + top_level->numeric_type, + minus_b, + two_a)); + + /* "return 1;" */ + gcc_jit_block_end_with_return ( + on_zero_discriminant, NULL, + gcc_jit_context_one (bottom_level->ctxt, top_level->int_type)); + + /* Block: "on_negative_discriminant" */ + gcc_jit_block_end_with_return ( + /* else return 0; */ + on_negative_discriminant, NULL, + gcc_jit_context_zero (bottom_level->ctxt, top_level->int_type)); +} + +void +verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + struct quadratic q; + + typedef void (*fn_type) (struct quadratic *q); + fn_type calc_discriminant = + (fn_type)gcc_jit_result_get_code (result, + "calc_discriminant"); + CHECK_NON_NULL (calc_discriminant); + + q.a = 3; + q.b = 5; + q.c = 7; + q.discriminant = 0; + calc_discriminant (&q); + + CHECK_VALUE (q.discriminant, -59); +} + +void +verify_bottom_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); +} + +int +main (int argc, char **argv) +{ + int i, j, k; + const int NUM_TOP_ITERATIONS = 2; + const int NUM_MIDDLE_ITERATIONS = 2; + const int NUM_BOTTOM_ITERATIONS = 2; + + /* We do the whole thing multiple times to shake out state-management + issues in the underlying code. */ + + for (i = 1; i <= NUM_TOP_ITERATIONS; i++) + { + /* Create the top-level context. */ + snprintf (test, sizeof (test), + "%s iteration %d of %d of top level", + extract_progname (argv[0]), + i, NUM_TOP_ITERATIONS); + + struct top_level top_level; + memset (&top_level, 0, sizeof (top_level)); + + top_level.ctxt = gcc_jit_context_acquire (); + set_options (top_level.ctxt, argv[0]); + + make_types (&top_level); + make_sqrt (&top_level); + + /* No errors should have occurred. */ + CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL); + + gcc_jit_context_dump_to_file (top_level.ctxt, + "dump-of-test-nested-contexts-top.c", + 1); + + for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++) + { + /* Create and populate the middle-level context, using + objects from the top-level context. */ + snprintf (test, sizeof (test), + ("%s iteration %d of %d of top level;" + " %d of %d of middle level"), + extract_progname (argv[0]), + i, NUM_TOP_ITERATIONS, + j, NUM_MIDDLE_ITERATIONS); + + struct middle_level middle_level; + memset (&middle_level, 0, sizeof (middle_level)); + + middle_level.ctxt = + gcc_jit_context_new_child_context (top_level.ctxt); + make_calc_discriminant (&top_level, + &middle_level); + + /* No errors should have occurred. */ + CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt), + NULL); + + gcc_jit_context_dump_to_file (middle_level.ctxt, + "dump-of-test-nested-contexts-middle.c", + 1); + + gcc_jit_result *middle_result = + gcc_jit_context_compile (middle_level.ctxt); + CHECK_NON_NULL (middle_result); + + verify_middle_code (middle_level.ctxt, middle_result); + + for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++) + { + /* Create and populate the innermost context, using + objects from the top-level and middle-level contexts. */ + snprintf (test, sizeof (test), + ("%s iteration %d of %d of top level;" + " %d of %d of middle level;" + " %d of %d of bottom level"), + extract_progname (argv[0]), + i, NUM_TOP_ITERATIONS, + j, NUM_MIDDLE_ITERATIONS, + k, NUM_BOTTOM_ITERATIONS); + + struct bottom_level bottom_level; + memset (&bottom_level, 0, sizeof (bottom_level)); + + bottom_level.ctxt = + gcc_jit_context_new_child_context (middle_level.ctxt); + make_test_quadratic (&top_level, + &middle_level, + &bottom_level); + + /* No errors should have occurred. */ + CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt), + NULL); + + gcc_jit_context_dump_to_file (bottom_level.ctxt, + "dump-of-test-nested-contexts-bottom.c", + 1); + + gcc_jit_result *bottom_result = + gcc_jit_context_compile (bottom_level.ctxt); + verify_bottom_code (bottom_level.ctxt, bottom_result); + gcc_jit_result_release (bottom_result); + gcc_jit_context_release (bottom_level.ctxt); + + } + + gcc_jit_result_release (middle_result); + gcc_jit_context_release (middle_level.ctxt); + + } + + gcc_jit_context_release (top_level.ctxt); + } + + totals (); + + return 0; +} diff --git a/gcc/testsuite/jit.dg/test-nested-loops.c b/gcc/testsuite/jit.dg/test-nested-loops.c new file mode 100644 index 00000000000..1d1a2ba4468 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-nested-loops.c @@ -0,0 +1,179 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + double + test_nested_loops (int n, double *a, double *b) + { + double result = 0.; + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + result += a[i] * b[j]; + return result + } + */ + gcc_jit_type *val_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_type *return_type = val_type; + gcc_jit_param *param_n = + gcc_jit_context_new_param (ctxt, NULL, int_type, "n"); + gcc_jit_param *param_a = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a"); + gcc_jit_param *param_b = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b"); + gcc_jit_param *params[3] = {param_n, param_a, param_b}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + return_type, + "test_nested_loops", + 3, params, 0); + + /* Create locals. */ + gcc_jit_lvalue *result = + gcc_jit_function_new_local (func, NULL, val_type, "result"); + gcc_jit_lvalue *i = + gcc_jit_function_new_local (func, NULL, int_type, "i"); + gcc_jit_lvalue *j = + gcc_jit_function_new_local (func, NULL, int_type, "j"); + + /* Create basic blocks. */ + gcc_jit_block *b_entry = + gcc_jit_function_new_block (func, "b_entry"); + gcc_jit_block *b_outer_loop_cond = + gcc_jit_function_new_block (func, "b_outer_loop_cond"); + gcc_jit_block *b_outer_loop_head = + gcc_jit_function_new_block (func, "b_outer_loop_head"); + gcc_jit_block *b_outer_loop_tail = + gcc_jit_function_new_block (func, "b_outer_loop_tail"); + gcc_jit_block *b_inner_loop_cond = + gcc_jit_function_new_block (func, "b_inner_loop_cond"); + gcc_jit_block *b_inner_loop_body = + gcc_jit_function_new_block (func, "b_inner_loop_body"); + gcc_jit_block *b_exit = + gcc_jit_function_new_block (func, "b_exit"); + + + /* Populate b_entry. */ + + /* "result = 0.;" */ + gcc_jit_block_add_assignment ( + b_entry, NULL, + result, + gcc_jit_context_zero (ctxt, val_type)); + /* "i = 0;" */ + gcc_jit_block_add_assignment ( + b_entry, NULL, + i, + gcc_jit_context_zero (ctxt, int_type)); + gcc_jit_block_end_with_jump (b_entry, NULL, b_outer_loop_cond); + + /* Populate b_outer_loop_cond. */ + gcc_jit_block_end_with_conditional ( + b_outer_loop_cond, + NULL, + /* (i < n) */ + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_LT, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_param_as_rvalue (param_n)), + b_outer_loop_head, + b_exit); + + /* Populate b_outer_loop_head. */ + /* j = 0; */ + gcc_jit_block_add_assignment ( + b_outer_loop_head, NULL, + j, + gcc_jit_context_zero (ctxt, int_type)); + gcc_jit_block_end_with_jump (b_outer_loop_head, NULL, b_inner_loop_cond); + + /* Populate b_inner_loop_cond. */ + gcc_jit_block_end_with_conditional ( + b_inner_loop_cond, + NULL, + /* (j < n) */ + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_LT, + gcc_jit_lvalue_as_rvalue (j), + gcc_jit_param_as_rvalue (param_n)), + b_inner_loop_body, + b_outer_loop_tail); + + /* Populate b_inner_loop_body. */ + /* "result += a[i] * b[j];" */ + gcc_jit_block_add_assignment_op ( + b_inner_loop_body, NULL, + result, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + val_type, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_context_new_array_access( + ctxt, NULL, + gcc_jit_param_as_rvalue (param_a), + gcc_jit_lvalue_as_rvalue (i))), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_context_new_array_access( + ctxt, NULL, + gcc_jit_param_as_rvalue (param_b), + gcc_jit_lvalue_as_rvalue (j))))); + /* "j++" */ + gcc_jit_block_add_assignment_op ( + b_inner_loop_body, NULL, + j, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + + gcc_jit_block_end_with_jump (b_inner_loop_body, NULL, b_inner_loop_cond); + + /* Populate b_outer_loop_tail. */ + /* "i++" */ + gcc_jit_block_add_assignment_op ( + b_outer_loop_tail, NULL, + i, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + gcc_jit_block_end_with_jump (b_outer_loop_tail, NULL, b_outer_loop_cond); + + /* Populate b_exit. */ + /* "return result;" */ + gcc_jit_block_end_with_return ( + b_exit, + NULL, + gcc_jit_lvalue_as_rvalue (result)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef double (*test_nested_loops_fn_type) (int n, double *a, double *b); + CHECK_NON_NULL (result); + + test_nested_loops_fn_type test_nested_loops = + (test_nested_loops_fn_type)gcc_jit_result_get_code (result, + "test_nested_loops"); + CHECK_NON_NULL (test_nested_loops); + double test_a[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}; + double test_b[] = {5., 6., 7., 8., 9., 10., 1., 2., 3., 4.}; + double val = test_nested_loops (10, test_a, test_b); + note ("test_nested_loops returned: %f", val); + CHECK_VALUE (val, 3025.0); +} diff --git a/gcc/testsuite/jit.dg/test-operator-overloading.cc b/gcc/testsuite/jit.dg/test-operator-overloading.cc new file mode 100644 index 00000000000..cbb1e98e1c3 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-operator-overloading.cc @@ -0,0 +1,310 @@ +/* Test of C++ API. */ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit++.h" + +#include <sstream> + +#include "harness.h" + +struct quadratic +{ + double a; + double b; + double c; + double discriminant; +}; + +/* As per test-quadratic.cc, let's try to inject the equivalent of: + + extern double sqrt (double); + + 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; + } + + However, we'll use operator overloading for maxium brevity, at the + risk of perhaps being too "magical". +*/ + +/**************************************************************************** + Test case + ****************************************************************************/ + +struct quadratic_test +{ + gccjit::context ctxt; + + /* "double" and "(double *)". */ + gccjit::type numeric_type; + gccjit::type numeric_type_ptr; + + /* The value (double)0. */ + gccjit::rvalue zero; + + gccjit::type int_type; + gccjit::type void_type; + + /* "struct quadratic" */ + gccjit::type quadratic; + gccjit::field a; + gccjit::field b; + gccjit::field c; + gccjit::field discriminant; + + /* "(struct quadratic *)" */ + gccjit::type quadratic_ptr; + + gccjit::function calc_discriminant; + + gccjit::function sqrt; + +}; + +static void +make_types (quadratic_test &testcase) +{ + testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE); + testcase.numeric_type_ptr = testcase.numeric_type.get_pointer (); + testcase.zero = testcase.ctxt.zero (testcase.numeric_type); + + testcase.int_type = testcase.ctxt.get_int_type <int> (); + testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID); + + testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a"); + testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b"); + testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c"); + testcase.discriminant = + testcase.ctxt.new_field (testcase.numeric_type, "discriminant"); + CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (), + "discriminant"); + std::vector<gccjit::field> fields (4); + fields[0] = testcase.a; + fields[1] = testcase.b; + fields[2] = testcase.c; + fields[3] = testcase.discriminant; + testcase.quadratic = + testcase.ctxt.new_struct_type ( + "quadratic", + fields); + testcase.quadratic_ptr = testcase.quadratic.get_pointer (); +} + +static void +make_sqrt (quadratic_test &testcase) +{ + std::vector<gccjit::param> params (1); + params[0] = + testcase.ctxt.new_param (testcase.numeric_type, "x"); + testcase.sqrt = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED, + testcase.numeric_type, + "sqrt", + params, + 0); +} + +static void +make_calc_discriminant (quadratic_test &testcase) +{ + /* Build "calc_discriminant". */ + gccjit::param param_q = + testcase.ctxt.new_param (testcase.quadratic_ptr, "q"); + std::vector <gccjit::param> params (1); + params[0] = param_q; + testcase.calc_discriminant = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + testcase.void_type, + "calc_discriminant", + params, + 0); + gccjit::block block = testcase.calc_discriminant.new_block (); + block.add_comment ("(b^2 - 4ac)"); + + gccjit::rvalue q_a = param_q.dereference_field (testcase.a); + gccjit::rvalue q_b = param_q.dereference_field (testcase.b); + gccjit::rvalue q_c = param_q.dereference_field (testcase.c); + + gccjit::rvalue four = + testcase.ctxt.new_rvalue (testcase.numeric_type, 4); + + block.add_assignment ( + /* q->discriminant =... */ + param_q.dereference_field (testcase.discriminant), + /* (q->b * q->b) - (4 * q->a * q->c) */ + (q_b * q_b) - (four * q_a * q_c)); + block.end_with_return (); +} + +static void +make_test_quadratic (quadratic_test &testcase) +{ + gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a"); + gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b"); + gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c"); + gccjit::param r1 = + testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1"); + gccjit::param r2 = + testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2"); + + std::vector<gccjit::param> params (5); + params[0] = a; + params[1] = b; + params[2] = c; + params[3] = r1; + params[4] = r2; + + gccjit::function test_quadratic = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + testcase.int_type, + "test_quadratic", + params, + 0); + + /* struct quadratic q; */ + gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q"); + + gccjit::block initial = test_quadratic.new_block ("initial"); + gccjit::block on_positive_discriminant + = test_quadratic.new_block ("positive_discriminant"); + gccjit::block on_nonpositive_discriminant + = test_quadratic.new_block ("nonpositive_discriminant"); + gccjit::block on_zero_discriminant + = test_quadratic.new_block ("zero_discriminant"); + gccjit::block on_negative_discriminant + = test_quadratic.new_block ("negative_discriminant"); + + CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (), + "zero_discriminant"); + + /* q.a = a; */ + initial.add_assignment (q.access_field (testcase.a), a); + /* q.b = b; */ + initial.add_assignment (q.access_field (testcase.b), b); + /* q.c = c; */ + initial.add_assignment (q.access_field (testcase.c), c); + /* calc_discriminant (&q); */ + gccjit::rvalue address_of_q = q.get_address (); + initial.add_eval (testcase.calc_discriminant (address_of_q)); + + initial.add_comment ("if (q.discriminant > 0)"); + initial.end_with_conditional ( + q.access_field (testcase.discriminant) > testcase.zero, + on_positive_discriminant, + on_nonpositive_discriminant); + + /* Block: "on_positive_discriminant" */ + /* double s = sqrt (q.discriminant); */ + gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s"); + gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant); + on_positive_discriminant.add_assignment (s, testcase.sqrt (discriminant_of_q)); + + gccjit::rvalue minus_b = -b; + gccjit::rvalue two = + testcase.ctxt.new_rvalue (testcase.numeric_type, 2); + gccjit::rvalue two_a = two * a; + CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (), + "(double)2 * a"); + + on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);"); + on_positive_discriminant.add_assignment (*r1, (minus_b + s) / two_a); + + on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)"); + on_positive_discriminant.add_assignment (*r2, (minus_b - s) / two_a); + + /* "return 2;" */ + on_positive_discriminant.end_with_return ( + testcase.ctxt.new_rvalue (testcase.int_type, 2)); + + /* Block: "on_nonpositive_discriminant" */ + /* "else if (q.discriminant == 0)" */ + on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)"); + on_nonpositive_discriminant.end_with_conditional ( + q.access_field (testcase.discriminant) == testcase.zero, + on_zero_discriminant, + on_negative_discriminant); + + /* Block: "on_zero_discriminant" */ + /* if (q.discriminant == 0) */ + on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);"); + on_zero_discriminant.add_assignment (*r1, minus_b / two_a); + + /* "return 1;" */ + on_zero_discriminant.end_with_return (testcase.int_type.one ()); + + /* Block: "on_negative_discriminant" */ + /* else return 0; */ + on_negative_discriminant.end_with_return (testcase.int_type.zero ()); + + /* Verify that output stream operator << works. */ + std::ostringstream os; + os << "streamed output: " << address_of_q; + CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q"); +} + +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); +} diff --git a/gcc/testsuite/jit.dg/test-quadratic.c b/gcc/testsuite/jit.dg/test-quadratic.c new file mode 100644 index 00000000000..715174c92f0 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-quadratic.c @@ -0,0 +1,488 @@ +#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)); + + gcc_jit_block_add_assignment ( + blk, NULL, + + /* q->discriminant =... */ + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_q), + NULL, + testcase->discriminant), + + /* (q->b * q->b) - (4 * q->a * q->c) */ + 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)))); /* end of gcc_jit_function_add_assignment call. */ + + 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); +} diff --git a/gcc/testsuite/jit.dg/test-quadratic.cc b/gcc/testsuite/jit.dg/test-quadratic.cc new file mode 100644 index 00000000000..f3476696f03 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-quadratic.cc @@ -0,0 +1,366 @@ +/* Test of C++ API. */ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit++.h" + +#include <sstream> + +#include "harness.h" + +struct quadratic +{ + double a; + double b; + double c; + double discriminant; +}; + +/* As per test-quadratic.c, let's try to inject the equivalent of: + + extern double sqrt (double); + + 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; + } + + However, we'll use the C++ bindings. +*/ + +/**************************************************************************** + Test case + ****************************************************************************/ + +struct quadratic_test +{ + gccjit::context ctxt; + + /* "double" and "(double *)". */ + gccjit::type numeric_type; + gccjit::type numeric_type_ptr; + + /* The value (double)0. */ + gccjit::rvalue zero; + + gccjit::type int_type; + gccjit::type void_type; + + /* "struct quadratic" */ + gccjit::type quadratic; + gccjit::field a; + gccjit::field b; + gccjit::field c; + gccjit::field discriminant; + + /* "(struct quadratic *)" */ + gccjit::type quadratic_ptr; + + gccjit::function calc_discriminant; + + gccjit::function sqrt; + +}; + +static void +make_types (quadratic_test &testcase) +{ + testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE); + testcase.numeric_type_ptr = testcase.numeric_type.get_pointer (); + testcase.zero = testcase.ctxt.zero (testcase.numeric_type); + + testcase.int_type = testcase.ctxt.get_int_type <int> (); + testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID); + + testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a"); + testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b"); + testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c"); + testcase.discriminant = + testcase.ctxt.new_field (testcase.numeric_type, "discriminant"); + CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (), + "discriminant"); + std::vector<gccjit::field> fields (4); + fields[0] = testcase.a; + fields[1] = testcase.b; + fields[2] = testcase.c; + fields[3] = testcase.discriminant; + testcase.quadratic = + testcase.ctxt.new_struct_type ( + "quadratic", + fields); + testcase.quadratic_ptr = testcase.quadratic.get_pointer (); +} + +static void +make_sqrt (quadratic_test &testcase) +{ + std::vector<gccjit::param> params (1); + params[0] = + testcase.ctxt.new_param (testcase.numeric_type, "x"); + testcase.sqrt = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED, + testcase.numeric_type, + "sqrt", + params, + 0); +} + +static void +make_calc_discriminant (quadratic_test &testcase) +{ + /* Build "calc_discriminant". */ + gccjit::param param_q = + testcase.ctxt.new_param (testcase.quadratic_ptr, "q"); + std::vector <gccjit::param> params (1); + params[0] = param_q; + testcase.calc_discriminant = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + testcase.void_type, + "calc_discriminant", + params, + 0); + gccjit::block block = testcase.calc_discriminant.new_block (); + block.add_comment ("(b^2 - 4ac)"); + + gccjit::rvalue q_a = param_q.dereference_field (testcase.a); + gccjit::rvalue q_b = param_q.dereference_field (testcase.b); + gccjit::rvalue q_c = param_q.dereference_field (testcase.c); + + block.add_assignment ( + /* q->discriminant =... */ + param_q.dereference_field (testcase.discriminant), + /* (q->b * q->b) - (4 * q->a * q->c) */ + testcase.ctxt.new_minus ( + testcase.numeric_type, + + /* (q->b * q->b) */ + testcase.ctxt.new_mult ( + testcase.numeric_type, + q_b, q_b), + + /* (4 * (q->a * q->c)) */ + testcase.ctxt.new_mult ( + testcase.numeric_type, + /* 4.0 */ + testcase.ctxt.new_rvalue ( + testcase.numeric_type, + 4), + /* (q->a * q->c) */ + testcase.ctxt.new_mult ( + testcase.numeric_type, + q_a, q_c)))); /* end of add_assignment call. */ + block.end_with_return (); +} + +static void +make_test_quadratic (quadratic_test &testcase) +{ + gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a"); + gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b"); + gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c"); + gccjit::param r1 = + testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1"); + gccjit::param r2 = + testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2"); + + std::vector<gccjit::param> params (5); + params[0] = a; + params[1] = b; + params[2] = c; + params[3] = r1; + params[4] = r2; + + gccjit::function test_quadratic = + testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + testcase.int_type, + "test_quadratic", + params, + 0); + + /* struct quadratic q; */ + gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q"); + + gccjit::block initial = test_quadratic.new_block ("initial"); + gccjit::block on_positive_discriminant + = test_quadratic.new_block ("positive_discriminant"); + gccjit::block on_nonpositive_discriminant + = test_quadratic.new_block ("nonpositive_discriminant"); + gccjit::block on_zero_discriminant + = test_quadratic.new_block ("zero_discriminant"); + gccjit::block on_negative_discriminant + = test_quadratic.new_block ("negative_discriminant"); + + CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (), + "zero_discriminant"); + + /* q.a = a; */ + initial.add_assignment (q.access_field (testcase.a), a); + /* q.b = b; */ + initial.add_assignment (q.access_field (testcase.b), b); + /* q.c = c; */ + initial.add_assignment (q.access_field (testcase.c), c); + /* calc_discriminant (&q); */ + gccjit::rvalue address_of_q = q.get_address (); + initial.add_call (testcase.calc_discriminant, address_of_q); + + initial.add_comment ("if (q.discriminant > 0)"); + initial.end_with_conditional ( + testcase.ctxt.new_gt ( + q.access_field (testcase.discriminant), + testcase.zero), + on_positive_discriminant, + on_nonpositive_discriminant); + + /* Block: "on_positive_discriminant" */ + /* double s = sqrt (q.discriminant); */ + gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s"); + gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant); + on_positive_discriminant.add_assignment ( + s, + testcase.ctxt.new_call (testcase.sqrt, discriminant_of_q)); + + gccjit::rvalue minus_b = + testcase.ctxt.new_minus ( + testcase.numeric_type, + b); + gccjit::rvalue two_a = + testcase.ctxt.new_mult ( + testcase.numeric_type, + testcase.ctxt.new_rvalue (testcase.numeric_type, 2), + a); + CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (), + "(double)2 * a"); + + on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);"); + on_positive_discriminant.add_assignment ( + /* "*r1 = ..." */ + r1.dereference (), + + /* (-b + s) / (2 * a) */ + testcase.ctxt.new_divide ( + testcase.numeric_type, + testcase.ctxt.new_plus ( + testcase.numeric_type, + minus_b, + s), + two_a)); + + on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)"); + on_positive_discriminant.add_assignment ( + /* "*r2 = ..." */ + r2.dereference (), + + /* (-b - s) / (2 * a) */ + testcase.ctxt.new_divide ( + testcase.numeric_type, + testcase.ctxt.new_minus ( + testcase.numeric_type, + minus_b, + s), + two_a)); + + /* "return 2;" */ + on_positive_discriminant.end_with_return ( + testcase.ctxt.new_rvalue (testcase.int_type, 2)); + + /* Block: "on_nonpositive_discriminant" */ + on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)"); + on_nonpositive_discriminant.end_with_conditional ( + testcase.ctxt.new_eq ( + q.access_field (testcase.discriminant), + testcase.zero), + on_zero_discriminant, + on_negative_discriminant); + + /* Block: "on_zero_discriminant" */ + /* if (q.discriminant == 0) */ + on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);"); + on_zero_discriminant.add_assignment ( + /* "*r1 = ..." */ + r1.dereference (), + + /* -b / (2 * a) */ + testcase.ctxt.new_divide ( + testcase.numeric_type, + minus_b, + two_a)); + + /* "return 1;" */ + on_zero_discriminant.end_with_return ( + testcase.ctxt.one (testcase.int_type)); + + /* Block: "on_negative_discriminant" */ + /* else return 0; */ + on_negative_discriminant.end_with_return ( + testcase.ctxt.zero (testcase.int_type)); + + /* Verify that output stream operator << works. */ + std::ostringstream os; + os << "streamed output: " << address_of_q; + CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q"); +} + +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); +} diff --git a/gcc/testsuite/jit.dg/test-reading-struct.c b/gcc/testsuite/jit.dg/test-reading-struct.c new file mode 100644 index 00000000000..a090ba9d2f5 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-reading-struct.c @@ -0,0 +1,135 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +struct bar +{ + int x; + int y; +}; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + int + test_reading (const struct bar *f) + { + return f->x * f->y; + } + + int + test_writing () + { + struct bar tmp; + tmp.x = 5; + tmp.y = 7; + return test_reading (&tmp); + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_field *x = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "x"); + gcc_jit_field *y = + gcc_jit_context_new_field (ctxt, + NULL, + int_type, + "y"); + gcc_jit_field *fields[] = {x, y}; + gcc_jit_type *struct_type = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type (ctxt, NULL, "bar", 2, fields)); + gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type); + gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (const_struct_type); + + /* Build "test_reading". */ + gcc_jit_param *param_f = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f"); + gcc_jit_function *fn_test_reading = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_reading", + 1, ¶m_f, + 0); + + /* return f->x * f->y; */ + gcc_jit_block *reading_block = gcc_jit_function_new_block (fn_test_reading, NULL); + gcc_jit_block_end_with_return ( + reading_block, + NULL, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + int_type, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + x)), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + y)))); + + /* Build "test_writing". */ + gcc_jit_function *fn_test_writing = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_writing", + 0, NULL, + 0); + + /* struct bar tmp; */ + gcc_jit_lvalue *local_tmp = + gcc_jit_function_new_local (fn_test_writing, NULL, + struct_type, + "tmp"); + /* tmp.x = 5; */ + gcc_jit_block *writing_block = gcc_jit_function_new_block (fn_test_writing, NULL); + gcc_jit_block_add_assignment ( + writing_block, NULL, + gcc_jit_lvalue_access_field (local_tmp, NULL, x), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 5)); + + /* tmp.y = 7; */ + gcc_jit_block_add_assignment ( + writing_block, NULL, + gcc_jit_lvalue_access_field (local_tmp, NULL, y), + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7)); + + /* return test_reading (&tmp); */ + gcc_jit_rvalue *arg = gcc_jit_lvalue_get_address (local_tmp, NULL); + gcc_jit_block_end_with_return ( + writing_block, + NULL, + gcc_jit_context_new_call ( + ctxt, NULL, + fn_test_reading, + 1, &arg)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*fn_type) (void); + CHECK_NON_NULL (result); + + fn_type test_writing = + (fn_type)gcc_jit_result_get_code (result, "test_writing"); + CHECK_NON_NULL (test_writing); + + /* Verify that the code correctly returns the product of the fields. */ + CHECK_VALUE (test_writing (), 35); +} + diff --git a/gcc/testsuite/jit.dg/test-string-literal.c b/gcc/testsuite/jit.dg/test-string-literal.c new file mode 100644 index 00000000000..097830d05cb --- /dev/null +++ b/gcc/testsuite/jit.dg/test-string-literal.c @@ -0,0 +1,52 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + const char * + test_string_literal (void) + { + return "hello world"; + } + */ + gcc_jit_type *const_char_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + const_char_ptr_type, + "test_string_literal", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_context_new_string_literal (ctxt, "hello world")); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef const char *(*fn_type) (void); + CHECK_NON_NULL (result); + fn_type test_string_literal = + (fn_type)gcc_jit_result_get_code (result, "test_string_literal"); + CHECK_NON_NULL (test_string_literal); + + /* Call the JIT-generated function. */ + const char *str = test_string_literal (); + CHECK_NON_NULL (str); + CHECK_VALUE (strcmp (str, "hello world"), 0); +} + diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c new file mode 100644 index 00000000000..d6fdcf6f92c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-sum-of-squares.c @@ -0,0 +1,126 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* + Simple sum-of-squares, to test conditionals and looping + + int loop_test (int n) + { + int i; + int sum = 0; + for (i = 0; i < n ; i ++) + { + sum += i * i; + } + return sum; + */ + gcc_jit_type *the_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *return_type = the_type; + + gcc_jit_param *n = + gcc_jit_context_new_param (ctxt, NULL, the_type, "n"); + gcc_jit_param *params[1] = {n}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + return_type, + "loop_test", + 1, params, 0); + + /* Build locals: */ + gcc_jit_lvalue *i = + gcc_jit_function_new_local (func, NULL, the_type, "i"); + gcc_jit_lvalue *sum = + gcc_jit_function_new_local (func, NULL, the_type, "sum"); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + gcc_jit_block *loop_cond = + gcc_jit_function_new_block (func, "loop_cond"); + gcc_jit_block *loop_body = + gcc_jit_function_new_block (func, "loop_body"); + gcc_jit_block *after_loop = + gcc_jit_function_new_block (func, "after_loop"); + + /* sum = 0; */ + gcc_jit_block_add_assignment ( + initial, NULL, + sum, + gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0)); + + /* i = 0; */ + gcc_jit_block_add_assignment ( + initial, NULL, + i, + gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0)); + + gcc_jit_block_end_with_jump (initial, NULL, loop_cond); + + /* if (i >= n) */ + gcc_jit_block_end_with_conditional ( + loop_cond, NULL, + gcc_jit_context_new_comparison ( + ctxt, NULL, + GCC_JIT_COMPARISON_GE, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_param_as_rvalue (n)), + after_loop, + loop_body); + + /* sum += i * i */ + gcc_jit_block_add_assignment ( + loop_body, NULL, + sum, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_PLUS, the_type, + gcc_jit_lvalue_as_rvalue (sum), + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, the_type, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_lvalue_as_rvalue (i)))); + + /* i++ */ + gcc_jit_block_add_assignment ( + loop_body, NULL, + i, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_PLUS, the_type, + gcc_jit_lvalue_as_rvalue (i), + gcc_jit_context_new_rvalue_from_int ( + ctxt, + the_type, + 1))); + + gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond); + + /* return sum */ + gcc_jit_block_end_with_return ( + after_loop, + NULL, + gcc_jit_lvalue_as_rvalue (sum)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*loop_test_fn_type) (int); + CHECK_NON_NULL (result); + loop_test_fn_type loop_test = + (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test"); + CHECK_NON_NULL (loop_test); + int val = loop_test (10); + note ("loop_test returned: %d", val); + CHECK_VALUE (val, 285); +} diff --git a/gcc/testsuite/jit.dg/test-threads.c b/gcc/testsuite/jit.dg/test-threads.c new file mode 100644 index 00000000000..7c248ccde6d --- /dev/null +++ b/gcc/testsuite/jit.dg/test-threads.c @@ -0,0 +1,252 @@ +/* test-threads.c + + As per test-combination.c, construct a test case by combining other test + cases, to try to shake out state issues. However each test runs in a + separate thread. */ + +#include <pthread.h> +#include <stdarg.h> +#include <stdio.h> + +/* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts + of "passed"/"failed" etc are globals. + + We get around this by putting a mutex around pass/fail calls. + */ + +static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h, + harness.h injects macros before including <dejagnu.h> so that the + pass/fail functions become "dejagnu_pass"/"dejagnu_fail" etc. */ + +void dejagnu_pass (const char* fmt, ...); +void dejagnu_fail (const char* fmt, ...); +void dejagnu_note (const char* fmt, ...); + +/* We now provide our own implementations of "pass"/"fail"/"note", which + call the underlying dejagnu implementations, but with a mutex. */ + +inline void +pass (const char* fmt, ...) +{ + va_list ap; + char buffer[512]; + + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + + pthread_mutex_lock (&dg_mutex); + dejagnu_pass (buffer); + pthread_mutex_unlock (&dg_mutex); +} + +inline void +fail (const char* fmt, ...) +{ + va_list ap; + char buffer[512]; + + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + + pthread_mutex_lock (&dg_mutex); + dejagnu_fail (buffer); + pthread_mutex_unlock (&dg_mutex); +} + +inline void +note (const char* fmt, ...) +{ + va_list ap; + char buffer[512]; + + va_start (ap, fmt); + vsnprintf (buffer, sizeof (buffer), fmt, ap); + va_end (ap); + + pthread_mutex_lock (&dg_mutex); + dejagnu_note (buffer); + pthread_mutex_unlock (&dg_mutex); +} + +#define MAKE_DEJAGNU_H_THREADSAFE + +/* We also need to provide our own version of TEST_NAME. */ +#define TEST_NAME + +/* We can now include all of the relevant selftests. */ + +#include "all-non-failing-tests.h" + +#define TEST_PROVIDES_MAIN +#define TEST_ESCHEWS_TEST_JIT + +/* Now construct a test case from all the other test cases. + + We undefine COMBINED_TEST so that we can now include harness.h + "for real". */ +#undef COMBINED_TEST +#include "harness.h" + +struct testcase +{ + const char *m_name; + void (*m_hook_to_create_code) (gcc_jit_context *ctxt, + void * user_data); + void (*m_hook_to_verify_code) (gcc_jit_context *ctxt, + gcc_jit_result *result); +}; + +const struct testcase testcases[] = { + {"accessing_struct", + create_code_accessing_struct, + verify_code_accessing_struct}, + {"accessing_union", + create_code_accessing_union, + verify_code_accessing_union}, + {"array_as_pointer", + create_code_array_as_pointer, + verify_code_array_as_pointer}, + {"arrays", + create_code_arrays, + verify_code_arrays}, + {"calling_external_function", + create_code_calling_external_function, + verify_code_calling_external_function}, + {"calling_function_ptr", + create_code_calling_function_ptr, + verify_code_calling_function_ptr}, + {"dot_product", + create_code_dot_product, + verify_code_dot_product}, + {"expressions", + create_code_expressions, + verify_code_expressions}, + {"factorial", + create_code_factorial, + verify_code_factorial}, + {"fibonacci", + create_code_fibonacci, + verify_code_fibonacci}, + {"functions", + create_code_functions, + verify_code_functions}, + {"hello_world", + create_code_hello_world, + verify_code_hello_world}, + {"linked_list", + create_code_linked_list, + verify_code_linked_list}, + {"long_names", + create_code_long_names, + verify_code_long_names}, + {"quadratic", + create_code_quadratic, + verify_code_quadratic}, + {"nested_loop", + create_code_nested_loop, + verify_code_nested_loop}, + {"reading_struct ", + create_code_reading_struct , + verify_code_reading_struct }, + {"string_literal", + create_code_string_literal, + verify_code_string_literal}, + {"sum_of_squares", + create_code_sum_of_squares, + verify_code_sum_of_squares}, + {"types", + create_code_types, + verify_code_types}, + {"using_global", + create_code_using_global, + verify_code_using_global}, + {"volatile", + create_code_volatile, + verify_code_volatile} +}; + +const int num_testcases = (sizeof (testcases) / sizeof (testcases[0])); + +struct thread_data +{ + pthread_t m_tid; + const struct testcase *m_testcase; +}; + +static const char *argv0; + +void * +run_threaded_test (void *data) +{ + struct thread_data *thread = (struct thread_data *)data; + int i; + + for (i = 0; i < 5; i++) + { + gcc_jit_context *ctxt; + gcc_jit_result *result; + + note ("run_threaded_test: %s iteration: %d", + thread->m_testcase->m_name, i); + + ctxt = gcc_jit_context_acquire (); + + set_options (ctxt, argv0); + + thread->m_testcase->m_hook_to_create_code (ctxt, NULL); + + result = gcc_jit_context_compile (ctxt); + + thread->m_testcase->m_hook_to_verify_code (ctxt, result); + + gcc_jit_context_release (ctxt); + + /* Once we're done with the code, this unloads the built .so file: */ + gcc_jit_result_release (result); + } + + return NULL; +} + +int +main (int argc, char **argv) +{ + int i; + + snprintf (test, sizeof (test), + "%s", + extract_progname (argv[0])); + + argv0 = argv[0]; + + /* The individual testcases are not thread-safe (some have their own + global variables), so we have one thread per test-case. */ + struct thread_data *threads = + calloc (num_testcases, sizeof (struct thread_data)); + + /* Start a thread per test-case. */ + for (i = 0; i < num_testcases; i++) + { + struct thread_data *thread = &threads[i]; + thread->m_testcase = &testcases[i]; + pthread_create (&thread->m_tid, + NULL, + run_threaded_test, + thread); + } + + /* Wait for all the threads to be done. */ + for (i = 0; i < num_testcases; i++) + { + struct thread_data *thread = &threads[i]; + (void)pthread_join (thread->m_tid, NULL); + } + + totals (); + + return 0; +} diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c new file mode 100644 index 00000000000..8debcd7eb82 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-types.c @@ -0,0 +1,361 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> +#include <stdbool.h> + +#include "libgccjit.h" + +#include "harness.h" + +struct zoo +{ + void *m_void_ptr; + + bool m_bool; + + char m_char; + signed char m_signed_char; + unsigned char m_unsigned_char; + + short m_short; + unsigned short m_unsigned_short; + + int m_int; + unsigned int m_unsigned_int; + + long m_long; + unsigned long m_unsigned_long; + + long long m_long_long; + unsigned long long m_unsigned_long_long; + + int m_sized_int_type; + + float m_float; + double m_double; + long double m_long_double; + + const char *m_const_char_ptr; + + size_t m_size_t; + + FILE *m_FILE_ptr; +}; + +int test_int = 42; +int *test_ptr = &test_int; + +const char *test_string = "test_string"; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_caller (struct zoo *z) + { + for each fields "m_field": + z->m_field = ...some data; + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + +#define CREATE_FIELD(TYPE, NAME) \ + gcc_jit_context_new_field ( \ + ctxt, NULL, \ + gcc_jit_context_get_type (ctxt, TYPE), \ + NAME) + + gcc_jit_field *field_m_void_ptr = + CREATE_FIELD (GCC_JIT_TYPE_VOID_PTR, "m_void_ptr"); + + gcc_jit_field *field_m_bool = + CREATE_FIELD (GCC_JIT_TYPE_BOOL, "m_bool"); + + gcc_jit_field *field_m_char = + CREATE_FIELD (GCC_JIT_TYPE_CHAR, "m_char"); + gcc_jit_field *field_m_signed_char = + CREATE_FIELD (GCC_JIT_TYPE_SIGNED_CHAR, "m_signed_char"); + gcc_jit_field *field_m_unsigned_char = + CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_CHAR, "m_unsigned_char"); + + gcc_jit_field *field_m_short = + CREATE_FIELD (GCC_JIT_TYPE_SHORT, "m_short"); + gcc_jit_field *field_m_unsigned_short = + CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_SHORT, "m_unsigned_short"); + + gcc_jit_field *field_m_int = + CREATE_FIELD (GCC_JIT_TYPE_INT, "m_int"); + gcc_jit_field *field_m_unsigned_int = + CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_INT, "m_unsigned_int"); + + gcc_jit_field *field_m_long = + CREATE_FIELD (GCC_JIT_TYPE_LONG, "m_long"); + gcc_jit_field *field_m_unsigned_long = + CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG, "m_unsigned_long"); + + gcc_jit_field *field_m_long_long = + CREATE_FIELD (GCC_JIT_TYPE_LONG_LONG, "m_long_long"); + gcc_jit_field *field_m_unsigned_long_long = + CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG_LONG, "m_unsigned_long_long"); + + /* Signed int type with sizeof (int): */ + gcc_jit_type *sized_int_type = + gcc_jit_context_get_int_type (ctxt, sizeof (int), 1); + gcc_jit_field *field_m_sized_int_type = + gcc_jit_context_new_field ( + ctxt, NULL, sized_int_type, "m_sized_int_type"); + + gcc_jit_field *field_m_float = + CREATE_FIELD (GCC_JIT_TYPE_FLOAT, "m_float"); + gcc_jit_field *field_m_double = + CREATE_FIELD (GCC_JIT_TYPE_DOUBLE, "m_double"); + gcc_jit_field *field_m_long_double = + CREATE_FIELD (GCC_JIT_TYPE_LONG_DOUBLE, "m_long_double"); + + gcc_jit_field *field_m_const_char_ptr = + CREATE_FIELD (GCC_JIT_TYPE_CONST_CHAR_PTR, "m_const_char_ptr"); + + gcc_jit_field *field_m_size_t = + CREATE_FIELD (GCC_JIT_TYPE_SIZE_T, "m_size_t"); + + gcc_jit_field *field_m_FILE_ptr = + CREATE_FIELD (GCC_JIT_TYPE_FILE_PTR, "m_FILE_ptr"); + +#undef CREATE_FIELD + + gcc_jit_field *zoo_fields[] = { + field_m_void_ptr, + + field_m_bool, + + field_m_char, + field_m_signed_char, + field_m_unsigned_char, + + field_m_short, + field_m_unsigned_short, + + field_m_int, + field_m_unsigned_int, + + field_m_long, + field_m_unsigned_long, + + field_m_long_long, + field_m_unsigned_long_long, + + field_m_sized_int_type, + + field_m_float, + field_m_double, + field_m_long_double, + + field_m_const_char_ptr, + + field_m_size_t, + + field_m_FILE_ptr + }; + + gcc_jit_type *zoo_type = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type ( + ctxt, + NULL, + "zoo", + sizeof (zoo_fields) / sizeof (zoo_fields[0]), + zoo_fields)); + + gcc_jit_type *zoo_ptr_type = + gcc_jit_type_get_pointer (zoo_type); + + /* Build the test_fn. */ + gcc_jit_param *param_z = + gcc_jit_context_new_param (ctxt, NULL, zoo_ptr_type, "z"); + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_types", + 1, ¶m_z, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + /* Write to the various fields of param "z". */ +#define ASSIGN(FIELD, EXPR) \ + gcc_jit_block_add_assignment ( \ + block, NULL, \ + gcc_jit_rvalue_dereference_field ( \ + gcc_jit_param_as_rvalue (param_z), \ + NULL, \ + (FIELD)), \ + (EXPR)); + + ASSIGN( + field_m_void_ptr, + gcc_jit_context_new_rvalue_from_ptr ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR), + test_ptr)) + + ASSIGN(field_m_bool, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL), 1)) + + ASSIGN(field_m_char, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR), + 'V')) + ASSIGN(field_m_signed_char, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIGNED_CHAR), + -37)) + ASSIGN(field_m_unsigned_char, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR), + 200)) + + ASSIGN(field_m_short, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SHORT), + -900)) + ASSIGN(field_m_unsigned_short, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT), + 0x3000)) + + ASSIGN(field_m_int, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT), + -0x2000)) + ASSIGN(field_m_unsigned_int, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT), + 1234567)) + + ASSIGN(field_m_long, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG), + -5)) + ASSIGN(field_m_unsigned_long, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG), + 12345678)) + + ASSIGN(field_m_long_long, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_LONG), + -42)) + ASSIGN(field_m_unsigned_long_long, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG), + 123456789)) + + ASSIGN(field_m_sized_int_type, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + sized_int_type, 500)) + + ASSIGN(field_m_float, + gcc_jit_context_new_rvalue_from_double ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT), + 3.141)) + ASSIGN(field_m_double, + gcc_jit_context_new_rvalue_from_double ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE), + 3.141)) + ASSIGN(field_m_long_double, + gcc_jit_context_new_rvalue_from_double ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_DOUBLE), + 3.141)) + + ASSIGN(field_m_const_char_ptr, + gcc_jit_context_new_rvalue_from_ptr ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR), + (char *)test_string)) + + ASSIGN(field_m_size_t, + gcc_jit_context_new_rvalue_from_int ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T), + sizeof (struct zoo))) + + ASSIGN(field_m_FILE_ptr, + gcc_jit_context_new_rvalue_from_ptr ( + ctxt, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FILE_PTR), + stderr)) + +#undef ASSIGN + + gcc_jit_block_end_with_void_return (block, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (struct zoo *); + CHECK_NON_NULL (result); + + fn_type test_types = + (fn_type)gcc_jit_result_get_code (result, "test_types"); + CHECK_NON_NULL (test_types); + + struct zoo z; + memset (&z, 0xf0, sizeof (z)); + + /* Call the JIT-generated function. */ + test_types (&z); + + /* Verify that it correctly wrote to the various fields. */ + CHECK_VALUE (z.m_void_ptr, test_ptr); + + CHECK_VALUE (z.m_bool, true); + + CHECK_VALUE (z.m_char, 'V'); + CHECK_VALUE (z.m_signed_char, -37); + CHECK_VALUE (z.m_unsigned_char, 200); + + CHECK_VALUE (z.m_short, -900); + CHECK_VALUE (z.m_unsigned_short, 0x3000); + + CHECK_VALUE (z.m_int, -0x2000); + CHECK_VALUE (z.m_unsigned_int, 1234567); + + CHECK_VALUE (z.m_long, -5); + CHECK_VALUE (z.m_unsigned_long, 12345678); + + CHECK_VALUE (z.m_long_long, -42); + CHECK_VALUE (z.m_unsigned_long_long, 123456789); + + CHECK_VALUE (z.m_sized_int_type, 500); + + CHECK_VALUE (z.m_float, 3.141f); + CHECK_VALUE (z.m_double, 3.141); + CHECK_VALUE (z.m_long_double, 3.141); + + CHECK_VALUE (z.m_const_char_ptr, test_string); + + CHECK_VALUE (z.m_size_t, sizeof (struct zoo)); + + CHECK_VALUE (z.m_FILE_ptr, stderr); +} diff --git a/gcc/testsuite/jit.dg/test-using-global.c b/gcc/testsuite/jit.dg/test-using-global.c new file mode 100644 index 00000000000..3ec949f76a3 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-using-global.c @@ -0,0 +1,73 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern int the_global; + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern int the_global; + + void + test_using_global (void) + { + the_global += 1; + } + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_using_global", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + + gcc_jit_block_add_assignment_op ( + block, NULL, + gcc_jit_context_new_global (ctxt, NULL, int_type, "the_global"), + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + gcc_jit_block_end_with_void_return (block, NULL); +} + +int the_global; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef void (*fn_type) (void); + CHECK_NON_NULL (result); + + fn_type test_using_global = + (fn_type)gcc_jit_result_get_code (result, "test_using_global"); + CHECK_NON_NULL (test_using_global); + + the_global = 42; + + /* Call the JIT-generated function. */ + test_using_global (); + + /* Verify that it correctly modified the_global. */ + CHECK_VALUE (the_global, 43); +} + diff --git a/gcc/testsuite/jit.dg/test-volatile.c b/gcc/testsuite/jit.dg/test-volatile.c new file mode 100644 index 00000000000..3ef3ca5cf4a --- /dev/null +++ b/gcc/testsuite/jit.dg/test-volatile.c @@ -0,0 +1,66 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +volatile int the_volatile; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern volatile int the_volatile; + + int + test_using_volatile (void) + { + return the_volatile; + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *volatile_int_type = + gcc_jit_type_get_volatile (int_type); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_using_volatile", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_lvalue *read_of_the_volatile = + gcc_jit_rvalue_dereference ( + gcc_jit_context_new_rvalue_from_ptr ( + ctxt, + gcc_jit_type_get_pointer (volatile_int_type), + (void *)&the_volatile), + NULL); + + gcc_jit_block_end_with_return ( + block, NULL, + gcc_jit_lvalue_as_rvalue (read_of_the_volatile)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*fn_type) (void); + CHECK_NON_NULL (result); + + fn_type test_using_volatile = + (fn_type)gcc_jit_result_get_code (result, "test_using_volatile"); + CHECK_NON_NULL (test_using_volatile); + + the_volatile = 42; + + /* Call the JIT-generated function. */ + test_using_volatile (); + + CHECK_VALUE (test_using_volatile (), 42); +} + |