Committed to branch dmalcolm/jit:

Expose the debug string facility to client code, to make it easier to
write client code.  In doing so, it makes sense to simply expose the
ultimate base class of "contextual object" as gcc_jit_object, to better
express which objects are "contextual", and to support querying which
context an object is within.

Make similar changes to the C++ API, including the ability to use "<<"
with jit objects.

As well as being usable from client code, this allows for usage from
within the debugger, for the C API:

  (gdb) call gcc_jit_object_get_debug_string ((gcc_jit_object *)rvalue)
  $7 = 0x610220 "R1 < R2"

and for the C++ API:

  (gdb) call lvalue.get_debug_string ()
  $4 = "q->discriminant"
  (gdb) call rvalue.get_debug_string ()
  $5 = "q->b * q->b - (double)4 * q->a * q->c"

gcc/jit/
        * libgccjit.h (struct gcc_jit_object): New.
        (gcc_jit_object_get_context): New.
        (gcc_jit_object_get_debug_string): New.
        (gcc_jit_location_as_object): New.
        (gcc_jit_type_as_object): New.
        (gcc_jit_field_as_object): New.
        (gcc_jit_param_as_object): New.
        (gcc_jit_function_as_object): New.
        (gcc_jit_label_as_object): New.
        (gcc_jit_lvalue_as_object): New.
        (gcc_jit_rvalue_as_object): New.
        (gcc_jit_loop_as_object): New.

        * libgccjit.map (gcc_jit_field_as_object): New.
        (gcc_jit_function_as_object): New.
        (gcc_jit_label_as_object): New.
        (gcc_jit_location_as_object): New.
        (gcc_jit_loop_as_object): New.
        (gcc_jit_lvalue_as_object): New.
        (gcc_jit_object_get_context): New.
        (gcc_jit_object_get_debug_string): New.
        (gcc_jit_param_as_object): New.
        (gcc_jit_rvalue_as_object): New.
        (gcc_jit_type_as_object): New.

        * libgccjit.c (struct gcc_jit_object): New.
        (gcc_jit_location_as_object): New.
        (gcc_jit_type_as_object): New.
        (gcc_jit_field_as_object): New.
        (gcc_jit_param_as_object): New.
        (gcc_jit_function_as_object): New.
        (gcc_jit_label_as_object): New.
        (gcc_jit_lvalue_as_object): New.
        (gcc_jit_rvalue_as_object): New.
        (gcc_jit_object_get_context): New.
        (gcc_jit_object_get_debug_string): New.
        (gcc_jit_loop_as_object): New.
        * internal-api.h (gcc::jit::recording::memento::get_context): New.
        (gcc::jit::recording::memento::as_object): New.

        * libgccjit++.h: Require iostream, for std::ostream.
        (class object): New base class.
        (operator << (std::ostream& stream, const object &obj)): New.
        (location): Inherit from the new "object" base class.
        (location::m_inner_loc): Remove, in favor of...
        (location::get_inner_location): ...new method.
        (field): Inherit from the new "object" base class.
        (field::m_inner_field): Remove, in favor of...
        (field::get_inner_field): ...new method.
        (type): Inherit from the new "object" base class.
        (type::m_inner_type): Remove, in favor of...
        (type::get_inner_type): ...new method.
        (function): Inherit from the new "object" base class.
        (function::m_inner_func): Remove, in favor of...
        (function::get_inner_function): ...new method.
        (label): Inherit from the new "object" base class.
        (label::m_inner_label): Remove, in favor of...
        (label::get_inner_label): ...new method.
        (rvalue) Inherit from the new "object" base class.
        (rvalue::m_inner_rvalue): Remove, in favor of...
        (rvalue::get_inner_rvalue): ...new method.

        (context::new_field): Update for move of inner pointer to the
        "object" base class.
        (context::new_struct_type): Likewise.
        (context::new_param): Likewise.
        (context::new_function): Likewise.
        (context::new_rvalue): Likewise.
        (context::zero): Likewise.
        (context::one): Likewise.
        (context::new_rvalue): Likewise.
        (context::new_rvalue): Likewise.
        (context::new_unary_op): Likewise.
        (context::new_binary_op): Likewise.
        (context::new_comparison): Likewise.
        (context::new_call): Likewise.

        (object::get_debug_string): New.
        (object::object): New.
        (object::get_inner_object): New.
        (operator << (std::ostream&, const object &)): New.

        (location::location): Update for move of inner pointer to the
        "object" base class.
        (location::get_inner_location): New.

        (field::field): Update for move of inner pointer to the
        "object" base class.
        (field::get_inner_field): New.

        (type::type): Update for move of inner pointer to the
        "object" base class.
        (type::get_pointer): Likewise.
        (type::get_inner_type): New.

        (function::function): Update for move of inner pointer to the
        "object" base class.
        (function::new_forward_label): Likewise.
        (function::new_local): Likewise.
        (function::add_eval): Likewise.
        (function::add_assignment): Likewise.
        (function::add_assignment_op): Likewise.
        (function::add_comment): Likewise.
        (function::add_conditional): Likewise.
        (function::add_label): Likewise.
        (function::place_forward_label): Likewise.
        (function::add_jump): Likewise.
        (function::add_return): Likewise.
        (function::get_inner_function): New.

        (label::label): Update for move of inner pointer to the "object"
        base class.
        (label::get_inner_label): New

        (rvalue::rvalue): Update for move of inner pointer to the "object"
        base class.
        (rvalue::get_inner_rvalue): New.
        (rvalue::access_field): Likewise.
        (rvalue::dereference_field): Likewise.
        (rvalue::dereference): Likewise.

        (lvalue::get_inner_lvalue): Update for move of inner pointer to
        the "object" base class.
        (lvalue::access_field): Likewise.
        (lvalue::get_address): Likewise.

