[jit] Add support for unions

David Malcolm dmalcolm@redhat.com
Wed Jan 1 00:00:00 GMT 2014


Pushed to branch dmalcolm/jit:

This adds a new API entrypoint:

  gcc_jit_context_new_union_type

gcc/jit/
	* libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
	(gcc_jit_lvalue_access_field): Rename first param from "struct_"
	to "struct_or_union".
	(gcc_jit_rvalue_access_field): Likewise.

	* libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.

	* libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.

	* internal-api.h (gcc::jit::recording::compound_type): New class
	(gcc::jit::recording::union): New class.
	(gcc::jit::playback::struct_): Rename this class to...
	(gcc::jit::playback::compound_type): ...this.
	(gcc::jit::recording::context::new_union_type): New method.
	(gcc::jit::recording::context): Rename field "m_structs" to
	"m_compound_types", generalizing from a vec <struct_ *> to a
	vec<compound_type *>.
	(gcc::jit::recording::field): Update field m_container from
	struct * to container_type *.
	(gcc::jit::recording::field::get_container): Generalize from
	struct_ * to container_type *.
	(gcc::jit::recording::field::set_container): Likewise.
	(gcc::jit::recording::compound_type): New subclass of type, to
	be a superclass of existing class struct_ and new class union_.
	(gcc::jit::recording::struct_::get_name): Move to...
	(gcc::jit::recording::compound_type::get_name): ...here.
	(gcc::jit::recording::struct_::get_loc): Move to...
	(gcc::jit::recording::compound_type::get_loc): ...here.
	(gcc::jit::recording::struct_::set_fields): Move to...
	(gcc::jit::recording::compound_type::set_fields): ...here.
	(gcc::jit::recording::struct_::dereference): Move to...
	(gcc::jit::recording::compound_type::dereference): ...here.
	(gcc::jit::recording::struct_::is_int): Move to...
	(gcc::jit::recording::compound_type::is_int): ...here.
	(gcc::jit::recording::struct_::is_float): Move to...
	(gcc::jit::recording::compound_type::is_float): ...here.
	(gcc::jit::recording::struct_::is_bool): Move to...
	(gcc::jit::recording::compound_type::is_bool): ...here.
	(gcc::jit::recording::struct_::is_pointer): Move to...
	(gcc::jit::recording::compound_type::is_pointer): ...here.
	(gcc::jit::recording::struct_::is_array): Move to...
	(gcc::jit::recording::compound_type::is_array): ...here.
	(gcc::jit::recording::struct_::playback_struct): Move to...
	(gcc::jit::recording::compound_type::playback_compound_type):
	...here, renaming and updating return type.
	(gcc::jit::recording::struct_): Inherit from compound_type,
	rather than just type.
	(gcc::jit::recording::fields): Update to work on compound_type *
	rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
	(gcc::jit::recording::union): New subclass of compound_type.
	(gcc::jit::playback::context::new_struct_type): Generalize by
	renaming to...
	(gcc::jit::playback::context::new_compound_type): ...this, and
	and an "is_struct" bool param.
	(gcc::jit::playback::struct_): Generalize by renaming class to...
	(gcc::jit::playback::compound_type): ...this.

	* internal-api.c (gcc::jit::recording::context::context): Rename
	field "m_structs" to "m_compound_types".
	(gcc::jit::recording::context::new_struct_type): Likewise.
	(gcc::jit::recording::context::new_union_type): New method.
	(gcc::jit::recording::context::dump_to_file): Field "m_structs"
	is renamed "m_compound_types" and changes type from struct_ *
	to compound_type *.
	(gcc::jit::recording::compound_type::compound_type): New ctor,
	built from old body of gcc::jit::recording::struct_::struct_.
	(gcc::jit::recording::struct_::set_fields): Move class to...
	(gcc::jit::recording::compound_type::set_fields): ... here.
	(gcc::jit::recording::struct_::dereference): Move class to...
	(gcc::jit::recording::compound_type::dereference): ...here.
	(gcc::jit::recording::struct_::struct_): Reimplement by calling
	base class ctor.
	(gcc::jit::recording::struct_::replay_into): The playback hook
	is now "new_compound_type" and adds a bool, with true for
	"is_struct" (vs a union).
	(gcc::jit::recording::struct_::make_debug_string): "m_name" is
	now moved to base class and private, so use an accessor.
	(gcc::jit::recording::union_::union_): New function.
	(gcc::jit::recording::union_::replay_into): New function.
	(gcc::jit::recording::union_::make_debug_string): New function.
	(gcc::jit::recording::fields::fields): Update first param from
	struct_ * to compound_type *, and rename field "m_struct" to
	"m_struct_or_union".
	(gcc::jit::recording::fields::replay_into): "m_struct" is now
	"m_struct_or_union" and has a playback_compound_type rather
	than a playback_struct.
	(gcc::jit::recording::fields::write_to_dump): Update for
	renaming of m_struct to m_struct_or_union.
	(gcc::jit::playback::context::new_struct_type): Rename method
	to...
	(gcc::jit::playback::context::new_compound_type): this,
	generalizing so that it can make unions as well as structs; the
	underlying playback type is now called "compound_type".
	(gcc::jit::playback::struct_::set_fields): This method's class has
	changed name, so this is now...
	(gcc::jit::playback::compound_type::set_fields): ...this method.

	* TODO.rst: Unions are done.

