aboutsummaryrefslogtreecommitdiff
path: root/gcc/jit/jit-playback.c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2015-06-30 20:39:50 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2015-06-30 20:39:50 +0000
commitec5d0088148d1d6218f5f503d1c8e67a529dfacd (patch)
treec7cf3f33890bd8579a8afa8a850a326bc0b1fd58 /gcc/jit/jit-playback.c
parent6a3603e356e14096e9554ceef57916fd03d9072b (diff)
downloadgcc-ec5d0088148d1d6218f5f503d1c8e67a529dfacd.zip
gcc-ec5d0088148d1d6218f5f503d1c8e67a529dfacd.tar.gz
gcc-ec5d0088148d1d6218f5f503d1c8e67a529dfacd.tar.bz2
jit: add switch statements
gcc/ChangeLog: * typed-splay-tree.h: New file. gcc/jit/ChangeLog: * docs/cp/topics/functions.rst (Blocks): Add switch statements to list of ways to terminate a block. (gccjit::block::end_with_switch): Add function description. (gccjit::case_): Add class. (gccjit::context::new_case): Add function description. * docs/cp/topics/objects.rst: Add "case_" to class hierarchy. * docs/topics/compatibility.rst (LIBGCCJIT_ABI_3): New. * docs/topics/functions.rst (Blocks): Add switch statements to list of ways to terminate a block. (gcc_jit_block_end_with_switch): Add function description. (gcc_jit_case): Add type. (gcc_jit_context_new_case): Add function description. (gcc_jit_case_as_object): Add function description. * docs/topics/objects.rst: Add gcc_jit_case to class hierarchy. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-common.h (gcc::jit::recording::case_): Add forward decl. (gcc::jit::playback::case_): Add forward decl. * jit-playback.c (add_case): New function. (gcc::jit::playback::block::add_switch): New function. * jit-playback.h (gcc::jit::playback::case_): New struct. (gcc::jit::playback::block::get_function): New method. (gcc::jit::playback::block::add_switch): New method. * jit-recording.c: Within namespace gcc::jit... (recording::context::new_case): New method. (recording::function::validate): Update for change to get_successor_blocks. (recording::block::end_with_switch): New method. (recording::block::get_successor_blocks): Update to support an arbitrary number of successor blocks. (recording::block::dump_edges_to_dot): Likewise. (memento_of_new_rvalue_from_const <int>::get_wide_int): New. (memento_of_new_rvalue_from_const <long>::get_wide_int): New. (memento_of_new_rvalue_from_const <double>::get_wide_int): New. (memento_of_new_rvalue_from_const <void *>::get_wide_int): New. (recording::statement::get_successor_blocks): Update to support an arbitrary number of successor blocks. (recording::conditional::get_successor_blocks): Likewise. (recording::jump::get_successor_blocks): Likewise. (recording::return_::get_successor_blocks): Likewise. (recording::case_::write_reproducer): New. (recording::case_::make_debug_string): New. (recording::switch_::switch_): New. (recording::switch_::replay_into): New. (recording::switch_::get_successor_blocks): New. (recording::switch_::make_debug_string): New. (recording::switch_::write_reproducer): New. * jit-recording.h: Within namespace gcc::jit::recording... (context::new_case): New. (rvalue::is_constant): New. (rvalue::get_wide_int): New. (block::end_with_switch): New. (block::get_successor_blocks): Update to support an arbitrary number of successor blocks. (memento_of_new_rvalue_from_const::is_constant): New. (memento_of_new_rvalue_from_const::get_wide_int): New. (statement::get_successor_blocks): Update to support an arbitrary number of successor blocks. (conditional::get_successor_blocks): Likewise. (jump::get_successor_blocks): Likewise. (return_::get_successor_blocks): Likewise. (case_): New subclass of memento. (switch_): New subclass of statement. * libgccjit++.h (gccjit::case_): New subclass of gccjit::object. (gccjit::context::new_case): New method. (gccjit::block::end_with_switch): New method. (gccjit::case_::case): New ctors. (gccjit::case_::get_inner_case): New method. * libgccjit.c: Include "typed-splay-tree.h" (struct gcc_jit_case): New. (gcc_jit_context_new_case): New function. (gcc_jit_case_as_object): New function. (valid_dest_for_switch): New function. (valid_case_for_switch): New function. (class api_call_validator): New class. (class case_range_validator): New class. (case_range_validator::case_range_validator): New. (case_range_validator::validate): New. (case_range_validator::case_compare): New. (case_range_validator::get_wide_int): new. (gcc_jit_block_end_with_switch): New. * libgccjit.h: Add gcc_jit_case to class hierarchy comment. (gcc_jit_case): New typedef. (gcc_jit_context_new_case): New function. (gcc_jit_case_as_object): New function. (gcc_jit_block_end_with_switch): New function. (LIBGCCJIT_HAVE_SWITCH_STATEMENTS): New. * libgccjit.map: Add gcc_jit_block_end_with_switch, gcc_jit_case_as_object and gcc_jit_context_new_case. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: Add test-switch.c. * jit.dg/test-error-gcc_jit_block_end_with_switch-NULL-case.c: New testcase. * jit.dg/test-error-gcc_jit_block_end_with_switch-mismatching-case-type.c: New testcase. * jit.dg/test-error-gcc_jit_block_end_with_switch-overlapping-ranges.c: New testcase. * jit.dg/test-error-gcc_jit_context_new_case-non-const-label.c: New testcase. * jit.dg/test-error-gcc_jit_context_new_case-non-integer-type.c: New testcase. * jit.dg/test-error-gcc_jit_context_new_case-reversed-endpoints.c: New testcase. * jit.dg/test-switch.c: New testcase. * jit.dg/test-switch.cc: New testcase. From-SVN: r225207
Diffstat (limited to 'gcc/jit/jit-playback.c')
-rw-r--r--gcc/jit/jit-playback.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 9d7f8d6..c9d7c8c 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1576,6 +1576,80 @@ add_return (location *loc,
add_stmt (return_stmt);
}
+/* Helper function for playback::block::add_switch.
+ Construct a case label for the given range, followed by a goto stmt
+ to the given block, appending them to stmt list *ptr_t_switch_body. */
+
+static void
+add_case (tree *ptr_t_switch_body,
+ tree t_low_value,
+ tree t_high_value,
+ playback::block *dest_block)
+{
+ tree t_label = create_artificial_label (UNKNOWN_LOCATION);
+ DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
+
+ tree t_case_label =
+ build_case_label (t_low_value, t_high_value, t_label);
+ append_to_statement_list (t_case_label, ptr_t_switch_body);
+
+ tree t_goto_stmt =
+ build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
+ append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
+}
+
+/* Add a switch statement to the function's statement list.
+
+ My initial attempt at implementing this constructed a TREE_VEC
+ of the cases and set it as SWITCH_LABELS (switch_expr). However,
+ gimplify.c:gimplify_switch_expr is set up to deal with SWITCH_BODY, and
+ doesn't have any logic for gimplifying SWITCH_LABELS.
+
+ Hence we create a switch body, and populate it with case labels, each
+ followed by a goto to the desired block. */
+
+void
+playback::block::
+add_switch (location *loc,
+ rvalue *expr,
+ block *default_block,
+ const auto_vec <case_> *cases)
+{
+ /* Compare with:
+ - c/c-typeck.c: c_start_case
+ - c-family/c-common.c:c_add_case_label
+ - java/expr.c:expand_java_switch and expand_java_add_case
+ We've already rejected overlaps and duplicates in
+ libgccjit.c:case_range_validator::validate. */
+
+ tree t_expr = expr->as_tree ();
+ tree t_type = TREE_TYPE (t_expr);
+
+ tree t_switch_body = alloc_stmt_list ();
+
+ int i;
+ case_ *c;
+ FOR_EACH_VEC_ELT (*cases, i, c)
+ {
+ tree t_low_value = c->m_min_value->as_tree ();
+ tree t_high_value = c->m_max_value->as_tree ();
+ add_case (&t_switch_body,
+ t_low_value,
+ t_high_value,
+ c->m_dest_block);
+ }
+ /* Default label. */
+ add_case (&t_switch_body,
+ NULL_TREE, NULL_TREE,
+ default_block);
+
+ tree switch_stmt = build3 (SWITCH_EXPR, t_type, t_expr,
+ t_switch_body, NULL_TREE);
+ if (loc)
+ set_tree_location (switch_stmt, loc);
+ add_stmt (switch_stmt);
+}
+
/* Constructor for gcc::jit::playback::block. */
playback::block::