gcc/testsuite/
        * jit.dg/harness.h (check_string_value): Add a forward declaration,
        so that we can use CHECK_STRING_VALUE from within tests used by
        test-combination.c.

        * jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
        stringification of the operation so that it be sanity-checked.
        (make_test_of_binary_op): Likewise.
        (make_test_of_comparison): Likewise.
        (make_tests_of_unary_ops): Verify that said stringifications are
        indeed sane.
        (make_tests_of_binary_ops): Likewise.
        (make_tests_of_comparisons): Likewise.

        * jit.dg/test-quadratic.cc (make_types): Verify that the
        get_debug_string method works.
        (make_test_quadratic): Likewise, also, verify that the <<
        operator works.
---
 gcc/jit/ChangeLog.jit                   | 128 ++++++++++++++
 gcc/jit/internal-api.h                  |   5 +
 gcc/jit/libgccjit++.h                   | 294 +++++++++++++++++++++-----------
 gcc/jit/libgccjit.c                     |  92 ++++++++++
 gcc/jit/libgccjit.h                     |  66 +++++++
 gcc/jit/libgccjit.map                   |  11 ++
 gcc/testsuite/ChangeLog.jit             |  20 +++
 gcc/testsuite/jit.dg/harness.h          |   2 +
 gcc/testsuite/jit.dg/test-expressions.c | 240 +++++++++++++++-----------
 gcc/testsuite/jit.dg/test-quadratic.cc  |  13 ++
 10 files changed, 674 insertions(+), 197 deletions(-)

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 0dd95f2..be96ff7 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,131 @@
+2014-02-03  David Malcolm  <dmalc...@redhat.com>
+
+       * libgccjit.h (struct gcc_jit_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_type_as_object): New.
+       (gcc_jit_field_as_object): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_loop_as_object): New.
+
+       * libgccjit.map (gcc_jit_field_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_loop_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_type_as_object): New.
+
+       * libgccjit.c (struct gcc_jit_object): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_type_as_object): New.
+       (gcc_jit_field_as_object): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_loop_as_object): New.
+       * internal-api.h (gcc::jit::recording::memento::get_context): New.
+       (gcc::jit::recording::memento::as_object): New.
+
+       * libgccjit++.h: Require iostream, for std::ostream.
+       (class object): New base class.
+       (operator << (std::ostream& stream, const object &obj)): New.
+       (location): Inherit from the new "object" base class.
+       (location::m_inner_loc): Remove, in favor of...
+       (location::get_inner_location): ...new method.
+       (field): Inherit from the new "object" base class.
+       (field::m_inner_field): Remove, in favor of...
+       (field::get_inner_field): ...new method.
+       (type): Inherit from the new "object" base class.
+       (type::m_inner_type): Remove, in favor of...
+       (type::get_inner_type): ...new method.
+       (function): Inherit from the new "object" base class.
+       (function::m_inner_func): Remove, in favor of...
+       (function::get_inner_function): ...new method.
+       (label): Inherit from the new "object" base class.
+       (label::m_inner_label): Remove, in favor of...
+       (label::get_inner_label): ...new method.
+       (rvalue) Inherit from the new "object" base class.
+       (rvalue::m_inner_rvalue): Remove, in favor of...
+       (rvalue::get_inner_rvalue): ...new method.
+
+       (context::new_field): Update for move of inner pointer to the
+       "object" base class.
+       (context::new_struct_type): Likewise.
+       (context::new_param): Likewise.
+       (context::new_function): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::zero): Likewise.
+       (context::one): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::new_unary_op): Likewise.
+       (context::new_binary_op): Likewise.
+       (context::new_comparison): Likewise.
+       (context::new_call): Likewise.
+
+       (object::get_debug_string): New.
+       (object::object): New.
+       (object::get_inner_object): New.
+       (operator << (std::ostream&, const object &)): New.
+
+       (location::location): Update for move of inner pointer to the
+       "object" base class.
+       (location::get_inner_location): New.
+
+       (field::field): Update for move of inner pointer to the
+       "object" base class.
+       (field::get_inner_field): New.
+
+       (type::type): Update for move of inner pointer to the
+       "object" base class.
+       (type::get_pointer): Likewise.
+       (type::get_inner_type): New.
+
+       (function::function): Update for move of inner pointer to the
+       "object" base class.
+       (function::new_forward_label): Likewise.
+       (function::new_local): Likewise.
+       (function::add_eval): Likewise.
+       (function::add_assignment): Likewise.
+       (function::add_assignment_op): Likewise.
+       (function::add_comment): Likewise.
+       (function::add_conditional): Likewise.
+       (function::add_label): Likewise.
+       (function::place_forward_label): Likewise.
+       (function::add_jump): Likewise.
+       (function::add_return): Likewise.
+       (function::get_inner_function): New.
+
+       (label::label): Update for move of inner pointer to the "object"
+       base class.
+       (label::get_inner_label): New
+
+       (rvalue::rvalue): Update for move of inner pointer to the "object"
+       base class.
+       (rvalue::get_inner_rvalue): New.
+       (rvalue::access_field): Likewise.
+       (rvalue::dereference_field): Likewise.
+       (rvalue::dereference): Likewise.
+
+       (lvalue::get_inner_lvalue): Update for move of inner pointer to
+       the "object" base class.
+       (lvalue::access_field): Likewise.
+       (lvalue::get_address): Likewise.
+
 2014-01-31  David Malcolm  <dmalc...@redhat.com>
 
        * libgccjit++.h: New file - a C++ wrapper for the libgccjit.h API.
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index f84196a..ce46433 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -298,6 +298,11 @@ public:
 
   void set_playback_obj (void *obj) { m_playback_obj = obj; }
 
+  context *get_context () { return m_ctxt; }
+
+  memento *
+  as_object () { return this; }
+
   /* Debugging hook, for use in generating error messages etc.  */
   const char *
   get_debug_string ();
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 8636dd1..be2f9ed 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -5,6 +5,7 @@
 
 #include "libgccjit.h"
 
