https://gcc.gnu.org/g:9a70651a2126e4aceefd2ebec63c0cf15ce83695

commit 9a70651a2126e4aceefd2ebec63c0cf15ce83695
Author: Pranil Dey <mkd...@gmail.com>
Date:   Tue Aug 20 22:07:57 2024 +0530

    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.

Diff:
---
 gcc/tree-cfg.cc |   5 ++-
 gcc/tree-eh.cc  | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-eh.h   |   5 +++
 3 files changed, 122 insertions(+), 2 deletions(-)

diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index fcb488d87113..964376d30dcc 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 9609bdc0d9b7..eec1e6af70d7 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<tree> *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<tree> 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<gimple *>(stmt)) = 
lp->index;
+                return;
+
+            case ERT_TRY:
+                if (match_lp(lp, &exception_types)) {
+                    *cfun->eh->throw_stmt_table->get(const_cast<gimple 
*>(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<tree> 
*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<tree> *ret_vector) {
+    if (!flag_exceptions) {
+        return false;
+    }
+
+    switch (gimple_code (stmt)) {
+        case GIMPLE_CALL:
+            extract_exception_types_for_call (as_a<gcall*> (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 2d3f765182a5..f3b2c16ed77e 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<tree> *);
+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<tree> *);
+extern bool stmt_throw_types (function *, gimple *, vec<tree> *);
 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);

Reply via email to