1.. Copyright (C) 2014-2020 Free Software Foundation, Inc.
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
16   <http://www.gnu.org/licenses/>.
17
18.. default-domain:: cpp
19
20Tutorial part 3: Loops and variables
21------------------------------------
22Consider this C function:
23
24 .. code-block:: c
25
26  int loop_test (int n)
27  {
28    int sum = 0;
29    for (int i = 0; i < n; i++)
30      sum += i * i;
31    return sum;
32  }
33
34This example demonstrates some more features of libgccjit, with local
35variables and a loop.
36
37To break this down into libgccjit terms, it's usually easier to reword
38the `for` loop as a `while` loop, giving:
39
40 .. code-block:: c
41
42  int loop_test (int n)
43  {
44    int sum = 0;
45    int i = 0;
46    while (i < n)
47    {
48      sum += i * i;
49      i++;
50    }
51    return sum;
52  }
53
54Here's what the final control flow graph will look like:
55
56    .. figure:: ../../intro/sum-of-squares.png
57      :alt: image of a control flow graph
58
59As before, we include the libgccjit++ header and make a
60:type:`gccjit::context`.
61
62.. code-block:: c++
63
64  #include <libgccjit++.h>
65
66  void test (void)
67  {
68    gccjit::context ctxt;
69    ctxt = gccjit::context::acquire ();
70
71The function works with the C `int` type.
72
73In the previous tutorial we acquired this via
74
75.. code-block:: c++
76
77  gccjit::type the_type = ctxt.get_type (ctxt, GCC_JIT_TYPE_INT);
78
79though we could equally well make it work on, say, `double`:
80
81.. code-block:: c++
82
83  gccjit::type the_type = ctxt.get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
84
85For integer types we can use :func:`gccjit::context::get_int_type<T>`
86to directly bind a specific type:
87
88.. code-block:: c++
89
90  gccjit::type the_type = ctxt.get_int_type <int> ();
91
92Let's build the function:
93
94.. code-block:: c++
95
96  gcc_jit_param n = ctxt.new_param (the_type, "n");
97  std::vector<gccjit::param> params;
98  params.push_back (n);
99  gccjit::function func =
100    ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
101                       return_type,
102                       "loop_test",
103                       params, 0);
104
105Expressions: lvalues and rvalues
106********************************
107
108The base class of expression is the :type:`gccjit::rvalue`,
109representing an expression that can be on the *right*-hand side of
110an assignment: a value that can be computed somehow, and assigned
111*to* a storage area (such as a variable).  It has a specific
112:type:`gccjit::type`.
113
114Anothe important class is :type:`gccjit::lvalue`.
115A :type:`gccjit::lvalue`. is something that can of the *left*-hand
116side of an assignment: a storage area (such as a variable).
117
118In other words, every assignment can be thought of as:
119
120.. code-block:: c
121
122   LVALUE = RVALUE;
123
124Note that :type:`gccjit::lvalue` is a subclass of
125:type:`gccjit::rvalue`, where in an assignment of the form:
126
127.. code-block:: c
128
129   LVALUE_A = LVALUE_B;
130
131the `LVALUE_B` implies reading the current value of that storage
132area, assigning it into the `LVALUE_A`.
133
134So far the only expressions we've seen are from the previous tutorial:
135
1361. the multiplication `i * i`:
137
138  .. code-block:: c++
139
140     gccjit::rvalue expr =
141       ctxt.new_binary_op (
142         GCC_JIT_BINARY_OP_MULT, int_type,
143         param_i, param_i);
144
145     /* Alternatively, using operator-overloading: */
146     gccjit::rvalue expr = param_i * param_i;
147
148  which is a :type:`gccjit::rvalue`, and
149
1502. the various function parameters: `param_i` and `param_n`, instances of
151   :type:`gccjit::param`, which is a subclass of :type:`gccjit::lvalue`
152   (and, in turn, of :type:`gccjit::rvalue`):
153   we can both read from and write to function parameters within the
154   body of a function.
155
156Our new example has a new kind of expression: we have two local
157variables.  We create them by calling
158:func:`gccjit::function::new_local`, supplying a type and a name:
159
160.. code-block:: c++
161
162  /* Build locals:  */
163  gccjit::lvalue i = func.new_local (the_type, "i");
164  gccjit::lvalue sum = func.new_local (the_type, "sum");
165
166These are instances of :type:`gccjit::lvalue` - they can be read from
167and written to.
168
169Note that there is no precanned way to create *and* initialize a variable
170like in C:
171
172.. code-block:: c
173
174   int i = 0;
175
176Instead, having added the local to the function, we have to separately add
177an assignment of `0` to `local_i` at the beginning of the function.
178
179Control flow
180************
181
182This function has a loop, so we need to build some basic blocks to
183handle the control flow.  In this case, we need 4 blocks:
184
1851. before the loop (initializing the locals)
1862. the conditional at the top of the loop (comparing `i < n`)
1873. the body of the loop
1884. after the loop terminates (`return sum`)
189
190so we create these as :type:`gccjit::block` instances within the
191:type:`gccjit::function`:
192
193.. code-block:: c++
194
195  gccjit::block b_initial = func.new_block ("initial");
196  gccjit::block b_loop_cond = func.new_block ("loop_cond");
197  gccjit::block b_loop_body = func.new_block ("loop_body");
198  gccjit::block b_after_loop = func.new_block ("after_loop");
199
200We now populate each block with statements.
201
202The entry block `b_initial` consists of initializations followed by a jump
203to the conditional.  We assign `0` to `i` and to `sum`, using
204:func:`gccjit::block::add_assignment` to add
205an assignment statement, and using :func:`gccjit::context::zero` to get
206the constant value `0` for the relevant type for the right-hand side of
207the assignment:
208
209.. code-block:: c++
210
211  /* sum = 0; */
212  b_initial.add_assignment (sum, ctxt.zero (the_type));
213
214  /* i = 0; */
215  b_initial.add_assignment (i, ctxt.zero (the_type));
216
217We can then terminate the entry block by jumping to the conditional:
218
219.. code-block:: c++
220
221  b_initial.end_with_jump (b_loop_cond);
222
223The conditional block is equivalent to the line `while (i < n)` from our
224C example. It contains a single statement: a conditional, which jumps to
225one of two destination blocks depending on a boolean
226:type:`gccjit::rvalue`, in this case the comparison of `i` and `n`.
227
228We could build the comparison using :func:`gccjit::context::new_comparison`:
229
230.. code-block:: c++
231
232   gccjit::rvalue guard =
233     ctxt.new_comparison (GCC_JIT_COMPARISON_GE,
234                          i, n);
235
236and can then use this to add `b_loop_cond`'s sole statement, via
237:func:`gccjit::block::end_with_conditional`:
238
239.. code-block:: c++
240
241  b_loop_cond.end_with_conditional (guard,
242                                    b_after_loop, // on_true
243                                    b_loop_body); // on_false
244
245However :type:`gccjit::rvalue` has overloaded operators for this, so we
246express the conditional as
247
248.. code-block:: c++
249
250   gccjit::rvalue guard = (i >= n);
251
252and hence we can write the block more concisely as:
253
254.. code-block:: c++
255
256  b_loop_cond.end_with_conditional (
257    i >= n,
258    b_after_loop, // on_true
259    b_loop_body); // on_false
260
261Next, we populate the body of the loop.
262
263The C statement `sum += i * i;` is an assignment operation, where an
264lvalue is modified "in-place".  We use
265:func:`gccjit::block::add_assignment_op` to handle these operations:
266
267.. code-block:: c++
268
269  /* sum += i * i */
270  b_loop_body.add_assignment_op (sum,
271                                 GCC_JIT_BINARY_OP_PLUS,
272                                 i * i);
273
274The `i++` can be thought of as `i += 1`, and can thus be handled in
275a similar way.  We use :c:func:`gcc_jit_context_one` to get the constant
276value `1` (for the relevant type) for the right-hand side
277of the assignment.
278
279.. code-block:: c++
280
281  /* i++ */
282  b_loop_body.add_assignment_op (i,
283                                 GCC_JIT_BINARY_OP_PLUS,
284                                 ctxt.one (the_type));
285
286.. note::
287
288  For numeric constants other than 0 or 1, we could use
289  :func:`gccjit::context::new_rvalue`, which has overloads
290  for both ``int`` and ``double``.
291
292The loop body completes by jumping back to the conditional:
293
294.. code-block:: c++
295
296  b_loop_body.end_with_jump (b_loop_cond);
297
298Finally, we populate the `b_after_loop` block, reached when the loop
299conditional is false.  We want to generate the equivalent of:
300
301.. code-block:: c++
302
303   return sum;
304
305so the block is just one statement:
306
307.. code-block:: c++
308
309  /* return sum */
310  b_after_loop.end_with_return (sum);
311
312.. note::
313
314   You can intermingle block creation with statement creation,
315   but given that the terminator statements generally include references
316   to other blocks, I find it's clearer to create all the blocks,
317   *then* all the statements.
318
319We've finished populating the function.  As before, we can now compile it
320to machine code:
321
322.. code-block:: c++
323
324   gcc_jit_result *result;
325   result = ctxt.compile ();
326
327   ctxt.release ();
328
329   if (!result)
330     {
331       fprintf (stderr, "NULL result");
332       return 1;
333     }
334
335   typedef int (*loop_test_fn_type) (int);
336   loop_test_fn_type loop_test =
337    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
338   if (!loop_test)
339     {
340       fprintf (stderr, "NULL loop_test");
341       gcc_jit_result_release (result);
342       return 1;
343     }
344   printf ("result: %d", loop_test (10));
345
346.. code-block:: bash
347
348   result: 285
349
350
351Visualizing the control flow graph
352**********************************
353
354You can see the control flow graph of a function using
355:func:`gccjit::function::dump_to_dot`:
356
357.. code-block:: c++
358
359  func.dump_to_dot ("/tmp/sum-of-squares.dot");
360
361giving a .dot file in GraphViz format.
362
363You can convert this to an image using `dot`:
364
365.. code-block:: bash
366
367   $ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
368
369or use a viewer (my preferred one is xdot.py; see
370https://github.com/jrfonseca/xdot.py; on Fedora you can
371install it with `yum install python-xdot`):
372
373    .. figure:: ../../intro/sum-of-squares.png
374      :alt: image of a control flow graph
375
376Full example
377************
378
379   .. literalinclude:: ../../examples/tut03-sum-of-squares.cc
380    :lines: 1-
381    :language: c++
382
383Building and running it:
384
385.. code-block:: console
386
387  $ gcc \
388      tut03-sum-of-squares.cc \
389      -o tut03-sum-of-squares \
390      -lgccjit
391
392  # Run the built program:
393  $ ./tut03-sum-of-squares
394  loop_test returned: 285
395