summaryrefslogtreecommitdiff
path: root/gcc/testsuite/jit.dg
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/jit.dg')
-rw-r--r--gcc/testsuite/jit.dg/all-non-failing-tests.h166
-rw-r--r--gcc/testsuite/jit.dg/harness.h242
-rw-r--r--gcc/testsuite/jit.dg/jit.exp293
-rw-r--r--gcc/testsuite/jit.dg/test-accessing-struct.c112
-rw-r--r--gcc/testsuite/jit.dg/test-accessing-union.c97
-rw-r--r--gcc/testsuite/jit.dg/test-array-as-pointer.c101
-rw-r--r--gcc/testsuite/jit.dg/test-arrays.c165
-rw-r--r--gcc/testsuite/jit.dg/test-calling-external-function.c118
-rw-r--r--gcc/testsuite/jit.dg/test-calling-function-ptr.c118
-rw-r--r--gcc/testsuite/jit.dg/test-combination.c67
-rw-r--r--gcc/testsuite/jit.dg/test-dot-product.c129
-rw-r--r--gcc/testsuite/jit.dg/test-empty.c20
-rw-r--r--gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c114
-rw-r--r--gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c48
-rw-r--r--gcc/testsuite/jit.dg/test-error-array-as-pointer.c99
-rw-r--r--gcc/testsuite/jit.dg/test-error-bad-cast.c63
-rw-r--r--gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c65
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c74
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c65
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c62
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c70
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c87
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c87
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c87
-rw-r--r--gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c89
-rw-r--r--gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c95
-rw-r--r--gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c55
-rw-r--r--gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c27
-rw-r--r--gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c34
-rw-r--r--gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c61
-rw-r--r--gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c80
-rw-r--r--gcc/testsuite/jit.dg/test-error-missing-return.c40
-rw-r--r--gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c37
-rw-r--r--gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c41
-rw-r--r--gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c36
-rw-r--r--gcc/testsuite/jit.dg/test-error-null-passed-to-api.c31
-rw-r--r--gcc/testsuite/jit.dg/test-error-return-within-void-function.c54
-rw-r--r--gcc/testsuite/jit.dg/test-error-unreachable-block.c50
-rw-r--r--gcc/testsuite/jit.dg/test-error-unterminated-block.c42
-rw-r--r--gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c29
-rw-r--r--gcc/testsuite/jit.dg/test-expressions.c896
-rw-r--r--gcc/testsuite/jit.dg/test-factorial.c103
-rw-r--r--gcc/testsuite/jit.dg/test-fibonacci.c136
-rw-r--r--gcc/testsuite/jit.dg/test-functions.c356
-rw-r--r--gcc/testsuite/jit.dg/test-fuzzer.c462
-rw-r--r--gcc/testsuite/jit.dg/test-hello-world.c72
-rw-r--r--gcc/testsuite/jit.dg/test-linked-list.c141
-rw-r--r--gcc/testsuite/jit.dg/test-long-names.c112
-rw-r--r--gcc/testsuite/jit.dg/test-nested-contexts.c641
-rw-r--r--gcc/testsuite/jit.dg/test-nested-loops.c179
-rw-r--r--gcc/testsuite/jit.dg/test-operator-overloading.cc310
-rw-r--r--gcc/testsuite/jit.dg/test-quadratic.c488
-rw-r--r--gcc/testsuite/jit.dg/test-quadratic.cc366
-rw-r--r--gcc/testsuite/jit.dg/test-reading-struct.c135
-rw-r--r--gcc/testsuite/jit.dg/test-string-literal.c52
-rw-r--r--gcc/testsuite/jit.dg/test-sum-of-squares.c126
-rw-r--r--gcc/testsuite/jit.dg/test-threads.c252
-rw-r--r--gcc/testsuite/jit.dg/test-types.c361
-rw-r--r--gcc/testsuite/jit.dg/test-using-global.c73
-rw-r--r--gcc/testsuite/jit.dg/test-volatile.c66
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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param,
+ 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, &param_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, &param_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, &param_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, &param,
+ 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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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);
+}
+