diff gcc/config/vax/vax.c @ 55:77e2b8dfacca gcc-4.4.5

update it from 4.4.3 to 4.5.0
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Fri, 12 Feb 2010 23:39:51 +0900
parents 58ad6c70ea60
children b7f97abdc517
line wrap: on
line diff
--- a/gcc/config/vax/vax.c	Sun Feb 07 18:28:00 2010 +0900
+++ b/gcc/config/vax/vax.c	Fri Feb 12 23:39:51 2010 +0900
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for VAX.
    Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002,
-   2004, 2005, 2006, 2007, 2008
+   2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -24,6 +24,7 @@
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "df.h"
 #include "tree.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -39,10 +40,13 @@
 #include "flags.h"
 #include "debug.h"
 #include "toplev.h"
+#include "tm-preds.h"
+#include "tm-constrs.h"
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
 
+static bool vax_legitimate_address_p (enum machine_mode, rtx, bool);
 static void vax_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void vax_file_start (void);
 static void vax_init_libfuncs (void);
@@ -52,6 +56,9 @@
 static int vax_address_cost (rtx, bool);
 static bool vax_rtx_costs (rtx, int, int, int *, 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);
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
@@ -87,6 +94,20 @@
 #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_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
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Set global variables as needed for the options enabled.  */
@@ -161,33 +182,43 @@
 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 +231,7 @@
 void
 print_operand_address (FILE * file, rtx addr)
 {
+  rtx orig = addr;
   rtx reg1, breg, ireg;
   rtx offset;
 
@@ -344,7 +376,11 @@
       /* 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 +390,36 @@
 	}
 
       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,8 +437,99 @@
       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 (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);
+    }
+}
 
 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)
 {
   switch (GET_CODE (op))
@@ -404,22 +560,22 @@
     }
 }
 
-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);
 
@@ -430,13 +586,13 @@
       REAL_VALUE_FROM_INT (s, x, 0, mode);
 
       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;
 }
 
 
@@ -550,10 +706,13 @@
 	 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 +736,7 @@
       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 +942,7 @@
 	  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 +971,10 @@
 
 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 +990,12 @@
   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 +1071,161 @@
 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;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+	      /* 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 (hval != 0)
+		{
+		  if (n <= 26 || hval >= ((unsigned)1 << (n - 26)))
+		    n = 0;	/* failure */
+		  else
+		    lval |= hval << (32 - n);
+		}
+#endif
+	      /*  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,%1,%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,%1,%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 (CONST_INT_P (operands[1])
-	  && (unsigned) INTVAL (operands[1]) >= 64)
 	{
-	  int i = INTVAL (operands[1]);
-	  if ((unsigned)(~i) < 64)
+	  if (push_operand (operands[1], SImode))
+	    return "pushl %1";
+	  return "clrl %0";
+	}
+
+      if (CONST_INT_P (operands[1])
+	  && (unsigned HOST_WIDE_INT) INTVAL (operands[1]) >= 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 +1237,27 @@
     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 +1282,96 @@
    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 +1380,25 @@
 	  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 +1408,11 @@
 	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 +1422,30 @@
       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 +1456,14 @@
 	  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 +1475,14 @@
 	  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 +1491,107 @@
     }
 }
 
-/* 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 ();
-    }
+    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);
+      }
+
+    default:
+      gcc_unreachable ();
+  }
 }
 
-/* 1 if X is an rtx for a constant that is a valid address.  */
+/* True if X is an rtx for a constant that is a valid address.  */
 
-int
+bool
 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);
+  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;
 }
 
-/* Nonzero if the constant value X is a legitimate general operand.
+/* True if the constant value X is a legitimate general operand.
    It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
 
-int
+bool
 legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
 {
-  return 1;
+  return true;
 }
 
 /* The other macros defined here are used only in legitimate_address_p ().  */
@@ -1133,78 +1611,78 @@
 /* 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;
+  if (GET_CODE (x) == SYMBOL_REF)
+    return !flag_pic || SYMBOL_REF_LOCAL_P (x) || !indirect;
 
-  return 1;
+  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
+      if (! reload_in_progress
 	  || reg_equiv_mem[REGNO (x)] == 0
-	  || indirectable_address_p (reg_equiv_mem[REGNO (x)], strict))
-	return 1;
+	  || 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 +1690,7 @@
     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 +1698,65 @@
   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 +1765,307 @@
 
   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 (indexable_address_p (xfoo0, xfoo1, mode, strict)
+      || indexable_address_p (xfoo1, xfoo0, mode, strict))
+    return true;
 
-  if (indirectable_constant_address_p (xfoo1)
-      && (BASE_REGISTER_P (xfoo0, strict)
-          || reg_plus_index_p (xfoo0, mode, strict)))
-    return 1;
-
-  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
+bool
 vax_mode_dependent_address_p (rtx x)
 {
   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.  */
 
-  return 1;
+      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 (fnaddr, 2));
+  emit_insn (gen_sync_istream ());
+}
+