OSDN Git Service

* config/linux.h (ASM_COMMENT_START): Remove from here,
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 95f8b2c..4d69240 100644 (file)
@@ -1,5 +1,5 @@
 /* Implements exception handling.
-   Copyright (C) 1989, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GNU CC.
@@ -97,9 +97,9 @@ Boston, MA 02111-1307, USA.  */
    On targets that support crtstuff.c, the unwind information
    is stored in a section named .eh_frame and the information for the
    entire shared object or program is registered with a call to
-   __register_frame.  On other targets, the information for each
+   __register_frame_info.  On other targets, the information for each
    translation unit is registered from the file generated by collect2.
-   __register_frame is defined in frame.c, and is responsible for
+   __register_frame_info is defined in frame.c, and is responsible for
    recording all of the unwind regions into one list (which is kept in a
    static variable named unwind_table_list).
 
@@ -107,7 +107,7 @@ Boston, MA 02111-1307, USA.  */
    throw. On machines that have unwind info support, __throw is generated
    by code in libgcc2.c, otherwise __throw is generated on a
    per-object-file basis for each source file compiled with
-   -fexceptions by the the C++ frontend.  Before __throw is invoked,
+   -fexceptions by the C++ frontend.  Before __throw is invoked,
    the current context of the throw needs to be placed in the global
    variable __eh_pc.
 
@@ -390,7 +390,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "defaults.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -404,6 +404,7 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-config.h"
 #include "recog.h"
 #include "output.h"
+#include "toplev.h"
 
 /* One to use setjmp/longjmp method of generating code for exception
    handling.  */
@@ -424,13 +425,6 @@ int protect_cleanup_actions_with_terminate;
 
 rtx exception_handler_labels;
 
-/* Nonzero means that __throw was invoked. 
-
-   This is used by the C++ frontend to know if code needs to be emitted
-   for __throw or not.  */
-
-int throw_used;
-
 /* The EH context.  Nonzero if the function has already
    fetched a pointer to the EH context  for exception handling.  */
 
@@ -489,9 +483,21 @@ struct label_node *outer_context_label_stack = NULL;
 
 struct label_node *false_label_stack = NULL;
 
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
+static void push_eh_entry      PROTO((struct eh_stack *));
+static struct eh_entry * pop_eh_entry          PROTO((struct eh_stack *));
+static void enqueue_eh_entry   PROTO((struct eh_queue *, struct eh_entry *));
+static struct eh_entry * dequeue_eh_entry      PROTO((struct eh_queue *));
+static rtx call_get_eh_context PROTO((void));
+static void start_dynamic_cleanup              PROTO((tree, tree));
+static void start_dynamic_handler              PROTO((void));
 static void expand_rethrow     PROTO((rtx));
+static void output_exception_table_entry       PROTO((FILE *, int));
+static int can_throw           PROTO((rtx));
+static rtx scan_region         PROTO((rtx, int, int *));
+static void eh_regs            PROTO((rtx *, rtx *, int));
+static void set_insn_eh_region PROTO((rtx *, int));
 
+rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 \f
 /* Various support routines to manipulate the various data structures
    used by the exception handling code.  */
@@ -547,20 +553,6 @@ top_label_entry (stack)
   return (*stack)->u.tlabel;
 }
 
-/* Make a copy of ENTRY using xmalloc to allocate the space.  */
-
-static struct eh_entry *
-copy_eh_entry (entry)
-     struct eh_entry *entry;
-{
-  struct eh_entry *newentry;
-
-  newentry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
-  bcopy ((char *) entry, (char *) newentry, sizeof (struct eh_entry));
-
-  return newentry;
-}
-
 /* Push a new eh_node entry onto STACK.  */
 
 static void
@@ -640,7 +632,7 @@ dequeue_eh_entry (queue)
   return tempentry;
 }
 \f
