diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc index 65b95fee243fb..e66cd30c1fe87 100644 --- a/gcc/dwarf2asm.cc +++ b/gcc/dwarf2asm.cc @@ -1159,4 +1159,14 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public, 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 37a0a05e5bb1c..80695b3c6c8b3 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h @@ -86,6 +86,8 @@ extern const char *eh_data_format_name (int); 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 1f39df3b1e250..61b711d4a5269 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1003,6 +1003,9 @@ dwarf2out_do_cfi_startproc (bool second) 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/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index faf9737808ce2..8e623800323c0 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -605,14 +605,21 @@ jit_langhook_init (void) build_common_tree_nodes (flag_signed_char); + /* I don't know why this has to be done explicitly. */ + void_list_node = build_tree_list (NULL_TREE, void_type_node); + + 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. */ mpfr_set_default_prec (256); - target_builtins.empty (); targetm.init_builtins (); return true; diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index b73d3a95de951..f0bcc42ca454b 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -568,6 +568,7 @@ new_function (location *loc, /* FIXME: this uses input_location: */ tree fndecl = build_fn_decl (name, fn_type); + TREE_NOTHROW (fndecl) = 0; if (loc) set_tree_location (fndecl, loc); @@ -2153,6 +2154,15 @@ playback::function::get_address (location *loc) return new rvalue (m_ctxt, t_fnptr); } +/* Construct a new local within this playback::function. */ + +void +playback::function:: +set_personality_function (function *personality_function) +{ + 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. */ @@ -2171,6 +2181,11 @@ build_stmt_list () int j; tree stmt; + // Do not add try/catch block to the function. + // TODO: explain why. + if (b->m_is_try_or_catch) + continue; + b->m_label_expr = build1 (LABEL_EXPR, void_type_node, b->as_label_decl ()); @@ -2269,6 +2284,70 @@ add_eval (location *loc, add_stmt (rvalue->as_tree ()); } + +void +playback::block:: +add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + gcc_assert (try_block); + gcc_assert (catch_block); + + try_block->m_is_try_or_catch = true; + catch_block->m_is_try_or_catch = true; + + if (loc) + { + set_tree_location (try_block->as_label_decl (), loc); + set_tree_location (catch_block->as_label_decl (), loc); + } + + tree try_body = alloc_stmt_list (); + int i; + tree stmt; + FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) { + append_to_statement_list (stmt, &try_body); + } + + tree catch_body = alloc_stmt_list (); + int j; + tree catch_stmt; + FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) { + append_to_statement_list (catch_stmt, &catch_body); + } + + if (is_finally) + { + tree success_body = alloc_stmt_list (); + + // TODO: find a better way to keep the EH_ELSE_EXPR than creating an empty inline asm. + tree t_string = build_string (""); + 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); + + // TODO: Don't automatically add the `EH_ELSE_EXPR`. Make an API to create such a node and let the user of libgccjit + // add it manually. + 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); + add_stmt (try_catch); + } +} + /* Add an assignment to the function's statement list. */ void diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 4d289d126ee84..2b0a4e7ddf065 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -536,6 +536,9 @@ class function : public wrapper rvalue * get_address (location *loc); + void + set_personality_function (function *personality_function); + void build_stmt_list (); @@ -606,6 +609,12 @@ class block : public wrapper add_eval (location *loc, rvalue *rvalue); + void + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally); + void add_assignment (location *loc, lvalue *lvalue, @@ -669,6 +678,7 @@ class block : public wrapper public: // for now tree m_label_expr; + bool m_is_try_or_catch = false; friend class function; }; diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 9113bfba308d2..066fb2b37423e 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4244,6 +4244,36 @@ recording::function::replay_into (replayer *r) 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) +{ + 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 the functions's context's list of mementos, and to the function's list of locals. @@ -4386,6 +4416,13 @@ recording::function::validate () /* Iteratively walk the graph of blocks, marking their "m_is_reachable" flag, starting at the initial block. */ auto_vec worklist (m_blocks.length ()); + int j; + block *func_block; + /* Push the blocks used in try/catch because they're not successors of + other blocks. */ + FOR_EACH_VEC_ELT (m_blocks, j, func_block) + if (func_block->m_is_reachable) + worklist.safe_push (func_block); worklist.safe_push (m_blocks[0]); while (worklist.length () > 0) { @@ -4581,6 +4618,28 @@ recording::block::add_eval (recording::location *loc, return result; } +/* The implementation of class gcc::jit::recording::block. */ + +/* Create a recording::try_catch instance and add it to + the block's context's list of mementos, and to the block's + list of statements. + Implements the heart of gcc_jit_block_add_try_catch. */ + +recording::statement * +recording::block::add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally) +{ + statement *result = new try_catch (this, loc, try_block, catch_block, is_finally); + // TODO: explain why we set the blocks reachable state. + try_block->m_is_reachable = true; + catch_block->m_is_reachable = true; + m_ctxt->record (result); + m_statements.safe_push (result); + return result; +} + /* Create a recording::assignment instance and add it to the block's context's list of mementos, and to the block's list of statements. @@ -6997,6 +7056,17 @@ recording::statement::write_to_dump (dump &d) 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 @@ -7035,6 +7105,59 @@ recording::eval::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_rvalue)); } +/* The implementation of class gcc::jit::recording::try_catch. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::try_catch. */ + +void +recording::try_catch::replay_into (replayer *r) +{ + playback_block (get_block ()) + ->add_try_catch (playback_location (r), + m_try_block->playback_block (), + m_catch_block->playback_block (), + m_is_finally); +} + +/* Implementation of recording::memento::make_debug_string for + an eval statement. */ + +recording::string * +recording::try_catch::make_debug_string () +{ + if (m_is_finally) + return string::from_printf (m_ctxt, + "try { %s } finally { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); + else + return string::from_printf (m_ctxt, + "try { %s } catch { %s };", + m_try_block->get_debug_string (), + m_catch_block->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for + eval statements. */ + +void +recording::try_catch::write_reproducer (reproducer &r) +{ + const char *func_name = "gcc_jit_block_add_try_catch"; + if (m_is_finally) + func_name = "gcc_jit_block_add_try_finally"; + r.write (" %s (%s, /*gcc_jit_block *block */\n" + " %s, /* gcc_jit_location *loc */\n" + " %s, /* gcc_jit_block *try_block */\n" + " %s); /* gcc_jit_block *catch_block */\n", + func_name, + r.get_identifier (get_block ()), + r.get_identifier (get_loc ()), + r.get_identifier (m_try_block), + r.get_identifier (m_catch_block)); +} + /* The implementation of class gcc::jit::recording::assignment. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index d021d935fbb21..592e0cf4396c1 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1442,6 +1442,7 @@ class function : public memento void dump_to_dot (const char *path); rvalue *get_address (location *loc); + void set_personality_function (function *function); void add_attribute (gcc_jit_fn_attribute attribute); void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); @@ -1492,6 +1493,12 @@ class block : public memento add_eval (location *loc, rvalue *rvalue); + statement * + add_try_catch (location *loc, + block *try_block, + block *catch_block, + bool is_finally = false); + statement * add_assignment (location *loc, lvalue *lvalue, @@ -1707,6 +1714,27 @@ class memento_of_new_string_literal : public rvalue 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: @@ -2343,6 +2371,31 @@ class eval : public statement rvalue *m_rvalue; }; +class try_catch : public statement +{ +public: + try_catch (block *b, + location *loc, + block *try_block, + block *catch_block, + bool is_finally = false) + : statement (b, loc), + m_try_block (try_block), + m_catch_block (catch_block), + m_is_finally (is_finally) {} + + void replay_into (replayer *r) final override; + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + +private: + block *m_try_block; + block *m_catch_block; + bool m_is_finally; +}; + class assignment : public statement { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index d909a7700a59e..e658837962966 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2938,6 +2938,64 @@ gcc_jit_block_add_eval (gcc_jit_block *block, rvalue->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_try_catch method in jit-recording.c. */ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + gcc_jit_block *try_block, + gcc_jit_block *catch_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 (catch_block, ctxt, loc, "NULL rvalue"); + + gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, catch_block); + + // TODO: remove this or use it. + /* "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_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); + + // TODO: remove this or use it. + /* "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 @@ -3712,6 +3770,20 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, ctxt->add_command_line_option (optname); } +/* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::recording::function::set_personality_function method, in + jit-recording.c. */ + +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func) +{ + RETURN_IF_FAIL (fn, NULL, NULL, "NULL function"); + + fn->set_personality_function (personality_func); +} + /* Public entrypoint. See description in libgccjit.h. The real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 7ddcc2e810b19..a39549ef945f3 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1422,6 +1422,38 @@ gcc_jit_block_add_eval (gcc_jit_block *block, gcc_jit_location *loc, gcc_jit_rvalue *rvalue); +/* Add a try/catch statement. + This is equivalent to this C++ code: + try { + try_block + } + catch (...) { + catch_block + } +*/ + +void +gcc_jit_block_add_try_catch (gcc_jit_block *block, + gcc_jit_location *loc, + 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. @@ -1819,6 +1851,10 @@ extern gcc_jit_rvalue * gcc_jit_function_get_address (gcc_jit_function *fn, gcc_jit_location *loc); +void +gcc_jit_function_set_personality_function (gcc_jit_function *fn, + gcc_jit_function *personality_func); + #define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 7e7df1ab92a7e..4d6a6cad15215 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -310,3 +310,10 @@ LIBGCCJIT_ABI_31 { global: gcc_jit_lvalue_add_attribute; } LIBGCCJIT_ABI_30; + +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 42937f0ba004f..4469e0f069dd2 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -2332,6 +2332,7 @@ toplev::finalize (void) 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 41cf57d2b305f..b734f6be4168e 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -4882,9 +4882,10 @@ pass_cleanup_eh::execute (function *fun) /* If the function no longer needs an EH personality routine clear it. This exposes cross-language inlining opportunities and avoids references to a never defined personality routine. */ - if (DECL_FUNCTION_PERSONALITY (current_function_decl) + // TODO: uncomment and find out why this doesn't work. + /*if (DECL_FUNCTION_PERSONALITY (current_function_decl) && function_needs_eh_personality (fun) != eh_personality_lang) - DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE; + DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;*/ return ret; } diff --git a/gcc/tree.cc b/gcc/tree.cc index 78b64ee98b3e5..ea95e67bb7968 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -15006,6 +15006,7 @@ void tree_cc_finalize (void) { clear_nonstandard_integer_type_cache (); + gcc_eh_personality_decl = NULL; } #if CHECKING_P