From 9b53c7f9484fea5fa0fd23a6444b03071debc4f2 Mon Sep 17 00:00:00 2001 From: Pranil Dey Date: Tue, 20 Aug 2024 22:07:57 +0530 Subject: Edge redirection for exceptions. This commit is contains change in code for the tree-eh.cc, tree-eh.h, MAINTAINERS and tree-cfg.cc files. Specifically it contains four functions - 1. void extract_exception_types_for_call which extracts the exception types in a call stmt and adds them into a vector tree. 2. bool stmt_throw_types does the same as stmt_could_throw the difference being that it also gives the list of exception types as given by the extract_exception_types_for_call function. 3. bool match_lp checks if a landing pad can handle any of the exception types given as input parameters by looking into the catch handlers. 4. update_stmt_eh_region is the function that walks up the EH tree and changes the landing pad for the last statement in a basic block in the control flow graph so that when the edge by make_eh_edge is created it points to the correct handlers. Further work to be done regarding RESX stmts. --- gcc/tree-cfg.cc | 5 ++- gcc/tree-eh.cc | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/tree-eh.h | 5 +++ 3 files changed, 122 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index e6fd129..bb101c8 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -855,11 +855,12 @@ make_edges_bb (basic_block bb, struct omp_region **pcur_region, int *pomp_index) if (!last) return ret; - + + update_stmt_eh_region(last); switch (gimple_code (last)) { case GIMPLE_GOTO: - if (make_goto_expr_edges (bb)) + if (make_goto_expr_edges (bb)) ret = 1; fallthru = false; break; diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index 9609bdc..eec1e6a 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -2271,6 +2271,84 @@ make_eh_dispatch_edges (geh_dispatch *stmt) return true; } +// Check if a landing pad can handle any of the given exception types +bool match_lp(eh_landing_pad lp, vec *exception_types) { + eh_region region = lp->region; + + // Ensure the region is of type ERT_TRY + if (region && region->type == ERT_TRY) { + eh_catch_d *catch_handler = region->u.eh_try.first_catch; + + while (catch_handler) { + tree type_list = catch_handler->type_list; + + for (tree t = type_list; t; t = TREE_CHAIN(t)) { + tree type = TREE_VALUE(t); + for (unsigned i = 0; i < exception_types->length(); ++i) { + // match found or a catch-all handler (NULL) + if (type == (*exception_types)[i] || !type) { + return true; + } + } + } + catch_handler = catch_handler->next_catch; + } + } + return false; +} + +// Function to update landing pad in throw_stmt_table for a given statement +void update_stmt_eh_region(gimple *stmt) { + auto_vec exception_types; + if (!stmt_throw_types (cfun, stmt, &exception_types)) { + return; + } + + int lp_nr = lookup_stmt_eh_lp_fn(cfun, stmt); + if (lp_nr <= 0) { + return; + } + + eh_landing_pad lp = get_eh_landing_pad_from_number(lp_nr); + if (!lp) { + return; + } + + eh_region region = lp->region; + + // Walk up the region tree + while (region) { + switch (region->type) { + case ERT_CLEANUP: + *cfun->eh->throw_stmt_table->get(const_cast(stmt)) = lp->index; + return; + + case ERT_TRY: + if (match_lp(lp, &exception_types)) { + *cfun->eh->throw_stmt_table->get(const_cast(stmt)) = lp->index; + return; + } + break; + + case ERT_MUST_NOT_THROW: + // Undefined behavior, leave edge unchanged + return; + + case ERT_ALLOWED_EXCEPTIONS: + if (!match_lp(lp, &exception_types)) { + return; + } + break; + + default: + break; + } + region = region->outer; + } + + remove_stmt_from_eh_lp_fn(cfun, stmt); +} + /* Create the single EH edge from STMT to its nearest landing pad, if there is such a landing pad within the current function. */ @@ -2913,6 +2991,42 @@ stmt_could_throw_1_p (gassign *stmt) return false; } +void extract_exception_types_for_call (gcall *call_stmt, vec *ret_vector) { + tree callee = gimple_call_fndecl (call_stmt); + if (callee == NULL_TREE) { + return; + } + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (callee)), "__cxa_throw") == 0) { + // Extracting exception type + tree exception_type_info = gimple_call_arg (call_stmt, 1); + if (exception_type_info && TREE_CODE (exception_type_info) == ADDR_EXPR) { + exception_type_info = TREE_OPERAND (exception_type_info, 0); + } + if (exception_type_info && TREE_CODE (exception_type_info) == VAR_DECL) { + // Converting the typeinfo to a compile-time type + tree exception_type = TREE_TYPE (exception_type_info); + if (exception_type) { + ret_vector->safe_push (exception_type); + } + } + } +} + +// Determine which types can be thrown by a GIMPLE statement and convert them to compile-time types +bool stmt_throw_types (function *fun, gimple *stmt, vec *ret_vector) { + if (!flag_exceptions) { + return false; + } + + switch (gimple_code (stmt)) { + case GIMPLE_CALL: + extract_exception_types_for_call (as_a (stmt), ret_vector); + return !ret_vector->is_empty (); + + default: + return false; + } +} /* Return true if statement STMT within FUN could throw an exception. */ diff --git a/gcc/tree-eh.h b/gcc/tree-eh.h index 2d3f765..f3b2c16 100644 --- a/gcc/tree-eh.h +++ b/gcc/tree-eh.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see typedef struct eh_region_d *eh_region; +typedef struct eh_landing_pad_d *eh_landing_pad; extern void using_eh_for_cleanups (void); extern void add_stmt_to_eh_lp (gimple *, int); @@ -30,6 +31,8 @@ extern bool remove_stmt_from_eh_lp (gimple *); extern int lookup_stmt_eh_lp_fn (struct function *, const gimple *); extern int lookup_stmt_eh_lp (const gimple *); extern bool make_eh_dispatch_edges (geh_dispatch *); +extern bool match_lp (eh_landing_pad, vec *); +extern void update_stmt_eh_region(gimple *); extern edge make_eh_edge (gimple *); extern edge redirect_eh_edge (edge, basic_block); extern void redirect_eh_dispatch_edge (geh_dispatch *, edge, basic_block); @@ -38,6 +41,8 @@ extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool, extern bool operation_could_trap_p (enum tree_code, bool, bool, tree); extern bool tree_could_trap_p (tree); extern tree rewrite_to_non_trapping_overflow (tree); +extern void extract_exception_types_for_call (gcall *, vec *); +extern bool stmt_throw_types (function *, gimple *, vec *); extern bool stmt_could_throw_p (function *, gimple *); extern bool stmt_unremovable_because_of_non_call_eh_p (function *, gimple *); extern bool tree_could_throw_p (tree); -- cgit v1.1 From c16d4a0ae162abc00d97bb73e598ca00d16cf555 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 27 Aug 2024 13:50:32 +0200 Subject: Fix handling of types * ipa-devirt.cc (odr_equivalent_or_derived_p): New. * ipa-utils.h (odr_equivalent_or_derived_p): Declare. * tree-eh.cc (same_or_derived_type): New. (match_lp): Use it. --- gcc/ipa-devirt.cc | 24 ++++++++++++++++++++++++ gcc/ipa-utils.h | 1 + gcc/tree-eh.cc | 26 +++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ipa-devirt.cc b/gcc/ipa-devirt.cc index a7ce434..d6cfcf2 100644 --- a/gcc/ipa-devirt.cc +++ b/gcc/ipa-devirt.cc @@ -1211,6 +1211,30 @@ skip_in_fields_list_p (tree t) return false; } +/* Return true if T2 is derived form T1. */ + +bool +odr_equivalent_or_derived_p (tree t1, tree t2) +{ + if (in_lto_p) + { + if (odr_types_equivalent_p (t1, t2)) + return true; + } + else + { + if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) + return true; + } + if (!TYPE_BINFO (t2)) + return false; + for (unsigned int i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (t2)); i++) + if (odr_equivalent_or_derived_p + (t1, BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (t2), i)))) + return true; + return false; +} + /* Compare T1 and T2, report ODR violations if WARN is true and set WARNED to true if anything is reported. Return true if types match. If true is returned, the types are also compatible in the sense of diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index d1da9c3..908b425 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -106,6 +106,7 @@ cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT, void warn_types_mismatch (tree t1, tree t2, location_t loc1 = UNKNOWN_LOCATION, location_t loc2 = UNKNOWN_LOCATION); bool odr_or_derived_type_p (const_tree t); +bool odr_equivalent_or_derived_p (tree t1, tree t2); bool odr_types_equivalent_p (tree type1, tree type2); bool odr_type_violation_reported_p (tree type); tree prevailing_odr_type (tree type); diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index eec1e6a..ab8e009 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -47,6 +47,8 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "gimplify.h" +#include "print-tree.h" +#include "ipa-utils.h" /* In some instances a tree and a gimple need to be stored in a same table, i.e. in hash tables. This is a structure to do this. */ @@ -2270,6 +2272,25 @@ make_eh_dispatch_edges (geh_dispatch *stmt) return true; } +bool +same_or_derived_type (tree t1, tree t2) +{ + t1 = TYPE_MAIN_VARIANT (t1); + t2 = TYPE_MAIN_VARIANT (t2); + if (t1 == t2) + return true; + while ((TREE_CODE (t1) == POINTER_TYPE || TREE_CODE (t1) == REFERENCE_TYPE) + && TREE_CODE (t1) == TREE_CODE (t2)) + { + t1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1)); + t2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2)); + } + if (t1 == t2) + return true; + if (!AGGREGATE_TYPE_P (t1) || !AGGREGATE_TYPE_P (t2)) + return false; + return odr_equivalent_or_derived_p (t1, t2); +} // Check if a landing pad can handle any of the given exception types bool match_lp(eh_landing_pad lp, vec *exception_types) { @@ -2282,11 +2303,14 @@ bool match_lp(eh_landing_pad lp, vec *exception_types) { while (catch_handler) { tree type_list = catch_handler->type_list; + if (!type_list) + return true; + for (tree t = type_list; t; t = TREE_CHAIN(t)) { tree type = TREE_VALUE(t); for (unsigned i = 0; i < exception_types->length(); ++i) { // match found or a catch-all handler (NULL) - if (type == (*exception_types)[i] || !type) { + if (!type || same_or_derived_type ((*exception_types)[i], type)) { return true; } } -- cgit v1.1