public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
From: David Malcolm <dmalcolm@redhat.com>
To: "Basile Starynkevitch" <basile@starynkevitch.net>,
	"Marc Nieper-Wißkirchen" <marc@nieper-wisskirchen.de>,
	jit@gcc.gnu.org
Cc: David Malcolm <dmalcolm@redhat.com>
Subject: [PATCH 3/6] FIXME: WIP on jit part of must-tail-call
Date: Fri, 01 Jan 2016 00:00:00 -0000	[thread overview]
Message-ID: <1463170721-13825-3-git-send-email-dmalcolm@redhat.com> (raw)
In-Reply-To: <1463170721-13825-1-git-send-email-dmalcolm@redhat.com>

This implements (most of) the libgccjit support for must-tail-call.

DONE:
  - C API
  - test coverage:
    - gcc/testsuite/jit.dg/all-non-failing-tests.h

TODO:
  - ChangeLog
  - blurb
  - C++ bindings support
  - test coverage:
    - example of failing TCO (implemented in a later patch)
  - feature macro in libgccjit.h
  - support for gcc_jit_context_dump_reproducer_to_file()
  - documentation for the new C entrypoints
  - documentation for the new C++ entrypoints
  - documentation for the new ABI tag (see topics/compatibility.rst).
  - regenerated texinfo
---
 gcc/jit/jit-common.h                               |   1 +
 gcc/jit/jit-playback.c                             |  23 +++--
 gcc/jit/jit-playback.h                             |   9 +-
 gcc/jit/jit-recording.c                            |  42 +++++---
 gcc/jit/jit-recording.h                            |  43 +++++---
 gcc/jit/libgccjit.c                                |  18 ++++
 gcc/jit/libgccjit.h                                |   5 +
 gcc/jit/libgccjit.map                              |   5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h       |   7 ++
 .../jit.dg/test-factorial-must-tail-call.c         | 109 +++++++++++++++++++++
 10 files changed, 224 insertions(+), 38 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-factorial-must-tail-call.c

diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 8a6cd74..b48ea0d 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -126,6 +126,7 @@ namespace recording {
         class local;
 	class global;
         class param;
+      class base_call;
     class statement;
     class case_;
 
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 579230d..0d51a97 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -853,7 +853,8 @@ playback::rvalue *
 playback::context::
 build_call (location *loc,
 	    tree fn_ptr,
-	    const auto_vec<rvalue *> *args)
+	    const auto_vec<rvalue *> *args,
+	    bool require_tail_call)
 {
   vec<tree, va_gc> *tree_args;
   vec_alloc (tree_args, args->length ());
@@ -867,9 +868,13 @@ build_call (location *loc,
   tree fn_type = TREE_TYPE (fn);
   tree return_type = TREE_TYPE (fn_type);
 
-  return new rvalue (this,
-		     build_call_vec (return_type,
-				     fn_ptr, tree_args));
+  tree call = build_call_vec (return_type,
+			      fn_ptr, tree_args);
+
+  if (require_tail_call)
+    CALL_EXPR_MUST_TAIL_CALL (call) = 1;
+
+  return new rvalue (this, call);
 
   /* see c-typeck.c: build_function_call
      which calls build_function_call_vec
@@ -889,7 +894,8 @@ playback::rvalue *
 playback::context::
 new_call (location *loc,
 	  function *func,
-	  const auto_vec<rvalue *> *args)
+	  const auto_vec<rvalue *> *args,
+	  bool require_tail_call)
 {
   tree fndecl;
 
@@ -901,7 +907,7 @@ new_call (location *loc,
 
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
 
-  return build_call (loc, fn, args);
+  return build_call (loc, fn, args, require_tail_call);
 }
 
 /* Construct a playback::rvalue instance (wrapping a tree) for a
@@ -911,12 +917,13 @@ playback::rvalue *
 playback::context::
 new_call_through_ptr (location *loc,
 		      rvalue *fn_ptr,
-		      const auto_vec<rvalue *> *args)
+		      const auto_vec<rvalue *> *args,
+		      bool require_tail_call)
 {
   gcc_assert (fn_ptr);
   tree t_fn_ptr = fn_ptr->as_tree ();
 
-  return build_call (loc, t_fn_ptr, args);
+  return build_call (loc, t_fn_ptr, args, require_tail_call);
 }
 
 /* Construct a tree for a cast.  */
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 905747c..669f3b8 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -130,12 +130,14 @@ public:
   rvalue *
   new_call (location *loc,
 	    function *func,
-	    const auto_vec<rvalue *> *args);
+	    const auto_vec<rvalue *> *args,
+	    bool require_tail_call);
 
   rvalue *
   new_call_through_ptr (location *loc,
 			rvalue *fn_ptr,
-			const auto_vec<rvalue *> *args);
+			const auto_vec<rvalue *> *args,
+			bool require_tail_call);
 
   rvalue *
   new_cast (location *loc,
@@ -229,7 +231,8 @@ private:
   rvalue *
   build_call (location *loc,
 	      tree fn_ptr,
-	      const auto_vec<rvalue *> *args);
+	      const auto_vec<rvalue *> *args,
+	      bool require_tail_call);
 
   tree
   build_cast (location *loc,
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 8f5f914..e60c0a0 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -4681,6 +4681,23 @@ recording::cast::write_reproducer (reproducer &r)
 	   r.get_identifier_as_type (get_type ()));
 }
 
