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