From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 94260 invoked by alias); 13 May 2016 19:53:32 -0000 Mailing-List: contact jit-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Subscribe: Sender: jit-owner@gcc.gnu.org Received: (qmail 94230 invoked by uid 89); 13 May 2016 19:53:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.1 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.3 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 spammy=sk:write_r, fntype, playback, 1109 X-Spam-Status: No, score=-3.3 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,T_FILL_THIS_FORM_SHORT autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: mx1.redhat.com From: David Malcolm To: Basile Starynkevitch , =?UTF-8?q?Marc=20Nieper-Wi=C3=9Fkirchen?= , jit@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 3/6] FIXME: WIP on jit part of must-tail-call Date: Fri, 01 Jan 2016 00:00:00 -0000 Message-Id: <1463170721-13825-3-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1463170721-13825-1-git-send-email-dmalcolm@redhat.com> References: <1463170652-13754-1-git-send-email-dmalcolm@redhat.com> <1463170721-13825-1-git-send-email-dmalcolm@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Fri, 13 May 2016 19:53:26 +0000 (UTC) X-SW-Source: 2016-q2/txt/msg00022.txt.bz2 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 *args) + const auto_vec *args, + bool require_tail_call) { vec *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 *args) + const auto_vec *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 *args) + const auto_vec *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 *args); + const auto_vec *args, + bool require_tail_call); rvalue * new_call_through_ptr (location *loc, rvalue *fn_ptr, - const auto_vec *args); + const auto_vec *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 *args); + const auto_vec *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 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 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 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 +#include +#include + +#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