gcc/testsuite/
	* jit.dg/test-accessing-union.c: New test case.
	* jit.dg/test-combination.c: Add test-accessing-union.c.
---
 gcc/jit/ChangeLog.jit                       | 101 +++++++++++++++++++++++++++
 gcc/jit/TODO.rst                            |   5 --
 gcc/jit/internal-api.c                      | 102 ++++++++++++++++++++--------
 gcc/jit/internal-api.h                      |  94 +++++++++++++++++--------
 gcc/jit/libgccjit.c                         |  30 ++++++++
 gcc/jit/libgccjit.h                         |  12 +++-
 gcc/jit/libgccjit.map                       |   1 +
 gcc/testsuite/ChangeLog.jit                 |   5 ++
 gcc/testsuite/jit.dg/test-accessing-union.c |  97 ++++++++++++++++++++++++++
 gcc/testsuite/jit.dg/test-combination.c     |   9 +++
 10 files changed, 391 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-accessing-union.c

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index f7fd642..cb4ee60 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,106 @@
 2014-08-08  David Malcolm  <dmalcolm@redhat.com>
 
+	* libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
+	(gcc_jit_lvalue_access_field): Rename first param from "struct_"
+	to "struct_or_union".
+	(gcc_jit_rvalue_access_field): Likewise.
+
+	* libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.
+
+	* libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.
+
+	* internal-api.h (gcc::jit::recording::compound_type): New class
+	(gcc::jit::recording::union): New class.
+	(gcc::jit::playback::struct_): Rename this class to...
+	(gcc::jit::playback::compound_type): ...this.
+	(gcc::jit::recording::context::new_union_type): New method.
+	(gcc::jit::recording::context): Rename field "m_structs" to
+	"m_compound_types", generalizing from a vec <struct_ *> to a
+	vec<compound_type *>.
+	(gcc::jit::recording::field): Update field m_container from
+	struct * to container_type *.
+	(gcc::jit::recording::field::get_container): Generalize from
+	struct_ * to container_type *.
+	(gcc::jit::recording::field::set_container): Likewise.
+	(gcc::jit::recording::compound_type): New subclass of type, to
+	be a superclass of existing class struct_ and new class union_.
+	(gcc::jit::recording::struct_::get_name): Move to...
+	(gcc::jit::recording::compound_type::get_name): ...here.
+	(gcc::jit::recording::struct_::get_loc): Move to...
+	(gcc::jit::recording::compound_type::get_loc): ...here.
+	(gcc::jit::recording::struct_::set_fields): Move to...
+	(gcc::jit::recording::compound_type::set_fields): ...here.
+	(gcc::jit::recording::struct_::dereference): Move to...
+	(gcc::jit::recording::compound_type::dereference): ...here.
+	(gcc::jit::recording::struct_::is_int): Move to...
+	(gcc::jit::recording::compound_type::is_int): ...here.
+	(gcc::jit::recording::struct_::is_float): Move to...
+	(gcc::jit::recording::compound_type::is_float): ...here.
+	(gcc::jit::recording::struct_::is_bool): Move to...
+	(gcc::jit::recording::compound_type::is_bool): ...here.
+	(gcc::jit::recording::struct_::is_pointer): Move to...
+	(gcc::jit::recording::compound_type::is_pointer): ...here.
+	(gcc::jit::recording::struct_::is_array): Move to...
+	(gcc::jit::recording::compound_type::is_array): ...here.
+	(gcc::jit::recording::struct_::playback_struct): Move to...
+	(gcc::jit::recording::compound_type::playback_compound_type):
+	...here, renaming and updating return type.
+	(gcc::jit::recording::struct_): Inherit from compound_type,
+	rather than just type.
+	(gcc::jit::recording::fields): Update to work on compound_type *
+	rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
+	(gcc::jit::recording::union): New subclass of compound_type.
+	(gcc::jit::playback::context::new_struct_type): Generalize by
+	renaming to...
+	(gcc::jit::playback::context::new_compound_type): ...this, and
+	and an "is_struct" bool param.
+	(gcc::jit::playback::struct_): Generalize by renaming class to...
+	(gcc::jit::playback::compound_type): ...this.
+
+	* internal-api.c (gcc::jit::recording::context::context): Rename
+	field "m_structs" to "m_compound_types".
+	(gcc::jit::recording::context::new_struct_type): Likewise.
+	(gcc::jit::recording::context::new_union_type): New method.
+	(gcc::jit::recording::context::dump_to_file): Field "m_structs"
+	is renamed "m_compound_types" and changes type from struct_ *
+	to compound_type *.
+	(gcc::jit::recording::compound_type::compound_type): New ctor,
+	built from old body of gcc::jit::recording::struct_::struct_.
+	(gcc::jit::recording::struct_::set_fields): Move class to...
+	(gcc::jit::recording::compound_type::set_fields): ... here.
+	(gcc::jit::recording::struct_::dereference): Move class to...
+	(gcc::jit::recording::compound_type::dereference): ...here.
+	(gcc::jit::recording::struct_::struct_): Reimplement by calling
+	base class ctor.
+	(gcc::jit::recording::struct_::replay_into): The playback hook
+	is now "new_compound_type" and adds a bool, with true for
+	"is_struct" (vs a union).
+	(gcc::jit::recording::struct_::make_debug_string): "m_name" is
+	now moved to base class and private, so use an accessor.
+	(gcc::jit::recording::union_::union_): New function.
+	(gcc::jit::recording::union_::replay_into): New function.
+	(gcc::jit::recording::union_::make_debug_string): New function.
+	(gcc::jit::recording::fields::fields): Update first param from
+	struct_ * to compound_type *, and rename field "m_struct" to
+	"m_struct_or_union".
+	(gcc::jit::recording::fields::replay_into): "m_struct" is now
+	"m_struct_or_union" and has a playback_compound_type rather
+	than a playback_struct.
+	(gcc::jit::recording::fields::write_to_dump): Update for
+	renaming of m_struct to m_struct_or_union.
+	(gcc::jit::playback::context::new_struct_type): Rename method
+	to...
+	(gcc::jit::playback::context::new_compound_type): this,
+	generalizing so that it can make unions as well as structs; the
+	underlying playback type is now called "compound_type".
+	(gcc::jit::playback::struct_::set_fields): This method's class has
+	changed name, so this is now...
+	(gcc::jit::playback::compound_type::set_fields): ...this method.
+
+	* TODO.rst: Unions are done.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
 	* TODO.rst: Function ptrs are done.
 	* internal-api.c
 	(gcc::jit::recording::context::new_function_ptr_type): New method.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index d832337..fd7b07c 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -13,11 +13,6 @@ Initial Release
 * enums and ABI: give enums specific numbers, in ranges, to make it
   possible to maintain a logical ordering whilst preserving ABI.
 
