OSDN Git Service

ch:
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 44507f8..efa61e5 100644 (file)
@@ -463,13 +463,13 @@ static void start_dynamic_cleanup PARAMS ((tree, tree));
 static void start_dynamic_handler      PARAMS ((void));
 static void expand_rethrow     PARAMS ((rtx));
 static void output_exception_table_entry       PARAMS ((FILE *, int));
-static int can_throw           PARAMS ((rtx));
 static rtx scan_region         PARAMS ((rtx, int, int *));
 static void eh_regs            PARAMS ((rtx *, rtx *, rtx *, int));
 static void set_insn_eh_region PARAMS ((rtx *, int));
 #ifdef DONT_USE_BUILTIN_SETJMP
 static void jumpif_rtx         PARAMS ((rtx, rtx));
 #endif
+static void find_exception_handler_labels_1 PARAMS ((rtx));
 static void mark_eh_node        PARAMS ((struct eh_node *));
 static void mark_eh_stack       PARAMS ((struct eh_stack *));
 static void mark_eh_queue       PARAMS ((struct eh_queue *));
@@ -483,7 +483,6 @@ static int find_func_region PARAMS ((int));
 static int find_func_region_from_symbol PARAMS ((rtx));
 static void clear_function_eh_region PARAMS ((void));
 static void process_nestinfo   PARAMS ((int, eh_nesting_info *, int *));
-
 rtx expand_builtin_return_addr PARAMS ((enum built_in_function, int, rtx));
 static void emit_cleanup_handler PARAMS ((struct eh_entry *));
 static int eh_region_from_symbol PARAMS ((rtx));
@@ -698,6 +697,7 @@ struct func_eh_entry
   int range_number;   /* EH region number from EH NOTE insn's.  */
   rtx rethrow_label;  /* Label for rethrow.  */
   int rethrow_ref;    /* Is rethrow_label referenced?  */
+  int emitted;        /* 1 if this entry has been emitted in assembly file.  */
   struct handler_info *handlers;
 };
 
@@ -739,7 +739,8 @@ new_eh_region_entry (note_eh_region, rethrow)
   else
     function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
   function_eh_regions[current_func_eh_entry].handlers = NULL;
-
+  function_eh_regions[current_func_eh_entry].emitted = 0;
   return current_func_eh_entry++;
 }
 
@@ -930,7 +931,8 @@ clear_function_eh_region ()
         next = ptr->next;
         free (ptr);
       }
-  free (function_eh_regions);
+  if (function_eh_regions)
+    free (function_eh_regions);
   num_func_eh_entries  = 0;
   current_func_eh_entry = 0;
 }
@@ -1361,7 +1363,7 @@ start_dynamic_handler ()
   buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
 
 #ifdef DONT_USE_BUILTIN_SETJMP
-  x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1,
+  x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST,
                               TYPE_MODE (integer_type_node), 1,
                               buf, Pmode);
   /* If we come back here for a catch, transfer control to the handler.  */
@@ -1759,7 +1761,8 @@ start_catch_handler (rtime)
 
       /* Now issue the call, and branch around handler if needed */
       call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, 
-                                          0, TYPE_MODE (integer_type_node),
+                                          LCT_NORMAL,
+                                         TYPE_MODE (integer_type_node),
                                          1, rtime_address, Pmode);
 
       /* Did the function return true? */
@@ -1865,10 +1868,9 @@ emit_cleanup_handler (entry)
   end_sequence ();
 
   /* And add it to the CATCH_CLAUSES.  */
-  push_to_sequence (catch_clauses);
+  push_to_full_sequence (catch_clauses, catch_clauses_last);
   emit_insns (handler_insns);
-  catch_clauses = get_insns ();
-  end_sequence ();
+  end_full_sequence (&catch_clauses, &catch_clauses_last);
 
   /* Now we've left the handler.  */
   pop_ehqueue ();
@@ -1990,10 +1992,9 @@ expand_end_all_catch ()
   pop_label_entry (&outer_context_label_stack);
 
   /* Add the new sequence of catches to the main one for this function.  */
-  push_to_sequence (catch_clauses);
+  push_to_full_sequence (catch_clauses, catch_clauses_last);
   emit_insns (new_catch_clause);
-  catch_clauses = get_insns ();
-  end_sequence ();
+  end_full_sequence (&catch_clauses, &catch_clauses_last);
   
   /* Here we fall through into the continuation code.  */
 }
@@ -2164,6 +2165,24 @@ add_eh_table_entry (n)
        }
     }
   eh_table[eh_table_size++] = n;
