]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/vax/vax.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / config / vax / vax.c
index eae2d190b85d3a9d3fd17ad5d3727659a6774857..90da3b9c2b8b709d2da6a4870237622a88f640c5 100644 (file)
@@ -1,7 +1,5 @@
 /* Subroutines for insn-output.c for VAX.
-   Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002,
-   2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,10 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "df.h"
 #include "tree.h"
+#include "calls.h"
+#include "varasm.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "function.h"
@@ -38,28 +38,39 @@ along with GCC; see the file COPYING3.  If not see
 #include "optabs.h"
 #include "flags.h"
 #include "debug.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
+#include "reload.h"
+#include "tm-preds.h"
+#include "tm-constrs.h"
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "wide-int.h"
 
-static void vax_output_function_prologue (FILE *, HOST_WIDE_INT);
+static void vax_option_override (void);
+static bool vax_legitimate_address_p (enum machine_mode, rtx, bool);
 static void vax_file_start (void);
 static void vax_init_libfuncs (void);
 static void vax_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                 HOST_WIDE_INT, tree);
 static int vax_address_cost_1 (rtx);
-static int vax_address_cost (rtx, bool);
-static bool vax_rtx_costs (rtx, int, int, int *, bool);
+static int vax_address_cost (rtx, enum machine_mode, addr_space_t, bool);
+static bool vax_rtx_costs (rtx, int, int, int, int *, bool);
+static rtx vax_function_arg (cumulative_args_t, enum machine_mode,
+                            const_tree, bool);
+static void vax_function_arg_advance (cumulative_args_t, enum machine_mode,
+                                     const_tree, bool);
 static rtx vax_struct_value_rtx (tree, int);
+static rtx vax_builtin_setjmp_frame_value (void);
+static void vax_asm_trampoline_template (FILE *);
+static void vax_trampoline_init (rtx, tree, rtx);
+static int vax_return_pops_args (tree, tree, int);
+static bool vax_mode_dependent_address_p (const_rtx, addr_space_t);
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
 
-#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE vax_output_function_prologue
-
 #undef TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START vax_file_start
 #undef TARGET_ASM_FILE_START_APP_OFF
@@ -73,9 +84,6 @@ static rtx vax_struct_value_rtx (tree, int);
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
 
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
-
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS vax_rtx_costs
 #undef TARGET_ADDRESS_COST
@@ -84,19 +92,60 @@ static rtx vax_struct_value_rtx (tree, int);
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG vax_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE vax_function_arg_advance
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX vax_struct_value_rtx
 
+#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
+#define TARGET_BUILTIN_SETJMP_FRAME_VALUE vax_builtin_setjmp_frame_value
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P vax_legitimate_address_p
+#undef TARGET_MODE_DEPENDENT_ADDRESS_P
+#define TARGET_MODE_DEPENDENT_ADDRESS_P vax_mode_dependent_address_p
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE vax_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT vax_trampoline_init
+#undef TARGET_RETURN_POPS_ARGS
+#define TARGET_RETURN_POPS_ARGS vax_return_pops_args
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE vax_option_override
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Set global variables as needed for the options enabled.  */
 
-void
-override_options (void)
+static void
+vax_option_override (void)
 {
   /* We're VAX floating point, not IEEE floating point.  */
   if (TARGET_G_FLOAT)
     REAL_MODE_FORMAT (DFmode) = &vax_g_format;
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+}
+
+static void
+vax_add_reg_cfa_offset (rtx insn, int offset, rtx src)
+{
+  rtx x;
+
+  x = plus_constant (Pmode, frame_pointer_rtx, offset);
+  x = gen_rtx_MEM (SImode, x);
+  x = gen_rtx_SET (VOIDmode, x, src);
+  add_reg_note (insn, REG_CFA_OFFSET, x);
 }
 
 /* Generate the assembly code for function entry.  FILE is a stdio
@@ -108,38 +157,67 @@ override_options (void)
    used in the function.  This function is responsible for knowing
    which registers should not be saved even if used.  */
 
