diff gcc/config/vax/vax.md @ 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 a06113de4d67
children f6334be47118
line wrap: on
line diff
--- a/gcc/config/vax/vax.md	Sun Feb 07 18:28:00 2010 +0900
+++ b/gcc/config/vax/vax.md	Fri Feb 12 23:39:51 2010 +0900
@@ -1,6 +1,6 @@
 ;; Machine description for GNU compiler, VAX Version
 ;; Copyright (C) 1987, 1988, 1991, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-;; 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
+;; 2002, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
 
 ;; This file is part of GCC.
 
@@ -43,7 +43,9 @@
 ;; Integer modes supported on VAX, with a mapping from machine mode
 ;; to mnemonic suffix.  DImode is always a special case.
 (define_mode_iterator VAXint [QI HI SI])
-(define_mode_attr  isfx [(QI "b") (HI "w") (SI "l")])
+(define_mode_iterator VAXintQH [QI HI])
+(define_mode_iterator VAXintQHSD [QI HI SI DI])
+(define_mode_attr  isfx [(QI "b") (HI "w") (SI "l") (DI "q")])
 
 ;; Similar for float modes supported on VAX.
 (define_mode_iterator VAXfp [SF DF])
@@ -52,30 +54,20 @@
 ;; Some output patterns want integer immediates with a prefix...
 (define_mode_attr  iprefx [(QI "B") (HI "H") (SI "N")])
 
-;; We don't want to allow a constant operand for test insns because
-;; (set (cc0) (const_int foo)) has no mode information.  Such insns will
-;; be folded while optimizing anyway.
+;;
+(include "constraints.md")
+(include "predicates.md")
 
-(define_insn "tst<mode>"
-  [(set (cc0)
-	(match_operand:VAXint 0 "nonimmediate_operand" "g"))]
-  ""
-  "tst<VAXint:isfx> %0")
-
-(define_insn "tst<mode>"
+(define_insn "*cmp<mode>"
   [(set (cc0)
-	(match_operand:VAXfp 0 "general_operand" "gF"))]
+	(compare (match_operand:VAXint 0 "nonimmediate_operand" "nrmT,nrmT")
+		 (match_operand:VAXint 1 "general_operand" "I,nrmT")))]
   ""
-  "tst<VAXfp:fsfx> %0")
+  "@
+   tst<VAXint:isfx> %0
+   cmp<VAXint:isfx> %0,%1")
 
-(define_insn "cmp<mode>"
-  [(set (cc0)
-	(compare (match_operand:VAXint 0 "nonimmediate_operand" "g")
-		 (match_operand:VAXint 1 "general_operand" "g")))]
-  ""
-  "cmp<VAXint:isfx> %0,%1")
-
-(define_insn "cmp<mode>"
+(define_insn "*cmp<mode>"
   [(set (cc0)
 	(compare (match_operand:VAXfp 0 "general_operand" "gF,gF")
 		 (match_operand:VAXfp 1 "general_operand" "G,gF")))]
@@ -86,8 +78,9 @@
 
 (define_insn "*bit<mode>"
   [(set (cc0)
-	(and:VAXint (match_operand:VAXint 0 "general_operand" "g")
-		   (match_operand:VAXint 1 "general_operand" "g")))]
+	(compare (and:VAXint (match_operand:VAXint 0 "general_operand" "nrmT")
+			     (match_operand:VAXint 1 "general_operand" "nrmT"))
+		 (const_int 0)))]
   ""
   "bit<VAXint:isfx> %0,%1")
 
@@ -115,12 +108,10 @@
 ;;  "movh %1,%0")
 
 (define_insn "movdi"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=g,g")
-	(match_operand:DI 1 "general_operand" "I,g"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
+	(match_operand:DI 1 "general_operand" "g"))]
   ""
-  "@
-   clrq %0
-   movq %D1,%0")
+  "* return vax_output_int_move (insn, operands, DImode);")
 
 ;; The VAX move instructions have space-time tradeoffs.  On a MicroVAX
 ;; register-register mov instructions take 3 bytes and 2 CPU cycles.  clrl
@@ -139,9 +130,37 @@
 ;;  Loads of constants between 64 and 128 used to be done with
 ;; "addl3 $63,#,dst" but this is slower than movzbl and takes as much space.
 
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+	(match_operand:SI 1 "general_operand" ""))]
+  ""
+  "
+{
+#ifdef NO_EXTERNAL_INDIRECT_ADDRESS
+  if (flag_pic
+      && GET_CODE (operands[1]) == CONST
+      && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF
+      && !SYMBOL_REF_LOCAL_P (XEXP (XEXP (operands[1], 0), 0)))
+    {
+      rtx symbol_ref = XEXP (XEXP (operands[1], 0), 0);
+      rtx const_int = XEXP (XEXP (operands[1], 0), 1);
+      rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
+      emit_move_insn (temp, symbol_ref);
+      emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, const_int));
+      DONE;
+    }
+#endif
+}")
+
+(define_insn "movsi_2"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+	(match_operand:SI 1 "nonsymbolic_operand" "nrmT"))]
+  ""
+  "* return vax_output_int_move (insn, operands, SImode);")
+
 (define_insn "mov<mode>"
-  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
-        (match_operand:VAXint 1 "general_operand" "g"))]
+  [(set (match_operand:VAXintQH 0 "nonimmediate_operand" "=g")
+	(match_operand:VAXintQH 1 "general_operand" "g"))]
   ""
   "* return vax_output_int_move (insn, operands, <MODE>mode);")
 