+  
+  if (flag_new_exceptions)
+    {
+      /* We will output the exception table late in the compilation. That
+         references type_info objects which should have already been output
+         by that time. We explicitly mark those objects as being
+         referenced now so we know to emit them.  */
+      struct handler_info *handler = get_first_handler (n);
+      
+      for (; handler; handler = handler->next)
+        if (handler->type_info && handler->type_info != CATCH_ALL_TYPE)
+          {
+            tree tinfo = (tree)handler->type_info;
+
+            tinfo = TREE_OPERAND (tinfo, 0);
+            TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
+          }
+    }
 #endif
 }
 
@@ -2205,40 +2224,44 @@ output_exception_table_entry (file, n)
   else
     rethrow = NULL_RTX;
 
+  if (function_eh_regions[index].emitted)
+    return;
+  function_eh_regions[index].emitted  = 1;
+
   for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
     {
       /* rethrow label should indicate the LAST entry for a region */
       if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
         {
           ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
-          assemble_label(buf);
+          assemble_eh_label(buf);
           rethrow = NULL_RTX;
         }
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
       
       if (handler == NULL)
-        assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
+        assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
       else
         {
           ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
           sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-          assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+          assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
         }
 
       if (flag_new_exceptions)
         {
           if (handler == NULL || handler->type_info == NULL)
-            assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+            assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
           else
             if (handler->type_info == CATCH_ALL_TYPE)
-              assemble_integer (GEN_INT (CATCH_ALL_TYPE), 
+              assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE), 
                                              POINTER_SIZE / BITS_PER_UNIT, 1);
             else
               output_constant ((tree)(handler->type_info), 
@@ -2272,61 +2295,101 @@ set_exception_version_code (code)
   version_code = code;
 }
 
-
+/* Free the EH table structures.  */
 void
-output_exception_table ()
+free_exception_table ()
+{
+  if (eh_table)
+    free (eh_table);
+  clear_function_eh_region ();
+}
+  
+/* Output the common content of an exception table.  */
+void
+output_exception_table_data ()
 {
   int i;
   char buf[256];
   extern FILE *asm_out_file;
 
-  if (! doing_eh (0) || ! eh_table)
-    return;
-
-  exception_section ();
-
-  /* Beginning marker for table.  */
-  assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
-  assemble_label ("__EXCEPTION_TABLE__");
-
   if (flag_new_exceptions)
     {
-      assemble_integer (GEN_INT (NEW_EH_RUNTIME), 
+      assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME), 
                                         POINTER_SIZE / BITS_PER_UNIT, 1);
-      assemble_integer (GEN_INT (language_code), 2 , 1); 
-      assemble_integer (GEN_INT (version_code), 2 , 1);
+      assemble_eh_integer (GEN_INT (language_code), 2 , 1); 
+      assemble_eh_integer (GEN_INT (version_code), 2 , 1);
 
       /* Add enough padding to make sure table aligns on a pointer boundry. */
       i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
       for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
         ;
       if (i != 0)
-        assemble_integer (const0_rtx, i , 1);
+        assemble_eh_integer (const0_rtx, i , 1);
 
       /* Generate the label for offset calculations on rethrows.  */
       ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
-      assemble_label(buf);
+      assemble_eh_label(buf);
     }
 
   for (i = 0; i < eh_table_size; ++i)
     output_exception_table_entry (asm_out_file, eh_table[i]);
 
-  free (eh_table);
-  clear_function_eh_region ();
+}
+
+/* Output an exception table for the entire compilation unit.  */
+void
+output_exception_table ()
+{
+  char buf[256];
+  extern FILE *asm_out_file;
+
+  if (! doing_eh (0) || ! eh_table)
+    return;
+
+  exception_section ();
+
+  /* Beginning marker for table.  */
+  assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+  assemble_eh_label ("__EXCEPTION_TABLE__");
+
+  output_exception_table_data ();
 
   /* Ending marker for table.  */
   /* Generate the label for end of table. */
   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
-  assemble_label(buf);
-  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+  assemble_eh_label(buf);
+  assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   /* For binary compatibility, the old __throw checked the second
      position for a -1, so we should output at least 2 -1's */
   if (! flag_new_exceptions)
-    assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+    assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   putc ('\n', asm_out_file);           /* blank line */
 }