-static void
-vax_output_function_prologue (FILE * file, HOST_WIDE_INT size)
+void
+vax_expand_prologue (void)
 {
-  int regno;
+  int regno, offset;
   int mask = 0;
+  HOST_WIDE_INT size;
+  rtx insn;
 
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
       mask |= 1 << regno;
 
-  fprintf (file, "\t.word 0x%x\n", mask);
+  insn = emit_insn (gen_procedure_entry_mask (GEN_INT (mask)));
+  RTX_FRAME_RELATED_P (insn) = 1;
 
-  if (dwarf2out_do_frame ())
-    {
-      const char *label = dwarf2out_cfi_label ();
-      int offset = 0;
+  /* The layout of the CALLG/S stack frame is follows:
 
-      for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno)
-       if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
-         dwarf2out_reg_save (label, regno, offset -= 4);
+               <- CFA, AP
+       r11
+       r10
+       ...     Registers saved as specified by MASK
+       r3
+       r2
+       return-addr
+       old fp
+       old ap
+       old psw
+       zero
+               <- FP, SP
 
-      dwarf2out_reg_save (label, PC_REGNUM, offset -= 4);
-      dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4);
-      dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4);
-      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4));
-    }
+     The rest of the prologue will adjust the SP for the local frame.  */
 
+  vax_add_reg_cfa_offset (insn, 4, arg_pointer_rtx);
+  vax_add_reg_cfa_offset (insn, 8, frame_pointer_rtx);
+  vax_add_reg_cfa_offset (insn, 12, pc_rtx);
+
+  offset = 16;
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (mask & (1 << regno))
+      {
+       vax_add_reg_cfa_offset (insn, offset, gen_rtx_REG (SImode, regno));
+       offset += 4;
+      }
+
+  /* Because add_reg_note pushes the notes, adding this last means that
+     it will be processed first.  This is required to allow the other
+     notes be interpreted properly.  */
+  add_reg_note (insn, REG_CFA_DEF_CFA,
+               plus_constant (Pmode, frame_pointer_rtx, offset));
+
+  /* Allocate the local stack frame.  */
+  size = get_frame_size ();
   size -= STARTING_FRAME_OFFSET;
-  if (size >= 64)
-    asm_fprintf (file, "\tmovab %wd(%Rsp),%Rsp\n", -size);
-  else if (size)
-    asm_fprintf (file, "\tsubl2 $%wd,%Rsp\n", size);
+  emit_insn (gen_addsi3 (stack_pointer_rtx,
+                        stack_pointer_rtx, GEN_INT (-size)));
+
+  /* Do not allow instructions referencing local stack memory to be
+     scheduled before the frame is allocated.  This is more pedantic
+     than anything else, given that VAX does not currently have a
+     scheduling description.  */
+  emit_insn (gen_blockage ());
 }
 
 /* When debugging with stabs, we want to output an extra dummy label
@@ -161,33 +239,43 @@ vax_file_start (void)
 static void
 vax_init_libfuncs (void)
 {
-  set_optab_libfunc (udiv_optab, SImode, TARGET_ELF ? "*__udiv" : "*udiv");
-  set_optab_libfunc (umod_optab, SImode, TARGET_ELF ? "*__urem" : "*urem");
+  if (TARGET_BSD_DIVMOD)
+    {
+      set_optab_libfunc (udiv_optab, SImode, TARGET_ELF ? "*__udiv" : "*udiv");
+      set_optab_libfunc (umod_optab, SImode, TARGET_ELF ? "*__urem" : "*urem");
+    }
 }
 
 /* This is like nonimmediate_operand with a restriction on the type of MEM.  */
 
-void
-split_quadword_operands (rtx * operands, rtx * low, int n ATTRIBUTE_UNUSED)
+static void
+split_quadword_operands (rtx insn, enum rtx_code code, rtx * operands,
+                        rtx * low, int n)
 {
   int i;
-  /* Split operands.  */
 
-  low[0] = low[1] = low[2] = 0;
-  for (i = 0; i < 3; i++)
+  for (i = 0; i < n; i++)
+    low[i] = 0;
+
+  for (i = 0; i < n; i++)
     {
-      if (low[i])
-       /* it's already been figured out */;
-      else if (MEM_P (operands[i])
-              && (GET_CODE (XEXP (operands[i], 0)) == POST_INC))
+      if (MEM_P (operands[i])
+         && (GET_CODE (XEXP (operands[i], 0)) == PRE_DEC
+             || GET_CODE (XEXP (operands[i], 0)) == POST_INC))
        {
          rtx addr = XEXP (operands[i], 0);
          operands[i] = low[i] = gen_rtx_MEM (SImode, addr);
-         if (which_alternative == 0 && i == 0)
-           {
-             addr = XEXP (operands[i], 0);
-             operands[i+1] = low[i+1] = gen_rtx_MEM (SImode, addr);
-           }
+       }
+      else if (optimize_size && MEM_P (operands[i])
+              && REG_P (XEXP (operands[i], 0))
+              && (code != MINUS || operands[1] != const0_rtx)
+              && find_regno_note (insn, REG_DEAD,
+                                  REGNO (XEXP (operands[i], 0))))
+       {
+         low[i] = gen_rtx_MEM (SImode,
+                               gen_rtx_POST_INC (Pmode,
+                                                 XEXP (operands[i], 0)));
+         operands[i] = gen_rtx_MEM (SImode, XEXP (operands[i], 0));
        }
       else
        {
@@ -200,6 +288,7 @@ split_quadword_operands (rtx * operands, rtx * low, int n ATTRIBUTE_UNUSED)
 void
 print_operand_address (FILE * file, rtx addr)
 {
+  rtx orig = addr;
   rtx reg1, breg, ireg;
   rtx offset;
 
@@ -288,11 +377,13 @@ print_operand_address (FILE * file, rtx addr)
              if (offset)
                {
                  if (CONST_INT_P (offset))
-                   offset = plus_constant (XEXP (addr, 0), INTVAL (offset));
+                   offset = plus_constant (Pmode, XEXP (addr, 0),
+                                           INTVAL (offset));
                  else
                    {
                      gcc_assert (CONST_INT_P (XEXP (addr, 0)));
-                     offset = plus_constant (offset, INTVAL (XEXP (addr, 0)));
+                     offset = plus_constant (Pmode, offset,
+                                             INTVAL (XEXP (addr, 0)));
                    }
                }
              offset = XEXP (addr, 0);
@@ -317,11 +408,13 @@ print_operand_address (FILE * file, rtx addr)
              if (offset)
                {
                  if (CONST_INT_P (offset))
-                   offset = plus_constant (XEXP (addr, 1), INTVAL (offset));
+                   offset = plus_constant (Pmode, XEXP (addr, 1),
+                                           INTVAL (offset));
                  else
                    {
                      gcc_assert (CONST_INT_P (XEXP (addr, 1)));
-                     offset = plus_constant (offset, INTVAL (XEXP (addr, 1)));
+                     offset = plus_constant (Pmode, offset,
+                                             INTVAL (XEXP (addr, 1)));
                    }
                }
              offset = XEXP (addr, 1);
@@ -344,7 +437,11 @@ print_operand_address (FILE * file, rtx addr)
       /* If REG1 is nonzero, figure out if it is a base or index register.  */
       if (reg1)
        {
-         if (breg != 0 || (offset && MEM_P (offset)))
+         if (breg
+             || (flag_pic && GET_CODE (addr) == SYMBOL_REF)
+             || (offset
+                 && (MEM_P (offset)
+                     || (flag_pic && symbolic_operand (offset, SImode)))))
            {
              gcc_assert (!ireg);
              ireg = reg1;
@@ -354,7 +451,36 @@ print_operand_address (FILE * file, rtx addr)
        }
 
       if (offset != 0)
-       output_address (offset);
+       {
+         if (flag_pic && symbolic_operand (offset, SImode))
+           {
+             if (breg && ireg)
+               {
+                 debug_rtx (orig);
+                 output_operand_lossage ("symbol used with both base and indexed registers");
+               }
+
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESS
+             if (flag_pic > 1 && GET_CODE (offset) == CONST
+                 && GET_CODE (XEXP (XEXP (offset, 0), 0)) == SYMBOL_REF
+                 && !SYMBOL_REF_LOCAL_P (XEXP (XEXP (offset, 0), 0)))
+               {
+                 debug_rtx (orig);
+                 output_operand_lossage ("symbol with offset used in PIC mode");
+               }
+#endif
+
+             /* symbol(reg) isn't PIC, but symbol[reg] is.  */
+             if (breg)
+               {
+                 ireg = breg;
+                 breg = 0;
+               }
+
+           }
+
+         output_address (offset);
+       }
 
       if (breg != 0)
        fprintf (file, "(%s)", reg_names[REGNO (breg)]);
@@ -372,7 +498,100 @@ print_operand_address (FILE * file, rtx addr)
       output_addr_const (file, addr);
     }
 }
+
+void
+print_operand (FILE *file, rtx x, int code)
+{
+  if (code == '#')
+    fputc (ASM_DOUBLE_CHAR, file);
+  else if (code == '|')
+    fputs (REGISTER_PREFIX, file);
+  else if (code == 'c')
+    fputs (cond_name (x), file);
+  else if (code == 'C')
+    fputs (rev_cond_name (x), file);
+  else if (code == 'D' && CONST_INT_P (x) && INTVAL (x) < 0)
+    fprintf (file, "$" NEG_HWI_PRINT_HEX16, INTVAL (x));
+  else if (code == 'P' && CONST_INT_P (x))
+    fprintf (file, "$" HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
+  else if (code == 'N' && CONST_INT_P (x))
+    fprintf (file, "$" HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x));
+  /* rotl instruction cannot deal with negative arguments.  */
+  else if (code == 'R' && CONST_INT_P (x))
+    fprintf (file, "$" HOST_WIDE_INT_PRINT_DEC, 32 - INTVAL (x));
+  else if (code == 'H' && CONST_INT_P (x))
+    fprintf (file, "$%d", (int) (0xffff & ~ INTVAL (x)));
+  else if (code == 'h' && CONST_INT_P (x))
+    fprintf (file, "$%d", (short) - INTVAL (x));
+  else if (code == 'B' && CONST_INT_P (x))
+    fprintf (file, "$%d", (int) (0xff & ~ INTVAL (x)));
+  else if (code == 'b' && CONST_INT_P (x))
+    fprintf (file, "$%d", (int) (0xff & - INTVAL (x)));
+  else if (code == 'M' && CONST_INT_P (x))
+    fprintf (file, "$%d", ~((1 << INTVAL (x)) - 1));
+  else if (code == 'x' && CONST_INT_P (x))
+    fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
+  else if (REG_P (x))
+    fprintf (file, "%s", reg_names[REGNO (x)]);
+  else if (MEM_P (x))
+    output_address (XEXP (x, 0));
+  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
+    {
+      char dstr[30];
+      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x),
+                      sizeof (dstr), 0, 1);
+      fprintf (file, "$0f%s", dstr);
+    }
+  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
+    {
+      char dstr[30];
+      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x),
+                      sizeof (dstr), 0, 1);
+      fprintf (file, "$0%c%s", ASM_DOUBLE_CHAR, dstr);
+    }
+  else
+    {
+      if (flag_pic > 1 && symbolic_operand (x, SImode))
+       {
+         debug_rtx (x);
+         output_operand_lossage ("symbol used as immediate operand");
+       }
+      putc ('$', file);
+      output_addr_const (file, x);
+    }
+}
 \f
+const char *
+cond_name (rtx op)
+{
+  switch (GET_CODE (op))
+    {
+    case NE:
+      return "neq";
+    case EQ:
+      return "eql";
+    case GE:
+      return "geq";
+    case GT:
+      return "gtr";
+    case LE:
+      return "leq";
+    case LT:
+      return "lss";
+    case GEU:
+      return "gequ";
+    case GTU:
+      return "gtru";
+    case LEU:
+      return "lequ";
+    case LTU:
+      return "lssu";
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 const char *
 rev_cond_name (rtx op)
 {
@@ -404,22 +623,22 @@ rev_cond_name (rtx op)
     }
 }
 
-int
-vax_float_literal(rtx c)
+static bool
+vax_float_literal (rtx c)
 {
   enum machine_mode mode;
   REAL_VALUE_TYPE r, s;
   int i;
 
   if (GET_CODE (c) != CONST_DOUBLE)
-    return 0;
+    return false;
 
   mode = GET_MODE (c);
 
   if (c == const_tiny_rtx[(int) mode][0]
       || c == const_tiny_rtx[(int) mode][1]
       || c == const_tiny_rtx[(int) mode][2])
-    return 1;
+    return true;
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, c);
 
@@ -427,16 +646,16 @@ vax_float_literal(rtx c)
     {
       int x = 1 << i;
       bool ok;
-      REAL_VALUE_FROM_INT (s, x, 0, mode);
+      real_from_integer (&s, mode, x, SIGNED);
 
       if (REAL_VALUES_EQUAL (r, s))
-       return 1;
+       return true;
       ok = exact_real_inverse (mode, &s);
       gcc_assert (ok);
       if (REAL_VALUES_EQUAL (r, s))
-       return 1;
+       return true;
     }
-  return 0;
+  return false;
 }
 
 
@@ -520,7 +739,9 @@ vax_address_cost_1 (rtx addr)
 }
 
 static int
-vax_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
+vax_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
+                 addr_space_t as ATTRIBUTE_UNUSED,
+                 bool speed ATTRIBUTE_UNUSED)
 {
   return (1 + (REG_P (x) ? 0 : vax_address_cost_1 (x)));
 }
@@ -534,8 +755,8 @@ vax_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
    costs on a per cpu basis.  */
 
 static bool
-vax_rtx_costs (rtx x, int code, int outer_code, int *total,
-              bool speed ATTRIBUTE_UNUSED)
+vax_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+              int *total, bool speed ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = GET_MODE (x);
   int i = 0;                              /* may be modified in switch */
@@ -550,10 +771,13 @@ vax_rtx_costs (rtx x, int code, int outer_code, int *total,
         patterns will not match).  */
     case CONST_INT:
       if (INTVAL (x) == 0)