@@ -192,17 +211,19 @@
    (match_operand 3 "" "")]
   ""
   "
+{
   emit_insn (gen_movmemhi1 (operands[0], operands[1], operands[2]));
   DONE;
-")
+}")
 
 ;; The definition of this insn does not really explain what it does,
 ;; but it should suffice
 ;; that anything generated as this insn will be recognized as one
 ;; and that it won't successfully combine with anything.
+
 (define_insn "movmemhi1"
-  [(set (match_operand:BLK 0 "memory_operand" "=m")
-	(match_operand:BLK 1 "memory_operand" "m"))
+  [(set (match_operand:BLK 0 "memory_operand" "=o")
+	(match_operand:BLK 1 "memory_operand" "o"))
    (use (match_operand:HI 2 "general_operand" "g"))
    (clobber (reg:SI 0))
    (clobber (reg:SI 1))
@@ -217,13 +238,13 @@
 
 (define_insn "truncsiqi2"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=g")
-	(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))]
+	(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))]
   ""
   "cvtlb %1,%0")
 
 (define_insn "truncsihi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
-	(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))]
+	(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))]
   ""
   "cvtlw %1,%0")
 
@@ -309,56 +330,62 @@
    add<VAXfp:fsfx>2 %1,%0
    add<VAXfp:fsfx>3 %1,%2,%0")
 
+(define_insn "pushlclsymreg"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "local_symbolic_operand" "i")))]
+  "flag_pic"
+  "pushab %a2[%1]")
+
+(define_insn "pushextsymreg"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "external_symbolic_operand" "i")))]
+  "flag_pic"
+  "pushab %a2[%1]")
+
+(define_insn "movlclsymreg"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "local_symbolic_operand" "i")))]
+  "flag_pic"
+  "movab %a2[%1],%0")
+
+(define_insn "movextsymreg"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+	(plus:SI (match_operand:SI 1 "register_operand" "%r")
+		 (match_operand:SI 2 "external_symbolic_operand" "i")))]
+  "flag_pic"
+  "movab %a2[%1],%0")
+
 (define_insn "add<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
-	(plus:VAXint (match_operand:VAXint 1 "general_operand" "g")
-		    (match_operand:VAXint 2 "general_operand" "g")))]
+	(plus:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")
+		    (match_operand:VAXint 2 "general_operand" "nrmT")))]
   ""
   "* return vax_output_int_add (insn, operands, <MODE>mode);")
 
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
+	(plus:DI (match_operand:DI 1 "general_operand" "g")
+		 (match_operand:DI 2 "general_operand" "g")))]
+  "!reload_in_progress"
+  "vax_expand_addsub_di_operands (operands, PLUS); DONE;")
+
+(define_insn "adcdi3"
+  [(set (match_operand:DI 0 "nonimmediate_addsub_di_operand" "=Rr")
+	(plus:DI (match_operand:DI 1 "general_addsub_di_operand" "%0")
+		 (match_operand:DI 2 "general_addsub_di_operand" "nRr")))]
+  "TARGET_QMATH"
+  "* return vax_output_int_add (insn, operands, DImode);")
+
 ;; The add-with-carry (adwc) instruction only accepts two operands.