+#include <iostream>
 #include <vector>
 
 /****************************************************************************
@@ -106,44 +107,61 @@ namespace gccjit
     gcc_jit_context *m_inner_ctxt;
   };
 
-  class location
+  class object
+  {
+  public:
+    std::string get_debug_string () const;
+
+  protected:
+    object ();
+    object (gcc_jit_object *obj);
+
+    gcc_jit_object *get_inner_object ();
+
+  private:
+    gcc_jit_object *m_inner_obj;
+  };
+
+  inline std::ostream& operator << (std::ostream& stream, const object &obj);
+
+  class location : public object
   {
   public:
     location ();
     location (gcc_jit_location *loc);
 
-  public:
-    gcc_jit_location *m_inner_loc;
+    gcc_jit_location *get_inner_location ();
    };
 
-  class field
+  class field : public object
   {
   public:
     field ();
     field (gcc_jit_field *inner);
 
- public:
-    gcc_jit_field *m_inner_field;
+    gcc_jit_field *get_inner_field ();
   };
 
-  class type
+  class type : public object
   {
   public:
     type ();
     type (gcc_jit_type *inner);
 
+    gcc_jit_type *get_inner_type ();
+
     type get_pointer ();
 
-  public:
-    gcc_jit_type *m_inner_type;
-  };
+ };
 
-  class function
+  class function : public object
   {
   public:
     function ();
     function (gcc_jit_function *func);
 
+    gcc_jit_function *get_inner_function ();
+
     label new_forward_label (const char *name);
 
     lvalue new_local (type type_,
@@ -198,25 +216,23 @@ namespace gccjit
                     rvalue rvalue);
     void add_return (rvalue rvalue);
 
-  public:
-    gcc_jit_function *m_inner_func;
-   };
+  };
 
-  class label
+  class label : public object
   {
   public:
     label ();
     label (gcc_jit_label *inner);
 
-  public:
-    gcc_jit_label *m_inner_label;
+    gcc_jit_label *get_inner_label ();
   };
 
-  class rvalue
+  class rvalue : public object
   {
   public:
     rvalue ();
     rvalue (gcc_jit_rvalue *inner);
+    gcc_jit_rvalue *get_inner_rvalue ();
 
     rvalue access_field (field field);
     rvalue access_field (location loc,
@@ -229,9 +245,7 @@ namespace gccjit
     lvalue dereference ();
     lvalue dereference (location loc);
 
-  public:
-    gcc_jit_rvalue *m_inner_rvalue;
-  };
+ };
 
   class lvalue : public rvalue
   {
@@ -298,8 +312,8 @@ 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,
+                                          loc.get_inner_location (),
+                                          type_.get_inner_type (),
                                           name));
 }
 
@@ -325,7 +339,7 @@ context::new_struct_type (location loc,
     reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
 
   return type (gcc_jit_context_new_struct_type (m_inner_ctxt,
-                                               loc.m_inner_loc,
+                                               loc.get_inner_location (),
                                                name,
                                                fields.size (),
                                                as_array_of_ptrs));
@@ -345,8 +359,8 @@ context::new_param (location loc,
                    const char *name)
 {
   return param (gcc_jit_context_new_param (m_inner_ctxt,
-                                          loc.m_inner_loc,
-                                          type_.m_inner_type,
+                                          loc.get_inner_location (),
+                                          type_.get_inner_type (),
                                           name));
 }
 
@@ -381,9 +395,9 @@ context::new_function (location loc,
     reinterpret_cast<gcc_jit_param **> (as_array_of_wrappers);
 
   return function (gcc_jit_context_new_function (m_inner_ctxt,
-                                                loc.m_inner_loc,
+                                                loc.get_inner_location (),
                                                 kind,
-                                                return_type.m_inner_type,
+                                                return_type.get_inner_type (),
                                                 name,
                                                 params.size (),
                                                 as_array_of_ptrs,
@@ -396,7 +410,7 @@ context::new_rvalue (type numeric_type,
 {
   return rvalue (
     gcc_jit_context_new_rvalue_from_int (m_inner_ctxt,
-                                        numeric_type.m_inner_type,
+                                        numeric_type.get_inner_type (),
                                         value));
 }
 
@@ -404,14 +418,14 @@ inline rvalue
 context::zero (type numeric_type)
 {
   return rvalue (gcc_jit_context_zero (m_inner_ctxt,
-                                      numeric_type.m_inner_type));
+                                      numeric_type.get_inner_type ()));
 }
 
 inline rvalue
 context::one (type numeric_type)
 {
   return rvalue (gcc_jit_context_one (m_inner_ctxt,
-                                      numeric_type.m_inner_type));
+                                      numeric_type.get_inner_type ()));
 }
 
 inline rvalue
@@ -420,7 +434,7 @@ context::new_rvalue (type numeric_type,
 {
   return rvalue (
     gcc_jit_context_new_rvalue_from_double (m_inner_ctxt,
-                                           numeric_type.m_inner_type,
+                                           numeric_type.get_inner_type (),
                                            value));
 }
 
@@ -430,7 +444,7 @@ context::new_rvalue (type pointer_type,
 {
   return rvalue (
     gcc_jit_context_new_rvalue_from_ptr (m_inner_ctxt,
-                                        pointer_type.m_inner_type,
+                                        pointer_type.get_inner_type (),
                                         value));
 }
 
@@ -458,10 +472,10 @@ context::new_unary_op (location loc,
                       rvalue a)
 {
   return rvalue (gcc_jit_context_new_unary_op (m_inner_ctxt,
-                                              loc.m_inner_loc,
+                                              loc.get_inner_location (),
                                               op,
-                                              result_type.m_inner_type,
-                                              a.m_inner_rvalue));
+                                              result_type.get_inner_type (),
+                                              a.get_inner_rvalue ()));
 }
 
 inline rvalue
@@ -481,11 +495,11 @@ context::new_binary_op (location loc,
                        rvalue a, rvalue b)
 {
   return rvalue (gcc_jit_context_new_binary_op (m_inner_ctxt,
-                                               loc.m_inner_loc,
+                                               loc.get_inner_location (),
                                                op,
-                                               result_type.m_inner_type,
-                                               a.m_inner_rvalue,
-                                               b.m_inner_rvalue));
+                                               result_type.get_inner_type (),
+                                               a.get_inner_rvalue (),
+                                               b.get_inner_rvalue ()));
 }
 
 inline rvalue
@@ -502,10 +516,10 @@ context::new_comparison (location loc,
                         rvalue a, rvalue b)
 {
   return rvalue (gcc_jit_context_new_comparison (m_inner_ctxt,
-                                                loc.m_inner_loc,
+                                                loc.get_inner_location (),
                                                 op,
-                                                a.m_inner_rvalue,
-                                                b.m_inner_rvalue));
+                                                a.get_inner_rvalue (),
+                                                b.get_inner_rvalue ()));
 }
 
 inline rvalue
@@ -530,38 +544,97 @@ context::new_call (location loc,
   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,
+                                  loc.get_inner_location (),
+                                  func.get_inner_function (),
                                   args.size (),
                                   as_array_of_ptrs);
 }
 
+// class object
+inline std::string
+object::get_debug_string () const
+{
+  return gcc_jit_object_get_debug_string (m_inner_obj);
+}
+
+inline object::object () : m_inner_obj (NULL) {}
+inline object::object (gcc_jit_object *obj) : m_inner_obj (obj) {}
+
+inline gcc_jit_object *
+object::get_inner_object ()
+{
+  return m_inner_obj;
+}
+
+inline std::ostream&
+operator << (std::ostream& stream, const object &obj)
+{
+  return stream << obj.get_debug_string ();
+}
+
 // class location
-inline location::location () : m_inner_loc (NULL) {}
-inline location::location (gcc_jit_location *loc) : m_inner_loc (loc) {}
+inline location::location () : object (NULL) {}
+inline location::location (gcc_jit_location *loc)
+  : object (gcc_jit_location_as_object (loc))
+{}
+
+inline gcc_jit_location *
+location::get_inner_location ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_location *> (get_inner_object ());
+}
 
 // class field
-inline field::field () : m_inner_field (NULL) {}
-inline field::field (gcc_jit_field *inner) : m_inner_field (inner) {}
+inline field::field () : object (NULL) {}
+inline field::field (gcc_jit_field *inner)
+  : object (gcc_jit_field_as_object (inner))
+{}
+
+inline gcc_jit_field *
+field::get_inner_field ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_field *> (get_inner_object ());
+}
 
 // class type
-inline type::type () : m_inner_type (NULL) {}
-inline type::type (gcc_jit_type *inner) : m_inner_type (inner) {}
+inline type::type () : object (NULL) {}
+inline type::type (gcc_jit_type *inner)
+  : object (gcc_jit_type_as_object (inner))
+{}
+
+inline gcc_jit_type *
+type::get_inner_type ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_type *> (get_inner_object ());
+}
 
 inline type
 type::get_pointer ()
 {
-  return type (gcc_jit_type_get_pointer (m_inner_type));
+  return type (gcc_jit_type_get_pointer (get_inner_type ()));
 }
 
 // class function
-inline function::function () : m_inner_func (NULL) {}
-inline function::function (gcc_jit_function *inner) : m_inner_func (inner) {}
+inline function::function () : object (NULL) {}
+inline function::function (gcc_jit_function *inner)
+  : object (gcc_jit_function_as_object (inner))
+{}
+
+inline gcc_jit_function *
+function::get_inner_function ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_function *> (get_inner_object ());
+}
 
 inline label
 function::new_forward_label (const char *name)
 {
-  return label (gcc_jit_function_new_forward_label (m_inner_func, name));
+  return label (gcc_jit_function_new_forward_label (get_inner_function (),
+                                                   name));
 }
 
 inline lvalue
@@ -576,9 +649,9 @@ 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,
+  return lvalue (gcc_jit_function_new_local (get_inner_function (),
+                                            loc.get_inner_location (),
+                                            type_.get_inner_type (),
                                             name));
 }
 
@@ -592,9 +665,9 @@ 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);
+  gcc_jit_function_add_eval (get_inner_function (),
+                            loc.get_inner_location (),
+                            rvalue.get_inner_rvalue ());
 }
 
 inline void
@@ -610,10 +683,10 @@ function::add_assignment (location loc,
                          lvalue lvalue,
                          rvalue rvalue)
 {
-  gcc_jit_function_add_assignment (m_inner_func,
-                                  loc.m_inner_loc,
+  gcc_jit_function_add_assignment (get_inner_function (),
+                                  loc.get_inner_location (),
                                   lvalue.get_inner_lvalue (),
-                                  rvalue.m_inner_rvalue);
+                                  rvalue.get_inner_rvalue ());
 }
 
 inline void
@@ -632,11 +705,11 @@ function::add_assignment_op (location loc,
                             enum gcc_jit_binary_op op,
                             rvalue rvalue)
 {
-  gcc_jit_function_add_assignment_op (m_inner_func,
-                                     loc.m_inner_loc,
+  gcc_jit_function_add_assignment_op (get_inner_function (),
+                                     loc.get_inner_location (),
                                      lvalue.get_inner_lvalue (),
                                      op,
-                                     rvalue.m_inner_rvalue);
+                                     rvalue.get_inner_rvalue ());
 }
 
 inline void
@@ -648,8 +721,8 @@ inline void
 function::add_comment (location loc,
                       const char *text)
 {
-  gcc_jit_function_add_comment (m_inner_func,
-                               loc.m_inner_loc,
+  gcc_jit_function_add_comment (get_inner_function (),
+                               loc.get_inner_location (),
                                text);
 }
 
@@ -666,11 +739,11 @@ function::add_conditional (location loc,
                           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);
+  gcc_jit_function_add_conditional (get_inner_function (),
+                                   loc.get_inner_location (),
+                                   boolval.get_inner_rvalue (),
+                                   on_true.get_inner_label (),
+                                   on_false.get_inner_label ());
 }
 
 inline label
@@ -682,8 +755,8 @@ inline label
 function::add_label (location loc,
                     const char *name)
 {
-  return label (gcc_jit_function_add_label (m_inner_func,
-                                           loc.m_inner_loc,
+  return label (gcc_jit_function_add_label (get_inner_function (),
+                                           loc.get_inner_location (),
                                            name));
 }
 
@@ -696,9 +769,9 @@ 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);
+  gcc_jit_function_place_forward_label (get_inner_function (),
+                                       loc.get_inner_location (),
+                                       lab.get_inner_label ());
 }
 
 inline void
@@ -710,9 +783,9 @@ 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);
+  gcc_jit_function_add_jump (get_inner_function (),
+                            loc.get_inner_location (),
+                            target.get_inner_label ());
 }
 
 inline void
@@ -724,18 +797,37 @@ 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);
+  gcc_jit_function_add_return (get_inner_function (),
+                              loc.get_inner_location (),
+                              rvalue.get_inner_rvalue ());
 }
 
 // class label
-inline label::label () : m_inner_label (NULL) {}
-inline label::label (gcc_jit_label *inner) : m_inner_label (inner) {}
+inline label::label () : object (NULL) {}
+inline label::label (gcc_jit_label *inner)
+  : object (gcc_jit_label_as_object (inner))
+{}
+
+inline gcc_jit_label *
+label::get_inner_label ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_label *> (get_inner_object ());
+}
 
 //  class rvalue
-inline rvalue::rvalue () : m_inner_rvalue (NULL) {}
-inline rvalue::rvalue (gcc_jit_rvalue *inner) : m_inner_rvalue (inner) {}
+inline rvalue::rvalue () : object (NULL) {}
+inline rvalue::rvalue (gcc_jit_rvalue *inner)
+  : object (gcc_jit_rvalue_as_object (inner))
+{}
+
+inline gcc_jit_rvalue *
+rvalue::get_inner_rvalue ()
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_rvalue *> (get_inner_object ());
+}
+
 
 inline rvalue
 rvalue::access_field (field field)
@@ -746,9 +838,9 @@ 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));
+  return rvalue (gcc_jit_rvalue_access_field (get_inner_rvalue (),
+                                             loc.get_inner_location (),
+                                             field.get_inner_field ()));
 }
 
 inline lvalue
@@ -762,9 +854,9 @@ 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));
+  return lvalue (gcc_jit_rvalue_dereference_field (get_inner_rvalue (),
+                                                  loc.get_inner_location (),
+                                                  field.get_inner_field ()));
 }
 
 inline lvalue
@@ -775,8 +867,8 @@ rvalue::dereference ()
 inline lvalue
 rvalue::dereference (location loc)
 {
-  return lvalue (gcc_jit_rvalue_dereference (m_inner_rvalue,
-                                            loc.m_inner_loc));
+  return lvalue (gcc_jit_rvalue_dereference (get_inner_rvalue (),
+                                            loc.get_inner_location ()));
 }
 
 // class lvalue : public rvalue
@@ -789,7 +881,7 @@ inline gcc_jit_lvalue *
 lvalue::get_inner_lvalue ()
 {
   /* Manual downcast: */
