OSDN Git Service

* gcc.c-torture/execute/ieee/ieee.exp: Change sh-*-* to sh*-*-*.
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 5ad9071..6ea1723 100644 (file)
@@ -3,22 +3,22 @@
    1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 /* An exception is an event that can be signaled from within a
@@ -54,6 +54,7 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
+#include "libfuncs.h"
 #include "insn-config.h"
 #include "except.h"
 #include "integrate.h"
@@ -100,7 +101,7 @@ tree (*lang_eh_runtime_type) PARAMS ((tree));
 rtx exception_handler_labels;
 
 static int call_site_base;
-static int sjlj_funcdef_number;
+static unsigned int sjlj_funcdef_number;
 static htab_t type_to_runtime_map;
 
 /* Describe the SjLj_Function_Context structure.  */
@@ -256,7 +257,7 @@ static tree lookup_type_for_runtime         PARAMS ((tree));
 
 static struct eh_region *expand_eh_region_end  PARAMS ((void));
 
-static rtx get_exception_filter                        PARAMS ((void));
+static rtx get_exception_filter                        PARAMS ((struct function *));
 
 static void collect_eh_region_array            PARAMS ((void));
 static void resolve_fixup_regions              PARAMS ((void));
@@ -720,9 +721,9 @@ expand_eh_region_end_cleanup (handler)
   /* In case this cleanup involves an inline destructor with a try block in
      it, we need to save the EH return data registers around it.  */
   data_save[0] = gen_reg_rtx (Pmode);
-  emit_move_insn (data_save[0], get_exception_pointer ());
+  emit_move_insn (data_save[0], get_exception_pointer (cfun));
   data_save[1] = gen_reg_rtx (word_mode);
-  emit_move_insn (data_save[1], get_exception_filter ());
+  emit_move_insn (data_save[1], get_exception_filter (cfun));
 
   expand_expr (handler, const0_rtx, VOIDmode, 0);
 
@@ -833,7 +834,11 @@ expand_end_all_catch ()
 
 /* End an exception region for an exception type filter.  ALLOWED is a
    TREE_LIST of types to be matched by the runtime.  FAILURE is an
-   expression to invoke if a mismatch ocurrs.  */
+   expression to invoke if a mismatch ocurrs.
+
+   ??? We could use these semantics for calls to rethrow, too; if we can
+   see the surrounding catch clause, we know that the exception we're
+   rethrowing satisfies the "filter" of the catch type.  */
 
 void
 expand_eh_region_end_allowed (allowed, failure)
@@ -857,10 +862,6 @@ expand_eh_region_end_allowed (allowed, failure)
      throws a different exception, that it will be processed by the
      correct region.  */
 
-  /* If there are any pending stack adjustments, we must emit them
-     before we branch -- otherwise, we won't know how much adjustment
-     is required later.  */
-  do_pending_stack_adjust ();
   around_label = gen_label_rtx ();
   emit_jump (around_label);
 
@@ -955,13 +956,14 @@ expand_eh_region_end_fixup (handler)
    within a handler.  */
 
 rtx
-get_exception_pointer ()
+get_exception_pointer (fun)
+     struct function *fun;
 {
-  rtx exc_ptr = cfun->eh->exc_ptr;
-  if (! exc_ptr)
+  rtx exc_ptr = fun->eh->exc_ptr;
+  if (fun == cfun && ! exc_ptr)
     {
       exc_ptr = gen_reg_rtx (Pmode);
-      cfun->eh->exc_ptr = exc_ptr;
+      fun->eh->exc_ptr = exc_ptr;
     }
   return exc_ptr;
 }
@@ -970,13 +972,14 @@ get_exception_pointer ()
    within a handler.  */
 
 static rtx
-get_exception_filter ()
+get_exception_filter (fun)
+     struct function *fun;
 {
-  rtx filter = cfun->eh->filter;
-  if (! filter)
+  rtx filter = fun->eh->filter;
+  if (fun == cfun && ! filter)
     {
       filter = gen_reg_rtx (word_mode);
-      cfun->eh->filter = filter;
+      fun->eh->filter = filter;
     }
   return filter;
 }
