summaryrefslogtreecommitdiff
path: root/gcc/jit/docs/examples/tut05-bf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/jit/docs/examples/tut05-bf.c')
-rw-r--r--gcc/jit/docs/examples/tut05-bf.c446
1 files changed, 446 insertions, 0 deletions
diff --git a/gcc/jit/docs/examples/tut05-bf.c b/gcc/jit/docs/examples/tut05-bf.c
new file mode 100644
index 00000000000..f948ede796a
--- /dev/null
+++ b/gcc/jit/docs/examples/tut05-bf.c
@@ -0,0 +1,446 @@
+/* A compiler for the "bf" language. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libgccjit.h"
+
+/* Make "main" function:
+ int
+ main (int argc, char **argv)
+ {
+ ...
+ }
+*/
+static gcc_jit_function *
+make_main (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_param *param_argc =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
+ gcc_jit_type *char_ptr_ptr_type =
+ gcc_jit_type_get_pointer (
+ gcc_jit_type_get_pointer (
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
+ gcc_jit_param *param_argv =
+ gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
+ gcc_jit_param *params[2] = {param_argc, param_argv};
+ gcc_jit_function *func_main =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "main",
+ 2, params,
+ 0);
+ return func_main;
+}
+
+#define MAX_OPEN_PARENS 16
+
+typedef struct bf_compiler
+{
+ const char *filename;
+ int line;
+ int column;
+
+ gcc_jit_context *ctxt;
+
+ gcc_jit_type *void_type;
+ gcc_jit_type *int_type;
+ gcc_jit_type *byte_type;
+ gcc_jit_type *array_type;
+
+ gcc_jit_function *func_getchar;
+ gcc_jit_function *func_putchar;
+
+ gcc_jit_function *func;
+ gcc_jit_block *curblock;
+
+ gcc_jit_rvalue *int_zero;
+ gcc_jit_rvalue *int_one;
+ gcc_jit_rvalue *byte_zero;
+ gcc_jit_rvalue *byte_one;
+ gcc_jit_lvalue *data_cells;
+ gcc_jit_lvalue *idx;
+
+ int num_open_parens;
+ gcc_jit_block *paren_test[MAX_OPEN_PARENS];
+ gcc_jit_block *paren_body[MAX_OPEN_PARENS];
+ gcc_jit_block *paren_after[MAX_OPEN_PARENS];
+
+} bf_compiler;
+
+/* Bail out, with a message on stderr. */
+
+static void
+fatal_error (bf_compiler *bfc, const char *msg)
+{
+ fprintf (stderr,
+ "%s:%i:%i: %s",
+ bfc->filename, bfc->line, bfc->column, msg);
+ abort ();
+}
+
+/* Get "data_cells[idx]" as an lvalue. */
+
+static gcc_jit_lvalue *
+bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
+{
+ return gcc_jit_context_new_array_access (
+ bfc->ctxt,
+ loc,
+ gcc_jit_lvalue_as_rvalue (bfc->data_cells),
+ gcc_jit_lvalue_as_rvalue (bfc->idx));
+}
+
+/* Get "data_cells[idx] == 0" as a boolean rvalue. */
+
+static gcc_jit_rvalue *
+bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
+{
+ return gcc_jit_context_new_comparison (
+ bfc->ctxt,
+ loc,
+ GCC_JIT_COMPARISON_EQ,
+ gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
+ bfc->byte_zero);
+}
+
+/* Compile one bf character. */
+
+static void
+bf_compile_char (bf_compiler *bfc,
+ unsigned char ch)
+{
+ gcc_jit_location *loc =
+ gcc_jit_context_new_location (bfc->ctxt,
+ bfc->filename,
+ bfc->line,
+ bfc->column);
+
+ /* Turn this on to trace execution, by injecting putchar ()
+ of each source char. */
+ if (0)
+ {
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (
+ bfc->ctxt,
+ bfc->int_type,
+ ch);
+ gcc_jit_rvalue *call =
+ gcc_jit_context_new_call (bfc->ctxt,
+ loc,
+ bfc->func_putchar,
+ 1, &arg);
+ gcc_jit_block_add_eval (bfc->curblock,
+ loc,
+ call);
+ }
+
+ switch (ch)
+ {
+ case '>':
+ gcc_jit_block_add_comment (bfc->curblock,
+ loc,
+ "'>': idx += 1;");
+ gcc_jit_block_add_assignment_op (bfc->curblock,
+ loc,
+ bfc->idx,
+ GCC_JIT_BINARY_OP_PLUS,
+ bfc->int_one);
+ break;
+
+ case '<':
+ gcc_jit_block_add_comment (bfc->curblock,
+ loc,
+ "'<': idx -= 1;");
+ gcc_jit_block_add_assignment_op (bfc->curblock,
+ loc,
+ bfc->idx,
+ GCC_JIT_BINARY_OP_MINUS,
+ bfc->int_one);
+ break;
+
+ case '+':
+ gcc_jit_block_add_comment (bfc->curblock,
+ loc,
+ "'+': data[idx] += 1;");
+ gcc_jit_block_add_assignment_op (bfc->curblock,
+ loc,
+ bf_get_current_data (bfc, loc),
+ GCC_JIT_BINARY_OP_PLUS,
+ bfc->byte_one);
+ break;
+
+ case '-':
+ gcc_jit_block_add_comment (bfc->curblock,
+ loc,
+ "'-': data[idx] -= 1;");
+ gcc_jit_block_add_assignment_op (bfc->curblock,
+ loc,
+ bf_get_current_data (bfc, loc),
+ GCC_JIT_BINARY_OP_MINUS,
+ bfc->byte_one);
+ break;
+
+ case '.':
+ {
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_cast (
+ bfc->ctxt,
+ loc,
+ gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
+ bfc->int_type);
+ gcc_jit_rvalue *call =
+ gcc_jit_context_new_call (bfc->ctxt,
+ loc,
+ bfc->func_putchar,
+ 1, &arg);
+ gcc_jit_block_add_comment (bfc->curblock,
+ loc,
+ "'.': putchar ((int)data[idx]);");
+ gcc_jit_block_add_eval (bfc->curblock,
+ loc,
+ call);
+ }
+ break;
+
+ case ',':
+ {
+ gcc_jit_rvalue *call =
+ gcc_jit_context_new_call (bfc->ctxt,
+ loc,
+ bfc->func_getchar,
+ 0, NULL);
+ gcc_jit_block_add_comment (
+ bfc->curblock,
+ loc,
+ "',': data[idx] = (unsigned char)getchar ();");
+ gcc_jit_block_add_assignment (bfc->curblock,
+ loc,
+ bf_get_current_data (bfc, loc),
+ gcc_jit_context_new_cast (
+ bfc->ctxt,
+ loc,
+ call,
+ bfc->byte_type));
+ }
+ break;
+
+ case '[':
+ {
+ gcc_jit_block *loop_test =
+ gcc_jit_function_new_block (bfc->func, NULL);
+ gcc_jit_block *on_zero =
+ gcc_jit_function_new_block (bfc->func, NULL);
+ gcc_jit_block *on_non_zero =
+ gcc_jit_function_new_block (bfc->func, NULL);
+
+ if (bfc->num_open_parens == MAX_OPEN_PARENS)
+ fatal_error (bfc, "too many open parens");
+
+ gcc_jit_block_end_with_jump (
+ bfc->curblock,
+ loc,
+ loop_test);
+
+ gcc_jit_block_add_comment (
+ loop_test,
+ loc,
+ "'['");
+ gcc_jit_block_end_with_conditional (
+ loop_test,
+ loc,
+ bf_current_data_is_zero (bfc, loc),
+ on_zero,
+ on_non_zero);
+ bfc->paren_test[bfc->num_open_parens] = loop_test;
+ bfc->paren_body[bfc->num_open_parens] = on_non_zero;
+ bfc->paren_after[bfc->num_open_parens] = on_zero;
+ bfc->num_open_parens += 1;
+ bfc->curblock = on_non_zero;
+ }
+ break;
+
+ case ']':
+ {
+ gcc_jit_block_add_comment (
+ bfc->curblock,
+ loc,
+ "']'");
+
+ if (bfc->num_open_parens == 0)
+ fatal_error (bfc, "mismatching parens");
+ bfc->num_open_parens -= 1;
+ gcc_jit_block_end_with_jump (
+ bfc->curblock,
+ loc,
+ bfc->paren_test[bfc->num_open_parens]);
+ bfc->curblock = bfc->paren_after[bfc->num_open_parens];
+ }
+ break;
+
+ case '\n':
+ bfc->line +=1;
+ bfc->column = 0;
+ break;
+ }
+
+ if (ch != '\n')
+ bfc->column += 1;
+}
+
+/* Compile the given .bf file into a gcc_jit_context, containing a
+ single "main" function suitable for compiling into an executable. */
+
+gcc_jit_context *
+bf_compile (const char *filename)
+{
+ bf_compiler bfc;
+ FILE *f_in;
+ int ch;
+
+ memset (&bfc, 0, sizeof (bfc));
+
+ bfc.filename = filename;
+ f_in = fopen (filename, "r");
+ if (!f_in)
+ fatal_error (&bfc, "unable to open file");
+ bfc.line = 1;
+
+ bfc.ctxt = gcc_jit_context_acquire ();
+
+ gcc_jit_context_set_int_option (
+ bfc.ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ 3);
+ gcc_jit_context_set_bool_option (
+ bfc.ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+ 0);
+ gcc_jit_context_set_bool_option (
+ bfc.ctxt,
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+ 1);
+ gcc_jit_context_set_bool_option (
+ bfc.ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+ 0);
+ gcc_jit_context_set_bool_option (
+ bfc.ctxt,
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+ 0);
+
+ bfc.void_type =
+ gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
+ bfc.int_type =
+ gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
+ bfc.byte_type =
+ gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
+ bfc.array_type =
+ gcc_jit_context_new_array_type (bfc.ctxt,
+ NULL,
+ bfc.byte_type,
+ 30000);
+
+ bfc.func_getchar =
+ gcc_jit_context_new_function (bfc.ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ bfc.int_type,
+ "getchar",
+ 0, NULL,
+ 0);
+
+ gcc_jit_param *param_c =
+ gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
+ bfc.func_putchar =
+ gcc_jit_context_new_function (bfc.ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ bfc.void_type,
+ "putchar",
+ 1, &param_c,
+ 0);
+
+ bfc.func = make_main (bfc.ctxt);
+ bfc.curblock =
+ gcc_jit_function_new_block (bfc.func, "initial");
+ bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
+ bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
+ bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
+ bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
+
+ bfc.data_cells =
+ gcc_jit_context_new_global (bfc.ctxt, NULL,
+ GCC_JIT_GLOBAL_INTERNAL,
+ bfc.array_type,
+ "data_cells");
+ bfc.idx =
+ gcc_jit_function_new_local (bfc.func, NULL,
+ bfc.int_type,
+ "idx");
+
+ gcc_jit_block_add_comment (bfc.curblock,
+ NULL,
+ "idx = 0;");
+ gcc_jit_block_add_assignment (bfc.curblock,
+ NULL,
+ bfc.idx,
+ bfc.int_zero);
+
+ bfc.num_open_parens = 0;
+
+ while ( EOF != (ch = fgetc (f_in)))
+ bf_compile_char (&bfc, (unsigned char)ch);
+
+ gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
+
+ fclose (f_in);
+
+ return bfc.ctxt;
+}
+
+/* Entrypoint to the compiler. */
+
+int
+main (int argc, char **argv)
+{
+ const char *input_file;
+ const char *output_file;
+ gcc_jit_context *ctxt;
+ const char *err;
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
+ return 1;
+ }
+
+ input_file = argv[1];
+ output_file = argv[2];
+ ctxt = bf_compile (input_file);
+
+ gcc_jit_context_compile_to_file (ctxt,
+ GCC_JIT_OUTPUT_KIND_EXECUTABLE,
+ output_file);
+
+ err = gcc_jit_context_get_first_error (ctxt);
+
+ if (err)
+ {
+ gcc_jit_context_release (ctxt);
+ return 1;
+ }
+
+ gcc_jit_context_release (ctxt);
+ return 0;
+}
+
+/* Use the built compiler to compile the example to an executable:
+
+ { dg-jit-set-exe-params SRCDIR/gcc/jit/docs/examples/emit-alphabet.bf emit-alphabet.bf.exe }
+
+ Then run the executable, and verify that it emits the alphabet:
+
+ { dg-final { jit-run-executable emit-alphabet.bf.exe "ABCDEFGHIJKLMNOPQRSTUVWXYZ" } } */