-  return reinterpret_cast<gcc_jit_lvalue *> (m_inner_rvalue);
+  return reinterpret_cast<gcc_jit_lvalue *> (get_inner_object ());
 }
 
 inline lvalue
@@ -802,8 +894,8 @@ 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));
+                                             loc.get_inner_location (),
+                                             field.get_inner_field ()));
 }
 
 inline rvalue
@@ -815,7 +907,7 @@ inline rvalue
 lvalue::get_address (location loc)
 {
   return rvalue (gcc_jit_lvalue_get_address (get_inner_lvalue (),
-                                            loc.m_inner_loc));
+                                            loc.get_inner_location ()));
 }
 
 // class param : public lvalue
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index d7f91f8..67d09ea 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -19,6 +19,10 @@ struct gcc_jit_result : public gcc::jit::result
 {
 };
 
+struct gcc_jit_object : public gcc::jit::recording::memento
+{
+};
+
 struct gcc_jit_location : public gcc::jit::recording::location
 {
 };
@@ -215,6 +219,22 @@ gcc_jit_context_new_location (gcc_jit_context *ctxt,
   return (gcc_jit_location *)ctxt->new_location (filename, line, column);
 }
 
+gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (loc, NULL, "NULL location");
+
+  return static_cast <gcc_jit_object *> (loc->as_object ());
+}
+
+gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
+
+  return static_cast <gcc_jit_object *> (type->as_object ());
+}
+
 gcc_jit_type *
 gcc_jit_context_get_type (gcc_jit_context *ctxt,
                          enum gcc_jit_types type)