-* more language features:
-
-  * more types:
-    * unions
-
 * expose the statements in the API? (mostly so they can be stringified?)
 
 * support more arithmetic ops and comparison modes
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index cacb526..bc353be 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -134,7 +134,7 @@ recording::context::context (context *parent_ctxt)
   : m_parent_ctxt (parent_ctxt),
     m_error_count (0),
     m_mementos (),
-    m_structs (),
+    m_compound_types (),
     m_functions (),
     m_FILE_type (NULL),
     m_builtins_manager(NULL)
@@ -377,7 +377,17 @@ recording::context::new_struct_type (recording::location *loc,
 {
   recording::struct_ *result = new struct_ (this, loc, new_string (name));
   record (result);
-  m_structs.safe_push (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+				    const char *name)
+{
+  recording::union_ *result = new union_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
   return result;
 }
 
@@ -695,15 +705,15 @@ recording::context::dump_to_file (const char *path, bool update_locations)
   int i;
   dump d (*this, path, update_locations);
 
-  /* Forward declaration of structs.  */
-  struct_ *st;
-  FOR_EACH_VEC_ELT (m_structs, i, st)
+  /* Forward declaration of structs and unions.  */
+  compound_type *st;
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
     {
       d.write ("%s;\n\n", st->get_debug_string ());
     }
 
   /* Content of structs, where set.  */
-  FOR_EACH_VEC_ELT (m_structs, i, st)
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
     if (st->get_fields ())
       {
 	st->get_fields ()->write_to_dump (d);
@@ -1294,10 +1304,10 @@ recording::field::make_debug_string ()
   return m_name;
 }
 
-/* gcc::jit::recording::struct_:: */
-recording::struct_::struct_ (context *ctxt,
-			     location *loc,
-			     string *name)
+/* gcc::jit::recording::compound_type */
+recording::compound_type::compound_type (context *ctxt,
+					 location *loc,
+					 string *name)
 : type (ctxt),
   m_loc (loc),
   m_name (name),
@@ -1306,9 +1316,9 @@ recording::struct_::struct_ (context *ctxt,
 }
 
 void
-recording::struct_::set_fields (location *loc,
-				int num_fields,
-				field **field_array)
+recording::compound_type::set_fields (location *loc,
+				      int num_fields,
+				      field **field_array)
 {
   m_loc = loc;
   gcc_assert (NULL == m_fields);
@@ -1318,38 +1328,71 @@ recording::struct_::set_fields (location *loc,
 }
 
 recording::type *
-recording::struct_::dereference ()
+recording::compound_type::dereference ()
 {
   return NULL; /* not a pointer */
 }
 
+/* gcc::jit::recording::struct_:: */
+recording::struct_::struct_ (context *ctxt,
+			     location *loc,
+			     string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
 void
 recording::struct_::replay_into (replayer *r)
 {
   set_playback_obj (
-    r->new_struct_type (playback_location (r, m_loc),
-			m_name->c_str ()));
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  true /* is_struct */));
 }
 
 recording::string *
 recording::struct_::make_debug_string ()
 {
   return string::from_printf (m_ctxt,
-			      "struct %s", m_name->c_str ());
+			      "struct %s", get_name ()->c_str ());
+}
+
+/* gcc::jit::recording::union_:: */
+recording::union_::union_ (context *ctxt,
+			   location *loc,
+			   string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+void
+recording::union_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  false /* is_struct */));
+}
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "union %s", get_name ()->c_str ());
 }
 
 /* gcc::jit::recording::fields:: */
