OSDN Git Service

* config/stormy16/stormy16.h: Remove DEFAULT_VTABLE_THUNKS.
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 163d5ed..cc7177d 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"
@@ -62,12 +63,13 @@ 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"
 #include "ggc.h"
 #include "tm_p.h"
-
+#include "target.h"
 
 /* Provide defaults for stuff that may not be defined when using
    sjlj exceptions.  */
@@ -87,7 +89,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));
@@ -99,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.  */
@@ -126,7 +128,8 @@ struct eh_region
   /* Each region does exactly one thing.  */
   enum eh_region_type
   {
-    ERT_CLEANUP = 1,
+    ERT_UNKNOWN = 0,
+    ERT_CLEANUP,
     ERT_TRY,
     ERT_CATCH,
     ERT_ALLOWED_EXCEPTIONS,
@@ -135,7 +138,7 @@ struct eh_region
     ERT_FIXUP
   } type;
 
-  /* Holds the action to perform based on the preceeding type.  */
+  /* Holds the action to perform based on the preceding type.  */
   union {
     /* A list of catch blocks, a surrounding try block,
        and the label for continuing after a catch.  */
@@ -146,13 +149,13 @@ struct eh_region
       rtx continue_label;
     } try;
 
-    /* The list through the catch handlers, the type object
-       matched, and a pointer to the generated code.  */
+    /* The list through the catch handlers, the list of type objects
+       matched, and the list of associated filters.  */
     struct {
       struct eh_region *next_catch;
       struct eh_region *prev_catch;
-      tree type;
-      int filter;
+      tree type_list;
+      tree filter_list;
     } catch;
 
     /* A tree_list of allowed types.  */
@@ -255,7 +258,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 +332,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 +369,6 @@ void
 init_eh ()
 {
   ggc_add_rtx_root (&exception_handler_labels, 1);
-  ggc_add_tree_root (&protect_cleanup_actions, 1);
 
   if (! flag_exceptions)
     return;
@@ -478,6 +479,10 @@ mark_eh_region (region)
 
   switch (region->type)
     {
+    case ERT_UNKNOWN:
+      /* This can happen if a nested function is inside the body of a region
+        and we do a GC as part of processing it.  */
+      break;
     case ERT_CLEANUP:
       ggc_mark_tree (region->u.cleanup.exp);
       break;
@@ -485,7 +490,8 @@ mark_eh_region (region)
       ggc_mark_rtx (region->u.try.continue_label);
       break;
     case ERT_CATCH:
-      ggc_mark_tree (region->u.catch.type);
+      ggc_mark_tree (region->u.catch.type_list);
+      ggc_mark_tree (region->u.catch.filter_list);
       break;
     case ERT_ALLOWED_EXCEPTIONS:
       ggc_mark_tree (region->u.allowed.type_list);
@@ -643,17 +649,6 @@ expand_eh_region_start ()
   if (! doing_eh (0))
     return;
 
-  /* We need a new block to record the start and end of the dynamic
-     handler chain.  We also want to prevent jumping into a try block.  */
-  expand_start_bindings (2);
-
-  /* But we don't need or want a new temporary level.  */
-  pop_temp_slots ();
-
-  /* Mark this block as created by expand_eh_region_start.  This is so
-     that we can pop the block with expand_end_bindings automatically.  */
-  mark_block_as_eh_region ();
-
   /* Insert a new blank region as a leaf in the tree.  */
   new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region));
   cur_region = cfun->eh->cur_region;
@@ -672,7 +667,7 @@ expand_eh_region_start ()
 
   /* Create a note marking the start of this region.  */
   new_region->region_number = ++cfun->eh->last_region_number;
-  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
+  note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
   NOTE_EH_HANDLER (note) = new_region->region_number;
 }
 
@@ -684,27 +679,13 @@ expand_eh_region_end ()
   struct eh_region *cur_region = cfun->eh->cur_region;
   rtx note;
 
-  /* Create a nute marking the end of this region.  */
-  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
+  /* Create a note marking the end of this region.  */
+  note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
   NOTE_EH_HANDLER (note) = cur_region->region_number;
 
   /* Pop.  */
   cfun->eh->cur_region = cur_region->outer;
 
