annotate gcc/jit/docs/examples/tut04-toyvm/toyvm.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* A simple stack-based virtual machine to demonstrate
kono
parents:
diff changeset
2 JIT-compilation.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3 Copyright (C) 2014-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
8 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
9 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
10 any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
13 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
15 General Public License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include <assert.h>
kono
parents:
diff changeset
22 #include <errno.h>
kono
parents:
diff changeset
23 #include <stdio.h>
kono
parents:
diff changeset
24 #include <stdlib.h>
kono
parents:
diff changeset
25 #include <string.h>
kono
parents:
diff changeset
26
kono
parents:
diff changeset
27 #include <dejagnu.h>
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 #include <libgccjit.h>
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 /* Typedefs. */
kono
parents:
diff changeset
32 typedef struct toyvm_op toyvm_op;
kono
parents:
diff changeset
33 typedef struct toyvm_function toyvm_function;
kono
parents:
diff changeset
34 typedef struct toyvm_frame toyvm_frame;
kono
parents:
diff changeset
35 typedef struct compilation_state compilation_state;
kono
parents:
diff changeset
36 typedef struct toyvm_compiled_function toyvm_compiled_function;
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 /* Functions are compiled to this function ptr type. */
kono
parents:
diff changeset
39 typedef int (*toyvm_compiled_code) (int);
kono
parents:
diff changeset
40
kono
parents:
diff changeset
41 enum opcode {
kono
parents:
diff changeset
42 /* Ops taking no operand. */
kono
parents:
diff changeset
43 DUP,
kono
parents:
diff changeset
44 ROT,
kono
parents:
diff changeset
45 BINARY_ADD,
kono
parents:
diff changeset
46 BINARY_SUBTRACT,
kono
parents:
diff changeset
47 BINARY_MULT,
kono
parents:
diff changeset
48 BINARY_COMPARE_LT,
kono
parents:
diff changeset
49 RECURSE,
kono
parents:
diff changeset
50 RETURN,
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 /* Ops taking an operand. */
kono
parents:
diff changeset
53 PUSH_CONST,
kono
parents:
diff changeset
54 JUMP_ABS_IF_TRUE
kono
parents:
diff changeset
55 };
kono
parents:
diff changeset
56
kono
parents:
diff changeset
57 #define FIRST_UNARY_OPCODE (PUSH_CONST)
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 const char * const opcode_names[] = {
kono
parents:
diff changeset
60 "DUP",
kono
parents:
diff changeset
61 "ROT",
kono
parents:
diff changeset
62 "BINARY_ADD",
kono
parents:
diff changeset
63 "BINARY_SUBTRACT",
kono
parents:
diff changeset
64 "BINARY_MULT",
kono
parents:
diff changeset
65 "BINARY_COMPARE_LT",
kono
parents:
diff changeset
66 "RECURSE",
kono
parents:
diff changeset
67 "RETURN",
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 "PUSH_CONST",
kono
parents:
diff changeset
70 "JUMP_ABS_IF_TRUE",
kono
parents:
diff changeset
71 };
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 struct toyvm_op
kono
parents:
diff changeset
74 {
kono
parents:
diff changeset
75 /* Which operation. */
kono
parents:
diff changeset
76 enum opcode op_opcode;
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 /* Some opcodes take an argument. */
kono
parents:
diff changeset
79 int op_operand;
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 /* The line number of the operation within the source file. */
kono
parents:
diff changeset
82 int op_linenum;
kono
parents:
diff changeset
83 };
kono
parents:
diff changeset
84
kono
parents:
diff changeset
85 #define MAX_OPS (64)
kono
parents:
diff changeset
86
kono
parents:
diff changeset
87 struct toyvm_function
kono
parents:
diff changeset
88 {
kono
parents:
diff changeset
89 const char *fn_filename;
kono
parents:
diff changeset
90 int fn_num_ops;
kono
parents:
diff changeset
91 toyvm_op fn_ops[MAX_OPS];
kono
parents:
diff changeset
92 };
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 #define MAX_STACK_DEPTH (8)
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 struct toyvm_frame
kono
parents:
diff changeset
97 {
kono
parents:
diff changeset
98 toyvm_function *frm_function;
kono
parents:
diff changeset
99 int frm_pc;
kono
parents:
diff changeset
100 int frm_stack[MAX_STACK_DEPTH];
kono
parents:
diff changeset
101 int frm_cur_depth;
kono
parents:
diff changeset
102 };
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 static void
kono
parents:
diff changeset
105 add_op (toyvm_function *fn, enum opcode opcode,
kono
parents:
diff changeset
106 int operand, int linenum)
kono
parents:
diff changeset
107 {
kono
parents:
diff changeset
108 toyvm_op *op;
kono
parents:
diff changeset
109 assert (fn->fn_num_ops < MAX_OPS);
kono
parents:
diff changeset
110 op = &fn->fn_ops[fn->fn_num_ops++];
kono
parents:
diff changeset
111 op->op_opcode = opcode;
kono
parents:
diff changeset
112 op->op_operand = operand;
kono
parents:
diff changeset
113 op->op_linenum = linenum;
kono
parents:
diff changeset
114 }
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 static void
kono
parents:
diff changeset
117 add_unary_op (toyvm_function *fn, enum opcode opcode,
kono
parents:
diff changeset
118 const char *rest_of_line, int linenum)
kono
parents:
diff changeset
119 {
kono
parents:
diff changeset
120 int operand = atoi (rest_of_line);
kono
parents:
diff changeset
121 add_op (fn, opcode, operand, linenum);
kono
parents:
diff changeset
122 }
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 static char *
kono
parents:
diff changeset
125 get_function_name (const char *filename)
kono
parents:
diff changeset
126 {
kono
parents:
diff changeset
127 /* Skip any path separators. */
kono
parents:
diff changeset
128 const char *pathsep = strrchr (filename, '/');
kono
parents:
diff changeset
129 if (pathsep)
kono
parents:
diff changeset
130 filename = pathsep + 1;
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 /* Copy filename to funcname. */
kono
parents:
diff changeset
133 char *funcname = (char *)malloc (strlen (filename) + 1);
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 strcpy (funcname, filename);
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 /* Convert "." to NIL terminator. */
kono
parents:
diff changeset
138 *(strchr (funcname, '.')) = '\0';
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 return funcname;
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143 static toyvm_function *
kono
parents:
diff changeset
144 toyvm_function_parse (const char *filename, const char *name)
kono
parents:
diff changeset
145 {
kono
parents:
diff changeset
146 FILE *f = NULL;
kono
parents:
diff changeset
147 toyvm_function *fn = NULL;
kono
parents:
diff changeset
148 char *line = NULL;
kono
parents:
diff changeset
149 ssize_t linelen;
kono
parents:
diff changeset
150 size_t bufsize;
kono
parents:
diff changeset
151 int linenum = 0;
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 assert (filename);
kono
parents:
diff changeset
154 assert (name);
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 f = fopen (filename, "r");
kono
parents:
diff changeset
157 if (!f)
kono
parents:
diff changeset
158 {
kono
parents:
diff changeset
159 fprintf (stderr,
kono
parents:
diff changeset
160 "cannot open file %s: %s\n",
kono
parents:
diff changeset
161 filename, strerror (errno));
kono
parents:
diff changeset
162 goto error;
kono
parents:
diff changeset
163 }
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 fn = (toyvm_function *)calloc (1, sizeof (toyvm_function));
kono
parents:
diff changeset
166 if (!fn)
kono
parents:
diff changeset
167 {
kono
parents:
diff changeset
168 fprintf (stderr, "out of memory allocating toyvm_function\n");
kono
parents:
diff changeset
169 goto error;
kono
parents:
diff changeset
170 }
kono
parents:
diff changeset
171 fn->fn_filename = filename;
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 /* Read the lines of the file. */
kono
parents:
diff changeset
174 while ((linelen = getline (&line, &bufsize, f)) != -1)
kono
parents:
diff changeset
175 {
kono
parents:
diff changeset
176 /* Note that this is a terrible parser, but it avoids the need to
kono
parents:
diff changeset
177 bring in lex/yacc as a dependency. */
kono
parents:
diff changeset
178 linenum++;
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 if (0)
kono
parents:
diff changeset
181 fprintf (stdout, "%3d: %s", linenum, line);
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 /* Lines beginning with # are comments. */
kono
parents:
diff changeset
184 if (line[0] == '#')
kono
parents:
diff changeset
185 continue;
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187 /* Skip blank lines. */
kono
parents:
diff changeset
188 if (line[0] == '\n')
kono
parents:
diff changeset
189 continue;
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 #define LINE_MATCHES(OPCODE) (0 == strncmp ((OPCODE), line, strlen (OPCODE)))
kono
parents:
diff changeset
192 if (LINE_MATCHES ("DUP\n"))
kono
parents:
diff changeset
193 add_op (fn, DUP, 0, linenum);
kono
parents:
diff changeset
194 else if (LINE_MATCHES ("ROT\n"))
kono
parents:
diff changeset
195 add_op (fn, ROT, 0, linenum);
kono
parents:
diff changeset
196 else if (LINE_MATCHES ("BINARY_ADD\n"))
kono
parents:
diff changeset
197 add_op (fn, BINARY_ADD, 0, linenum);
kono
parents:
diff changeset
198 else if (LINE_MATCHES ("BINARY_SUBTRACT\n"))
kono
parents:
diff changeset
199 add_op (fn, BINARY_SUBTRACT, 0, linenum);
kono
parents:
diff changeset
200 else if (LINE_MATCHES ("BINARY_MULT\n"))
kono
parents:
diff changeset
201 add_op (fn, BINARY_MULT, 0, linenum);
kono
parents:
diff changeset
202 else if (LINE_MATCHES ("BINARY_COMPARE_LT\n"))
kono
parents:
diff changeset
203 add_op (fn, BINARY_COMPARE_LT, 0, linenum);
kono
parents:
diff changeset
204 else if (LINE_MATCHES ("RECURSE\n"))
kono
parents:
diff changeset
205 add_op (fn, RECURSE, 0, linenum);
kono
parents:
diff changeset
206 else if (LINE_MATCHES ("RETURN\n"))
kono
parents:
diff changeset
207 add_op (fn, RETURN, 0, linenum);
kono
parents:
diff changeset
208 else if (LINE_MATCHES ("PUSH_CONST "))
kono
parents:
diff changeset
209 add_unary_op (fn, PUSH_CONST,
kono
parents:
diff changeset
210 line + strlen ("PUSH_CONST "), linenum);
kono
parents:
diff changeset
211 else if (LINE_MATCHES ("JUMP_ABS_IF_TRUE "))
kono
parents:
diff changeset
212 add_unary_op (fn, JUMP_ABS_IF_TRUE,
kono
parents:
diff changeset
213 line + strlen("JUMP_ABS_IF_TRUE "), linenum);
kono
parents:
diff changeset
214 else
kono
parents:
diff changeset
215 {
kono
parents:
diff changeset
216 fprintf (stderr, "%s:%d: parse error\n", filename, linenum);
kono
parents:
diff changeset
217 free (fn);
kono
parents:
diff changeset
218 fn = NULL;
kono
parents:
diff changeset
219 goto error;
kono
parents:
diff changeset
220 }
kono
parents:
diff changeset
221 #undef LINE_MATCHES
kono
parents:
diff changeset
222 }
kono
parents:
diff changeset
223 free (line);
kono
parents:
diff changeset
224 fclose (f);
kono
parents:
diff changeset
225
kono
parents:
diff changeset
226 return fn;
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 error:
kono
parents:
diff changeset
229 free (line);
kono
parents:
diff changeset
230 if (f)
kono
parents:
diff changeset
231 fclose (f);
kono
parents:
diff changeset
232 free (fn);
kono
parents:
diff changeset
233 return NULL;
kono
parents:
diff changeset
234 }
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 static void
kono
parents:
diff changeset
237 toyvm_function_disassemble_op (toyvm_function *fn, toyvm_op *op, int index, FILE *out)
kono
parents:
diff changeset
238 {
kono
parents:
diff changeset
239 fprintf (out, "%s:%d: index %d: %s",
kono
parents:
diff changeset
240 fn->fn_filename, op->op_linenum, index,
kono
parents:
diff changeset
241 opcode_names[op->op_opcode]);
kono
parents:
diff changeset
242 if (op->op_opcode >= FIRST_UNARY_OPCODE)
kono
parents:
diff changeset
243 fprintf (out, " %d", op->op_operand);
kono
parents:
diff changeset
244 fprintf (out, "\n");
kono
parents:
diff changeset
245 }
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 static void
kono
parents:
diff changeset
248 toyvm_function_disassemble (toyvm_function *fn, FILE *out)
kono
parents:
diff changeset
249 {
kono
parents:
diff changeset
250 int i;
kono
parents:
diff changeset
251 for (i = 0; i < fn->fn_num_ops; i++)
kono
parents:
diff changeset
252 {
kono
parents:
diff changeset
253 toyvm_op *op = &fn->fn_ops[i];
kono
parents:
diff changeset
254 toyvm_function_disassemble_op (fn, op, i, out);
kono
parents:
diff changeset
255 }
kono
parents:
diff changeset
256 }
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 static void
kono
parents:
diff changeset
259 toyvm_frame_push (toyvm_frame *frame, int arg)
kono
parents:
diff changeset
260 {
kono
parents:
diff changeset
261 assert (frame->frm_cur_depth < MAX_STACK_DEPTH);
kono
parents:
diff changeset
262 frame->frm_stack[frame->frm_cur_depth++] = arg;
kono
parents:
diff changeset
263 }
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265 static int
kono
parents:
diff changeset
266 toyvm_frame_pop (toyvm_frame *frame)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 assert (frame->frm_cur_depth > 0);
kono
parents:
diff changeset
269 return frame->frm_stack[--frame->frm_cur_depth];
kono
parents:
diff changeset
270 }
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 static void
kono
parents:
diff changeset
273 toyvm_frame_dump_stack (toyvm_frame *frame, FILE *out)
kono
parents:
diff changeset
274 {
kono
parents:
diff changeset
275 int i;
kono
parents:
diff changeset
276 fprintf (out, "stack:");
kono
parents:
diff changeset
277 for (i = 0; i < frame->frm_cur_depth; i++)
kono
parents:
diff changeset
278 {
kono
parents:
diff changeset
279 fprintf (out, " %d", frame->frm_stack[i]);
kono
parents:
diff changeset
280 }
kono
parents:
diff changeset
281 fprintf (out, "\n");
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 /* Execute the given function. */
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 static int
kono
parents:
diff changeset
287 toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
kono
parents:
diff changeset
288 {
kono
parents:
diff changeset
289 toyvm_frame frame;
kono
parents:
diff changeset
290 #define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
kono
parents:
diff changeset
291 #define POP(ARG) (toyvm_frame_pop (&frame))
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 frame.frm_function = fn;
kono
parents:
diff changeset
294 frame.frm_pc = 0;
kono
parents:
diff changeset
295 frame.frm_cur_depth = 0;
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 PUSH (arg);
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 while (1)
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 toyvm_op *op;
kono
parents:
diff changeset
302 int x, y;
kono
parents:
diff changeset
303 assert (frame.frm_pc < fn->fn_num_ops);
kono
parents:
diff changeset
304 op = &fn->fn_ops[frame.frm_pc++];
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 if (trace)
kono
parents:
diff changeset
307 {
kono
parents:
diff changeset
308 toyvm_frame_dump_stack (&frame, trace);
kono
parents:
diff changeset
309 toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 switch (op->op_opcode)
kono
parents:
diff changeset
313 {
kono
parents:
diff changeset
314 /* Ops taking no operand. */
kono
parents:
diff changeset
315 case DUP:
kono
parents:
diff changeset
316 x = POP ();
kono
parents:
diff changeset
317 PUSH (x);
kono
parents:
diff changeset
318 PUSH (x);
kono
parents:
diff changeset
319 break;
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 case ROT:
kono
parents:
diff changeset
322 y = POP ();
kono
parents:
diff changeset
323 x = POP ();
kono
parents:
diff changeset
324 PUSH (y);
kono
parents:
diff changeset
325 PUSH (x);
kono
parents:
diff changeset
326 break;
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 case BINARY_ADD:
kono
parents:
diff changeset
329 y = POP ();
kono
parents:
diff changeset
330 x = POP ();
kono
parents:
diff changeset
331 PUSH (x + y);
kono
parents:
diff changeset
332 break;
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 case BINARY_SUBTRACT:
kono
parents:
diff changeset
335 y = POP ();
kono
parents:
diff changeset
336 x = POP ();
kono
parents:
diff changeset
337 PUSH (x - y);
kono
parents:
diff changeset
338 break;
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 case BINARY_MULT:
kono
parents:
diff changeset
341 y = POP ();
kono
parents:
diff changeset
342 x = POP ();
kono
parents:
diff changeset
343 PUSH (x * y);
kono
parents:
diff changeset
344 break;
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 case BINARY_COMPARE_LT:
kono
parents:
diff changeset
347 y = POP ();
kono
parents:
diff changeset
348 x = POP ();
kono
parents:
diff changeset
349 PUSH (x < y);
kono
parents:
diff changeset
350 break;
kono
parents:
diff changeset
351
kono
parents:
diff changeset
352 case RECURSE:
kono
parents:
diff changeset
353 x = POP ();
kono
parents:
diff changeset
354 x = toyvm_function_interpret (fn, x, trace);
kono
parents:
diff changeset
355 PUSH (x);
kono
parents:
diff changeset
356 break;
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 case RETURN:
kono
parents:
diff changeset
359 return POP ();
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 /* Ops taking an operand. */
kono
parents:
diff changeset
362 case PUSH_CONST:
kono
parents:
diff changeset
363 PUSH (op->op_operand);
kono
parents:
diff changeset
364 break;
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 case JUMP_ABS_IF_TRUE:
kono
parents:
diff changeset
367 x = POP ();
kono
parents:
diff changeset
368 if (x)
kono
parents:
diff changeset
369 frame.frm_pc = op->op_operand;
kono
parents:
diff changeset
370 break;
kono
parents:
diff changeset
371
kono
parents:
diff changeset
372 default:
kono
parents:
diff changeset
373 assert (0); /* unknown opcode */
kono
parents:
diff changeset
374
kono
parents:
diff changeset
375 } /* end of switch on opcode */
kono
parents:
diff changeset
376 } /* end of while loop */
kono
parents:
diff changeset
377
kono
parents:
diff changeset
378 #undef PUSH
kono
parents:
diff changeset
379 #undef POP
kono
parents:
diff changeset
380 }
kono
parents:
diff changeset
381
kono
parents:
diff changeset
382 /* JIT compilation. */
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 struct compilation_state
kono
parents:
diff changeset
385 {
kono
parents:
diff changeset
386 gcc_jit_context *ctxt;
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 gcc_jit_type *int_type;
kono
parents:
diff changeset
389 gcc_jit_type *bool_type;
kono
parents:
diff changeset
390 gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 gcc_jit_rvalue *const_one;
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 gcc_jit_function *fn;
kono
parents:
diff changeset
395 gcc_jit_param *param_arg;
kono
parents:
diff changeset
396 gcc_jit_lvalue *stack;
kono
parents:
diff changeset
397 gcc_jit_lvalue *stack_depth;
kono
parents:
diff changeset
398 gcc_jit_lvalue *x;
kono
parents:
diff changeset
399 gcc_jit_lvalue *y;
kono
parents:
diff changeset
400
kono
parents:
diff changeset
401 gcc_jit_location *op_locs[MAX_OPS];
kono
parents:
diff changeset
402 gcc_jit_block *initial_block;
kono
parents:
diff changeset
403 gcc_jit_block *op_blocks[MAX_OPS];
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 };
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 /* Stack manipulation. */
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 static void
kono
parents:
diff changeset
410 add_push (compilation_state *state,
kono
parents:
diff changeset
411 gcc_jit_block *block,
kono
parents:
diff changeset
412 gcc_jit_rvalue *rvalue,
kono
parents:
diff changeset
413 gcc_jit_location *loc)
kono
parents:
diff changeset
414 {
kono
parents:
diff changeset
415 /* stack[stack_depth] = RVALUE */
kono
parents:
diff changeset
416 gcc_jit_block_add_assignment (
kono
parents:
diff changeset
417 block,
kono
parents:
diff changeset
418 loc,
kono
parents:
diff changeset
419 /* stack[stack_depth] */
kono
parents:
diff changeset
420 gcc_jit_context_new_array_access (
kono
parents:
diff changeset
421 state->ctxt,
kono
parents:
diff changeset
422 loc,
kono
parents:
diff changeset
423 gcc_jit_lvalue_as_rvalue (state->stack),
kono
parents:
diff changeset
424 gcc_jit_lvalue_as_rvalue (state->stack_depth)),
kono
parents:
diff changeset
425 rvalue);
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 /* "stack_depth++;". */
kono
parents:
diff changeset
428 gcc_jit_block_add_assignment_op (
kono
parents:
diff changeset
429 block,
kono
parents:
diff changeset
430 loc,
kono
parents:
diff changeset
431 state->stack_depth,
kono
parents:
diff changeset
432 GCC_JIT_BINARY_OP_PLUS,
kono
parents:
diff changeset
433 state->const_one);
kono
parents:
diff changeset
434 }
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 static void
kono
parents:
diff changeset
437 add_pop (compilation_state *state,
kono
parents:
diff changeset
438 gcc_jit_block *block,
kono
parents:
diff changeset
439 gcc_jit_lvalue *lvalue,
kono
parents:
diff changeset
440 gcc_jit_location *loc)
kono
parents:
diff changeset
441 {
kono
parents:
diff changeset
442 /* "--stack_depth;". */
kono
parents:
diff changeset
443 gcc_jit_block_add_assignment_op (
kono
parents:
diff changeset
444 block,
kono
parents:
diff changeset
445 loc,
kono
parents:
diff changeset
446 state->stack_depth,
kono
parents:
diff changeset
447 GCC_JIT_BINARY_OP_MINUS,
kono
parents:
diff changeset
448 state->const_one);
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 /* "LVALUE = stack[stack_depth];". */
kono
parents:
diff changeset
451 gcc_jit_block_add_assignment (
kono
parents:
diff changeset
452 block,
kono
parents:
diff changeset
453 loc,
kono
parents:
diff changeset
454 lvalue,
kono
parents:
diff changeset
455 /* stack[stack_depth] */
kono
parents:
diff changeset
456 gcc_jit_lvalue_as_rvalue (
kono
parents:
diff changeset
457 gcc_jit_context_new_array_access (
kono
parents:
diff changeset
458 state->ctxt,
kono
parents:
diff changeset
459 loc,
kono
parents:
diff changeset
460 gcc_jit_lvalue_as_rvalue (state->stack),
kono
parents:
diff changeset
461 gcc_jit_lvalue_as_rvalue (state->stack_depth))));
kono
parents:
diff changeset
462 }
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 /* A struct to hold the compilation results. */
kono
parents:
diff changeset
465
kono
parents:
diff changeset
466 struct toyvm_compiled_function
kono
parents:
diff changeset
467 {
kono
parents:
diff changeset
468 gcc_jit_result *cf_jit_result;
kono
parents:
diff changeset
469 toyvm_compiled_code cf_code;
kono
parents:
diff changeset
470 };
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 /* The main compilation hook. */
kono
parents:
diff changeset
473
kono
parents:
diff changeset
474 static toyvm_compiled_function *
kono
parents:
diff changeset
475 toyvm_function_compile (toyvm_function *fn)
kono
parents:
diff changeset
476 {
kono
parents:
diff changeset
477 compilation_state state;
kono
parents:
diff changeset
478 int pc;
kono
parents:
diff changeset
479 char *funcname;
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 memset (&state, 0, sizeof (state));
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 funcname = get_function_name (fn->fn_filename);
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 state.ctxt = gcc_jit_context_acquire ();
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 gcc_jit_context_set_bool_option (state.ctxt,
kono
parents:
diff changeset
488 GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
kono
parents:
diff changeset
489 0);
kono
parents:
diff changeset
490 gcc_jit_context_set_bool_option (state.ctxt,
kono
parents:
diff changeset
491 GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
kono
parents:
diff changeset
492 0);
kono
parents:
diff changeset
493 gcc_jit_context_set_int_option (state.ctxt,
kono
parents:
diff changeset
494 GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
kono
parents:
diff changeset
495 3);
kono
parents:
diff changeset
496 gcc_jit_context_set_bool_option (state.ctxt,
kono
parents:
diff changeset
497 GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
kono
parents:
diff changeset
498 0);
kono
parents:
diff changeset
499 gcc_jit_context_set_bool_option (state.ctxt,
kono
parents:
diff changeset
500 GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
kono
parents:
diff changeset
501 0);
kono
parents:
diff changeset
502 gcc_jit_context_set_bool_option (state.ctxt,
kono
parents:
diff changeset
503 GCC_JIT_BOOL_OPTION_DEBUGINFO,
kono
parents:
diff changeset
504 1);
kono
parents:
diff changeset
505
kono
parents:
diff changeset
506 /* Create types. */
kono
parents:
diff changeset
507 state.int_type =
kono
parents:
diff changeset
508 gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
kono
parents:
diff changeset
509 state.bool_type =
kono
parents:
diff changeset
510 gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
kono
parents:
diff changeset
511 state.stack_type =
kono
parents:
diff changeset
512 gcc_jit_context_new_array_type (state.ctxt, NULL,
kono
parents:
diff changeset
513 state.int_type, MAX_STACK_DEPTH);
kono
parents:
diff changeset
514
kono
parents:
diff changeset
515 /* The constant value 1. */
kono
parents:
diff changeset
516 state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 /* Create locations. */
kono
parents:
diff changeset
519 for (pc = 0; pc < fn->fn_num_ops; pc++)
kono
parents:
diff changeset
520 {
kono
parents:
diff changeset
521 toyvm_op *op = &fn->fn_ops[pc];
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
kono
parents:
diff changeset
524 fn->fn_filename,
kono
parents:
diff changeset
525 op->op_linenum,
kono
parents:
diff changeset
526 0); /* column */
kono
parents:
diff changeset
527 }
kono
parents:
diff changeset
528
kono
parents:
diff changeset
529 /* Creating the function. */
kono
parents:
diff changeset
530 state.param_arg =
kono
parents:
diff changeset
531 gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
kono
parents:
diff changeset
532 state.int_type, "arg");
kono
parents:
diff changeset
533 state.fn =
kono
parents:
diff changeset
534 gcc_jit_context_new_function (state.ctxt,
kono
parents:
diff changeset
535 state.op_locs[0],
kono
parents:
diff changeset
536 GCC_JIT_FUNCTION_EXPORTED,
kono
parents:
diff changeset
537 state.int_type,
kono
parents:
diff changeset
538 funcname,
kono
parents:
diff changeset
539 1, &state.param_arg, 0);
kono
parents:
diff changeset
540
kono
parents:
diff changeset
541 /* Create stack lvalues. */
kono
parents:
diff changeset
542 state.stack =
kono
parents:
diff changeset
543 gcc_jit_function_new_local (state.fn, NULL,
kono
parents:
diff changeset
544 state.stack_type, "stack");
kono
parents:
diff changeset
545 state.stack_depth =
kono
parents:
diff changeset
546 gcc_jit_function_new_local (state.fn, NULL,
kono
parents:
diff changeset
547 state.int_type, "stack_depth");
kono
parents:
diff changeset
548 state.x =
kono
parents:
diff changeset
549 gcc_jit_function_new_local (state.fn, NULL,
kono
parents:
diff changeset
550 state.int_type, "x");
kono
parents:
diff changeset
551 state.y =
kono
parents:
diff changeset
552 gcc_jit_function_new_local (state.fn, NULL,
kono
parents:
diff changeset
553 state.int_type, "y");
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 /* 1st pass: create blocks, one per opcode. */
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 /* We need an entry block to do one-time initialization, so create that
kono
parents:
diff changeset
558 first. */
kono
parents:
diff changeset
559 state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 /* Create a block per operation. */
kono
parents:
diff changeset
562 for (pc = 0; pc < fn->fn_num_ops; pc++)
kono
parents:
diff changeset
563 {
kono
parents:
diff changeset
564 char buf[16];
kono
parents:
diff changeset
565 sprintf (buf, "instr%i", pc);
kono
parents:
diff changeset
566 state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
kono
parents:
diff changeset
567 }
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 /* Populate the initial block. */
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 /* "stack_depth = 0;". */
kono
parents:
diff changeset
572 gcc_jit_block_add_assignment (
kono
parents:
diff changeset
573 state.initial_block,
kono
parents:
diff changeset
574 state.op_locs[0],
kono
parents:
diff changeset
575 state.stack_depth,
kono
parents:
diff changeset
576 gcc_jit_context_zero (state.ctxt, state.int_type));
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 /* "PUSH (arg);". */
kono
parents:
diff changeset
579 add_push (&state,
kono
parents:
diff changeset
580 state.initial_block,
kono
parents:
diff changeset
581 gcc_jit_param_as_rvalue (state.param_arg),
kono
parents:
diff changeset
582 state.op_locs[0]);
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 /* ...and jump to insn 0. */
kono
parents:
diff changeset
585 gcc_jit_block_end_with_jump (state.initial_block,
kono
parents:
diff changeset
586 state.op_locs[0],
kono
parents:
diff changeset
587 state.op_blocks[0]);
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 /* 2nd pass: fill in instructions. */
kono
parents:
diff changeset
590 for (pc = 0; pc < fn->fn_num_ops; pc++)
kono
parents:
diff changeset
591 {
kono
parents:
diff changeset
592 gcc_jit_location *loc = state.op_locs[pc];
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 gcc_jit_block *block = state.op_blocks[pc];
kono
parents:
diff changeset
595 gcc_jit_block *next_block = (pc < fn->fn_num_ops
kono
parents:
diff changeset
596 ? state.op_blocks[pc + 1]
kono
parents:
diff changeset
597 : NULL);
kono
parents:
diff changeset
598
kono
parents:
diff changeset
599 toyvm_op *op;
kono
parents:
diff changeset
600 op = &fn->fn_ops[pc];
kono
parents:
diff changeset
601
kono
parents:
diff changeset
602 /* Helper macros. */
kono
parents:
diff changeset
603
kono
parents:
diff changeset
604 #define X_EQUALS_POP()\
kono
parents:
diff changeset
605 add_pop (&state, block, state.x, loc)
kono
parents:
diff changeset
606 #define Y_EQUALS_POP()\
kono
parents:
diff changeset
607 add_pop (&state, block, state.y, loc)
kono
parents:
diff changeset
608 #define PUSH_RVALUE(RVALUE)\
kono
parents:
diff changeset
609 add_push (&state, block, (RVALUE), loc)
kono
parents:
diff changeset
610 #define PUSH_X()\
kono
parents:
diff changeset
611 PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
kono
parents:
diff changeset
612 #define PUSH_Y() \
kono
parents:
diff changeset
613 PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
kono
parents:
diff changeset
616
kono
parents:
diff changeset
617 /* Handle the individual opcodes. */
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 switch (op->op_opcode)
kono
parents:
diff changeset
620 {
kono
parents:
diff changeset
621 case DUP:
kono
parents:
diff changeset
622 X_EQUALS_POP ();
kono
parents:
diff changeset
623 PUSH_X ();
kono
parents:
diff changeset
624 PUSH_X ();
kono
parents:
diff changeset
625 break;
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 case ROT:
kono
parents:
diff changeset
628 Y_EQUALS_POP ();
kono
parents:
diff changeset
629 X_EQUALS_POP ();
kono
parents:
diff changeset
630 PUSH_Y ();
kono
parents:
diff changeset
631 PUSH_X ();
kono
parents:
diff changeset
632 break;
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 case BINARY_ADD:
kono
parents:
diff changeset
635 Y_EQUALS_POP ();
kono
parents:
diff changeset
636 X_EQUALS_POP ();
kono
parents:
diff changeset
637 PUSH_RVALUE (
kono
parents:
diff changeset
638 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
639 state.ctxt,
kono
parents:
diff changeset
640 loc,
kono
parents:
diff changeset
641 GCC_JIT_BINARY_OP_PLUS,
kono
parents:
diff changeset
642 state.int_type,
kono
parents:
diff changeset
643 gcc_jit_lvalue_as_rvalue (state.x),
kono
parents:
diff changeset
644 gcc_jit_lvalue_as_rvalue (state.y)));
kono
parents:
diff changeset
645 break;
kono
parents:
diff changeset
646
kono
parents:
diff changeset
647 case BINARY_SUBTRACT:
kono
parents:
diff changeset
648 Y_EQUALS_POP ();
kono
parents:
diff changeset
649 X_EQUALS_POP ();
kono
parents:
diff changeset
650 PUSH_RVALUE (
kono
parents:
diff changeset
651 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
652 state.ctxt,
kono
parents:
diff changeset
653 loc,
kono
parents:
diff changeset
654 GCC_JIT_BINARY_OP_MINUS,
kono
parents:
diff changeset
655 state.int_type,
kono
parents:
diff changeset
656 gcc_jit_lvalue_as_rvalue (state.x),
kono
parents:
diff changeset
657 gcc_jit_lvalue_as_rvalue (state.y)));
kono
parents:
diff changeset
658 break;
kono
parents:
diff changeset
659
kono
parents:
diff changeset
660 case BINARY_MULT:
kono
parents:
diff changeset
661 Y_EQUALS_POP ();
kono
parents:
diff changeset
662 X_EQUALS_POP ();
kono
parents:
diff changeset
663 PUSH_RVALUE (
kono
parents:
diff changeset
664 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
665 state.ctxt,
kono
parents:
diff changeset
666 loc,
kono
parents:
diff changeset
667 GCC_JIT_BINARY_OP_MULT,
kono
parents:
diff changeset
668 state.int_type,
kono
parents:
diff changeset
669 gcc_jit_lvalue_as_rvalue (state.x),
kono
parents:
diff changeset
670 gcc_jit_lvalue_as_rvalue (state.y)));
kono
parents:
diff changeset
671 break;
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 case BINARY_COMPARE_LT:
kono
parents:
diff changeset
674 Y_EQUALS_POP ();
kono
parents:
diff changeset
675 X_EQUALS_POP ();
kono
parents:
diff changeset
676 PUSH_RVALUE (
kono
parents:
diff changeset
677 /* cast of bool to int */
kono
parents:
diff changeset
678 gcc_jit_context_new_cast (
kono
parents:
diff changeset
679 state.ctxt,
kono
parents:
diff changeset
680 loc,
kono
parents:
diff changeset
681 /* (x < y) as a bool */
kono
parents:
diff changeset
682 gcc_jit_context_new_comparison (
kono
parents:
diff changeset
683 state.ctxt,
kono
parents:
diff changeset
684 loc,
kono
parents:
diff changeset
685 GCC_JIT_COMPARISON_LT,
kono
parents:
diff changeset
686 gcc_jit_lvalue_as_rvalue (state.x),
kono
parents:
diff changeset
687 gcc_jit_lvalue_as_rvalue (state.y)),
kono
parents:
diff changeset
688 state.int_type));
kono
parents:
diff changeset
689 break;
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 case RECURSE:
kono
parents:
diff changeset
692 {
kono
parents:
diff changeset
693 X_EQUALS_POP ();
kono
parents:
diff changeset
694 gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
kono
parents:
diff changeset
695 PUSH_RVALUE (
kono
parents:
diff changeset
696 gcc_jit_context_new_call (
kono
parents:
diff changeset
697 state.ctxt,
kono
parents:
diff changeset
698 loc,
kono
parents:
diff changeset
699 state.fn,
kono
parents:
diff changeset
700 1, &arg));
kono
parents:
diff changeset
701 break;
kono
parents:
diff changeset
702 }
kono
parents:
diff changeset
703
kono
parents:
diff changeset
704 case RETURN:
kono
parents:
diff changeset
705 X_EQUALS_POP ();
kono
parents:
diff changeset
706 gcc_jit_block_end_with_return (
kono
parents:
diff changeset
707 block,
kono
parents:
diff changeset
708 loc,
kono
parents:
diff changeset
709 gcc_jit_lvalue_as_rvalue (state.x));
kono
parents:
diff changeset
710 break;
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 /* Ops taking an operand. */
kono
parents:
diff changeset
713 case PUSH_CONST:
kono
parents:
diff changeset
714 PUSH_RVALUE (
kono
parents:
diff changeset
715 gcc_jit_context_new_rvalue_from_int (
kono
parents:
diff changeset
716 state.ctxt,
kono
parents:
diff changeset
717 state.int_type,
kono
parents:
diff changeset
718 op->op_operand));
kono
parents:
diff changeset
719 break;
kono
parents:
diff changeset
720
kono
parents:
diff changeset
721 case JUMP_ABS_IF_TRUE:
kono
parents:
diff changeset
722 X_EQUALS_POP ();
kono
parents:
diff changeset
723 gcc_jit_block_end_with_conditional (
kono
parents:
diff changeset
724 block,
kono
parents:
diff changeset
725 loc,
kono
parents:
diff changeset
726 /* "(bool)x". */
kono
parents:
diff changeset
727 gcc_jit_context_new_cast (
kono
parents:
diff changeset
728 state.ctxt,
kono
parents:
diff changeset
729 loc,
kono
parents:
diff changeset
730 gcc_jit_lvalue_as_rvalue (state.x),
kono
parents:
diff changeset
731 state.bool_type),
kono
parents:
diff changeset
732 state.op_blocks[op->op_operand], /* on_true */
kono
parents:
diff changeset
733 next_block); /* on_false */
kono
parents:
diff changeset
734 break;
kono
parents:
diff changeset
735
kono
parents:
diff changeset
736 default:
kono
parents:
diff changeset
737 assert(0);
kono
parents:
diff changeset
738 } /* end of switch on opcode */
kono
parents:
diff changeset
739
kono
parents:
diff changeset
740 /* Go to the next block. */
kono
parents:
diff changeset
741 if (op->op_opcode != JUMP_ABS_IF_TRUE
kono
parents:
diff changeset
742 && op->op_opcode != RETURN)
kono
parents:
diff changeset
743 gcc_jit_block_end_with_jump (
kono
parents:
diff changeset
744 block,
kono
parents:
diff changeset
745 loc,
kono
parents:
diff changeset
746 next_block);
kono
parents:
diff changeset
747
kono
parents:
diff changeset
748 } /* end of loop on PC locations. */
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 /* We've now finished populating the context. Compile it. */
kono
parents:
diff changeset
751 gcc_jit_result *jit_result = gcc_jit_context_compile (state.ctxt);
kono
parents:
diff changeset
752 gcc_jit_context_release (state.ctxt);
kono
parents:
diff changeset
753
kono
parents:
diff changeset
754 toyvm_compiled_function *toyvm_result =
kono
parents:
diff changeset
755 (toyvm_compiled_function *)calloc (1, sizeof (toyvm_compiled_function));
kono
parents:
diff changeset
756 if (!toyvm_result)
kono
parents:
diff changeset
757 {
kono
parents:
diff changeset
758 fprintf (stderr, "out of memory allocating toyvm_compiled_function\n");
kono
parents:
diff changeset
759 gcc_jit_result_release (jit_result);
kono
parents:
diff changeset
760 return NULL;
kono
parents:
diff changeset
761 }
kono
parents:
diff changeset
762
kono
parents:
diff changeset
763 toyvm_result->cf_jit_result = jit_result;
kono
parents:
diff changeset
764 toyvm_result->cf_code =
kono
parents:
diff changeset
765 (toyvm_compiled_code)gcc_jit_result_get_code (jit_result,
kono
parents:
diff changeset
766 funcname);
kono
parents:
diff changeset
767
kono
parents:
diff changeset
768 free (funcname);
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 return toyvm_result;
kono
parents:
diff changeset
771 }
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 char test[1024];
kono
parents:
diff changeset
774
kono
parents:
diff changeset
775 #define CHECK_NON_NULL(PTR) \
kono
parents:
diff changeset
776 do { \
kono
parents:
diff changeset
777 if ((PTR) != NULL) \
kono
parents:
diff changeset
778 { \
kono
parents:
diff changeset
779 pass ("%s: %s is non-null", test, #PTR); \
kono
parents:
diff changeset
780 } \
kono
parents:
diff changeset
781 else \
kono
parents:
diff changeset
782 { \
kono
parents:
diff changeset
783 fail ("%s: %s is NULL", test, #PTR); \
kono
parents:
diff changeset
784 abort (); \
kono
parents:
diff changeset
785 } \
kono
parents:
diff changeset
786 } while (0)
kono
parents:
diff changeset
787
kono
parents:
diff changeset
788 #define CHECK_VALUE(ACTUAL, EXPECTED) \
kono
parents:
diff changeset
789 do { \
kono
parents:
diff changeset
790 if ((ACTUAL) == (EXPECTED)) \
kono
parents:
diff changeset
791 { \
kono
parents:
diff changeset
792 pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
kono
parents:
diff changeset
793 } \
kono
parents:
diff changeset
794 else \
kono
parents:
diff changeset
795 { \
kono
parents:
diff changeset
796 fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
kono
parents:
diff changeset
797 fprintf (stderr, "incorrect value\n"); \
kono
parents:
diff changeset
798 abort (); \
kono
parents:
diff changeset
799 } \
kono
parents:
diff changeset
800 } while (0)
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 static void
kono
parents:
diff changeset
803 test_script (const char *scripts_dir, const char *script_name, int input,
kono
parents:
diff changeset
804 int expected_result)
kono
parents:
diff changeset
805 {
kono
parents:
diff changeset
806 char *script_path;
kono
parents:
diff changeset
807 toyvm_function *fn;
kono
parents:
diff changeset
808 int interpreted_result;
kono
parents:
diff changeset
809 toyvm_compiled_function *compiled_fn;
kono
parents:
diff changeset
810 toyvm_compiled_code code;
kono
parents:
diff changeset
811 int compiled_result;
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 snprintf (test, sizeof (test), "toyvm.c: %s", script_name);
kono
parents:
diff changeset
814
kono
parents:
diff changeset
815 script_path = (char *)malloc (strlen (scripts_dir)
kono
parents:
diff changeset
816 + strlen (script_name) + 1);
kono
parents:
diff changeset
817 CHECK_NON_NULL (script_path);
kono
parents:
diff changeset
818 sprintf (script_path, "%s%s", scripts_dir, script_name);
kono
parents:
diff changeset
819
kono
parents:
diff changeset
820 fn = toyvm_function_parse (script_path, script_name);
kono
parents:
diff changeset
821 CHECK_NON_NULL (fn);
kono
parents:
diff changeset
822
kono
parents:
diff changeset
823 interpreted_result = toyvm_function_interpret (fn, input, NULL);
kono
parents:
diff changeset
824 CHECK_VALUE (interpreted_result, expected_result);
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 compiled_fn = toyvm_function_compile (fn);
kono
parents:
diff changeset
827 CHECK_NON_NULL (compiled_fn);
kono
parents:
diff changeset
828
kono
parents:
diff changeset
829 code = (toyvm_compiled_code)compiled_fn->cf_code;
kono
parents:
diff changeset
830 CHECK_NON_NULL (code);
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 compiled_result = code (input);
kono
parents:
diff changeset
833 CHECK_VALUE (compiled_result, expected_result);
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 gcc_jit_result_release (compiled_fn->cf_jit_result);
kono
parents:
diff changeset
836 free (compiled_fn);
kono
parents:
diff changeset
837 free (fn);
kono
parents:
diff changeset
838 free (script_path);
kono
parents:
diff changeset
839 }
kono
parents:
diff changeset
840
kono
parents:
diff changeset
841 #define PATH_TO_SCRIPTS ("/jit/docs/examples/tut04-toyvm/")
kono
parents:
diff changeset
842
kono
parents:
diff changeset
843 static void
kono
parents:
diff changeset
844 test_suite (void)
kono
parents:
diff changeset
845 {
kono
parents:
diff changeset
846 const char *srcdir;
kono
parents:
diff changeset
847 char *scripts_dir;
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 snprintf (test, sizeof (test), "toyvm.c");
kono
parents:
diff changeset
850
kono
parents:
diff changeset
851 /* We need to locate the test scripts.
kono
parents:
diff changeset
852 Rely on "srcdir" being set in the environment. */
kono
parents:
diff changeset
853
kono
parents:
diff changeset
854 srcdir = getenv ("srcdir");
kono
parents:
diff changeset
855 CHECK_NON_NULL (srcdir);
kono
parents:
diff changeset
856
kono
parents:
diff changeset
857 scripts_dir = (char *)malloc (strlen (srcdir) + strlen(PATH_TO_SCRIPTS)
kono
parents:
diff changeset
858 + 1);
kono
parents:
diff changeset
859 CHECK_NON_NULL (scripts_dir);
kono
parents:
diff changeset
860 sprintf (scripts_dir, "%s%s", srcdir, PATH_TO_SCRIPTS);
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 test_script (scripts_dir, "factorial.toy", 10, 3628800);
kono
parents:
diff changeset
863 test_script (scripts_dir, "fibonacci.toy", 10, 55);
kono
parents:
diff changeset
864
kono
parents:
diff changeset
865 free (scripts_dir);
kono
parents:
diff changeset
866 }
kono
parents:
diff changeset
867
kono
parents:
diff changeset
868 int
kono
parents:
diff changeset
869 main (int argc, char **argv)
kono
parents:
diff changeset
870 {
kono
parents:
diff changeset
871 const char *filename = NULL;
kono
parents:
diff changeset
872 toyvm_function *fn = NULL;
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 /* If called with no args, assume we're being run by the test suite. */
kono
parents:
diff changeset
875 if (argc < 3)
kono
parents:
diff changeset
876 {
kono
parents:
diff changeset
877 test_suite ();
kono
parents:
diff changeset
878 return 0;
kono
parents:
diff changeset
879 }
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 if (argc != 3)
kono
parents:
diff changeset
882 {
kono
parents:
diff changeset
883 fprintf (stdout,
kono
parents:
diff changeset
884 "%s FILENAME INPUT: Parse and run a .toy file\n",
kono
parents:
diff changeset
885 argv[0]);
kono
parents:
diff changeset
886 exit (1);
kono
parents:
diff changeset
887 }
kono
parents:
diff changeset
888
kono
parents:
diff changeset
889 filename = argv[1];
kono
parents:
diff changeset
890 fn = toyvm_function_parse (filename, filename);
kono
parents:
diff changeset
891 if (!fn)
kono
parents:
diff changeset
892 exit (1);
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 if (0)
kono
parents:
diff changeset
895 toyvm_function_disassemble (fn, stdout);
kono
parents:
diff changeset
896
kono
parents:
diff changeset
897 printf ("interpreter result: %d\n",
kono
parents:
diff changeset
898 toyvm_function_interpret (fn, atoi (argv[2]), NULL));
kono
parents:
diff changeset
899
kono
parents:
diff changeset
900 /* JIT-compilation. */
kono
parents:
diff changeset
901 toyvm_compiled_function *compiled_fn
kono
parents:
diff changeset
902 = toyvm_function_compile (fn);
kono
parents:
diff changeset
903
kono
parents:
diff changeset
904 toyvm_compiled_code code = compiled_fn->cf_code;
kono
parents:
diff changeset
905 printf ("compiler result: %d\n",
kono
parents:
diff changeset
906 code (atoi (argv[2])));
kono
parents:
diff changeset
907
kono
parents:
diff changeset
908 gcc_jit_result_release (compiled_fn->cf_jit_result);
kono
parents:
diff changeset
909 free (compiled_fn);
kono
parents:
diff changeset
910
kono
parents:
diff changeset
911 return 0;
kono
parents:
diff changeset
912 }