-/* Routine to see if exception exception handling is turned on.
+/* Routine to see if exception handling is turned on.
    DO_WARN is non-zero if we want to inform the user that exception
    handling is turned off. 
 
@@ -707,15 +699,13 @@ add_partial_entry (handler)
   pop_obstacks ();
 }
 
-/* Emit code to get EH context to current function.  Should only be used
-   by emit_eh_context.  */
+/* Emit code to get EH context to current function.  */
 
 static rtx
 call_get_eh_context ()
 {
   static tree fn;
   tree expr;
-  rtx ehc, reg, insns;
 
   if (fn == NULL_TREE)
     {
@@ -741,16 +731,7 @@ call_get_eh_context ()
                expr, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (expr) = 1;
 
-  start_sequence ();
-  ehc = expand_expr (expr, NULL_RTX, VOIDmode, 0);
-  reg = copy_to_reg (ehc);
-
-  insns = get_insns ();
-  end_sequence ();
-
-  emit_insns_before (insns, get_first_nonparm_insn ());
-
-  return reg;
+  return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
 }
 
 /* Get a reference to the EH context.
@@ -769,15 +750,13 @@ get_eh_context ()
 
       current_function_ehc = gen_reg_rtx (Pmode);
       
-      insn = gen_rtx (USE,
-                     GET_MODE (current_function_ehc),
-                     current_function_ehc);
+      insn = gen_rtx_USE (GET_MODE (current_function_ehc),
+                         current_function_ehc);
       insn = emit_insn_before (insn, get_first_nonparm_insn ());
 
       REG_NOTES (insn)
-       = gen_rtx (EXPR_LIST, 
-                  REG_EH_CONTEXT, current_function_ehc,
-                  REG_NOTES (insn));
+       = gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc,
+                            REG_NOTES (insn));
     }
   return current_function_ehc;
 }
@@ -802,7 +781,7 @@ get_dynamic_handler_chain ()
   result = copy_to_reg (dhc);
 
   /* We don't want a copy of the dcc, but rather, the single dcc.  */
-  return gen_rtx (MEM, Pmode, result);
+  return gen_rtx_MEM (Pmode, result);
 }
 
 /* Get a reference to the dynamic cleanup chain.  It points to the
@@ -822,7 +801,7 @@ get_dynamic_cleanup_chain ()
   result = copy_to_reg (dcc);
 
   /* We don't want a copy of the dcc, but rather, the single dcc.  */
-  return gen_rtx (MEM, Pmode, result);
+  return gen_rtx_MEM (Pmode, result);
 }
 
 /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
@@ -864,7 +843,7 @@ start_dynamic_cleanup (func, arg)
      tree func;
      tree arg;
 {
-  rtx dhc, dcc;
+  rtx dcc;
   rtx new_func, new_arg;
   rtx x, buf;
   int size;
@@ -889,10 +868,10 @@ start_dynamic_cleanup (func, arg)
 
   /* Store func and arg into the cleanup list element.  */
 
-  new_func = gen_rtx (MEM, Pmode, plus_constant (XEXP (buf, 0),
-                                                GET_MODE_SIZE (Pmode)));
-  new_arg = gen_rtx (MEM, Pmode, plus_constant (XEXP (buf, 0),
-                                               GET_MODE_SIZE (Pmode)*2));
+  new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+                                               GET_MODE_SIZE (Pmode)));
+  new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+                                              GET_MODE_SIZE (Pmode)*2));
   x = expand_expr (func, new_func, Pmode, 0);
   if (x != new_func)
     emit_move_insn (new_func, x);
@@ -945,8 +924,8 @@ start_dynamic_handler ()
   /* Store dhc into the first word of the newly allocated buffer.  */
 
   dhc = get_dynamic_handler_chain ();
-  dcc = gen_rtx (MEM, Pmode, plus_constant (XEXP (arg, 0),
-                                           GET_MODE_SIZE (Pmode)));
+  dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0),
+                                          GET_MODE_SIZE (Pmode)));
   emit_move_insn (arg, dhc);
 
   /* Zero out the start of the cleanup chain.  */
@@ -958,15 +937,18 @@ start_dynamic_handler ()
 #ifdef DONT_USE_BUILTIN_SETJMP
   x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
                               buf, Pmode);
+  /* If we come back here for a catch, transfer control to the handler.  */
+  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
 #else
-  x = expand_builtin_setjmp (buf, NULL_RTX);
+  {
+    /* A label to continue execution for the no exception case.  */
+    rtx noex = gen_label_rtx();
+    x = expand_builtin_setjmp (buf, NULL_RTX, noex,
+                              ehstack.top->entry->exception_handler_label);
+    emit_label (noex);
+  }
 #endif
 
-  /* If we come back here for a catch, transfer control to the
-     handler.  */
-
-  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
-
   /* We are committed to this, so update the handler chain.  */
 
   emit_move_insn (dhc, XEXP (arg, 0));
