OSDN Git Service

* alpha.c (reg_or_6bit_operand): Remove CONSTANT_P_RTX handling.
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 2ba9ac3..152a1c0 100644 (file)
@@ -34,9 +34,9 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "recog.h"
 #include "reload.h"
+#include "tree.h"
 #include "expr.h"
 #include "obstack.h"
-#include "tree.h"
 #include "except.h"
 #include "function.h"
 #include "toplev.h"
@@ -79,6 +79,10 @@ char *alpha_mlat_string;     /* -mmemory-latency= */
 rtx alpha_compare_op0, alpha_compare_op1;
 int alpha_compare_fp_p;
 
+/* Define the information needed to modify the epilogue for EH.  */
+
+rtx alpha_eh_epilogue_sp_ofs;
+
 /* Non-zero if inside of a function, because the Alpha asm can't
    handle .files inside of functions.  */
 
@@ -96,6 +100,10 @@ int alpha_memory_latency = 3;
 
 static int alpha_function_needs_gp;
 
+/* The alias set for prologue/epilogue register save/restore.  */
+
+static int alpha_sr_alias_set;
+
 /* Declarations of static functions.  */
 static void alpha_set_memflags_1
   PROTO((rtx, int, int, int));
@@ -256,11 +264,11 @@ override_options ()
     if (!alpha_mlat_string)
       alpha_mlat_string = "L1";
 
-    if (isdigit (alpha_mlat_string[0])
+    if (ISDIGIT ((unsigned char)alpha_mlat_string[0])
        && (lat = strtol (alpha_mlat_string, &end, 10), *end == '\0'))
       ;
     else if ((alpha_mlat_string[0] == 'L' || alpha_mlat_string[0] == 'l')
-            && isdigit (alpha_mlat_string[1])
+            && ISDIGIT ((unsigned char)alpha_mlat_string[1])
             && alpha_mlat_string[2] == '\0')
       {
        static int const cache_latency[][4] = 
@@ -298,6 +306,9 @@ override_options ()
   /* Default the definition of "small data" to 8 bytes.  */
   if (!g_switch_set)
     g_switch_value = 8;
+
+  /* Acquire a unique set number for our register saves and restores.  */
+  alpha_sr_alias_set = new_alias_set ();
 }
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -337,7 +348,6 @@ reg_or_6bit_operand (op, mode)
 {
   return ((GET_CODE (op) == CONST_INT
           && (unsigned HOST_WIDE_INT) INTVAL (op) < 64)
-         || GET_CODE (op) == CONSTANT_P_RTX
          || register_operand (op, mode));
 }
 
@@ -351,7 +361,6 @@ reg_or_8bit_operand (op, mode)
 {
   return ((GET_CODE (op) == CONST_INT
           && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
-         || GET_CODE (op) == CONSTANT_P_RTX
          || register_operand (op, mode));
 }
 
@@ -363,8 +372,7 @@ cint8_operand (op, mode)
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return ((GET_CODE (op) == CONST_INT
-          && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
-         || GET_CODE (op) == CONSTANT_P_RTX);
+          && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100));
 }
 
 /* Return 1 if the operand is a valid second operand to an add insn.  */
@@ -375,11 +383,9 @@ add_operand (op, mode)
      enum machine_mode mode;
 {
   if (GET_CODE (op) == CONST_INT)
+    /* Constraints I, J, O and P are covered by K.  */
     return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
-           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')
-           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
-  else if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
+           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
 
   return register_operand (op, mode);
 }
@@ -393,10 +399,8 @@ sext_add_operand (op, mode)
      enum machine_mode mode;
 {
   if (GET_CODE (op) == CONST_INT)
-    return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255
-           || (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255);
-  else if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
+    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
+           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
 
   return register_operand (op, mode);
 }
@@ -427,8 +431,6 @@ and_operand (op, mode)
     return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
            || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
            || zap_mask (INTVAL (op)));
-  else if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
 
   return register_operand (op, mode);
 }
@@ -443,8 +445,6 @@ or_operand (op, mode)
   if (GET_CODE (op) == CONST_INT)
     return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
            || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100);
-  else if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
 
   return register_operand (op, mode);
 }
@@ -483,9 +483,9 @@ mode_mask_operand (op, mode)
   return (GET_CODE (op) == CONST_INT
          && (INTVAL (op) == 0xff
              || INTVAL (op) == 0xffff
-             || INTVAL (op) == 0xffffffff
+             || INTVAL (op) == (HOST_WIDE_INT)0xffffffff
 #if HOST_BITS_PER_WIDE_INT == 64
-             || INTVAL (op) == 0xffffffffffffffff
+             || INTVAL (op) == -1
 #endif
              ));
 }
@@ -544,7 +544,6 @@ reg_or_cint_operand (op, mode)
     enum machine_mode mode;
 {
      return (GET_CODE (op) == CONST_INT
-            || GET_CODE (op) == CONSTANT_P_RTX
             || register_operand (op, mode));
 }
 
@@ -562,7 +561,7 @@ some_operand (op, mode)
   switch (GET_CODE (op))
     {
     case REG:  case MEM:  case CONST_DOUBLE:  case CONST_INT:  case LABEL_REF:
-    case SYMBOL_REF:  case CONST:  case CONSTANT_P_RTX:
+    case SYMBOL_REF:  case CONST:
       return 1;
 
     case SUBREG:
@@ -611,7 +610,6 @@ input_operand (op, mode)
       return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
 
     case CONST_INT:
-    case CONSTANT_P_RTX:
       return mode == QImode || mode == HImode || add_operand (op, mode);
 
     default:
@@ -822,6 +820,31 @@ any_memory_operand (op, mode)
              && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));
 }
 
+/* Returns 1 if OP is not an eliminable register.
+
+   This exists to cure a pathological abort in the s8addq (et al) patterns,
+
+       long foo () { long t; bar(); return (long) &t * 26107; }
+
+   which run afoul of a hack in reload to cure a (presumably) similar
+   problem with lea-type instructions on other targets.  But there is
+   one of us and many of them, so work around the problem by selectively
+   preventing combine from making the optimization.  */
+
+int
+reg_not_elim_operand (op, mode)
+      register rtx op;
+      enum machine_mode mode;
+{
+  rtx inner = op;
+  if (GET_CODE (op) == SUBREG)
+    inner = SUBREG_REG (op);
+  if (inner == frame_pointer_rtx || inner == arg_pointer_rtx)
+    return 0;
+
+  return register_operand (op, mode);
+}
+\f
 /* Return 1 if this function can directly return via $26.  */
 
 int