+
+/* Used by the ia64 unwind format to output data for an individual 
+   function.  */
+void
+output_function_exception_table ()
+{
+  extern FILE *asm_out_file;
+
+  if (! doing_eh (0) || ! eh_table)
+    return;
+
+#ifdef HANDLER_SECTION
+  HANDLER_SECTION;
+#endif
+
+  output_exception_table_data ();
+
+  /* Ending marker for table.  */
+  assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+  putc ('\n', asm_out_file);           /* blank line */
+}
+
 \f
 /* Emit code to get EH context.
    
@@ -2372,27 +2435,18 @@ emit_eh_context ()
       }
 }
 
-/* Scan the current insns and build a list of handler labels. The
-   resulting list is placed in the global variable exception_handler_labels.
-
-   It is called after the last exception handling region is added to
-   the current function (when the rtl is almost all built for the
-   current function) and before the jump optimization pass.  */
+/* Scan the insn chain F and build a list of handler labels. The
+   resulting list is placed in the global variable exception_handler_labels.  */
 
-void
-find_exception_handler_labels ()
+static void
+find_exception_handler_labels_1 (f)
+     rtx f;
 {
   rtx insn;
 
-  exception_handler_labels = NULL_RTX;
-
-  /* If we aren't doing exception handling, there isn't much to check.  */
-  if (! doing_eh (0))
-    return;
-
   /* For each start of a region, add its label to the list.  */
 
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+  for (insn = f; insn; insn = NEXT_INSN (insn))
     {
       struct handler_info* ptr;
       if (GET_CODE (insn) == NOTE
@@ -2411,9 +2465,34 @@ find_exception_handler_labels ()
                                ptr->handler_label, exception_handler_labels);
             }
        }
+      else if (GET_CODE (insn) == CALL_INSN
+              && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+       {
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 0));
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 1));
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 2));
+       }
     }
 }
 
+/* Scan the current insns and build a list of handler labels. The
+   resulting list is placed in the global variable exception_handler_labels.
+
+   It is called after the last exception handling region is added to
+   the current function (when the rtl is almost all built for the
+   current function) and before the jump optimization pass.  */
+void
+find_exception_handler_labels ()
+{
+  exception_handler_labels = NULL_RTX;
+
+  /* If we aren't doing exception handling, there isn't much to check.  */
+  if (! doing_eh (0))
+    return;
+
+  find_exception_handler_labels_1 (get_insns ());
+}     
+
 /* Return a value of 1 if the parameter label number is an exception handler
    label. Return 0 otherwise. */
 
@@ -2528,7 +2607,8 @@ mark_eh_status (eh)
   mark_eh_queue (eh->x_ehqueue);
   ggc_mark_rtx (eh->x_catch_clauses);
 
-  lang_mark_false_label_stack (eh->x_false_label_stack);
+  if (lang_mark_false_label_stack)
+    (*lang_mark_false_label_stack) (eh->x_false_label_stack);
   mark_tree_label_node (eh->x_caught_return_label_stack);
 
   ggc_mark_tree (eh->x_protect_list);
@@ -2611,12 +2691,11 @@ free_eh_status (f)
 }
 \f
 /* This section is for the exception handling specific optimization
-   pass.  First are the internal routines, and then the main
-   optimization pass.  */
+   pass.  */
 
 /* Determine if the given INSN can throw an exception.  */
 
-static int
+int
 can_throw (insn)
      rtx insn;
 {
@@ -2912,9 +2991,10 @@ expand_builtin_frob_return_addr (addr_tree)
    The first passes the exception context to the handler.  For this
    we use the return value register for a void*.
 
-   The second holds the stack pointer value to be restored.  For
-   this we use the static chain register if it exists and is different
-   from the previous, otherwise some arbitrary call-clobbered register.
+   The second holds the stack pointer value to be restored.  For this
+   we use the static chain register if it exists, is different from
+   the previous, and is call-clobbered; otherwise some arbitrary
+   call-clobbered register.
 
    The third holds the address of the handler itself.  Here we use
    some arbitrary call-clobbered register.  */
@@ -2925,7 +3005,7 @@ eh_regs (pcontext, psp, pra, outgoing)
      int outgoing ATTRIBUTE_UNUSED;
 {
   rtx rcontext, rsp, rra;
-  int i;
+  unsigned int i;
 
 #ifdef FUNCTION_OUTGOING_VALUE
   if (outgoing)
@@ -2941,7 +3021,8 @@ eh_regs (pcontext, psp, pra, outgoing)
     rsp = static_chain_incoming_rtx;
   else
     rsp = static_chain_rtx;
-  if (REGNO (rsp) == REGNO (rcontext))
+  if (REGNO (rsp) == REGNO (rcontext)
+      || ! call_used_regs [REGNO (rsp)])
 #endif /* STATIC_CHAIN_REGNUM */
     rsp = NULL_RTX;