-  /* If we have already started ending the bindings, don't recurse.  */
-  if (is_eh_region ())
-    {
-      /* Because we don't need or want a new temporary level and
-        because we didn't create one in expand_eh_region_start,
-        create a fake one now to avoid removing one in
-        expand_end_bindings.  */
-      push_temp_slots ();
-
-      mark_block_as_not_eh_region ();
-
-      expand_end_bindings (NULL_TREE, 0, 0);
-    }
-
   return cur_region;
 }
 
@@ -716,6 +697,7 @@ expand_eh_region_end_cleanup (handler)
      tree handler;
 {
   struct eh_region *region;
+  tree protect_cleanup_actions;
   rtx around_label;
   rtx data_save[2];
 
@@ -732,15 +714,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 propagate 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 ());
-  data_save[1] = gen_reg_rtx (Pmode);
-  emit_move_insn (data_save[1], get_exception_filter ());
+  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 (cfun));
 
   expand_expr (handler, const0_rtx, VOIDmode, 0);
 
@@ -784,26 +773,44 @@ expand_start_all_catch ()
   emit_jump (region->u.try.continue_label);
 }
 
-/* Begin a catch clause.  TYPE is the type caught, or null if this is
-   a catch-all clause.  */
+/* Begin a catch clause.  TYPE is the type caught, a list of such types, or
+   null if this is a catch-all clause. Providing a type list enables to
+   associate the catch region with potentially several exception types, which
+   is useful e.g. for Ada. */
 
 void
-expand_start_catch (type)
-     tree type;
+expand_start_catch (type_or_list)
+     tree type_or_list;
 {
   struct eh_region *t, *c, *l;
+  tree type_list;
 
   if (! doing_eh (0))
     return;
 
-  if (type)
-    add_type_for_runtime (type);
+  type_list = type_or_list;
+
+  if (type_or_list)
+    {
+      /* Ensure to always end up with a type list to normalize further
+         processing, then register each type against the runtime types
+         map.  */
+      tree type_node;
+
+      if (TREE_CODE (type_or_list) != TREE_LIST)
+        type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
+
+      type_node = type_list;
+      for (; type_node; type_node = TREE_CHAIN (type_node))
+        add_type_for_runtime (TREE_VALUE (type_node));
+    }
+
   expand_eh_region_start ();
 
   t = cfun->eh->try_region;
   c = cfun->eh->cur_region;
   c->type = ERT_CATCH;
-  c->u.catch.type = type;
+  c->u.catch.type_list = type_list;
   c->label = gen_label_rtx ();
 
   l = t->u.try.last_catch;
@@ -851,7 +858,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 occurs.
+
+   ??? 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)
@@ -880,6 +891,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);
 }
@@ -965,13 +980,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;
 }
@@ -980,13 +996,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 (Pmode);
-      cfun->eh->filter = filter;
+      filter = gen_reg_rtx (word_mode);
+      fun->eh->filter = filter;
     }
   return filter;
 }
@@ -1100,7 +1117,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;
@@ -1126,11 +1143,30 @@ static void
 remove_fixup_regions ()
 {
   int i;
+  rtx insn, note;
+  struct eh_region *fixup;
 
+  /* Walk the insn chain and adjust the REG_EH_REGION numbers
+     for instructions referencing fixup regions.  This is only
+     strictly necessary for fixup regions with no parent, but
+     doesn't hurt to do it for all regions.  */
+  for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && (note = find_reg_note (insn, REG_EH_REGION, NULL))
+       && INTVAL (XEXP (note, 0)) > 0
+       && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
+       && fixup->type == ERT_FIXUP)
+      {
+       if (fixup->u.fixup.real_region)
+         XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
+       else
+         remove_note (insn, note);
+      }
+
+  /* Remove the fixup regions from the tree.  */
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *fixup = cfun->eh->region_array[i];
-
+      fixup = cfun->eh->region_array[i];
       if (! fixup)
        continue;
 
@@ -1233,6 +1269,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),
@@ -1334,7 +1372,7 @@ duplicate_eh_region_1 (o, map)
       break;
 
     case ERT_CATCH:
-      n->u.catch.type = o->u.catch.type;
+      n->u.catch.type_list = o->u.catch.type_list;
       break;
 
     case ERT_ALLOWED_EXCEPTIONS:
@@ -1437,7 +1475,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
@@ -1461,9 +1499,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;
@@ -1524,7 +1559,7 @@ lookup_type_for_runtime (type)
   slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
                                            TYPE_HASH (type), NO_INSERT);
 