@@ -983,15 +965,13 @@ start_dynamic_handler ()
    This routine notices one particular common case in C++ code
    generation, and optimizes it so as to not need the exception
    region.  It works by creating a dynamic cleanup action, instead of
-   of a using an exception region.  */
+   a using an exception region.  */
 
 int
 expand_eh_region_start_tree (decl, cleanup)
      tree decl;
      tree cleanup;
 {
-  rtx note;
-
   /* This is the old code.  */
   if (! doing_eh (0))
     return 0;
@@ -1222,7 +1202,6 @@ emit_throw ()
 #else
       emit_library_call (throw_libfunc, 0, VOIDmode, 0);
 #endif
-      throw_used = 1;
     }
   emit_barrier ();
 }
@@ -1570,19 +1549,7 @@ exception_table_p ()
   return 0;
 }
 
-/* 1 if we need a static constructor to register EH table info.  */
-
-int
-register_exception_table_p ()
-{
-#if defined (DWARF2_UNWIND_INFO)
-  return 0;
-#endif
-
-  return exception_table_p ();
-}
-
-/* Output the entry of the exception table corresponding to to the
+/* Output the entry of the exception table corresponding to the
    exception region numbered N to file FILE. 
 
    N is the code label number corresponding to the handler of the
@@ -1597,15 +1564,15 @@ output_exception_table_entry (file, n)
   rtx sym;
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
-  sym = gen_rtx (SYMBOL_REF, Pmode, buf);
+  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
-  sym = gen_rtx (SYMBOL_REF, Pmode, buf);
+  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
-  sym = gen_rtx (SYMBOL_REF, Pmode, buf);
+  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   putc ('\n', file);           /* blank line */
@@ -1639,18 +1606,6 @@ output_exception_table ()
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
   putc ('\n', asm_out_file);           /* blank line */
 }
-
-/* Generate code to initialize the exception table at program startup
-   time.  */
-
-void
-register_exception_table ()
-{
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
-                    VOIDmode, 1,
-                    gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
-                    Pmode);
-}
 \f
 /* Emit code to get EH context.
    
@@ -1678,11 +1633,15 @@ emit_eh_context ()
          {
            rtx insns;
            
-           /* If this is the first use insn, emit the call. */
+           start_sequence ();
+
+           /* If this is the first use insn, emit the call here.  This
+              will always be at the top of our function, because if
+              expand_inline_function notices a REG_EH_CONTEXT note, it
+              adds a use insn to this function as well.  */
            if (ehc == 0)
              ehc = call_get_eh_context ();
 
-           start_sequence ();
            emit_move_insn (XEXP (reg, 0), ehc);
            insns = get_insns ();
            end_sequence ();
@@ -1748,8 +1707,8 @@ find_exception_handler_labels ()
 
              if (label)
                exception_handler_labels
-                 = gen_rtx (EXPR_LIST, VOIDmode,
-                            label, exception_handler_labels);
+                 = gen_rtx_EXPR_LIST (VOIDmode,
+                                      label, exception_handler_labels);
              else
                warning ("didn't find handler for EH region %d",
                         NOTE_BLOCK_NUMBER (insn));
@@ -1820,7 +1779,7 @@ check_exception_handler_labels ()
                  == NOTE_BLOCK_NUMBER (insn))
                break;
            }
-         if (handler == NULL_RTX)
+         if (handler == NULL_RTX && !flag_syntax_only)
            warning ("region exists, no handler %d",
                     NOTE_BLOCK_NUMBER (insn));
        }
@@ -1838,9 +1797,6 @@ check_exception_handler_labels ()
 void
 init_eh ()
 {
-  /* Generate rtl to reference the variable in which the PC of the
-     current context is saved.  */
-  tree type = build_pointer_type (make_node (VOID_TYPE));
 }
 
 /* Initialize the per-function EH information.  */
@@ -1877,7 +1833,7 @@ save_eh_status (p)
   p->protect_list = protect_list;
   p->ehc = current_function_ehc;
 
-  init_eh ();
+  init_eh_for_function ();
 }
 
 /* Restore the per-function EH info saved into the area denoted by P.  
@@ -2042,7 +1998,7 @@ scan_region (insn, n, delete_outer)
 void
 exception_optimize ()
 {
-  rtx insn, regions = NULL_RTX;
+  rtx insn;
   int n;
 
   /* Remove empty regions.  */
