Skip to content

Add support for try/catch #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions gcc/dwarf2asm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 2 additions & 0 deletions gcc/dwarf2asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions gcc/dwarf2out.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
9 changes: 8 additions & 1 deletion gcc/jit/dummy-frontend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
79 changes: 79 additions & 0 deletions gcc/jit/jit-playback.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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. */
Expand All @@ -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 ());
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions gcc/jit/jit-playback.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ class function : public wrapper
rvalue *
get_address (location *loc);

void
set_personality_function (function *personality_function);

void
build_stmt_list ();

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
};
Expand Down
123 changes: 123 additions & 0 deletions gcc/jit/jit-recording.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<block *> 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)
{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading