OSDN Git Service

* flow.c (find_unreachable_blocks): New function.
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index ca68f65..90c0dc9 100644 (file)
@@ -62,6 +62,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "dwarf2asm.h"
 #include "dwarf2out.h"
+#include "dwarf2.h"
 #include "toplev.h"
 #include "hashtab.h"
 #include "intl.h"
@@ -87,7 +88,7 @@ int flag_non_call_exceptions;
 
 /* Protect cleanup actions with must-not-throw regions, with a call
    to the given failure handler.  */
-tree protect_cleanup_actions;
+tree (*lang_protect_cleanup_actions) PARAMS ((void));
 
 /* Return true if type A catches type B.  */
 int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
@@ -255,7 +256,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));
@@ -329,7 +330,6 @@ static int add_call_site                    PARAMS ((rtx, int));
 static void push_uleb128                       PARAMS ((varray_type *,
                                                         unsigned int));
 static void push_sleb128                       PARAMS ((varray_type *, int));
-static const char *eh_data_format_name         PARAMS ((int));
 #ifndef HAVE_AS_LEB128
 static int dw2_size_of_call_site_table         PARAMS ((void));
 static int sjlj_size_of_call_site_table                PARAMS ((void));
@@ -367,7 +367,6 @@ void
 init_eh ()
 {
   ggc_add_rtx_root (&exception_handler_labels, 1);
-  ggc_add_tree_root (&protect_cleanup_actions, 1);
 
   if (! flag_exceptions)
     return;
@@ -691,6 +690,7 @@ expand_eh_region_end_cleanup (handler)
      tree handler;
 {
   struct eh_region *region;
+  tree protect_cleanup_actions;
   rtx around_label;
   rtx data_save[2];
 
@@ -707,15 +707,22 @@ expand_eh_region_end_cleanup (handler)
 
   emit_label (region->label);
 
+  /* Give the language a chance to specify an action to be taken if an
+     exception is thrown that would propogate out of the HANDLER.  */
+  protect_cleanup_actions 
+    = (lang_protect_cleanup_actions 
+       ? (*lang_protect_cleanup_actions) () 
+       : NULL_TREE);
+
   if (protect_cleanup_actions)
     expand_eh_region_start ();
 
   /* 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);
 
@@ -855,6 +862,10 @@ expand_eh_region_end_allowed (allowed, failure)
 
   emit_label (region->label);
   expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  /* We must adjust the stack before we reach the AROUND_LABEL because
+     the call to FAILURE does not occur on all paths to the
+     AROUND_LABEL.  */
+  do_pending_stack_adjust ();
 
   emit_label (around_label);
 }
@@ -940,13 +951,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;
 }
@@ -955,13 +967,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;
 }
@@ -1075,7 +1088,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;
@@ -1890,7 +1903,7 @@ dw2_build_landing_pads ()
       emit_move_insn (cfun->eh->exc_ptr,
                      gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0)));
       emit_move_insn (cfun->eh->filter,
-                     gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (1)));
+                     gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
 
       seq = get_insns ();
       end_sequence ();
@@ -2139,6 +2152,10 @@ sjlj_emit_function_enter (dispatch_label)
 
   start_sequence ();
 
+  /* We're storing this libcall's address into memory instead of
+     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));
   emit_move_insn (mem, eh_personality_libfunc);
@@ -2341,8 +2358,8 @@ finish_eh_generation ()
 
   /* 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.  */
 
