1 .. Copyright (C) 2014 Free Software Foundation, Inc.
2 Originally contributed by David Malcolm <dmalcolm@redhat.com>
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.
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.
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/>.
18 .. default-domain:: cpp
20 Tutorial part 2: Creating a trivial machine code function
21 ---------------------------------------------------------
23 Consider this C function:
32 How can we construct this at run-time using libgccjit's C++ API?
34 First we need to include the relevant header:
38 #include <libgccjit++.h>
40 All state associated with compilation is associated with a
41 :type:`gccjit::context`, which is a thin C++ wrapper around the C API's
42 :c:type:`gcc_jit_context *`.
44 Create one using :func:`gccjit::context::acquire`:
49 ctxt = gccjit::context::acquire ();
51 The JIT library has a system of types. It is statically-typed: every
52 expression is of a specific type, fixed at compile-time. In our example,
53 all of the expressions are of the C `int` type, so let's obtain this from
54 the context, as a :type:`gccjit::type`, using
55 :func:`gccjit::context::get_type`:
59 gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
61 :type:`gccjit::type` is an example of a "contextual" object: every
62 entity in the API is associated with a :type:`gccjit::context`.
64 Memory management is easy: all such "contextual" objects are automatically
65 cleaned up for you when the context is released, using
66 :func:`gccjit::context::release`:
72 so you don't need to manually track and cleanup all objects, just the
75 All of the C++ classes in the API are thin wrappers around pointers to
78 The C++ class hierarchy within the ``gccjit`` namespace looks like this::
91 One thing you can do with a :type:`gccjit::object` is
92 to ask it for a human-readable description as a :type:`std::string`, using
93 :func:`gccjit::object::get_debug_string`:
97 printf ("obj: %s\n", obj.get_debug_string ().c_str ());
99 giving this text on stdout:
105 This is invaluable when debugging.
107 Let's create the function. To do so, we first need to construct
108 its single parameter, specifying its type and giving it a name,
109 using :func:`gccjit::context::new_param`:
113 gccjit::param param_i = ctxt.new_param (int_type, "i");
115 and we can then make a vector of all of the params of the function,
116 in this case just one:
120 std::vector<gccjit::param> params;
121 params.push_back (param_i);
123 Now we can create the function, using
124 :c:func:`gccjit::context::new_function`:
128 gccjit::function func =
129 ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
135 To define the code within the function, we must create basic blocks
136 containing statements.
138 Every basic block contains a list of statements, eventually terminated
139 by a statement that either returns, or jumps to another basic block.
141 Our function has no control-flow, so we just need one basic block:
145 gccjit::block block = func.new_block ();
147 Our basic block is relatively simple: it immediately terminates by
148 returning the value of an expression.
150 We can build the expression using :func:`gccjit::context::new_binary_op`:
154 gccjit::rvalue expr =
156 GCC_JIT_BINARY_OP_MULT, int_type,
159 A :type:`gccjit::rvalue` is another example of a
160 :type:`gccjit::object` subclass. As before, we can print it with
161 :func:`gccjit::object::get_debug_string`.
165 printf ("expr: %s\n", expr.get_debug_string ().c_str ());
173 Note that :type:`gccjit::rvalue` provides numerous overloaded operators
174 which can be used to dramatically reduce the amount of typing needed.
175 We can build the above binary operation more directly with this one-liner:
179 gccjit::rvalue expr = param_i * param_i;
181 Creating the expression in itself doesn't do anything; we have to add
182 this expression to a statement within the block. In this case, we use it
183 to build a return statement, which terminates the basic block:
187 block.end_with_return (expr);
189 OK, we've populated the context. We can now compile it using
190 :func:`gccjit::context::compile`:
194 gcc_jit_result *result;
195 result = ctxt.compile ();
197 and get a :c:type:`gcc_jit_result *`.
199 We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
200 machine code routine within the result, in this case, the function we
205 void *fn_ptr = gcc_jit_result_get_code (result, "square");
208 fprintf (stderr, "NULL fn_ptr");
212 We can now cast the pointer to an appropriate function pointer type, and
217 typedef int (*fn_type) (int);
218 fn_type square = (fn_type)fn_ptr;
219 printf ("result: %d", square (5));
229 To get more information on what's going on, you can set debugging flags
230 on the context using :func:`gccjit::context::set_bool_option`.
232 .. (I'm deliberately not mentioning
233 :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
234 it's probably more of use to implementors than to users)
236 Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
237 C-like representation to stderr when you compile (GCC's "GIMPLE"
242 ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1);
243 result = ctxt.compile ();
247 square (signed int i)
256 We can see the generated machine code in assembler form (on stderr) by
257 setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
262 ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1);
263 result = ctxt.compile ();
270 .type square, @function
275 .cfi_def_cfa_offset 16
278 .cfi_def_cfa_register 6
288 .size square, .-square
289 .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
290 .section .note.GNU-stack,"",@progbits
292 By default, no optimizations are performed, the equivalent of GCC's
293 `-O0` option. We can turn things up to e.g. `-O3` by calling
294 :func:`gccjit::context::set_int_option` with
295 :c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
299 ctxt.set_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3);
307 .type square, @function
317 .size square, .-square
318 .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
319 .section .note.GNU-stack,"",@progbits
321 Naturally this has only a small effect on such a trivial function.
327 Here's what the above looks like as a complete program:
329 .. literalinclude:: ../../examples/tut02-square.cc
333 Building and running it:
335 .. code-block:: console
342 # Run the built program: