diff mbox

[jit] New API entrypoint: gcc_jit_context_new_cast

Message ID 1393622965-25438-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Feb. 28, 2014, 9:29 p.m. UTC
Committed to branch dmalcolm/jit:

gcc/jit/
	* libgccjit.h (gcc_jit_context_new_cast): New.
	* libgccjit.map (gcc_jit_context_new_cast): New.
	* libgccjit++.h (gccjit::context::new_cast): New method.
	* libgccjit.c (gcc_jit_context_new_cast): New.

	* internal-api.h (gcc::jit::recording::context::new_cast): New method.
	(gcc::jit::recording::cast): New subclass of rvalue.
	(gcc::jit::playback::context::new_cast): New method.
	(gcc::jit::playback::context::build_cast): New method.

	* internal-api.c (convert): New.
	(gcc::jit::recording::context::new_cast): New.
	(gcc::jit::recording::cast::replay_into): New.
	(gcc::jit::recording::cast::make_debug_string): New.
	(gcc::jit::playback::context::build_cast): New.
	(gcc::jit::playback::context::new_cast): New.

	* TODO.rst: Update.

gcc/testsuite/
	* jit.dg/test-expressions.c (make_test_of_cast): New, to test new
	entrypoint gcc_jit_context_new_cast.
	(make_tests_of_casts): New.
	(create_code): Add call to make_tests_of_casts.
	(verify_code): Add call to verify_casts.
---
 gcc/jit/ChangeLog.jit                   |  21 ++++++
 gcc/jit/TODO.rst                        |   9 +--
 gcc/jit/internal-api.c                  | 102 ++++++++++++++++++++++++++
 gcc/jit/internal-api.h                  |  33 +++++++++
 gcc/jit/libgccjit++.h                   |  15 ++++
 gcc/jit/libgccjit.c                     |  13 ++++
 gcc/jit/libgccjit.h                     |  11 +++
 gcc/jit/libgccjit.map                   |   1 +
 gcc/testsuite/ChangeLog.jit             |   8 ++
 gcc/testsuite/jit.dg/test-expressions.c | 126 ++++++++++++++++++++++++++++++++
 10 files changed, 332 insertions(+), 7 deletions(-)
diff mbox

Patch

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 6c43ce9..625e01a 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,26 @@ 
 2014-02-28  David Malcolm  <dmalcolm@redhat.com>
 
+	* libgccjit.h (gcc_jit_context_new_cast): New.
+	* libgccjit.map (gcc_jit_context_new_cast): New.
+	* libgccjit++.h (gccjit::context::new_cast): New method.
+	* libgccjit.c (gcc_jit_context_new_cast): New.
+
+	* internal-api.h (gcc::jit::recording::context::new_cast): New method.
+	(gcc::jit::recording::cast): New subclass of rvalue.
+	(gcc::jit::playback::context::new_cast): New method.
+	(gcc::jit::playback::context::build_cast): New method.
+
+	* internal-api.c (convert): New.
+	(gcc::jit::recording::context::new_cast): New.
+	(gcc::jit::recording::cast::replay_into): New.
+	(gcc::jit::recording::cast::make_debug_string): New.
+	(gcc::jit::playback::context::build_cast): New.
+	(gcc::jit::playback::context::new_cast): New.
+
+	* TODO.rst: Update.
+
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
 	* libgccjit.h (gcc_jit_block_get_function): New.
 	* libgccjit.map (gcc_jit_block_get_function): New.
 	* libgccjit++.h (gccjit::block::get_function): New method.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index 227113a..8a2308e 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -23,13 +23,6 @@  Initial Release
 
 * expose the statements in the API? (mostly so they can be stringified?)
 
-* explicit casts::
-
-    extern gcc_jit_rvalue *
-    gcc_jit_rvalue_cast (gcc_jit_rvalue *, gcc_jit_type *);
-
-  e.g. (void*) to (struct foo*)
-
 * support more arithmetic ops and comparison modes
 
 * access to a function by address::
@@ -119,6 +112,8 @@  Initial Release
   have each block have its own stmt_list, avoiding the need for this
   traversal, and having the block structure show up within tree dumps.
 
+* Implement more kinds of casts e.g. pointers
+
 Bugs
 ====
 * INTERNAL functions don't seem to work (see e.g. test-quadratic, on trying
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index fa08e56..573dc67 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -16,12 +16,29 @@ 
 #include "diagnostic-core.h"
 #include "dumpfile.h"
 #include "tree-cfg.h"
+#include "target.h"
+#include "convert.h"
 
 #include <pthread.h>
 
 #include "internal-api.h"
 #include "jit-builtins.h"
 
+/* gcc::jit::playback::context::build_cast uses the convert.h API,
+   which in turn requires the frontend to provide a "convert"
+   function, apparently as a fallback.
+
+   Hence we provide this dummy one, with the requirement that any casts
+   are handled before reaching this.  */
+extern tree convert (tree type, tree expr);
+
+tree
+convert (tree /*type*/, tree /*expr*/)
+{
+  error ("unhandled conversion");
+  return error_mark_node;
+}
+
 namespace gcc {
 namespace jit {
 
@@ -474,6 +491,16 @@  recording::context::new_comparison (recording::location *loc,
 }
 
 recording::rvalue *
+recording::context::new_cast (recording::location *loc,
+			      recording::rvalue *expr,
+			      recording::type *type_)
+{
+  recording::rvalue *result = new cast (this, loc, expr, type_);
+  record (result);
+  return result;
+}
+
+recording::rvalue *
 recording::context::new_call (recording::location *loc,
 			      function *func,
 			      int numargs , recording::rvalue **args)
@@ -1685,6 +1712,23 @@  recording::comparison::replay_into (replayer *r)
 				       m_b->playback_rvalue ()));
 }
 
+void
+recording::cast::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_cast (playback_location (r, m_loc),
+				 m_rvalue->playback_rvalue (),
+				 get_type ()->playback_type ()));
+}
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%s",
+			      get_type ()->get_debug_string (),
+			      m_rvalue->get_debug_string ());
+}
+
 recording::call::call (recording::context *ctxt,
 		       recording::location *loc,
 		       recording::function *func,
@@ -2719,6 +2763,64 @@  new_call (location *loc,
    */
 }
 
+tree
+playback::context::build_cast (tree expr, tree dst_type)
+{
+  /* For comparison, see:
+     - c/c-typeck.c:build_c_cast
+     - c/c-convert.c: convert
+     - convert.h
+
+     Only some kinds of cast are currently supported here.  */
+  tree ret = NULL;
+  ret = targetm.convert_to_type (dst_type, expr);
+  if (ret)
+      return ret;
+  enum tree_code dst_code = TREE_CODE (dst_type);
+  switch (dst_code)
+    {
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      ret = convert_to_integer (dst_type, expr);
+      goto maybe_fold;
+
+    case BOOLEAN_TYPE:
+      /* Compare with c_objc_common_truthvalue_conversion and
+	 c_common_truthvalue_conversion. */
+      /* For now, convert to: (expr != 0)  */
+      ret = build2 (NE_EXPR, dst_type,
+		    expr, integer_zero_node);
+      goto maybe_fold;
+
+    case REAL_TYPE:
+      ret = convert_to_real (dst_type, expr);
+      goto maybe_fold;
+
+    default:
+      add_error ("can't handle cast");
+      return error_mark_node;
+
+    maybe_fold:
+      if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR)
+	ret = fold (ret);
+      return ret;
+    }
+}
+
+playback::rvalue *
+playback::context::
+new_cast (playback::location *loc,
+	  playback::rvalue *expr,
+	  playback::type *type_)
+{
+
+  tree t_cast = build_cast (expr->as_tree (),
+			    type_->as_tree ());
+  if (loc)
+    set_tree_location (t_cast, loc);
+  return new rvalue (this, t_cast);
+}
+
 playback::lvalue *
 playback::context::
 new_array_access (location *loc,
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index a37cafe..7114094a 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -252,6 +252,11 @@  public:
 	    function *func,
 	    int numargs, rvalue **args);
 
+  rvalue *
+  new_cast (location *loc,
+	    rvalue *expr,
+	    type *type_);
+
   lvalue *
   new_array_access (location *loc,
 		    rvalue *ptr,
@@ -1123,6 +1128,26 @@  private:
   rvalue *m_b;
 };
 
+class cast : public rvalue
+{
+public:
+  cast (context *ctxt,
+	location *loc,
+	rvalue *a,
+	type *type_)
+  : rvalue (ctxt, loc, type_),
+    m_rvalue (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
 class call : public rvalue
 {
 public:
@@ -1580,6 +1605,11 @@  public:
 	    function *func,
 	    vec<rvalue *> args);
 
+  rvalue *
+  new_cast (location *loc,
+	    rvalue *expr,
+	    type *type_);
+
   lvalue *
   new_array_access (location *loc,
 		    rvalue *ptr,
@@ -1651,6 +1681,9 @@  public:
 private:
   void dump_generated_code ();
 
+  tree
+  build_cast (tree expr, tree dst_type);
+
   source_file *
   get_source_file (const char *filename);
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 7c1c3be..b77e82f 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -239,6 +239,10 @@  namespace gccjit
 		     rvalue arg3, rvalue arg4, rvalue arg5,
 		     location loc = location ());
 
+    rvalue new_cast (rvalue expr,
+		     type type_,
+		     location loc = location ());
+
     lvalue new_array_access (rvalue ptr,
 			     rvalue index,
 			     location loc = location ());
@@ -956,6 +960,17 @@  context::new_call (function func,
   return new_call (func, args, loc);
 }
 
+inline rvalue
+context::new_cast (rvalue expr,
+		   type type_,
+		   location loc)
+{
+  return rvalue (gcc_jit_context_new_cast (m_inner_ctxt,
+					   loc.get_inner_location (),
+					   expr.get_inner_rvalue (),
+					   type_.get_inner_type ()));
+}
+
 inline lvalue
 context::new_array_access (rvalue ptr,
 			   rvalue index,
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index ce7987c..6c078ce 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -835,6 +835,19 @@  gcc_jit_context_new_call (gcc_jit_context *ctxt,
 					   (gcc::jit::recording::rvalue **)args);
 }
 
+gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_rvalue *rvalue,
+			  gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, "NULL rvalue");
+  RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
+
+  return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
+}
+
 extern gcc_jit_lvalue *
 gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
 				  gcc_jit_location *loc,
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index f00d672..c97cb75 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -691,6 +691,17 @@  gcc_jit_context_new_call (gcc_jit_context *ctxt,
 			  gcc_jit_function *func,
 			  int numargs , gcc_jit_rvalue **args);
 