@@ -254,6 +274,14 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
   return (gcc_jit_field *)ctxt->new_field (loc, type, name);
 }
 
+gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (field, NULL, "NULL field");
+
+  return static_cast <gcc_jit_object *> (field->as_object ());
+}
+
 gcc_jit_type *
 gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
                                 gcc_jit_location *loc,
@@ -295,6 +323,14 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt,
   return (gcc_jit_param *)ctxt->new_param (loc, type, name);
 }
 
+gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, "NULL param");
+
+  return static_cast <gcc_jit_object *> (param->as_object ());
+}
+
 gcc_jit_lvalue *
 gcc_jit_param_as_lvalue (gcc_jit_param *param)
 {
@@ -339,6 +375,14 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
                        is_variadic);
 }
 
+gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, "NULL function");
+
+  return static_cast <gcc_jit_object *> (func->as_object ());
+}
+
 gcc_jit_label*
 gcc_jit_function_new_forward_label (gcc_jit_function *func,
                                    const char *name)
@@ -349,6 +393,14 @@ gcc_jit_function_new_forward_label (gcc_jit_function *func,
   return (gcc_jit_label *)func->new_forward_label (name);
 }
 
+gcc_jit_object *
+gcc_jit_label_as_object (gcc_jit_label *label)
+{
+  RETURN_NULL_IF_FAIL (label, NULL, "NULL label");
+
+  return static_cast <gcc_jit_object *> (label->as_object ());
+}
+
 gcc_jit_lvalue *
 gcc_jit_context_new_global (gcc_jit_context *ctxt,
                            gcc_jit_location *loc,
@@ -362,6 +414,14 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
   return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name);
 }
 
+gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, "NULL lvalue");
+
+  return static_cast <gcc_jit_object *> (lvalue->as_object ());
+}
+
 gcc_jit_rvalue *
 gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
 {
@@ -370,6 +430,14 @@ gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
   return (gcc_jit_rvalue *)lvalue->as_rvalue ();
 }
 
+gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, "NULL rvalue");
+
+  return static_cast <gcc_jit_object *> (rvalue->as_object ());
+}
+
 gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
                                     gcc_jit_type *numeric_type,
@@ -546,6 +614,22 @@ gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
   return (gcc_jit_rvalue *)ctxt->new_array_lookup (loc, ptr, index);
 }
 
+gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, "NULL object");
+
+  return static_cast <gcc_jit_context *> (obj->get_context ());
+}
+
+const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, "NULL object");
+
+  return obj->get_debug_string ();
+}
+
 gcc_jit_lvalue *
 gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
                             gcc_jit_location *loc,
@@ -780,6 +864,14 @@ gcc_jit_function_new_loop (gcc_jit_function *func,
   return (gcc_jit_loop *)func->new_loop (loc, boolval);
 }
 
+gcc_jit_object *
+gcc_jit_loop_as_object (gcc_jit_loop *loop)
+{
+  RETURN_NULL_IF_FAIL (loop, NULL, "NULL loop");
+
+  return static_cast <gcc_jit_object *> (loop->as_object ());
+}
+
 void
 gcc_jit_loop_end (gcc_jit_loop *loop,
                  gcc_jit_location *loc)
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 3ff61d8..f408baf 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -28,6 +28,24 @@ typedef struct gcc_jit_context gcc_jit_context;
 /* A gcc_jit_result encapsulates the result of a compilation.  */
 typedef struct gcc_jit_result gcc_jit_result;
 
+/* An object created within a context.  Such objects are automatically
+   cleaned up when the context is released.
+
+   The class hierarchy looks like this:
+
+     +- gcc_jit_object
+         +- gcc_jit_location
+         +- gcc_jit_type
+         +- gcc_jit_field
+         +- gcc_jit_function
+         +- gcc_jit_label
+         +- gcc_jit_rvalue
+             +- gcc_jit_lvalue
+                 +- gcc_jit_param
+         +- gcc_jit_loop
+*/
+typedef struct gcc_jit_object gcc_jit_object;
+
 /* A gcc_jit_location encapsulates a source code location, so that
    you can (optionally) associate locations in your language with
    statements in the JIT-compiled code, allowing the debugger to
@@ -238,7 +256,20 @@ gcc_jit_result_release (gcc_jit_result *result);
  managing blocks.   If you have blocks, you can simply create labels
  for the start of each block.  You can even create labels for every
  instruction in your language; unused labels will be optimized away.
+**********************************************************************/
+
+/**********************************************************************
+ The base class of "contextual" object.
  **********************************************************************/
+/* Which context is "obj" within?  */
+extern gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj);
+
+/* Get a human-readable description of this object.
+   The string buffer is created the first time this is called on a given
+   object, and persists until the object's context is released.  */
+extern const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj);
 
 /**********************************************************************
  Debugging information.
@@ -252,11 +283,19 @@ gcc_jit_context_new_location (gcc_jit_context *ctxt,
                              int line,
                              int column);
 
+/* Upcasting from location to object.  */
+extern gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc);
+
 
 /**********************************************************************
  Types.
  **********************************************************************/
 
+/* Upcasting from type to object.  */
+extern gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type);
+
 /* Access to specific types.  */
 enum gcc_jit_types
 {
@@ -327,6 +366,10 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
                           gcc_jit_type *type,
                           const char *name);
 
+/* Upcasting from field to object.  */
+extern gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field);
+
 extern gcc_jit_type *
 gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
                                 gcc_jit_location *loc,
@@ -343,6 +386,10 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt,
                           gcc_jit_type *type,
                           const char *name);
 
+/* Upcasting from param to object.  */
+extern gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param);
+
 extern gcc_jit_lvalue *
 gcc_jit_param_as_lvalue (gcc_jit_param *param);
 
@@ -377,6 +424,10 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
                              gcc_jit_param **params,
                              int is_variadic);
 
+/* Upcasting from function to object.  */
+extern gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func);
+
 /* Create a label, to be placed later.
 
    The name can be NULL, or you can give it a meaningful name, which
@@ -385,6 +436,10 @@ extern gcc_jit_label *
 gcc_jit_function_new_forward_label (gcc_jit_function *func,
                                    const char *name);
 
+/* Upcasting from label to object.  */
+extern gcc_jit_object *
+gcc_jit_label_as_object (gcc_jit_label *label);
+
 /**********************************************************************
  lvalues, rvalues and expressions.
  **********************************************************************/
@@ -395,9 +450,16 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
                            gcc_jit_type *type,
                            const char *name);
 
+/* Upcasting.  */
+extern gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
+
 extern gcc_jit_rvalue *
 gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
 
+extern gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue);
+
 /* Integer constants. */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
@@ -750,6 +812,10 @@ gcc_jit_function_new_loop (gcc_jit_function *func,
                           gcc_jit_location *loc,
                           gcc_jit_rvalue *boolval);
 
+/* Upcasting from loop to object.  */
+extern gcc_jit_object *
+gcc_jit_loop_as_object (gcc_jit_loop *loop);
+
 extern void
 gcc_jit_loop_end (gcc_jit_loop *loop,
                  gcc_jit_location *loc);
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index fe2a492..88cec7b 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -28,6 +28,7 @@
     gcc_jit_context_set_int_option;
     gcc_jit_context_set_str_option;
     gcc_jit_context_zero;
+    gcc_jit_field_as_object;
     gcc_jit_function_add_assignment;
     gcc_jit_function_add_assignment_op;
     gcc_jit_function_add_comment;
@@ -36,21 +37,31 @@
     gcc_jit_function_add_jump;
     gcc_jit_function_add_label;
     gcc_jit_function_add_return;
+    gcc_jit_function_as_object;
     gcc_jit_function_new_forward_label;
     gcc_jit_function_new_local;
     gcc_jit_function_new_loop;
     gcc_jit_function_place_forward_label;
+    gcc_jit_label_as_object;
+    gcc_jit_location_as_object;
+    gcc_jit_loop_as_object;
     gcc_jit_loop_end;
