]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/docs/intro/tutorial05.rst
Update copyright years.
[thirdparty/gcc.git] / gcc / jit / docs / intro / tutorial05.rst
CommitLineData
83ffe9cd 1.. Copyright (C) 2015-2023 Free Software Foundation, Inc.
fdce7209
DM
2 Originally contributed by David Malcolm <dmalcolm@redhat.com>
3
4 This is free software: you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see
786973ce 16 <https://www.gnu.org/licenses/>.
fdce7209
DM
17
18Tutorial part 5: Implementing an Ahead-of-Time compiler
19-------------------------------------------------------
20
21If you have a pre-existing language frontend that's compatible with
22libgccjit's license, it's possible to hook it up to libgccjit as a
23backend. In the previous example we showed
24how to do that for in-memory JIT-compilation, but libgccjit can also
25compile code directly to a file, allowing you to implement a more
26traditional ahead-of-time compiler ("JIT" is something of a misnomer
27for this use-case).
28
29The essential difference is to compile the context using
30:c:func:`gcc_jit_context_compile_to_file` rather than
31:c:func:`gcc_jit_context_compile`.
32
33The "brainf" language
34*********************
35
36In this example we use libgccjit to construct an ahead-of-time compiler
37for an esoteric programming language that we shall refer to as "brainf".
38
39brainf scripts operate on an array of bytes, with a notional data pointer
40within the array.
41
42brainf is hard for humans to read, but it's trivial to write a parser for
43it, as there is no lexing; just a stream of bytes. The operations are:
44
85cf5a23 45.. list-table::
46 :header-rows: 1
47
48 * - Character
49 - Meaning
50
51 * - ``>``
52 - ``idx += 1``
53 * - ``<``
54 - ``idx -= 1``
55 * - ``+``
56 - ``data[idx] += 1``
57 * - ``-``
58 - ``data[idx] -= 1``
59 * - ``.``
60 - ``output (data[idx])``
61 * - ``,``
62 - ``data[idx] = input ()``
63 * - ``[``
64 - loop until ``data[idx] == 0``
65 * - ``]``
66 - end of loop
67 * - Anything else
68 - ignored
fdce7209
DM
69
70Unlike the previous example, we'll implement an ahead-of-time compiler,
71which reads ``.bf`` scripts and outputs executables (though it would
72be trivial to have it run them JIT-compiled in-process).
73
74Here's what a simple ``.bf`` script looks like:
75
76 .. literalinclude:: ../examples/emit-alphabet.bf
77 :lines: 1-
78
79.. note::
80
81 This example makes use of whitespace and comments for legibility, but
82 could have been written as::
83
84 ++++++++++++++++++++++++++
85 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
86 [>.+<-]
87
88 It's not a particularly useful language, except for providing
89 compiler-writers with a test case that's easy to parse. The point
90 is that you can use :c:func:`gcc_jit_context_compile_to_file`
91 to use libgccjit as a backend for a pre-existing language frontend
92 (provided that the pre-existing frontend is compatible with libgccjit's
93 license).
94
95Converting a brainf script to libgccjit IR
96******************************************
97
85c943f3 98As before we write simple code to populate a :c:expr:`gcc_jit_context *`.
fdce7209
DM
99
100 .. literalinclude:: ../examples/tut05-bf.c
101 :start-after: #define MAX_OPEN_PARENS 16
102 :end-before: /* Entrypoint to the compiler. */
103 :language: c
104
105Compiling a context to a file
106*****************************
107
108Unlike the previous tutorial, this time we'll compile the context
109directly to an executable, using :c:func:`gcc_jit_context_compile_to_file`:
110
111.. code-block:: c
112
113 gcc_jit_context_compile_to_file (ctxt,
114 GCC_JIT_OUTPUT_KIND_EXECUTABLE,
115 output_file);
116
117Here's the top-level of the compiler, which is what actually calls into
118:c:func:`gcc_jit_context_compile_to_file`:
119
120 .. literalinclude:: ../examples/tut05-bf.c
121 :start-after: /* Entrypoint to the compiler. */
122 :end-before: /* Use the built compiler to compile the example to an executable:
123 :language: c
124
125Note how once the context is populated you could trivially instead compile
126it to memory using :c:func:`gcc_jit_context_compile` and run it in-process
127as in the previous tutorial.
128
129To create an executable, we need to export a ``main`` function. Here's
130how to create one from the JIT API:
131
132 .. literalinclude:: ../examples/tut05-bf.c
133 :start-after: #include "libgccjit.h"
134 :end-before: #define MAX_OPEN_PARENS 16
135 :language: c
136
137.. note::
138
139 The above implementation ignores ``argc`` and ``argv``, but you could
140 make use of them by exposing ``param_argc`` and ``param_argv`` to the
141 caller.
142
143Upon compiling this C code, we obtain a bf-to-machine-code compiler;
144let's call it ``bfc``:
145
146.. code-block:: console
147
148 $ gcc \
149 tut05-bf.c \
150 -o bfc \
151 -lgccjit
152
153We can now use ``bfc`` to compile .bf files into machine code executables:
154
155.. code-block:: console
156
157 $ ./bfc \
158 emit-alphabet.bf \
159 a.out
160
161which we can run directly:
162
163.. code-block:: console
164
165 $ ./a.out
166 ABCDEFGHIJKLMNOPQRSTUVWXYZ
167
168Success!
169
170We can also inspect the generated executable using standard tools:
171
172.. code-block:: console
173
174 $ objdump -d a.out |less
175
176which shows that libgccjit has managed to optimize the function
177somewhat (for example, the runs of 26 and 65 increment operations
178have become integer constants 0x1a and 0x41):
179
180.. code-block:: console
181
182 0000000000400620 <main>:
183 400620: 80 3d 39 0a 20 00 00 cmpb $0x0,0x200a39(%rip) # 601060 <data
184 400627: 74 07 je 400630 <main
185 400629: eb fe jmp 400629 <main+0x9>
186 40062b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
187 400630: 48 83 ec 08 sub $0x8,%rsp
188 400634: 0f b6 05 26 0a 20 00 movzbl 0x200a26(%rip),%eax # 601061 <data_cells+0x1>
189 40063b: c6 05 1e 0a 20 00 1a movb $0x1a,0x200a1e(%rip) # 601060 <data_cells>
190 400642: 8d 78 41 lea 0x41(%rax),%edi
191 400645: 40 88 3d 15 0a 20 00 mov %dil,0x200a15(%rip) # 601061 <data_cells+0x1>
192 40064c: 0f 1f 40 00 nopl 0x0(%rax)
193 400650: 40 0f b6 ff movzbl %dil,%edi
194 400654: e8 87 fe ff ff callq 4004e0 <putchar@plt>
195 400659: 0f b6 05 01 0a 20 00 movzbl 0x200a01(%rip),%eax # 601061 <data_cells+0x1>
196 400660: 80 2d f9 09 20 00 01 subb $0x1,0x2009f9(%rip) # 601060 <data_cells>
197 400667: 8d 78 01 lea 0x1(%rax),%edi
198 40066a: 40 88 3d f0 09 20 00 mov %dil,0x2009f0(%rip) # 601061 <data_cells+0x1>
199 400671: 75 dd jne 400650 <main+0x30>
200 400673: 31 c0 xor %eax,%eax
201 400675: 48 83 c4 08 add $0x8,%rsp
202 400679: c3 retq
203 40067a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
204
205We also set up debugging information (via
206:c:func:`gcc_jit_context_new_location` and
207:c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO`), so it's possible to use ``gdb``
208to singlestep through the generated binary and inspect the internal
209state ``idx`` and ``data_cells``:
210
211.. code-block:: console
212
213 (gdb) break main
214 Breakpoint 1 at 0x400790
215 (gdb) run
216 Starting program: a.out
217
218 Breakpoint 1, 0x0000000000400790 in main (argc=1, argv=0x7fffffffe448)
219 (gdb) stepi
220 0x0000000000400797 in main (argc=1, argv=0x7fffffffe448)
221 (gdb) stepi
222 0x00000000004007a0 in main (argc=1, argv=0x7fffffffe448)
223 (gdb) stepi
224 9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
225 (gdb) list
226 4
227 5 cell 0 = 26
228 6 ++++++++++++++++++++++++++
229 7
230 8 cell 1 = 65
231 9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
232 10
233 11 while cell#0 != 0
234 12 [
235 13 >
236 (gdb) n
237 6 ++++++++++++++++++++++++++
238 (gdb) n
239 9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
240 (gdb) p idx
241 $1 = 1
242 (gdb) p data_cells
243 $2 = "\032", '\000' <repeats 29998 times>
244 (gdb) p data_cells[0]
245 $3 = 26 '\032'
246 (gdb) p data_cells[1]
247 $4 = 0 '\000'
248 (gdb) list
249 4
250 5 cell 0 = 26
251 6 ++++++++++++++++++++++++++
252 7
253 8 cell 1 = 65
254 9 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
255 10
256 11 while cell#0 != 0
257 12 [
258 13 >
259
260
261Other forms of ahead-of-time-compilation
262****************************************
263
85c943f3 264The above demonstrates compiling a :c:expr:`gcc_jit_context *` directly
fdce7209
DM
265to an executable. It's also possible to compile it to an object file,
266and to a dynamic library. See the documentation of
267:c:func:`gcc_jit_context_compile_to_file` for more information.