-       return true;
+       {
+         *total = 0;
+         return true;
+       }
       if (outer_code == AND)
        {
-          *total = ((unsigned HOST_WIDE_INT) ~INTVAL (x) <= 077) ? 1 : 2;
+         *total = ((unsigned HOST_WIDE_INT) ~INTVAL (x) <= 077) ? 1 : 2;
          return true;
        }
       if ((unsigned HOST_WIDE_INT) INTVAL (x) <= 077
@@ -577,7 +801,7 @@ vax_rtx_costs (rtx x, int code, int outer_code, int *total,
       if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
        *total = vax_float_literal (x) ? 5 : 8;
       else
-        *total = ((CONST_DOUBLE_HIGH (x) == 0
+       *total = ((CONST_DOUBLE_HIGH (x) == 0
                   && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x) < 64)
                  || (outer_code == PLUS
                      && CONST_DOUBLE_HIGH (x) == -1
@@ -783,7 +1007,7 @@ vax_rtx_costs (rtx x, int code, int outer_code, int *total,
          else
            {
              if (CONST_DOUBLE_HIGH (op) != 0
-                 || (unsigned)CONST_DOUBLE_LOW (op) > 63)
+                 || (unsigned HOST_WIDE_INT)CONST_DOUBLE_LOW (op) > 63)
                *total += 2;
            }
          break;
@@ -812,10 +1036,10 @@ vax_rtx_costs (rtx x, int code, int outer_code, int *total,
 
 static void
 vax_output_mi_thunk (FILE * file,
-                     tree thunk ATTRIBUTE_UNUSED,
-                     HOST_WIDE_INT delta,
-                     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
-                     tree function)
+                    tree thunk ATTRIBUTE_UNUSED,
+                    HOST_WIDE_INT delta,
+                    HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                    tree function)
 {
   fprintf (file, "\t.word 0x0ffc\n\taddl2 $" HOST_WIDE_INT_PRINT_DEC, delta);
   asm_fprintf (file, ",4(%Rap)\n");
@@ -831,6 +1055,12 @@ vax_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
   return gen_rtx_REG (Pmode, VAX_STRUCT_VALUE_REGNUM);
 }
 
+static rtx
+vax_builtin_setjmp_frame_value (void)
+{
+  return hard_frame_pointer_rtx;
+}
+
 /* Worker function for NOTICE_UPDATE_CC.  */
 
 void
@@ -906,28 +1136,159 @@ const char *
 vax_output_int_move (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
                     enum machine_mode mode)
 {
+  rtx hi[3], lo[3];
+  const char *pattern_hi, *pattern_lo;
+
   switch (mode)
     {
+    case DImode:
+      if (operands[1] == const0_rtx)
+       return "clrq %0";
+      if (TARGET_QMATH && optimize_size
+         && (CONST_INT_P (operands[1])
+             || GET_CODE (operands[1]) == CONST_DOUBLE))
+       {
+         unsigned HOST_WIDE_INT hval, lval;
+         int n;
+
+         if (GET_CODE (operands[1]) == CONST_DOUBLE)
+           {
+             gcc_assert (HOST_BITS_PER_WIDE_INT != 64);
+
+             /* Make sure only the low 32 bits are valid.  */
+             lval = CONST_DOUBLE_LOW (operands[1]) & 0xffffffff;
+             hval = CONST_DOUBLE_HIGH (operands[1]) & 0xffffffff;
+           }
+         else
+           {
+             lval = INTVAL (operands[1]);
+             hval = 0;
+           }
+
+         /* Here we see if we are trying to see if the 64bit value is really
+            a 6bit shifted some arbitrary amount.  If so, we can use ashq to
+            shift it to the correct value saving 7 bytes (1 addr-mode-byte +
+            8 bytes - 1 shift byte - 1 short literal byte.  */
+         if (lval != 0
+             && (n = exact_log2 (lval & (- lval))) != -1
+             && (lval >> n) < 64)
+           {
+             lval >>= n;
+
+             /* On 32bit platforms, if the 6bits didn't overflow into the
+                upper 32bit value that value better be 0.  If we have
+                overflowed, make sure it wasn't too much.  */
+             if (HOST_BITS_PER_WIDE_INT == 32 && hval != 0)
+               {
+                 if (n <= 26 || hval >= ((unsigned)1 << (n - 26)))
+                   n = 0;      /* failure */
+                 else
+                   lval |= hval << (32 - n);
+               }
+             /*  If n is 0, then ashq is not the best way to emit this.  */
+             if (n > 0)
+               {
+                 operands[1] = GEN_INT (lval);
+                 operands[2] = GEN_INT (n);
+                 return "ashq %2,%D1,%0";
+               }
+#if HOST_BITS_PER_WIDE_INT == 32
+           }
+         /* On 32bit platforms, if the low 32bit value is 0, checkout the
+            upper 32bit value.  */
+         else if (hval != 0
+                  && (n = exact_log2 (hval & (- hval)) - 1) != -1
+                  && (hval >> n) < 64)
+           {
+             operands[1] = GEN_INT (hval >> n);
+             operands[2] = GEN_INT (n + 32);
+             return "ashq %2,%D1,%0";
+#endif
+           }
+       }
+
+      if (TARGET_QMATH
+         && (!MEM_P (operands[0])
+             || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
+             || GET_CODE (XEXP (operands[0], 0)) == POST_INC
+             || !illegal_addsub_di_memory_operand (operands[0], DImode))
+         && ((CONST_INT_P (operands[1])
+              && (unsigned HOST_WIDE_INT) INTVAL (operands[1]) >= 64)
+             || GET_CODE (operands[1]) == CONST_DOUBLE))
+       {
+         hi[0] = operands[0];
+         hi[1] = operands[1];
+
+         split_quadword_operands (insn, SET, hi, lo, 2);
+
+         pattern_lo = vax_output_int_move (NULL, lo, SImode);
+         pattern_hi = vax_output_int_move (NULL, hi, SImode);
+
+         /* The patterns are just movl/movl or pushl/pushl then a movq will
+            be shorter (1 opcode byte + 1 addrmode byte + 8 immediate value
+            bytes .vs. 2 opcode bytes + 2 addrmode bytes + 8 immediate value
+            value bytes.  */
+         if ((!strncmp (pattern_lo, "movl", 4)
+             && !strncmp (pattern_hi, "movl", 4))
+             || (!strncmp (pattern_lo, "pushl", 5)
+                 && !strncmp (pattern_hi, "pushl", 5)))
+           return "movq %1,%0";
+
+         if (MEM_P (operands[0])
+             && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
+           {
+             output_asm_insn (pattern_hi, hi);
+             operands[0] = lo[0];
+             operands[1] = lo[1];
+             operands[2] = lo[2];
+             return pattern_lo;
+           }
+         else
+           {
+             output_asm_insn (pattern_lo, lo);
+             operands[0] = hi[0];
+             operands[1] = hi[1];
+             operands[2] = hi[2];
+             return pattern_hi;
+           }
+       }
+      return "movq %1,%0";
+
     case SImode:
-      if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST)
+      if (symbolic_operand (operands[1], SImode))
        {
          if (push_operand (operands[0], SImode))
            return "pushab %a1";
          return "movab %a1,%0";
        }
+
       if (operands[1] == const0_rtx)
-       return "clrl %0";
+       {
+         if (push_operand (operands[1], SImode))
+           return "pushl %1";
+         return "clrl %0";
+       }
+
       if (CONST_INT_P (operands[1])
-         && (unsigned) INTVAL (operands[1]) >= 64)
+         && (unsigned HOST_WIDE_INT) INTVAL (operands[1]) >= 64)
        {
-         int i = INTVAL (operands[1]);
-         if ((unsigned)(~i) < 64)
+         HOST_WIDE_INT i = INTVAL (operands[1]);
+         int n;
+         if ((unsigned HOST_WIDE_INT)(~i) < 64)
            return "mcoml %N1,%0";
-         if ((unsigned)i < 0x100)
+         if ((unsigned HOST_WIDE_INT)i < 0x100)
            return "movzbl %1,%0";
          if (i >= -0x80 && i < 0)
            return "cvtbl %1,%0";
-         if ((unsigned)i < 0x10000)
+         if (optimize_size
+             && (n = exact_log2 (i & (-i))) != -1
+             && ((unsigned HOST_WIDE_INT)i >> n) < 64)
+           {
+             operands[1] = GEN_INT ((unsigned HOST_WIDE_INT)i >> n);
+             operands[2] = GEN_INT (n);
+             return "ashl %2,%1,%0";
+           }
+         if ((unsigned HOST_WIDE_INT)i < 0x10000)
            return "movzwl %1,%0";
          if (i >= -0x8000 && i < 0)
            return "cvtwl %1,%0";
@@ -939,25 +1300,27 @@ vax_output_int_move (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
     case HImode:
       if (CONST_INT_P (operands[1]))
        {
-         int i = INTVAL (operands[1]);
+         HOST_WIDE_INT i = INTVAL (operands[1]);
          if (i == 0)
            return "clrw %0";
-         else if ((unsigned int)i < 64)
+         else if ((unsigned HOST_WIDE_INT)i < 64)
            return "movw %1,%0";
-         else if ((unsigned int)~i < 64)
+         else if ((unsigned HOST_WIDE_INT)~i < 64)
            return "mcomw %H1,%0";
-         else if ((unsigned int)i < 256)
+         else if ((unsigned HOST_WIDE_INT)i < 256)
            return "movzbw %1,%0";
+         else if (i >= -0x80 && i < 0)
+           return "cvtbw %1,%0";
        }
       return "movw %1,%0";
 
     case QImode:
       if (CONST_INT_P (operands[1]))
        {
-         int i = INTVAL (operands[1]);
+         HOST_WIDE_INT i = INTVAL (operands[1]);
          if (i == 0)
            return "clrb %0";
-         else if ((unsigned int)~i < 64)
+         else if ((unsigned HOST_WIDE_INT)~i < 64)
            return "mcomb %B1,%0";
        }
       return "movb %1,%0";
@@ -982,11 +1345,96 @@ vax_output_int_move (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
    which are not modified very often.  */
 
 const char *
-vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
-                   enum machine_mode mode)
+vax_output_int_add (rtx insn, rtx *operands, enum machine_mode mode)
 {
   switch (mode)
     {
+    case DImode:
+      {
+       rtx low[3];
+       const char *pattern;
+       int carry = 1;
+       bool sub;
+
+       if (TARGET_QMATH && 0)
+         debug_rtx (insn);
+
+       split_quadword_operands (insn, PLUS, operands, low, 3);
+
+       if (TARGET_QMATH)
+         {
+           gcc_assert (rtx_equal_p (operands[0], operands[1]));
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESSS
+           gcc_assert (!flag_pic || !external_memory_operand (low[2], SImode));
+           gcc_assert (!flag_pic || !external_memory_operand (low[0], SImode));
+#endif
+
+           /* No reason to add a 0 to the low part and thus no carry, so just
+              emit the appropriate add/sub instruction.  */
+           if (low[2] == const0_rtx)
+             return vax_output_int_add (NULL, operands, SImode);
+
+           /* Are we doing addition or subtraction?  */
+           sub = CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0;
+
+           /* We can't use vax_output_int_add since some the patterns don't
+              modify the carry bit.  */
+           if (sub)
+             {
+               if (low[2] == constm1_rtx)
+                 pattern = "decl %0";
+               else
+                 pattern = "subl2 $%n2,%0";
+             }
+           else
+             {
+               if (low[2] == const1_rtx)
+                 pattern = "incl %0";
+               else
+                 pattern = "addl2 %2,%0";
+             }
+           output_asm_insn (pattern, low);
+
+           /* In 2's complement, -n = ~n + 1.  Since we are dealing with
+              two 32bit parts, we complement each and then add one to
+              low part.  We know that the low part can't overflow since
+              it's value can never be 0.  */
+           if (sub)
+               return "sbwc %N2,%0";
+           return "adwc %2,%0";
+         }
+
+       /* Add low parts.  */
+       if (rtx_equal_p (operands[0], operands[1]))
+         {
+           if (low[2] == const0_rtx)
+       /* Should examine operand, punt if not POST_INC.  */
+             pattern = "tstl %0", carry = 0;
+           else if (low[2] == const1_rtx)
+             pattern = "incl %0";
+           else
+             pattern = "addl2 %2,%0";
+         }
+       else
+         {
+           if (low[2] == const0_rtx)
+             pattern = "movl %1,%0", carry = 0;
+           else
+             pattern = "addl3 %2,%1,%0";
+         }
+       if (pattern)
+         output_asm_insn (pattern, low);
+       if (!carry)
+         /* If CARRY is 0, we don't have any carry value to worry about.  */
+         return get_insn_template (CODE_FOR_addsi3, insn);
+       /* %0 = C + %1 + %2 */
+       if (!rtx_equal_p (operands[0], operands[1]))
+         output_asm_insn ((operands[1] == const0_rtx
+                           ? "clrl %0"
+                           : "movl %1,%0"), operands);
+       return "adwc %2,%0";
+      }
+
     case SImode:
       if (rtx_equal_p (operands[0], operands[1]))
        {
@@ -995,19 +1443,25 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
          if (operands[2] == constm1_rtx)
            return "decl %0";
          if (CONST_INT_P (operands[2])
-             && (unsigned) (- INTVAL (operands[2])) < 64)
+             && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
            return "subl2 $%n2,%0";
          if (CONST_INT_P (operands[2])
-             && (unsigned) INTVAL (operands[2]) >= 64
+             && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 64
              && REG_P (operands[1])
              && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768)
                   || REGNO (operands[1]) > 11))
            return "movab %c2(%1),%0";
+         if (REG_P (operands[0]) && symbolic_operand (operands[2], SImode))
+           return "movab %a2[%0],%0";
          return "addl2 %2,%0";
        }
 
       if (rtx_equal_p (operands[0], operands[2]))
-       return "addl2 %1,%0";
+       {
+         if (REG_P (operands[0]) && symbolic_operand (operands[1], SImode))
+           return "movab %a1[%0],%0";
+         return "addl2 %1,%0";
+       }
 
       if (CONST_INT_P (operands[2])
          && INTVAL (operands[2]) < 32767
@@ -1017,11 +1471,11 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
        return "pushab %c2(%1)";
 
       if (CONST_INT_P (operands[2])
-         && (unsigned) (- INTVAL (operands[2])) < 64)
+         && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
        return "subl3 $%n2,%1,%0";
 
       if (CONST_INT_P (operands[2])
-         && (unsigned) INTVAL (operands[2]) >= 64
+         && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 64
          && REG_P (operands[1])
          && ((INTVAL (operands[2]) < 32767 && INTVAL (operands[2]) > -32768)
               || REGNO (operands[1]) > 11))
@@ -1031,6 +1485,30 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
       if (REG_P (operands[1]) && REG_P (operands[2]))
        return "movab (%1)[%2],%0";
       */
+
+      if (REG_P (operands[1]) && symbolic_operand (operands[2], SImode))
+       {
+         if (push_operand (operands[0], SImode))
+           return "pushab %a2[%1]";
+         return "movab %a2[%1],%0";
+       }
+
+      if (REG_P (operands[2]) && symbolic_operand (operands[1], SImode))
+       {
+         if (push_operand (operands[0], SImode))
+           return "pushab %a1[%2]";
+         return "movab %a1[%2],%0";
+       }
+
+      if (flag_pic && REG_P (operands[0])
+         && symbolic_operand (operands[2], SImode))
+       return "movab %a2,%0;addl2 %1,%0";
+
+      if (flag_pic
+         && (symbolic_operand (operands[1], SImode)
+             || symbolic_operand (operands[1], SImode)))
+       debug_rtx (insn);
+
       return "addl3 %1,%2,%0";
 
     case HImode:
@@ -1041,14 +1519,14 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
          if (operands[2] == constm1_rtx)
            return "decw %0";
          if (CONST_INT_P (operands[2])
-             && (unsigned) (- INTVAL (operands[2])) < 64)
+             && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
            return "subw2 $%n2,%0";
          return "addw2 %2,%0";
        }
       if (rtx_equal_p (operands[0], operands[2]))
        return "addw2 %1,%0";
       if (CONST_INT_P (operands[2])
-         && (unsigned) (- INTVAL (operands[2])) < 64)
+         && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
        return "subw3 $%n2,%1,%0";
       return "addw3 %1,%2,%0";
 
@@ -1060,14 +1538,14 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
          if (operands[2] == constm1_rtx)
            return "decb %0";
          if (CONST_INT_P (operands[2])
-             && (unsigned) (- INTVAL (operands[2])) < 64)
+             && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
            return "subb2 $%n2,%0";
          return "addb2 %2,%0";
        }
       if (rtx_equal_p (operands[0], operands[2]))
        return "addb2 %1,%0";
       if (CONST_INT_P (operands[2])
-         && (unsigned) (- INTVAL (operands[2])) < 64)
+         && (unsigned HOST_WIDE_INT) (- INTVAL (operands[2])) < 64)
        return "subb3 $%n2,%1,%0";
       return "addb3 %1,%2,%0";
 
@@ -1076,44 +1554,98 @@ vax_output_int_add (rtx insn ATTRIBUTE_UNUSED, rtx *operands,
     }
 }
 
-/* Output a conditional branch.  */
 const char *
-vax_output_conditional_branch (enum rtx_code code)
+vax_output_int_subtract (rtx insn, rtx *operands, enum machine_mode mode)
 {
-  switch (code)
+  switch (mode)
     {
-      case EQ:  return "jeql %l0";
-      case NE:  return "jneq %l0";
-      case GT:  return "jgtr %l0";
-      case LT:  return "jlss %l0";
-      case GTU: return "jgtru %l0";
-      case LTU: return "jlssu %l0";
-      case GE:  return "jgeq %l0";
-      case LE:  return "jleq %l0";
-      case GEU: return "jgequ %l0";
-      case LEU: return "jlequ %l0";
-      default:
-        gcc_unreachable ();
-    }
-}
-
-/* 1 if X is an rtx for a constant that is a valid address.  */
+    case DImode:
+      {
+       rtx low[3];
+       const char *pattern;
+       int carry = 1;
+
+       if (TARGET_QMATH && 0)
+         debug_rtx (insn);
+
+       split_quadword_operands (insn, MINUS, operands, low, 3);
+
+       if (TARGET_QMATH)
+         {
+           if (operands[1] == const0_rtx && low[1] == const0_rtx)
+             {
+               /* Negation is tricky.  It's basically complement and increment.
+                  Negate hi, then lo, and subtract the carry back.  */
+               if ((MEM_P (low[0]) && GET_CODE (XEXP (low[0], 0)) == POST_INC)
+                   || (MEM_P (operands[0])
+                       && GET_CODE (XEXP (operands[0], 0)) == POST_INC))
+                 fatal_insn ("illegal operand detected", insn);
+               output_asm_insn ("mnegl %2,%0", operands);
+               output_asm_insn ("mnegl %2,%0", low);
+               return "sbwc $0,%0";
+             }
+           gcc_assert (rtx_equal_p (operands[0], operands[1]));
+           gcc_assert (rtx_equal_p (low[0], low[1]));
+           if (low[2] == const1_rtx)
+             output_asm_insn ("decl %0", low);
+           else
+             output_asm_insn ("subl2 %2,%0", low);
+           return "sbwc %2,%0";
+         }
+
+       /* Subtract low parts.  */
+       if (rtx_equal_p (operands[0], operands[1]))
+         {
+           if (low[2] == const0_rtx)
+             pattern = 0, carry = 0;
+           else if (low[2] == constm1_rtx)
+             pattern = "decl %0";
+           else
+             pattern = "subl2 %2,%0";
+         }
+       else
+         {
+           if (low[2] == constm1_rtx)
+             pattern = "decl %0";
+           else if (low[2] == const0_rtx)
+             pattern = get_insn_template (CODE_FOR_movsi, insn), carry = 0;
+           else
+             pattern = "subl3 %2,%1,%0";
+         }
+       if (pattern)
+         output_asm_insn (pattern, low);
+       if (carry)
+         {
+           if (!rtx_equal_p (operands[0], operands[1]))
+             return "movl %1,%0;sbwc %2,%0";
+           return "sbwc %2,%0";
+           /* %0 = %2 - %1 - C */
+         }
+       return get_insn_template (CODE_FOR_subsi3, insn);
+      }
 
-int
-legitimate_constant_address_p (rtx x)
-{
-  return (GET_CODE (x) == LABEL_REF || GET_CODE (x) == SYMBOL_REF
-         || CONST_INT_P (x) || GET_CODE (x) == CONST
-         || GET_CODE (x) == HIGH);
+    default:
+      gcc_unreachable ();
+  }
 }
 
-/* Nonzero if the constant value X is a legitimate general operand.
-   It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+/* True if X is an rtx for a constant that is a valid address.  */
 
-int
-legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
+bool
+legitimate_constant_address_p (rtx x)
 {
-  return 1;
+  if (GET_CODE (x) == LABEL_REF || GET_CODE (x) == SYMBOL_REF
+         || CONST_INT_P (x) || GET_CODE (x) == HIGH)
+    return true;
+  if (GET_CODE (x) != CONST)
+    return false;
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESS
+  if (flag_pic
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+      && !SYMBOL_REF_LOCAL_P (XEXP (XEXP (x, 0), 0)))
+    return false;
+#endif
+   return true;
 }
 
 /* The other macros defined here are used only in legitimate_address_p ().  */
@@ -1133,78 +1665,77 @@ legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
 /* Re-definition of CONSTANT_ADDRESS_P, which is true only when there
    are no SYMBOL_REFs for external symbols present.  */
 
-static int
-indirectable_constant_address_p (rtx x)
+static bool
+indirectable_constant_address_p (rtx x, bool indirect)
 {
-  if (!CONSTANT_ADDRESS_P (x))
-    return 0;
-  if (GET_CODE (x) == CONST && GET_CODE (XEXP ((x), 0)) == PLUS)
-    x = XEXP (XEXP (x, 0), 0);
-  if (GET_CODE (x) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (x))
-    return 0;
-
-  return 1;
+  if (GET_CODE (x) == SYMBOL_REF)
+    return !flag_pic || SYMBOL_REF_LOCAL_P (x) || !indirect;
+
+  if (GET_CODE (x) == CONST)
+    return !flag_pic
+          || GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
+          || SYMBOL_REF_LOCAL_P (XEXP (XEXP (x, 0), 0));
+
+  return CONSTANT_ADDRESS_P (x);
 }
 
 #else /* not NO_EXTERNAL_INDIRECT_ADDRESS */
 
-static int
-indirectable_constant_address_p (rtx x)
+static bool
+indirectable_constant_address_p (rtx x, bool indirect ATTRIBUTE_UNUSED)
 {
   return CONSTANT_ADDRESS_P (x);
 }
 
 #endif /* not NO_EXTERNAL_INDIRECT_ADDRESS */
 
-/* Nonzero if X is an address which can be indirected.  External symbols
+/* True if X is an address which can be indirected.  External symbols
    could be in a sharable image library, so we disallow those.  */
 
-static int
-indirectable_address_p(rtx x, int strict)
+static bool
+indirectable_address_p (rtx x, bool strict, bool indirect)
 {
-  if (indirectable_constant_address_p (x))
-    return 1;
-  if (BASE_REGISTER_P (x, strict))
-    return 1;
-  if (GET_CODE (x) == PLUS
-      && BASE_REGISTER_P (XEXP (x, 0), strict)
-      && indirectable_constant_address_p (XEXP (x, 1)))
-    return 1;
-  return 0;
+  if (indirectable_constant_address_p (x, indirect)
+      || BASE_REGISTER_P (x, strict))
+    return true;
+  if (GET_CODE (x) != PLUS
+      || !BASE_REGISTER_P (XEXP (x, 0), strict)
+      || (flag_pic && !CONST_INT_P (XEXP (x, 1))))
+    return false;
+  return indirectable_constant_address_p (XEXP (x, 1), indirect);
 }
 
-/* Return 1 if x is a valid address not using indexing.
+/* Return true if x is a valid address not using indexing.
    (This much is the easy part.)  */
-static int
-nonindexed_address_p (rtx x, int strict)
+static bool
+nonindexed_address_p (rtx x, bool strict)
 {
   rtx xfoo0;
   if (REG_P (x))
     {
-      extern rtx *reg_equiv_mem;
-      if (!reload_in_progress
-         || reg_equiv_mem[REGNO (x)] == 0
-         || indirectable_address_p (reg_equiv_mem[REGNO (x)], strict))
-       return 1;
+      if (! reload_in_progress
+         || reg_equiv_mem (REGNO (x)) == 0
+         || indirectable_address_p (reg_equiv_mem (REGNO (x)), strict, false))
+       return true;
     }
-  if (indirectable_constant_address_p (x))
-    return 1;
-  if (indirectable_address_p (x, strict))
-    return 1;
+  if (indirectable_constant_address_p (x, false))
+    return true;
+  if (indirectable_address_p (x, strict, false))
+    return true;
   xfoo0 = XEXP (x, 0);
-  if (MEM_P (x) && indirectable_address_p (xfoo0, strict))
-    return 1;
+  if (MEM_P (x) && indirectable_address_p (xfoo0, strict, true))
+    return true;
   if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
       && BASE_REGISTER_P (xfoo0, strict))
-    return 1;
-  return 0;
+    return true;
+  return false;
 }
 
-/* 1 if PROD is either a reg times size of mode MODE and MODE is less
+/* True if PROD is either a reg times size of mode MODE and MODE is less
    than or equal 8 bytes, or just a reg if MODE is one byte.  */
 
-static int
-index_term_p (rtx prod, enum machine_mode mode, int strict)
+static bool
+index_term_p (rtx prod, enum machine_mode mode, bool strict)
 {
   rtx xfoo0, xfoo1;
 
@@ -1212,7 +1743,7 @@ index_term_p (rtx prod, enum machine_mode mode, int strict)
     return BASE_REGISTER_P (prod, strict);
 
   if (GET_CODE (prod) != MULT || GET_MODE_SIZE (mode) > 8)
-    return 0;
+    return false;
 
   xfoo0 = XEXP (prod, 0);
   xfoo1 = XEXP (prod, 1);
@@ -1220,52 +1751,65 @@ index_term_p (rtx prod, enum machine_mode mode, int strict)
   if (CONST_INT_P (xfoo0)
       && INTVAL (xfoo0) == (int)GET_MODE_SIZE (mode)
       && INDEX_REGISTER_P (xfoo1, strict))
-    return 1;
+    return true;
 
   if (CONST_INT_P (xfoo1)
       && INTVAL (xfoo1) == (int)GET_MODE_SIZE (mode)
       && INDEX_REGISTER_P (xfoo0, strict))
-    return 1;
+    return true;
 
-  return 0;
+  return false;
 }
 
-/* Return 1 if X is the sum of a register
+/* Return true if X is the sum of a register
    and a valid index term for mode MODE.  */
-static int
-reg_plus_index_p (rtx x, enum machine_mode mode, int strict)
+static bool
+reg_plus_index_p (rtx x, enum machine_mode mode, bool strict)
 {
   rtx xfoo0, xfoo1;
 
   if (GET_CODE (x) != PLUS)
-    return 0;
+    return false;
 
   xfoo0 = XEXP (x, 0);
   xfoo1 = XEXP (x, 1);
 
   if (BASE_REGISTER_P (xfoo0, strict) && index_term_p (xfoo1, mode, strict))
-    return 1;
+    return true;
 
   if (BASE_REGISTER_P (xfoo1, strict) && index_term_p (xfoo0, mode, strict))
-    return 1;
+    return true;
 
-  return 0;
+  return false;
 }
 
-/* legitimate_address_p returns 1 if it recognizes an RTL expression "x"
+/* Return true if xfoo0 and xfoo1 constitute a valid indexed address.  */
+static bool
+indexable_address_p (rtx xfoo0, rtx xfoo1, enum machine_mode mode, bool strict)
+{
+  if (!CONSTANT_ADDRESS_P (xfoo0))
+    return false;
+  if (BASE_REGISTER_P (xfoo1, strict))
+    return !flag_pic || mode == QImode;
+  if (flag_pic && symbolic_operand (xfoo0, SImode))
+    return false;
+  return reg_plus_index_p (xfoo1, mode, strict);
+}
+
+/* legitimate_address_p returns true if it recognizes an RTL expression "x"
    that is a valid memory address for an instruction.
    The MODE argument is the machine mode for the MEM expression
    that wants to use this address.  */
-int
-legitimate_address_p (enum machine_mode mode, rtx x, int strict)
+bool
+vax_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
   rtx xfoo0, xfoo1;
 
   if (nonindexed_address_p (x, strict))
-    return 1;
+    return true;
 
   if (GET_CODE (x) != PLUS)
-    return 0;
+    return false;
 
   /* Handle <address>[index] represented with index-sum outermost */
 
@@ -1274,50 +1818,361 @@ legitimate_address_p (enum machine_mode mode, rtx x, int strict)
 
   if (index_term_p (xfoo0, mode, strict)
       && nonindexed_address_p (xfoo1, strict))
-    return 1;
+    return true;
 
   if (index_term_p (xfoo1, mode, strict)
       && nonindexed_address_p (xfoo0, strict))
-    return 1;
+    return true;
 
   /* Handle offset(reg)[index] with offset added outermost */
 
-  if (indirectable_constant_address_p (xfoo0)
-      && (BASE_REGISTER_P (xfoo1, strict)
-          || reg_plus_index_p (xfoo1, mode, strict)))
-    return 1;
-
-  if (indirectable_constant_address_p (xfoo1)
-      && (BASE_REGISTER_P (xfoo0, strict)
-          || reg_plus_index_p (xfoo0, mode, strict)))
-    return 1;
+  if (indexable_address_p (xfoo0, xfoo1, mode, strict)
+      || indexable_address_p (xfoo1, xfoo0, mode, strict))
+    return true;
 
-  return 0;
+  return false;
 }
 
-/* Return 1 if x (a legitimate address expression) has an effect that
+/* Return true if x (a legitimate address expression) has an effect that
    depends on the machine mode it is used for.  On the VAX, the predecrement
    and postincrement address depend thus (the amount of decrement or
    increment being the length of the operand) and all indexed address depend
    thus (because the index scale factor is the length of the operand).  */
 
-int
-vax_mode_dependent_address_p (rtx x)
+static bool
+vax_mode_dependent_address_p (const_rtx x, addr_space_t as ATTRIBUTE_UNUSED)
 {
   rtx xfoo0, xfoo1;
 
   /* Auto-increment cases are now dealt with generically in recog.c.  */
-
   if (GET_CODE (x) != PLUS)
-    return 0;
+    return false;
 
   xfoo0 = XEXP (x, 0);
   xfoo1 = XEXP (x, 1);
 
-  if (CONSTANT_ADDRESS_P (xfoo0) && REG_P (xfoo1))
-    return 0;
-  if (CONSTANT_ADDRESS_P (xfoo1) && REG_P (xfoo0))
-    return 0;
+  if (CONST_INT_P (xfoo0) && REG_P (xfoo1))
+    return false;
+  if (CONST_INT_P (xfoo1) && REG_P (xfoo0))
+    return false;
+  if (!flag_pic && CONSTANT_ADDRESS_P (xfoo0) && REG_P (xfoo1))
+    return false;
+  if (!flag_pic && CONSTANT_ADDRESS_P (xfoo1) && REG_P (xfoo0))
+    return false;
+
+  return true;
+}
+
+static rtx
+fixup_mathdi_operand (rtx x, enum machine_mode mode)
+{
+  if (illegal_addsub_di_memory_operand (x, mode))
+    {
+      rtx addr = XEXP (x, 0);
+      rtx temp = gen_reg_rtx (Pmode);
+      rtx offset = 0;
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESS
+      if (GET_CODE (addr) == CONST && flag_pic)
+       {
+         offset = XEXP (XEXP (addr, 0), 1);
+         addr = XEXP (XEXP (addr, 0), 0);
+       }
+#endif
+      emit_move_insn (temp, addr);
+      if (offset)
+       temp = gen_rtx_PLUS (Pmode, temp, offset);
+      x = gen_rtx_MEM (DImode, temp);
+    }
+  return x;
+}
+
+void
+vax_expand_addsub_di_operands (rtx * operands, enum rtx_code code)
+{
+  int hi_only = operand_subword (operands[2], 0, 0, DImode) == const0_rtx;
+  rtx temp;
+
+  rtx (*gen_old_insn)(rtx, rtx, rtx);
+  rtx (*gen_si_insn)(rtx, rtx, rtx);
+  rtx (*gen_insn)(rtx, rtx, rtx);
+
+  if (code == PLUS)
+    {
+      gen_old_insn = gen_adddi3_old;
+      gen_si_insn = gen_addsi3;
+      gen_insn = gen_adcdi3;
+    }
+  else if (code == MINUS)
+    {
+      gen_old_insn = gen_subdi3_old;
+      gen_si_insn = gen_subsi3;
+      gen_insn = gen_sbcdi3;
+    }
+  else
+    gcc_unreachable ();
+
+  /* If this is addition (thus operands are commutative) and if there is one
+     addend that duplicates the desination, we want that addend to be the
+     first addend.  */
+  if (code == PLUS
+      && rtx_equal_p (operands[0], operands[2])
+      && !rtx_equal_p (operands[1], operands[2]))
+    {
+      temp = operands[2];
+      operands[2] = operands[1];
+      operands[1] = temp;
+    }
+
+  if (!TARGET_QMATH)
+    {
+      emit_insn ((*gen_old_insn) (operands[0], operands[1], operands[2]));
+    }
+  else if (hi_only)
+    {
+      if (!rtx_equal_p (operands[0], operands[1])
+         && (REG_P (operands[0]) && MEM_P (operands[1])))
+       {
+         emit_move_insn (operands[0], operands[1]);
+         operands[1] = operands[0];
+       }
+
+      operands[0] = fixup_mathdi_operand (operands[0], DImode);
+      operands[1] = fixup_mathdi_operand (operands[1], DImode);
+      operands[2] = fixup_mathdi_operand (operands[2], DImode);
+
+      if (!rtx_equal_p (operands[0], operands[1]))
+       emit_move_insn (operand_subword (operands[0], 0, 0, DImode),
+                         operand_subword (operands[1], 0, 0, DImode));
+
+      emit_insn ((*gen_si_insn) (operand_subword (operands[0], 1, 0, DImode),
+                                operand_subword (operands[1], 1, 0, DImode),
+                                operand_subword (operands[2], 1, 0, DImode)));
+    }
+  else
+    {
+      /* If are adding the same value together, that's really a multiply by 2,
+        and that's just a left shift of 1.  */
+      if (rtx_equal_p (operands[1], operands[2]))
+       {
+         gcc_assert (code != MINUS);
+         emit_insn (gen_ashldi3 (operands[0], operands[1], const1_rtx));
+         return;
+       }
+
+      operands[0] = fixup_mathdi_operand (operands[0], DImode);
+
+      /* If an operand is the same as operand[0], use the operand[0] rtx
+        because fixup will an equivalent rtx but not an equal one. */
+
+      if (rtx_equal_p (operands[0], operands[1]))
+       operands[1] = operands[0];
+      else
+       operands[1] = fixup_mathdi_operand (operands[1], DImode);
+
+      if (rtx_equal_p (operands[0], operands[2]))
+       operands[2] = operands[0];
+      else
+       operands[2] = fixup_mathdi_operand (operands[2], DImode);
+
+      /* If we are subtracting not from ourselves [d = a - b], and because the
+        carry ops are two operand only, we would need to do a move prior to
+        the subtract.  And if d == b, we would need a temp otherwise
+        [d = a, d -= d] and we end up with 0.  Instead we rewrite d = a - b
+        into d = -b, d += a.  Since -b can never overflow, even if b == d,
+        no temp is needed.
+
+        If we are doing addition, since the carry ops are two operand, if
+        we aren't adding to ourselves, move the first addend to the
+        destination first.  */
+
+      gcc_assert (operands[1] != const0_rtx || code == MINUS);
+      if (!rtx_equal_p (operands[0], operands[1]) && operands[1] != const0_rtx)
+       {
+         if (code == MINUS && CONSTANT_P (operands[1]))
+           {
+             temp = gen_reg_rtx (DImode);
+             emit_insn (gen_sbcdi3 (operands[0], const0_rtx, operands[2]));
+             code = PLUS;
+             gen_insn = gen_adcdi3;
+             operands[2] = operands[1];
+             operands[1] = operands[0];
+           }
+         else
+           emit_move_insn (operands[0], operands[1]);
+       }
+
+      /* Subtracting a constant will have been rewritten to an addition of the
+        negative of that constant before we get here.  */
+      gcc_assert (!CONSTANT_P (operands[2]) || code == PLUS);
+      emit_insn ((*gen_insn) (operands[0], operands[1], operands[2]));
+    }
+}
+
+bool
+adjacent_operands_p (rtx lo, rtx hi, enum machine_mode mode)
+{
+  HOST_WIDE_INT lo_offset;
+  HOST_WIDE_INT hi_offset;
+
+  if (GET_CODE (lo) != GET_CODE (hi))
+    return false;
+
+  if (REG_P (lo))
+    return mode == SImode && REGNO (lo) + 1 == REGNO (hi);
+  if (CONST_INT_P (lo))
+    return INTVAL (hi) == 0 && 0 <= INTVAL (lo) && INTVAL (lo) < 64;
+  if (CONST_INT_P (lo))
+    return mode != SImode;
+
+  if (!MEM_P (lo))
+    return false;
+
+  if (MEM_VOLATILE_P (lo) || MEM_VOLATILE_P (hi))
+    return false;
+
+  lo = XEXP (lo, 0);
+  hi = XEXP (hi, 0);
+
+  if (GET_CODE (lo) == POST_INC /* || GET_CODE (lo) == PRE_DEC */)
+    return rtx_equal_p (lo, hi);
+
+  switch (GET_CODE (lo))
+    {
+    case REG:
+    case SYMBOL_REF:
+      lo_offset = 0;
+      break;
+    case CONST:
+      lo = XEXP (lo, 0);
+      /* FALLTHROUGH */
+    case PLUS:
+      if (!CONST_INT_P (XEXP (lo, 1)))
+       return false;
+      lo_offset = INTVAL (XEXP (lo, 1));
+      lo = XEXP (lo, 0);
+      break;
+    default:
+      return false;
+    }
+
+  switch (GET_CODE (hi))
+    {
+    case REG:
+    case SYMBOL_REF:
+      hi_offset = 0;
+      break;
+    case CONST:
+      hi = XEXP (hi, 0);
+      /* FALLTHROUGH */
+    case PLUS:
+      if (!CONST_INT_P (XEXP (hi, 1)))
+       return false;
+      hi_offset = INTVAL (XEXP (hi, 1));
+      hi = XEXP (hi, 0);
+      break;
+    default:
+      return false;
+    }
+
+  if (GET_CODE (lo) == MULT || GET_CODE (lo) == PLUS)
+    return false;
+
+  return rtx_equal_p (lo, hi)
+        && hi_offset - lo_offset == GET_MODE_SIZE (mode);
+}
+
+/* Output assembler code for a block containing the constant parts
+   of a trampoline, leaving space for the variable parts.  */
+
+/* On the VAX, the trampoline contains an entry mask and two instructions:
+     .word NN
+     movl $STATIC,r0   (store the functions static chain)
+     jmp  *$FUNCTION   (jump to function code at address FUNCTION)  */
+
+static void
+vax_asm_trampoline_template (FILE *f ATTRIBUTE_UNUSED)
+{
+  assemble_aligned_integer (2, const0_rtx);
+  assemble_aligned_integer (2, GEN_INT (0x8fd0));
+  assemble_aligned_integer (4, const0_rtx);
+  assemble_aligned_integer (1, GEN_INT (0x50 + STATIC_CHAIN_REGNUM));
+  assemble_aligned_integer (2, GEN_INT (0x9f17));
+  assemble_aligned_integer (4, const0_rtx);
+}
+
+/* We copy the register-mask from the function's pure code
+   to the start of the trampoline.  */
+
+static void
+vax_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem;
+
+  emit_block_move (m_tramp, assemble_trampoline_template (),
+                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+  mem = adjust_address (m_tramp, HImode, 0);
+  emit_move_insn (mem, gen_const_mem (HImode, fnaddr));
+
+  mem = adjust_address (m_tramp, SImode, 4);
+  emit_move_insn (mem, cxt);
+  mem = adjust_address (m_tramp, SImode, 11);
+  emit_move_insn (mem, plus_constant (Pmode, fnaddr, 2));
+  emit_insn (gen_sync_istream ());
+}
+
+/* Value is the number of bytes of arguments automatically
+   popped when returning from a subroutine call.
+   FUNDECL is the declaration node of the function (as a tree),
+   FUNTYPE is the data type of the function (as a tree),
+   or for a library call it is an identifier node for the subroutine name.
+   SIZE is the number of bytes of arguments passed on the stack.
+
+   On the VAX, the RET insn pops a maximum of 255 args for any function.  */
+
+static int
+vax_return_pops_args (tree fundecl ATTRIBUTE_UNUSED,
+                     tree funtype ATTRIBUTE_UNUSED, int size)
+{
+  return size > 255 * 4 ? 0 : size;
+}
+
+/* Define where to put the arguments to a function.
+   Value is zero to push the argument on the stack,
+   or a hard register in which to store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+    This is null for libcalls where that information may
+    not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+    the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).  */
+
+/* On the VAX all args are pushed.  */
+
+static rtx
+vax_function_arg (cumulative_args_t cum ATTRIBUTE_UNUSED,
+                 enum machine_mode mode ATTRIBUTE_UNUSED,
+                 const_tree type ATTRIBUTE_UNUSED,
+                 bool named ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
+/* Update the data in CUM to advance over an argument of mode MODE and
+   data type TYPE.  (TYPE is null for libcalls where that information
+   may not be available.)  */
+
+static void
+vax_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+                         const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
 
-  return 1;
+  *cum += (mode != BLKmode
+          ? (GET_MODE_SIZE (mode) + 3) & ~3
+          : (int_size_in_bytes (type) + 3) & ~3);
 }