@@ -2165,7 +2121,7 @@ eh_regs (r1, r2, outgoing)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
        if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
          {
-           reg2 = gen_rtx (REG, Pmode, i);
+           reg2 = gen_rtx_REG (Pmode, i);
            break;
          }
 
@@ -2186,7 +2142,7 @@ expand_builtin_eh_stub ()
 {
   rtx stub_start = gen_label_rtx ();
   rtx after_stub = gen_label_rtx ();
-  rtx handler, offset, temp;
+  rtx handler, offset;
 
   emit_jump (after_stub);
   emit_label (stub_start);
@@ -2197,7 +2153,7 @@ expand_builtin_eh_stub ()
   emit_indirect_jump (handler);
 
   emit_label (after_stub);
-  return gen_rtx (LABEL_REF, Pmode, stub_start);
+  return gen_rtx_LABEL_REF (Pmode, stub_start);
 }
 
 /* Set up the registers for passing the handler address and stack offset
@@ -2215,6 +2171,113 @@ expand_builtin_set_eh_regs (handler, offset)
   store_expr (handler, reg1, 0);
 
   /* These will be used by the stub.  */
-  emit_insn (gen_rtx (USE, VOIDmode, reg1));
-  emit_insn (gen_rtx (USE, VOIDmode, reg2));
+  emit_insn (gen_rtx_USE (VOIDmode, reg1));
+  emit_insn (gen_rtx_USE (VOIDmode, reg2));
 }
+
+\f
+
+/* This contains the code required to verify whether arbitrary instructions
+   are in the same exception region. */
+
+static int *insn_eh_region = (int *)0;
+static int maximum_uid;
+
+static void
+set_insn_eh_region (first, region_num)
+     rtx *first;
+     int region_num;
+{
+  rtx insn;
+  int rnum;
+
+  for (insn = *first; insn; insn = NEXT_INSN (insn))
+    {
+      if ((GET_CODE (insn) == NOTE) && 
+                        (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
+        {
+          rnum = NOTE_BLOCK_NUMBER (insn);
+          insn_eh_region[INSN_UID (insn)] =  rnum;
+          insn = NEXT_INSN (insn);
+          set_insn_eh_region (&insn, rnum);
+          /* Upon return, insn points to the EH_REGION_END of nested region */
+          continue;
+        }
+      insn_eh_region[INSN_UID (insn)] = region_num;
+      if ((GET_CODE (insn) == NOTE) && 
+            (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
+        break;
+    }
+  *first = insn;
+}
+
+/* Free the insn table, an make sure it cannot be used again. */
+
+void free_insn_eh_region () 
+{
+  if (!doing_eh (0))
+    return;
+
+  if (insn_eh_region)
+    {
+      free (insn_eh_region);
+      insn_eh_region = (int *)0;
+    }
+}
+
+/* Initialize the table. max_uid must be calculated and handed into 
+   this routine. If it is unavailable, passing a value of 0 will 
+   cause this routine to calculate it as well. */
+
+void init_insn_eh_region (first, max_uid)
+     rtx first;
+     int max_uid;
+{
+  rtx insn;
+
+  if (!doing_eh (0))
+    return;
+
+  if (insn_eh_region)
+    free_insn_eh_region();
+
+  if (max_uid == 0) 
+    for (insn = first; insn; insn = NEXT_INSN (insn))
+      if (INSN_UID (insn) > max_uid)       /* find largest UID */
+        max_uid = INSN_UID (insn);
+
+  maximum_uid = max_uid;
+  insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
+  insn = first;
+  set_insn_eh_region (&insn, 0);
+}
+
+
+/* Check whether 2 instructions are within the same region. */
+
+int in_same_eh_region(insn1, insn2) 
+     rtx insn1,insn2;
+{
+  int ret, uid1, uid2;
+
+  /* If no exceptions, instructions are always in same region. */
+  if (!doing_eh (0))
+    return 1;
+
+  /* If the table isn't allocated, assume the worst. */
+  if (!insn_eh_region)  
+    return 0;
+
+  uid1 = INSN_UID (insn1);
+  uid2 = INSN_UID (insn2);
+
+  /* if instructions have been allocated beyond the end, either
+     the table is out of date, or this is a late addition, or
+     something... Assume the worst. */
+  if (uid1 > maximum_uid || uid2 > maximum_uid)
+    return 0;
+
+  ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
+  return ret;
+}
+