@@ -866,12 +889,15 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
   if (GET_CODE (base) == PLUS)
     offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  *paligned_mem = gen_rtx_MEM (SImode,
-                          plus_constant (base, offset & ~3));
+  *paligned_mem = gen_rtx_MEM (SImode, plus_constant (base, offset & ~3));
   MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref);
   MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref);
   RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref);
 
+  /* Sadly, we cannot use alias sets here because we may overlap other
+     data in a different alias set.  */
+  /* MEM_ALIAS_SET (*paligned_mem) = MEM_ALIAS_SET (ref); */
+
   *pbitnum = GEN_INT ((offset & 3) * 8);
 }
 
@@ -945,6 +971,12 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
       MEM_IN_STRUCT_P (x) = in_struct_p;
       MEM_VOLATILE_P (x) = volatile_p;
       RTX_UNCHANGING_P (x) = unchanging_p;
+      /* Sadly, we cannot use alias sets because the extra aliasing
+        produced by the AND interferes.  Given that two-byte quantities
+        are the only thing we would be able to differentiate anyway,
+        there does not seem to be any point in convoluting the early
+        out of the alias check.  */
+      /* MEM_ALIAS_SET (x) = alias_set; */
       break;
 
     default:
@@ -963,14 +995,19 @@ alpha_set_memflags (insn, ref)
      rtx insn;
      rtx ref;
 {
-  /* Note that it is always safe to get these flags, though they won't
-     be what we think if REF is not a MEM.  */
-  int in_struct_p = MEM_IN_STRUCT_P (ref);
-  int volatile_p = MEM_VOLATILE_P (ref);
-  int unchanging_p = RTX_UNCHANGING_P (ref);
-
-  if (GET_CODE (ref) != MEM
-      || (! in_struct_p && ! volatile_p && ! unchanging_p))
+  int in_struct_p, volatile_p, unchanging_p;
+
+  if (GET_CODE (ref) != MEM)
+    return;
+
+  in_struct_p = MEM_IN_STRUCT_P (ref);
+  volatile_p = MEM_VOLATILE_P (ref);
+  unchanging_p = RTX_UNCHANGING_P (ref);
+
+  /* This is only called from alpha.md, after having had something 
+     generated from one of the insn patterns.  So if everything is
+     zero, the pattern is already up-to-date.  */
+  if (! in_struct_p && ! volatile_p && ! unchanging_p)
     return;
 
   alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p);
@@ -1128,7 +1165,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
        for (; bits > 0; bits--)
          if ((temp = (alpha_emit_set_const
                       (subtarget, mode,
-                       (unsigned HOST_WIDE_INT) c >> bits, i))) != 0
+                       (unsigned HOST_WIDE_INT) (c >> bits), i))) != 0
              || ((temp = (alpha_emit_set_const
                          (subtarget, mode,
                           ((unsigned HOST_WIDE_INT) c) >> bits, i)))
@@ -1176,70 +1213,66 @@ alpha_emit_set_const_1 (target, mode, c, n)
   return 0;
 }
 
-#if HOST_BITS_PER_WIDE_INT == 64
 /* Having failed to find a 3 insn sequence in alpha_emit_set_const,
    fall back to a straight forward decomposition.  We do this to avoid
    exponential run times encountered when looking for longer sequences
    with alpha_emit_set_const.  */
 
 rtx
-alpha_emit_set_long_const (target, c)
+alpha_emit_set_long_const (target, c1, c2)
      rtx target;
-     HOST_WIDE_INT c;
+     HOST_WIDE_INT c1, c2;
 {
-  /* Use a pseudo if highly optimizing and still generating RTL.  */
-  rtx subtarget
-    = (flag_expensive_optimizations && rtx_equal_function_value_matters
-       ? 0 : target);
   HOST_WIDE_INT d1, d2, d3, d4;
-  rtx r1, r2;
 
   /* Decompose the entire word */
-  d1 = ((c & 0xffff) ^ 0x8000) - 0x8000;
-  c -= d1;
-  d2 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  c = (c - d2) >> 32;
-  d3 = ((c & 0xffff) ^ 0x8000) - 0x8000;
-  c -= d3;
-  d4 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
-
-  if (c - d4 != 0)
-    abort();
+#if HOST_BITS_PER_WIDE_INT >= 64
+  if (c2 != -(c1 < 0))
+    abort ();
+  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d1;
+  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  c1 = (c1 - d2) >> 32;
+  d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d3;
+  d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (c1 != d4)
+    abort ();
+#else
+  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d1;
+  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (c1 != d2)
+    abort ();
+  c2 += (d2 < 0);
+  d3 = ((c2 & 0xffff) ^ 0x8000) - 0x8000;
+  c2 -= d3;
+  d4 = ((c2 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (c2 != d4)
+    abort ();
+#endif
 
   /* Construct the high word */
-  if (d3 == 0)
-    r1 = copy_to_suggested_reg (GEN_INT (d4), subtarget, DImode);
-  else if (d4 == 0)
-    r1 = copy_to_suggested_reg (GEN_INT (d3), subtarget, DImode);
+  if (d4)
+    {
+      emit_move_insn (target, GEN_INT (d4));
+      if (d3)
+       emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3)));
+    }
   else
-    r1 = expand_binop (DImode, add_optab, GEN_INT (d3), GEN_INT (d4),
-                      subtarget, 0, OPTAB_WIDEN);
+    emit_move_insn (target, GEN_INT (d3));
 
   /* Shift it into place */
-  r2 = expand_binop (DImode, ashl_optab, r1, GEN_INT (32), 
-                    subtarget, 0, OPTAB_WIDEN);
-
-  if (subtarget == 0 && d1 == d3 && d2 == d4)
-    r1 = expand_binop (DImode, add_optab, r1, r2, subtarget, 0, OPTAB_WIDEN);
-  else
-    {
-      r1 = r2;
-
-      /* Add in the low word */
-      if (d2 != 0)
-       r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d2),
-                          subtarget, 0, OPTAB_WIDEN);
-      if (d1 != 0)
-       r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d1),
-                          subtarget, 0, OPTAB_WIDEN);
-    }
+  emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32)));
 
-  if (subtarget == 0)
-    r1 = copy_to_suggested_reg(r1, target, DImode);
+  /* Add in the low bits.  */
+  if (d2)
+    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2)));
+  if (d1)
+    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1)));
 