-(define_insn "adddi3"
+(define_insn "adddi3_old"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=ro>,ro>")
 	(plus:DI (match_operand:DI 1 "general_operand" "%0,ro>")
-		 (match_operand:DI 2 "general_operand" "Fro,F")))]
-  ""
-  "*
-{
-  rtx low[3];
-  const char *pattern;
-  int carry = 1;
-
-  split_quadword_operands (operands, low, 3);
-  /* 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\";
-}")
+		 (match_operand:DI 2 "general_operand" "Fsro,Fs")))]
+  "!TARGET_QMATH"
+  "* return vax_output_int_add (insn, operands, DImode);")
 
 ;;- All kinds of subtract instructions.
 
@@ -373,56 +400,34 @@
 
 (define_insn "sub<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
-	(minus:VAXint (match_operand:VAXint 1 "general_operand" "0,g")
-		     (match_operand:VAXint 2 "general_operand" "g,g")))]
+	(minus:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
+		     (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))]
   ""
   "@
    sub<VAXint:isfx>2 %2,%0
    sub<VAXint:isfx>3 %2,%1,%0")
 
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
+	(minus:DI (match_operand:DI 1 "general_operand" "g")
+		  (match_operand:DI 2 "general_operand" "g")))]
+  "!reload_in_progress"
+  "vax_expand_addsub_di_operands (operands, MINUS); DONE;")
+
+(define_insn "sbcdi3"
+  [(set (match_operand:DI 0 "nonimmediate_addsub_di_operand" "=Rr,=Rr")
+	(minus:DI (match_operand:DI 1 "general_addsub_di_operand" "0,I")
+		  (match_operand:DI 2 "general_addsub_di_operand" "nRr,Rr")))]
+  "TARGET_QMATH"
+  "* return vax_output_int_subtract (insn, operands, DImode);")
+
 ;; The subtract-with-carry (sbwc) instruction only takes two operands.
-(define_insn "subdi3"
+(define_insn "subdi3_old"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=or>,or>")
 	(minus:DI (match_operand:DI 1 "general_operand" "0,or>")
-		  (match_operand:DI 2 "general_operand" "For,F")))]
-  ""
-  "*
-{
-  rtx low[3];
-  const char *pattern;
-  int carry = 1;
-
-  split_quadword_operands (operands, low, 3);
-  /* 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);
-}")
+		  (match_operand:DI 2 "general_operand" "Fsor,Fs")))]
+  "!TARGET_QMATH"
+  "* return vax_output_int_subtract (insn, operands, DImode);")
 
 ;;- Multiply instructions.
 
@@ -438,8 +443,8 @@
 
 (define_insn "mul<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
-	(mult:VAXint (match_operand:VAXint 1 "general_operand" "0,g,g")
-		    (match_operand:VAXint 2 "general_operand" "g,0,g")))]
+	(mult:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
+		    (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
   ""
   "@
    mul<VAXint:isfx>2 %2,%0
@@ -449,9 +454,9 @@
 (define_insn "mulsidi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
 	(mult:DI (sign_extend:DI
-		  (match_operand:SI 1 "nonimmediate_operand" "g"))
+		  (match_operand:SI 1 "nonimmediate_operand" "nrmT"))
 		 (sign_extend:DI
-		  (match_operand:SI 2 "nonimmediate_operand" "g"))))]
+		  (match_operand:SI 2 "nonimmediate_operand" "nrmT"))))]
   ""
   "emul %1,%2,$0,%0")
 
@@ -459,9 +464,9 @@
   [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
 	(plus:DI
 	 (mult:DI (sign_extend:DI
-		   (match_operand:SI 1 "nonimmediate_operand" "g"))
+		   (match_operand:SI 1 "nonimmediate_operand" "nrmT"))
 		  (sign_extend:DI
-		   (match_operand:SI 2 "nonimmediate_operand" "g")))
+		   (match_operand:SI 2 "nonimmediate_operand" "nrmT")))
 	 (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "g"))))]
   ""
   "emul %1,%2,%3,%0")
@@ -471,9 +476,9 @@
   [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
 	(plus:DI
 	 (mult:DI (sign_extend:DI
-		   (match_operand:SI 1 "nonimmediate_operand" "g"))
+		   (match_operand:SI 1 "nonimmediate_operand" "nrmT"))
 		  (sign_extend:DI
-		   (match_operand:SI 2 "nonimmediate_operand" "g")))
+		   (match_operand:SI 2 "nonimmediate_operand" "nrmT")))
 	 (match_operand:DI 3 "immediate_operand" "F")))]
   "GET_CODE (operands[3]) == CONST_DOUBLE
     && CONST_DOUBLE_HIGH (operands[3]) == (CONST_DOUBLE_LOW (operands[3]) >> 31)"
@@ -497,8 +502,8 @@
 
 (define_insn "div<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
-	(div:VAXint (match_operand:VAXint 1 "general_operand" "0,g")
-		   (match_operand:VAXint 2 "general_operand" "g,g")))]
+	(div:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
+		   (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))]
   ""
   "@
    div<VAXint:isfx>2 %2,%0
@@ -527,7 +532,7 @@
   rtx op1 = operands[1];
 
   /* If there is a constant argument, complement that one.  */
-  if (CONST_INT_P (operands[2]) && !CONST_INT_P (op1))
+  if (CONST_INT_P (operands[2]) && ! CONST_INT_P (op1))
     {
       operands[1] = operands[2];
       operands[2] = op1;
@@ -542,8 +547,8 @@
 
 (define_insn "*and<mode>"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
-	(and:VAXint (not:VAXint (match_operand:VAXint 1 "general_operand" "g,g"))
-		    (match_operand:VAXint 2 "general_operand" "0,g")))]
+	(and:VAXint (not:VAXint (match_operand:VAXint 1 "general_operand" "nrmT,nrmT"))
+		    (match_operand:VAXint 2 "general_operand" "0,nrmT")))]
   ""
   "@
    bic<VAXint:isfx>2 %1,%0