-recording::fields::fields (struct_ *struct_,
+recording::fields::fields (compound_type *struct_or_union,
 			   int num_fields,
 			   field **fields)
-: memento (struct_->m_ctxt),
-  m_struct (struct_),
+: memento (struct_or_union->m_ctxt),
+  m_struct_or_union (struct_or_union),
   m_fields ()
 {
   for (int i = 0; i < num_fields; i++)
     {
       gcc_assert (fields[i]->get_container () == NULL);
-      fields[i]->set_container (m_struct);
+      fields[i]->set_container (m_struct_or_union);
       m_fields.safe_push (fields[i]);
     }
 }
@@ -1361,7 +1404,7 @@ recording::fields::replay_into (replayer *)
   playback_fields.create (m_fields.length ());
   for (unsigned i = 0; i < m_fields.length (); i++)
     playback_fields.safe_push (m_fields[i]->playback_field ());
-  m_struct->playback_struct ()->set_fields (playback_fields);
+  m_struct_or_union->playback_compound_type ()->set_fields (playback_fields);
 }
 
 void
@@ -1370,7 +1413,7 @@ recording::fields::write_to_dump (dump &d)
   int i;
   field *f;
 
-  d.write ("%s\n{\n", m_struct->get_debug_string ());
+  d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
   FOR_EACH_VEC_ELT (m_fields, i, f)
     f->write_to_dump (d);
   d.write ("};\n");
