OSDN Git Service

* builtins.c (expand_builtin_setjmp): Delete.
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 29 Sep 2006 06:32:58 +0000 (06:32 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 29 Sep 2006 06:32:58 +0000 (06:32 +0000)
(expand_builtin) <BUILT_IN_SETJMP>: Mark as unreachable.
<BUILT_IN_SETJMP_SETUP>: New case.
<BUILT_IN_SETJMP_DISPATCHER>: Likewise.
<BUILT_IN_SETJMP_RECEIVER>: Likewise.
* builtins.def (BUILT_IN_SETJMP_SETUP): New built-in stub.
(BUILT_IN_SETJMP_DISPATCHER): Likewise.
(BUILT_IN_SETJMP_RECEIVER): Likewise.
* gimple-low.c (struct lower_data): New field calls_builtin_setjmp.
(lower_function_body): Initialize it to false.  If it is set to true
at the end of the processing, emit the setjmp dispatcher.
(lower_stmt) <CALL_EXPR>: Invoke lower_builtin_setjmp if the callee
is __builtin_setjmp and set calls_builtin_setjmp to true as well.
<MODIFY_EXPR>: Fall through to above case if there is a CALL_EXPR
on the rhs of the assignment.
(lower_builtin_setjmp): New function.
* tree.c (build_common_builtin_nodes): Build BUILT_IN_SETJMP_SETUP,
BUILT_IN_SETJMP_DISPATCHER and BUILT_IN_SETJMP_RECEIVER nodes.
* tree-cfg.c (make_exit_edges) <CALL_EXPR>: Use specific predicate
to detect calls that can go to non-local labels.  Use specific
helper to create the abnormal edges associated with them.
<MODIFY_EXPR>: Likewise.
(make_abnormal_goto_edges): New function extracted from...
(make_goto_expr_edges): ...here.  Call it for computed gotos.
(simple_goto_p): Minor tweak.
(tree_can_make_abnormal_goto): New predicate.
(tree_redirect_edge_and_branch): Return zero on all abnormal edges.
(tree_purge_dead_abnormal_call_edges): New function.
* tree-flow.h (tree_can_make_abnormal_goto): Declare.
(tree_purge_dead_abnormal_call_edges): Likewise.
(make_abnormal_goto_edges): Likewise.
* tree-inline.c (expand_call_inline): Simplify statement frobbing.
Purge all dead abnormal edges if the call was in the last statement.
* tree-optimize.c (has_abnormal_outgoing_edge_p): New predicate.
(execute_fixup_cfg): If there are non-local labels in the function,
scan the basic blocks and split them at calls that can go to non-local
labels or add missing abnormal call edges.  Write down the CFG in the
dump file.
(pass_fixup_cfg): Remove TODO_dump_func flag.
* unwind-sjlj.c: Poison setjmp.
* doc/install.texi (enable-sjlj-exceptions): Use more general wording.
* doc/tm.texi (DWARF2_UNWIND_INFO): Likewise.
(TARGET_UNWIND_TABLES_DEFAULT): Fix typo.
(DONT_USE_BUILTIN_SETJMP): Document it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@117298 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/doc/install.texi
gcc/doc/tm.texi
gcc/gimple-low.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/non-local-goto-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/non-local-goto-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/setjmp-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/setjmp-4.c [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-flow.h
gcc/tree-inline.c
gcc/tree-optimize.c
gcc/tree.c
gcc/unwind-sjlj.c

index c4161a0..3f96481 100644 (file)
@@ -1,3 +1,50 @@
+2006-09-28  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * builtins.c (expand_builtin_setjmp): Delete.
+       (expand_builtin) <BUILT_IN_SETJMP>: Mark as unreachable.
+       <BUILT_IN_SETJMP_SETUP>: New case.
+       <BUILT_IN_SETJMP_DISPATCHER>: Likewise.
+       <BUILT_IN_SETJMP_RECEIVER>: Likewise.
+       * builtins.def (BUILT_IN_SETJMP_SETUP): New built-in stub.
+       (BUILT_IN_SETJMP_DISPATCHER): Likewise.
+       (BUILT_IN_SETJMP_RECEIVER): Likewise.
+       * gimple-low.c (struct lower_data): New field calls_builtin_setjmp.
+       (lower_function_body): Initialize it to false.  If it is set to true
+       at the end of the processing, emit the setjmp dispatcher.
+       (lower_stmt) <CALL_EXPR>: Invoke lower_builtin_setjmp if the callee
+       is __builtin_setjmp and set calls_builtin_setjmp to true as well.
+       <MODIFY_EXPR>: Fall through to above case if there is a CALL_EXPR
+       on the rhs of the assignment.
+       (lower_builtin_setjmp): New function.
+       * tree.c (build_common_builtin_nodes): Build BUILT_IN_SETJMP_SETUP,
+       BUILT_IN_SETJMP_DISPATCHER and BUILT_IN_SETJMP_RECEIVER nodes.
+       * tree-cfg.c (make_exit_edges) <CALL_EXPR>: Use specific predicate
+       to detect calls that can go to non-local labels.  Use specific
+       helper to create the abnormal edges associated with them.
+       <MODIFY_EXPR>: Likewise.
+       (make_abnormal_goto_edges): New function extracted from...
+       (make_goto_expr_edges): ...here.  Call it for computed gotos.
+       (simple_goto_p): Minor tweak.
+       (tree_can_make_abnormal_goto): New predicate.
+       (tree_redirect_edge_and_branch): Return zero on all abnormal edges.
+       (tree_purge_dead_abnormal_call_edges): New function.
+       * tree-flow.h (tree_can_make_abnormal_goto): Declare.
+       (tree_purge_dead_abnormal_call_edges): Likewise.
+       (make_abnormal_goto_edges): Likewise.
+       * tree-inline.c (expand_call_inline): Simplify statement frobbing.
+       Purge all dead abnormal edges if the call was in the last statement.
+       * tree-optimize.c (has_abnormal_outgoing_edge_p): New predicate.
+       (execute_fixup_cfg): If there are non-local labels in the function,
+       scan the basic blocks and split them at calls that can go to non-local
+       labels or add missing abnormal call edges.  Write down the CFG in the
+       dump file.
+       (pass_fixup_cfg): Remove TODO_dump_func flag.
+       * unwind-sjlj.c: Poison setjmp.
+       * doc/install.texi (enable-sjlj-exceptions): Use more general wording.
+       * doc/tm.texi (DWARF2_UNWIND_INFO): Likewise.
+       (TARGET_UNWIND_TABLES_DEFAULT): Fix typo.
+       (DONT_USE_BUILTIN_SETJMP): Document it.
+
 2006-09-28  Geoffrey Keating  <geoffk@apple.com>
 
        PR target/28617
index 4684a54..8fb58ca 100644 (file)
@@ -81,7 +81,6 @@ static int apply_result_size (void);
 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
 static rtx result_vector (int, rtx);
 #endif
-static rtx expand_builtin_setjmp (tree, rtx);
 static void expand_builtin_update_setjmp_buf (rtx);
 static void expand_builtin_prefetch (tree);
 static rtx expand_builtin_apply_args (void);
@@ -608,8 +607,8 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
 static HOST_WIDE_INT setjmp_alias_set = -1;
 
 /* Construct the leading half of a __builtin_setjmp call.  Control will
-   return to RECEIVER_LABEL.  This is used directly by sjlj exception
-   handling code.  */
+   return to RECEIVER_LABEL.  This is also called directly by the SJLJ
+   exception handling code.  */
 
 void
 expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
@@ -660,8 +659,8 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
   current_function_has_nonlocal_label = 1;
 }
 
-/* Construct the trailing part of a __builtin_setjmp call.
-   This is used directly by sjlj exception handling code.  */
+/* Construct the trailing part of a __builtin_setjmp call.  This is
+   also called directly by the SJLJ exception handling code.  */
 
 void
 expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
@@ -729,73 +728,10 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
   emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
 }
 
-/* __builtin_setjmp is passed a pointer to an array of five words (not
-   all will be used on all machines).  It operates similarly to the C
-   library function of the same name, but is more efficient.  Much of
-   the code below (and for longjmp) is copied from the handling of
-   non-local gotos.
-
-   NOTE: This is intended for use by GNAT and the exception handling
-   scheme in the compiler and will only work in the method used by
-   them.  */
-
-static rtx
-expand_builtin_setjmp (tree arglist, rtx target)
-{
-  rtx buf_addr, next_lab, cont_lab;
-
-  if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-
-  if (target == 0 || !REG_P (target)
-      || REGNO (target) < FIRST_PSEUDO_REGISTER)
-    target = gen_reg_rtx (TYPE_MODE (integer_type_node));
-
-  buf_addr = expand_normal (TREE_VALUE (arglist));
-
-  next_lab = gen_label_rtx ();
-  cont_lab = gen_label_rtx ();
-
-  expand_builtin_setjmp_setup (buf_addr, next_lab);
-
-  /* Set TARGET to zero and branch to the continue label.  Use emit_jump to
-     ensure that pending stack adjustments are flushed.  */
-  emit_move_insn (target, const0_rtx);
-  emit_jump (cont_lab);
-
-  emit_label (next_lab);
-
-  /* Because setjmp and longjmp are not represented in the CFG, a cfgcleanup
-     may find that the basic block starting with NEXT_LAB is unreachable.
-     The whole block, along with NEXT_LAB, would be removed (see PR26983).
-     Make sure that never happens.  */
-  LABEL_PRESERVE_P (next_lab) = 1;
-     
-  expand_builtin_setjmp_receiver (next_lab);
-
-  /* Set TARGET to one.  */
-  emit_move_insn (target, const1_rtx);
-  emit_label (cont_lab);
-
-  /* Tell flow about the strange goings on.  Putting `next_lab' on
-     `nonlocal_goto_handler_labels' to indicates that function
-     calls may traverse the arc back to this label.  */
-
-  current_function_has_nonlocal_label = 1;
-  nonlocal_goto_handler_labels
-    = gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
-
-  return target;
-}
-
 /* __builtin_longjmp is passed a pointer to an array of five words (not
    all will be used on all machines).  It operates similarly to the C
    library function of the same name, but is more efficient.  Much of
-   the code below is copied from the handling of non-local gotos.
-
-   NOTE: This is intended for use by GNAT and the exception handling
-   scheme in the compiler and will only work in the method used by
-   them.  */
+   the code below is copied from the handling of non-local gotos.  */
 
 static void
 expand_builtin_longjmp (rtx buf_addr, rtx value)
@@ -6077,18 +6013,63 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_SETJMP:
-      target = expand_builtin_setjmp (arglist, target);
-      if (target)
-       return target;
+      /* This should have been lowered to the builtins below.  */
+      gcc_unreachable ();
+
+    case BUILT_IN_SETJMP_SETUP:
+      /* __builtin_setjmp_setup is passed a pointer to an array of five words
+          and the receiver label.  */
+      if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+       {
+         rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
+                                     VOIDmode, EXPAND_NORMAL);
+         tree label = TREE_OPERAND (TREE_VALUE (TREE_CHAIN (arglist)), 0);
+         rtx label_r = label_rtx (label);
+
+         /* This is copied from the handling of non-local gotos.  */
+         expand_builtin_setjmp_setup (buf_addr, label_r);
+         nonlocal_goto_handler_labels
+           = gen_rtx_EXPR_LIST (VOIDmode, label_r,
+                                nonlocal_goto_handler_labels);
+         /* ??? Do not let expand_label treat us as such since we would
+            not want to be both on the list of non-local labels and on
+            the list of forced labels.  */
+         FORCED_LABEL (label) = 0;
+         return const0_rtx;
+       }
+      break;
+
+    case BUILT_IN_SETJMP_DISPATCHER:
+       /* __builtin_setjmp_dispatcher is passed the dispatcher label.  */
+      if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
+       {
+         tree label = TREE_OPERAND (TREE_VALUE (arglist), 0);
+         rtx label_r = label_rtx (label);
+
+         /* Remove the dispatcher label from the list of non-local labels
+            since the receiver labels have been added to it above.  */
+         remove_node_from_expr_list (label_r, &nonlocal_goto_handler_labels);
+         return const0_rtx;
+       }
+      break;
+
+    case BUILT_IN_SETJMP_RECEIVER:
+       /* __builtin_setjmp_receiver is passed the receiver label.  */
+      if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
+       {
+         tree label = TREE_OPERAND (TREE_VALUE (arglist), 0);
+         rtx label_r = label_rtx (label);
+
+         expand_builtin_setjmp_receiver (label_r);
+         return const0_rtx;
+       }
       break;
 
       /* __builtin_longjmp is passed a pointer to an array of five words.
         It's similar to the C library longjmp function but works with
         __builtin_setjmp above.  */
     case BUILT_IN_LONGJMP:
-      if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-       break;
-      else
+      if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
        {
          rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
                                      VOIDmode, EXPAND_NORMAL);
@@ -6103,6 +6084,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
          expand_builtin_longjmp (buf_addr, value);
          return const0_rtx;
        }
+      break;
 
     case BUILT_IN_NONLOCAL_GOTO:
       target = expand_builtin_nonlocal_goto (arglist);
index 2dcbd39..0e73cf4 100644 (file)
@@ -690,6 +690,11 @@ DEF_BUILTIN_STUB (BUILT_IN_INIT_TRAMPOLINE, "__builtin_init_trampoline")
 DEF_BUILTIN_STUB (BUILT_IN_ADJUST_TRAMPOLINE, "__builtin_adjust_trampoline")
 DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto")
 
+/* Implementing __builtin_setjmp.  */
+DEF_BUILTIN_STUB (BUILT_IN_SETJMP_SETUP, "__builtin_setjmp_setup")
+DEF_BUILTIN_STUB (BUILT_IN_SETJMP_DISPATCHER, "__builtin_setjmp_dispatcher")
+DEF_BUILTIN_STUB (BUILT_IN_SETJMP_RECEIVER, "__builtin_setjmp_receiver")
+
 /* Implementing variable sized local variables.  */
 DEF_BUILTIN_STUB (BUILT_IN_STACK_SAVE, "__builtin_stack_save")
 DEF_BUILTIN_STUB (BUILT_IN_STACK_RESTORE, "__builtin_stack_restore")
index 66ec7ca..1925b55 100644 (file)
@@ -1456,9 +1456,9 @@ file to compile into a @file{.class} file.
 Search for libiconv in @file{DIR/include} and @file{DIR/lib}.
 
 @item --enable-sjlj-exceptions
-Force use of @code{builtin_setjmp} for exceptions.  @samp{configure}
-ordinarily picks the correct value based on the platform.  Only use
-this option if you are sure you need a different setting.
+Force use of the @code{setjmp}/@code{longjmp}-based scheme for exceptions.
+@samp{configure} ordinarily picks the correct value based on the platform.
+Only use this option if you are sure you need a different setting.
 
 @item --with-system-zlib
 Use installed @samp{zlib} rather than that included with GCC@.
index 44f1aaa..c724a49 100644 (file)
@@ -7924,8 +7924,7 @@ Define this macro to 0 if your target supports DWARF 2 frame unwind
 information, but it does not yet work with exception handling.
 Otherwise, if your target supports this information (if it defines
 @samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
-or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of
-1.
+or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of 1.
 
 If @code{TARGET_UNWIND_INFO} is defined, the target specific unwinder
 will be used in all cases.  Defining this macro will enable the generation
@@ -7933,7 +7932,8 @@ of DWARF 2 frame debugging information.
 
 If @code{TARGET_UNWIND_INFO} is not defined, and this macro is defined to 1,
 the DWARF 2 unwinder will be the default exception handling mechanism;
-otherwise, @code{setjmp}/@code{longjmp} will be used by default.
+otherwise, the @code{setjmp}/@code{longjmp}-based scheme will be used by
+default.
 @end defmac
 
 @defmac TARGET_UNWIND_INFO
@@ -7941,7 +7941,7 @@ Define this macro if your target has ABI specified unwind tables.  Usually
 these will be output by @code{TARGET_UNWIND_EMIT}.
 @end defmac
 
-@deftypevar {Target Hook} bool TARGET_UNWID_TABLES_DEFAULT
+@deftypevar {Target Hook} bool TARGET_UNWIND_TABLES_DEFAULT
 This variable should be set to @code{true} if the target ABI requires unwinding
 tables even when exceptions are not used.
 @end deftypevar
@@ -7949,8 +7949,14 @@ tables even when exceptions are not used.
 @defmac MUST_USE_SJLJ_EXCEPTIONS
 This macro need only be defined if @code{DWARF2_UNWIND_INFO} is
 runtime-variable.  In that case, @file{except.h} cannot correctly
-determine the corresponding definition of
-@code{MUST_USE_SJLJ_EXCEPTIONS}, so the target must provide it directly.
+determine the corresponding definition of @code{MUST_USE_SJLJ_EXCEPTIONS},
+so the target must provide it directly.
+@end defmac
+
+@defmac DONT_USE_BUILTIN_SETJMP
+Define this macro to 1 if the @code{setjmp}/@code{longjmp}-based scheme
+should use the @code{setjmp}/@code{longjmp} functions from the C library
+instead of the @code{__builtin_setjmp}/@code{__builtin_longjmp} machinery.
 @end defmac
 
 @defmac DWARF_CIE_DATA_ALIGNMENT
index ff6b8b2..c6a0312 100644 (file)
@@ -49,14 +49,18 @@ struct lower_data
   /* A TREE_LIST of label and return statements to be moved to the end
      of the function.  */
   tree return_statements;
+
+  /* True if the function calls __builtin_setjmp.  */
+  bool calls_builtin_setjmp;
 };
 
 static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
 static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *);
 static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *);
 static void lower_return_expr (tree_stmt_iterator *, struct lower_data *);
+static void lower_builtin_setjmp (tree_stmt_iterator *);
 
-/* Lowers the body of current_function_decl.  */
+/* Lower the body of current_function_decl.  */
 
 static unsigned int
 lower_function_body (void)
@@ -113,6 +117,35 @@ lower_function_body (void)
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
     }
 
+  /* If the function calls __builtin_setjmp, we need to emit the computed
+     goto that will serve as the unique dispatcher for all the receivers.  */
+  if (data.calls_builtin_setjmp)
+    {
+      tree disp_label, disp_var, arg;
+
+      /* Build 'DISP_LABEL:' and insert.  */
+      disp_label = create_artificial_label ();
+      /* This mark will create forward edges from every call site.  */
+      DECL_NONLOCAL (disp_label) = 1;
+      current_function_has_nonlocal_label = 1;
+      x = build1 (LABEL_EXPR, void_type_node, disp_label);
+      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+
+      /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);'
+        and insert.  */
+      disp_var = create_tmp_var (ptr_type_node, "setjmpvar");
+      t = build_addr (disp_label, current_function_decl);
+      arg = tree_cons (NULL, t, NULL);
+      t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER];
+      t = build_function_call_expr (t,arg);
+      x = build2 (MODIFY_EXPR, void_type_node, disp_var, t);
+
+      /* Build 'goto DISP_VAR;' and insert.  */
+      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+      x = build1 (GOTO_EXPR, void_type_node, disp_var);
+      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
+    }
+
   gcc_assert (data.block == DECL_INITIAL (current_function_decl));
   BLOCK_SUBBLOCKS (data.block)
     = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
@@ -139,7 +172,7 @@ struct tree_opt_pass pass_lower_cf =
 };
 
 
-/* Lowers the EXPR.  Unlike gimplification the statements are not relowered
+/* Lower the EXPR.  Unlike gimplification the statements are not relowered
    when they are changed -- if this has to be done, the lowering routine must
    do it explicitly.  DATA is passed through the recursion.  */
 
@@ -171,7 +204,7 @@ lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data)
 }
 
 
-/* Lowers statement TSI.  DATA is passed through the recursion.  */
+/* Lower statement TSI.  DATA is passed through the recursion.  */
 
 static void
 lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
@@ -207,8 +240,6 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
       
     case NOP_EXPR:
     case ASM_EXPR:
-    case MODIFY_EXPR:
-    case CALL_EXPR:
     case GOTO_EXPR:
     case LABEL_EXPR:
     case SWITCH_EXPR:
@@ -223,6 +254,27 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
     case OMP_CONTINUE:
       break;
 
+    case MODIFY_EXPR:
+      if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
+       stmt = TREE_OPERAND (stmt, 1);
+      else
+       break;
+      /* FALLTHRU */
+
+    case CALL_EXPR:
+      {
+       tree decl = get_callee_fndecl (stmt);
+       if (decl
+           && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+           && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
+         {
+           data->calls_builtin_setjmp = true;
+           lower_builtin_setjmp (tsi);
+           return;
+         }
+      }
+      break;
+
     case OMP_PARALLEL:
       lower_omp_directive (tsi, data);
       return;
@@ -234,7 +286,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
   tsi_next (tsi);
 }
 
-/* Lowers a bind_expr TSI.  DATA is passed through the recursion.  */
+/* Lower a bind_expr TSI.  DATA is passed through the recursion.  */
 
 static void
 lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
@@ -403,7 +455,7 @@ block_may_fallthru (tree block)
     }
 }
 
-/* Lowers a cond_expr TSI.  DATA is passed through the recursion.  */
+/* Lower a cond_expr TSI.  DATA is passed through the recursion.  */
 
 static void
 lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
@@ -498,6 +550,8 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
   tsi_next (tsi);
 }
 
+/* Lower a return_expr TSI.  DATA is passed through the recursion.  */
+
 static void
 lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
 {
@@ -534,6 +588,129 @@ lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
   tsi_link_before (tsi, t, TSI_SAME_STMT);
   tsi_delink (tsi);
 }
+
+/* Lower a __builtin_setjmp TSI.
+
+   __builtin_setjmp is passed a pointer to an array of five words (not
+   all will be used on all machines).  It operates similarly to the C
+   library function of the same name, but is more efficient.
+
+   It is lowered into 3 other builtins, namely __builtin_setjmp_setup,
+   __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with
+   __builtin_setjmp_dispatcher shared among all the instances; that's
+   why it is only emitted at the end by lower_function_body.
+
+   After full lowering, the body of the function should look like:
+
+    {
+      void * setjmpvar.0;
+      int D.1844;
+      int D.2844;
+
+      [...]
+
+      __builtin_setjmp_setup (&buf, &<D1847>);
+      D.1844 = 0;
+      goto <D1846>;
+      <D1847>:;
+      __builtin_setjmp_receiver (&<D1847>);
+      D.1844 = 1;
+      <D1846>:;
+      if (D.1844 == 0) goto <D1848>; else goto <D1849>;
+
+      [...]
+
+      __builtin_setjmp_setup (&buf, &<D2847>);
+      D.2844 = 0;
+      goto <D2846>;
+      <D2847>:;
+      __builtin_setjmp_receiver (&<D2847>);
+      D.2844 = 1;
+      <D2846>:;
+      if (D.2844 == 0) goto <D2848>; else goto <D2849>;
+
+      [...]
+
+      <D3850>:;
+      return;
+      <D3853>: [non-local];
+      setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>);
+      goto setjmpvar.0;
+    }
+
+   The dispatcher block will be both the unique destination of all the
+   abnormal call edges and the unique source of all the abnormal edges
+   to the receivers, thus keeping the complexity explosion localized.  */
+
+static void
+lower_builtin_setjmp (tree_stmt_iterator *tsi)
+{
+  tree stmt = tsi_stmt (*tsi);
+  tree cont_label = create_artificial_label ();
+  tree next_label = create_artificial_label ();
+  tree dest, t, arg;
+
+  /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
+     passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
+  FORCED_LABEL (next_label) = 1;
+
+  if (TREE_CODE (stmt) == MODIFY_EXPR)
+    {
+      dest = TREE_OPERAND (stmt, 0);
+      stmt = TREE_OPERAND (stmt, 1);
+    }
+  else
+    dest = NULL_TREE;
+
+  /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert.  */
+  t = build_addr (next_label, current_function_decl);
+  arg = tree_cons (NULL, t, NULL);
+  t = TREE_VALUE (TREE_OPERAND (stmt, 1));
+  arg = tree_cons (NULL, t, arg);
+  t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP];
+  t = build_function_call_expr (t, arg);
+  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
+  tsi_link_before (tsi, t, TSI_SAME_STMT);
+
+  /* Build 'DEST = 0' and insert.  */
+  if (dest)
+    {
+      t = build2 (MODIFY_EXPR, void_type_node, dest, integer_zero_node);
+      SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
+      tsi_link_before (tsi, t, TSI_SAME_STMT);
+    }
+
+  /* Build 'goto CONT_LABEL' and insert.  */
+  t = build1 (GOTO_EXPR, void_type_node, cont_label);
+  tsi_link_before (tsi, t, TSI_SAME_STMT);
+
+  /* Build 'NEXT_LABEL:' and insert.  */
+  t = build1 (LABEL_EXPR, void_type_node, next_label);
+  tsi_link_before (tsi, t, TSI_SAME_STMT);
+
+  /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert.  */
+  t = build_addr (next_label, current_function_decl);
+  arg = tree_cons (NULL, t, NULL);
+  t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER];
+  t = build_function_call_expr (t, arg);
+  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
+  tsi_link_before (tsi, t, TSI_SAME_STMT);
+
+  /* Build 'DEST = 1' and insert.  */
+  if (dest)
+    {
+      t = build2 (MODIFY_EXPR, void_type_node, dest, integer_one_node);
+      SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
+      tsi_link_before (tsi, t, TSI_SAME_STMT);
+    }
+
+  /* Build 'CONT_LABEL:' and insert.  */
+  t = build1 (LABEL_EXPR, void_type_node, cont_label);
+  tsi_link_before (tsi, t, TSI_SAME_STMT);
+
+  /* Remove the call to __builtin_setjmp.  */
+  tsi_delink (tsi);
+}
 \f
 
 /* Record the variables in VARS into function FN.  */
index 112f6fe..d59cd1b 100644 (file)
@@ -1,5 +1,12 @@
 2006-09-28  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * gcc.dg/non-local-goto-1.c: New test.
+       * gcc.dg/non-local-goto-2.c: Likewise.
+       * gcc.dg/setjmp-3.c: Likewise.
+       * gcc.dg/setjmp-4.c: Likewise.
+
+2006-09-28  Eric Botcazou  <ebotcazou@adacore.com>
+
        * gnat.dg/self_aggregate_with_pointer.adb: New test.
 
 2006-09-27  Steven G. Kargl  <kargls@gcc.gnu.org>
diff --git a/gcc/testsuite/gcc.dg/non-local-goto-1.c b/gcc/testsuite/gcc.dg/non-local-goto-1.c
new file mode 100644 (file)
index 0000000..2bace07
--- /dev/null
@@ -0,0 +1,56 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+int global;
+
+static foo(void) __attribute__((noinline));
+
+static foo(void)
+{
+  global = 1;
+}
+
+static bar(void)
+{
+  foo ();
+}
+
+int execute(int cmd)
+{
+  __label__ start;
+
+  void raise(void)
+  {
+    goto start;
+  }
+
+  int last;
+
+  bar ();
+
+  last = 0;
+
+start:
+
+  if (last == 0)
+    while (1)
+      {
+        last = 1;
+        raise ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/non-local-goto-2.c b/gcc/testsuite/gcc.dg/non-local-goto-2.c
new file mode 100644 (file)
index 0000000..24ed650
--- /dev/null
@@ -0,0 +1,57 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void);
+
+int global;
+
+static foo(void) __attribute__((noinline));
+
+static foo(void)
+{
+  global = 1;
+}
+
+static bar(void)
+{
+  foo ();
+  global = 0;
+}
+
+int execute(int cmd)
+{
+  __label__ start;
+
+  void raise(void)
+  {
+    goto start;
+  }
+
+  int last;
+
+  bar ();
+
+  last = 0;
+
+start:
+
+  if (last == 0)
+    while (1)
+      {
+        last = 1;
+        raise ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/setjmp-3.c b/gcc/testsuite/gcc.dg/setjmp-3.c
new file mode 100644 (file)
index 0000000..94dc590
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+#include <setjmp.h>
+
+extern void abort (void);
+
+jmp_buf buf;
+
+void raise(void)
+{
+  __builtin_longjmp (buf, 1);
+}
+
+int execute(int cmd)
+{
+  int last = 0;
+
+  if (__builtin_setjmp (buf) == 0)
+    while (1)
+      {
+        last = 1;
+        raise ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/setjmp-4.c b/gcc/testsuite/gcc.dg/setjmp-4.c
new file mode 100644 (file)
index 0000000..b4a917b
--- /dev/null
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+#include <setjmp.h>
+
+extern void abort (void);
+
+jmp_buf buf;
+
+void raise(void)
+{
+  __builtin_longjmp (buf, 1);
+}
+
+int execute(int cmd)
+{
+  int last = 0;
+
+  __builtin_setjmp (buf);
+
+  if (last == 0)
+    while (1)
+      {
+        last = 1;
+        raise ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    abort ();
+
+  return 0;
+}
index 67d0491..46ee1b1 100644 (file)
@@ -489,9 +489,8 @@ make_edges (void)
              /* If this function receives a nonlocal goto, then we need to
                 make edges from this call site to all the nonlocal goto
                 handlers.  */
-             if (TREE_SIDE_EFFECTS (last)
-                 && current_function_has_nonlocal_label)
-               make_goto_expr_edges (bb);
+             if (tree_can_make_abnormal_goto (last))
+               make_abnormal_goto_edges (bb, true);
 
              /* If this statement has reachable exception handlers, then
                 create abnormal edges to them.  */
@@ -507,10 +506,8 @@ make_edges (void)
                  /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the
                     CALL_EXPR may have an abnormal edge.  Search the RHS for
                     this case and create any required edges.  */
-                 tree op = get_call_expr_in (last);
-                 if (op && TREE_SIDE_EFFECTS (op)
-                     && current_function_has_nonlocal_label)
-                   make_goto_expr_edges (bb);
+                 if (tree_can_make_abnormal_goto (last))
+                   make_abnormal_goto_edges (bb, true);  
 
                  make_eh_edges (last);
                }
@@ -836,76 +833,60 @@ label_to_block_fn (struct function *ifun, tree dest)
   return VEC_index (basic_block, ifun->cfg->x_label_to_block_map, uid);
 }
 
+/* Create edges for an abnormal goto statement at block BB.  If FOR_CALL
+   is true, the source statement is a CALL_EXPR instead of a GOTO_EXPR.  */
+
+void
+make_abnormal_goto_edges (basic_block bb, bool for_call)
+{
+  basic_block target_bb;
+  block_stmt_iterator bsi;
+
+  FOR_EACH_BB (target_bb)
+    for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       tree target = bsi_stmt (bsi);
+
+       if (TREE_CODE (target) != LABEL_EXPR)
+         break;
+
+       target = LABEL_EXPR_LABEL (target);
+
+       /* Make an edge to every label block that has been marked as a
+          potential target for a computed goto or a non-local goto.  */
+       if ((FORCED_LABEL (target) && !for_call)
+           || (DECL_NONLOCAL (target) && for_call))
+         {
+           make_edge (bb, target_bb, EDGE_ABNORMAL);
+           break;
+         }
+      }
+}
+
 /* Create edges for a goto statement at block BB.  */
 
 static void
 make_goto_expr_edges (basic_block bb)
 {
-  tree goto_t;
-  basic_block target_bb;
-  bool for_call;
   block_stmt_iterator last = bsi_last (bb);
+  tree goto_t = bsi_stmt (last);
 
-  goto_t = bsi_stmt (last);
-
-  /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
-     CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
-     from a nonlocal goto.  */
-  if (TREE_CODE (goto_t) != GOTO_EXPR)
-    for_call = true;
-  else
+  /* A simple GOTO creates normal edges.  */
+  if (simple_goto_p (goto_t))
     {
       tree dest = GOTO_DESTINATION (goto_t);
-      for_call = false;
-
-      /* A GOTO to a local label creates normal edges.  */
-      if (simple_goto_p (goto_t))
-       {
-         edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+      edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
 #ifdef USE_MAPPED_LOCATION
-         e->goto_locus = EXPR_LOCATION (goto_t);
+      e->goto_locus = EXPR_LOCATION (goto_t);
 #else
-         e->goto_locus = EXPR_LOCUS (goto_t);
+      e->goto_locus = EXPR_LOCUS (goto_t);
 #endif
-         bsi_remove (&last, true);
-         return;
-       }
-
-      /* Nothing more to do for nonlocal gotos.  */
-      if (TREE_CODE (dest) == LABEL_DECL)
-       return;
-
-      /* Computed gotos remain.  */
+      bsi_remove (&last, true);
+      return;
     }
 
-  /* Look for the block starting with the destination label.  In the
-     case of a computed goto, make an edge to any label block we find
-     in the CFG.  */
-  FOR_EACH_BB (target_bb)
-    {
-      block_stmt_iterator bsi;
-
-      for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       {
-         tree target = bsi_stmt (bsi);
-
-         if (TREE_CODE (target) != LABEL_EXPR)
-           break;
-
-         if (
-             /* Computed GOTOs.  Make an edge to every label block that has
-                been marked as a potential target for a computed goto.  */
-             (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && !for_call)
-             /* Nonlocal GOTO target.  Make an edge to every label block
-                that has been marked as a potential target for a nonlocal
-                goto.  */
-             || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call))
-           {
-             make_edge (bb, target_bb, EDGE_ABNORMAL);
-             break;
-           }
-       }
-    }
+  /* A computed GOTO creates abnormal edges.  */
+  make_abnormal_goto_edges (bb, false);
 }
 
 
@@ -2517,13 +2498,31 @@ computed_goto_p (tree t)
 }
 
 
-/* Checks whether EXPR is a simple local goto.  */
+/* Return true if T is a simple local goto.  */
+
+bool
+simple_goto_p (tree t)
+{
+  return (TREE_CODE (t) == GOTO_EXPR
+         && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL);
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+   Transfers of control flow associated with EH are excluded.  */
 
 bool
-simple_goto_p (tree expr)
+tree_can_make_abnormal_goto (tree t)
 {
-  return (TREE_CODE (expr) == GOTO_EXPR
-         && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL);
+  if (computed_goto_p (t))
+    return true;
+  if (TREE_CODE (t) == MODIFY_EXPR)
+    t = TREE_OPERAND (t, 1);
+  if (TREE_CODE (t) == WITH_SIZE_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == CALL_EXPR)
+    return TREE_SIDE_EFFECTS (t) && current_function_has_nonlocal_label;
+  return false;
 }
 
 
@@ -4072,7 +4071,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
   edge ret;
   tree label, stmt;
 
-  if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
+  if (e->flags & EDGE_ABNORMAL)
     return NULL;
 
   if (e->src != ENTRY_BLOCK_PTR
@@ -5374,6 +5373,41 @@ tree_flow_call_edges_add (sbitmap blocks)
   return blocks_split;
 }
 
+/* Purge dead abnormal call edges from basic block BB.  */
+
+bool
+tree_purge_dead_abnormal_call_edges (basic_block bb)
+{
+  bool changed = tree_purge_dead_eh_edges (bb);
+
+  if (current_function_has_nonlocal_label)
+    {
+      tree stmt = last_stmt (bb);
+      edge_iterator ei;
+      edge e;
+
+      if (!(stmt && tree_can_make_abnormal_goto (stmt)))
+       for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+         {
+           if (e->flags & EDGE_ABNORMAL)
+             {
+               remove_edge (e);
+               changed = true;
+             }
+           else
+             ei_next (&ei);
+         }
+
+      /* See tree_purge_dead_eh_edges below.  */
+      if (changed)
+       free_dominance_info (CDI_DOMINATORS);
+    }
+
+  return changed;
+}
+
+/* Purge dead EH edges from basic block BB.  */
+
 bool
 tree_purge_dead_eh_edges (basic_block bb)
 {
index e8fa099..f70eb77 100644 (file)
@@ -564,6 +564,7 @@ extern bool is_ctrl_stmt (tree);
 extern bool is_ctrl_altering_stmt (tree);
 extern bool computed_goto_p (tree);
 extern bool simple_goto_p (tree);
+extern bool tree_can_make_abnormal_goto (tree);
 extern basic_block single_noncomplex_succ (basic_block bb);
 extern void tree_dump_bb (basic_block, FILE *, int);
 extern void debug_tree_bb (basic_block);
@@ -596,6 +597,7 @@ extern bool tree_duplicate_sese_region (edge, edge, basic_block *, unsigned,
                                        basic_block *);
 extern void add_phi_args_after_copy_bb (basic_block);
 extern void add_phi_args_after_copy (basic_block *, unsigned);
+extern bool tree_purge_dead_abnormal_call_edges (basic_block);
 extern bool tree_purge_dead_eh_edges (basic_block);
 extern bool tree_purge_all_dead_eh_edges (bitmap);
 extern tree gimplify_val (block_stmt_iterator *, tree, tree);
@@ -607,6 +609,7 @@ extern tree gimplify_build3 (block_stmt_iterator *, enum tree_code,
                             tree, tree, tree, tree);
 extern void init_empty_tree_cfg (void);
 extern void fold_cond_expr_cond (void);
+extern void make_abnormal_goto_edges (basic_block, bool);
 extern void replace_uses_by (tree, tree);
 extern void start_recording_case_labels (void);
 extern void end_recording_case_labels (void);
index baca834..61b1dab 100644 (file)
@@ -1930,6 +1930,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   edge e;
   block_stmt_iterator bsi, stmt_bsi;
   bool successfully_inlined = FALSE;
+  bool purge_dead_abnormal_edges;
   tree t_step;
   tree var;
 
@@ -2024,30 +2025,36 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
 #endif
 
   /* We will be inlining this callee.  */
-
   id->eh_region = lookup_stmt_eh_region (stmt);
 
   /* Split the block holding the CALL_EXPR.  */
-
   e = split_block (bb, stmt);
   bb = e->src;
   return_block = e->dest;
   remove_edge (e);
 
-  /* split_block splits before the statement, work around this by moving
-     the call into the first half_bb.  Not pretty, but seems easier than
-     doing the CFG manipulation by hand when the CALL_EXPR is in the last
-     statement in BB.  */
+  /* split_block splits after the statement; work around this by
+     moving the call into the second block manually.  Not pretty,
+     but seems easier than doing the CFG manipulation by hand
+     when the CALL_EXPR is in the last statement of BB.  */
   stmt_bsi = bsi_last (bb);
+  bsi_remove (&stmt_bsi, false);
+
+  /* If the CALL_EXPR was in the last statement of BB, it may have
+     been the source of abnormal edges.  In this case, schedule
+     the removal of dead abnormal edges.  */
   bsi = bsi_start (return_block);
-  if (!bsi_end_p (bsi))
-    bsi_move_before (&stmt_bsi, &bsi);
-  else
+  if (bsi_end_p (bsi))
     {
-      tree stmt = bsi_stmt (stmt_bsi);
-      bsi_remove (&stmt_bsi, false);
       bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
+      purge_dead_abnormal_edges = true;
     }
+  else
+    {
+      bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+      purge_dead_abnormal_edges = false;
+    }
+
   stmt_bsi = bsi_start (return_block);
 
   /* Build a block containing code to initialize the arguments, the
@@ -2147,9 +2154,8 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
        tsi_delink() will leave the iterator in a sane state.  */
     bsi_remove (&stmt_bsi, true);
 
-  bsi_next (&bsi);
-  if (bsi_end_p (bsi))
-    tree_purge_dead_eh_edges (return_block);
+  if (purge_dead_abnormal_edges)
+    tree_purge_dead_abnormal_call_edges (return_block);
 
   /* If the value of the new expression is ignored, that's OK.  We
      don't warn about this for CALL_EXPRs, so we shouldn't warn about
index 3f4471a..50dd22b 100644 (file)
@@ -237,9 +237,26 @@ struct tree_opt_pass pass_free_cfg_annotations =
   0,                                   /* todo_flags_finish */
   0                                    /* letter */
 };
-/* Pass: fixup_cfg - IPA passes or compilation of earlier functions might've
-   changed some properties - such as marked functions nothrow.  Remove now
-   redundant edges and basic blocks.  */
+
+/* Return true if BB has at least one abnormal outgoing edge.  */
+
+static inline bool
+has_abnormal_outgoing_edge_p (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (e->flags & EDGE_ABNORMAL)
+      return true;
+
+  return false;
+}
+
+/* Pass: fixup_cfg.  IPA passes, compilation of earlier functions or inlining
+   might have changed some properties, such as marked functions nothrow or
+   added calls that can potentially go to non-local labels.  Remove redundant
+   edges and basic blocks, and create new ones if necessary.  */
 
 static unsigned int
 execute_fixup_cfg (void)
@@ -262,8 +279,37 @@ execute_fixup_cfg (void)
          }
        tree_purge_dead_eh_edges (bb);
       }