+/* The implementation of class gcc::jit::recording::base_call.  */
+
+/* The constructor for gcc::jit::recording::base_call.  */
+
+recording::base_call::base_call (context *ctxt,
+				 location *loc,
+				 type *type_,
+				 int numargs,
+				 rvalue **args)
+: rvalue (ctxt, loc, type_),
+  m_args (),
+  m_require_tail_call (0)
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
 /* The implementation of class gcc::jit::recording::call.  */
 
 /* The constructor for gcc::jit::recording::call.  */
@@ -4690,12 +4707,9 @@ recording::call::call (recording::context *ctxt,
 		       recording::function *func,
 		       int numargs,
 		       rvalue **args)
-: rvalue (ctxt, loc, func->get_return_type ()),
-  m_func (func),
-  m_args ()
+: base_call (ctxt, loc, func->get_return_type (), numargs, args),
+  m_func (func)
 {
-  for (int i = 0; i< numargs; i++)
-    m_args.safe_push (args[i]);
 }
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -4711,7 +4725,8 @@ recording::call::replay_into (replayer *r)
 
   set_playback_obj (r->new_call (playback_location (r, m_loc),
 				 m_func->playback_function (),
-				 &playback_args));
+				 &playback_args,
+				 m_require_tail_call));
 }
 
 /* Implementation of pure virtual hook recording::rvalue::visit_children
@@ -4801,14 +4816,12 @@ recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
 					       recording::rvalue *fn_ptr,
 					       int numargs,
 					       rvalue **args)
-: rvalue (ctxt, loc,
-	  fn_ptr->get_type ()->dereference ()
-	    ->as_a_function_type ()->get_return_type ()),
-  m_fn_ptr (fn_ptr),
-  m_args ()
+: base_call (ctxt, loc,
+	     fn_ptr->get_type ()->dereference ()
+	       ->as_a_function_type ()->get_return_type (),
+	     numargs, args),
+  m_fn_ptr (fn_ptr)
 {
-  for (int i = 0; i< numargs; i++)
-    m_args.safe_push (args[i]);
 }
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -4824,7 +4837,8 @@ recording::call_through_ptr::replay_into (replayer *r)
 
   set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
 					     m_fn_ptr->playback_rvalue (),
-					     &playback_args));
+					     &playback_args,
+					     m_require_tail_call));
 }
 
 /* Implementation of pure virtual hook recording::rvalue::visit_children
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 1c3e763..4b46a08 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -960,8 +960,9 @@ public:
   void set_scope (function *scope);
   function *get_scope () const { return m_scope; }
 
-  /* Dynamic cast.  */
+  /* Dynamic casts.  */
   virtual param *dyn_cast_param () { return NULL; }
+  virtual base_call *dyn_cast_base_call () { return NULL; }
 
   virtual const char *access_as_rvalue (reproducer &r);
 
@@ -1418,7 +1419,33 @@ private:
   rvalue *m_rvalue;
 };
 
