[jit] Add libgccjit++.h, a C++ wrapper to the API

David Malcolm dmalcolm@redhat.com
Fri Jan 31 22:46:00 GMT 2014


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  <dmalcolm@redhat.com>
 
+	* 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  <dmalcolm@redhat.com>
+
 	* 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 = &params[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  <dmalcolm@redhat.com>
+
+	* jit.dg/test-quadratic.cc: New file - a translation of
+	test-quadratic.c to the libgccjit++.h C++ API.
+
 2014-01-30  David Malcolm  <dmalcolm@redhat.com>
 
 	* 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



More information about the Gcc-patches mailing list