@@ -556,7 +561,7 @@
 
 (define_insn "*and<mode>_const_int"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
-	(and:VAXint (match_operand:VAXint 1 "general_operand" "0,g")
+	(and:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
 		   (match_operand:VAXint 2 "const_int_operand" "n,n")))]
   ""
   "@
@@ -568,8 +573,8 @@
 
 (define_insn "ior<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
-	(ior:VAXint (match_operand:VAXint 1 "general_operand" "0,g,g")
-		   (match_operand:VAXint 2 "general_operand" "g,0,g")))]
+	(ior:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
+		   (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
   ""
   "@
    bis<VAXint:isfx>2 %2,%0
@@ -580,8 +585,8 @@
 
 (define_insn "xor<mode>3"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
-	(xor:VAXint (match_operand:VAXint 1 "general_operand" "0,g,g")
-		   (match_operand:VAXint 2 "general_operand" "g,0,g")))]
+	(xor:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
+		   (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
   ""
   "@
    xor<VAXint:isfx>2 %2,%0
@@ -597,13 +602,13 @@
 
 (define_insn "neg<mode>2"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
-	(neg:VAXint (match_operand:VAXint 1 "general_operand" "g")))]
+	(neg:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))]
   ""
   "mneg<VAXint:isfx> %1,%0")
 
 (define_insn "one_cmpl<mode>2"
   [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
-	(not:VAXint (match_operand:VAXint 1 "general_operand" "g")))]
+	(not:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))]
   ""
   "mcom<VAXint:isfx> %1,%0")
 
@@ -620,43 +625,50 @@
   ""
   "
 {
-  if (!CONST_INT_P (operands[2]))
+  if (! CONST_INT_P(operands[2]))
     operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
 }")
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
+	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
 		     (match_operand:QI 2 "const_int_operand" "n")))]
   ""
   "ashl $%n2,%1,%0")
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
+	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
 		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))]
   ""
   "ashl %2,%1,%0")
 
 (define_insn "ashlsi3"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(ashift:SI (match_operand:SI 1 "general_operand" "g")
+	(ashift:SI (match_operand:SI 1 "general_operand" "nrmT")
 		   (match_operand:QI 2 "general_operand" "g")))]
   ""
   "*
 {
   if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1]))
     return \"addl2 %0,%0\";
-  if (REG_P (operands[1])
-      && CONST_INT_P (operands[2]))
+  if (REG_P (operands[1]) && CONST_INT_P (operands[2]))
     {
       int i = INTVAL (operands[2]);
       if (i == 1)
 	return \"addl3 %1,%1,%0\";
-      if (i == 2)
-	return \"moval 0[%1],%0\";
-      if (i == 3)
-	return \"movad 0[%1],%0\";
+      if (i == 2 && !optimize_size)
+	{
+	  if (push_operand (operands[0], SImode))
+	    return \"pushal 0[%1]\";
+	  return \"moval 0[%1],%0\";
+	}
+      if (i == 3 && !optimize_size)
+	{
+	  if (push_operand (operands[0], SImode))
+	    return \"pushaq 0[%1]\";
+	  return \"movaq 0[%1],%0\";
+	}
     }
   return \"ashl %2,%1,%0\";
 }")
@@ -695,7 +707,7 @@
   [(set (match_dup 3)
 	(minus:QI (const_int 32)
 		  (match_dup 4)))
-   (set (match_operand:SI 0 "general_operand" "=g")
+   (set (match_operand:SI 0 "nonimmediate_operand" "=g")
 	(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
 			 (match_dup 3)
 			 (match_operand:SI 2 "register_operand" "g")))]
@@ -714,27 +726,27 @@
   ""
   "
 {
-  if (!CONST_INT_P (operands[2]))
+  if (! CONST_INT_P (operands[2]))
     operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
 }")
 
 (define_insn "rotlsi3"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(rotate:SI (match_operand:SI 1 "general_operand" "g")
+	(rotate:SI (match_operand:SI 1 "general_operand" "nrmT")
 		   (match_operand:QI 2 "general_operand" "g")))]
   ""
   "rotl %2,%1,%0")
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(rotatert:SI (match_operand:SI 1 "general_operand" "g")
+	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
 		     (match_operand:QI 2 "const_int_operand" "n")))]
   ""
   "rotl %R2,%1,%0")
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(rotatert:SI (match_operand:SI 1 "general_operand" "g")
+	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
 		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))]
   ""
   "rotl %2,%1,%0")