-  return r1;
+  return target;
 }
-#endif /* HOST_BITS_PER_WIDE_INT == 64 */
 
 /* Generate the comparison for a conditional branch.  */
 
@@ -1416,7 +1449,7 @@ alpha_emit_conditional_move (cmp, mode)
       abort ();
     }
 
-  /* ??? We mark the the branch mode to be CCmode to prevent the compare
+  /* ??? We mark the branch mode to be CCmode to prevent the compare
      and cmov from being combined, since the compare insn follows IEEE
      rules that the cmov does not.  */
   if (alpha_compare_fp_p && !flag_fast_math)
@@ -1790,7 +1823,8 @@ alpha_expand_block_move (operands)
 {
   rtx bytes_rtx        = operands[2];
   rtx align_rtx = operands[3];
-  HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
+  HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
+  HOST_WIDE_INT bytes = orig_bytes;
   HOST_WIDE_INT src_align = INTVAL (align_rtx);
   HOST_WIDE_INT dst_align = src_align;
   rtx orig_src = operands[1];
@@ -1863,7 +1897,7 @@ alpha_expand_block_move (operands)
       enum machine_mode mode;
       tmp = XEXP (XEXP (orig_src, 0), 0);
 
-      mode = mode_for_size (bytes, MODE_INT, 1);
+      mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 1);
       if (mode != BLKmode
          && GET_MODE_SIZE (GET_MODE (tmp)) <= bytes)
        {
@@ -1979,7 +2013,7 @@ alpha_expand_block_move (operands)
     }
  src_done:
 
-  if (nregs > sizeof(data_regs)/sizeof(*data_regs))
+  if (nregs > (int)(sizeof(data_regs)/sizeof(*data_regs)))
     abort();
 
   /*
@@ -1993,7 +2027,7 @@ alpha_expand_block_move (operands)
       enum machine_mode mode;
       tmp = XEXP (XEXP (orig_dst, 0), 0);
 
-      mode = mode_for_size (bytes, MODE_INT, 1);
+      mode = mode_for_size (orig_bytes * BITS_PER_UNIT, MODE_INT, 1);
       if (GET_MODE (tmp) == mode && nregs == 1)
        {
          emit_move_insn (tmp, data_regs[0]);
@@ -2003,9 +2037,12 @@ alpha_expand_block_move (operands)
 
       /* ??? If nregs > 1, consider reconstructing the word in regs.  */
       /* ??? Optimize mode < dst_mode with strict_low_part.  */
-      /* No appropriate mode; fall back on memory.  */
+
+      /* No appropriate mode; fall back on memory.  We can speed things
+        up by recognizing extra alignment information.  */
       orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
                                 copy_addr_to_reg (XEXP (orig_dst, 0)));
+      dst_align = GET_MODE_SIZE (GET_MODE (tmp));
     }
 
   /* Write out the data in whatever chunks reading the source allowed.  */
@@ -2431,6 +2468,7 @@ void
 alpha_init_expanders ()
 {
   alpha_return_addr_rtx = NULL_RTX;
+  alpha_eh_epilogue_sp_ofs = NULL_RTX;
 
   /* Arrange to save and restore machine status around nested functions.  */
   save_machine_status = alpha_save_machine_status;
@@ -2454,7 +2492,7 @@ alpha_return_addr (count, frame)
 
   /* No rtx yet.  Invent one, and initialize it from $26 in the prologue.  */
   alpha_return_addr_rtx = gen_reg_rtx (Pmode);
-  init = gen_rtx_SET (Pmode, alpha_return_addr_rtx,
+  init = gen_rtx_SET (VOIDmode, alpha_return_addr_rtx,
                      gen_rtx_REG (Pmode, REG_RA));
 
   /* Emit the insn to the prologue with the other argument copies.  */
@@ -2468,6 +2506,8 @@ alpha_return_addr (count, frame)
 static int
 alpha_ra_ever_killed ()
 {
+  rtx top;
+
 #ifdef ASM_OUTPUT_MI_THUNK
   if (current_function_is_thunk)
     return 0;
@@ -2475,8 +2515,11 @@ alpha_ra_ever_killed ()
   if (!alpha_return_addr_rtx)
     return regs_ever_live[REG_RA];
 
-  return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA),
-                           get_insns(), NULL_RTX);
+  push_topmost_sequence ();
+  top = get_insns ();
+  pop_topmost_sequence ();
+
+  return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA), top, NULL_RTX);
 }
 
 \f
@@ -2724,7 +2767,7 @@ print_operand (file, x, code)
               && CONST_DOUBLE_LOW (x) == -1)
        fprintf (file, "q");
 #else
-      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffffffffffff)
+      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == -1)
        fprintf (file, "q");
       else if (GET_CODE (x) == CONST_DOUBLE
               && CONST_DOUBLE_HIGH (x) == 0
@@ -2825,46 +2868,60 @@ print_operand (file, x, code)
 /* Emit RTL insns to initialize the variable parts of a trampoline at
    TRAMP. FNADDR is an RTX for the address of the function's pure
    code.  CXT is an RTX for the static chain value for the function.
+
+   The three offset parameters are for the individual template's
+   layout.  A JMPOFS < 0 indicates that the trampoline does not 
+   contain instructions at all.
+
    We assume here that a function will be called many more times than
    its address is taken (e.g., it might be passed to qsort), so we
    take the trouble to initialize the "hint" field in the JMP insn.
    Note that the hint field is PC (new) + 4 * bits 13:0.  */
 
 void
-alpha_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp;
-     rtx fnaddr;
-     rtx cxt;
+alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
+     rtx tramp, fnaddr, cxt;
+     int fnofs, cxtofs, jmpofs;
 {
   rtx temp, temp1, addr;
+  /* ??? Something is wrong with VMS codegen in that we get aborts when
+     using ptr_mode.  Hack around it for now.  */
+  enum machine_mode mode = TARGET_OPEN_VMS ? Pmode : ptr_mode;
 
   /* Store function address and CXT.  */
-  addr = memory_address (Pmode, plus_constant (tramp, 16));
-  emit_move_insn (gen_rtx (MEM, Pmode, addr), fnaddr);
-  addr = memory_address (Pmode, plus_constant (tramp, 24));
-  emit_move_insn (gen_rtx (MEM, Pmode, addr), cxt);
-
-  /* Compute hint value.  */
-  temp = force_operand (plus_constant (tramp, 12), NULL_RTX);
-  temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1, OPTAB_WIDEN);
-  temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
-                      build_int_2 (2, 0), NULL_RTX, 1);
-  temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
-
-  /* Merge in the hint.  */
-  addr = memory_address (SImode, plus_constant (tramp, 8));
-  temp1 = force_reg (SImode, gen_rtx (MEM, SImode, addr));
-  temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
-  temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1, OPTAB_WIDEN);
-  emit_move_insn (gen_rtx (MEM, SImode, addr), temp1);
+  addr = memory_address (mode, plus_constant (tramp, fnofs));
+  emit_move_insn (gen_rtx (MEM, mode, addr), fnaddr);
+  addr = memory_address (mode, plus_constant (tramp, cxtofs));
+  emit_move_insn (gen_rtx (MEM, mode, addr), cxt);
+
+  /* This has been disabled since the hint only has a 32k range, and in
+     no existing OS is the stack within 32k of the text segment. */
+  if (0 && jmpofs >= 0)
+    {
+      /* Compute hint value.  */
+      temp = force_operand (plus_constant (tramp, jmpofs+4), NULL_RTX);
+      temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1,
+                          OPTAB_WIDEN);
+      temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
+                          build_int_2 (2, 0), NULL_RTX, 1);
+      temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
+
+      /* Merge in the hint.  */
+      addr = memory_address (SImode, plus_constant (tramp, jmpofs));
+      temp1 = force_reg (SImode, gen_rtx (MEM, SImode, addr));
+      temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
+      temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
+                           OPTAB_WIDEN);
+      emit_move_insn (gen_rtx (MEM, SImode, addr), temp1);
+    }
 
 #ifdef TRANSFER_FROM_TRAMPOLINE
   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
                     0, VOIDmode, 1, addr, Pmode);
 #endif
 