+/* Type-coercion.
+
+   Currently only a limited set of conversions are possible:
+     int <-> float
+     int <-> bool  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_rvalue *rvalue,
+			  gcc_jit_type *type);
+
 extern gcc_jit_lvalue *
 gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
 				  gcc_jit_location *loc,
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 9f6a466..c8ad1a4 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -23,6 +23,7 @@ 
     gcc_jit_context_new_array_type;
     gcc_jit_context_new_binary_op;
     gcc_jit_context_new_call;
+    gcc_jit_context_new_cast;
     gcc_jit_context_new_child_context;
     gcc_jit_context_new_comparison;
     gcc_jit_context_new_field;
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index ea8566c..d3ca998 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,11 @@ 
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
+	* jit.dg/test-expressions.c (make_test_of_cast): New, to test new
+	entrypoint gcc_jit_context_new_cast.
+	(make_tests_of_casts): New.
+	(create_code): Add call to make_tests_of_casts.
+	(verify_code): Add call to verify_casts.
+
 2014-02-27  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/test-accessing-struct.c (create_code): Port to
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
index e339d8a..07fe9d6 100644
--- a/gcc/testsuite/jit.dg/test-expressions.c
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -454,6 +454,130 @@  verify_comparisons (gcc_jit_result *result)
 }
 
 /**********************************************************************
+ Casts
+ **********************************************************************/
+
+static const char*
+make_test_of_cast (gcc_jit_context *ctxt,
+		   gcc_jit_type *input_type,
+		   gcc_jit_type *output_type,
+		   const char *funcname)
+{
+  /* Make a test function of the form:
+       OUTPUT_TYPE test_cast_* (INPUT_TYPE a)
+       {
+          return (OUTPUT_TYPE)a;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, input_type, "a");
+  gcc_jit_param *params[] = {param_a};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  output_type,
+				  funcname,
+				  1, params,
+				  0);
+  gcc_jit_rvalue *cast =
+    gcc_jit_context_new_cast (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_a),
+      output_type);
+  gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, cast);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (cast));
+}
+
+static void
+make_tests_of_casts (gcc_jit_context *ctxt)
+{
+  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_type *bool_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+
+  /* float/int conversions */
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+		       float_type,
+		       int_type,
+		       "test_cast_from_float_to_int"),
+    "(int)a");
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+		       int_type,
+		       float_type,
+		       "test_cast_from_int_to_float"),
+    "(float)a");
+
+  /* bool/int conversions */
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+		       bool_type,
+		       int_type,
+		       "test_cast_from_bool_to_int"),
+    "(int)a");
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+		       int_type,
+		       bool_type,
+		       "test_cast_from_int_to_bool"),
+    "(bool)a");
+}
+
+static void
+verify_casts (gcc_jit_result *result)
+{
+  /* float to int */
+  {
+    typedef int (*fn_type) (float);
+    fn_type test_cast_from_float_to_int =
+      (fn_type)gcc_jit_result_get_code (result,
+					"test_cast_from_float_to_int");
+    CHECK_NON_NULL (test_cast_from_float_to_int);
+    CHECK_VALUE (test_cast_from_float_to_int (4.2), 4);
+  }
+
+  /* int to float */
+  {
+    typedef float (*fn_type) (int);
+    fn_type test_cast_from_int_to_float =
+      (fn_type)gcc_jit_result_get_code (result,
+					"test_cast_from_int_to_float");
+    CHECK_NON_NULL (test_cast_from_int_to_float);
+    CHECK_VALUE (test_cast_from_int_to_float (4), 4.0);
+  }
+
+  /* bool to int */
+  {
+    typedef int (*fn_type) (bool);
+    fn_type test_cast_from_bool_to_int =
+      (fn_type)gcc_jit_result_get_code (result,
+					"test_cast_from_bool_to_int");
+    CHECK_NON_NULL (test_cast_from_bool_to_int);
+    CHECK_VALUE (test_cast_from_bool_to_int (0), 0);
+    CHECK_VALUE (test_cast_from_bool_to_int (1), 1);
+  }
+
+  /* int to bool */
+  {
+    typedef bool (*fn_type) (int);
+    fn_type test_cast_from_int_to_bool =
+      (fn_type)gcc_jit_result_get_code (result,
+					"test_cast_from_int_to_bool");
+    CHECK_NON_NULL (test_cast_from_int_to_bool);
+    CHECK_VALUE (test_cast_from_int_to_bool (0), 0);
+    CHECK_VALUE (test_cast_from_int_to_bool (1), 1);
+  }
+}
+
+/**********************************************************************
  Dereferences
  **********************************************************************/
 
@@ -617,6 +741,7 @@  create_code (gcc_jit_context *ctxt, void *user_data)
   make_tests_of_unary_ops (ctxt);
   make_tests_of_binary_ops (ctxt);
   make_tests_of_comparisons (ctxt);
+  make_tests_of_casts (ctxt);
   make_tests_of_dereferences (ctxt);
   make_test_of_get_address (ctxt);
 }
@@ -629,6 +754,7 @@  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
   verify_unary_ops (result);
   verify_binary_ops (result);
   verify_comparisons (result);
+  verify_casts (result);
   verify_dereferences (result);
   verify_get_address (result);
 }