aboutsummaryrefslogtreecommitdiff
path: root/gcc/jit
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2016-05-20 19:12:49 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2016-05-20 19:12:49 +0000
commit15c671a79ca66df5b1de70dd1a0b78414fe003ef (patch)
treef210624d9cf8816cc56a0800f0429cd6e558a371 /gcc/jit
parentdfbdde160f9970aea0bfc6c9d2005d911de6b593 (diff)
downloadgcc-15c671a79ca66df5b1de70dd1a0b78414fe003ef.zip
gcc-15c671a79ca66df5b1de70dd1a0b78414fe003ef.tar.gz
gcc-15c671a79ca66df5b1de70dd1a0b78414fe003ef.tar.bz2
jit: implement gcc_jit_rvalue_set_bool_require_tail_call
This implements the libgccjit support for must-tail-call via a new: gcc_jit_rvalue_set_bool_require_tail_call API entrypoint. (I didn't implement a wrapper for this within the C++ bindings) gcc/jit/ChangeLog: * docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_6. * docs/topics/expressions.rst (Function calls): Add documentation of gcc_jit_rvalue_set_bool_require_tail_call. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-common.h (gcc::jit::recording::base_call): Add forward decl. * jit-playback.c: Within namespace gcc::jit::playback... (context::build_call) Add "require_tail_call" param and use it to set CALL_EXPR_MUST_TAIL_CALL. (context::new_call): Add "require_tail_call" param. (context::new_call_through_ptr): Likewise. * jit-playback.h: Within namespace gcc::jit::playback... (context::new_call: Add "require_tail_call" param. (context::new_call_through_ptr): Likewise. (context::build_call): Likewise. * jit-recording.c: Within namespace gcc::jit::recording... (base_call::base_call): New constructor. (base_call::write_reproducer_tail_call): New method. (call::call): Update for inheritance from base_call. (call::replay_into): Provide m_require_tail_call to call to new_call. (call::write_reproducer): Call write_reproducer_tail_call. (call_through_ptr::call_through_ptr): Update for inheritance from base_call. (call_through_ptr::replay_into): Provide m_require_tail_call to call to new_call_through_ptr. (recording::call_through_ptr::write_reproducer): Call write_reproducer_tail_call. * jit-recording.h: Within namespace gcc::jit::recording... (rvalue::dyn_cast_base_call): New virtual function. (class base_call): New subclass of class rvalue. (class call): Inherit from base_call rather than directly from rvalue, moving get_precedence and m_args to base_call. (class call_through_ptr): Likewise. * libgccjit.c (gcc_jit_rvalue_set_bool_require_tail_call): New function. * libgccjit.h (LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call): New macro. (gcc_jit_rvalue_set_bool_require_tail_call): New function. * libgccjit.map (LIBGCCJIT_ABI_6): New. (gcc_jit_rvalue_set_bool_require_tail_call): Add. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: Add test-factorial-must-tail-call.c. * jit.dg/test-error-impossible-must-tail-call.c: New test case. * jit.dg/test-factorial-must-tail-call.c: New test case. From-SVN: r236531
Diffstat (limited to 'gcc/jit')
-rw-r--r--gcc/jit/ChangeLog44
-rw-r--r--gcc/jit/docs/topics/compatibility.rst7
-rw-r--r--gcc/jit/docs/topics/expressions.rst24
-rw-r--r--gcc/jit/jit-common.h1
-rw-r--r--gcc/jit/jit-playback.c23
-rw-r--r--gcc/jit/jit-playback.h9
-rw-r--r--gcc/jit/jit-recording.c60
-rw-r--r--gcc/jit/jit-recording.h46
-rw-r--r--gcc/jit/libgccjit.c20
-rw-r--r--gcc/jit/libgccjit.h13
-rw-r--r--gcc/jit/libgccjit.map5
11 files changed, 214 insertions, 38 deletions
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index f9320ec..1c3e1fc 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,47 @@
+2016-05-20 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_6.
+ * docs/topics/expressions.rst (Function calls): Add documentation
+ of gcc_jit_rvalue_set_bool_require_tail_call.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * jit-common.h (gcc::jit::recording::base_call): Add forward decl.
+ * jit-playback.c: Within namespace gcc::jit::playback...
+ (context::build_call) Add "require_tail_call" param and use it
+ to set CALL_EXPR_MUST_TAIL_CALL.
+ (context::new_call): Add "require_tail_call" param.
+ (context::new_call_through_ptr): Likewise.
+ * jit-playback.h: Within namespace gcc::jit::playback...
+ (context::new_call: Add "require_tail_call" param.
+ (context::new_call_through_ptr): Likewise.
+ (context::build_call): Likewise.
+ * jit-recording.c: Within namespace gcc::jit::recording...
+ (base_call::base_call): New constructor.
+ (base_call::write_reproducer_tail_call): New method.
+ (call::call): Update for inheritance from base_call.
+ (call::replay_into): Provide m_require_tail_call to call
+ to new_call.
+ (call::write_reproducer): Call write_reproducer_tail_call.
+ (call_through_ptr::call_through_ptr): Update for inheritance from
+ base_call.
+ (call_through_ptr::replay_into): Provide m_require_tail_call to call
+ to new_call_through_ptr.
+ (recording::call_through_ptr::write_reproducer): Call
+ write_reproducer_tail_call.
+ * jit-recording.h: Within namespace gcc::jit::recording...
+ (rvalue::dyn_cast_base_call): New virtual function.
+ (class base_call): New subclass of class rvalue.
+ (class call): Inherit from base_call rather than directly from
+ rvalue, moving get_precedence and m_args to base_call.
+ (class call_through_ptr): Likewise.
+ * libgccjit.c (gcc_jit_rvalue_set_bool_require_tail_call): New
+ function.
+ * libgccjit.h
+ (LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call): New
+ macro.
+ (gcc_jit_rvalue_set_bool_require_tail_call): New function.
+ * libgccjit.map (LIBGCCJIT_ABI_6): New.
+ (gcc_jit_rvalue_set_bool_require_tail_call): Add.
+
2016-05-17 David Malcolm <dmalcolm@redhat.com>
* dummy-frontend.c: Include diagnostic.h.
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index d9eacf2..7abd050 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -135,3 +135,10 @@ entrypoints:
-------------------
``LIBGCCJIT_ABI_5`` covers the addition of
:func:`gcc_jit_context_set_bool_use_external_driver`
+
+.. _LIBGCCJIT_ABI_6:
+
+``LIBGCCJIT_ABI_6``
+-------------------
+``LIBGCCJIT_ABI_6`` covers the addition of
+:func:`gcc_jit_rvalue_set_bool_require_tail_call`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 0445332..261483c 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -424,6 +424,30 @@ Function calls
The same caveat as for :c:func:`gcc_jit_context_new_call` applies.
+.. function:: void\
+ gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *call,\
+ int require_tail_call)
+
+ Given an :c:type:`gcc_jit_rvalue *` for a call created through
+ :c:func:`gcc_jit_context_new_call` or
+ :c:func:`gcc_jit_context_new_call_through_ptr`, mark/clear the
+ call as needing tail-call optimization. The optimizer will
+ attempt to optimize the call into a jump instruction; if it is
+ unable to do do, an error will be emitted.
+
+ This may be useful when implementing functions that use the
+ continuation-passing style (e.g. for functional programming
+ languages), in which every function "returns" by calling a
+ "continuation" function pointer. This call must be
+ guaranteed to be implemented as a jump, otherwise the program
+ could consume an arbitrary amount of stack space as it executed.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_6`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
Type-coercion
*************
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 156448d..c9f4084 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -854,7 +854,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 ());
@@ -868,9 +869,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
@@ -890,7 +895,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;
@@ -902,7 +908,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
@@ -912,12 +918,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 8f7a43d..c00c258 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -133,12 +133,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,
@@ -236,7 +238,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..9376342 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -4681,6 +4681,39 @@ 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]);
+}
+
+/* Subroutine for use by call and call_though_ptr's write_reproducer
+ methods. */
+
+void
+recording::base_call::write_reproducer_tail_call (reproducer &r,
+ const char *id)
+{
+ if (m_require_tail_call)
+ {
+ r.write (" gcc_jit_rvalue_set_bool_require_tail_call (%s, /* gcc_jit_rvalue *call*/\n"
+ " %i); /* int require_tail_call*/\n",
+ id,
+ 1);
+ }
+}
+
/* The implementation of class gcc::jit::recording::call. */
/* The constructor for gcc::jit::recording::call. */
@@ -4690,12 +4723,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 +4741,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
@@ -4790,6 +4821,7 @@ recording::call::write_reproducer (reproducer &r)
r.get_identifier (m_func),
m_args.length (),
args_id);
+ write_reproducer_tail_call (r, id);
}
/* The implementation of class gcc::jit::recording::call_through_ptr. */
@@ -4801,14 +4833,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 +4854,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
@@ -4907,6 +4938,7 @@ recording::call_through_ptr::write_reproducer (reproducer &r)
r.get_identifier_as_rvalue (m_fn_ptr),
m_args.length (),
args_id);
+ write_reproducer_tail_call (r, id);
}
/* The implementation of class gcc::jit::recording::array_access. */
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 1c3e763..0e3511c 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,36 @@ 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:
+ void write_reproducer_tail_call (reproducer &r, const char *id);
+
+ protected:
+ auto_vec<rvalue *> m_args;
+ bool m_require_tail_call;
+};
+
+class call : public base_call
{
public:
call (context *ctxt,
@@ -1434,17 +1464,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 +1485,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..c2c6aeb 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2950,3 +2950,23 @@ gcc_jit_timer_print (gcc_jit_timer *timer,
timer->start (TV_TOTAL);
timer->push (TV_JIT_CLIENT_CODE);
}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is effectively done by the
+ gcc::jit::base_call::set_require_tail_call setter in jit-recording.h. */
+
+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);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a8b9f55..175cc16c 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1374,6 +1374,19 @@ extern void
gcc_jit_timer_print (gcc_jit_timer *timer,
FILE *f_out);
+
+#define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
+
+/* Mark/clear a call as needing tail-call optimization.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_6; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
+*/
+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;