-  emit_insn (gen_rtx (UNSPEC_VOLATILE, VOIDmode,
-                     gen_rtvec (1, const0_rtx), 0));
+  if (jmpofs >= 0)
+    emit_insn (gen_imb ());
 }
 \f
 /* Do what is necessary for `va_start'.  The argument is ignored;
@@ -2934,7 +2991,7 @@ alpha_builtin_saveregs (arglist)
       dest = change_address (block, ptr_mode, XEXP (block, 0));
       emit_move_insn (dest, addr);
 
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                           dest, ptr_mode,
                           GEN_INT (GET_MODE_SIZE (ptr_mode)),
@@ -2948,7 +3005,7 @@ alpha_builtin_saveregs (arglist)
                                            POINTER_SIZE/BITS_PER_UNIT));
       emit_move_insn (dest, argsize);
 
-      if (flag_check_memory_usage)
+      if (current_function_check_memory_usage)
        emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
                           dest, ptr_mode,
                           GEN_INT (GET_MODE_SIZE
@@ -3178,6 +3235,32 @@ alpha_write_verstamp (file)
 #endif
 }
 \f
+/* Helper function to set RTX_FRAME_RELATED_P on instructions, including
+   sequences.  */
+
+static rtx
+set_frame_related_p ()
+{
+  rtx seq = gen_sequence ();
+  end_sequence ();
+
+  if (GET_CODE (seq) == SEQUENCE)
+    {
+      int i = XVECLEN (seq, 0);
+      while (--i >= 0)
+       RTX_FRAME_RELATED_P (XVECEXP (seq, 0, i)) = 1;
+     return emit_insn (seq);
+    }
+  else
+    {
+      seq = emit_insn (seq);
+      RTX_FRAME_RELATED_P (seq) = 1;
+      return seq;
+    }
+}
+
+#define FRP(exp)  (start_sequence (), exp, set_frame_related_p ())
+
 /* Write function prologue.  */
 
 /* On vms we have two kinds of functions:
@@ -3207,7 +3290,7 @@ alpha_expand_prologue ()
   HOST_WIDE_INT frame_size;
   /* Offset from base reg to register save area.  */
   HOST_WIDE_INT reg_offset;
-  rtx sa_reg;
+  rtx sa_reg, mem;
   int i;
 
   sa_size = alpha_sa_size ();
@@ -3257,8 +3340,8 @@ alpha_expand_prologue ()
 
       if (frame_size != 0)
        {
-         emit_move_insn (stack_pointer_rtx,
-                         plus_constant (stack_pointer_rtx, -frame_size));
+         FRP (emit_move_insn (stack_pointer_rtx,
+                              plus_constant (stack_pointer_rtx, -frame_size)));
        }
     }
   else
@@ -3288,7 +3371,18 @@ alpha_expand_prologue ()
          emit_move_insn (last, const0_rtx);
        }
 
-      emit_move_insn (stack_pointer_rtx, plus_constant (ptr, -leftover));
+      ptr = emit_move_insn (stack_pointer_rtx, plus_constant (ptr, -leftover));
+
+      /* This alternative is special, because the DWARF code cannot possibly
+        intuit through the loop above.  So we invent this note it looks at
+        instead.  */
+      RTX_FRAME_RELATED_P (ptr) = 1;
+      REG_NOTES (ptr)
+       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                            gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                              gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                            GEN_INT (-frame_size))),
+                            REG_NOTES (ptr));
     }
 
   /* Cope with very large offsets to the register save area.  */
@@ -3304,21 +3398,23 @@ alpha_expand_prologue ()
        bias = reg_offset, reg_offset = 0;
 
       sa_reg = gen_rtx_REG (DImode, 24);
-      emit_move_insn (sa_reg, plus_constant (stack_pointer_rtx, bias));
+      FRP (emit_move_insn (sa_reg, plus_constant (stack_pointer_rtx, bias)));
     }
     
   /* Save regs in stack order.  Beginning with VMS PV.  */
   if (TARGET_OPEN_VMS && vms_is_stack_procedure)
     {
-      emit_move_insn (gen_rtx_MEM (DImode, stack_pointer_rtx),
-                     gen_rtx_REG (DImode, REG_PV));
+      mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
+      MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
     }
 
   /* Save register RA next.  */
   if (imask & (1L << REG_RA))
     {
-      emit_move_insn (gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)),
-                     gen_rtx_REG (DImode, REG_RA));
+      mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+      MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
       imask &= ~(1L << REG_RA);
       reg_offset += 8;
     }
