WIP: add support for try/catch
diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 4be67e3..bfc2573 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h
@@ -25,6 +25,7 @@ #include "ipa-ref.h" #include "plugin-api.h" #include "ipa-param-manipulation.h" +#include "print-tree.h" extern void debuginfo_early_init (void); extern void debuginfo_init (void);
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc index 7b5be0f..cef7d0b 100644 --- a/gcc/cgraphunit.cc +++ b/gcc/cgraphunit.cc
@@ -240,9 +240,14 @@ /* Double check that no one output the function into assembly file early. */ if (!native_rtl_p ()) + { + if (!(!DECL_ASSEMBLER_NAME_SET_P (decl) + || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + debug_tree (decl); gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl) || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))); + } if (!definition) return false; @@ -1390,7 +1395,7 @@ || cnode->alias || gimple_has_body_p (decl) || cnode->native_rtl_p ()); - gcc_assert (cnode->analyzed == cnode->definition); + gcc_assert (cnode->analyzed == cnode->definition); } node->aux = NULL; }
diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc index 274f574..e640a71 100644 --- a/gcc/dwarf2asm.cc +++ b/gcc/dwarf2asm.cc
@@ -938,7 +938,7 @@ /* The strings are always those from IDENTIFIER_NODEs, and, therefore, we should never have two copies of the same string. */ - gcc_assert (ret); + //gcc_assert (ret); return ret; } @@ -1159,4 +1159,14 @@ va_end (ap); } +void dwarf2asm_cc_finalize (void) +{ + if (indirect_pool) + { + indirect_pool->empty(); + indirect_pool = NULL; + } + dw2_const_labelno = 0; +} + #include "gt-dwarf2asm.h"
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index 871a77b..53720ab 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h
@@ -86,6 +86,8 @@ extern rtx dw2_force_const_mem (rtx, bool); extern void dw2_output_indirect_constants (void); +void dwarf2asm_cc_finalize (void); + /* These are currently unused. */ #if 0
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 28a4ae0..1bf4289 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc
@@ -1003,6 +1003,9 @@ if (targetm.asm_out.make_eh_symbol_indirect != NULL) ref = targetm.asm_out.make_eh_symbol_indirect (ref, true); else + // TODO: HERE: should not insert multiple times the same personality function. + // If we don't, we segfault later, possibly because we don't generate the info for the duplicates. + // I'm not sure why it's attempting to insert multiple times the same personality function. ref = dw2_force_const_mem (ref, true); }
diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc index 8a27e7b..8b1a0a4 100644 --- a/gcc/ipa-visibility.cc +++ b/gcc/ipa-visibility.cc
@@ -709,6 +709,15 @@ } node->dissolve_same_comdat_group_list (); } + if (!((!DECL_WEAK (node->decl) + && !DECL_COMDAT (node->decl)) + || TREE_PUBLIC (node->decl) + || node->weakref + || DECL_EXTERNAL (node->decl))) + { + fprintf (stderr, "%d, %d, %d, %d, %d\n", DECL_WEAK (node->decl), DECL_COMDAT (node->decl), TREE_PUBLIC (node->decl), node->weakref, DECL_EXTERNAL (node->decl)); + debug_tree (node->decl); + } gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl)) || TREE_PUBLIC (node->decl)
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 1110993..a9330f5 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc
@@ -611,6 +611,10 @@ target_builtins.empty (); build_common_builtin_nodes (); + /* Initialize EH, if we've been told to do so. */ + if (flag_exceptions) + using_eh_for_cleanups (); + /* The default precision for floating point numbers. This is used for floating point constants with abstract type. This may eventually be controllable by a command line option. */
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 83c8c21..775e08f 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc
@@ -547,8 +547,7 @@ enum built_in_function builtin_id, int is_target_builtin, const std::vector<gcc_jit_fn_attribute> &attributes, - const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes, - function *personality_function) + const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes) { int i; param *param; @@ -571,11 +570,7 @@ /* FIXME: this uses input_location: */ tree fndecl = build_fn_decl (name, fn_type); - - if (personality_function) - { - DECL_FUNCTION_PERSONALITY (fndecl) = personality_function->as_fndecl (); - } + TREE_NOTHROW (fndecl) = 0; if (loc) set_tree_location (fndecl, loc); @@ -659,6 +654,9 @@ break; case GCC_JIT_FN_ATTRIBUTE_WEAK: DECL_WEAK (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + //declare_weak (fndecl); + //make_decl_one_only(fndecl, DECL_ASSEMBLER_NAME(fndecl)); break; } @@ -2164,6 +2162,16 @@ return new rvalue (m_ctxt, t_fnptr); } +/* Construct a new local within this playback::function. */ + +void +playback::function:: +set_personality_function (function *personality_function) +{ + //fprintf (stderr, "************* Setting personality function %s for %s\n", IDENTIFIER_POINTER (DECL_NAME (personality_function->as_fndecl ())), IDENTIFIER_POINTER (DECL_NAME (m_inner_fndecl))); + DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl (); +} + /* Build a statement list for the function as a whole out of the lists of statements for the individual blocks, building labels for each block. */ @@ -2222,8 +2230,11 @@ if (m_kind == GCC_JIT_FUNCTION_INTERNAL ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE) { - DECL_EXTERNAL (m_inner_fndecl) = 0; - TREE_PUBLIC (m_inner_fndecl) = 0; + if (!DECL_WEAK (m_inner_fndecl)) + { + DECL_EXTERNAL (m_inner_fndecl) = 0; + TREE_PUBLIC (m_inner_fndecl) = 0; + } } if (m_kind != GCC_JIT_FUNCTION_IMPORTED) @@ -2290,7 +2301,8 @@ playback::block:: add_try_catch (location *loc, block *try_block, - block *catch_block) + block *catch_block, + bool is_finally) { gcc_assert (try_block); gcc_assert (catch_block); @@ -2318,8 +2330,38 @@ append_to_statement_list (catch_stmt, &catch_body); } - add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, + if (is_finally) + { + tree noop = build_int_cst (integer_type_node, 0); + tree stmt = build1 (NOP_EXPR, void_type_node, size_zero_node); + tree success_body = alloc_stmt_list (); + //append_to_statement_list (stmt, &success_body); + + + tree t_string = build_string ("nop"); + tree asm_stmt + = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + + // asm statements without outputs, including simple ones, are treated + // as volatile. + ASM_VOLATILE_P (asm_stmt) = 1; + ASM_INPUT_P (asm_stmt) = 0; + append_to_statement_list (asm_stmt, &success_body); + //debug_tree (success_body); + + catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body); + add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, try_body, catch_body)); + } + else + { + catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); + tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node, + try_body, catch_body); + //if (is_finally) + // TRY_CATCH_IS_CLEANUP (try_catch) = true; + add_stmt (try_catch); + } } /* Add an assignment to the function's statement list. */
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 75fb21b..83021bb 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h
@@ -113,8 +113,7 @@ enum built_in_function builtin_id, int is_target_builtin, const std::vector<gcc_jit_fn_attribute> &attributes, - const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes, - function *personality_function); + const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes); lvalue * new_global (location *loc, @@ -537,6 +536,9 @@ get_address (location *loc); void + set_personality_function (function *personality_function); + + void build_stmt_list (); void @@ -609,7 +611,8 @@ void add_try_catch (location *loc, block *try_block, - block *catch_block); + block *catch_block, + bool is_finally); void add_assignment (location *loc,
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index ba87421..c5420c5 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc
@@ -4180,8 +4180,7 @@ m_fn_ptr_type (NULL), m_is_target_builtin (is_target_builtin), m_attributes(), - m_string_attributes(), - m_personality_function (NULL) + m_string_attributes() { for (int i = 0; i< num_params; i++) { @@ -4234,12 +4233,6 @@ FOR_EACH_VEC_ELT (m_params, i, param) params.safe_push (param->playback_param ()); - playback::function *personality_function = NULL; - if (m_personality_function) - { - personality_function = m_personality_function->playback_function (); - } - set_playback_obj (r->new_function (playback_location (r, m_loc), m_kind, m_return_type->playback_type (), @@ -4249,14 +4242,37 @@ m_builtin_id, m_is_target_builtin, m_attributes, - m_string_attributes, - personality_function)); + m_string_attributes)); +} + +/* Implementation of recording::memento::make_debug_string for + setting a personality function. */ + +recording::string * +recording::memento_of_set_personality_function::make_debug_string () +{ + return string::from_printf (m_ctxt, + "%s", + m_personality_function->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for setting the personality function. */ + +void +recording::memento_of_set_personality_function::write_reproducer (reproducer &r) +{ + r.write (" gcc_jit_function_set_personality_function (%s,\n" + " %s);\n", + r.get_identifier (m_function), + r.get_identifier (m_personality_function)); } void recording::function::set_personality_function (function *function) { - m_personality_function = function; + recording::memento_of_set_personality_function *result = + new memento_of_set_personality_function (m_ctxt, this, function); + m_ctxt->record (result); } /* Create a recording::local instance and add it to @@ -4613,9 +4629,10 @@ recording::statement * recording::block::add_try_catch (location *loc, block *try_block, - block *catch_block) + block *catch_block, + bool is_finally) { - statement *result = new try_catch (this, loc, try_block, catch_block); + statement *result = new try_catch (this, loc, try_block, catch_block, is_finally); //try_block->m_has_been_terminated = true; //catch_block->m_has_been_terminated = true; try_block->m_is_reachable = true; @@ -7041,6 +7058,17 @@ m_loc = d.make_location (); } +/* The implementation of class gcc::jit::recording::memento_of_set_personality_function. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_set_personality_function. */ + +void +recording::memento_of_set_personality_function::replay_into (replayer *r) +{ + m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ()); +} + /* The implementation of class gcc::jit::recording::eval. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -7090,7 +7118,8 @@ playback_block (get_block ()) ->add_try_catch (playback_location (r), m_try_block->playback_block (), - m_catch_block->playback_block ()); + m_catch_block->playback_block (), + m_is_finally); } /* Implementation of recording::memento::make_debug_string for @@ -7099,6 +7128,7 @@ recording::string * recording::try_catch::make_debug_string () { + // TODO: handle m_is_finally. return string::from_printf (m_ctxt, "try { %s } catch { %s };", m_try_block->get_debug_string (), @@ -7111,6 +7141,7 @@ void recording::try_catch::write_reproducer (reproducer &r) { + // TODO: handle m_is_finally. r.write (" gcc_jit_block_add_try_catch (%s, /*gcc_jit_block *block */\n" " %s, /* gcc_jit_location *loc */\n" " %s, /* gcc_jit_block *try_block */\n"
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 246bf3e..547f5de 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h
@@ -1465,7 +1465,6 @@ int m_is_target_builtin; std::vector<gcc_jit_fn_attribute> m_attributes; std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes; - function *m_personality_function; }; class block : public memento @@ -1497,7 +1496,8 @@ statement * add_try_catch (location *loc, block *try_block, - block *catch_block); + block *catch_block, + bool is_finally = false); statement * add_assignment (location *loc, @@ -1714,6 +1714,27 @@ string *m_value; }; +class memento_of_set_personality_function : public memento +{ +public: + memento_of_set_personality_function (context *ctx, + function *func, + function *personality_function) + : memento(ctx), + m_function (func), + m_personality_function (personality_function) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + function *m_function; + function *m_personality_function; +}; + class memento_of_new_rvalue_from_vector : public rvalue { public: @@ -2357,10 +2378,12 @@ try_catch (block *b, location *loc, block *try_block, - block *catch_block) + block *catch_block, + bool is_finally = false) : statement (b, loc), m_try_block (try_block), - m_catch_block (catch_block) {} + m_catch_block (catch_block), + m_is_finally (is_finally) {} void replay_into (replayer *r) final override; @@ -2371,6 +2394,7 @@ private: block *m_try_block; block *m_catch_block; + bool m_is_finally; }; class assignment : public statement
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 16c8208..98cd254 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc
@@ -2967,6 +2967,34 @@ } /* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::block::add_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block) +{ + RETURN_IF_NOT_VALID_BLOCK (block, loc); + gcc::jit::recording::context *ctxt = block->get_context (); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_IF_FAIL (try_block, ctxt, loc, "NULL rvalue"); + RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, finally_block, true); + + /* "stmt" should be good enough to be usable in error-messages, + but might still not be compilable; perform some more + error-checking here. We do this here so that the error messages + can contain a stringified version of "stmt", whilst appearing + as close as possible to the point of failure. */ + /*try_block->verify_valid_within_stmt (__func__, stmt); + catch_block->verify_valid_within_stmt (__func__, stmt);*/ +} + +/* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the gcc::jit::recording::block::add_assignment method in
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 1fd5c87..399e5c8 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h
@@ -1427,7 +1427,7 @@ try { try_block } - catch { + catch (...) { catch_block } */ @@ -1438,6 +1438,22 @@ gcc_jit_block *try_block, gcc_jit_block *catch_block); +/* Add a try/finally statement. + This is equivalent to this C++-like code: + try { + try_block + } + finally { + finally_block + } +*/ + +void +gcc_jit_block_add_try_finally (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *finally_block); + /* Add evaluation of an rvalue, assigning the result to the given lvalue.
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index a1fc114..4d6a6ca 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map
@@ -314,5 +314,6 @@ LIBGCCJIT_ABI_32 { global: gcc_jit_block_add_try_catch; + gcc_jit_block_add_try_finally; gcc_jit_function_set_personality_function; } LIBGCCJIT_ABI_31;
diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 61d234a..9456c95 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc
@@ -2353,6 +2353,7 @@ cgraphunit_cc_finalize (); symtab_thunks_cc_finalize (); dwarf2out_cc_finalize (); + dwarf2asm_cc_finalize (); gcse_cc_finalize (); ipa_cp_cc_finalize (); ira_costs_cc_finalize ();
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index 076ecd3..38b8ea8 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc
@@ -4882,7 +4882,11 @@ and avoids references to a never defined personality routine. */ if (DECL_FUNCTION_PERSONALITY (current_function_decl) && function_needs_eh_personality (fun) != eh_personality_lang) - DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE; + { + //fprintf(stderr, "Unset personality function for %s\n", IDENTIFIER_POINTER (DECL_NAME (current_function_decl))); + // TODO: uncomment: + //DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE; + } return ret; }
diff --git a/gcc/tree.cc b/gcc/tree.cc index 007c932..0388284 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc
@@ -14766,6 +14766,7 @@ tree_cc_finalize (void) { clear_nonstandard_integer_type_cache (); + gcc_eh_personality_decl = NULL; } #if CHECKING_P