OSDN Git Service

* alpha.c (reg_or_6bit_operand): Remove CONSTANT_P_RTX handling.
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 2b29714..152a1c0 100644 (file)
@@ -100,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));
@@ -260,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] = 
@@ -302,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.  */
@@ -341,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));
 }
 
@@ -355,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));
 }
 
@@ -367,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.  */
@@ -379,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);
 }
@@ -397,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);
 }
@@ -431,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);
 }
@@ -447,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);
 }
@@ -487,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
              ));
 }
@@ -548,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));
 }
 
@@ -566,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:
@@ -615,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:
@@ -826,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
@@ -870,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);
 }
 
@@ -949,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:
@@ -967,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);
@@ -1132,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)))
@@ -1180,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);
+  emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32)));
 
-  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);
-    }
+  /* 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)));
 
-  if (subtarget == 0)
-    r1 = copy_to_suggested_reg(r1, target, DImode);
-
-  return r1;
+  return target;
 }
-#endif /* HOST_BITS_PER_WIDE_INT == 64 */
 
 /* Generate the comparison for a conditional branch.  */
 
@@ -1794,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];
@@ -1867,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)
        {
@@ -1983,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();
 
   /*
@@ -1997,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]);
@@ -2007,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.  */
@@ -2459,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.  */
@@ -2734,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
@@ -2958,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)),
@@ -2972,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
@@ -3257,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 ();
@@ -3371,16 +3404,17 @@ alpha_expand_prologue ()
   /* Save regs in stack order.  Beginning with VMS PV.  */
   if (TARGET_OPEN_VMS && vms_is_stack_procedure)
     {
-      FRP (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))
     {
-      FRP (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;
     }
@@ -3389,18 +3423,18 @@ alpha_expand_prologue ()
   for (i = 0; i < 32; i++)
     if (imask & (1L << i))
       {
-       FRP (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))
       {
-       FRP (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;
       }
 
@@ -3679,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 ();
@@ -3738,10 +3772,9 @@ alpha_expand_epilogue ()
 
       if (! alpha_eh_epilogue_sp_ofs)
        {
-          FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
-                              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, REG_RA), mem));
        }
       reg_offset += 8;
       imask &= ~(1L << REG_RA);
@@ -3753,10 +3786,9 @@ alpha_expand_epilogue ()
              fp_offset = reg_offset;
            else
              {
-               FRP (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;
          }
@@ -3764,10 +3796,9 @@ alpha_expand_epilogue ()
       for (i = 0; i < 32; ++i)
        if (fmask & (1L << i))
          {
-           FRP (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;
          }
     }
@@ -3811,13 +3842,10 @@ alpha_expand_epilogue ()
            {
              /* We can't drop new things to memory this late, afaik,
                 so build it up by pieces.  */
-#if HOST_BITS_PER_WIDE_INT == 64
-             FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size));
+             FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size,
+                                                       -(frame_size < 0)));
              if (!sp_adj2)
                abort ();
-#else
-             abort ();
-#endif
            }
        }
 
@@ -3827,9 +3855,9 @@ alpha_expand_epilogue ()
       if (fp_is_frame_pointer)
        {
          emit_insn (gen_blockage ());
-         FRP (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)
        {
@@ -4288,6 +4316,13 @@ alpha_handle_trap_shadows (insns)
 /* 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,
@@ -4299,6 +4334,58 @@ enum alphaev5_pipe {
   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;
@@ -4348,10 +4435,109 @@ alphaev5_insn_pipe (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 swapp
-   by the hardware into EV5_E1. 
+/* 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.  */
 
@@ -4409,7 +4595,7 @@ alphaev5_next_group (insn, pin_use, plen)
        case EV5_E0:
          if (in_use & EV5_E0)
            {
-             if (!(in_use & EV5_E01) || in_use & EV5_E1)
+             if (!(in_use & EV5_E01) || (in_use & EV5_E1))
                goto done;
              in_use |= EV5_E1;
            }
@@ -4482,9 +4668,73 @@ alphaev5_next_group (insn, pin_use, plen)
   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
-alphaev5_align_insns (insns)
+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;
@@ -4496,14 +4746,17 @@ alphaev5_align_insns (insns)
   /* 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;
-      prev_in_use = EV5_E01 | EV5_E0;
+      ofs = 8 & (align - 1);
+      prev_in_use = gp_in_use;
     }
-  align = (FUNCTION_BOUNDARY/BITS_PER_UNIT < 16
-          ? FUNCTION_BOUNDARY/BITS_PER_UNIT : 16);
 
   i = insns;
   if (GET_CODE (i) == NOTE)
@@ -4511,7 +4764,7 @@ alphaev5_align_insns (insns)
 
   while (i)
     {
-      next = alphaev5_next_group (i, &in_use, &len);
+      next = (*next_group)(i, &in_use, &len);
 
       /* When we see a label, resync alignment etc.  */
       if (GET_CODE (i) == CODE_LABEL)
@@ -4519,7 +4772,7 @@ alphaev5_align_insns (insns)
          int new_align = 1 << label_to_alignment (i);
          if (new_align >= align)
            {
-             align = new_align < 16 ? new_align : 16;
+             align = new_align < max_align ? new_align : max_align;
              ofs = 0;
            }
          else if (ofs & (new_align-1))
@@ -4569,30 +4822,25 @@ alphaev5_align_insns (insns)
          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 || GET_CODE (where) != CODE_LABEL)
-           where = i;
-
-         do 
+         if (where)
            {
-             if (!(prev_in_use & EV5_E1))
+             if (GET_CODE (where) == CODE_LABEL)
                {
-                 prev_in_use |= EV5_E1;
-                 emit_insn_before (gen_nop(), where);
+                 rtx where2 = prev_nonnote_insn (where);
+                 if (where2 && GET_CODE (where2) == JUMP_INSN)
+                   where = where2;
                }
-             else if (TARGET_FP && !(prev_in_use & EV5_FA))
-               {
-                 prev_in_use |= EV5_FA;
-                 emit_insn_before (gen_fnop(), where);
-               }
-             else if (TARGET_FP && !(prev_in_use & EV5_FM))
-               {
-                 prev_in_use |= EV5_FM;
-                 emit_insn_before (gen_fnop(), where);
-               }
-             else
-               emit_insn_before (gen_unop(), where);
+             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;
        }
@@ -4621,8 +4869,12 @@ alpha_reorg (insns)
       && alpha_tp != ALPHA_TP_INSN
       && flag_schedule_insns_after_reload)
     {
-      if (alpha_cpu == PROCESSOR_EV5)
-       alphaev5_align_insns (insns);
+      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
 }