@@ -3327,18 +3423,18 @@ alpha_expand_prologue ()
   for (i = 0; i < 32; i++)
     if (imask & (1L << i))
       {
-       emit_move_insn (gen_rtx_MEM (DImode,
-                                    plus_constant (sa_reg, reg_offset)),
-                       gen_rtx_REG (DImode, i));
+       mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+       MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+       FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
        reg_offset += 8;
       }
 
   for (i = 0; i < 32; i++)
     if (fmask & (1L << i))
       {
-       emit_move_insn (gen_rtx_MEM (DFmode,
-                                    plus_constant (sa_reg, reg_offset)),
-                       gen_rtx_REG (DFmode, i+32));
+       mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
+       MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+       FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
        reg_offset += 8;
       }
 
@@ -3347,25 +3443,25 @@ alpha_expand_prologue ()
       if (!vms_is_stack_procedure)
        {
          /* Register frame procedures fave the fp.  */
-         emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
-                         hard_frame_pointer_rtx);
+         FRP (emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
+                              hard_frame_pointer_rtx));
        }
 
       if (vms_base_regno != REG_PV)
-       emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
-                       gen_rtx_REG (DImode, REG_PV));
+       FRP (emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
+                            gen_rtx_REG (DImode, REG_PV)));
 
       if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
        {
-         emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+         FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
        }
 
       /* If we have to allocate space for outgoing args, do it now.  */
       if (current_function_outgoing_args_size != 0)
        {
-         emit_move_insn (stack_pointer_rtx, 
-           plus_constant (hard_frame_pointer_rtx,
-             - ALPHA_ROUND (current_function_outgoing_args_size)));
+         FRP (emit_move_insn (stack_pointer_rtx, 
+               plus_constant (hard_frame_pointer_rtx,
+                - ALPHA_ROUND (current_function_outgoing_args_size))));
        }
     }
   else
@@ -3374,13 +3470,13 @@ alpha_expand_prologue ()
       if (frame_pointer_needed)
        {
          if (TARGET_CAN_FAULT_IN_PROLOGUE)
-           emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+           FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
          else
            {
              /* This must always be the last instruction in the
                 prologue, thus we emit a special move + clobber.  */
-             emit_insn (gen_init_fp (hard_frame_pointer_rtx,
-                                     stack_pointer_rtx, sa_reg));
+             FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx,
+                                          stack_pointer_rtx, sa_reg)));
            }
        }
     }
@@ -3597,6 +3693,12 @@ output_end_prologue (file)
 
 /* Write function epilogue.  */
 
+/* ??? At some point we will want to support full unwind, and so will 
+   need to mark the epilogue as well.  At the moment, we just confuse
+   dwarf2out.  */
+#undef FRP
+#define FRP(exp) exp
+
 void
 alpha_expand_epilogue ()
 {
@@ -3611,7 +3713,7 @@ alpha_expand_epilogue ()
   HOST_WIDE_INT reg_offset;
   int fp_is_frame_pointer, fp_offset;
   rtx sa_reg, sa_reg_exp = NULL;
-  rtx sp_adj1, sp_adj2;
+  rtx sp_adj1, sp_adj2, mem;
   int i;
 
   sa_size = alpha_sa_size ();
@@ -3645,7 +3747,7 @@ alpha_expand_epilogue ()
           && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
          || (!TARGET_OPEN_VMS && frame_pointer_needed))
        {
-         emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
+         FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
        }
 
       /* Cope with very large offsets to the register save area.  */
@@ -3663,13 +3765,17 @@ alpha_expand_epilogue ()
          sa_reg = gen_rtx_REG (DImode, 22);
          sa_reg_exp = plus_constant (stack_pointer_rtx, bias);
 
-         emit_move_insn (sa_reg, sa_reg_exp);
+         FRP (emit_move_insn (sa_reg, sa_reg_exp));
        }
          
       /* Restore registers in order, excepting a true frame pointer. */
 
-      emit_move_insn (gen_rtx_REG (DImode, REG_RA),
-                     gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset)));
+      if (! alpha_eh_epilogue_sp_ofs)
+       {
+         mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
+         MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+          FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
+       }
       reg_offset += 8;
       imask &= ~(1L << REG_RA);
 
@@ -3680,10 +3786,9 @@ alpha_expand_epilogue ()
              fp_offset = reg_offset;
            else
              {
-               emit_move_insn (gen_rtx_REG (DImode, i),
-                               gen_rtx_MEM (DImode,
-                                            plus_constant(sa_reg,
-                                                          reg_offset)));
+               mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
+               MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+               FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem));
              }
            reg_offset += 8;
          }
@@ -3691,54 +3796,57 @@ alpha_expand_epilogue ()
       for (i = 0; i < 32; ++i)
        if (fmask & (1L << i))
          {
-           emit_move_insn (gen_rtx_REG (DFmode, i+32),
-                           gen_rtx_MEM (DFmode,
-                                        plus_constant(sa_reg, reg_offset)));
+           mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset));
+           MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+           FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem));
            reg_offset += 8;
          }
     }
 
-  if (frame_size)
+  if (frame_size || alpha_eh_epilogue_sp_ofs)
     {
+      sp_adj1 = stack_pointer_rtx;
+
+      if (alpha_eh_epilogue_sp_ofs)
+       {
+         sp_adj1 = gen_rtx_REG (DImode, 23);
+         emit_move_insn (sp_adj1,
+                         gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                       alpha_eh_epilogue_sp_ofs));
+       }
+
       /* If the stack size is large, begin computation into a temporary
         register so as not to interfere with a potential fp restore,
         which must be consecutive with an SP restore.  */
       if (frame_size < 32768)
-       {
-         sp_adj1 = stack_pointer_rtx;
-         sp_adj2 = GEN_INT (frame_size);
-       }
+       sp_adj2 = GEN_INT (frame_size);
       else if (frame_size < 0x40007fffL)
        {
          int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
 
-         sp_adj2 = plus_constant (stack_pointer_rtx, frame_size - low);
+         sp_adj2 = plus_constant (sp_adj1, frame_size - low);
          if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2))
            sp_adj1 = sa_reg;
          else
            {
              sp_adj1 = gen_rtx_REG (DImode, 23);
-             emit_move_insn (sp_adj1, sp_adj2);
+             FRP (emit_move_insn (sp_adj1, sp_adj2));
            }
          sp_adj2 = GEN_INT (low);
        }
       else
        {
-         sp_adj2 = gen_rtx_REG (DImode, 23);
-         sp_adj1 = alpha_emit_set_const (sp_adj2, DImode, frame_size, 3);
-         if (!sp_adj1)
+         rtx tmp = gen_rtx_REG (DImode, 23);
+         FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
+         if (!sp_adj2)
            {
              /* We can't drop new things to memory this late, afaik,
                 so build it up by pieces.  */
-#if HOST_BITS_PER_WIDE_INT == 64
-             sp_adj1 = alpha_emit_set_long_const (sp_adj2, frame_size);
-             if (!sp_adj1)
+             FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size,
+                                                       -(frame_size < 0)));
+             if (!sp_adj2)
                abort ();
-#else
-             abort ();
-#endif
            }
-         sp_adj2 = stack_pointer_rtx;
        }
 
       /* From now on, things must be in order.  So emit blockages.  */
@@ -3747,29 +3855,29 @@ alpha_expand_epilogue ()
       if (fp_is_frame_pointer)
        {
          emit_insn (gen_blockage ());
-         emit_move_insn (hard_frame_pointer_rtx,
-                         gen_rtx_MEM (DImode,
-                                      plus_constant(sa_reg, fp_offset)));
+         mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, fp_offset));
+         MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+         FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
        }
       else if (TARGET_OPEN_VMS)
        {
          emit_insn (gen_blockage ());
-         emit_move_insn (hard_frame_pointer_rtx,
-                         gen_rtx_REG (DImode, vms_save_fp_regno));
+         FRP (emit_move_insn (hard_frame_pointer_rtx,
+                              gen_rtx_REG (DImode, vms_save_fp_regno)));
        }
 
       /* Restore the stack pointer.  */
       emit_insn (gen_blockage ());
-      emit_move_insn (stack_pointer_rtx,
-                     gen_rtx_PLUS (DImode, sp_adj1, sp_adj2));
+      FRP (emit_move_insn (stack_pointer_rtx,
+                          gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
     }
   else 
     {
       if (TARGET_OPEN_VMS && !vms_is_stack_procedure)
         {
           emit_insn (gen_blockage ());
-          emit_move_insn (hard_frame_pointer_rtx,
-                         gen_rtx_REG (DImode, vms_save_fp_regno));
+          FRP (emit_move_insn (hard_frame_pointer_rtx,
+                              gen_rtx_REG (DImode, vms_save_fp_regno)));
         }
     }
 
@@ -4076,10 +4184,7 @@ alpha_handle_trap_shadows (insns)
 {
   struct shadow_summary shadow;
   int trap_pending, exception_nesting;
-  rtx i;
-
-  if (alpha_tp == ALPHA_TP_PROG && !flag_exceptions)
-    return;
+  rtx i, n;
 
   trap_pending = 0;
   exception_nesting = 0;
@@ -4182,7 +4287,9 @@ alpha_handle_trap_shadows (insns)
              else
                {
                close_shadow:
-                 emit_insn_before (gen_trapb (), i);
+                 n = emit_insn_before (gen_trapb (), i);
+                 PUT_MODE (n, TImode);
+                 PUT_MODE (i, TImode);
                  trap_pending = 0;
                  shadow.used.i = 0;
                  shadow.used.fp = 0;
@@ -4204,14 +4311,572 @@ alpha_handle_trap_shadows (insns)
        }
     }
 }