@@ -1090,7 +1093,7 @@ resolve_fixup_regions ()
   for (i = 1; i <= n; ++i)
     {
       struct eh_region *fixup = cfun->eh->region_array[i];
-      struct eh_region *cleanup;
+      struct eh_region *cleanup = 0;
 
       if (! fixup || fixup->type != ERT_FIXUP)
        continue;
@@ -1131,7 +1134,7 @@ remove_fixup_regions ()
        && fixup->type == ERT_FIXUP)
       {
        if (fixup->u.fixup.real_region)
-         XEXP (note, 1) = GEN_INT (fixup->u.fixup.real_region->region_number);
+         XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
        else
          remove_note (insn, note);
       }
@@ -1242,6 +1245,8 @@ convert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
                  /* If we wanted exceptions for non-call insns, then
                     any may_trap_p instruction could throw.  */
                  || (flag_non_call_exceptions
+                     && GET_CODE (PATTERN (insn)) != CLOBBER
+                     && GET_CODE (PATTERN (insn)) != USE
                      && may_trap_p (PATTERN (insn)))))
            {
              REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
@@ -1446,7 +1451,7 @@ duplicate_eh_regions (ifun, map)
        cur->inner = root;
 
       for (i = 1; i <= ifun_last_region_number; ++i)
-       if (n_array[i]->outer == NULL)
+       if (n_array[i] && n_array[i]->outer == NULL)
          n_array[i]->outer = cur;
     }
   else
@@ -1470,9 +1475,6 @@ duplicate_eh_regions (ifun, map)
 }
 
 \f
-/* ??? Move from tree.c to tree.h.  */
-#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
-
 static int
 t2r_eq (pentry, pdata)
      const PTR pentry;
@@ -1848,8 +1850,7 @@ connect_post_landing_pads ()
       seq = get_insns ();
       end_sequence ();
       emit_insns_before (seq, region->resume);
-
-      /* Leave the RESX to be deleted by flow.  */
+      delete_insn (region->resume);
     }
 }
 
@@ -1857,12 +1858,14 @@ connect_post_landing_pads ()
 static void
 dw2_build_landing_pads ()
 {
-  int i, j;
+  int i;
+  unsigned int j;
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
       struct eh_region *region = cfun->eh->region_array[i];
       rtx seq;
+      bool clobbers_hard_regs = false;
 
       /* Mind we don't process a region more than once.  */
       if (!region || region->region_number != i)
@@ -1899,7 +1902,19 @@ dw2_build_landing_pads ()
          if (r == INVALID_REGNUM)
            break;
          if (! call_used_regs[r])
-           emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
+           {
+             emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
+             clobbers_hard_regs = true;
+           }
+       }
+
+      if (clobbers_hard_regs)
+       {
+         /* @@@ This is a kludge.  Not all machine descriptions define a
+            blockage insn, but we must not allow the code we just generated
+            to be reordered by scheduling.  So emit an ASM_INPUT to act as
+            blockage insn.  */
+         emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
        }
 
       emit_move_insn (cfun->eh->exc_ptr,
@@ -2040,10 +2055,6 @@ sjlj_mark_call_sites (lp_info)
   int last_call_site = -2;
   rtx insn, mem;
 
-  mem = change_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
-                       plus_constant (XEXP (cfun->eh->sjlj_fc, 0),
-                                      sjlj_fc_call_site_ofs));
-
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     {
       struct eh_region *region;
@@ -2086,53 +2097,11 @@ sjlj_mark_call_sites (lp_info)
       /* Don't separate a call from it's argument loads.  */
       before = insn;
       if (GET_CODE (insn) == CALL_INSN)
-       {
-         HARD_REG_SET parm_regs;
-         int nparm_regs;
-         
-         /* Since different machines initialize their parameter registers
-            in different orders, assume nothing.  Collect the set of all
-            parameter registers.  */
-         CLEAR_HARD_REG_SET (parm_regs);
-         nparm_regs = 0;
-         for (p = CALL_INSN_FUNCTION_USAGE (insn); p ; p = XEXP (p, 1))
-           if (GET_CODE (XEXP (p, 0)) == USE
-               && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
-             {
-               if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
-                 abort ();
-
-               /* We only care about registers which can hold function
-                  arguments.  */
-               if (! FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
-                 continue;
-
-               SET_HARD_REG_BIT (parm_regs, REGNO (XEXP (XEXP (p, 0), 0)));
-               nparm_regs++;
-             }
-
-         /* Search backward for the first set of a register in this set.  */
-         while (nparm_regs)
-           {
-             before = PREV_INSN (before);
-
-             /* Given that we've done no other optimizations yet,
-                the arguments should be immediately available.  */
-             if (GET_CODE (before) == CODE_LABEL)
-               abort ();
-
-             p = single_set (before);
-             if (p && GET_CODE (SET_DEST (p)) == REG
-                 && REGNO (SET_DEST (p)) < FIRST_PSEUDO_REGISTER
-                 && TEST_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p))))
-               {
-                 CLEAR_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p)));
-                 nparm_regs--;
-               }
-           }
-       }
+         before = find_first_parameter_load (insn, NULL_RTX);
 
       start_sequence ();
