annotate gcc/jit/docs/intro/tutorial03.rst @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1 .. Copyright (C) 2014-2018 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2 Originally contributed by David Malcolm <dmalcolm@redhat.com>
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This is free software: you can redistribute it and/or modify it
kono
parents:
diff changeset
5 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
6 the Free Software Foundation, either version 3 of the License, or
kono
parents:
diff changeset
7 (at your option) any later version.
kono
parents:
diff changeset
8
kono
parents:
diff changeset
9 This program is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
10 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
12 General Public License for more details.
kono
parents:
diff changeset
13
kono
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
15 along with this program. If not, see
kono
parents:
diff changeset
16 <http://www.gnu.org/licenses/>.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 Tutorial part 3: Loops and variables
kono
parents:
diff changeset
19 ------------------------------------
kono
parents:
diff changeset
20 Consider this C function:
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 .. code-block:: c
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 int loop_test (int n)
kono
parents:
diff changeset
25 {
kono
parents:
diff changeset
26 int sum = 0;
kono
parents:
diff changeset
27 for (int i = 0; i < n; i++)
kono
parents:
diff changeset
28 sum += i * i;
kono
parents:
diff changeset
29 return sum;
kono
parents:
diff changeset
30 }
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 This example demonstrates some more features of libgccjit, with local
kono
parents:
diff changeset
33 variables and a loop.
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 To break this down into libgccjit terms, it's usually easier to reword
kono
parents:
diff changeset
36 the `for` loop as a `while` loop, giving:
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 .. code-block:: c
kono
parents:
diff changeset
39
kono
parents:
diff changeset
40 int loop_test (int n)
kono
parents:
diff changeset
41 {
kono
parents:
diff changeset
42 int sum = 0;
kono
parents:
diff changeset
43 int i = 0;
kono
parents:
diff changeset
44 while (i < n)
kono
parents:
diff changeset
45 {
kono
parents:
diff changeset
46 sum += i * i;
kono
parents:
diff changeset
47 i++;
kono
parents:
diff changeset
48 }
kono
parents:
diff changeset
49 return sum;
kono
parents:
diff changeset
50 }
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 Here's what the final control flow graph will look like:
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 .. figure:: sum-of-squares.png
kono
parents:
diff changeset
55 :alt: image of a control flow graph
kono
parents:
diff changeset
56
kono
parents:
diff changeset
57 As before, we include the libgccjit header and make a
kono
parents:
diff changeset
58 :c:type:`gcc_jit_context *`.
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 .. code-block:: c
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 #include <libgccjit.h>
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 void test (void)
kono
parents:
diff changeset
65 {
kono
parents:
diff changeset
66 gcc_jit_context *ctxt;
kono
parents:
diff changeset
67 ctxt = gcc_jit_context_acquire ();
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 The function works with the C `int` type:
kono
parents:
diff changeset
70
kono
parents:
diff changeset
71 .. code-block:: c
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 gcc_jit_type *the_type =
kono
parents:
diff changeset
74 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
kono
parents:
diff changeset
75 gcc_jit_type *return_type = the_type;
kono
parents:
diff changeset
76
kono
parents:
diff changeset
77 though we could equally well make it work on, say, `double`:
kono
parents:
diff changeset
78
kono
parents:
diff changeset
79 .. code-block:: c
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 gcc_jit_type *the_type =
kono
parents:
diff changeset
82 gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84 Let's build the function:
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 .. code-block:: c
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 gcc_jit_param *n =
kono
parents:
diff changeset
89 gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
kono
parents:
diff changeset
90 gcc_jit_param *params[1] = {n};
kono
parents:
diff changeset
91 gcc_jit_function *func =
kono
parents:
diff changeset
92 gcc_jit_context_new_function (ctxt, NULL,
kono
parents:
diff changeset
93 GCC_JIT_FUNCTION_EXPORTED,
kono
parents:
diff changeset
94 return_type,
kono
parents:
diff changeset
95 "loop_test",
kono
parents:
diff changeset
96 1, params, 0);
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 Expressions: lvalues and rvalues
kono
parents:
diff changeset
99 ********************************
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 The base class of expression is the :c:type:`gcc_jit_rvalue *`,
kono
parents:
diff changeset
102 representing an expression that can be on the *right*-hand side of
kono
parents:
diff changeset
103 an assignment: a value that can be computed somehow, and assigned
kono
parents:
diff changeset
104 *to* a storage area (such as a variable). It has a specific
kono
parents:
diff changeset
105 :c:type:`gcc_jit_type *`.
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 Anothe important class is :c:type:`gcc_jit_lvalue *`.
kono
parents:
diff changeset
108 A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand
kono
parents:
diff changeset
109 side of an assignment: a storage area (such as a variable).
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 In other words, every assignment can be thought of as:
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 .. code-block:: c
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 LVALUE = RVALUE;
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 Note that :c:type:`gcc_jit_lvalue *` is a subclass of
kono
parents:
diff changeset
118 :c:type:`gcc_jit_rvalue *`, where in an assignment of the form:
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 .. code-block:: c
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 LVALUE_A = LVALUE_B;
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 the `LVALUE_B` implies reading the current value of that storage
kono
parents:
diff changeset
125 area, assigning it into the `LVALUE_A`.
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 So far the only expressions we've seen are `i * i`:
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 .. code-block:: c
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 gcc_jit_rvalue *expr =
kono
parents:
diff changeset
132 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
133 ctxt, NULL,
kono
parents:
diff changeset
134 GCC_JIT_BINARY_OP_MULT, int_type,
kono
parents:
diff changeset
135 gcc_jit_param_as_rvalue (param_i),
kono
parents:
diff changeset
136 gcc_jit_param_as_rvalue (param_i));
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 which is a :c:type:`gcc_jit_rvalue *`, and the various function
kono
parents:
diff changeset
139 parameters: `param_i` and `param_n`, instances of
kono
parents:
diff changeset
140 :c:type:`gcc_jit_param *`, which is a subclass of
kono
parents:
diff changeset
141 :c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`gcc_jit_rvalue *`):
kono
parents:
diff changeset
142 we can both read from and write to function parameters within the
kono
parents:
diff changeset
143 body of a function.
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 Our new example has a couple of local variables. We create them by
kono
parents:
diff changeset
146 calling :c:func:`gcc_jit_function_new_local`, supplying a type and a
kono
parents:
diff changeset
147 name:
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 .. code-block:: c
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 /* Build locals: */
kono
parents:
diff changeset
152 gcc_jit_lvalue *i =
kono
parents:
diff changeset
153 gcc_jit_function_new_local (func, NULL, the_type, "i");
kono
parents:
diff changeset
154 gcc_jit_lvalue *sum =
kono
parents:
diff changeset
155 gcc_jit_function_new_local (func, NULL, the_type, "sum");
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from
kono
parents:
diff changeset
158 and written to.
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 Note that there is no precanned way to create *and* initialize a variable
kono
parents:
diff changeset
161 like in C:
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 .. code-block:: c
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 int i = 0;
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 Instead, having added the local to the function, we have to separately add
kono
parents:
diff changeset
168 an assignment of `0` to `local_i` at the beginning of the function.
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 Control flow
kono
parents:
diff changeset
171 ************
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 This function has a loop, so we need to build some basic blocks to
kono
parents:
diff changeset
174 handle the control flow. In this case, we need 4 blocks:
kono
parents:
diff changeset
175
kono
parents:
diff changeset
176 1. before the loop (initializing the locals)
kono
parents:
diff changeset
177 2. the conditional at the top of the loop (comparing `i < n`)
kono
parents:
diff changeset
178 3. the body of the loop
kono
parents:
diff changeset
179 4. after the loop terminates (`return sum`)
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 so we create these as :c:type:`gcc_jit_block *` instances within the
kono
parents:
diff changeset
182 :c:type:`gcc_jit_function *`:
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 .. code-block:: c
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 gcc_jit_block *b_initial =
kono
parents:
diff changeset
187 gcc_jit_function_new_block (func, "initial");
kono
parents:
diff changeset
188 gcc_jit_block *b_loop_cond =
kono
parents:
diff changeset
189 gcc_jit_function_new_block (func, "loop_cond");
kono
parents:
diff changeset
190 gcc_jit_block *b_loop_body =
kono
parents:
diff changeset
191 gcc_jit_function_new_block (func, "loop_body");
kono
parents:
diff changeset
192 gcc_jit_block *b_after_loop =
kono
parents:
diff changeset
193 gcc_jit_function_new_block (func, "after_loop");
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 We now populate each block with statements.
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 The entry block `b_initial` consists of initializations followed by a jump
kono
parents:
diff changeset
198 to the conditional. We assign `0` to `i` and to `sum`, using
kono
parents:
diff changeset
199 :c:func:`gcc_jit_block_add_assignment` to add
kono
parents:
diff changeset
200 an assignment statement, and using :c:func:`gcc_jit_context_zero` to get
kono
parents:
diff changeset
201 the constant value `0` for the relevant type for the right-hand side of
kono
parents:
diff changeset
202 the assignment:
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 .. code-block:: c
kono
parents:
diff changeset
205
kono
parents:
diff changeset
206 /* sum = 0; */
kono
parents:
diff changeset
207 gcc_jit_block_add_assignment (
kono
parents:
diff changeset
208 b_initial, NULL,
kono
parents:
diff changeset
209 sum,
kono
parents:
diff changeset
210 gcc_jit_context_zero (ctxt, the_type));
kono
parents:
diff changeset
211
kono
parents:
diff changeset
212 /* i = 0; */
kono
parents:
diff changeset
213 gcc_jit_block_add_assignment (
kono
parents:
diff changeset
214 b_initial, NULL,
kono
parents:
diff changeset
215 i,
kono
parents:
diff changeset
216 gcc_jit_context_zero (ctxt, the_type));
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 We can then terminate the entry block by jumping to the conditional:
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 .. code-block:: c
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 The conditional block is equivalent to the line `while (i < n)` from our
kono
parents:
diff changeset
225 C example. It contains a single statement: a conditional, which jumps to
kono
parents:
diff changeset
226 one of two destination blocks depending on a boolean
kono
parents:
diff changeset
227 :c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`.
kono
parents:
diff changeset
228 We build the comparison using :c:func:`gcc_jit_context_new_comparison`:
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 .. code-block:: c
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 /* (i >= n) */
kono
parents:
diff changeset
233 gcc_jit_rvalue *guard =
kono
parents:
diff changeset
234 gcc_jit_context_new_comparison (
kono
parents:
diff changeset
235 ctxt, NULL,
kono
parents:
diff changeset
236 GCC_JIT_COMPARISON_GE,
kono
parents:
diff changeset
237 gcc_jit_lvalue_as_rvalue (i),
kono
parents:
diff changeset
238 gcc_jit_param_as_rvalue (n));
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 and can then use this to add `b_loop_cond`'s sole statement, via
kono
parents:
diff changeset
241 :c:func:`gcc_jit_block_end_with_conditional`:
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 .. code-block:: c
kono
parents:
diff changeset
244
kono
parents:
diff changeset
245 /* Equivalent to:
kono
parents:
diff changeset
246 if (guard)
kono
parents:
diff changeset
247 goto after_loop;
kono
parents:
diff changeset
248 else
kono
parents:
diff changeset
249 goto loop_body; */
kono
parents:
diff changeset
250 gcc_jit_block_end_with_conditional (
kono
parents:
diff changeset
251 b_loop_cond, NULL,
kono
parents:
diff changeset
252 guard,
kono
parents:
diff changeset
253 b_after_loop, /* on_true */
kono
parents:
diff changeset
254 b_loop_body); /* on_false */
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 Next, we populate the body of the loop.
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 The C statement `sum += i * i;` is an assignment operation, where an
kono
parents:
diff changeset
259 lvalue is modified "in-place". We use
kono
parents:
diff changeset
260 :c:func:`gcc_jit_block_add_assignment_op` to handle these operations:
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 .. code-block:: c
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 /* sum += i * i */
kono
parents:
diff changeset
265 gcc_jit_block_add_assignment_op (
kono
parents:
diff changeset
266 b_loop_body, NULL,
kono
parents:
diff changeset
267 sum,
kono
parents:
diff changeset
268 GCC_JIT_BINARY_OP_PLUS,
kono
parents:
diff changeset
269 gcc_jit_context_new_binary_op (
kono
parents:
diff changeset
270 ctxt, NULL,
kono
parents:
diff changeset
271 GCC_JIT_BINARY_OP_MULT, the_type,
kono
parents:
diff changeset
272 gcc_jit_lvalue_as_rvalue (i),
kono
parents:
diff changeset
273 gcc_jit_lvalue_as_rvalue (i)));
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 The `i++` can be thought of as `i += 1`, and can thus be handled in
kono
parents:
diff changeset
276 a similar way. We use :c:func:`gcc_jit_context_one` to get the constant
kono
parents:
diff changeset
277 value `1` (for the relevant type) for the right-hand side
kono
parents:
diff changeset
278 of the assignment.
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 .. code-block:: c
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 /* i++ */
kono
parents:
diff changeset
283 gcc_jit_block_add_assignment_op (
kono
parents:
diff changeset
284 b_loop_body, NULL,
kono
parents:
diff changeset
285 i,
kono
parents:
diff changeset
286 GCC_JIT_BINARY_OP_PLUS,
kono
parents:
diff changeset
287 gcc_jit_context_one (ctxt, the_type));
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 .. note::
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 For numeric constants other than 0 or 1, we could use
kono
parents:
diff changeset
292 :c:func:`gcc_jit_context_new_rvalue_from_int` and
kono
parents:
diff changeset
293 :c:func:`gcc_jit_context_new_rvalue_from_double`.
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 The loop body completes by jumping back to the conditional:
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 .. code-block:: c
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 Finally, we populate the `b_after_loop` block, reached when the loop
kono
parents:
diff changeset
302 conditional is false. We want to generate the equivalent of:
kono
parents:
diff changeset
303
kono
parents:
diff changeset
304 .. code-block:: c
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 return sum;
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 so the block is just one statement:
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 .. code-block:: c
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 /* return sum */
kono
parents:
diff changeset
313 gcc_jit_block_end_with_return (
kono
parents:
diff changeset
314 b_after_loop,
kono
parents:
diff changeset
315 NULL,
kono
parents:
diff changeset
316 gcc_jit_lvalue_as_rvalue (sum));
kono
parents:
diff changeset
317
kono
parents:
diff changeset
318 .. note::
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320 You can intermingle block creation with statement creation,
kono
parents:
diff changeset
321 but given that the terminator statements generally include references
kono
parents:
diff changeset
322 to other blocks, I find it's clearer to create all the blocks,
kono
parents:
diff changeset
323 *then* all the statements.
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 We've finished populating the function. As before, we can now compile it
kono
parents:
diff changeset
326 to machine code:
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 .. code-block:: c
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 gcc_jit_result *result;
kono
parents:
diff changeset
331 result = gcc_jit_context_compile (ctxt);
kono
parents:
diff changeset
332
kono
parents:
diff changeset
333 typedef int (*loop_test_fn_type) (int);
kono
parents:
diff changeset
334 loop_test_fn_type loop_test =
kono
parents:
diff changeset
335 (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
kono
parents:
diff changeset
336 if (!loop_test)
kono
parents:
diff changeset
337 goto error;
kono
parents:
diff changeset
338 printf ("result: %d", loop_test (10));
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 .. code-block:: bash
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 result: 285
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344
kono
parents:
diff changeset
345 Visualizing the control flow graph
kono
parents:
diff changeset
346 **********************************
kono
parents:
diff changeset
347
kono
parents:
diff changeset
348 You can see the control flow graph of a function using
kono
parents:
diff changeset
349 :c:func:`gcc_jit_function_dump_to_dot`:
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 .. code-block:: c
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
kono
parents:
diff changeset
354
kono
parents:
diff changeset
355 giving a .dot file in GraphViz format.
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 You can convert this to an image using `dot`:
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 .. code-block:: bash
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 $ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 or use a viewer (my preferred one is xdot.py; see
kono
parents:
diff changeset
364 https://github.com/jrfonseca/xdot.py; on Fedora you can
kono
parents:
diff changeset
365 install it with `yum install python-xdot`):
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 .. figure:: sum-of-squares.png
kono
parents:
diff changeset
368 :alt: image of a control flow graph
kono
parents:
diff changeset
369
kono
parents:
diff changeset
370 Full example
kono
parents:
diff changeset
371 ************
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 .. literalinclude:: ../examples/tut03-sum-of-squares.c
kono
parents:
diff changeset
374 :lines: 1-
kono
parents:
diff changeset
375 :language: c
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 Building and running it:
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 .. code-block:: console
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 $ gcc \
kono
parents:
diff changeset
382 tut03-sum-of-squares.c \
kono
parents:
diff changeset
383 -o tut03-sum-of-squares \
kono
parents:
diff changeset
384 -lgccjit
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 # Run the built program:
kono
parents:
diff changeset
387 $ ./tut03-sum-of-squares
kono
parents:
diff changeset
388 loop_test returned: 285