-  /* We should have always inserrted the data earlier.  */
+  /* We should have always inserted the data earlier.  */
   return TREE_VALUE (*slot);
 }
 
@@ -1682,7 +1717,36 @@ assign_filter_values ()
       switch (r->type)
        {
        case ERT_CATCH:
-         r->u.catch.filter = add_ttypes_entry (ttypes, r->u.catch.type);
+         /* Whatever type_list is (NULL or true list), we build a list
+            of filters for the region.  */
+         r->u.catch.filter_list = NULL_TREE;
+
+         if (r->u.catch.type_list != NULL)
+           {
+             /* Get a filter value for each of the types caught and store
+                them in the region's dedicated list.  */
+             tree tp_node = r->u.catch.type_list;
+
+             for (;tp_node; tp_node = TREE_CHAIN (tp_node))
+               {
+                 int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
+                 tree flt_node = build_int_2 (flt, 0);
+                 
+                 r->u.catch.filter_list 
+                   = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
+               }
+           }
+         else
+           {
+             /* Get a filter value for the NULL list also since it will need
+                an action record anyway.  */
+             int flt = add_ttypes_entry (ttypes, NULL);
+             tree flt_node = build_int_2 (flt, 0);
+             
+             r->u.catch.filter_list 
+               = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
+           }
+             
          break;
 
        case ERT_ALLOWED_EXCEPTIONS:
@@ -1720,7 +1784,7 @@ build_post_landing_pads ()
               all the way up the chain until blocked by a cleanup.  */
          /* ??? Outer try regions can share landing pads with inner
             try regions if the types are completely non-overlapping,
-            and there are no interveaning cleanups.  */
+            and there are no intervening cleanups.  */
 
          region->post_landing_pad = gen_label_rtx ();
 
@@ -1736,13 +1800,27 @@ build_post_landing_pads ()
            for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
              {
                /* ??? _Unwind_ForcedUnwind wants no match here.  */
-               if (c->u.catch.type == NULL)
+               if (c->u.catch.type_list == NULL)
                  emit_jump (c->label);
                else
-                 emit_cmp_and_jump_insns (cfun->eh->filter,
-                                          GEN_INT (c->u.catch.filter),
-                                          EQ, NULL_RTX, word_mode,
-                                          0, 0, c->label);
+                 {
+                   /* Need for one cmp/jump per type caught. Each type
+                      list entry has a matching entry in the filter list
+                      (see assign_filter_values).  */
+                   tree tp_node = c->u.catch.type_list;
+                   tree flt_node = c->u.catch.filter_list;
+
+                   for (; tp_node; )
+                     {
+                       emit_cmp_and_jump_insns
+                         (cfun->eh->filter,
+                          GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
+                          EQ, NULL_RTX, word_mode, 0, c->label);
+
+                       tp_node = TREE_CHAIN (tp_node);
+                       flt_node = TREE_CHAIN (flt_node);
+                     }
+                 }
              }
          }
 
@@ -1768,8 +1846,7 @@ build_post_landing_pads ()
 
          emit_cmp_and_jump_insns (cfun->eh->filter,
                                   GEN_INT (region->u.allowed.filter),
-                                  EQ, NULL_RTX, word_mode, 0, 0,
-                                  region->label);
+                                  EQ, NULL_RTX, word_mode, 0, region->label);
 
          /* We delay the generation of the _Unwind_Resume until we generate
             landing pads.  We emit a marker here so as to get good control
@@ -1839,8 +1916,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);
     }
 }
 
@@ -1848,12 +1924,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)
@@ -1890,13 +1968,25 @@ 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,
                      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 ();
@@ -1990,7 +2080,7 @@ sjlj_assign_call_site_values (dispatch_label, lp_info)
 
      A region receives a dispatch index if it is directly reachable
      and requires in-function processing.  Regions that share post-landing
-     pads may share dispatch indicies.  */
+     pads may share dispatch indices.  */
   /* ??? Post-landing pad sharing doesn't actually happen at the moment
      (see build_post_landing_pads) so we don't bother checking for it.  */
 
@@ -2031,10 +2121,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;
@@ -2077,48 +2163,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 ();
-
-               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 ();
@@ -2140,12 +2189,14 @@ sjlj_emit_function_enter (dispatch_label)
 
   start_sequence ();
 
