#include #include #include "libgccjit.h" #include "harness.h" /* A doubly-linked list, to ensure that the JIT API can cope with self-referential types. */ struct node { struct node *prev; struct node *next; int value; }; void create_code (gcc_jit_context *ctxt, void *user_data) { /* Let's try to inject the equivalent of: int test_linked_list (struct node *n) { int total = 0; while (n) { total += n->value; n = n->next; } return total; } */ gcc_jit_type *t_int = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); gcc_jit_struct *t_node = gcc_jit_context_new_opaque_struct (ctxt, NULL, "node"); gcc_jit_type *t_node_ptr = gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node)); gcc_jit_field *f_prev = gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev"); gcc_jit_field *f_next = gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next"); gcc_jit_field *f_value = gcc_jit_context_new_field (ctxt, NULL, t_int, "value"); gcc_jit_field *fields[] = {f_prev, f_next, f_value}; gcc_jit_struct_set_fields (t_node, NULL, 3, fields); /* Build the test function. */ gcc_jit_param *param_n = gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n"); gcc_jit_function *fn = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, t_int, "test_linked_list", 1, ¶m_n, 0); /* int total; */ gcc_jit_lvalue *total = gcc_jit_function_new_local (fn, NULL, t_int, "total"); gcc_jit_block *initial = gcc_jit_function_new_block (fn, "initial"); gcc_jit_block *loop_test = gcc_jit_function_new_block (fn, "loop_test"); gcc_jit_block *loop_body = gcc_jit_function_new_block (fn, "loop_body"); gcc_jit_block *final = gcc_jit_function_new_block (fn, "final"); /* total = 0; */ gcc_jit_block_add_assignment ( initial, NULL, total, gcc_jit_context_zero (ctxt, t_int)); gcc_jit_block_end_with_jump (initial, NULL, loop_test); /* while (n) */ gcc_jit_block_end_with_conditional ( loop_test, NULL, gcc_jit_context_new_comparison (ctxt, NULL, GCC_JIT_COMPARISON_NE, gcc_jit_param_as_rvalue (param_n), gcc_jit_context_null (ctxt, t_node_ptr)), loop_body, final); /* total += n->value; */ gcc_jit_block_add_assignment_op ( loop_body, NULL, total, GCC_JIT_BINARY_OP_PLUS, gcc_jit_lvalue_as_rvalue ( gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_n), NULL, f_value))); /* n = n->next; */ gcc_jit_block_add_assignment ( loop_body, NULL, gcc_jit_param_as_lvalue (param_n), gcc_jit_lvalue_as_rvalue ( gcc_jit_rvalue_dereference_field ( gcc_jit_param_as_rvalue (param_n), NULL, f_next))); gcc_jit_block_end_with_jump (loop_body, NULL, loop_test); /* return total; */ gcc_jit_block_end_with_return ( final, NULL, gcc_jit_lvalue_as_rvalue (total)); } void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { struct node a, b, c; typedef int (*fn_type) (struct node *n); CHECK_NON_NULL (result); fn_type test_linked_list = (fn_type)gcc_jit_result_get_code (result, "test_linked_list"); CHECK_NON_NULL (test_linked_list); /* Construct a simple linked-list on the stack: a->b->c: */ a.prev = NULL; a.next = &b; a.value = 5; b.prev = &a; b.next = &c; b.value = 3; c.prev = &b; c.next = NULL; c.value = 7; CHECK_VALUE (test_linked_list (NULL), 0); CHECK_VALUE (test_linked_list (&a), 15); CHECK_VALUE (test_linked_list (&b), 10); CHECK_VALUE (test_linked_list (&c), 7); }