+\f
+#ifdef HAIFA
+/* Alpha can only issue instruction groups simultaneously if they are
+   suitibly aligned.  This is very processor-specific.  */
+
+enum alphaev4_pipe {
+  EV4_STOP = 0,
+  EV4_IB0 = 1,
+  EV4_IB1 = 2,
+  EV4_IBX = 4
+};
+
+enum alphaev5_pipe {
+  EV5_STOP = 0,
+  EV5_NONE = 1,
+  EV5_E01 = 2,
+  EV5_E0 = 4,
+  EV5_E1 = 8,
+  EV5_FAM = 16,
+  EV5_FA = 32,
+  EV5_FM = 64
+};
+
+static enum alphaev4_pipe alphaev4_insn_pipe PROTO((rtx));
+static enum alphaev5_pipe alphaev5_insn_pipe PROTO((rtx));
+static rtx alphaev4_next_group PROTO((rtx, int*, int*));
+static rtx alphaev5_next_group PROTO((rtx, int*, int*));
+static rtx alphaev4_next_nop PROTO((int*));
+static rtx alphaev5_next_nop PROTO((int*));
+
+static void alpha_align_insns
+  PROTO((rtx, int, rtx (*)(rtx, int*, int*), rtx (*)(int*), int));
+
+static enum alphaev4_pipe
+alphaev4_insn_pipe (insn)
+     rtx insn;
+{
+  if (recog_memoized (insn) < 0)
+    return EV4_STOP;
+  if (get_attr_length (insn) != 4)
+    return EV4_STOP;
+
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ILD:
+    case TYPE_FLD:
+      return EV4_IBX;
+
+    case TYPE_LDSYM:
+    case TYPE_IADD:
+    case TYPE_ILOG:
+    case TYPE_ICMOV:
+    case TYPE_ICMP:
+    case TYPE_IST:
+    case TYPE_FST:
+    case TYPE_SHIFT:
+    case TYPE_IMUL:
+    case TYPE_FBR:
+      return EV4_IB0;
+
+    case TYPE_MISC:
+    case TYPE_IBR:
+    case TYPE_JSR:
+    case TYPE_FCPYS:
+    case TYPE_FCMOV:
+    case TYPE_FADD:
+    case TYPE_FDIV:
+    case TYPE_FMUL:
+      return EV4_IB1;
+
+    default:
+      abort();
+    }
+}
+
+static enum alphaev5_pipe
+alphaev5_insn_pipe (insn)
+     rtx insn;
+{
+  if (recog_memoized (insn) < 0)
+    return EV5_STOP;
+  if (get_attr_length (insn) != 4)
+    return EV5_STOP;
+
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ILD:
+    case TYPE_FLD:
+    case TYPE_LDSYM:
+    case TYPE_IADD:
+    case TYPE_ILOG:
+    case TYPE_ICMOV:
+    case TYPE_ICMP:
+      return EV5_E01;
+
+    case TYPE_IST:
+    case TYPE_FST:
+    case TYPE_SHIFT:
+    case TYPE_IMUL:
+    case TYPE_MISC:
+    case TYPE_MVI:
+      return EV5_E0;
+
+    case TYPE_IBR:
+    case TYPE_JSR:
+      return EV5_E1;
+
+    case TYPE_FCPYS:
+      return EV5_FAM;
+
+    case TYPE_FBR:
+    case TYPE_FCMOV:
+    case TYPE_FADD:
+    case TYPE_FDIV:
+      return EV5_FA;
+
+    case TYPE_FMUL:
+      return EV5_FM;
+
+    default:
+      abort();
+    }
+}
+
+/* IN_USE is a mask of the slots currently filled within the insn group. 
+   The mask bits come from alphaev4_pipe above.  If EV4_IBX is set, then
+   the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. 
+
+   LEN is, of course, the length of the group in bytes.  */
+
+static rtx
+alphaev4_next_group (insn, pin_use, plen)
+     rtx insn;
+     int *pin_use, *plen;
+{
+  int len, in_use;
+
+  len = in_use = 0;
+
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+      || GET_CODE (PATTERN (insn)) == CLOBBER
+      || GET_CODE (PATTERN (insn)) == USE)
+    goto next_and_done;
+
+  while (1)
+    {
+      enum alphaev4_pipe pipe;
+
+      pipe = alphaev4_insn_pipe (insn);
+      switch (pipe)
+       {
+       case EV4_STOP:
+         /* Force complex instructions to start new groups.  */
+         if (in_use)
+           goto done;
+
+         /* If this is a completely unrecognized insn, its an asm.
+            We don't know how long it is, so record length as -1 to
+            signal a needed realignment.  */
+         if (recog_memoized (insn) < 0)
+           len = -1;
+         else
+           len = get_attr_length (insn);
+         goto next_and_done;
+
+       case EV4_IBX:
+         if (in_use & EV4_IB0)
+           {
+             if (in_use & EV4_IB1)
+               goto done;
+             in_use |= EV4_IB1;
+           }
+         else
+           in_use |= EV4_IB0 | EV4_IBX;
+         break;
+
+       case EV4_IB0:
+         if (in_use & EV4_IB0)
+           {
+             if (!(in_use & EV4_IBX) || (in_use & EV4_IB1))
+               goto done;
+             in_use |= EV4_IB1;
+           }
+         in_use |= EV4_IB0;
+         break;
+
+       case EV4_IB1:
+         if (in_use & EV4_IB1)
+           goto done;
+         in_use |= EV4_IB1;
+         break;
+
+       default:
+         abort();
+       }
+      len += 4;
+      
+      /* Haifa doesn't do well scheduling branches.  */
+      if (GET_CODE (insn) == JUMP_INSN)
+       goto next_and_done;
+
+    next:
+      insn = next_nonnote_insn (insn);
+
+      if (!insn || GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       goto done;
+
+      /* Let Haifa tell us where it thinks insn group boundaries are.  */
+      if (GET_MODE (insn) == TImode)
+       goto done;
+
+      if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE)
+       goto next;
+    }
+
+ next_and_done:
+  insn = next_nonnote_insn (insn);
+
+ done:
+  *plen = len;
+  *pin_use = in_use;
+  return insn;
+}
+
+/* IN_USE is a mask of the slots currently filled within the insn group. 
+   The mask bits come from alphaev5_pipe above.  If EV5_E01 is set, then
+   the insn in EV5_E0 can be swapped by the hardware into EV5_E1. 
+
+   LEN is, of course, the length of the group in bytes.  */
+
+static rtx
+alphaev5_next_group (insn, pin_use, plen)
+     rtx insn;
+     int *pin_use, *plen;
+{
+  int len, in_use;
+
+  len = in_use = 0;
+
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+      || GET_CODE (PATTERN (insn)) == CLOBBER
+      || GET_CODE (PATTERN (insn)) == USE)
+    goto next_and_done;
+
+  while (1)
+    {
+      enum alphaev5_pipe pipe;
+
+      pipe = alphaev5_insn_pipe (insn);
+      switch (pipe)
+       {
+       case EV5_STOP:
+         /* Force complex instructions to start new groups.  */
+         if (in_use)
+           goto done;
+
+         /* If this is a completely unrecognized insn, its an asm.
+            We don't know how long it is, so record length as -1 to
+            signal a needed realignment.  */
+         if (recog_memoized (insn) < 0)
+           len = -1;
+         else
+           len = get_attr_length (insn);
+         goto next_and_done;
+
+       /* ??? Most of the places below, we would like to abort, as 
+          it would indicate an error either in Haifa, or in the 
+          scheduling description.  Unfortunately, Haifa never 
+          schedules the last instruction of the BB, so we don't
+          have an accurate TI bit to go off.  */
+       case EV5_E01:
+         if (in_use & EV5_E0)
+           {
+             if (in_use & EV5_E1)
+               goto done;
+             in_use |= EV5_E1;
+           }
+         else
+           in_use |= EV5_E0 | EV5_E01;
+         break;
+
+       case EV5_E0:
+         if (in_use & EV5_E0)
+           {
+             if (!(in_use & EV5_E01) || (in_use & EV5_E1))
+               goto done;
+             in_use |= EV5_E1;
+           }
+         in_use |= EV5_E0;
+         break;
+
+       case EV5_E1:
+         if (in_use & EV5_E1)
+           goto done;
+         in_use |= EV5_E1;
+         break;
+
+       case EV5_FAM:
+         if (in_use & EV5_FA)
+           {
+             if (in_use & EV5_FM)
+               goto done;
+             in_use |= EV5_FM;
+           }
+         else
+           in_use |= EV5_FA | EV5_FAM;
+         break;
+
+       case EV5_FA:
+         if (in_use & EV5_FA)
+           goto done;
+         in_use |= EV5_FA;
+         break;
+
+       case EV5_FM:
+         if (in_use & EV5_FM)
+           goto done;
+         in_use |= EV5_FM;
+         break;
+
+       case EV5_NONE:
+         break;
+
+       default:
+         abort();
+       }
+      len += 4;
+      
+      /* Haifa doesn't do well scheduling branches.  */
+      /* ??? If this is predicted not-taken, slotting continues, except
+        that no more IBR, FBR, or JSR insns may be slotted.  */
+      if (GET_CODE (insn) == JUMP_INSN)
+       goto next_and_done;
+
+    next:
+      insn = next_nonnote_insn (insn);
+
+      if (!insn || GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       goto done;
+
+      /* Let Haifa tell us where it thinks insn group boundaries are.  */
+      if (GET_MODE (insn) == TImode)
+       goto done;
+
+      if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE)
+       goto next;
+    }
+
+ next_and_done:
+  insn = next_nonnote_insn (insn);
+
+ done:
+  *plen = len;
+  *pin_use = in_use;
+  return insn;
+}
+
+static rtx
+alphaev4_next_nop (pin_use)
+     int *pin_use;
+{
+  int in_use = *pin_use;
+  rtx nop;
 
+  if (!(in_use & EV4_IB0))
+    {
+      in_use |= EV4_IB0;
+      nop = gen_nop ();
+    }
+  else if ((in_use & (EV4_IBX|EV4_IB1)) == EV4_IBX)
+    {
+      in_use |= EV4_IB1;
+      nop = gen_nop ();
+    }
+  else if (TARGET_FP && !(in_use & EV4_IB1))
+    {
+      in_use |= EV4_IB1;
+      nop = gen_fnop ();
+    }
+  else
+    nop = gen_unop ();
+
+  *pin_use = in_use;
+  return nop;
+}
+
+static rtx
+alphaev5_next_nop (pin_use)
+     int *pin_use;
+{
+  int in_use = *pin_use;
+  rtx nop;
+
+  if (!(in_use & EV5_E1))
+    {
+      in_use |= EV5_E1;
+      nop = gen_nop ();
+    }
+  else if (TARGET_FP && !(in_use & EV5_FA))
+    {
+      in_use |= EV5_FA;
+      nop = gen_fnop ();
+    }
+  else if (TARGET_FP && !(in_use & EV5_FM))
+    {
+      in_use |= EV5_FM;
+      nop = gen_fnop ();
+    }
+  else
+    nop = gen_unop ();
+
+  *pin_use = in_use;
+  return nop;
+}
+
+/* The instruction group alignment main loop.  */
+
+static void
+alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use)
+     rtx insns;
+     int max_align;
+     rtx (*next_group) PROTO((rtx, int*, int*));
+     rtx (*next_nop) PROTO((int*));
+     int gp_in_use;
+{
+  /* ALIGN is the known alignment for the insn group.  */
+  int align;
+  /* OFS is the offset of the current insn in the insn group.  */
+  int ofs;
+  int prev_in_use, in_use, len;
+  rtx i, next;
+
+  /* Let shorten branches care for assigning alignments to code labels.  */
+  shorten_branches (insns);
+
+  align = (FUNCTION_BOUNDARY/BITS_PER_UNIT < max_align
+          ? FUNCTION_BOUNDARY/BITS_PER_UNIT : max_align);
+
+  /* Account for the initial GP load, which happens before the scheduled
+     prologue we emitted as RTL.  */
+  ofs = prev_in_use = 0;
+  if (alpha_does_function_need_gp())
+    {
+      ofs = 8 & (align - 1);
+      prev_in_use = gp_in_use;
+    }
+
+  i = insns;
+  if (GET_CODE (i) == NOTE)
+    i = next_nonnote_insn (i);
+
+  while (i)
+    {
+      next = (*next_group)(i, &in_use, &len);
+
+      /* When we see a label, resync alignment etc.  */
+      if (GET_CODE (i) == CODE_LABEL)
+       {
+         int new_align = 1 << label_to_alignment (i);
+         if (new_align >= align)
+           {
+             align = new_align < max_align ? new_align : max_align;
+             ofs = 0;
+           }
+         else if (ofs & (new_align-1))
+           ofs = (ofs | (new_align-1)) + 1;
+         if (len != 0)
+           abort();
+       }
+
+      /* Handle complex instructions special.  */
+      else if (in_use == 0)
+       {
+         /* Asms will have length < 0.  This is a signal that we have
+            lost alignment knowledge.  Assume, however, that the asm
+            will not mis-align instructions.  */
+         if (len < 0)
+           {
+             ofs = 0;
+             align = 4;
+             len = 0;
+           }
+       }
+
+      /* If the known alignment is smaller than the recognized insn group,
+        realign the output.  */
+      else if (align < len)
+       {
+         int new_log_align = len > 8 ? 4 : 3;
+         rtx where;
+
+         where = prev_nonnote_insn (i);
+         if (!where || GET_CODE (where) != CODE_LABEL)
+           where = i;
+
+         emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
+         align = 1 << new_log_align;
+         ofs = 0;
+       }
+
+      /* If the group won't fit in the same INT16 as the previous,
+        we need to add padding to keep the group together.  Rather
+        than simply leaving the insn filling to the assembler, we
+        can make use of the knowledge of what sorts of instructions
+        were issued in the previous group to make sure that all of
+        the added nops are really free.  */
+      else if (ofs + len > align)
+       {
+         int nop_count = (align - ofs) / 4;
+         rtx where;
+
+         /* Insert nops before labels and branches to truely merge the
+            execution of the nops with the previous instruction group.  */
+         where = prev_nonnote_insn (i);
+         if (where)
+           {
+             if (GET_CODE (where) == CODE_LABEL)
+               {
+                 rtx where2 = prev_nonnote_insn (where);
+                 if (where2 && GET_CODE (where2) == JUMP_INSN)
+                   where = where2;
+               }
+             else if (GET_CODE (where) != JUMP_INSN)
+               where = i;
+           }
+         else
+           where = i;
+
+         do 
+           emit_insn_before ((*next_nop)(&prev_in_use), where);
+         while (--nop_count);
+         ofs = 0;
+       }
+
+      ofs = (ofs + len) & (align - 1);
+      prev_in_use = in_use;
+      i = next;
+    }
+}
+#endif /* HAIFA */
+\f
 /* Machine dependant reorg pass.  */
 
 void
 alpha_reorg (insns)
      rtx insns;
 {
-  alpha_handle_trap_shadows (insns);
+  if (alpha_tp != ALPHA_TP_PROG || flag_exceptions)
+    alpha_handle_trap_shadows (insns);
+
+#ifdef HAIFA
+  /* Due to the number of extra trapb insns, don't bother fixing up
+     alignment when trap precision is instruction.  Moreover, we can
+     only do our job when sched2 is run and Haifa is our scheduler.  */
+  if (optimize && !optimize_size
+      && alpha_tp != ALPHA_TP_INSN
+      && flag_schedule_insns_after_reload)
+    {
+      if (alpha_cpu == PROCESSOR_EV4)
+       alpha_align_insns (insns, 8, alphaev4_next_group,
+                          alphaev4_next_nop, EV4_IB0);
+      else if (alpha_cpu == PROCESSOR_EV5)
+       alpha_align_insns (insns, 16, alphaev5_next_group,
+                          alphaev5_next_nop, EV5_E01 | EV5_E0);
+    }
+#endif
 }
 
 \f