-  mem = change_address (fc, Pmode,
-                       plus_constant (XEXP (fc, 0), sjlj_fc_personality_ofs));
+  /* 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 = 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];
@@ -2158,7 +2209,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);
@@ -2167,8 +2218,7 @@ sjlj_emit_function_enter (dispatch_label)
     NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
 
     emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
-                            TYPE_MODE (integer_type_node), 0, 0,
-                            dispatch_label);
+                            TYPE_MODE (integer_type_node), 0, dispatch_label);
   }
 #else
   expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
@@ -2242,12 +2292,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
@@ -2258,9 +2307,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.  */
@@ -2279,9 +2326,8 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
          continue;
        }
 
-      emit_cmp_and_jump_insns (dispatch,
-                              GEN_INT (lp_info[i].dispatch_index), EQ,
-                              NULL_RTX, TYPE_MODE (integer_type_node), 0, 0,
+      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
+                              EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
                               cfun->eh->region_array[i]->post_landing_pad);
     }
 
@@ -2336,14 +2382,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.  */
 
@@ -2359,9 +2405,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.  */
@@ -2589,7 +2635,7 @@ reachable_next_level (region, type_thrown, info)
            /* A catch-all handler ends the search.  */
            /* ??? _Unwind_ForcedUnwind will want outer cleanups
               to be run as well.  */
-           if (c->u.catch.type == NULL)
+           if (c->u.catch.type_list == NULL)
              {
                add_reachable_handler (info, region, c);
                return RNL_CAUGHT;
@@ -2597,14 +2643,20 @@ reachable_next_level (region, type_thrown, info)
 
            if (type_thrown)
              {
-               /* If we have a type match, end the search.  */
-               if (c->u.catch.type == type_thrown
-                   || (lang_eh_type_covers
-                       && (*lang_eh_type_covers) (c->u.catch.type,
-                                                  type_thrown)))
+               /* If we have a at least one type match, end the search.  */
+               tree tp_node = c->u.catch.type_list;
+               
+               for (; tp_node; tp_node = TREE_CHAIN (tp_node))
                  {
-                   add_reachable_handler (info, region, c);
-                   return RNL_CAUGHT;
+                   tree type = TREE_VALUE (tp_node);
+
+                   if (type == type_thrown
+                       || (lang_eh_type_covers
+                           && (*lang_eh_type_covers) (type, type_thrown)))
+                     {
+                       add_reachable_handler (info, region, c);
+                       return RNL_CAUGHT;
+                     }
                  }
 
                /* If we have definitive information of a match failure,
@@ -2613,19 +2665,49 @@ reachable_next_level (region, type_thrown, info)
                  return RNL_NOT_CAUGHT;
              }
 
+           /* At this point, we either don't know what type is thrown or
+              don't have front-end assistance to help deciding if it is
+              covered by one of the types in the list for this region.
+           
+              We'd then like to add this region to the list of reachable
+              handlers since it is indeed potentially reachable based on the
+              information we have. 
+              
+              Actually, this handler is for sure not reachable if all the
+              types it matches have already been caught. That is, it is only
+              potentially reachable if at least one of the types it catches
+              has not been previously caught.  */
+
            if (! info)
              ret = RNL_MAYBE_CAUGHT;
-
-           /* A type must not have been previously caught.  */
-           else if (! check_handled (info->types_caught, c->u.catch.type))
+           else
              {
-               add_reachable_handler (info, region, c);
-               info->types_caught = tree_cons (NULL, c->u.catch.type,
-                                               info->types_caught);
+               tree tp_node = c->u.catch.type_list;
+               bool maybe_reachable = false;
 
-               /* ??? If the catch type is a base class of every allowed
-                  type, then we know we can stop the search.  */
-               ret = RNL_MAYBE_CAUGHT;
+               /* Compute the potential reachability of this handler and
+                  update the list of types caught at the same time.  */
+               for (; tp_node; tp_node = TREE_CHAIN (tp_node))
+                 {
+                   tree type = TREE_VALUE (tp_node);
+
+                   if (! check_handled (info->types_caught, type))
+                     {
+                       info->types_caught
+                         = tree_cons (NULL, type, info->types_caught);
+                       
+                       maybe_reachable = true;
+                     }
+                 }
+               
+               if (maybe_reachable)
+                 {
+                   add_reachable_handler (info, region, c);
+               
+                   /* ??? If the catch type is a base class of every allowed
+                      type, then we know we can stop the search.  */
+                   ret = RNL_MAYBE_CAUGHT;
+                 }
              }
          }
 
@@ -2647,7 +2729,7 @@ reachable_next_level (region, type_thrown, info)
                                         region->u.allowed.type_list,
                                         info->types_allowed);
            