@@ -761,7 +773,7 @@
    "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
    && INTVAL (operands[2]) % INTVAL (operands[1]) == 0
    && (REG_P (operands[0])
-       || !mode_dependent_address_p (XEXP (operands[0], 0)))"
+       || ! mode_dependent_address_p (XEXP (operands[0], 0)))"
   "*
 {
   if (REG_P (operands[0]))
@@ -789,7 +801,7 @@
   "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
    && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
    && (REG_P (operands[1])
-       || !mode_dependent_address_p (XEXP (operands[1], 0)))"
+       || ! mode_dependent_address_p (XEXP (operands[1], 0)))"
   "*
 {
   if (REG_P (operands[1]))
@@ -816,7 +828,7 @@
   "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
    && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
    && (REG_P (operands[1])
-       || !mode_dependent_address_p (XEXP (operands[1], 0)))"
+       || ! mode_dependent_address_p (XEXP (operands[1], 0)))"
   "*
 {
   if (REG_P (operands[1]))
@@ -842,8 +854,8 @@
 	(compare
 	 (sign_extract:SI (match_operand:SI 0 "register_operand" "r")
 			  (match_operand:QI 1 "general_operand" "g")
-			  (match_operand:SI 2 "general_operand" "g"))
-	 (match_operand:SI 3 "general_operand" "g")))]
+			  (match_operand:SI 2 "general_operand" "nrmT"))
+	 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "cmpv %2,%1,%0,%3")
 
@@ -852,8 +864,8 @@
 	(compare
 	 (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
 			  (match_operand:QI 1 "general_operand" "g")
-			  (match_operand:SI 2 "general_operand" "g"))
-	 (match_operand:SI 3 "general_operand" "g")))]
+			  (match_operand:SI 2 "general_operand" "nrmT"))
+	 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "cmpzv %2,%1,%0,%3")
 
@@ -866,13 +878,12 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
 	(sign_extract:SI (match_operand:SI 1 "register_operand" "ro")
 			 (match_operand:QI 2 "general_operand" "g")
-			 (match_operand:SI 3 "general_operand" "g")))]
+			 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "*
 {
-  if (!CONST_INT_P (operands[3])
-      || !CONST_INT_P (operands[2])
-      || !REG_P (operands[0])
+  if (! CONST_INT_P (operands[3]) || ! CONST_INT_P (operands[2])
+      || ! REG_P (operands[0])
       || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16))
     return \"extv %3,%2,%1,%0\";
   if (INTVAL (operands[2]) == 8)
@@ -884,13 +895,12 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
 	(zero_extract:SI (match_operand:SI 1 "register_operand" "ro")
 			 (match_operand:QI 2 "general_operand" "g")
-			 (match_operand:SI 3 "general_operand" "g")))]
+			 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "*
 {
-  if (!CONST_INT_P (operands[3])
-      || !CONST_INT_P (operands[2])
-      || !REG_P (operands[0]))
+  if (! CONST_INT_P (operands[3]) || ! CONST_INT_P (operands[2])
+      || ! REG_P (operands[0]))
     return \"extzv %3,%2,%1,%0\";
   if (INTVAL (operands[2]) == 8)
     return \"rotl %R3,%1,%0\;movzbl %0,%0\";
@@ -912,8 +922,8 @@
 	(compare
 	 (sign_extract:SI (match_operand:QI 0 "memory_operand" "m")
 			  (match_operand:QI 1 "general_operand" "g")
-			  (match_operand:SI 2 "general_operand" "g"))
-	 (match_operand:SI 3 "general_operand" "g")))]
+			  (match_operand:SI 2 "general_operand" "nrmT"))
+	 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "cmpv %2,%1,%0,%3")
 
@@ -922,8 +932,8 @@
 	(compare
 	 (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm")
 			  (match_operand:QI 1 "general_operand" "g")
-			  (match_operand:SI 2 "general_operand" "g"))
-	 (match_operand:SI 3 "general_operand" "g")))]
+			  (match_operand:SI 2 "general_operand" "nrmT"))
+	 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "cmpzv %2,%1,%0,%3")
 
@@ -931,12 +941,11 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
 	(sign_extract:SI (match_operand:QI 1 "memory_operand" "m")
 			 (match_operand:QI 2 "general_operand" "g")
-			 (match_operand:SI 3 "general_operand" "g")))]
+			 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "*
 {
-  if (!REG_P (operands[0])
-      || !CONST_INT_P (operands[2])
+  if (!REG_P (operands[0]) || !CONST_INT_P (operands[2])
       || !CONST_INT_P (operands[3])
       || (INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16)
       || INTVAL (operands[2]) + INTVAL (operands[3]) > 32
@@ -961,12 +970,11 @@
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
 	(zero_extract:SI (match_operand:QI 1 "memory_operand" "m")
 			 (match_operand:QI 2 "general_operand" "g")
-			 (match_operand:SI 3 "general_operand" "g")))]
+			 (match_operand:SI 3 "general_operand" "nrmT")))]
   ""
   "*
 {
-  if (!REG_P (operands[0])
-      || !CONST_INT_P (operands[2])
+  if (!REG_P (operands[0]) || !CONST_INT_P (operands[2])
       || !CONST_INT_P (operands[3])
       || INTVAL (operands[2]) + INTVAL (operands[3]) > 32
       || side_effects_p (operands[1])
@@ -977,6 +985,28 @@
     return \"rotl %R3,%1,%0\;movzbl %0,%0\";
   if (INTVAL (operands[2]) == 16)
     return \"rotl %R3,%1,%0\;movzwl %0,%0\";
+  if (MEM_P (operands[1])
+      && GET_CODE (XEXP (operands[1], 0)) == PLUS
+      && REG_P (XEXP (XEXP (operands[1], 0), 0))
+      && CONST_INT_P (XEXP (XEXP (operands[1], 0), 1))
+      && CONST_INT_P (operands[2])
+      && CONST_INT_P (operands[3]))
+    {
+      HOST_WIDE_INT o = INTVAL (XEXP (XEXP (operands[1], 0), 1));
+      HOST_WIDE_INT l = INTVAL (operands[2]);
+      HOST_WIDE_INT v = INTVAL (operands[3]);
+      if ((o & 3) && (o & 3) * 8 + v + l <= 32)
+	{
+	  rtx tmp;
+	  tmp = XEXP (XEXP (operands[1], 0), 0);
+	  if (o & ~3)
+	    tmp = gen_rtx_PLUS (SImode, tmp, GEN_INT (o & ~3));
+	  operands[1] = gen_rtx_MEM (QImode, tmp);
+	  operands[3] = GEN_INT (v + (o & 3) * 8);
+	}
+      if (optimize_size)
+	return \"extzv %3,%2,%1,%0\";
+    }
   return \"rotl %R3,%1,%0\;bicl2 %M2,%0\";
 }")
 
@@ -991,16 +1021,39 @@
 (define_insn ""
   [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+g")
 			 (match_operand:QI 1 "general_operand" "g")
-			 (match_operand:SI 2 "general_operand" "g"))
-	(match_operand:SI 3 "general_operand" "g"))]
+			 (match_operand:SI 2 "general_operand" "nrmT"))
+	(match_operand:SI 3 "general_operand" "nrmT"))]
   ""
-  "insv %3,%2,%1,%0")
+  "*
+{
+  if (MEM_P (operands[0])
+      && GET_CODE (XEXP (operands[0], 0)) == PLUS
+      && REG_P (XEXP (XEXP (operands[0], 0), 0))
+      && CONST_INT_P (XEXP (XEXP (operands[0], 0), 1))
+      && CONST_INT_P (operands[1])
+      && CONST_INT_P (operands[2]))
+    {
+      HOST_WIDE_INT o = INTVAL (XEXP (XEXP (operands[0], 0), 1));
+      HOST_WIDE_INT v = INTVAL (operands[2]);
+      HOST_WIDE_INT l = INTVAL (operands[1]);
+      if ((o & 3) && (o & 3) * 8 + v + l <= 32)
+	{
+	  rtx tmp;
+	  tmp = XEXP (XEXP (operands[0], 0), 0);
+	  if (o & ~3)
+	    tmp = gen_rtx_PLUS (SImode, tmp, GEN_INT (o & ~3));
+	  operands[0] = gen_rtx_MEM (QImode, tmp);
+	  operands[2] = GEN_INT (v + (o & 3) * 8);
+	}
+    }
+  return \"insv %3,%2,%1,%0\";
+}")
 
 (define_insn ""
   [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
 			 (match_operand:QI 1 "general_operand" "g")
-			 (match_operand:SI 2 "general_operand" "g"))
-	(match_operand:SI 3 "general_operand" "g"))]
+			 (match_operand:SI 2 "general_operand" "nrmT"))
+	(match_operand:SI 3 "general_operand" "nrmT"))]
   ""
   "insv %3,%2,%1,%0")
 
@@ -1012,21 +1065,45 @@
   "jbr %l0")
 
 ;; Conditional jumps
-(define_code_iterator any_cond [eq ne gt lt gtu ltu ge le geu leu])
+
+(define_expand "cbranch<mode>4"
+  [(set (cc0)
+        (compare (match_operand:VAXint 1 "nonimmediate_operand" "")
+                 (match_operand:VAXint 2 "general_operand" "")))
+   (set (pc)
+        (if_then_else
+              (match_operator 0 "ordered_comparison_operator" [(cc0)
+                                                               (const_int 0)])
+              (label_ref (match_operand 3 "" ""))
+              (pc)))]
+ "")
 