+    gcc_jit_lvalue_as_object;
     gcc_jit_lvalue_as_rvalue;
     gcc_jit_lvalue_access_field;
     gcc_jit_lvalue_get_address;
+    gcc_jit_object_get_context;
+    gcc_jit_object_get_debug_string;
     gcc_jit_param_as_lvalue;
+    gcc_jit_param_as_object;
     gcc_jit_param_as_rvalue;
     gcc_jit_result_get_code;
     gcc_jit_result_release;
     gcc_jit_rvalue_access_field;
+    gcc_jit_rvalue_as_object;
     gcc_jit_rvalue_dereference;
     gcc_jit_rvalue_dereference_field;
+    gcc_jit_type_as_object;
     gcc_jit_type_get_const;
     gcc_jit_type_get_pointer;
 
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index d59b578..3db5cf5 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,23 @@
+2014-02-03  David Malcolm  <dmalc...@redhat.com>
+
+       * jit.dg/harness.h (check_string_value): Add a forward declaration,
+       so that we can use CHECK_STRING_VALUE from within tests used by
+       test-combination.c.
+
+       * jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
+       stringification of the operation so that it be sanity-checked.
+       (make_test_of_binary_op): Likewise.
+       (make_test_of_comparison): Likewise.
+       (make_tests_of_unary_ops): Verify that said stringifications are
+       indeed sane.
+       (make_tests_of_binary_ops): Likewise.
+       (make_tests_of_comparisons): Likewise.
+
+       * jit.dg/test-quadratic.cc (make_types): Verify that the
+       get_debug_string method works.
+       (make_test_quadratic): Likewise, also, verify that the <<
+       operator works.
+
 2014-01-31  David Malcolm  <dmalc...@redhat.com>
 
        * jit.dg/test-quadratic.cc: New file - a translation of
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index d82513f..7e8341a 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -57,6 +57,8 @@ create_code (gcc_jit_context *ctxt, void * user_data);
 extern void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
 
+extern void check_string_value (const char *actual, const char *expected);
+
 /* Implement framework needed for turning the testcase hooks into an
    executable.  test-combination.c combines multiple testcases into one
    testcase, so we have TEST_COMBINATION as a way of temporarily turning
diff --git a/gcc/testsuite/jit.dg/test-expressions.c 
b/gcc/testsuite/jit.dg/test-expressions.c
index 43d548f..36588c6 100644
--- a/gcc/testsuite/jit.dg/test-expressions.c
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -10,7 +10,7 @@
  Unary ops
  **********************************************************************/
 
-static void
+static const char *
 make_test_of_unary_op (gcc_jit_context *ctxt,
                       gcc_jit_type *type,
                       enum gcc_jit_unary_op op,
@@ -21,6 +21,8 @@ make_test_of_unary_op (gcc_jit_context *ctxt,
        {
          return OP a;
        }
+     and return a debug dump of the OP so that
+     the caller can sanity-check the debug dump implementation.
   */
   gcc_jit_param *param_a =
     gcc_jit_context_new_param (ctxt, NULL, type, "a");
@@ -31,15 +33,17 @@ make_test_of_unary_op (gcc_jit_context *ctxt,
                                  funcname,
                                  1, &param_a,
                                  0);
-  gcc_jit_function_add_return (
-    test_fn,
+  gcc_jit_rvalue *unary_op = gcc_jit_context_new_unary_op (
+    ctxt,
     NULL,
-    gcc_jit_context_new_unary_op (
-      ctxt,
-      NULL,
-      op,
-      type,
-      gcc_jit_param_as_rvalue (param_a)));
+    op,
+    type,
+    gcc_jit_param_as_rvalue (param_a));
+
+  gcc_jit_function_add_return (test_fn, NULL, unary_op);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (unary_op));
 }
 
 
@@ -49,18 +53,24 @@ make_tests_of_unary_ops (gcc_jit_context *ctxt)
   gcc_jit_type *int_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
 
-  make_test_of_unary_op (ctxt,
-                        int_type,
-                        GCC_JIT_UNARY_OP_MINUS,
-                        "test_UNARY_OP_MINUS_on_int");
-  make_test_of_unary_op (ctxt,
-                        int_type,
-                        GCC_JIT_UNARY_OP_BITWISE_NEGATE,
-                        "test_UNARY_OP_BITWISE_NEGATE_on_int");
-  make_test_of_unary_op (ctxt,
-                        int_type,
-                        GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
-                        "test_UNARY_OP_LOGICAL_NEGATE_on_int");
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_MINUS,
+                          "test_UNARY_OP_MINUS_on_int"),
+    "-(a)");
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+                          "test_UNARY_OP_BITWISE_NEGATE_on_int"),
+    "~(a)");
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+                          "test_UNARY_OP_LOGICAL_NEGATE_on_int"),
+    "!(a)");
 }
 
 static void
@@ -98,7 +108,7 @@ verify_unary_ops (gcc_jit_result *result)
  Binary ops
  **********************************************************************/
 
-static void
+static const char *
 make_test_of_binary_op (gcc_jit_context *ctxt,
                        gcc_jit_type *type,
                        enum gcc_jit_binary_op op,
@@ -122,16 +132,19 @@ make_test_of_binary_op (gcc_jit_context *ctxt,
                                  funcname,
                                  2, params,
                                  0);
-  gcc_jit_function_add_return (
-    test_fn,
-    NULL,
+  gcc_jit_rvalue *binary_op =
     gcc_jit_context_new_binary_op (
       ctxt,
       NULL,
       op,
       type,
       gcc_jit_param_as_rvalue (param_a),
-      gcc_jit_param_as_rvalue (param_b)));
+      gcc_jit_param_as_rvalue (param_b));
+
+  gcc_jit_function_add_return (test_fn, NULL, binary_op);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (binary_op));
 }
 
 
@@ -141,48 +154,68 @@ make_tests_of_binary_ops (gcc_jit_context *ctxt)
   gcc_jit_type *int_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
 