-    
+
+  if (current_function_has_nonlocal_label)
+    FOR_EACH_BB (bb)
+      {
+       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+         {
+           tree stmt = bsi_stmt (bsi);
+           if (tree_can_make_abnormal_goto (stmt))
+             {
+               if (stmt == bsi_stmt (bsi_last (bb)))
+                 {
+                   if (!has_abnormal_outgoing_edge_p (bb))
+                     make_abnormal_goto_edges (bb, true);
+                 }
+               else
+                 {
+                   edge e = split_block (bb, stmt);
+                   bb = e->src;
+                   make_abnormal_goto_edges (bb, true);
+                 }
+               break;
+             }
+         }
+      }
+
   cleanup_tree_cfg ();
+
+  /* Dump a textual representation of the flowgraph.  */
+  if (dump_file)
+    dump_tree_cfg (dump_file, dump_flags);
+
   return 0;
 }
 
@@ -280,7 +326,7 @@ struct tree_opt_pass pass_fixup_cfg =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
+  0,                                   /* todo_flags_finish */
   0                                    /* letter */
 };
 
index cfbfe14..e838ba1 100644 (file)
@@ -6714,6 +6714,26 @@ build_common_builtin_nodes (void)
                        "__builtin_nonlocal_goto",
                        ECF_NORETURN | ECF_NOTHROW);
 
