1 #include <stdlib.h>
2 #include <stdio.h>
3 
4 #include "libgccjit.h"
5 
6 #include "harness.h"
7 
8 /* A doubly-linked list, to ensure that the JIT API can cope with
9    self-referential types.  */
10 struct node
11 {
12   struct node *prev;
13   struct node *next;
14   int value;
15 };
16 
17 void
create_code(gcc_jit_context * ctxt,void * user_data)18 create_code (gcc_jit_context *ctxt, void *user_data)
19 {
20   /* Let's try to inject the equivalent of:
21      int
22      test_linked_list (struct node *n)
23      {
24 	int total = 0;
25 	while (n)
26 	  {
27 	    total += n->value;
28 	    n = n->next;
29 	  }
30 	return total;
31      }
32   */
33   gcc_jit_type *t_int =
34     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
35   gcc_jit_struct *t_node =
36     gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
37   gcc_jit_type *t_node_ptr =
38     gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node));
39 
40   gcc_jit_field *f_prev =
41     gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev");
42   gcc_jit_field *f_next =
43     gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next");
44   gcc_jit_field *f_value =
45     gcc_jit_context_new_field (ctxt, NULL, t_int, "value");
46   gcc_jit_field *fields[] = {f_prev, f_next, f_value};
47   gcc_jit_struct_set_fields (t_node, NULL, 3, fields);
48 
49   /* Build the test function.  */
50   gcc_jit_param *param_n =
51     gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n");
52   gcc_jit_function *fn =
53     gcc_jit_context_new_function (ctxt, NULL,
54 				  GCC_JIT_FUNCTION_EXPORTED,
55 				  t_int,
56 				  "test_linked_list",
57 				  1, &param_n,
58 				  0);
59   /* int total; */
60   gcc_jit_lvalue *total =
61     gcc_jit_function_new_local (fn, NULL, t_int, "total");
62 
63   gcc_jit_block *initial = gcc_jit_function_new_block (fn, "initial");
64   gcc_jit_block *loop_test = gcc_jit_function_new_block (fn, "loop_test");
65   gcc_jit_block *loop_body = gcc_jit_function_new_block (fn, "loop_body");
66   gcc_jit_block *final = gcc_jit_function_new_block (fn, "final");
67 
68   /* total = 0; */
69   gcc_jit_block_add_assignment (
70     initial, NULL,
71     total,
72     gcc_jit_context_zero (ctxt, t_int));
73   gcc_jit_block_end_with_jump (initial, NULL, loop_test);
74 
75   /* while (n) */
76   gcc_jit_block_end_with_conditional (
77     loop_test, NULL,
78     gcc_jit_context_new_comparison (ctxt, NULL,
79 				    GCC_JIT_COMPARISON_NE,
80 				    gcc_jit_param_as_rvalue (param_n),
81 				    gcc_jit_context_null (ctxt, t_node_ptr)),
82     loop_body,
83     final);
84 
85   /* total += n->value; */
86   gcc_jit_block_add_assignment_op (
87     loop_body, NULL,
88     total,
89     GCC_JIT_BINARY_OP_PLUS,
90     gcc_jit_lvalue_as_rvalue (
91       gcc_jit_rvalue_dereference_field (
92 	gcc_jit_param_as_rvalue (param_n),
93 	NULL,
94 	f_value)));
95 
96   /* n = n->next; */
97   gcc_jit_block_add_assignment (
98     loop_body, NULL,
99     gcc_jit_param_as_lvalue (param_n),
100     gcc_jit_lvalue_as_rvalue (
101       gcc_jit_rvalue_dereference_field (
102 	gcc_jit_param_as_rvalue (param_n),
103 	NULL,
104 	f_next)));
105 
106   gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
107 
108   /* return total; */
109   gcc_jit_block_end_with_return (
110     final, NULL, gcc_jit_lvalue_as_rvalue (total));
111 }
112 
113 void
verify_code(gcc_jit_context * ctxt,gcc_jit_result * result)114 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
115 {
116   struct node a, b, c;
117   typedef int (*fn_type) (struct node *n);
118   CHECK_NON_NULL (result);
119 
120   fn_type test_linked_list =
121     (fn_type)gcc_jit_result_get_code (result, "test_linked_list");
122   CHECK_NON_NULL (test_linked_list);
123 
124   /* Construct a simple linked-list on the stack: a->b->c: */
125   a.prev = NULL;
126   a.next = &b;
127   a.value = 5;
128 
129   b.prev = &a;
130   b.next = &c;
131   b.value = 3;
132 
133   c.prev = &b;
134   c.next = NULL;
135   c.value = 7;
136 
137   CHECK_VALUE (test_linked_list (NULL), 0);
138   CHECK_VALUE (test_linked_list (&a), 15);
139   CHECK_VALUE (test_linked_list (&b), 10);
140   CHECK_VALUE (test_linked_list (&c), 7);
141 }
142