-      /* If we have definitive information about the type heirarchy,
+      /* If we have definitive information about the type hierarchy,
         then we can tell if the thrown type will pass through the
         filter.  */
       if (type_thrown && lang_eh_type_covers)
@@ -2718,14 +2800,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)
@@ -2891,7 +2979,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
@@ -2956,7 +3044,12 @@ rtx
 expand_builtin_frob_return_addr (addr_tree)
      tree addr_tree;
 {
-  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (addr) != Pmode)
+    addr = convert_memory_address (Pmode, addr);
+#endif
 
 #ifdef RETURN_ADDR_OFFSET
   addr = force_reg (Pmode, addr);
@@ -2978,6 +3071,14 @@ 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
+  if (GET_MODE (stackadj) != Pmode)
+    stackadj = convert_memory_address (Pmode, stackadj);
+
+  if (GET_MODE (handler) != Pmode)
+    handler = convert_memory_address (Pmode, handler);
+#endif
+
   if (! cfun->eh->ehr_label)
     {
       cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
@@ -3039,6 +3140,17 @@ expand_eh_return ()
   emit_label (around_label);
 }
 \f
+/* In the following functions, we represent entries in the action table
+   as 1-based indices.  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;
@@ -3086,7 +3198,7 @@ add_action_record (ar_hash, filter, next)
       /* The filter value goes in untouched.  The link to the next
         record is a "self-relative" byte offset, or zero to indicate
         that there is no next record.  So convert the absolute 1 based
-        indicies we've been carrying around into a displacement.  */
+        indices we've been carrying around into a displacement.  */
 
       push_sleb128 (&cfun->eh->action_record_data, filter);
       if (next)
@@ -3131,21 +3243,46 @@ collect_one_action_chain (ar_hash, region)
       /* Process the associated catch regions in reverse order.
         If there's a catch-all handler, then we don't need to
         search outer regions.  Use a magic -3 value to record
-        that we havn't done the outer search.  */
+        that we haven't done the outer search.  */
       next = -3;
       for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
        {
-         if (c->u.catch.type == NULL)
-           next = add_action_record (ar_hash, c->u.catch.filter, 0);
+         if (c->u.catch.type_list == NULL)
+           {
+             /* Retrieve the filter from the head of the filter list
+                where we have stored it (see assign_filter_values).  */
+             int filter 
+               = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
+
+             next = add_action_record (ar_hash, filter, 0);
+           }
          else
            {
+             /* Once the outer search is done, trigger an action record for
+                 each filter we have.  */
+             tree flt_node;
+
              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);
+               }
+             
+             flt_node = c->u.catch.filter_list;
+             for (; flt_node; flt_node = TREE_CHAIN (flt_node))
+               {
+                 int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
+                 next = add_action_record (ar_hash, filter, next);
                }
-             next = add_action_record (ar_hash, c->u.catch.filter, next);
            }
        }
       return next;
@@ -3214,7 +3351,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;
@@ -3367,83 +3504,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 ()
@@ -3482,7 +3542,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;
@@ -3552,7 +3612,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];
@@ -3562,6 +3622,7 @@ output_function_exception_table ()
 #endif
   int have_tt_data;
   int funcdef_number;
+  int tt_format_size = 0;
 
   /* Not all functions need anything.  */
   if (! cfun->uses_eh_lsda)
@@ -3571,13 +3632,32 @@ output_function_exception_table ()
                    ? sjlj_funcdef_number
                    : current_funcdef_number);
 
-  exception_section ();
+#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
+  (*targetm.asm_out.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_align (tt_format_size * BITS_PER_UNIT);
+    }
 
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
 
@@ -3589,26 +3669,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)
@@ -3629,14 +3697,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
@@ -3646,8 +3714,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;
@@ -3660,12 +3728,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",
@@ -3695,20 +3763,25 @@ output_function_exception_table ()
                         (i ? NULL : "Action record table"));
 
   if (have_tt_data)
-    assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+    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);
 
-      /* ??? Handle ASM_PREFERRED_DATA_FORMAT.  */
-      output_constant (type, GET_MODE_SIZE (ptr_mode));
+      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