+  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+  tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+  ftype = build_function_type (void_type_node, tmp);
+  local_define_builtin ("__builtin_setjmp_setup", ftype,
+                       BUILT_IN_SETJMP_SETUP,
+                       "__builtin_setjmp_setup", ECF_NOTHROW);
+
+  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+  ftype = build_function_type (ptr_type_node, tmp);
+  local_define_builtin ("__builtin_setjmp_dispatcher", ftype,
+                       BUILT_IN_SETJMP_DISPATCHER,
+                       "__builtin_setjmp_dispatcher",
+                       ECF_PURE | ECF_NOTHROW);
+
+  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+  ftype = build_function_type (void_type_node, tmp);
+  local_define_builtin ("__builtin_setjmp_receiver", ftype,
+                       BUILT_IN_SETJMP_RECEIVER,
+                       "__builtin_setjmp_receiver", ECF_NOTHROW);
+
   ftype = build_function_type (ptr_type_node, void_list_node);
   local_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
                        "__builtin_stack_save", ECF_NOTHROW);
index 72c363c..e1a62c9 100644 (file)
@@ -1,5 +1,5 @@
 /* SJLJ exception handling and frame unwind runtime interface routines.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
    Free Software Foundation, Inc.
 
    This file is part of GCC.
@@ -45,10 +45,14 @@ typedef void *jmp_buf[JMP_BUF_SIZE];
 extern void longjmp(jmp_buf, int) __attribute__((noreturn));
 #endif
 #else
-#define setjmp __builtin_setjmp
 #define longjmp __builtin_longjmp
 #endif
 
+/* The setjmp side is dealt with in the except.c file.  */
+#undef setjmp
+#define setjmp setjmp_should_not_be_used_in_this_file
+
+
 /* This structure is allocated on the stack of the target function.
    This must match the definition created in except.c:init_eh.  */
 struct SjLj_Function_Context