@@ -2957,6 +2974,10 @@ expand_builtin_frob_return_addr (addr_tree)
 {
   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  addr = convert_memory_address (Pmode, addr);
+#endif
+
 #ifdef RETURN_ADDR_OFFSET
   addr = force_reg (Pmode, addr);
   addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
@@ -2977,6 +2998,11 @@ expand_builtin_eh_return (stackadj_tree, handler_tree)
   stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
   handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  stackadj = convert_memory_address (Pmode, stackadj);
+  handler = convert_memory_address (Pmode, handler);
+#endif
+
   if (! cfun->eh->ehr_label)
     {
       cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
@@ -3366,83 +3392,6 @@ push_sleb128 (data_area, value)
 }
 
 \f
-#define DW_EH_PE_absptr                0x00
-#define DW_EH_PE_omit          0xff
-
-#define DW_EH_PE_uleb128       0x01
-#define DW_EH_PE_udata2                0x02
-#define DW_EH_PE_udata4                0x03
-#define DW_EH_PE_udata8                0x04
-#define DW_EH_PE_sleb128       0x09
-#define DW_EH_PE_sdata2                0x0A
-#define DW_EH_PE_sdata4                0x0B
-#define DW_EH_PE_sdata8                0x0C
-#define DW_EH_PE_signed                0x08
-
-#define DW_EH_PE_pcrel         0x10
-#define DW_EH_PE_textrel       0x20
-#define DW_EH_PE_datarel       0x30
-#define DW_EH_PE_funcrel       0x40
-
-static const char *
-eh_data_format_name (format)
-     int format;
-{
-  switch (format)
-    {
-    case DW_EH_PE_absptr:      return "absolute";
-    case DW_EH_PE_omit:                return "omit";
-
-    case DW_EH_PE_uleb128:     return "uleb128";
-    case DW_EH_PE_udata2:      return "udata2";
-    case DW_EH_PE_udata4:      return "udata4";
-    case DW_EH_PE_udata8:      return "udata8";
-    case DW_EH_PE_sleb128:     return "sleb128";
-    case DW_EH_PE_sdata2:      return "sdata2";
-    case DW_EH_PE_sdata4:      return "sdata4";
-    case DW_EH_PE_sdata8:      return "sdata8";
-
-    case DW_EH_PE_uleb128 | DW_EH_PE_pcrel:    return "pcrel uleb128";
-    case DW_EH_PE_udata2 | DW_EH_PE_pcrel:     return "pcrel udata2";
-    case DW_EH_PE_udata4 | DW_EH_PE_pcrel:     return "pcrel udata4";
-    case DW_EH_PE_udata8 | DW_EH_PE_pcrel:     return "pcrel udata8";
-    case DW_EH_PE_sleb128 | DW_EH_PE_pcrel:    return "pcrel sleb128";
-    case DW_EH_PE_sdata2 | DW_EH_PE_pcrel:     return "pcrel sdata2";
-    case DW_EH_PE_sdata4 | DW_EH_PE_pcrel:     return "pcrel sdata4";
-    case DW_EH_PE_sdata8 | DW_EH_PE_pcrel:     return "pcrel sdata8";
-
-    case DW_EH_PE_uleb128 | DW_EH_PE_textrel:  return "textrel uleb128";
-    case DW_EH_PE_udata2 | DW_EH_PE_textrel:   return "textrel udata2";
-    case DW_EH_PE_udata4 | DW_EH_PE_textrel:   return "textrel udata4";
-    case DW_EH_PE_udata8 | DW_EH_PE_textrel:   return "textrel udata8";
-    case DW_EH_PE_sleb128 | DW_EH_PE_textrel:  return "textrel sleb128";
-    case DW_EH_PE_sdata2 | DW_EH_PE_textrel:   return "textrel sdata2";
-    case DW_EH_PE_sdata4 | DW_EH_PE_textrel:   return "textrel sdata4";
-    case DW_EH_PE_sdata8 | DW_EH_PE_textrel:   return "textrel sdata8";
-
-    case DW_EH_PE_uleb128 | DW_EH_PE_datarel:  return "datarel uleb128";
-    case DW_EH_PE_udata2 | DW_EH_PE_datarel:   return "datarel udata2";
-    case DW_EH_PE_udata4 | DW_EH_PE_datarel:   return "datarel udata4";
-    case DW_EH_PE_udata8 | DW_EH_PE_datarel:   return "datarel udata8";
-    case DW_EH_PE_sleb128 | DW_EH_PE_datarel:  return "datarel sleb128";
-    case DW_EH_PE_sdata2 | DW_EH_PE_datarel:   return "datarel sdata2";
-    case DW_EH_PE_sdata4 | DW_EH_PE_datarel:   return "datarel sdata4";
-    case DW_EH_PE_sdata8 | DW_EH_PE_datarel:   return "datarel sdata8";
-
-    case DW_EH_PE_uleb128 | DW_EH_PE_funcrel:  return "funcrel uleb128";
-    case DW_EH_PE_udata2 | DW_EH_PE_funcrel:   return "funcrel udata2";
-    case DW_EH_PE_udata4 | DW_EH_PE_funcrel:   return "funcrel udata4";
-    case DW_EH_PE_udata8 | DW_EH_PE_funcrel:   return "funcrel udata8";
-    case DW_EH_PE_sleb128 | DW_EH_PE_funcrel:  return "funcrel sleb128";
-    case DW_EH_PE_sdata2 | DW_EH_PE_funcrel:   return "funcrel sdata2";
-    case DW_EH_PE_sdata4 | DW_EH_PE_funcrel:   return "funcrel sdata4";
-    case DW_EH_PE_sdata8 | DW_EH_PE_funcrel:   return "funcrel sdata8";
-
-    default:
-      abort ();
-    }
-}
-
 #ifndef HAVE_AS_LEB128
 static int
 dw2_size_of_call_site_table ()
@@ -3551,7 +3500,7 @@ sjlj_output_call_site_table ()
 void
 output_function_exception_table ()
 {
-  int format, i, n;
+  int tt_format, cs_format, lp_format, i, n;
 #ifdef HAVE_AS_LEB128
   char ttype_label[32];
   char cs_after_size_label[32];
@@ -3561,6 +3510,7 @@ output_function_exception_table ()
 #endif
   int have_tt_data;
   int funcdef_number;
+  int tt_format_size;
 
   /* Not all functions need anything.  */
   if (! cfun->uses_eh_lsda)
@@ -3570,13 +3520,32 @@ output_function_exception_table ()
                    ? sjlj_funcdef_number
                    : current_funcdef_number);
 
+#ifdef IA64_UNWIND_INFO
+  fputs ("\t.personality\t", asm_out_file);
+  output_addr_const (asm_out_file, eh_personality_libfunc);
+  fputs ("\n\t.handlerdata\n", asm_out_file);
+  /* Note that varasm still thinks we're in the function's code section.
+     The ".endp" directive that will immediately follow will take us back.  */
+#else
   exception_section ();
+#endif
 
   have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
                  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
 
-  if (have_tt_data)
-    assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+  /* Indicate the format of the @TType entries.  */
+  if (! have_tt_data)
+    tt_format = DW_EH_PE_omit;
+  else
+    {
+      tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
+#ifdef HAVE_AS_LEB128
+      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
+#endif
+      tt_format_size = size_of_encoded_value (tt_format);
+
+      assemble_eh_align (tt_format_size * BITS_PER_UNIT);
+    }
 
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
 
@@ -3588,26 +3557,14 @@ output_function_exception_table ()
      be most useful in moving the landing pads completely out of
      line to another section, but it could also be used to minimize
      the size of uleb128 landing pad offsets.  */
-  format = DW_EH_PE_omit;
-  dw2_asm_output_data (1, format, "@LPStart format (%s)",
-                      eh_data_format_name (format));
+  lp_format = DW_EH_PE_omit;
+  dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
+                      eh_data_format_name (lp_format));
 
   /* @LPStart pointer would go here.  */
 