+      mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
+                           sjlj_fc_call_site_ofs);
       emit_move_insn (mem, GEN_INT (this_call_site));
       p = get_insns ();
       end_sequence ();
@@ -2158,12 +2127,10 @@ sjlj_emit_function_enter (dispatch_label)
      calling it directly.  Thus, we must call assemble_external_libcall
      here, as we can not depend on emit_library_call to do it for us.  */
   assemble_external_libcall (eh_personality_libfunc);
-  mem = change_address (fc, Pmode,
-                       plus_constant (XEXP (fc, 0), sjlj_fc_personality_ofs));
+  mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
   emit_move_insn (mem, eh_personality_libfunc);
 
-  mem = change_address (fc, Pmode,
-                       plus_constant (XEXP (fc, 0), sjlj_fc_lsda_ofs));
+  mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
   if (cfun->uses_eh_lsda)
     {
       char buf[20];
@@ -2176,7 +2143,7 @@ sjlj_emit_function_enter (dispatch_label)
 #ifdef DONT_USE_BUILTIN_SETJMP
   {
     rtx x, note;
-    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_NORMAL,
+    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
                                 TYPE_MODE (integer_type_node), 1,
                                 plus_constant (XEXP (fc, 0),
                                                sjlj_fc_jbuf_ofs), Pmode);
@@ -2260,12 +2227,11 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
 
   /* Load up dispatch index, exc_ptr and filter values from the
      function context.  */
-  mem = change_address (fc, TYPE_MODE (integer_type_node),
-                       plus_constant (XEXP (fc, 0), sjlj_fc_call_site_ofs));
+  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
+                       sjlj_fc_call_site_ofs);
   dispatch = copy_to_reg (mem);
 
-  mem = change_address (fc, word_mode,
-                       plus_constant (XEXP (fc, 0), sjlj_fc_data_ofs));
+  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
   if (word_mode != Pmode)
     {
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -2276,9 +2242,7 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
     }
   emit_move_insn (cfun->eh->exc_ptr, mem);
 
-  mem = change_address (fc, word_mode,
-                       plus_constant (XEXP (fc, 0),
-                                      sjlj_fc_data_ofs + UNITS_PER_WORD));
+  mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
   emit_move_insn (cfun->eh->filter, mem);
 
   /* Jump to one of the directly reachable regions.  */
@@ -2354,14 +2318,14 @@ finish_eh_generation ()
      connect many of the handlers, and then type information will not
      be effective.  Still, this is a win over previous implementations.  */
 
-  jump_optimize_minimal (get_insns ());
+  rebuild_jump_labels (get_insns ());
   find_basic_blocks (get_insns (), max_reg_num (), 0);
-  cleanup_cfg ();
+  cleanup_cfg (CLEANUP_PRE_LOOP);
 
   /* These registers are used by the landing pads.  Make sure they
      have been generated.  */
-  get_exception_pointer ();
-  get_exception_filter ();
+  get_exception_pointer (cfun);
+  get_exception_filter (cfun);
 
   /* Construct the landing pads.  */
 
@@ -2377,9 +2341,9 @@ finish_eh_generation ()
 
   /* We've totally changed the CFG.  Start over.  */
   find_exception_handler_labels ();
-  jump_optimize_minimal (get_insns ());
+  rebuild_jump_labels (get_insns ());
   find_basic_blocks (get_insns (), max_reg_num (), 0);
-  cleanup_cfg ();
+  cleanup_cfg (CLEANUP_PRE_LOOP);
 }
 \f
 /* This section handles removing dead code for flow.  */
@@ -2736,14 +2700,20 @@ reachable_handlers (insn)
   region = cfun->eh->region_array[region_number];
 
   type_thrown = NULL_TREE;