-(define_insn "b<code>"
+(define_expand "cbranch<mode>4"
+  [(set (cc0)
+        (compare (match_operand:VAXfp 1 "general_operand" "")
+                 (match_operand:VAXfp 2 "general_operand" "")))
+   (set (pc)
+        (if_then_else
+              (match_operator 0 "ordered_comparison_operator" [(cc0)
+                                                               (const_int 0)])
+              (label_ref (match_operand 3 "" ""))
+              (pc)))]
+ "")
+
+(define_insn "*branch"
   [(set (pc)
-	(if_then_else (any_cond (cc0)
-				(const_int 0))
-		      (label_ref (match_operand 0 "" ""))
+	(if_then_else (match_operator 0 "ordered_comparison_operator"
+				      [(cc0)
+				       (const_int 0)])
+		      (label_ref (match_operand 1 "" ""))
 		      (pc)))]
   ""
-  "* return vax_output_conditional_branch (<CODE>);")
+  "j%c0 %l1")
 
 ;; Recognize reversed jumps.
-(define_insn ""
+(define_insn "*branch_reversed"
   [(set (pc)
-	(if_then_else (match_operator 0 "comparison_operator"
+	(if_then_else (match_operator 0 "ordered_comparison_operator"
 				      [(cc0)
 				       (const_int 0)])
 		      (pc)
@@ -1044,7 +1121,7 @@
 	(if_then_else
 	 (ne (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g")
 			      (const_int 1)
-			      (match_operand:SI 1 "general_operand" "I,g"))
+			      (match_operand:SI 1 "general_operand" "I,nrmT"))
 	     (const_int 0))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))]
@@ -1058,7 +1135,7 @@
 	(if_then_else
 	 (eq (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,g")
 			      (const_int 1)
-			      (match_operand:SI 1 "general_operand" "I,g"))
+			      (match_operand:SI 1 "general_operand" "I,nrmT"))
 	     (const_int 0))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))]
@@ -1072,7 +1149,7 @@
 	(if_then_else
 	 (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r")
 			      (const_int 1)
-			      (match_operand:SI 1 "general_operand" "I,g"))
+			      (match_operand:SI 1 "general_operand" "I,nrmT"))
 	     (const_int 0))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))]
@@ -1086,7 +1163,7 @@
 	(if_then_else
 	 (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r")
 			      (const_int 1)
-			      (match_operand:SI 1 "general_operand" "I,g"))
+			      (match_operand:SI 1 "general_operand" "I,nrmT"))
 	     (const_int 0))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))]
@@ -1135,7 +1212,7 @@
 	(if_then_else
 	 (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
 		      (const_int 1))
-	     (match_operand:SI 1 "general_operand" "g"))
+	     (match_operand:SI 1 "general_operand" "nrmT"))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))
    (set (match_dup 0)
@@ -1148,7 +1225,7 @@
   [(set (pc)
 	(if_then_else
 	 (lt (match_operand:SI 0 "nonimmediate_operand" "+g")
-	     (match_operand:SI 1 "general_operand" "g"))
+	     (match_operand:SI 1 "general_operand" "nrmT"))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))
    (set (match_dup 0)
@@ -1162,7 +1239,7 @@
 	(if_then_else
 	 (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
 		      (const_int 1))
-	     (match_operand:SI 1 "general_operand" "g"))
+	     (match_operand:SI 1 "general_operand" "nrmT"))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))
    (set (match_dup 0)
@@ -1175,7 +1252,7 @@
   [(set (pc)
 	(if_then_else
 	 (le (match_operand:SI 0 "nonimmediate_operand" "+g")
-	     (match_operand:SI 1 "general_operand" "g"))
+	     (match_operand:SI 1 "general_operand" "nrmT"))
 	 (label_ref (match_operand 2 "" ""))
 	 (pc)))
    (set (match_dup 0)
@@ -1278,7 +1355,7 @@
 (define_expand "call_value"
   [(set (match_operand 0 "" "")
       (call (match_operand:QI 1 "memory_operand" "")
-            (match_operand:SI 2 "const_int_operand" "")))]
+	    (match_operand:SI 2 "const_int_operand" "")))]
   ""
   "
 {
@@ -1299,9 +1376,9 @@
 
 (define_expand "untyped_call"
   [(parallel [(call (match_operand 0 "" "")
-                  (const_int 0))
-            (match_operand 1 "" "")
-            (match_operand 2 "" "")])]
+	      (const_int 0))
+	      (match_operand 1 "" "")
+	      (match_operand 2 "" "")])]
   ""
   "
 {
@@ -1386,6 +1463,8 @@
    (match_operand 4 "" "")]
   ""
 {
+  rtx test;
+
   /* i = index - minimum_bound;
      But only if the lower bound is not already zero.  */
   if (operands[1] != const0_rtx)
@@ -1397,9 +1476,9 @@
       operands[0] = index;
     }
 
-  /* if (i > (maximum_bound - minimum_bound + 1) goto default;  */
-  emit_insn (gen_cmpsi (operands[0], operands[2]));
-  emit_jump_insn (gen_bgtu (operands[4]));
+  /* if (i > (maximum_bound - minimum_bound + 1)) goto default;  */
+  test = gen_rtx_fmt_ee (GTU, VOIDmode, operands[0], operands[2]);
+  emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2], operands[4]));
 
   /* casesi (i, 0, table);  */
   emit_jump_insn (gen_casesi1 (operands[0], operands[2], operands[3]));