- /* Test binary ops.  */
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_PLUS,
-                         "test_BINARY_OP_PLUS_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_MINUS,
-                         "test_BINARY_OP_MINUS_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_MULT,
-                         "test_BINARY_OP_MULT_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_DIVIDE,
-                         "test_BINARY_OP_DIVIDE_on_int");
+  /* Test binary ops.  */
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_PLUS,
+                           "test_BINARY_OP_PLUS_on_int"),
+    "a + b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MINUS,
+                           "test_BINARY_OP_MINUS_on_int"),
+    "a - b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MULT,
+                           "test_BINARY_OP_MULT_on_int"),
+    "a * b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_DIVIDE,
+                           "test_BINARY_OP_DIVIDE_on_int"),
+    "a / b");
   /* TODO: test for DIVIDE on float or double */
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_MODULO,
-                         "test_BINARY_OP_MODULO_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_BITWISE_AND,
-                         "test_BINARY_OP_BITWISE_AND_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_BITWISE_XOR,
-                         "test_BINARY_OP_BITWISE_XOR_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_BITWISE_OR,
-                         "test_BINARY_OP_BITWISE_OR_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_LOGICAL_AND,
-                         "test_BINARY_OP_LOGICAL_AND_on_int");
-  make_test_of_binary_op (ctxt,
-                         int_type,
-                         GCC_JIT_BINARY_OP_LOGICAL_OR,
-                         "test_BINARY_OP_LOGICAL_OR_on_int");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MODULO,
+                           "test_BINARY_OP_MODULO_on_int"),
+    "a % b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_AND,
+                           "test_BINARY_OP_BITWISE_AND_on_int"),
+    "a & b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_XOR,
+                           "test_BINARY_OP_BITWISE_XOR_on_int"),
+    "a ^ b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_OR,
+                           "test_BINARY_OP_BITWISE_OR_on_int"),
+    "a | b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_LOGICAL_AND,
+                           "test_BINARY_OP_LOGICAL_AND_on_int"),
+    "a && b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_LOGICAL_OR,
+                           "test_BINARY_OP_LOGICAL_OR_on_int"),
+    "a || b");
 }
 
 static void
@@ -279,7 +312,7 @@ verify_binary_ops (gcc_jit_result *result)
  Comparisons
  **********************************************************************/
 
-static void
+static const char *
 make_test_of_comparison (gcc_jit_context *ctxt,
                         gcc_jit_type *type,
                         enum gcc_jit_comparison op,
@@ -303,15 +336,18 @@ make_test_of_comparison (gcc_jit_context *ctxt,
                                  funcname,
                                  2, params,
                                  0);
-  gcc_jit_function_add_return (
-    test_fn,
-    NULL,
+  gcc_jit_rvalue *comparison =
     gcc_jit_context_new_comparison (
       ctxt,
       NULL,
       op,
       gcc_jit_param_as_rvalue (param_a),
-      gcc_jit_param_as_rvalue (param_b)));
+      gcc_jit_param_as_rvalue (param_b));
+
+  gcc_jit_function_add_return (test_fn, NULL, comparison);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (comparison));
 }
 
 static void
@@ -320,30 +356,42 @@ make_tests_of_comparisons (gcc_jit_context *ctxt)
   gcc_jit_type *int_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
 
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_EQ,
-                          "test_COMPARISON_EQ_on_int");
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_NE,
-                          "test_COMPARISON_NE_on_int");
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_LT,
-                          "test_COMPARISON_LT_on_int");
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_LE,
-                          "test_COMPARISON_LE_on_int");
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_GT,
-                          "test_COMPARISON_GT_on_int");
-  make_test_of_comparison (ctxt,
-                          int_type,
-                          GCC_JIT_COMPARISON_GE,
-                          "test_COMPARISON_GE_on_int");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_EQ,
+                            "test_COMPARISON_EQ_on_int"),
+    "a == b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_NE,
+                            "test_COMPARISON_NE_on_int"),
+    "a != b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_LT,
+                            "test_COMPARISON_LT_on_int"),
+    "a < b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_LE,
+                            "test_COMPARISON_LE_on_int"),
+    "a <= b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_GT,
+                            "test_COMPARISON_GT_on_int"),
+    "a > b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_GE,
+                            "test_COMPARISON_GE_on_int"),
+    "a >= b");
 }
 
 static void
diff --git a/gcc/testsuite/jit.dg/test-quadratic.cc 
b/gcc/testsuite/jit.dg/test-quadratic.cc
index 0151926..52ae92e 100644
--- a/gcc/testsuite/jit.dg/test-quadratic.cc
+++ b/gcc/testsuite/jit.dg/test-quadratic.cc
@@ -4,6 +4,8 @@
 
 #include "libgccjit++.h"
 
+#include <sstream>
+
 #include "harness.h"
 
 struct quadratic
@@ -98,6 +100,8 @@ make_types (quadratic_test &testcase)
   testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
   testcase.discriminant =
     testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+  CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
+                      "discriminant");
   std::vector<gccjit::field> fields (4);
   fields[0] = testcase.a;
   fields[1] = testcase.b;
@@ -227,6 +231,8 @@ make_test_quadratic (quadratic_test &testcase)
 
   gccjit::label on_negative_discriminant
     = test_quadratic.new_forward_label ("negative_discriminant");
+  CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
+                      "zero_discriminant");
 
   test_quadratic.add_comment ("if (q.discriminant > 0)");
   test_quadratic.add_conditional (
@@ -258,6 +264,8 @@ make_test_quadratic (quadratic_test &testcase)
       testcase.numeric_type,
       testcase.ctxt.new_rvalue (testcase.numeric_type, 2),
       a);
+  CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
+                      "(double)2 * a");
 
   test_quadratic.add_comment ("*r1 = (-b + s) / (2 * a);");
   test_quadratic.add_assignment (
@@ -326,6 +334,11 @@ make_test_quadratic (quadratic_test &testcase)
   /* else return 0; */
   test_quadratic.place_forward_label (on_negative_discriminant);
   test_quadratic.add_return (testcase.ctxt.zero (testcase.int_type));
+
+  /* Verify that output stream operator << works.  */
+  std::ostringstream os;
+  os << "streamed output: " << address_of_q;
+  CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
 }
 
 void
-- 
1.7.11.7

Reply via email to