Committed to branch dmalcolm/jit:
The libgccjit C API is relatively low-level and thus should be easy to
maintain a stable ABI for, and to wrap from many different languages.
However, it's rather verbose.
This commit adds an example of a C++ wrapper, which makes use of methods,
overloading, and inheritance, giving a much more terse API.
It's all done as small inline functions wrapped around the raw C pointers,
within one header, so it shouldn't need to be built as a separate library,
hence this shouldn't add an ABI (I hope), just an API.
As an example, I ported test-quadratic.c to it (as a new file:
test-quadratic.cc), and was able to considerably reduce the line-count
whilst fitting within a 80-column limit:
# line, word, byte counts:
$ wc \
gcc/testsuite/jit.dg/test-quadratic.c \
gcc/testsuite/jit.dg/test-quadratic.cc
487 1066 12748 gcc/testsuite/jit.dg/test-quadratic.c
369 911 9985 gcc/testsuite/jit.dg/test-quadratic.cc
856 1977 22733 total
Caveat: I haven't yet managed to get DejaGnu to run this as part of
the test suite; I've been building/running it manually for now.
gcc/jit/
* libgccjit++.h: New file - a C++ wrapper for the libgccjit.h API.
* TODO.rst ("Test Suite"): New section, adding note about C++
tests.
gcc/testsuite/
* jit.dg/test-quadratic.cc: New file - a translation of
test-quadratic.c to the libgccjit++.h C++ API.
---
gcc/jit/ChangeLog.jit | 7 +
gcc/jit/TODO.rst | 4 +
gcc/jit/libgccjit++.h | 829 +++++++++++++++++++++++++++++++++
gcc/testsuite/ChangeLog.jit | 5 +
gcc/testsuite/jit.dg/test-quadratic.cc | 369 +++++++++++++++
5 files changed, 1214 insertions(+)
create mode 100644 gcc/jit/libgccjit++.h
create mode 100644 gcc/testsuite/jit.dg/test-quadratic.cc
diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 4babb1e..0dd95f2 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,12 @@
2014-01-31 David Malcolm <[email protected]>
+ * libgccjit++.h: New file - a C++ wrapper for the libgccjit.h API.
+
+ * TODO.rst ("Test Suite"): New section, adding note about C++
+ tests.
+
+2014-01-31 David Malcolm <[email protected]>
+
* libgccjit.h (gcc_jit_context_new_rvalue_from_int): Give the type
parameter a more descriptive name.
(gcc_jit_context_zero): Likewise.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index 5b6e0f7..0572b78 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -133,6 +133,10 @@ Initial Release
* gcc_jit_loop_end: verify that loops are validly nested?
+Test suite
+==========
+* get DejaGnu to build and run C++ testcases
+
Future milestones
=================
* try porting llvmpipe to gcc
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
new file mode 100644
index 0000000..8636dd1
--- /dev/null
+++ b/gcc/jit/libgccjit++.h
@@ -0,0 +1,829 @@
+/* A C++ API for libgccjit, purely as inline wrapper functions. */
+
+#ifndef LIBGCCJIT_PLUS_PLUS_H
+#define LIBGCCJIT_PLUS_PLUS_H
+
+#include "libgccjit.h"
+
+#include <vector>
+
+/****************************************************************************
+ C++ API
+ ****************************************************************************/
+
+namespace gccjit
+{
+ class context;
+ class location;
+ class field;
+ class type;
+ class param;
+ class function;
+ class label;
+ class rvalue;
+ class lvalue;
+
+ class context
+ {
+ public:
+ static context acquire ();
+ context ();
+ context (gcc_jit_context *ctxt);
+
+ location
+ new_location (const char *filename,
+ int line,
+ int column);
+
+ type get_type (enum gcc_jit_types kind);
+
+ field new_field (type type_, const char *name);
+ field new_field (location loc, type type_, const char *name);
+
+ type new_struct_type (const char *name,
+ std::vector<field> fields);
+ type new_struct_type (location loc,
+ const char *name,
+ std::vector<field> fields);
+
+ param new_param (type type_,
+ const char *name);
+ param new_param (location loc,
+ type type_,
+ const char *name);
+
+ function new_function (enum gcc_jit_function_kind kind,
+ type return_type,
+ const char *name,
+ std::vector<param> params,
+ int is_variadic);
+ function new_function (location loc,
+ enum gcc_jit_function_kind kind,
+ type return_type,
+ const char *name,
+ std::vector<param> params,
+ int is_variadic);
+
+ rvalue new_rvalue (type numeric_type,
+ int value);
+ rvalue zero (type numeric_type);
+ rvalue one (type numeric_type);
+ rvalue new_rvalue (type numeric_type,
+ double value);
+ rvalue new_rvalue (type pointer_type,
+ void *value);
+ rvalue new_rvalue (const char *value);
+
+ rvalue new_unary_op (enum gcc_jit_unary_op op,
+ type result_type,
+ rvalue a);
+ rvalue new_unary_op (location loc,
+ enum gcc_jit_unary_op op,
+ type result_type,
+ rvalue a);
+
+ rvalue new_binary_op (enum gcc_jit_binary_op op,
+ type result_type,
+ rvalue a, rvalue b);
+ rvalue new_binary_op (location loc,
+ enum gcc_jit_binary_op op,
+ type result_type,
+ rvalue a, rvalue b);
+
+ rvalue new_comparison (enum gcc_jit_comparison op,
+ rvalue a, rvalue b);
+ rvalue new_comparison (location loc,
+ enum gcc_jit_comparison op,
+ rvalue a, rvalue b);
+
+ rvalue new_call (function func,
+ std::vector<rvalue> args);
+ rvalue new_call (location loc,
+ function func,
+ std::vector<rvalue> args);
+
+ public:
+ gcc_jit_context *m_inner_ctxt;
+ };
+
+ class location
+ {
+ public:
+ location ();
+ location (gcc_jit_location *loc);
+
+ public:
+ gcc_jit_location *m_inner_loc;
+ };
+
+ class field
+ {
+ public:
+ field ();
+ field (gcc_jit_field *inner);
+
+ public:
+ gcc_jit_field *m_inner_field;
+ };
+
+ class type
+ {
+ public:
+ type ();
+ type (gcc_jit_type *inner);
+
+ type get_pointer ();
+
+ public:
+ gcc_jit_type *m_inner_type;
+ };
+
+ class function
+ {
+ public:
+ function ();
+ function (gcc_jit_function *func);
+
+ label new_forward_label (const char *name);
+
+ lvalue new_local (type type_,
+ const char *name);
+ lvalue new_local (location loc,
+ type type_,
+ const char *name);
+
+ void add_eval (rvalue rvalue);
+ void add_eval (location loc,
+ rvalue rvalue);
+
+ void add_assignment (lvalue lvalue,
+ rvalue rvalue);
+ void add_assignment (location loc,
+ lvalue lvalue,
+ rvalue rvalue);
+
+ void add_assignment_op (lvalue lvalue,
+ enum gcc_jit_binary_op op,
+ rvalue rvalue);
+ void add_assignment_op (location loc,
+ lvalue lvalue,
+ enum gcc_jit_binary_op op,
+ rvalue rvalue);
+
+ void add_comment (location loc,
+ const char *text);
+ void add_comment (const char *text);
+
+ void add_conditional (location loc,
+ rvalue boolval,
+ label on_true,
+ label on_false);
+ void add_conditional (rvalue boolval,
+ label on_true,
+ label on_false);
+
+ label add_label (location loc,
+ const char *name);
+ label add_label (const char *name);
+
+ void place_forward_label (location loc,
+ label lab);
+ void place_forward_label (label lab);
+
+ void add_jump (location loc,
+ label target);
+ void add_jump (label target);
+
+ void add_return (location loc,
+ rvalue rvalue);
+ void add_return (rvalue rvalue);
+
+ public:
+ gcc_jit_function *m_inner_func;
+ };
+
+ class label
+ {
+ public:
+ label ();
+ label (gcc_jit_label *inner);
+
+ public:
+ gcc_jit_label *m_inner_label;
+ };
+
+ class rvalue
+ {
+ public:
+ rvalue ();
+ rvalue (gcc_jit_rvalue *inner);
+
+ rvalue access_field (field field);
+ rvalue access_field (location loc,
+ field field);
+
+ lvalue dereference_field (field field);
+ lvalue dereference_field (location loc,
+ field field);
+
+ lvalue dereference ();
+ lvalue dereference (location loc);
+
+ public:
+ gcc_jit_rvalue *m_inner_rvalue;
+ };
+
+ class lvalue : public rvalue
+ {
+ public:
+ lvalue ();
+ lvalue (gcc_jit_lvalue *inner);
+
+ gcc_jit_lvalue *get_inner_lvalue ();
+
+ lvalue access_field (field field);
+ lvalue access_field (location loc,
+ field field);
+
+ rvalue get_address ();
+ rvalue get_address (location loc);
+ };
+
+ class param : public lvalue
+ {
+ public:
+ param ();
+ param (gcc_jit_param *inner);
+
+ gcc_jit_param *get_inner_param ();
+ };
+}
+
+/****************************************************************************
+ Implementation of the API
+ ****************************************************************************/
+namespace gccjit {
+
+// class context
+inline context context::acquire ()
+{
+ return context (gcc_jit_context_acquire ());
+}
+inline context::context () : m_inner_ctxt (NULL) {}
+inline context::context (gcc_jit_context *inner) : m_inner_ctxt (inner) {}
+
+inline location
+context::new_location (const char *filename,
+ int line,
+ int column)
+{
+ return location (gcc_jit_context_new_location (m_inner_ctxt,
+ filename,
+ line,
+ column));
+}
+
+inline type
+context::get_type (enum gcc_jit_types kind)
+{
+ return type (gcc_jit_context_get_type (m_inner_ctxt, kind));
+}
+
+inline field
+context::new_field (type type_, const char *name)
+{
+ return new_field (location (), type_, name);
+}
+inline field
+context::new_field (location loc, type type_, const char *name)
+{
+ return field (gcc_jit_context_new_field (m_inner_ctxt,
+ loc.m_inner_loc,
+ type_.m_inner_type,
+ name));
+}
+
+inline type
+context::new_struct_type (const char *name,
+ std::vector<field> fields)
+{
+ return new_struct_type (location (),
+ name,
+ fields);
+}
+inline type
+context::new_struct_type (location loc,
+ const char *name,
+ std::vector<field> fields)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ field *as_array_of_wrappers = &fields[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_field **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
+
+ return type (gcc_jit_context_new_struct_type (m_inner_ctxt,
+ loc.m_inner_loc,
+ name,
+ fields.size (),
+ as_array_of_ptrs));
+}
+
+inline param
+context::new_param (type type_,
+ const char *name)
+{
+ return new_param (location (),
+ type_,
+ name);
+}
+inline param
+context::new_param (location loc,
+ type type_,
+ const char *name)
+{
+ return param (gcc_jit_context_new_param (m_inner_ctxt,
+ loc.m_inner_loc,
+ type_.m_inner_type,
+ name));
+}
+
+inline function
+context::new_function (enum gcc_jit_function_kind kind,
+ type return_type,
+ const char *name,
+ std::vector<param> params,
+ int is_variadic)
+{
+ return new_function (location (),
+ kind,
+ return_type,
+ name,
+ params,
+ is_variadic);
+}
+inline function
+context::new_function (location loc,
+ enum gcc_jit_function_kind kind,
+ type return_type,
+ const char *name,
+ std::vector<param> params,
+ int is_variadic)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ param *as_array_of_wrappers = ¶ms[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_param **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_param **> (as_array_of_wrappers);
+
+ return function (gcc_jit_context_new_function (m_inner_ctxt,
+ loc.m_inner_loc,
+ kind,
+ return_type.m_inner_type,
+ name,
+ params.size (),
+ as_array_of_ptrs,
+ is_variadic));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+ int value)
+{
+ return rvalue (
+ gcc_jit_context_new_rvalue_from_int (m_inner_ctxt,
+ numeric_type.m_inner_type,
+ value));
+}
+
+inline rvalue
+context::zero (type numeric_type)
+{
+ return rvalue (gcc_jit_context_zero (m_inner_ctxt,
+ numeric_type.m_inner_type));
+}
+
+inline rvalue
+context::one (type numeric_type)
+{
+ return rvalue (gcc_jit_context_one (m_inner_ctxt,
+ numeric_type.m_inner_type));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+ double value)
+{
+ return rvalue (
+ gcc_jit_context_new_rvalue_from_double (m_inner_ctxt,
+ numeric_type.m_inner_type,
+ value));
+}
+
+inline rvalue
+context::new_rvalue (type pointer_type,
+ void *value)
+{
+ return rvalue (
+ gcc_jit_context_new_rvalue_from_ptr (m_inner_ctxt,
+ pointer_type.m_inner_type,
+ value));
+}
+
+inline rvalue
+context::new_rvalue (const char *value)
+{
+ return rvalue (
+ gcc_jit_context_new_string_literal (m_inner_ctxt, value));
+}
+
+inline rvalue
+context::new_unary_op (enum gcc_jit_unary_op op,
+ type result_type,
+ rvalue a)
+{
+ return new_unary_op (location (),
+ op,
+ result_type,
+ a);
+}
+inline rvalue
+context::new_unary_op (location loc,
+ enum gcc_jit_unary_op op,
+ type result_type,
+ rvalue a)
+{
+ return rvalue (gcc_jit_context_new_unary_op (m_inner_ctxt,
+ loc.m_inner_loc,
+ op,
+ result_type.m_inner_type,
+ a.m_inner_rvalue));
+}
+
+inline rvalue
+context::new_binary_op (enum gcc_jit_binary_op op,
+ type result_type,
+ rvalue a, rvalue b)
+{
+ return new_binary_op (location (),
+ op,
+ result_type,
+ a, b);
+}
+inline rvalue
+context::new_binary_op (location loc,
+ enum gcc_jit_binary_op op,
+ type result_type,
+ rvalue a, rvalue b)
+{
+ return rvalue (gcc_jit_context_new_binary_op (m_inner_ctxt,
+ loc.m_inner_loc,
+ op,
+ result_type.m_inner_type,
+ a.m_inner_rvalue,
+ b.m_inner_rvalue));
+}
+
+inline rvalue
+context::new_comparison (enum gcc_jit_comparison op,
+ rvalue a, rvalue b)
+{
+ return new_comparison (location (),
+ op,
+ a, b);
+}
+inline rvalue
+context::new_comparison (location loc,
+ enum gcc_jit_comparison op,
+ rvalue a, rvalue b)
+{
+ return rvalue (gcc_jit_context_new_comparison (m_inner_ctxt,
+ loc.m_inner_loc,
+ op,
+ a.m_inner_rvalue,
+ b.m_inner_rvalue));
+}
+
+inline rvalue
+context::new_call (function func,
+ std::vector<rvalue> args)
+{
+ return new_call (location (),
+ func,
+ args);
+}
+
+inline rvalue
+context::new_call (location loc,
+ function func,
+ std::vector<rvalue> args)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ rvalue *as_array_of_wrappers = &args[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_rvalue **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+ return gcc_jit_context_new_call (m_inner_ctxt,
+ loc.m_inner_loc,
+ func.m_inner_func,
+ args.size (),
+ as_array_of_ptrs);
+}
+
+// class location
+inline location::location () : m_inner_loc (NULL) {}
+inline location::location (gcc_jit_location *loc) : m_inner_loc (loc) {}
+
+// class field
+inline field::field () : m_inner_field (NULL) {}
+inline field::field (gcc_jit_field *inner) : m_inner_field (inner) {}
+
+// class type
+inline type::type () : m_inner_type (NULL) {}
+inline type::type (gcc_jit_type *inner) : m_inner_type (inner) {}
+
+inline type
+type::get_pointer ()
+{
+ return type (gcc_jit_type_get_pointer (m_inner_type));
+}
+
+// class function
+inline function::function () : m_inner_func (NULL) {}
+inline function::function (gcc_jit_function *inner) : m_inner_func (inner) {}
+
+inline label
+function::new_forward_label (const char *name)
+{
+ return label (gcc_jit_function_new_forward_label (m_inner_func, name));
+}
+
+inline lvalue
+function::new_local (type type_,
+ const char *name)
+{
+ return new_local (location (), type_, name);
+}
+
+inline lvalue
+function::new_local (location loc,
+ type type_,
+ const char *name)
+{
+ return lvalue (gcc_jit_function_new_local (m_inner_func,
+ loc.m_inner_loc,
+ type_.m_inner_type,
+ name));
+}
+
+inline void
+function::add_eval (rvalue rvalue)
+{
+ add_eval (location (),
+ rvalue);
+}
+inline void
+function::add_eval (location loc,
+ rvalue rvalue)
+{
+ gcc_jit_function_add_eval (m_inner_func,
+ loc.m_inner_loc,
+ rvalue.m_inner_rvalue);
+}
+
+inline void
+function::add_assignment (lvalue lvalue,
+ rvalue rvalue)
+{
+ add_assignment (location (),
+ lvalue,
+ rvalue);
+}
+inline void
+function::add_assignment (location loc,
+ lvalue lvalue,
+ rvalue rvalue)
+{
+ gcc_jit_function_add_assignment (m_inner_func,
+ loc.m_inner_loc,
+ lvalue.get_inner_lvalue (),
+ rvalue.m_inner_rvalue);
+}
+
+inline void
+function::add_assignment_op (lvalue lvalue,
+ enum gcc_jit_binary_op op,
+ rvalue rvalue)
+{
+ add_assignment_op (location (),
+ lvalue,
+ op,
+ rvalue);
+}
+inline void
+function::add_assignment_op (location loc,
+ lvalue lvalue,
+ enum gcc_jit_binary_op op,
+ rvalue rvalue)
+{
+ gcc_jit_function_add_assignment_op (m_inner_func,
+ loc.m_inner_loc,
+ lvalue.get_inner_lvalue (),
+ op,
+ rvalue.m_inner_rvalue);
+}
+
+inline void
+function::add_comment (const char *text)
+{
+ add_comment (location (), text);
+}
+inline void
+function::add_comment (location loc,
+ const char *text)
+{
+ gcc_jit_function_add_comment (m_inner_func,
+ loc.m_inner_loc,
+ text);
+}
+
+inline void
+function::add_conditional (rvalue boolval,
+ label on_true,
+ label on_false)
+{
+ return add_conditional (location (), boolval, on_true, on_false);
+}
+inline void
+function::add_conditional (location loc,
+ rvalue boolval,
+ label on_true,
+ label on_false)
+{
+ gcc_jit_function_add_conditional (m_inner_func,
+ loc.m_inner_loc,
+ boolval.m_inner_rvalue,
+ on_true.m_inner_label,
+ on_false.m_inner_label);
+}
+
+inline label
+function::add_label (const char *name)
+{
+ return add_label (location (), name);
+}
+inline label
+function::add_label (location loc,
+ const char *name)
+{
+ return label (gcc_jit_function_add_label (m_inner_func,
+ loc.m_inner_loc,
+ name));
+}
+
+inline void
+function::place_forward_label (label lab)
+{
+ return place_forward_label (location (), lab);
+}
+inline void
+function::place_forward_label (location loc,
+ label lab)
+{
+ gcc_jit_function_place_forward_label (m_inner_func,
+ loc.m_inner_loc,
+ lab.m_inner_label);
+}
+
+inline void
+function::add_jump (label target)
+{
+ add_jump (location (), target);
+}
+inline void
+function::add_jump (location loc,
+ label target)
+{
+ gcc_jit_function_add_jump (m_inner_func,
+ loc.m_inner_loc,
+ target.m_inner_label);
+}
+
+inline void
+function::add_return (rvalue rvalue)
+{
+ add_return (location (), rvalue);
+}
+inline void
+function::add_return (location loc,
+ rvalue rvalue)
+{
+ gcc_jit_function_add_return (m_inner_func,
+ loc.m_inner_loc,
+ rvalue.m_inner_rvalue);
+}
+
+// class label
+inline label::label () : m_inner_label (NULL) {}
+inline label::label (gcc_jit_label *inner) : m_inner_label (inner) {}
+
+// class rvalue
+inline rvalue::rvalue () : m_inner_rvalue (NULL) {}
+inline rvalue::rvalue (gcc_jit_rvalue *inner) : m_inner_rvalue (inner) {}
+
+inline rvalue
+rvalue::access_field (field field)
+{
+ return access_field (location (), field);
+}
+inline rvalue
+rvalue::access_field (location loc,
+ field field)
+{
+ return rvalue (gcc_jit_rvalue_access_field (m_inner_rvalue,
+ loc.m_inner_loc,
+ field.m_inner_field));
+}
+
+inline lvalue
+rvalue::dereference_field (field field)
+{
+ return dereference_field (location (),
+ field);
+}
+
+inline lvalue
+rvalue::dereference_field (location loc,
+ field field)
+{
+ return lvalue (gcc_jit_rvalue_dereference_field (m_inner_rvalue,
+ loc.m_inner_loc,
+ field.m_inner_field));
+}
+
+inline lvalue
+rvalue::dereference ()
+{
+ return dereference (location ());
+}
+inline lvalue
+rvalue::dereference (location loc)
+{
+ return lvalue (gcc_jit_rvalue_dereference (m_inner_rvalue,
+ loc.m_inner_loc));
+}
+
+// class lvalue : public rvalue
+inline lvalue::lvalue () : rvalue () {}
+inline lvalue::lvalue (gcc_jit_lvalue *inner)
+ : rvalue (gcc_jit_lvalue_as_rvalue (inner))
+{}
+
+inline gcc_jit_lvalue *
+lvalue::get_inner_lvalue ()
+{
+ /* Manual downcast: */
+ return reinterpret_cast<gcc_jit_lvalue *> (m_inner_rvalue);
+}
+
+inline lvalue
+lvalue::access_field (field field)
+{
+ return access_field (location (), field);
+}
+inline lvalue
+lvalue::access_field (location loc,
+ field field)
+{
+ return lvalue (gcc_jit_lvalue_access_field (get_inner_lvalue (),
+ loc.m_inner_loc,
+ field.m_inner_field));
+}
+
+inline rvalue
+lvalue::get_address ()
+{
+ return get_address (location ());
+}
+inline rvalue
+lvalue::get_address (location loc)
+{
+ return rvalue (gcc_jit_lvalue_get_address (get_inner_lvalue (),
+ loc.m_inner_loc));
+}
+
+// class param : public lvalue
+inline param::param () : lvalue () {}
+inline param::param (gcc_jit_param *inner)
+ : lvalue (gcc_jit_param_as_lvalue (inner))
+{}
+
+} // namespace gccjit
+
+#endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 47dface..d59b578 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,8 @@
+2014-01-31 David Malcolm <[email protected]>
+
+ * jit.dg/test-quadratic.cc: New file - a translation of
+ test-quadratic.c to the libgccjit++.h C++ API.
+
2014-01-30 David Malcolm <[email protected]>
* jit.dg/test-error-label-already-placed.c: New test case.
diff --git a/gcc/testsuite/jit.dg/test-quadratic.cc
b/gcc/testsuite/jit.dg/test-quadratic.cc
new file mode 100644
index 0000000..0151926
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-quadratic.cc
@@ -0,0 +1,369 @@
+/* Test of C++ API. */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+struct quadratic
+{
+ double a;
+ double b;
+ double c;
+ double discriminant;
+};
+
+/* As per test-quadratic.c, let's try to inject the equivalent of:
+
+ extern double sqrt (double);
+
+ void
+ calc_discriminant (struct quadratic *q)
+ {
+ // (b^2 - 4ac)
+ q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+ }
+
+ int
+ test_quadratic (double a, double b, double c, double *r1, double *r2)
+ {
+ struct quadratic q;
+ q.a = a;
+ q.b = b;
+ q.c = c;
+ calc_discriminant (&q);
+ if (q.discriminant > 0)
+ {
+ double s = sqrt (q.discriminant);
+ *r1 = (-b + s) / (2 * a);
+ *r2 = (-b - s) / (2 * a);
+ return 2;
+ }
+ else if (q.discriminant == 0)
+ {
+ *r1 = -b / (2 * a);
+ return 1;
+ }
+ else return 0;
+ }
+
+ However, we'll use the C++ bindings.
+*/
+
+/****************************************************************************
+ Test case
+ ****************************************************************************/
+
+struct quadratic_test
+{
+ gccjit::context ctxt;
+
+ /* "double" and "(double *)". */
+ gccjit::type numeric_type;
+ gccjit::type numeric_type_ptr;
+
+ /* The value (double)0. */
+ gccjit::rvalue zero;
+
+ gccjit::type int_type;
+
+ /* "struct quadratic" */
+ gccjit::type quadratic;
+ gccjit::field a;
+ gccjit::field b;
+ gccjit::field c;
+ gccjit::field discriminant;
+
+ /* "(struct quadratic *)" */
+ gccjit::type quadratic_ptr;
+
+ gccjit::function calc_discriminant;
+
+ gccjit::function sqrt;
+
+};
+
+static void
+make_types (quadratic_test &testcase)
+{
+ testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+ testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
+ testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
+
+ testcase.int_type = testcase.ctxt.get_type (GCC_JIT_TYPE_INT);
+
+ testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
+ testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
+ testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
+ testcase.discriminant =
+ testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+ std::vector<gccjit::field> fields (4);
+ fields[0] = testcase.a;
+ fields[1] = testcase.b;
+ fields[2] = testcase.c;
+ fields[3] = testcase.discriminant;
+ testcase.quadratic =
+ testcase.ctxt.new_struct_type (
+ "quadratic",
+ fields);
+ testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
+}
+
+static void
+make_sqrt (quadratic_test &testcase)
+{
+ std::vector<gccjit::param> params (1);
+ params[0] =
+ testcase.ctxt.new_param (testcase.numeric_type, "x");
+ testcase.sqrt =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
+ testcase.numeric_type,
+ "sqrt",
+ params,
+ 0);
+}
+
+static void
+make_calc_discriminant (quadratic_test &testcase)
+{
+ /* Build "calc_discriminant". */
+ gccjit::param param_q =
+ testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
+ std::vector <gccjit::param> params (1);
+ params[0] = param_q;
+ testcase.calc_discriminant =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.numeric_type,
+ "calc_discriminant",
+ params,
+ 0);
+ testcase.calc_discriminant.add_comment ("(b^2 - 4ac)");
+
+ gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
+ gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
+ gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
+
+ testcase.calc_discriminant.add_assignment (
+ /* q->discriminant =... */
+ param_q.dereference_field (testcase.discriminant),
+
+ /* (q->b * q->b) - (4 * q->a * q->c) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MINUS,
+ testcase.numeric_type,
+
+ /* (q->b * q->b) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MULT,
+ testcase.numeric_type,
+ q_b, q_b),
+
+ /* (4 * (q->a * q->c)) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MULT,
+ testcase.numeric_type,
+ /* 4.0 */
+ testcase.ctxt.new_rvalue (
+ testcase.numeric_type,
+ 4),
+ /* (q->a * q->c) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MULT,
+ testcase.numeric_type,
+ q_a, q_c)))); /* end of add_assignment call. */
+}
+
+static void
+make_test_quadratic (quadratic_test &testcase)
+{
+ gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
+ gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
+ gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
+ gccjit::param r1 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
+ gccjit::param r2 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
+
+ std::vector<gccjit::param> params (5);
+ params[0] = a;
+ params[1] = b;
+ params[2] = c;
+ params[3] = r1;
+ params[4] = r2;
+
+ gccjit::function test_quadratic =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.int_type,
+ "test_quadratic",
+ params,
+ 0);
+
+ /* struct quadratic q; */
+ gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
+ /* q.a = a; */
+ test_quadratic.add_assignment (q.access_field (testcase.a), a);
+ /* q.b = b; */
+ test_quadratic.add_assignment (q.access_field (testcase.b), b);
+ /* q.c = c; */
+ test_quadratic.add_assignment (q.access_field (testcase.c), c);
+ /* calc_discriminant (&q); */
+ gccjit::rvalue address_of_q = q.get_address ();
+ std::vector<gccjit::rvalue> args (1);
+ args[0] = address_of_q;
+ test_quadratic.add_eval (
+ testcase.ctxt.new_call (
+ testcase.calc_discriminant,
+ args));
+
+ gccjit::label on_positive_discriminant
+ = test_quadratic.new_forward_label ("positive_discriminant");
+
+ gccjit::label on_nonpositive_discriminant
+ = test_quadratic.new_forward_label ("nonpositive_discriminant");
+
+ gccjit::label on_zero_discriminant
+ = test_quadratic.new_forward_label ("zero_discriminant");
+
+ gccjit::label on_negative_discriminant
+ = test_quadratic.new_forward_label ("negative_discriminant");
+
+ test_quadratic.add_comment ("if (q.discriminant > 0)");
+ test_quadratic.add_conditional (
+ testcase.ctxt.new_comparison (
+ GCC_JIT_COMPARISON_GT,
+ q.access_field (testcase.discriminant),
+ testcase.zero),
+ on_positive_discriminant,
+ on_nonpositive_discriminant);
+
+ test_quadratic.place_forward_label (on_positive_discriminant);
+ /* double s = sqrt (q.discriminant); */
+ gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
+ gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
+ test_quadratic.add_assignment (
+ s,
+ testcase.ctxt.new_call (
+ testcase.sqrt,
+ std::vector<gccjit::rvalue> (1, discriminant_of_q)));
+
+ gccjit::rvalue minus_b =
+ testcase.ctxt.new_unary_op (
+ GCC_JIT_UNARY_OP_MINUS,
+ testcase.numeric_type,
+ b);
+ gccjit::rvalue two_a =
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MULT,
+ testcase.numeric_type,
+ testcase.ctxt.new_rvalue (testcase.numeric_type, 2),
+ a);
+
+ test_quadratic.add_comment ("*r1 = (-b + s) / (2 * a);");
+ test_quadratic.add_assignment (
+ /* "*r1 = ..." */
+ r1.dereference (),
+
+ /* (-b + s) / (2 * a) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase.numeric_type,
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_PLUS,
+ testcase.numeric_type,
+ minus_b,
+ s),
+ two_a));
+
+ test_quadratic.add_comment ("*r2 = (-b - s) / (2 * a)");
+ test_quadratic.add_assignment (
+ /* "*r2 = ..." */
+ r2.dereference (),
+
+ /* (-b - s) / (2 * a) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase.numeric_type,
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_MINUS,
+ testcase.numeric_type,
+ minus_b,
+ s),
+ two_a));
+
+ /* "return 2;" */
+ test_quadratic.add_return (testcase.ctxt.new_rvalue (testcase.int_type, 2));
+
+ /* "else if (q.discriminant == 0)" */
+ test_quadratic.place_forward_label (on_nonpositive_discriminant);
+ test_quadratic.add_comment ("else if (q.discriminant == 0)");
+ test_quadratic.add_conditional (
+ testcase.ctxt.new_comparison (
+ GCC_JIT_COMPARISON_EQ,
+ q.access_field (testcase.discriminant),
+ testcase.zero),
+ on_zero_discriminant,
+ on_negative_discriminant);
+
+ /* if (q.discriminant == 0) */
+ test_quadratic.place_forward_label (on_zero_discriminant);
+
+ test_quadratic.add_comment ("*r1 = -b / (2 * a);");
+ test_quadratic.add_assignment (
+ /* "*r1 = ..." */
+ r1.dereference (),
+
+ /* -b / (2 * a) */
+ testcase.ctxt.new_binary_op (
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase.numeric_type,
+ minus_b,
+ two_a));
+
+ /* "return 1;" */
+ test_quadratic.add_return (testcase.ctxt.one (testcase.int_type));
+
+ /* else return 0; */
+ test_quadratic.place_forward_label (on_negative_discriminant);
+ test_quadratic.add_return (testcase.ctxt.zero (testcase.int_type));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ struct quadratic_test testcase;
+ memset (&testcase, 0, sizeof (testcase));
+ testcase.ctxt = ctxt;
+ make_types (testcase);
+ make_sqrt (testcase);
+ make_calc_discriminant (testcase);
+ make_test_quadratic (testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (double a, double b, double c,
+ double *r1, double *r2);
+
+ CHECK_NON_NULL (result);
+
+ fn_type test_quadratic =
+ (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+ CHECK_NON_NULL (test_quadratic);
+
+ /* Verify that the code correctly solves quadratic equations. */
+ double r1, r2;
+
+ /* This one has two solutions: */
+ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+ CHECK_VALUE (r1, 1);
+ CHECK_VALUE (r2, -4);
+
+ /* This one has one solution: */
+ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+ CHECK_VALUE (r1, -0.5);
+
+ /* This one has no real solutions: */
+ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
--
1.7.11.7