@@ -1413,13 +1492,37 @@
   [(match_operand:SI 1 "const_int_operand" "n")
    (set (pc)
 	(plus:SI (sign_extend:SI
-		  (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "general_operand" "g")
+		  (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "general_operand" "nrmT")
 					    (const_int 2))
 			  (pc))))
 		 (label_ref:SI (match_operand 2 "" ""))))]
   ""
   "casel %0,$0,%1")
 
+(define_insn "pushextsym"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(match_operand:SI 1 "external_symbolic_operand" "i"))]
+  ""
+  "pushab %a1")
+
+(define_insn "movextsym"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+	(match_operand:SI 1 "external_symbolic_operand" "i"))]
+  ""
+  "movab %a1,%0")
+
+(define_insn "pushlclsym"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(match_operand:SI 1 "local_symbolic_operand" "i"))]
+  ""
+  "pushab %a1")
+
+(define_insn "movlclsym"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
+	(match_operand:SI 1 "local_symbolic_operand" "i"))]
+  ""
+  "movab %a1,%0")
+
 ;;- load or push effective address
 ;; These come after the move and add/sub patterns
 ;; because we don't want pushl $1 turned into pushad 1.
@@ -1428,77 +1531,29 @@
 ;; It does not work to use constraints to distinguish pushes from moves,
 ;; because < matches any autodecrement, not just a push.
 
-(define_insn ""
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:QI 1 "address_operand" "p"))]
-  ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushab %a1\";
-  else
-    return \"movab %a1,%0\";
-}")
-
-(define_insn ""
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:HI 1 "address_operand" "p"))]
+(define_insn "pushaddr<mode>"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(match_operand:VAXintQHSD 1 "address_operand" "p"))]
   ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushaw %a1\";
-  else
-    return \"movaw %a1,%0\";
-}")
+  "pusha<VAXintQHSD:isfx> %a1")
 
-(define_insn ""
+(define_insn "movaddr<mode>"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:SI 1 "address_operand" "p"))]
+	(match_operand:VAXintQHSD 1 "address_operand" "p"))]
   ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushal %a1\";
-  else
-    return \"moval %a1,%0\";
-}")
+  "mova<VAXintQHSD:isfx> %a1,%0")
 
-(define_insn ""
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:DI 1 "address_operand" "p"))]
-  ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushaq %a1\";
-  else
-    return \"movaq %a1,%0\";
-}")
-
-(define_insn ""
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:SF 1 "address_operand" "p"))]
+(define_insn "pushaddr<mode>"
+  [(set (match_operand:SI 0 "push_operand" "=g")
+	(match_operand:VAXfp 1 "address_operand" "p"))]
   ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushaf %a1\";
-  else
-    return \"movaf %a1,%0\";
-}")
+  "pusha<VAXfp:fsfx> %a1")
 
-(define_insn ""
+(define_insn "movaddr<mode>"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-	(match_operand:DF 1 "address_operand" "p"))]
+	(match_operand:VAXfp 1 "address_operand" "p"))]
   ""
-  "*
-{
-  if (push_operand (operands[0], SImode))
-    return \"pushad %a1\";
-  else
-    return \"movad %a1,%0\";
-}")
+  "mova<VAXfp:fsfx> %a1,%0")
 
 ;; These used to be peepholes, but it is more straightforward to do them
 ;; as single insns.  However, we must force the output to be a register
@@ -1515,7 +1570,7 @@
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
-	(and:SI (ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
+	(and:SI (ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
 			     (match_operand:QI 2 "const_int_operand" "n"))
 		(match_operand:SI 3 "const_int_operand" "n")))]
   "(INTVAL (operands[3]) & ~((1 << (32 - INTVAL (operands[2]))) - 1)) == 0"
@@ -1537,7 +1592,7 @@
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
-	(and:SI (ashift:SI (match_operand:SI 1 "general_operand" "g")
+	(and:SI (ashift:SI (match_operand:SI 1 "general_operand" "nrmT")
 			   (match_operand:QI 2 "const_int_operand" "n"))
 		(match_operand:SI 3 "const_int_operand" "n")))]
   ""
@@ -1553,3 +1608,29 @@
   [(unspec_volatile [(const_int 0)] VUNSPEC_SYNC_ISTREAM)]
   ""
   "movpsl -(%|sp)\;pushal 1(%|pc)\;rei")
+
+(define_expand "nonlocal_goto"
+  [(use (match_operand 0 "general_operand" ""))
+   (use (match_operand 1 "general_operand" ""))
+   (use (match_operand 2 "general_operand" ""))
+   (use (match_operand 3 "general_operand" ""))]
+  ""
+{
+  rtx lab = operands[1];
+  rtx stack = operands[2];
+  rtx fp = operands[3];
+
+  emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+  emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+  emit_move_insn (hard_frame_pointer_rtx, fp);
+  emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
+
+  emit_use (hard_frame_pointer_rtx);
+  emit_use (stack_pointer_rtx);
+
+  /* We'll convert this to direct jump via a peephole optimization.  */
+  emit_indirect_jump (copy_to_reg (lab));
+  emit_barrier ();
+  DONE;
+})