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