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 --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 <dmalc...@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 <dmalc...@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 <dmalc...@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 <dmalc...@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); } -- 1.7.11.7