@@ -2685,27 +2728,28 @@ new_field (location *loc,
   return new field (decl);
 }
 
-playback::struct_ *
+playback::compound_type *
 playback::context::
-new_struct_type (location *loc,
-		 const char *name)
+new_compound_type (location *loc,
+		   const char *name,
+		   bool is_struct) /* else is union */
 {
   gcc_assert (name);
 
   /* Compare with c/c-decl.c: start_struct. */
 
-  tree t = make_node (RECORD_TYPE);
+  tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
   TYPE_NAME (t) = get_identifier (name);
   TYPE_SIZE (t) = 0;
 
   if (loc)
     set_tree_location (t, loc);
 
-  return new struct_ (t);
+  return new compound_type (t);
 }
 
 void
-playback::struct_::set_fields (const vec<playback::field *> &fields)
+playback::compound_type::set_fields (const vec<playback::field *> &fields)
 {
   /* Compare with c/c-decl.c: finish_struct. */
   tree t = as_tree ();
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index c4fe2f3..274b6ca 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -85,7 +85,9 @@ namespace recording {
   class type;
   class function_type;
   class field;
+  class compound_type;
   class struct_;
+  class union_;
   class fields;
   class function;
   class block;
@@ -101,7 +103,7 @@ namespace playback {
   class location;
   class type;
   class field;
-  class struct_;
+  class compound_type;
   class function;
   class block;
   class rvalue;
@@ -192,6 +194,10 @@ public:
   new_struct_type (location *loc,
 		   const char *name);
 
+  union_ *
+  new_union_type (location *loc,
+		  const char *name);
+
   type *
   new_function_ptr_type (location *loc,
 			 type *return_type,
@@ -347,7 +353,7 @@ private:
   vec<memento *> m_mementos;
 
   /* Specific recordings, for use by dump_to_file.  */
-  vec<struct_ *> m_structs;
+  vec<compound_type *> m_compound_types;
   vec<function *> m_functions;
 
   type *m_basic_types[NUM_GCC_JIT_TYPES];
@@ -748,8 +754,8 @@ public:
 
   type * get_type () const { return m_type; }
 
-  struct_ * get_container () const { return m_container; }
-  void set_container (struct_ *c) { m_container = c; }
+  compound_type * get_container () const { return m_container; }
+  void set_container (compound_type *c) { m_container = c; }
 
   void replay_into (replayer *);
 
@@ -768,22 +774,19 @@ private:
   location *m_loc;
   type *m_type;
   string *m_name;
-  struct_ *m_container;
+  compound_type *m_container;
 };
 
-class struct_ : public type
+/* Base class for struct_ and union_ */
+class compound_type : public type
 {
 public:
-  struct_ (context *ctxt,
-	   location *loc,
-	   string *name);
-
-  struct_ *dyn_cast_struct () { return this; }
-
-  type *
-  as_type () { return this; }
+  compound_type (context *ctxt,
+		 location *loc,
+		 string *name);
 
   string *get_name () const { return m_name; }
+  location *get_loc () const { return m_loc; }
   fields * get_fields () { return m_fields; }
 
   void
@@ -799,28 +802,42 @@ public:
   type *is_pointer () { return NULL; }
   type *is_array () { return NULL; }
 
-  void replay_into (replayer *r);
-
-  playback::struct_ *
-  playback_struct ()
+  playback::compound_type *
+  playback_compound_type ()
   {
-    return static_cast <playback::struct_ *> (m_playback_obj);
+    return static_cast <playback::compound_type *> (m_playback_obj);
   }
 
 private:
-  string * make_debug_string ();
-
-private:
   location *m_loc;
   string *m_name;
   fields *m_fields;
 };
 
+class struct_ : public compound_type
+{
+public:
+  struct_ (context *ctxt,
+	   location *loc,
+	   string *name);
+
+  struct_ *dyn_cast_struct () { return this; }
+
+  type *
+  as_type () { return this; }
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+};
+
 // memento of struct_::set_fields
 class fields : public memento
 {
 public:
-  fields (struct_ *struct_,
+  fields (compound_type *struct_or_union,
 	  int num_fields,
 	  field **fields);
 
@@ -832,10 +849,28 @@ private:
   string * make_debug_string ();
 
 private:
-  struct_ *m_struct;
+  compound_type *m_struct_or_union;
   vec<field *> m_fields;
 };
 
+class union_ : public compound_type
+{
+public:
+  union_ (context *ctxt,
+	  location *loc,
+	  string *name);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
 class rvalue : public memento
 {
 public:
@@ -1674,9 +1709,10 @@ public:
 	     type *type,
 	     const char *name);
 
-  struct_ *
-  new_struct_type (location *loc,
-		   const char *name);
+  compound_type *
+  new_compound_type (location *loc,
+		     const char *name,
+		     bool is_struct); /* else is union */
 
   type *
   new_function_type (type *return_type,
@@ -1899,10 +1935,10 @@ private:
   tree m_inner;
 };
 
-class struct_ : public type
+class compound_type : public type
 {
 public:
-  struct_ (tree inner)
+  compound_type (tree inner)
     : type (inner)
   {}
 
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 28deb7d..9550d8f 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -462,6 +462,36 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
 }
 
 gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				const char *name,
+				int num_fields,
+				gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	NULL == fields[i]->get_container (),
+	ctxt, loc,
+	"%s is already a field of %s",
+	fields[i]->get_debug_string (),
+	fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::union_ *result =
+    ctxt->new_union_type (loc, name);
+  result->set_fields (loc,
+		      num_fields,
+		      (gcc::jit::recording::field **)fields);
+  return (gcc_jit_type *) (result);
+}
+
+gcc_jit_type *
 gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
 				       gcc_jit_location *loc,
 				       gcc_jit_type *return_type,
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a7e437ed..29d3389 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -436,6 +436,14 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
 			   int num_fields,
 			   gcc_jit_field **fields);
 
+/* Unions work similarly to structs.  */
+extern gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				const char *name,
+				int num_fields,
+				gcc_jit_field **fields);
+
 /* Function pointers. */
 
 extern gcc_jit_type *
@@ -753,7 +761,7 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
       (EXPR).field = ...;
    in C.  */
 extern gcc_jit_lvalue *
-gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
 			     gcc_jit_location *loc,
 			     gcc_jit_field *field);
 
@@ -761,7 +769,7 @@ gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
       (EXPR).field
    in C.  */
 extern gcc_jit_rvalue *
-gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
 			     gcc_jit_location *loc,
 			     gcc_jit_field *field);
 
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index d7f5d7c..768e010 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -40,6 +40,7 @@
     gcc_jit_context_new_string_literal;
     gcc_jit_context_new_struct_type;
     gcc_jit_context_new_unary_op;
