1 
2 /// A D API for libgccjit, purely as final class wrapper functions.
3 /// Copyright (C) 2014-2015 Iain Buclaw.
4 
5 /// This file is part of gccjitd.
6 
7 /// This program is free software: you can redistribute it and/or modify
8 /// it under the terms of the GNU General Public License as published by
9 /// the Free Software Foundation, either version 3 of the License, or
10 /// (at your option) any later version.
11 
12 /// This program is distributed in the hope that it will be useful,
13 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
14 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 /// GNU General Public License for more details.
16 
17 /// You should have received a copy of the GNU General Public License
18 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 
20 module gccjit.d;
21 
22 public import gccjit.c;
23 
24 import std.conv : to;
25 import std.string : toStringz;
26 import std.traits : isIntegral, isSigned;
27 
28 /// Errors within the API become D exceptions of this class.
29 final class JITError : Exception
30 {
31     @safe pure nothrow this(string msg, Throwable next = null)
32     {
33         super(msg, next);
34     }
35 
36     @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null)
37     {
38         super(msg, file, line, next);
39     }
40 }
41 
42 /// Class wrapper for gcc_jit_object.
43 /// All JITObject's are created within a JITContext, and are automatically
44 /// cleaned up when the context is released.
45 
46 /// The class hierachy looks like this:
47 ///  $(OL - JITObject
48 ///      $(OL - JITLocation)
49 ///      $(OL - JITType
50 ///         $(OL - JITStruct))
51 ///      $(OL - JITField)
52 ///      $(OL - JITFunction)
53 ///      $(OL - JITBlock)
54 ///      $(OL - JITRValue
55 ///          $(OL - JITLValue
56 ///              $(OL - JITParam))))
57 class JITObject
58 {
59     /// Return the context this JITObject is within.
60     final JITContext getContext()
61     {
62         auto result = gcc_jit_object_get_context(this.m_inner_obj);
63         return new JITContext(result);
64     }
65 
66     /// Get a human-readable description of this object.
67     override final string toString()
68     {
69         auto result = gcc_jit_object_get_debug_string(this.m_inner_obj);
70         return to!string(result);
71     }
72 
73 protected:
74     // Constructors and getObject are hidden from public.
75     this()
76     {
77         this.m_inner_obj = null;
78     }
79 
80     this(gcc_jit_object *obj)
81     {
82         if (!obj)
83             throw new JITError("Unknown error, got bad object");
84         this.m_inner_obj = obj;
85     }
86 
87     final gcc_jit_object *getObject()
88     {
89         return this.m_inner_obj;
90     }
91 
92 private:
93     // The actual gccjit object we interface with.
94     gcc_jit_object *m_inner_obj;
95 }
96 
97 /// Class wrapper for gcc_jit_location.
98 /// A JITLocation encapsulates a source code locations, so that you can associate
99 /// locations in your language with statements in the JIT-compiled code.
100 class JITLocation : JITObject
101 {
102     ///
103     this()
104     {
105         super();
106     }
107 
108     ///
109     this(gcc_jit_location *loc)
110     {
111         super(gcc_jit_location_as_object(loc));
112     }
113 
114     /// Returns the internal gcc_jit_location object.
115     final gcc_jit_location *getLocation()
116     {
117         // Manual downcast.
118         return cast(gcc_jit_location *)(this.getObject());
119     }
120 }
121 
122 /// The top-level of the API is the JITContext class.
123 
124 /// A JITContext instance encapsulates the state of a compilation.
125 /// It goes through two states.
126 /// Initial:
127 ///     During which you can set up options on it, and add types,
128 ///     functions and code, using the API below. Invoking compile
129 ///     on it transitions it to the PostCompilation state.
130 /// PostCompilation:
131 ///     When you can call JITContext.release to clean it up.
132 final class JITContext
133 {
134     ///
135     this(bool acquire = true)
136     {
137         if (acquire)
138             this.m_inner_ctxt = gcc_jit_context_acquire();
139         else
140             this.m_inner_ctxt = null;
141     }
142 
143     ///
144     this(gcc_jit_context *context)
145     {
146         if (!context)
147             throw new JITError("Unknown error, got bad context");
148         this.m_inner_ctxt = context;
149     }
150 
151     /// Acquire a JIT-compilation context.
152     static JITContext acquire()
153     {
154         return new JITContext(gcc_jit_context_acquire());
155     }
156 
157     /// Release the context.
158     /// After this call, it's no longer valid to use this JITContext.
159     void release()
160     {
161         gcc_jit_context_release(this.m_inner_ctxt);
162         this.m_inner_ctxt = null;
163     }
164 
165     /// Set a string option of the context; see JITStrOption for notes
166     /// on the options and their meanings.
167     /// Params:
168     ///     opt   = Which option to set.
169     ///     value = The new value.
170     void setOption(JITStrOption opt, string value)
171     {
172         gcc_jit_context_set_str_option(this.m_inner_ctxt, opt, value.toStringz());
173     }
174 
175     /// Set an integer option of the context; see JITIntOption for notes
176     /// on the options and their meanings.
177     /// Params:
178     ///     opt   = Which option to set.
179     ///     value = The new value.
180     void setOption(JITIntOption opt, int value)
181     {
182         gcc_jit_context_set_int_option(this.m_inner_ctxt, opt, value);
183     }
184 
185     /// Set a boolean option of the context; see JITBoolOption for notes
186     /// on the options and their meanings.
187     /// Params:
188     ///     opt   = Which option to set.
189     ///     value = The new value.
190     void setOption(JITBoolOption opt, bool value)
191     {
192         gcc_jit_context_set_bool_option(this.m_inner_ctxt, opt, value);
193     }
194 
195     /// Calls into GCC and runs the build.  It can only be called once on a
196     /// given context.
197     /// Returns:
198     ///     A wrapper around a .so file.
199     JITResult compile()
200     {
201         auto result = gcc_jit_context_compile(this.m_inner_ctxt);
202         if (!result)
203             throw new JITError(this.getFirstError());
204         return new JITResult(result);
205     }
206 
207     /// Returns:
208     ///     The first error message that occurred when compiling the context.
209     string getFirstError()
210     {
211         const char *err = gcc_jit_context_get_first_error(this.m_inner_ctxt);
212         if (err)
213             return to!string(err);
214         return null;
215     }
216 
217     /// Dump a C-like representation describing what's been set up on the
218     /// context to file.
219     /// Params:
220     ///     path             = Location of file to write to.
221     ///     update_locations = If true, then also write JITLocation information.
222     void dump(string path, bool update_locations)
223     {
224         gcc_jit_context_dump_to_file(this.m_inner_ctxt,
225                                      path.toStringz(),
226                                      update_locations);
227     }
228 
229     /// Returns the internal gcc_jit_context object.
230     gcc_jit_context *getContext()
231     {
232         return this.m_inner_ctxt;
233     }
234 
235     /// Build a JITType from one of the types in JITTypeKind.
236     JITType getType(JITTypeKind kind)
237     {
238         auto result = gcc_jit_context_get_type(this.m_inner_ctxt, kind);
239         return new JITType(result);
240     }
241 
242     /// Build an integer type of a given size and signedness.
243     JITType getIntType(int num_bytes, bool is_signed)
244     {
245         auto result = gcc_jit_context_get_int_type(this.m_inner_ctxt,
246                                                    num_bytes, is_signed);
247         return new JITType(result);
248     }
249 
250     /// A way to map a specific int type, using the compiler to
251     /// get the details automatically e.g:
252     ///     JITType type = getIntType!size_t();
253     JITType getIntType(T)() if (isIntegral!T)
254     {
255         return this.getIntType(T.sizeof, isSigned!T);
256     }
257 
258     /// Create a reference to a GCC builtin function.
259     JITFunction getBuiltinFunction(string name)
260     {
261         auto result = gcc_jit_context_get_builtin_function(this.m_inner_ctxt,
262                                                            name.toStringz());
263         return new JITFunction(result);
264     }
265 
266     /// Create a new child context of the given JITContext, inheriting a copy
267     /// of all option settings from the parent.
268     /// The returned JITContext can reference objects created within the
269     /// parent, but not vice-versa.  The lifetime of the child context must be
270     /// bounded by that of the parent. You should release a child context
271     /// before releasing the parent context.
272     JITContext newChildContext()
273     {
274         auto result = gcc_jit_context_new_child_context(this.m_inner_ctxt);
275         if (!result)
276             throw new JITError("Unknown error creating child context");
277         return new JITContext(result);
278     }
279 
280     /// Make a JITLocation representing a source location,
281     /// for use by the debugger.
282     /// Note:
283     ///     You need to enable JITBoolOption.DEBUGINFO on the context
284     ///     for these locations to actually be usable by the debugger.
285     JITLocation newLocation(string filename, int line, int column)
286     {
287         auto result = gcc_jit_context_new_location(this.m_inner_ctxt,
288                                                    filename.toStringz(),
289                                                    line, column);
290         return new JITLocation(result);
291     }
292 
293     /// Given type "T", build a new array type of "T[N]".
294     JITType newArrayType(JITLocation loc, JITType type, int dims)
295     {
296         auto result = gcc_jit_context_new_array_type(this.m_inner_ctxt,
297                                                      loc ? loc.getLocation() : null,
298                                                      type.getType(), dims);
299         return new JITType(result);
300     }
301 
302     /// Ditto
303     JITType newArrayType(JITType type, int dims)
304     {
305         return this.newArrayType(null, type, dims);
306     }
307 
308     /// Ditto
309     JITType newArrayType(JITLocation loc, JITTypeKind kind, int dims)
310     {
311         return this.newArrayType(loc, this.getType(kind), dims);
312     }
313 
314     /// Ditto
315     JITType newArrayType(JITTypeKind kind, int dims)
316     {
317         return this.newArrayType(null, this.getType(kind), dims);
318     }
319 
320     /// Create a field, for use within a struct or union.
321     JITField newField(JITLocation loc, JITType type, string name)
322     {
323         auto result = gcc_jit_context_new_field(this.m_inner_ctxt,
324                                                 loc ? loc.getLocation() : null,
325                                                 type.getType(),
326                                                 name.toStringz());
327         return new JITField(result);
328     }
329 
330     /// Ditto
331     JITField newField(JITType type, string name)
332     {
333         return this.newField(null, type, name);
334     }
335 
336     /// Ditto
337     JITField newField(JITLocation loc, JITTypeKind kind, string name)
338     {
339         return this.newField(loc, this.getType(kind), name);
340     }
341 
342     /// Ditto
343     JITField newField(JITTypeKind kind, string name)
344     {
345         return this.newField(null, this.getType(kind), name);
346     }
347 
348     /// Create a struct type from an array of fields.
349     JITStruct newStructType(JITLocation loc, string name, JITField[] fields...)
350     {
351         // Convert to an array of inner pointers.
352         gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length];
353         foreach(i, field; fields)
354             field_p[i] = field.getField();
355 
356         // Treat the array as being of the underlying pointers, relying on
357         // the wrapper type being such a pointer internally.
358         auto result = gcc_jit_context_new_struct_type(this.m_inner_ctxt,
359                                                       loc ? loc.getLocation() : null,
360                                                       name.toStringz(),
361                                                       cast(int)fields.length,
362                                                       field_p.ptr);
363         return new JITStruct(result);
364     }
365 
366     /// Ditto
367     JITStruct newStructType(string name, JITField[] fields...)
368     {
369         return this.newStructType(null, name, fields);
370     }
371 
372     /// Create an opaque struct type.
373     JITStruct newOpaqueStructType(JITLocation loc, string name)
374     {
375         auto result = gcc_jit_context_new_opaque_struct(this.m_inner_ctxt,
376                                                         loc ? loc.getLocation() : null,
377                                                         name.toStringz());
378         return new JITStruct(result);
379     }
380 
381     /// Ditto
382     JITStruct newOpaqueStructType(string name)
383     {
384         return this.newOpaqueStructType(null, name);
385     }
386 
387     /// Create a union type from an array of fields.
388     JITType newUnionType(JITLocation loc, string name, JITField[] fields...)
389     {
390         // Convert to an array of inner pointers.
391         gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length];
392         foreach(i, field; fields)
393             field_p[i] = field.getField();
394 
395         // Treat the array as being of the underlying pointers, relying on
396         // the wrapper type being such a pointer internally.
397         auto result = gcc_jit_context_new_union_type(this.m_inner_ctxt,
398                                                      loc ? loc.getLocation() : null,
399                                                      name.toStringz(),
400                                                      cast(int)fields.length,
401                                                      field_p.ptr);
402         return new JITType(result);
403     }
404 
405     /// Ditto
406     JITType newUnionType(string name, JITField[] fields...)
407     {
408         return this.newUnionType(null, name, fields);
409     }
410 
411     /// Create a function type.
412     JITType newFunctionType(JITLocation loc, JITType return_type,
413                             bool is_variadic, JITType[] param_types...)
414     {
415         // Convert to an array of inner pointers.
416         gcc_jit_type*[] type_p = new gcc_jit_type*[param_types.length];
417         foreach(i, type; param_types)
418             type_p[i] = type.getType();
419 
420         // Treat the array as being of the underlying pointers, relying on
421         // the wrapper type being such a pointer internally.
422         auto result = gcc_jit_context_new_function_ptr_type(this.m_inner_ctxt,
423                                                             loc ? loc.getLocation() : null,
424                                                             return_type.getType(),
425                                                             cast(int)param_types.length,
426                                                             type_p.ptr, is_variadic);
427         return new JITType(result);
428     }
429 
430     /// Ditto
431     JITType newFunctionType(JITType return_type, bool is_variadic,
432                             JITType[] param_types...)
433     {
434         return this.newFunctionType(null, return_type, is_variadic,
435                                     param_types);
436     }
437 
438     /// Ditto
439     JITType newFunctionType(JITLocation loc, JITTypeKind return_kind,
440                             bool is_variadic, JITType[] param_types...)
441     {
442         return this.newFunctionType(loc, this.getType(return_kind),
443                                     is_variadic, param_types);
444     }
445 
446     /// Ditto
447     JITType newFunctionType(JITTypeKind return_kind, bool is_variadic,
448                             JITType[] param_types...)
449     {
450         return this.newFunctionType(null, this.getType(return_kind),
451                                     is_variadic, param_types);
452     }
453 
454     /// Create a function parameter.
455     JITParam newParam(JITLocation loc, JITType type, string name)
456     {
457         auto result = gcc_jit_context_new_param(this.m_inner_ctxt,
458                                                 loc ? loc.getLocation() : null,
459                                                 type.getType(),
460                                                 name.toStringz());
461         return new JITParam(result);
462     }
463 
464     /// Ditto
465     JITParam newParam(JITType type, string name)
466     {
467         return this.newParam(null, type, name);
468     }
469 
470     /// Ditto
471     JITParam newParam(JITLocation loc, JITTypeKind kind, string name)
472     {
473         return this.newParam(loc, this.getType(kind), name);
474     }
475 
476     /// Ditto
477     JITParam newParam(JITTypeKind kind, string name)
478     {
479         return this.newParam(null, this.getType(kind), name);
480     }
481 
482     /// Create a function.
483     JITFunction newFunction(JITLocation loc, JITFunctionKind kind, JITType return_type,
484                             string name, bool is_variadic, JITParam[] params...)
485     {
486         // Convert to an array of inner pointers.
487         gcc_jit_param*[] param_p = new gcc_jit_param*[params.length];
488         foreach(i, param; params)
489             param_p[i] = param.getParam();
490 
491         // Treat the array as being of the underlying pointers, relying on
492         // the wrapper type being such a pointer internally.
493         auto result = gcc_jit_context_new_function(this.m_inner_ctxt,
494                                                    loc ? loc.getLocation() : null,
495                                                    kind, return_type.getType(),
496                                                    name.toStringz(),
497                                                    cast(int)params.length,
498                                                    param_p.ptr, is_variadic);
499         return new JITFunction(result);
500     }
501 
502     /// Ditto
503     JITFunction newFunction(JITFunctionKind kind, JITType return_type,
504                             string name, bool is_variadic, JITParam[] params...)
505     {
506         return this.newFunction(null, kind, return_type, name, is_variadic, params);
507     }
508 
509     /// Ditto
510     JITFunction newFunction(JITLocation loc, JITFunctionKind kind, JITTypeKind return_kind,
511                             string name, bool is_variadic, JITParam[] params...)
512     {
513         return this.newFunction(loc, kind, this.getType(return_kind),
514                                 name, is_variadic, params);
515     }
516 
517     /// Ditto
518     JITFunction newFunction(JITFunctionKind kind, JITTypeKind return_kind,
519                             string name, bool is_variadic, JITParam[] params...)
520     {
521         return this.newFunction(null, kind, this.getType(return_kind),
522                                 name, is_variadic, params);
523     }
524 
525     ///
526     JITLValue newGlobal(JITLocation loc, JITGlobalKind global_kind,
527                         JITType type, string name)
528     {
529         auto result = gcc_jit_context_new_global(this.m_inner_ctxt,
530                                                  loc ? loc.getLocation() : null,
531                                                  global_kind, type.getType(),
532                                                  name.toStringz());
533         return new JITLValue(result);
534     }
535 
536     /// Ditto
537     JITLValue newGlobal(JITGlobalKind global_kind, JITType type, string name)
538     {
539         return this.newGlobal(null, global_kind, type, name);
540     }
541 
542     /// Ditto
543     JITLValue newGlobal(JITLocation loc, JITGlobalKind global_kind,
544                         JITTypeKind kind, string name)
545     {
546         return this.newGlobal(loc, global_kind, this.getType(kind), name);
547     }
548 
549     /// Ditto
550     JITLValue newGlobal(JITGlobalKind global_kind, JITTypeKind kind, string name)
551     {
552         return this.newGlobal(null, global_kind, this.getType(kind), name);
553     }
554 
555     /// Given a JITType, which must be a numeric type, get an integer constant
556     /// as a JITRValue of that type.
557     JITRValue newRValue(JITType type, int value)
558     {
559         auto result = gcc_jit_context_new_rvalue_from_int(this.m_inner_ctxt,
560                                                           type.getType(), value);
561         return new JITRValue(result);
562     }
563 
564     /// Ditto
565     JITRValue newRValue(JITTypeKind kind, int value)
566     {
567         return newRValue(this.getType(kind), value);
568     }
569 
570     /// Given a JITType, which must be a floating point type, get a floating
571     /// point constant as a JITRValue of that type.
572     JITRValue newRValue(JITType type, double value)
573     {
574         auto result = gcc_jit_context_new_rvalue_from_double(this.m_inner_ctxt,
575                                                              type.getType(), value);
576         return new JITRValue(result);
577     }
578 
579     /// Ditto
580     JITRValue newRValue(JITTypeKind kind, double value)
581     {
582         return newRValue(this.getType(kind), value);
583     }
584 
585     /// Given a JITType, which must be a pointer type, and an address, get a
586     /// JITRValue representing that address as a pointer of that type.
587     JITRValue newRValue(JITType type, void *value)
588     {
589         auto result = gcc_jit_context_new_rvalue_from_ptr(this.m_inner_ctxt,
590                                                           type.getType(), value);
591         return new JITRValue(result);
592     }
593 
594     /// Ditto
595     JITRValue newRValue(JITTypeKind kind, void *value)
596     {
597         return newRValue(this.getType(kind), value);
598     }
599 
600     /// Make a JITRValue for the given string literal value.
601     /// Params:
602     ///     value = The string literal.
603     JITRValue newRValue(string value)
604     {
605         auto result = gcc_jit_context_new_string_literal(this.m_inner_ctxt,
606                                                          value.toStringz());
607         return new JITRValue(result);
608     }
609 
610     /// Given a JITType, which must be a numeric type, get the constant 0 as a
611     /// JITRValue of that type.
612     JITRValue zero(JITType type)
613     {
614         auto result = gcc_jit_context_zero(this.m_inner_ctxt, type.getType());
615         return new JITRValue(result);
616     }
617 
618     /// Ditto
619     JITRValue zero(JITTypeKind kind)
620     {
621         return this.zero(this.getType(kind));
622     }
623 
624     /// Given a JITType, which must be a numeric type, get the constant 1 as a
625     /// JITRValue of that type.
626     JITRValue one(JITType type)
627     {
628         auto result = gcc_jit_context_one(this.m_inner_ctxt, type.getType());
629         return new JITRValue(result);
630     }
631 
632     /// Ditto
633     JITRValue one(JITTypeKind kind)
634     {
635         return this.one(this.getType(kind));
636     }
637 
638     /// Given a JITType, which must be a pointer type, get a JITRValue
639     /// representing the NULL pointer of that type.
640     JITRValue nil(JITType type)
641     {
642         auto result = gcc_jit_context_null(this.m_inner_ctxt, type.getType());
643         return new JITRValue(result);
644     }
645 
646     /// Ditto
647     JITRValue nil(JITTypeKind kind)
648     {
649         return this.nil(this.getType(kind));
650     }
651 
652     /// Generic unary operations.
653 
654     /// Make a JITRValue for the given unary operation.
655     /// Params:
656     ///     loc  = The source location, if any.
657     ///     op   = Which unary operation.
658     ///     type = The type of the result.
659     ///     a    = The input expression.
660     JITRValue newUnaryOp(JITLocation loc, JITUnaryOp op, JITType type, JITRValue a)
661     {
662         auto result = gcc_jit_context_new_unary_op(this.m_inner_ctxt,
663                                                    loc ? loc.getLocation() : null,
664                                                    op, type.getType(),
665                                                    a.getRValue());
666         return new JITRValue(result);
667     }
668 
669     /// Ditto
670     JITRValue newUnaryOp(JITUnaryOp op, JITType type, JITRValue a)
671     {
672         return this.newUnaryOp(null, op, type, a);
673     }
674 
675     /// Generic binary operations.
676 
677     /// Make a JITRValue for the given binary operation.
678     /// Params:
679     ///     loc  = The source location, if any.
680     ///     op   = Which binary operation.
681     ///     type = The type of the result.
682     ///     a    = The first input expression.
683     ///     b    = The second input expression.
684     JITRValue newBinaryOp(JITLocation loc, JITBinaryOp op,
685                           JITType type, JITRValue a, JITRValue b)
686     {
687         auto result = gcc_jit_context_new_binary_op(this.m_inner_ctxt,
688                                                     loc ? loc.getLocation() : null,
689                                                     op, type.getType(),
690                                                     a.getRValue(),
691                                                     b.getRValue());
692         return new JITRValue(result);
693     }
694 
695     /// Ditto
696     JITRValue newBinaryOp(JITBinaryOp op, JITType type, JITRValue a, JITRValue b)
697     {
698         return this.newBinaryOp(null, op, type, a, b);
699     }
700 
701     /// Generic comparisons.
702 
703     /// Make a JITRValue of boolean type for the given comparison.
704     /// Params:
705     ///     loc  = The source location, if any.
706     ///     op   = Which comparison.
707     ///     a    = The first input expression.
708     ///     b    = The second input expression.
709     JITRValue newComparison(JITLocation loc, JITComparison op,
710                             JITRValue a, JITRValue b)
711     {
712         auto result = gcc_jit_context_new_comparison(this.m_inner_ctxt,
713                                                      loc ? loc.getLocation() : null,
714                                                      op, a.getRValue(),
715                                                      b.getRValue());
716         return new JITRValue(result);
717     }
718 
719     /// Ditto
720     JITRValue newComparison(JITComparison op, JITRValue a, JITRValue b)
721     {
722         return this.newComparison(null, op, a, b);
723     }
724 
725     /// The most general way of creating a function call.
726     JITRValue newCall(JITLocation loc, JITFunction func, JITRValue[] args...)
727     {
728         // Convert to an array of inner pointers.
729         gcc_jit_rvalue*[] arg_p = new gcc_jit_rvalue*[args.length];
730         foreach(i, arg; args)
731             arg_p[i] = arg.getRValue();
732 
733         // Treat the array as being of the underlying pointers, relying on
734         // the wrapper type being such a pointer internally.
735         auto result = gcc_jit_context_new_call(this.m_inner_ctxt,
736                                                loc ? loc.getLocation() : null,
737                                                func.getFunction(),
738                                                cast(int)args.length,
739                                                arg_p.ptr);
740         return new JITRValue(result);
741     }
742 
743     /// Ditto
744     JITRValue newCall(JITFunction func, JITRValue[] args...)
745     {
746         return this.newCall(null, func, args);
747     }
748 
749     /// Calling a function through a pointer.
750     JITRValue newCall(JITLocation loc, JITRValue ptr, JITRValue[] args...)
751     {
752         // Convert to an array of inner pointers.
753         gcc_jit_rvalue*[] arg_p = new gcc_jit_rvalue*[args.length];
754         foreach(i, arg; args)
755             arg_p[i] = arg.getRValue();
756 
757         // Treat the array as being of the underlying pointers, relying on
758         // the wrapper type being such a pointer internally.
759         auto result = gcc_jit_context_new_call_through_ptr(this.m_inner_ctxt,
760                                                            loc ? loc.getLocation() : null,
761                                                            ptr.getRValue(),
762                                                            cast(int)args.length,
763                                                            arg_p.ptr);
764         return new JITRValue(result);
765     }
766 
767     /// Ditto
768     JITRValue newCall(JITRValue ptr, JITRValue[] args...)
769     {
770         return this.newCall(null, ptr, args);
771     }
772 
773     /// Type-coercion.
774     /// Currently only a limited set of conversions are possible.
775     /// int <=> float and int <=> bool.
776     JITRValue newCast(JITLocation loc, JITRValue expr, JITType type)
777     {
778         auto result = gcc_jit_context_new_cast(this.m_inner_ctxt,
779                                                loc ? loc.getLocation() : null,
780                                                expr.getRValue(), type.getType());
781         return new JITRValue(result);
782     }
783 
784     /// Ditto
785     JITRValue newCast(JITRValue expr, JITType type)
786     {
787         return this.newCast(null, expr, type);
788     }
789 
790     /// Ditto
791     JITRValue newCast(JITLocation loc, JITRValue expr, JITTypeKind kind)
792     {
793         return this.newCast(loc, expr, this.getType(kind));
794     }
795 
796     /// Ditto
797     JITRValue newCast(JITRValue expr, JITTypeKind kind)
798     {
799         return this.newCast(null, expr, this.getType(kind));
800     }
801 
802     /// Accessing an array or pointer through an index.
803     /// Params:
804     ///     loc   = The source location, if any.
805     ///     ptr   = The pointer or array.
806     ///     index = The index within the array.
807     JITLValue newArrayAccess(JITLocation loc, JITRValue ptr, JITRValue index)
808     {
809         auto result = gcc_jit_context_new_array_access(this.m_inner_ctxt,
810                                                        loc ? loc.getLocation() : null,
811                                                        ptr.getRValue(), index.getRValue());
812         return new JITLValue(result);
813     }
814 
815     /// Ditto
816     JITLValue newArrayAccess(JITRValue ptr, JITRValue index)
817     {
818         return this.newArrayAccess(null, ptr, index);
819     }
820 
821 private:
822     gcc_jit_context *m_inner_ctxt;
823 }
824 
825 /// Class wrapper for gcc_jit_field
826 class JITField : JITObject
827 {
828     ///
829     this()
830     {
831         super();
832     }
833 
834     ///
835     this(gcc_jit_field *field)
836     {
837         super(gcc_jit_field_as_object(field));
838     }
839 
840     /// Returns the internal gcc_jit_field object.
841     final gcc_jit_field *getField()
842     {
843         // Manual downcast.
844         return cast(gcc_jit_field *)(this.getObject());
845     }
846 }
847 
848 /// Types can be created in several ways:
849 /// $(UL
850 ///     $(LI Fundamental types can be accessed using JITContext.getType())
851 ///     $(LI Derived types can be accessed by calling methods on an existing type.)
852 ///     $(LI By creating structures via JITStruct.)
853 /// )
854 
855 class JITType : JITObject
856 {
857     ///
858     this()
859     {
860         super();
861     }
862 
863     ///
864     this(gcc_jit_type *type)
865     {
866         super(gcc_jit_type_as_object(type));
867     }
868 
869     /// Returns the internal gcc_jit_type object.
870     final gcc_jit_type *getType()
871     {
872         // Manual downcast.
873         return cast(gcc_jit_type *)(this.getObject());
874     }
875 
876     /// Given type T, get type T*.
877     final JITType pointerOf()
878     {
879         auto result = gcc_jit_type_get_pointer(this.getType());
880         return new JITType(result);
881     }
882 
883     /// Given type T, get type const T.
884     final JITType constOf()
885     {
886         auto result = gcc_jit_type_get_const(this.getType());
887         return new JITType(result);
888     }
889 
890     /// Given type T, get type volatile T.
891     final JITType volatileOf()
892     {
893         auto result = gcc_jit_type_get_volatile(this.getType());
894         return new JITType(result);
895     }
896 }
897 
898 /// You can model C struct types by creating JITStruct and JITField
899 /// instances, in either order:
900 /// $(UL
901 ///     $(LI By creating the fields, then the structure.)
902 ///     $(LI By creating the structure, then populating it with fields,
903 ///          typically to allow modelling self-referential structs.)
904 /// )
905 class JITStruct : JITType
906 {
907     ///
908     this()
909     {
910         super(null);
911     }
912 
913     ///
914     this(gcc_jit_struct *agg)
915     {
916         super(gcc_jit_struct_as_type(agg));
917     }
918 
919     /// Returns the internal gcc_jit_struct object.
920     final gcc_jit_struct *getStruct()
921     {
922         // Manual downcast.
923         return cast(gcc_jit_struct *)(this.getObject());
924     }
925 
926     /// Populate the fields of a formerly-opaque struct type.
927     /// This can only be called once on a given struct type.
928     final void setFields(JITLocation loc, JITField[] fields...)
929     {
930         // Convert to an array of inner pointers.
931         gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length];
932         foreach(i, field; fields)
933             field_p[i] = field.getField();
934 
935         // Treat the array as being of the underlying pointers, relying on
936         // the wrapper type being such a pointer internally.
937         gcc_jit_struct_set_fields(this.getStruct(), loc ? loc.getLocation() : null,
938                                   cast(int)fields.length, field_p.ptr);
939     }
940 
941     /// Ditto
942     final void setFields(JITField[] fields...)
943     {
944         this.setFields(null, fields);
945     }
946 }
947 
948 /// Class wrapper for gcc_jit_function
949 class JITFunction : JITObject
950 {
951     ///
952     this()
953     {
954         super();
955     }
956 
957     ///
958     this(gcc_jit_function *func)
959     {
960         if (!func)
961             throw new JITError("Unknown error, got bad function");
962         super(gcc_jit_function_as_object(func));
963     }
964 
965     /// Returns the internal gcc_jit_function object.
966     final gcc_jit_function *getFunction()
967     {
968         // Manual downcast.
969         return cast(gcc_jit_function *)(this.getObject());
970     }
971 
972     /// Dump function to dot file.
973     final void dump(string path)
974     {
975         gcc_jit_function_dump_to_dot(this.getFunction(), path.toStringz());
976     }
977 
978     /// Get a specific param of a function by index.
979     final JITParam getParam(int index)
980     {
981         auto result = gcc_jit_function_get_param(this.getFunction(), index);
982         return new JITParam(result);
983     }
984 
985     /// Create a new JITBlock.
986     /// The name can be null, or you can give it a meaningful name, which may
987     /// show up in dumps of the internal representation, and in error messages.
988     final JITBlock newBlock()
989     {
990         auto result = gcc_jit_function_new_block(this.getFunction(), null);
991         return new JITBlock(result);
992     }
993 
994     /// Ditto
995     final JITBlock newBlock(string name)
996     {
997         auto result = gcc_jit_function_new_block(this.getFunction(),
998                                                  name.toStringz());
999         return new JITBlock(result);
1000     }
1001 
1002     /// Create a new local variable.
1003     final JITLValue newLocal(JITLocation loc, JITType type, string name)
1004     {
1005         auto result = gcc_jit_function_new_local(this.getFunction(),
1006                                                  loc ? loc.getLocation() : null,
1007                                                  type.getType(),
1008                                                  name.toStringz());
1009         return new JITLValue(result);
1010     }
1011 
1012     /// Ditto
1013     final JITLValue newLocal(JITType type, string name)
1014     {
1015         return this.newLocal(null, type, name);
1016     }
1017 }
1018 
1019 
1020 /// Class wrapper for gcc_jit_block
1021 class JITBlock : JITObject
1022 {
1023     ///
1024     this()
1025     {
1026         super();
1027     }
1028 
1029     ///
1030     this(gcc_jit_block *block)
1031     {
1032         super(gcc_jit_block_as_object(block));
1033     }
1034 
1035     /// Returns the internal gcc_jit_block object.
1036     final gcc_jit_block *getBlock()
1037     {
1038         // Manual downcast.
1039         return cast(gcc_jit_block *)(this.getObject());
1040     }
1041 
1042     /// Returns the JITFunction this JITBlock is within.
1043     final JITFunction getFunction()
1044     {
1045         auto result = gcc_jit_block_get_function(this.getBlock());
1046         return new JITFunction(result);
1047     }
1048 
1049     /// Add evaluation of an rvalue, discarding the result.
1050     final void addEval(JITLocation loc, JITRValue rvalue)
1051     {
1052         gcc_jit_block_add_eval(this.getBlock(),
1053                                loc ? loc.getLocation() : null,
1054                                rvalue.getRValue());
1055     }
1056 
1057     /// Ditto
1058     final void addEval(JITRValue rvalue)
1059     {
1060         return this.addEval(null, rvalue);
1061     }
1062 
1063     /// Add evaluation of an rvalue, assigning the result to the given lvalue.
1064     /// This is equivalent to "lvalue = rvalue".
1065     final void addAssignment(JITLocation loc, JITLValue lvalue, JITRValue rvalue)
1066     {
1067         gcc_jit_block_add_assignment(this.getBlock(),
1068                                      loc ? loc.getLocation() : null,
1069                                      lvalue.getLValue(), rvalue.getRValue());
1070     }
1071 
1072     /// Ditto
1073     final void addAssignment(JITLValue lvalue, JITRValue rvalue)
1074     {
1075         return this.addAssignment(null, lvalue, rvalue);
1076     }
1077 
1078     /// Add evaluation of an rvalue, using the result to modify an lvalue.
1079     /// This is equivalent to "lvalue op= rvalue".
1080     final void addAssignmentOp(JITLocation loc, JITLValue lvalue,
1081                          JITBinaryOp op, JITRValue rvalue)
1082     {
1083         gcc_jit_block_add_assignment_op(this.getBlock(),
1084                                         loc ? loc.getLocation() : null,
1085                                         lvalue.getLValue(), op, rvalue.getRValue());
1086     }
1087 
1088     /// Ditto
1089     final void addAssignmentOp(JITLValue lvalue, JITBinaryOp op, JITRValue rvalue)
1090     {
1091         return this.addAssignmentOp(null, lvalue, op, rvalue);
1092     }
1093 
1094     /// A way to add a function call to the body of a function being
1095     /// defined, with various number of args.
1096     final JITRValue addCall(JITLocation loc, JITFunction func, JITRValue[] args...)
1097     {
1098         JITRValue rv = this.getContext().newCall(loc, func, args);
1099         this.addEval(loc, rv);
1100         return rv;
1101     }
1102 
1103     /// Ditto
1104     final JITRValue addCall(JITFunction func, JITRValue[] args...)
1105     {
1106         return this.addCall(null, func, args);
1107     }
1108 
1109     /// Add a no-op textual comment to the internal representation of the code.
1110     /// It will be optimized away, but visible in the dumps seens via
1111     /// JITBoolOption.DUMP_INITIAL_TREE and JITBoolOption.DUMP_INITIAL_GIMPLE.
1112     final void addComment(JITLocation loc, string text)
1113     {
1114         gcc_jit_block_add_comment(this.getBlock(),
1115                                   loc ? loc.getLocation() : null,
1116                                   text.toStringz());
1117     }
1118 
1119     /// Ditto
1120     final void addComment(string text)
1121     {
1122         return this.addComment(null, text);
1123     }
1124 
1125     /// Terminate a block by adding evaluation of an rvalue, branching on the
1126     /// result to the appropriate successor block.
1127     final void endWithConditional(JITLocation loc, JITRValue val,
1128                             JITBlock on_true, JITBlock on_false)
1129     {
1130         gcc_jit_block_end_with_conditional(this.getBlock(),
1131                                            loc ? loc.getLocation() : null,
1132                                            val.getRValue(),
1133                                            on_true.getBlock(),
1134                                            on_false.getBlock());
1135     }
1136 
1137     /// Ditto
1138     final void endWithConditional(JITRValue val, JITBlock on_true, JITBlock on_false)
1139     {
1140         return this.endWithConditional(null, val, on_true, on_false);
1141     }
1142 
1143     /// Terminate a block by adding a jump to the given target block.
1144     /// This is equivalent to "goto target".
1145     final void endWithJump(JITLocation loc, JITBlock target)
1146     {
1147         gcc_jit_block_end_with_jump(this.getBlock(),
1148                                     loc ? loc.getLocation() : null,
1149                                     target.getBlock());
1150     }
1151 
1152     /// Ditto
1153     final void endWithJump(JITBlock target)
1154     {
1155         return this.endWithJump(null, target);
1156     }
1157 
1158     /// Terminate a block by adding evaluation of an rvalue, returning the value.
1159     /// This is equivalent to "return rvalue".
1160     final void endWithReturn(JITLocation loc, JITRValue rvalue)
1161     {
1162         gcc_jit_block_end_with_return(this.getBlock(),
1163                                       loc ? loc.getLocation() : null,
1164                                       rvalue.getRValue());
1165     }
1166 
1167     /// Ditto
1168     final void endWithReturn(JITRValue rvalue)
1169     {
1170         return this.endWithReturn(null, rvalue);
1171     }
1172 
1173     /// Terminate a block by adding a valueless return, for use within a
1174     /// function with "void" return type.
1175     /// This is equivalent to "return".
1176     final void endWithReturn(JITLocation loc = null)
1177     {
1178         gcc_jit_block_end_with_void_return(this.getBlock(),
1179                                            loc ? loc.getLocation() : null);
1180     }
1181 }
1182 
1183 /// Class wrapper for gcc_jit_rvalue
1184 class JITRValue : JITObject
1185 {
1186     ///
1187     this()
1188     {
1189         super();
1190     }
1191 
1192     ///
1193     this(gcc_jit_rvalue *rvalue)
1194     {
1195         if (!rvalue)
1196             throw new JITError("Unknown error, got bad rvalue");
1197         super(gcc_jit_rvalue_as_object(rvalue));
1198     }
1199 
1200     /// Returns the internal gcc_jit_rvalue object.
1201     final gcc_jit_rvalue *getRValue()
1202     {
1203         // Manual downcast.
1204         return cast(gcc_jit_rvalue *)(this.getObject());
1205     }
1206 
1207     /// Returns the JITType of the rvalue.
1208     final JITType getType()
1209     {
1210         auto result = gcc_jit_rvalue_get_type(this.getRValue());
1211         return new JITType(result);
1212     }
1213 
1214     /// Accessing a field of an rvalue of struct type.
1215     /// This is equivalent to "(value).field".
1216     JITRValue accessField(JITLocation loc, JITField field)
1217     {
1218         auto result = gcc_jit_rvalue_access_field(this.getRValue(),
1219                                                   loc ? loc.getLocation() : null,
1220                                                   field.getField());
1221         return new JITRValue(result);
1222     }
1223 
1224     /// Ditto
1225     JITRValue accessField(JITField field)
1226     {
1227         return this.accessField(null, field);
1228     }
1229 
1230     /// Accessing a field of an rvalue of pointer type.
1231     /// This is equivalent to "(*value).field".
1232     final JITLValue dereferenceField(JITLocation loc, JITField field)
1233     {
1234         auto result = gcc_jit_rvalue_dereference_field(this.getRValue(),
1235                                                        loc ? loc.getLocation() : null,
1236                                                        field.getField());
1237         return new JITLValue(result);
1238     }
1239 
1240     /// Ditto
1241     final JITLValue dereferenceField(JITField field)
1242     {
1243         return this.dereferenceField(null, field);
1244     }
1245 
1246     /// Dereferencing an rvalue of pointer type.
1247     /// This is equivalent to "*(value)".
1248     final JITLValue dereference(JITLocation loc = null)
1249     {
1250         auto result = gcc_jit_rvalue_dereference(this.getRValue(),
1251                                                  loc ? loc.getLocation() : null);
1252         return new JITLValue(result);
1253     }
1254 
1255     /// Convert an rvalue to the given JITType.  See JITContext.newCast for
1256     /// limitations.
1257     final JITRValue castTo(JITLocation loc, JITType type)
1258     {
1259         return this.getContext().newCast(loc, this, type);
1260     }
1261 
1262     /// Ditto
1263     final JITRValue castTo(JITType type)
1264     {
1265         return this.castTo(null, type);
1266     }
1267 
1268     /// Ditto
1269     final JITRValue castTo(JITLocation loc, JITTypeKind kind)
1270     {
1271         return this.castTo(loc, this.getContext().getType(kind));
1272     }
1273 
1274     /// Ditto
1275     final JITRValue castTo(JITTypeKind kind)
1276     {
1277         return this.castTo(null, this.getContext().getType(kind));
1278     }
1279 }
1280 
1281 /// Class wrapper for gcc_jit_lvalue
1282 class JITLValue : JITRValue
1283 {
1284     ///
1285     this()
1286     {
1287         super();
1288     }
1289 
1290     ///
1291     this(gcc_jit_lvalue *lvalue)
1292     {
1293         if (!lvalue)
1294             throw new JITError("Unknown error, got bad lvalue");
1295         super(gcc_jit_lvalue_as_rvalue(lvalue));
1296     }
1297 
1298     /// Returns the internal gcc_jit_lvalue object.
1299     final gcc_jit_lvalue *getLValue()
1300     {
1301         // Manual downcast.
1302         return cast(gcc_jit_lvalue *)(this.getObject());
1303     }
1304 
1305     /// Accessing a field of an lvalue of struct type.
1306     /// This is equivalent to "(value).field = ...".
1307     override JITLValue accessField(JITLocation loc, JITField field)
1308     {
1309         auto result = gcc_jit_lvalue_access_field(this.getLValue(),
1310                                                   loc ? loc.getLocation() : null,
1311                                                   field.getField());
1312         return new JITLValue(result);
1313     }
1314 
1315     /// Ditto
1316     override JITLValue accessField(JITField field)
1317     {
1318         return this.accessField(null, field);
1319     }
1320 
1321     /// Taking the address of an lvalue.
1322     /// This is equivalent to "&(value)".
1323     final JITRValue getAddress(JITLocation loc = null)
1324     {
1325         auto result = gcc_jit_lvalue_get_address(this.getLValue(),
1326                                                  loc ? loc.getLocation() : null);
1327         return new JITRValue(result);
1328     }
1329 }
1330 
1331 /// Class wrapper for gcc_jit_param
1332 class JITParam : JITLValue
1333 {
1334     ///
1335     this()
1336     {
1337         super();
1338     }
1339 
1340     ///
1341     this(gcc_jit_param *param)
1342     {
1343         if (!param)
1344             throw new JITError("Unknown error, got bad param");
1345         super(gcc_jit_param_as_lvalue(param));
1346     }
1347 
1348     /// Returns the internal gcc_jit_param object.
1349     final gcc_jit_param *getParam()
1350     {
1351         // Manual downcast.
1352         return cast(gcc_jit_param *)(this.getObject());
1353     }
1354 }
1355 
1356 /// Class wrapper for gcc_jit_result
1357 final class JITResult
1358 {
1359     ///
1360     this()
1361     {
1362         this.m_inner_result = null;
1363     }
1364 
1365     ///
1366     this(gcc_jit_result *result)
1367     {
1368         if (!result)
1369             throw new JITError("Unknown error, got bad result");
1370         this.m_inner_result = result;
1371     }
1372 
1373     /// Returns the internal gcc_jit_result object.
1374     gcc_jit_result *getResult()
1375     {
1376         return this.m_inner_result;
1377     }
1378 
1379     /// Locate a given function within the built machine code.
1380     /// This will need to be cast to a function pointer of the correct type
1381     /// before it can be called.
1382     void *getCode(string name)
1383     {
1384         return gcc_jit_result_get_code(this.getResult(), name.toStringz());
1385     }
1386 
1387     /// Locate a given global within the built machine code.
1388     /// It must have been created using JITGlobalKind.EXPORTED.
1389     /// This returns is a pointer to the global.
1390     void *getGlobal(string name)
1391     {
1392         return gcc_jit_result_get_global(this.getResult(), name.toStringz());
1393     }
1394 
1395     /// Once we're done with the code, this unloads the built .so file.
1396     /// After this call, it's no longer valid to use this JITResult.
1397     void release()
1398     {
1399         gcc_jit_result_release(this.getResult());
1400     }
1401 
1402 private:
1403     gcc_jit_result *m_inner_result;
1404 }
1405 
1406 /// Kinds of function.
1407 enum JITFunctionKind : gcc_jit_function_kind
1408 {
1409     /// Function is defined by the client code and visible by name
1410     /// outside of the JIT.
1411     EXPORTED = GCC_JIT_FUNCTION_EXPORTED,
1412     /// Function is defined by the client code, but is invisible
1413     /// outside of the JIT.
1414     INTERNAL = GCC_JIT_FUNCTION_INTERNAL,
1415     /// Function is not defined by the client code; we're merely
1416     /// referring to it.
1417     IMPORTED = GCC_JIT_FUNCTION_IMPORTED,
1418     /// Function is only ever inlined into other functions, and is
1419     /// invisible outside of the JIT.
1420     ALWAYS_INLINE = GCC_JIT_FUNCTION_ALWAYS_INLINE,
1421 }
1422 
1423 /// Kinds of global.
1424 enum JITGlobalKind : gcc_jit_global_kind
1425 {
1426   /// Global is defined by the client code and visible by name
1427   /// outside of this JIT context.
1428   EXPORTED = GCC_JIT_GLOBAL_EXPORTED,
1429   /// Global is defined by the client code, but is invisible
1430   /// outside of this JIT context.  Analogous to a "static" global.
1431   INTERNAL = GCC_JIT_GLOBAL_INTERNAL,
1432   /// Global is not defined by the client code; we're merely
1433   /// referring to it.  Analogous to using an "extern" global.
1434   IMPORTED = GCC_JIT_GLOBAL_IMPORTED,
1435 }
1436 
1437 /// Standard types.
1438 enum JITTypeKind : gcc_jit_types
1439 {
1440     /// C's void type.
1441     VOID = GCC_JIT_TYPE_VOID,
1442 
1443     /// C's void* type.
1444     VOID_PTR = GCC_JIT_TYPE_VOID_PTR,
1445 
1446     /// C++'s bool type.
1447     BOOL = GCC_JIT_TYPE_BOOL,
1448 
1449     /// C's char type.
1450     CHAR = GCC_JIT_TYPE_CHAR,
1451 
1452     /// C's signed char type.
1453     SIGNED_CHAR = GCC_JIT_TYPE_SIGNED_CHAR,
1454 
1455     /// C's unsigned char type.
1456     UNSIGNED_CHAR = GCC_JIT_TYPE_UNSIGNED_CHAR,
1457 
1458     /// C's short type.
1459     SHORT = GCC_JIT_TYPE_SHORT,
1460 
1461     /// C's unsigned short type.
1462     UNSIGNED_SHORT = GCC_JIT_TYPE_UNSIGNED_SHORT,
1463 
1464     /// C's int type.
1465     INT = GCC_JIT_TYPE_INT,
1466 
1467     /// C's unsigned int type.
1468     UNSIGNED_INT = GCC_JIT_TYPE_UNSIGNED_INT,
1469 
1470     /// C's long type.
1471     LONG = GCC_JIT_TYPE_LONG,
1472 
1473     /// C's unsigned long type.
1474     UNSIGNED_LONG = GCC_JIT_TYPE_UNSIGNED_LONG,
1475 
1476     /// C99's long long type.
1477     LONG_LONG = GCC_JIT_TYPE_LONG_LONG,
1478 
1479     /// C99's unsigned long long type.
1480     UNSIGNED_LONG_LONG = GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
1481 
1482     /// Single precision floating point type.
1483     FLOAT = GCC_JIT_TYPE_FLOAT,
1484 
1485     /// Double precision floating point type.
1486     DOUBLE = GCC_JIT_TYPE_DOUBLE,
1487 
1488     /// Largest supported floating point type.
1489     LONG_DOUBLE = GCC_JIT_TYPE_LONG_DOUBLE,
1490 
1491     /// C's const char* type.
1492     CONST_CHAR_PTR = GCC_JIT_TYPE_CONST_CHAR_PTR,
1493 
1494     /// C's size_t type.
1495     SIZE_T = GCC_JIT_TYPE_SIZE_T,
1496 
1497     /// C's FILE* type.
1498     FILE_PTR = GCC_JIT_TYPE_FILE_PTR,
1499 
1500     /// Single precision complex float type.
1501     COMPLEX_FLOAT = GCC_JIT_TYPE_COMPLEX_FLOAT,
1502 
1503     /// Double precision complex float type.
1504     COMPLEX_DOUBLE = GCC_JIT_TYPE_COMPLEX_DOUBLE,
1505 
1506     /// Largest supported complex float type.
1507     COMPLEX_LONG_DOUBLE = GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE,
1508 }
1509 
1510 /// Kinds of unary ops.
1511 enum JITUnaryOp : gcc_jit_unary_op
1512 {
1513     /// Negate an arithmetic value.
1514     /// This is equivalent to "-(value)".
1515     MINUS = GCC_JIT_UNARY_OP_MINUS,
1516     /// Bitwise negation of an integer value (one's complement).
1517     /// This is equivalent to "~(value)".
1518     BITWISE_NEGATE = GCC_JIT_UNARY_OP_BITWISE_NEGATE,
1519     /// Logical negation of an arithmetic or pointer value.
1520     /// This is equivalent to "!(value)".
1521     LOGICAL_NEGATE = GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
1522 }
1523 
1524 /// Kinds of binary ops.
1525 enum JITBinaryOp : gcc_jit_binary_op
1526 {
1527     /// Addition of arithmetic values.
1528     /// This is equivalent to "(a) + (b)".
1529     PLUS = GCC_JIT_BINARY_OP_PLUS,
1530     /// Subtraction of arithmetic values.
1531     /// This is equivalent to "(a) - (b)".
1532     MINUS = GCC_JIT_BINARY_OP_MINUS,
1533     /// Multiplication of a pair of arithmetic values.
1534     /// This is equivalent to "(a) * (b)".
1535     MULT = GCC_JIT_BINARY_OP_MULT,
1536     /// Quotient of division of arithmetic values.
1537     /// This is equivalent to "(a) / (b)".
1538     DIVIDE = GCC_JIT_BINARY_OP_DIVIDE,
1539     /// Remainder of division of arithmetic values.
1540     /// This is equivalent to "(a) % (b)".
1541     MODULO = GCC_JIT_BINARY_OP_MODULO,
1542     /// Bitwise AND.
1543     /// This is equivalent to "(a) & (b)".
1544     BITWISE_AND = GCC_JIT_BINARY_OP_BITWISE_AND,
1545     /// Bitwise exclusive OR.
1546     /// This is equivalent to "(a) ^ (b)".
1547     BITWISE_XOR = GCC_JIT_BINARY_OP_BITWISE_XOR,
1548     /// Bitwise inclusive OR.
1549     /// This is equivalent to "(a) | (b)".
1550     BITWISE_OR = GCC_JIT_BINARY_OP_BITWISE_OR,
1551     /// Logical AND.
1552     /// This is equivalent to "(a) && (b)".
1553     LOGICAL_AND = GCC_JIT_BINARY_OP_LOGICAL_AND,
1554     /// Logical OR.
1555     /// This is equivalent to "(a) || (b)".
1556     LOGICAL_OR = GCC_JIT_BINARY_OP_LOGICAL_OR,
1557     /// Left shift.
1558     /// This is equivalent to "(a) << (b)".
1559     LSHIFT = GCC_JIT_BINARY_OP_LSHIFT,
1560     /// Right shift.
1561     /// This is equivalent to "(a) >> (b)".
1562     RSHIFT = GCC_JIT_BINARY_OP_RSHIFT,
1563 }
1564 
1565 /// Kinds of comparison.
1566 enum JITComparison : gcc_jit_comparison
1567 {
1568     /// This is equivalent to "(a) == (b)".
1569     EQ = GCC_JIT_COMPARISON_EQ,
1570     /// This is equivalent to "(a) != (b)".
1571     NE = GCC_JIT_COMPARISON_NE,
1572     /// This is equivalent to "(a) < (b)".
1573     LT = GCC_JIT_COMPARISON_LT,
1574     /// This is equivalent to "(a) <= (b)".
1575     LE = GCC_JIT_COMPARISON_LE,
1576     /// This is equivalent to "(a) > (b)".
1577     GT = GCC_JIT_COMPARISON_GT,
1578     /// This is equivalent to "(a) >= (b)".
1579     GE = GCC_JIT_COMPARISON_GE,
1580 }
1581 
1582 /// String options
1583 enum JITStrOption : gcc_jit_str_option
1584 {
1585     /// The name of the program, for use as a prefix when printing error
1586     /// messages to stderr. If None, or default, "libgccjit.so" is used.
1587     PROGNAME = GCC_JIT_STR_OPTION_PROGNAME,
1588 }
1589 
1590 /// Integer options
1591 enum JITIntOption : gcc_jit_int_option
1592 {
1593     /// How much to optimize the code.
1594 
1595     /// Valid values are 0-3, corresponding to GCC's command-line options
1596     /// -O0 through -O3.
1597 
1598     /// The default value is 0 (unoptimized).
1599     OPTIMIZATION_LEVEL = GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
1600 }
1601 
1602 /// Boolean options
1603 enum JITBoolOption : gcc_jit_bool_option
1604 {
1605     /// If true, JITContext.compile() will attempt to do the right thing
1606     /// so that if you attach a debugger to the process, it will be able
1607     /// to inspect variables and step through your code.
1608 
1609     /// Note that you can’t step through code unless you set up source
1610     /// location information for the code (by creating and passing in
1611     /// JITLocation instances).
1612     DEBUGINFO = GCC_JIT_BOOL_OPTION_DEBUGINFO,
1613 
1614     /// If true, JITContext.compile() will dump its initial "tree"
1615     /// representation of your code to stderr, before any optimizations.
1616     DUMP_INITIAL_TREE = GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
1617 
1618     /// If true, JITContext.compile() will dump its initial "gimple"
1619     /// representation of your code to stderr, before any optimizations
1620     /// are performed. The dump resembles C code.
1621     DUMP_INITIAL_GIMPLE = GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1622 
1623     /// If true, JITContext.compile() will dump the final generated code
1624     /// to stderr, in the form of assembly language.
1625     DUMP_GENERATED_CODE = GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1626 
1627     /// If true, JITContext.compile() will print information to stderr
1628     /// on the actions it is performing, followed by a profile showing
1629     /// the time taken and memory usage of each phase.
1630     DUMP_SUMMARY = GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
1631 
1632     /// If true, JITContext.compile() will dump copious amounts of
1633     /// information on what it’s doing to various files within a
1634     /// temporary directory. Use JITBoolOption.KEEP_INTERMEDIATES
1635     /// to see the results. The files are intended to be human-readable,
1636     /// but the exact files and their formats are subject to change.
1637     DUMP_EVERYTHING = GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
1638 
1639     /// If true, libgccjit will aggressively run its garbage collector,
1640     /// to shake out bugs (greatly slowing down the compile). This is
1641     /// likely to only be of interest to developers of the library.
1642     SELFCHECK_GC = GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
1643 
1644     /// If true, the JITContext will not clean up intermediate files
1645     /// written to the filesystem, and will display their location on
1646     /// stderr.
1647     KEEP_INTERMEDIATES = GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
1648 }
1649