-class call : public rvalue
+class base_call : public rvalue
+{
+ public:
+  base_call (context *ctxt,
+	     location *loc,
+	     type *type_,
+	     int numargs,
+	     rvalue **args);
+
+  enum precedence get_precedence () const FINAL OVERRIDE
+  {
+    return PRECEDENCE_POSTFIX;
+  }
+
+  base_call *dyn_cast_base_call () FINAL OVERRIDE { return this; }
+
+  void set_require_tail_call (bool require_tail_call)
+  {
+    m_require_tail_call = require_tail_call;
+  }
+
+ protected:
+  auto_vec<rvalue *> m_args;
+  bool m_require_tail_call;
+};
+
+class call : public base_call
 {
 public:
   call (context *ctxt,
@@ -1434,17 +1461,12 @@ public:
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
-  enum precedence get_precedence () const FINAL OVERRIDE
-  {
-    return PRECEDENCE_POSTFIX;
-  }
 
 private:
   function *m_func;
-  auto_vec<rvalue *> m_args;
 };
 
-class call_through_ptr : public rvalue
+class call_through_ptr : public base_call
 {
 public:
   call_through_ptr (context *ctxt,
@@ -1460,14 +1482,9 @@ public:
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
-  enum precedence get_precedence () const FINAL OVERRIDE
-  {
-    return PRECEDENCE_POSTFIX;
-  }
 
 private:
   rvalue *m_fn_ptr;
-  auto_vec<rvalue *> m_args;
 };
 
 class array_access : public lvalue
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 02ff50c..c577b3a 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2950,3 +2950,21 @@ gcc_jit_timer_print (gcc_jit_timer *timer,
   timer->start (TV_TOTAL);
   timer->push (TV_JIT_CLIENT_CODE);
 }
+
+/* FIXME.  */
+
+void
+gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *rvalue,
+					   int require_tail_call)
+{
+  RETURN_IF_FAIL (rvalue, NULL, NULL, "NULL call");
+  JIT_LOG_FUNC (rvalue->get_context ()->get_logger ());
+
+  /* Verify that it's a call.  */
+  gcc::jit::recording::base_call *call = rvalue->dyn_cast_base_call ();
+  RETURN_IF_FAIL_PRINTF1 (call, NULL, NULL, "not a call: %s",
+			  rvalue->get_debug_string ());
+
+  call->set_require_tail_call (require_tail_call);
+  // TODO: do something with the flag
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a8b9f55..c0ba4c1 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1374,6 +1374,11 @@ extern void
 gcc_jit_timer_print (gcc_jit_timer *timer,
 		     FILE *f_out);
 
+/* FIXME.  */
+extern void
+gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *call,
+					   int require_tail_call);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 65f3166..545b192 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -145,3 +145,8 @@ LIBGCCJIT_ABI_5 {
   global:
     gcc_jit_context_set_bool_use_external_driver;
 } LIBGCCJIT_ABI_4;
+
+LIBGCCJIT_ABI_6 {
+  global:
+    gcc_jit_rvalue_set_bool_require_tail_call;
+} LIBGCCJIT_ABI_5;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 463eefb..3fe5bc1 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -105,6 +105,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-factorial-must-tail-call.c */
+#define create_code create_code_factorial_must_tail_call
+#define verify_code verify_code_factorial_must_tail_call
+#include "test-factorial-must-tail-call.c"
+#undef create_code
+#undef verify_code
+
 /* test-fibonacci.c */
 #define create_code create_code_fibonacci
 #define verify_code verify_code_fibonacci
diff --git a/gcc/testsuite/jit.dg/test-factorial-must-tail-call.c b/gcc/testsuite/jit.dg/test-factorial-must-tail-call.c
new file mode 100644
index 0000000..c862611
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-factorial-must-tail-call.c
@@ -0,0 +1,109 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+      int
+      my_factorial_must_tail_call (int x)
+      {
+        if (x < 2)
+          return x;
+        else
+          return x * my_factorial_must_tail_call (x - 1);
+      }
+
+     and mark the call as requiring tail-call-optimization.
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "my_factorial_must_tail_call",
+				  1, params, 0);
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *on_true =
+    gcc_jit_function_new_block (func, "on_true");
+  gcc_jit_block *on_false =
+    gcc_jit_function_new_block (func, "on_false");
+
+ /* if (x < 2) */
+  gcc_jit_block_end_with_conditional (
+    initial, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	2)),
+    on_true,
+    on_false);
+
+  /* true branch: */
+  /* return x */
+  gcc_jit_block_end_with_return (
+    on_true,
+    NULL,
+    gcc_jit_param_as_rvalue (x));
+
+  /* false branch: */
+  gcc_jit_rvalue *x_minus_1 =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	1));
+  /* my_factorial_must_tail_call (x - 1) */
+  gcc_jit_rvalue *call =
+      gcc_jit_context_new_call (
+        ctxt, NULL,
+        func,
+        1, &x_minus_1);
+
+  /* Mark the call as requiring tail-call optimization.  */
+  gcc_jit_rvalue_set_bool_require_tail_call (call, 1);
+
+  gcc_jit_block_end_with_return (
+    on_false,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_param_as_rvalue (x),
+      call));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*my_factorial_fn_type) (int);
+  CHECK_NON_NULL (result);
+  my_factorial_fn_type my_factorial_must_tail_call =
+    (my_factorial_fn_type)gcc_jit_result_get_code (result, "my_factorial_must_tail_call");
+  CHECK_NON_NULL (my_factorial_must_tail_call);
+  int val = my_factorial_must_tail_call (10);
+  note ("my_factorial_must_tail_call returned: %d", val);
+  CHECK_VALUE (val, 3628800);
+}
+
-- 
1.8.5.3

  parent reply	other threads:[~2016-05-13 19:53 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-01  0:00 [PATCH 0/6] jit: Work-in-progress implementation " David Malcolm
2016-01-01  0:00 ` [PATCH 1/6] FIXME: introduce can_implement_as_sibling_call_p David Malcolm
2016-01-01  0:00   ` [PATCH 4/6] FIXME: non-working scanasm test David Malcolm
2016-01-01  0:00   ` David Malcolm [this message]
2016-01-01  0:00   ` [PATCH 5/6] FIXME: initial support for gcc diagnostics as jit errors David Malcolm
2016-01-01  0:00   ` [PATCH 2/6] FIXME: WIP on non-jit part of must-tail-call David Malcolm
2016-01-01  0:00   ` [PATCH 6/6] FIXME: jit: add test of failing must-TCO David Malcolm
2016-01-01  0:00 ` [PATCH 0/6] jit: Work-in-progress implementation of must-tail-call Marc Nieper-Wißkirchen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1463170721-13825-3-git-send-email-dmalcolm@redhat.com \
    --to=dmalcolm@redhat.com \
    --cc=basile@starynkevitch.net \
    --cc=jit@gcc.gnu.org \
    --cc=marc@nieper-wisskirchen.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).