+    gcc_jit_context_new_union_type;
     gcc_jit_context_null;
     gcc_jit_context_one;
     gcc_jit_context_release;
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 0842a1b..cdde662 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,5 +1,10 @@
 2014-08-08  David Malcolm  <dmalcolm@redhat.com>
 
+	* jit.dg/test-accessing-union.c: New test case.
+	* jit.dg/test-combination.c: Add test-accessing-union.c.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
 	* jit.dg/test-combination.c (create_code): Add missing calls to
 	create_code_quadratic and create_code_reading_struct.
 	(verify_code): Add missing calls to verify_code_quadratic and
diff --git a/gcc/testsuite/jit.dg/test-accessing-union.c b/gcc/testsuite/jit.dg/test-accessing-union.c
new file mode 100644
index 0000000..658d1bc
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-accessing-union.c
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+union int_or_float
+{
+  int as_int;
+  float as_float;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     float
+     test_union (int i)
+     {
+        union int_or_float u;
+	u.as_int = i;
+	return u.as_float;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+  gcc_jit_field *as_int =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "as_int");
+  gcc_jit_field *as_float =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               float_type,
+                               "as_float");
+  gcc_jit_field *fields[] = {as_int, as_float};
+  gcc_jit_type *union_type =
+    gcc_jit_context_new_union_type (ctxt, NULL,
+				    "int_or_float", 2, fields);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  float_type,
+                                  "test_union",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_lvalue *u =
+    gcc_jit_function_new_local (test_fn, NULL,
+				union_type, "u");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* u.as_int = i; */
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    /* "u.as_int = ..." */
+    gcc_jit_lvalue_access_field (u,
+				 NULL,
+				 as_int),
+    gcc_jit_param_as_rvalue (param_i));
+
+  /* return u.as_float; */
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
+				 NULL,
+				 as_float));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef float (*fn_type) (int i);
+  CHECK_NON_NULL (result);
+
+  fn_type test_union =
+    (fn_type)gcc_jit_result_get_code (result, "test_union");
+  CHECK_NON_NULL (test_union);
+
+  /* Call the JIT-generated function.  */
+  float f_result = test_union (42);
+
+  union int_or_float u;
+  u.as_float = f_result;
+
+  CHECK_VALUE (u.as_int, 42);
+}
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index a8bf3bc..a3e3102 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -14,6 +14,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-accessing-union.c */
+#define create_code create_code_accessing_union
+#define verify_code verify_code_accessing_union
+#include "test-accessing-union.c"
+#undef create_code
+#undef verify_code
+
 /* test-array-as-pointer.c */
 #define create_code create_code_array_as_pointer
 #define verify_code verify_code_array_as_pointer
@@ -155,6 +162,7 @@ void
 create_code (gcc_jit_context *ctxt, void * user_data)
 {
   create_code_accessing_struct (ctxt, user_data);
+  create_code_accessing_union (ctxt, user_data);
   create_code_array_as_pointer (ctxt, user_data);
   create_code_arrays (ctxt, user_data);
   create_code_calling_external_function (ctxt, user_data);
@@ -179,6 +187,7 @@ void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
 {
   verify_code_accessing_struct (ctxt, result);
+  verify_code_accessing_union (ctxt, result);
   verify_code_array_as_pointer (ctxt, result);
   verify_code_arrays (ctxt, result);
   verify_code_calling_external_function (ctxt, result);
-- 
1.8.5.3



More information about the Jit mailing list