-  /* Indicate the format of the @TType entries.  */
-  if (! have_tt_data)
-    format = DW_EH_PE_omit;
-  else
-    {
-      /* ??? Define a ASM_PREFERRED_DATA_FORMAT to say what 
-        sort of dynamic-relocation-free reference to emit.  */
-      format = 0;
-#ifdef HAVE_AS_LEB128
-      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
-#endif
-    }
-  dw2_asm_output_data (1, format, "@TType format (%s)",
-                      eh_data_format_name (format));
+  dw2_asm_output_data (1, tt_format, "@TType format (%s)",
+                      eh_data_format_name (tt_format));
 
 #ifndef HAVE_AS_LEB128
   if (USING_SJLJ_EXCEPTIONS)
@@ -3628,14 +3585,14 @@ output_function_exception_table ()
       ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
 #else
       /* Ug.  Alignment queers things.  */
-      unsigned int before_disp, after_disp, last_disp, disp, align;
+      unsigned int before_disp, after_disp, last_disp, disp;
 
-      align = POINTER_SIZE / BITS_PER_UNIT;
       before_disp = 1 + 1;
       after_disp = (1 + size_of_uleb128 (call_site_len)
                    + call_site_len
                    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
-                   + VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) * align);
+                   + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
+                      * tt_format_size));
 
       disp = after_disp;
       do
@@ -3645,8 +3602,8 @@ output_function_exception_table ()
          last_disp = disp;
          disp_size = size_of_uleb128 (disp);
          pad = before_disp + disp_size + after_disp;
-         if (pad % align)
-           pad = align - (pad % align);
+         if (pad % tt_format_size)
+           pad = tt_format_size - (pad % tt_format_size);
          else
            pad = 0;
          disp = after_disp + pad;
@@ -3659,12 +3616,12 @@ output_function_exception_table ()
 
   /* Indicate the format of the call-site offsets.  */
 #ifdef HAVE_AS_LEB128
-  format = DW_EH_PE_uleb128;
+  cs_format = DW_EH_PE_uleb128;
 #else
-  format = DW_EH_PE_udata4;
+  cs_format = DW_EH_PE_udata4;
 #endif
-  dw2_asm_output_data (1, format, "call-site format (%s)",
-                      eh_data_format_name (format));
+  dw2_asm_output_data (1, cs_format, "call-site format (%s)",
+                      eh_data_format_name (cs_format));
 
 #ifdef HAVE_AS_LEB128
   ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
@@ -3694,7 +3651,7 @@ output_function_exception_table ()
                         (i ? NULL : "Action record table"));
 
   if (have_tt_data)
-    assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+    assemble_eh_align (tt_format_size * BITS_PER_UNIT);
 
   i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
   while (i-- > 0)
@@ -3706,8 +3663,10 @@ output_function_exception_table ()
       else
        type = lookup_type_for_runtime (type);
 
-      /* ??? Handle ASM_PREFERRED_DATA_FORMAT.  */
-      output_constant (type, GET_MODE_SIZE (ptr_mode));
+      dw2_asm_output_encoded_addr_rtx (tt_format,
+                                      expand_expr (type, NULL_RTX, VOIDmode,
+                                                   EXPAND_INITIALIZER),
+                                      NULL);
     }
 
 #ifdef HAVE_AS_LEB128