-  if (region->type == ERT_THROW)
+  if (GET_CODE (insn) == JUMP_INSN
+      && GET_CODE (PATTERN (insn)) == RESX)
+    {
+      /* A RESX leaves a region instead of entering it.  Thus the
+        region itself may have been deleted out from under us.  */
+      if (region == NULL)
+       return NULL;
+      region = region->outer;
+    }
+  else if (region->type == ERT_THROW)
     {
       type_thrown = region->u.throw.type;
       region = region->outer;
     }
-  else if (GET_CODE (insn) == JUMP_INSN
-          && GET_CODE (PATTERN (insn)) == RESX)
-    region = region->outer;
 
   for (; region; region = region->outer)
     if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
@@ -2909,7 +2879,7 @@ void
 expand_builtin_unwind_init ()
 {
   /* Set this so all the registers get saved in our frame; we need to be
-     able to copy the saved values for any registers from frames we unwind. */
+     able to copy the saved values for any registers from frames we unwind.  */
   current_function_has_nonlocal_label = 1;
 
 #ifdef SETUP_FRAME_ADDRESSES
@@ -3066,6 +3036,17 @@ expand_eh_return ()
   emit_label (around_label);
 }
 \f
+/* In the following functions, we represent entries in the action table
+   as 1-based indicies.  Special cases are:
+
+        0:     null action record, non-null landing pad; implies cleanups
+       -1:     null action record, null landing pad; implies no action
+       -2:     no call-site entry; implies must_not_throw
+       -3:     we have yet to process outer regions
+
+   Further, no special cases apply to the "next" field of the record.
+   For next, 0 means end of list.  */
+
 struct action_record
 {
   int offset;
@@ -3169,8 +3150,16 @@ collect_one_action_chain (ar_hash, region)
              if (next == -3)
                {
                  next = collect_one_action_chain (ar_hash, region->outer);
-                 if (next < 0)
+
+                 /* If there is no next action, terminate the chain.  */
+                 if (next == -1)
                    next = 0;
+                 /* If all outer actions are cleanups or must_not_throw,
+                    we'll have no action record for it, since we had wanted
+                    to encode these states in the call-site record directly.
+                    Add a cleanup action to the chain to catch these.  */
+                 else if (next <= 0)
+                   next = add_action_record (ar_hash, 0, 0);
                }
              next = add_action_record (ar_hash, c->u.catch.filter, next);
            }
@@ -3241,7 +3230,7 @@ convert_to_eh_region_ranges ()
   rtx last_action_insn = NULL_RTX;
   rtx last_landing_pad = NULL_RTX;
   rtx first_no_action_insn = NULL_RTX;
-  int call_site;
+  int call_site = 0;
 
   if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
     return;
@@ -3432,7 +3421,7 @@ sjlj_size_of_call_site_table ()
 static void
 dw2_output_call_site_table ()
 {
-  const char *function_start_lab
+  const char *const function_start_lab
     = IDENTIFIER_POINTER (current_function_func_begin_label);
   int n = cfun->eh->call_site_data_used;
   int i;
@@ -3512,7 +3501,7 @@ output_function_exception_table ()
 #endif
   int have_tt_data;
   int funcdef_number;
-  int tt_format_size;
+  int tt_format_size = 0;
 
   /* Not all functions need anything.  */
   if (! cfun->uses_eh_lsda)
@@ -3546,7 +3535,7 @@ output_function_exception_table ()
 #endif
       tt_format_size = size_of_encoded_value (tt_format);
 
-      assemble_eh_align (tt_format_size * BITS_PER_UNIT);
+      assemble_align (tt_format_size * BITS_PER_UNIT);
     }
 
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
@@ -3653,22 +3642,25 @@ output_function_exception_table ()
                         (i ? NULL : "Action record table"));
 
   if (have_tt_data)
-    assemble_eh_align (tt_format_size * BITS_PER_UNIT);
+    assemble_align (tt_format_size * BITS_PER_UNIT);
 
   i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
   while (i-- > 0)
     {
       tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
+      rtx value;
 
       if (type == NULL_TREE)
        type = integer_zero_node;
       else
        type = lookup_type_for_runtime (type);
 
-      dw2_asm_output_encoded_addr_rtx (tt_format,
-                                      expand_expr (type, NULL_RTX, VOIDmode,
-                                                   EXPAND_INITIALIZER),
-                                      NULL);
+      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+      if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
+       assemble_integer (value, tt_format_size,
+                         tt_format_size * BITS_PER_UNIT, 1);
+      else
+        dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
     }
 
 #ifdef HAVE_AS_LEB128