;; Machine description for GNU compiler, VAX Version
;; Copyright (C) 1987-2021 Free Software Foundation, Inc.

;; This file is part of GCC.

;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.

;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3.  If not see
;; <http://www.gnu.org/licenses/>.


;;- Instruction patterns.  When multiple patterns apply,
;;- the first one in the file is chosen.
;;-
;;- See file "rtl.def" for documentation on define_insn, match_*, et al.

;; UNSPEC_VOLATILE usage:

(define_c_enum "unspecv" [
  VUNSPEC_BLOCKAGE 	    ; 'blockage' insn to prevent scheduling across an
			    ; insn in the code.
  VUNSPEC_SYNC_ISTREAM      ; sequence of insns to sync the I-stream
  VUNSPEC_PEM		    ; 'procedure_entry_mask' insn.
])

(define_constants
  [(VAX_AP_REGNUM 12)	    ; Register 12 contains the argument pointer
   (VAX_FP_REGNUM 13)	    ; Register 13 contains the frame pointer
   (VAX_SP_REGNUM 14)	    ; Register 14 contains the stack pointer
   (VAX_PC_REGNUM 15)	    ; Register 15 contains the program counter
   (VAX_PSL_REGNUM 16)	    ; Register 16 contains the processor status
			    ; and condition codes in particular
  ]
)

;; 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_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])
(define_mode_attr  fsfx [(SF "f") (DF "%#")])

;; Some output patterns want integer immediates with a prefix...
(define_mode_attr  iprefx [(QI "B") (HI "H") (SI "N")])

(define_mode_iterator VAXcc [CC CCN CCNZ CCZ])
(define_mode_iterator VAXccnz [CCN CCNZ CCZ])

(define_code_iterator any_extract [sign_extract zero_extract])

;;
(include "constraints.md")
(include "predicates.md")

;; Make instructions that set the N, N+Z, and Z condition codes respectively.
(define_subst "subst_<mode>"
  [(set (match_operand 0 "")
	(match_operand 1 ""))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  ""
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz (match_dup 1)
			 (const_int 0)))
   (set (match_dup 0)
	(match_dup 1))])

(define_subst "subst_f<VAXccnz:mode>"
  [(set (match_operand:VAXfp 0 "")
	(match_operand:VAXfp 1 ""))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  ""
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz (match_dup 1)
			 (const_double_zero:VAXfp)))
   (set (match_dup 0)
	(match_dup 1))])

;; Select all from the attributes below that apply to a given insn that
;; has a clobber on CC for the comparison elimination pass to use it in
;; place of a subsequent comparison instruction matching the mode used
;; by a comparison operator in branch.
;;
;; For example a branch doing `eq' in SImode will use `*cmpsi_ccz', so
;; to eliminate it a `*movsi_ccz', etc. pattern will be required via the
;; `ccz' substitution.  Analogously for the other CC modes.
;;
;; The general `cc' mode, which sets all of the C, N, V and Z condition
;; codes, has to be handled specially as it makes no sense for the usual
;; comparison against zero, so no substitution has been defined for it.
(define_subst_attr "ccn" "subst_ccn" "" "_ccn")
(define_subst_attr "ccnz" "subst_ccnz" "" "_ccnz")
(define_subst_attr "ccz" "subst_ccz" "" "_ccz")
(define_subst_attr "fccn" "subst_fccn" "" "_ccn")
(define_subst_attr "fccnz" "subst_fccnz" "" "_ccnz")
(define_subst_attr "fccz" "subst_fccz" "" "_ccz")

(define_insn "*cmp<VAXint:mode>_<VAXcc:mode>"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc (match_operand:VAXint 0 "general_operand" "nrmT,nrmT")
		       (match_operand:VAXint 1 "general_operand" "I,nrmT")))]
  "reload_completed"
  "@
   tst<VAXint:isfx> %0
   cmp<VAXint:isfx> %0,%1")

;; We don't have a CMPQ instruction, but we can set the N and Z condition
;; codes with MOVQ, and also this comparison can be folded into a preceding
;; operation by the post-reload comparison elimination pass.
(define_insn "*cmpdi_<VAXccnz:mode>"
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz (match_operand:DI 0 "general_operand" "r,nmT")
			 (match_operand:DI 1 "const_zero_operand" "I,I")))
   (clobber (match_scratch:DI 2 "=X,r"))]
  "reload_completed"
  "@
   movq %0,%0
   movq %0,%2")

(define_insn "*cmp<VAXfp:mode>_<VAXccnz:mode>"
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz (match_operand:VAXfp 0 "general_operand" "gF,gF")
			 (match_operand:VAXfp 1 "general_operand" "G,gF")))]
  "reload_completed"
  "@
   tst<VAXfp:fsfx> %0
   cmp<VAXfp:fsfx> %0,%1")

(define_insn "*bit<VAXint:mode>_<VAXccnz:mode>"
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz
	  (and:VAXint (match_operand:VAXint 0 "general_operand" "nrmT")
		      (match_operand:VAXint 1 "general_operand" "nrmT"))
	  (const_int 0)))]
  "reload_completed"
  "bit<VAXint:isfx> %0,%1")

;; The VAX has no sCOND insns.  It does have add/subtract with carry
;; which could be used to implement the sltu and sgeu patterns.  However,
;; to do this properly requires a complete rewrite of the compare insns
;; to keep them together with the sltu/sgeu insns until after the
;; reload pass is complete.  The previous implementation didn't do this
;; and has been deleted.


(define_insn_and_split "mov<mode>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(match_operand:VAXfp 1 "general_operand" "G,gF"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*mov<mode><fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(match_operand:VAXfp 1 "general_operand" "G,gF"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   clr<VAXfp:fsfx> %0
   mov<VAXfp:fsfx> %1,%0")

;; Some VAXen don't support this instruction.
;;(define_insn_and_split "movti"
;;  [(set (match_operand:TI 0 "nonimmediate_operand" "=g")
;;	(match_operand:TI 1 "general_operand" "g"))]
;;  ""
;;  "#"
;;  "reload_completed"
;;  [(parallel
;;     [(set (match_dup 0)
;;	   (match_dup 1))
;;      (clobber (reg:CC VAX_PSL_REGNUM))])]
;;  "")
;;
;;(define_insn "*movti<ccn><ccnz><ccz>"
;;  [(set (match_operand:TI 0 "nonimmediate_operand" "=g")
;;	(match_operand:TI 1 "general_operand" "g"))
;;   (clobber (reg:CC VAX_PSL_REGNUM))]
;;  "reload_completed"
;;  "movo %1,%0")

(define_insn_and_split "movdi"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(match_operand:DI 1 "general_operand" "g"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

;; In some cases `vax_output_int_move' splits a `DImode' move into a pair
;; of `SImode' moves, in which case the flags aren't usefully set.  Have
;; separate patterns then, for the cases where the move may and may not be
;; split each.  We use the outer condition only so in some cases we will
;; fail to notice the move does not actually get split, but this is OK.
(define_insn "*movdi_maybe_split"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(match_operand:DI 1 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed && vax_maybe_split_dimode_move (operands)"
  "* return vax_output_int_move (insn, operands, DImode);")

(define_insn "*movdi_unsplit<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(match_operand:DI 1 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed && !vax_maybe_split_dimode_move (operands)"
  "* 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
;; takes 2 bytes and 3 cycles.  mov from constant to register takes 2 cycles
;; if the constant is smaller than 4 bytes, 3 cycles for a longword
;; constant.  movz, mneg, and mcom are as fast as mov, so movzwl is faster
;; than movl for positive constants that fit in 16 bits but not 6 bits.  cvt
;; instructions take 4 cycles.  inc takes 3 cycles.  The machine description
;; is willing to trade 1 byte for 1 cycle (clrl instead of movl $0; cvtwl
;; instead of movl).

;; Cycle counts for other models may vary (on a VAX 750 they are similar,
;; but on a VAX 9000 most move and add instructions with one constant
;; operand take 1 cycle).

;;  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_and_split "movsi_2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:SI 1 "nonsymbolic_operand" "nrmT"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movsi_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:SI 1 "nonsymbolic_operand" "nrmT"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "* return vax_output_int_move (insn, operands, SImode);")

(define_insn_and_split "mov<mode>"
  [(set (match_operand:VAXintQH 0 "nonimmediate_operand" "=g")
	(match_operand:VAXintQH 1 "general_operand" "g"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*mov<mode><ccn><ccnz><ccz>"
  [(set (match_operand:VAXintQH 0 "nonimmediate_operand" "=g")
	(match_operand:VAXintQH 1 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "* return vax_output_int_move (insn, operands, <MODE>mode);")

(define_insn_and_split "movstricthi"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
	(match_operand:HI 1 "general_operand" "g"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (strict_low_part (match_dup 0))
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movstricthi<ccn><ccnz><ccz>"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
	(match_operand:HI 1 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  if (CONST_INT_P (operands[1]))
    {
      int i = INTVAL (operands[1]);
      if (i == 0)
	return \"clrw %0\";
      else if ((unsigned int)i < 64)
	return \"movw %1,%0\";
      else if ((unsigned int)~i < 64)
	return \"mcomw %H1,%0\";
      else if ((unsigned int)i < 256)
	return \"movzbw %1,%0\";
    }
  return \"movw %1,%0\";
}")

(define_insn_and_split "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
	(match_operand:QI 1 "general_operand" "g"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (strict_low_part (match_dup 0))
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movstrictqi<ccn><ccnz><ccz>"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
	(match_operand:QI 1 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  if (CONST_INT_P (operands[1]))
    {
      int i = INTVAL (operands[1]);
      if (i == 0)
	return \"clrb %0\";
      else if ((unsigned int)~i < 64)
	return \"mcomb %B1,%0\";
    }
  return \"movb %1,%0\";
}")

;; This is here to accept 4 arguments and pass the first 3 along
;; to the movmemhi1 pattern that really does the work.
(define_expand "cpymemhi"
  [(set (match_operand:BLK 0 "memory_operand" "")
	(match_operand:BLK 1 "memory_operand" ""))
   (use (match_operand:HI 2 "general_operand" ""))
   (match_operand 3 "" "")]
  ""
  "
{
  emit_insn (gen_movmemhi1 (operands[0], operands[1], operands[2]));
  DONE;
}")

(define_expand "movmemhi"
  [(set (match_operand:BLK 0 "memory_operand" "")
	(match_operand:BLK 1 "memory_operand" ""))
   (use (match_operand:HI 2 "general_operand" ""))
   (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_and_split "movmemhi1"
  [(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))
   (clobber (reg:SI 2))
   (clobber (reg:SI 3))
   (clobber (reg:SI 4))
   (clobber (reg:SI 5))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (use (match_dup 2))
      (clobber (reg:SI 0))
      (clobber (reg:SI 1))
      (clobber (reg:SI 2))
      (clobber (reg:SI 3))
      (clobber (reg:SI 4))
      (clobber (reg:SI 5))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movmemhi1"
  [(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))
   (clobber (reg:SI 2))
   (clobber (reg:SI 3))
   (clobber (reg:SI 4))
   (clobber (reg:SI 5))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "movc3 %2,%1,%0")

;; Extension and truncation insns.

(define_insn_and_split "truncsiqi2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=g")
	(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (truncate:QI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*truncsiqi2<ccn><ccnz><ccz>"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=g")
	(truncate:QI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtlb %1,%0")

(define_insn_and_split "truncsihi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (truncate:HI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*truncsihi2<ccn><ccnz><ccz>"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(truncate:HI (match_operand:SI 1 "nonimmediate_operand" "nrmT")))
      (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtlw %1,%0")

(define_insn_and_split "trunchiqi2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=g")
	(truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (truncate:QI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*trunchiqi2<ccn><ccnz><ccz>"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=g")
	(truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtwb %1,%0")

(define_insn_and_split "extendhisi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extend:SI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extendhisi2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtwl %1,%0")

(define_insn_and_split "extendqihi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extend:HI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extendqihi2<ccn><ccnz><ccz>"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtbw %1,%0")

(define_insn_and_split "extendqisi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extend:SI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extendqisi2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtbl %1,%0")

(define_insn_and_split "extendsfdf2"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=g")
	(float_extend:DF (match_operand:SF 1 "general_operand" "gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (float_extend:DF (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extendsfdf2<fccn><fccnz><fccz>"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=g")
	(float_extend:DF (match_operand:SF 1 "general_operand" "gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvtf%# %1,%0")

(define_insn_and_split "truncdfsf2"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=g")
	(float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (float_truncate:SF (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*truncdfsf2<fccn><fccnz><fccz>"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=g")
	(float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvt%#f %1,%0")

(define_insn_and_split "zero_extendhisi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extend:SI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*zero_extendhisi2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "movzwl %1,%0")

(define_insn_and_split "zero_extendqihi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extend:HI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*zero_extendqihi2<ccn><ccnz><ccz>"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "movzbw %1,%0")

(define_insn_and_split "zero_extendqisi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extend:SI (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*zero_extendqisi2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "movzbl %1,%0")

;; Fix-to-float conversion insns.

(define_insn_and_split "float<VAXint:mode><VAXfp:mode>2"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g")
	(float:VAXfp (match_operand:VAXint 1 "nonimmediate_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (float:VAXfp (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*float<VAXint:mode><VAXfp:mode>2<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g")
	(float:VAXfp (match_operand:VAXint 1 "nonimmediate_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvt<VAXint:isfx><VAXfp:fsfx> %1,%0")

;; Float-to-fix conversion insns.

(define_insn_and_split "fix_trunc<VAXfp:mode><VAXint:mode>2"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(fix:VAXint (match_operand:VAXfp 1 "general_operand" "gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (fix:VAXint (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*fix_trunc<VAXfp:mode><VAXint:mode>2<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(fix:VAXint (match_operand:VAXfp 1 "general_operand" "gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "cvt<VAXfp:fsfx><VAXint:isfx> %1,%0")

(define_expand "fixuns_trunc<VAXfp:mode><VAXint:mode>2"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "")
	(fix:VAXint (match_operand:VAXfp 1 "general_operand")))]
  "")

;;- All kinds of add instructions.

(define_insn_and_split "add<mode>3"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g,g")
	(plus:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF,gF")
		    (match_operand:VAXfp 2 "general_operand" "gF,0,gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:VAXfp (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*add<mode>3<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g,g")
	(plus:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF,gF")
		    (match_operand:VAXfp 2 "general_operand" "gF,0,gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   add<VAXfp:fsfx>2 %2,%0
   add<VAXfp:fsfx>2 %1,%0
   add<VAXfp:fsfx>3 %1,%2,%0")

(define_insn_and_split "add<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(plus:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")
		     (match_operand:VAXint 2 "general_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:VAXint (match_dup 1)
			(match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*add<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(plus:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")
		     (match_operand:VAXint 2 "general_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "* 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_and_split "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"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:DI (match_dup 1)
		    (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*adcdi3<ccn>"
  [(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")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "TARGET_QMATH && reload_completed"
  "* return vax_output_int_add (insn, operands, DImode);")

;; The add-with-carry (adwc) instruction only accepts two operands.
(define_insn_and_split "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" "Fsro,Fs")))]
  "!TARGET_QMATH"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:DI (match_dup 1)
		    (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*adddi3_old<ccn>"
  [(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" "Fsro,Fs")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_QMATH && reload_completed"
  "* return vax_output_int_add (insn, operands, DImode);")

;;- All kinds of subtract instructions.

(define_insn_and_split "sub<mode>3"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(minus:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF")
		     (match_operand:VAXfp 2 "general_operand" "gF,gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (minus:VAXfp (match_dup 1)
			(match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*sub<mode>3<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(minus:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF")
		     (match_operand:VAXfp 2 "general_operand" "gF,gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   sub<VAXfp:fsfx>2 %2,%0
   sub<VAXfp:fsfx>3 %2,%1,%0")

(define_insn_and_split "sub<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(minus:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		      (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (minus:VAXint (match_dup 1)
			 (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*sub<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(minus:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		      (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   sub<VAXint:isfx>2 %2,%0
   sub<VAXint:isfx>3 %2,%1,%0")

(define_insn "*sub<mode>3_cc"
  [(set (reg:CC VAX_PSL_REGNUM)
	(compare:CC (match_operand:VAXint 1 "general_operand" "0,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))
   (set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(minus:VAXint (match_dup 1)
		      (match_dup 2)))]
  "reload_completed"
  "@
   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_and_split "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"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (minus:DI (match_dup 1)
		     (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*sbcdi3<ccn>"
  [(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")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "TARGET_QMATH && reload_completed"
  "* return vax_output_int_subtract (insn, operands, DImode);")

;; The subtract-with-carry (sbwc) instruction only takes two operands.
(define_insn_and_split "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" "Fsor,Fs")))]
  "!TARGET_QMATH"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (minus:DI (match_dup 1)
		     (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*subdi3_old<ccn>"
  [(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" "Fsor,Fs")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_QMATH && reload_completed"
  "* return vax_output_int_subtract (insn, operands, DImode);")

;;- Multiply instructions.

(define_insn_and_split "mul<mode>3"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g,g")
	(mult:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF,gF")
		    (match_operand:VAXfp 2 "general_operand" "gF,0,gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (mult:VAXfp (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*mul<mode>3<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g,g")
	(mult:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF,gF")
		    (match_operand:VAXfp 2 "general_operand" "gF,0,gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   mul<VAXfp:fsfx>2 %2,%0
   mul<VAXfp:fsfx>2 %1,%0
   mul<VAXfp:fsfx>3 %1,%2,%0")

(define_insn_and_split "mul<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(mult:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		     (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (mult:VAXint (match_dup 1)
			(match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*mul<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(mult:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		     (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   mul<VAXint:isfx>2 %2,%0
   mul<VAXint:isfx>2 %1,%0
   mul<VAXint:isfx>3 %1,%2,%0")

(define_insn_and_split "mulsidi3"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(mult:DI
	  (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	  (sign_extend:DI (match_operand:SI 2 "general_operand" "nrmT"))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (mult:DI
	     (sign_extend:DI (match_dup 1))
	     (sign_extend:DI (match_dup 2))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*mulsidi3<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(mult:DI
	  (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	  (sign_extend:DI (match_operand:SI 2 "general_operand" "nrmT"))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "emul %1,%2,$0,%0")

(define_insn_and_split "*maddsidi4"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(plus:DI
	  (mult:DI
	    (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	    (sign_extend:DI (match_operand:SI 2 "general_operand" "nrmT")))
	  (sign_extend:DI (match_operand:SI 3 "general_operand" "g"))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:DI
	     (mult:DI
	       (sign_extend:DI (match_dup 1))
	       (sign_extend:DI (match_dup 2)))
	     (sign_extend:DI (match_dup 3))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*maddsidi4_2<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(plus:DI
	  (mult:DI
	    (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	    (sign_extend:DI (match_operand:SI 2 "general_operand" "nrmT")))
	  (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "g"))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "emul %1,%2,%3,%0")

;; 'F' constraint means type CONST_DOUBLE
(define_insn_and_split "*maddsidi4_const"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(plus:DI
	  (mult:DI
	    (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	    (sign_extend:DI (match_operand:SI 2 "general_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)"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:DI
	     (mult:DI
	       (sign_extend:DI (match_dup 1))
	       (sign_extend:DI (match_dup 2)))
	     (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*maddsidi4_const_2<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(plus:DI
	  (mult:DI
	    (sign_extend:DI (match_operand:SI 1 "general_operand" "nrmT"))
	    (sign_extend:DI (match_operand:SI 2 "general_operand" "nrmT")))
	  (match_operand:DI 3 "immediate_operand" "F")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "GET_CODE (operands[3]) == CONST_DOUBLE
   && CONST_DOUBLE_HIGH (operands[3]) == (CONST_DOUBLE_LOW (operands[3]) >> 31)
   && reload_completed"
  "*
{
  if (CONST_DOUBLE_HIGH (operands[3]))
    operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[3]));
  return \"emul %1,%2,%3,%0\";
}")

;;- Divide instructions.

(define_insn_and_split "div<mode>3"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(div:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF")
		   (match_operand:VAXfp 2 "general_operand" "gF,gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (div:VAXfp (match_dup 1)
		      (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*div<mode>3<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g,g")
	(div:VAXfp (match_operand:VAXfp 1 "general_operand" "0,gF")
		   (match_operand:VAXfp 2 "general_operand" "gF,gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   div<VAXfp:fsfx>2 %2,%0
   div<VAXfp:fsfx>3 %2,%1,%0")

(define_insn_and_split "div<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(div:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (div:VAXint (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*div<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(div:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   div<VAXint:isfx>2 %2,%0
   div<VAXint:isfx>3 %2,%1,%0")

;; This is left out because it is very slow;
;; we are better off programming around the "lack" of this insn.
;;(define_insn_and_split "divmoddisi4"
;;  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
;;	(div:SI (match_operand:DI 1 "general_operand" "g")
;;		(match_operand:SI 2 "general_operand" "g")))
;;   (set (match_operand:SI 3 "nonimmediate_operand" "=g")
;;	(mod:SI (match_dup 1)
;;		(match_dup 2)))]
;;  ""
;;  "#"
;;  "reload_completed"
;;  [(parallel
;;     [(set (match_dup 0)
;;	   (div:SI (match_dup 1)
;;		   (match_dup 2)))
;;      (set (match_dup 3)
;;	   (mod:SI (match_dup 1)
;;		   (match_dup 2)))
;;      (clobber (reg:CC VAX_PSL_REGNUM))])]
;;  "")
;;
;;(define_insn "*divmoddisi4<ccn><ccnz><ccz>"
;;  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
;;	(div:SI (match_operand:DI 1 "general_operand" "g")
;;		(match_operand:SI 2 "general_operand" "g")))
;;   (set (match_operand:SI 3 "nonimmediate_operand" "=g")
;;	(mod:SI (match_dup 1)
;;		(match_dup 2)))
;;   (clobber (reg:CC VAX_PSL_REGNUM))]
;;  "reload_completed"
;;  "ediv %2,%1,%0,%3")

;; Bit-and on the VAX is done with a clear-bits insn.
(define_expand "and<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "")
	(and:VAXint (not:VAXint (match_operand:VAXint 1 "general_operand" ""))
		    (match_operand:VAXint 2 "general_operand" "")))]
  ""
  "
{
  rtx op1 = operands[1];

  /* If there is a constant argument, complement that one.  */
  if (CONST_INT_P (operands[2]) && ! CONST_INT_P (op1))
    {
      operands[1] = operands[2];
      operands[2] = op1;
      op1 = operands[1];
    }

  if (CONST_INT_P (op1))
    operands[1] = GEN_INT (~INTVAL (op1));
  else
    operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1);
}")

(define_insn_and_split "*and<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(and:VAXint (not:VAXint
		      (match_operand:VAXint 1 "general_operand" "nrmT,nrmT"))
		    (match_operand:VAXint 2 "general_operand" "0,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (and:VAXint (not:VAXint
			 (match_dup 1))
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*and<mode>3_2<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(and:VAXint (not:VAXint
		      (match_operand:VAXint 1 "general_operand" "nrmT,nrmT"))
		    (match_operand:VAXint 2 "general_operand" "0,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   bic<VAXint:isfx>2 %1,%0
   bic<VAXint:isfx>3 %1,%2,%0")

;; The following used to be needed because constant propagation can
;; create them starting from the bic insn patterns above.  This is no
;; longer a problem.  However, having these patterns allows optimization
;; opportunities in combine.c.

(define_insn_and_split "*and<mode>3_const_int"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(and:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		    (match_operand:VAXint 2 "const_int_operand" "n,n")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (and:VAXint (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*and<mode>3_2_const_int<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(and:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT")
		    (match_operand:VAXint 2 "const_int_operand" "n,n")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   bic<VAXint:isfx>2 %<VAXint:iprefx>2,%0
   bic<VAXint:isfx>3 %<VAXint:iprefx>2,%1,%0")

;; We have no direct AND operation and consequently the RTL sequence
;; the "and<mode>3" pattern produces does not match the instruction
;; the "*bit<mode>" pattern does for the purpose of the compare
;; elimination pass.  Try to get rid of the extra operation by hand
;; and where the sequence is used to set the condition codes only
;; convert MCOM/BIC => BIT.
(define_peephole2
  [(parallel
     [(set (match_operand:VAXint 0 "register_operand")
	   (not:VAXint (match_operand:VAXint 1 "general_operand")))
      (clobber (reg:CC VAX_PSL_REGNUM))])
   (parallel
     [(set (reg:VAXccnz VAX_PSL_REGNUM)
	   (compare:VAXccnz
	     (and:VAXint (not:VAXint (match_dup 0))
			 (match_operand:VAXint 3 "general_operand"))
	     (const_int 0)))
      (set (match_operand:VAXint 2 "register_operand")
	   (and:VAXint (not:VAXint (match_dup 0))
		       (match_dup 3)))])]
  "peep2_reg_dead_p (2, operands[0]) && peep2_reg_dead_p (2, operands[2])"
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz
	  (and:VAXint (match_dup 1)
		      (match_dup 3))
	  (const_int 0)))]
  "")

;;- Bit set instructions.

(define_insn_and_split "ior<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(ior:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ior:VAXint (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ior<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(ior:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   bis<VAXint:isfx>2 %2,%0
   bis<VAXint:isfx>2 %1,%0
   bis<VAXint:isfx>3 %2,%1,%0")

;;- xor instructions.

(define_insn_and_split "xor<mode>3"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(xor:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (xor:VAXint (match_dup 1)
		       (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*xor<mode>3<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g,g")
	(xor:VAXint (match_operand:VAXint 1 "general_operand" "0,nrmT,nrmT")
		    (match_operand:VAXint 2 "general_operand" "nrmT,0,nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "@
   xor<VAXint:isfx>2 %2,%0
   xor<VAXint:isfx>2 %1,%0
   xor<VAXint:isfx>3 %2,%1,%0")

(define_insn_and_split "neg<mode>2"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g")
	(neg:VAXfp (match_operand:VAXfp 1 "general_operand" "gF")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (neg:VAXfp (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*neg<mode>2<fccn><fccnz><fccz>"
  [(set (match_operand:VAXfp 0 "nonimmediate_operand" "=g")
	(neg:VAXfp (match_operand:VAXfp 1 "general_operand" "gF")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "mneg<VAXfp:fsfx> %1,%0")

(define_insn_and_split "neg<mode>2"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(neg:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (neg:VAXint (match_dup 1)))
	 (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*neg<mode>2<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(neg:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "mneg<VAXint:isfx> %1,%0")

(define_insn "*neg<mode>2_cc"
  [(set (reg:CC VAX_PSL_REGNUM)
	(compare:CC (const_int 0)
		    (neg:VAXint
		      (match_operand:VAXint 1 "general_operand" "0,nrmT"))))
   (set (match_operand:VAXint 0 "nonimmediate_operand" "=g,g")
	(neg:VAXint (match_dup 1)))]
  "reload_completed"
  "mneg<VAXint:isfx> %1,%0")

(define_insn_and_split "one_cmpl<mode>2"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(not:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (not:VAXint (match_dup 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*one_cmpl<mode>2<ccn><ccnz><ccz>"
  [(set (match_operand:VAXint 0 "nonimmediate_operand" "=g")
	(not:VAXint (match_operand:VAXint 1 "general_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "mcom<VAXint:isfx> %1,%0")

;; Arithmetic right shift on the VAX works by negating the shift count,
;; then emitting a right shift with the shift count negated.  This means
;; that all actual shift counts in the RTL will be positive.  This
;; prevents converting shifts to ZERO_EXTRACTs with negative positions,
;; which isn't valid.
(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "general_operand" "=g")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
		     (match_operand:QI 2 "general_operand" "g")))]
  ""
  "
{
  if (! CONST_INT_P(operands[2]))
    operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
}")

(define_insn_and_split "*ashlnegsi3_const_int"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (match_operand:QI 2 "const_int_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ashiftrt:SI (match_dup 1)
			(match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ashlnegsi3_const_int_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (match_operand:QI 2 "const_int_operand" "n")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "ashl $%n2,%1,%0")

(define_insn_and_split "*ashlnegsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ashiftrt:SI (match_dup 1)
			(neg:QI (match_dup 2))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ashlnegsi3_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "ashl %2,%1,%0")

(define_insn_and_split "ashlsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashift:SI (match_operand:SI 1 "general_operand" "nrmT")
		   (match_operand:QI 2 "general_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ashift:SI (match_dup 1)
		      (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ashlsi3<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(ashift:SI (match_operand:SI 1 "general_operand" "nrmT")
		   (match_operand:QI 2 "general_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  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]))
    {
      int i = INTVAL (operands[2]);
      if (i == 1)
	return \"addl3 %1,%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\";
}")

;; Arithmetic right shift on the VAX works by negating the shift count.
(define_expand "ashrdi3"
  [(set (match_operand:DI 0 "general_operand" "=g")
	(ashiftrt:DI (match_operand:DI 1 "general_operand" "g")
		     (match_operand:QI 2 "general_operand" "g")))]
  ""
  "
{
  operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
}")

(define_insn_and_split "ashldi3"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(ashift:DI (match_operand:DI 1 "general_operand" "g")
		   (match_operand:QI 2 "general_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ashift:DI (match_dup 1)
		      (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ashldi3<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(ashift:DI (match_operand:DI 1 "general_operand" "g")
		   (match_operand:QI 2 "general_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "ashq %2,%D1,%0")

(define_insn_and_split "*ashlnegdi3"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(ashiftrt:DI (match_operand:DI 1 "general_operand" "g")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (ashiftrt:DI (match_dup 1)
			(neg:QI (match_dup 2))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*ashlnegdi3_2<ccn><ccnz><ccz>"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=g")
	(ashiftrt:DI (match_operand:DI 1 "general_operand" "g")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "ashq %2,%D1,%0")

;; We used to have expand_shift handle logical right shifts by using extzv,
;; but this make it very difficult to do lshrdi3.  Since the VAX is the
;; only machine with this kludge, it's better to just do this with a
;; define_expand and remove that case from expand_shift.

(define_expand "lshrsi3"
  [(set (match_dup 3)
	(minus:QI (const_int 32)
		  (match_dup 4)))
   (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")))]
  ""
  "
{
  operands[3] = gen_reg_rtx (QImode);
  operands[4] = gen_lowpart (QImode, operands[2]);
}")

;; Rotate right on the VAX works by negating the shift count.
(define_expand "rotrsi3"
  [(set (match_operand:SI 0 "general_operand" "=g")
	(rotatert:SI (match_operand:SI 1 "general_operand" "g")
		     (match_operand:QI 2 "general_operand" "g")))]
  ""
  "
{
  if (! CONST_INT_P (operands[2]))
    operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
}")

(define_insn_and_split "rotlsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotate:SI (match_operand:SI 1 "general_operand" "nrmT")
		   (match_operand:QI 2 "general_operand" "g")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (rotate:SI (match_dup 1)
		      (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*rotlsi3<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotate:SI (match_operand:SI 1 "general_operand" "nrmT")
		   (match_operand:QI 2 "general_operand" "g")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "rotl %2,%1,%0")

(define_insn_and_split "*rotrsi3_const_int"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (match_operand:QI 2 "const_int_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (rotatert:SI (match_dup 1)
			(match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*rotrsi3_const_int_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (match_operand:QI 2 "const_int_operand" "n")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "rotl %R2,%1,%0")

(define_insn_and_split "*rotrnegsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (rotatert:SI (match_dup 1)
			(neg:QI (match_dup 2))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*rotrnegsi3_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(rotatert:SI (match_operand:SI 1 "general_operand" "nrmT")
		     (neg:QI (match_operand:QI 2 "general_operand" "g"))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "rotl %2,%1,%0")

;; This insn is probably slower than a multiply and an add.
;;(define_insn_and_split "*amulsi4"
;;  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
;;	(mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g")
;;			  (match_operand:SI 2 "general_operand" "g"))
;;		 (match_operand:SI 3 "general_operand" "g")))]
;;  ""
;;  "#"
;;  "reload_completed"
;;  [(parallel
;;     [(set (match_dup 0)
;;	   (mult:SI (plus:SI (match_dup 1)
;;			     (match_dup 2))
;;		    (match_dup 3)))
;;      (clobber (reg:CC VAX_PSL_REGNUM))])]
;;  "")
;;
;;(define_insn "*amulsi4_2<ccn><ccnz><ccz>"
;;  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
;;	(mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g")
;;			  (match_operand:SI 2 "general_operand" "g"))
;;		 (match_operand:SI 3 "general_operand" "g")))
;;   (clobber (reg:CC VAX_PSL_REGNUM))]
;;  "reload_completed"
;;  "index %1,$0x80000000,$0x7fffffff,%3,%2,%0")

;; Special cases of bit-field insns which we should
;; recognize in preference to the general case.
;; These handle aligned 8-bit and 16-bit fields
;; that can be done with move or convert instructions.

(define_insn_and_split "*insv_aligned"
  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+ro")
			 (match_operand:QI 1 "const_int_operand" "n")
			 (match_operand:SI 2 "const_int_operand" "n"))
	(match_operand:SI 3 "general_operand" "g"))]
  "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
   && INTVAL (operands[2]) % INTVAL (operands[1]) == 0
   && (!MEM_P (operands[0])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[0], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[0], 0),
					 MEM_ADDR_SPACE (operands[0]))))
   && (!(REG_P (operands[0])
	 || (SUBREG_P (operands[0]) && REG_P (SUBREG_REG (operands[0]))))
       || INTVAL (operands[2]) == 0)"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (zero_extract:SI (match_dup 0)
			    (match_dup 1)
			    (match_dup 2))
	   (match_dup 3))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*insv_aligned_2<ccn><ccnz><ccz>"
  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+ro")
			 (match_operand:QI 1 "const_int_operand" "n")
			 (match_operand:SI 2 "const_int_operand" "n"))
	(match_operand:SI 3 "general_operand" "g"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
   && INTVAL (operands[2]) % INTVAL (operands[1]) == 0
   && (!MEM_P (operands[0])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[0], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[0], 0),
					 MEM_ADDR_SPACE (operands[0]))))
   && (!(REG_P (operands[0])
	 || (SUBREG_P (operands[0]) && REG_P (SUBREG_REG (operands[0]))))
       || INTVAL (operands[2]) == 0)
   && reload_completed"
  "*
{
  if (!REG_P (operands[0]))
    operands[0]
      = adjust_address (operands[0],
			INTVAL (operands[1]) == 8 ? QImode : HImode,
			INTVAL (operands[2]) / 8);
  else
    gcc_assert (INTVAL (operands[2]) == 0);

  if (INTVAL (operands[1]) == 8)
    return \"movb %3,%0\";
  return \"movw %3,%0\";
}")

(define_insn_and_split "*extzv_aligned"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=&g")
	(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "const_int_operand" "n")
			 (match_operand:SI 3 "const_int_operand" "n")))]
  "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
   && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
   && (!MEM_P (operands[1])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[1], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[1], 0),
					 MEM_ADDR_SPACE (operands[1]))))
   && (!(REG_P (operands[1])
	 || (SUBREG_P (operands[1]) && REG_P (SUBREG_REG (operands[1]))))
       || INTVAL (operands[3]) == 0)"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extzv_aligned_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=&g")
	(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "const_int_operand" "n")
			 (match_operand:SI 3 "const_int_operand" "n")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
   && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
   && (!MEM_P (operands[1])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[1], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[1], 0),
					 MEM_ADDR_SPACE (operands[1]))))
   && (!(REG_P (operands[1])
	 || (SUBREG_P (operands[1]) && REG_P (SUBREG_REG (operands[1]))))
       || INTVAL (operands[3]) == 0)
   && reload_completed"
  "*
{
  if (!REG_P (operands[1]))
    operands[1]
      = adjust_address (operands[1],
			INTVAL (operands[2]) == 8 ? QImode : HImode,
			INTVAL (operands[3]) / 8);
  else
    gcc_assert (INTVAL (operands[3]) == 0);

  if (INTVAL (operands[2]) == 8)
    return \"movzbl %1,%0\";
  return \"movzwl %1,%0\";
}")

(define_insn_and_split "*extv_aligned"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "const_int_operand" "n")
			 (match_operand:SI 3 "const_int_operand" "n")))]
  "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
   && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
   && (!MEM_P (operands[1])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[1], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[1], 0),
					 MEM_ADDR_SPACE (operands[1]))))
   && (!(REG_P (operands[1])
	 || (SUBREG_P (operands[1]) && REG_P (SUBREG_REG (operands[1]))))
       || INTVAL (operands[3]) == 0)"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extv_aligned_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "const_int_operand" "n")
			 (match_operand:SI 3 "const_int_operand" "n")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
   && INTVAL (operands[3]) % INTVAL (operands[2]) == 0
   && (!MEM_P (operands[1])
       || ((!flag_pic
	    || vax_acceptable_pic_operand_p (XEXP (operands[1], 0),
					     true, true))
	   && !mode_dependent_address_p (XEXP (operands[1], 0),
					 MEM_ADDR_SPACE (operands[1]))))
   && (!(REG_P (operands[1])
	 || (SUBREG_P (operands[1]) && REG_P (SUBREG_REG (operands[1]))))
       || INTVAL (operands[3]) == 0)
   && reload_completed"
  "*
{
  if (!REG_P (operands[1]))
    operands[1]
      = adjust_address (operands[1],
			INTVAL (operands[2]) == 8 ? QImode : HImode,
			INTVAL (operands[3]) / 8);
  else
    gcc_assert (INTVAL (operands[3]) == 0);

  if (INTVAL (operands[2]) == 8)
    return \"cvtbl %1,%0\";
  return \"cvtwl %1,%0\";
}")

;; Register and non-offsettable-memory SImode cases of bit-field insns.

(define_insn "*cmpv_<mode>"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc
	 (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "ro")
			  (match_operand:QI 1 "general_operand" "g")
			  (match_operand:SI 2 "general_operand" "nrmT"))
	 (match_operand:SI 3 "general_operand" "nrmT")))]
  "reload_completed"
  "cmpv %2,%1,%0,%3")

(define_insn "*cmpzv_<mode>"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc
	 (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "ro")
			  (match_operand:QI 1 "general_operand" "g")
			  (match_operand:SI 2 "general_operand" "nrmT"))
	 (match_operand:SI 3 "general_operand" "nrmT")))]
  "reload_completed"
  "cmpzv %2,%1,%0,%3")

;; When the field position and size are constant and the destination
;; is a register, extv and extzv are much slower than a rotate followed
;; by a bicl or sign extension.  Because we might end up choosing ext[z]v
;; anyway, we can't allow immediate values for the primary source operand.

(define_insn_and_split "*extv_non_const"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "general_operand" "g")
			 (match_operand:SI 3 "general_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extv_non_const_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "general_operand" "g")
			 (match_operand:SI 3 "general_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  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)
    return \"rotl %R3,%1,%0\;cvtbl %0,%0\";
  return \"rotl %R3,%1,%0\;cvtwl %0,%0\";
}")

(define_insn_and_split "*extzv_non_const"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "general_operand" "g")
			 (match_operand:SI 3 "general_operand" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extzv_non_const_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "ro")
			 (match_operand:QI 2 "general_operand" "g")
			 (match_operand:SI 3 "general_operand" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  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\";
  if (INTVAL (operands[2]) == 16)
    return \"rotl %R3,%1,%0\;movzwl %0,%0\";
  if (INTVAL (operands[3]) & 31)
    return \"rotl %R3,%1,%0\;bicl2 %M2,%0\";
  if (rtx_equal_p (operands[0], operands[1]))
    return \"bicl2 %M2,%0\";
  return \"bicl3 %M2,%1,%0\";
}")

;; Non-register cases.
;; nonimmediate_operand is used to make sure that mode-ambiguous cases
;; don't match these (and therefore match the cases above instead).

(define_insn "*cmpv_2_<mode>"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc
	 (sign_extract:SI (match_operand:QI 0 "memory_operand" "m")
			  (match_operand:QI 1 "general_operand" "g")
			  (match_operand:SI 2 "general_operand" "nrmT"))
	 (match_operand:SI 3 "general_operand" "nrmT")))]
  "reload_completed"
  "cmpv %2,%1,%0,%3")

(define_insn "*cmpzv_2_<mode>"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc
	 (zero_extract:SI (match_operand:QI 0 "memory_operand" "m")
			  (match_operand:QI 1 "general_operand" "g")
			  (match_operand:SI 2 "general_operand" "nrmT"))
	 (match_operand:SI 3 "general_operand" "nrmT")))]
  "reload_completed"
  "cmpzv %2,%1,%0,%3")

(define_expand "extv"
  [(set (match_operand:SI 0 "general_operand" "")
	(sign_extract:SI (match_operand:SI 1 "general_operand" "")
			 (match_operand:QI 2 "general_operand" "")
			 (match_operand:SI 3 "general_operand" "")))]
  ""
  "")

(define_insn_and_split "*extv"
  [(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" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (sign_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extv_2<ccn><ccnz><ccz>"
  [(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" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  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
      || side_effects_p (operands[1])
      || (MEM_P (operands[1])
	  && mode_dependent_address_p (XEXP (operands[1], 0),
				       MEM_ADDR_SPACE (operands[1]))))
    return \"extv %3,%2,%1,%0\";
  if (INTVAL (operands[2]) == 8)
    return \"rotl %R3,%1,%0\;cvtbl %0,%0\";
  return \"rotl %R3,%1,%0\;cvtwl %0,%0\";
}")

(define_expand "extzv"
  [(set (match_operand:SI 0 "general_operand" "")
	(zero_extract:SI (match_operand:SI 1 "general_operand" "")
			 (match_operand:QI 2 "general_operand" "")
			 (match_operand:SI 3 "general_operand" "")))]
  ""
  "")

(define_insn_and_split "*extzv"
  [(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" "nrmT")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (zero_extract:SI (match_dup 1)
			    (match_dup 2)
			    (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*extzv_2<ccn><ccnz><ccz>"
  [(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" "nrmT")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  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])
      || (MEM_P (operands[1])
	  && mode_dependent_address_p (XEXP (operands[1], 0),
				       MEM_ADDR_SPACE (operands[1]))))
    return \"extzv %3,%2,%1,%0\";
  if (INTVAL (operands[2]) == 8)
    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\";
}")

;; Combine EXTV/CMPL and EXTZV/CMPL sequences where the output of
;; extraction is used for the comparison only into CMPV and CMPZV
;; respectively.
(define_peephole2
  [(parallel
     [(set (match_operand:SI 0 "register_operand")
	   (any_extract:SI (match_operand 1 "general_operand")
			   (match_operand:QI 2 "general_operand")
			   (match_operand:SI 3 "general_operand")))
      (clobber (reg:CC VAX_PSL_REGNUM))])
   (set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc (match_dup 0)
		       (match_operand:SI 4 "general_operand")))]
  "peep2_reg_dead_p (2, operands[0])"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc
	  (any_extract:SI (match_dup 1)
			  (match_dup 2)
			  (match_dup 3))
	  (match_dup 4)))]
  "")

(define_expand "insv"
  [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
			 (match_operand:QI 1 "general_operand" "")
			 (match_operand:SI 2 "general_operand" ""))
	(match_operand:SI 3 "general_operand" ""))]
  ""
  "")

;; This one actually doesn't change CC.
(define_insn "*insv"
  [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m")
			 (match_operand:QI 1 "general_operand" "g")
			 (match_operand:SI 2 "general_operand" "nrmT"))
	(match_operand:SI 3 "general_operand" "nrmT"))]
  ""
  "*
{
  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\";
}")

;; This one actually doesn't change CC.
(define_insn "*insv_2"
  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+ro")
			 (match_operand:QI 1 "general_operand" "g")
			 (match_operand:SI 2 "general_operand" "nrmT"))
	(match_operand:SI 3 "general_operand" "nrmT"))]
  ""
  "insv %3,%2,%1,%0")

;; Unconditional jump
(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "jbr %l0")

;; Conditional jumps

(define_expand "cbranch<mode>4"
  [(set (pc)
	(if_then_else
	  (match_operator 0 "ordered_comparison_operator"
			  [(match_operand:VAXint 1 "general_operand" "")
			   (match_operand:VAXint 2 "general_operand" "")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))]
  ""
  "")

(define_insn_and_split "*cbranch<VAXint:mode>4_<VAXcc:mode>"
  [(set (pc)
	(if_then_else
	  (match_operator 0 "vax_<VAXcc:mode>_comparison_operator"
			  [(match_operand:VAXint 1 "general_operand" "nrmT")
			   (match_operand:VAXint 2 "general_operand" "nrmT")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))]
  ""
  "#"
  "reload_completed"
  [(set (reg:VAXcc VAX_PSL_REGNUM)
	(compare:VAXcc (match_dup 1) (match_dup 2)))
   (set (pc)
	(if_then_else
	  (match_op_dup 0 [(reg:VAXcc VAX_PSL_REGNUM)
			   (const_int 0)])
	 (label_ref (match_operand 3 "" ""))
	 (pc)))]
  "")

(define_expand "cbranch<mode>4"
  [(set (pc)
	(if_then_else
	  (match_operator 0 "ordered_comparison_operator"
			  [(match_operand:VAXfp 1 "general_operand" "")
			   (match_operand:VAXfp 2 "general_operand" "")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))]
  ""
  "")

(define_insn_and_split "*cbranch<VAXfp:mode>4_<VAXccnz:mode>"
  [(set (pc)
	(if_then_else
	  (match_operator 0 "vax_<VAXccnz:mode>_comparison_operator"
			  [(match_operand:VAXfp 1 "general_operand" "gF")
			   (match_operand:VAXfp 2 "general_operand" "gF")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))]
  ""
  "#"
  "reload_completed"
  [(set (reg:VAXccnz VAX_PSL_REGNUM)
	(compare:VAXccnz (match_dup 1) (match_dup 2)))
   (set (pc)
	(if_then_else
 	  (match_op_dup 0 [(reg:VAXccnz VAX_PSL_REGNUM)
			   (const_int 0)])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))]
  "")

(define_insn "*branch_<mode>"
  [(set (pc)
	(if_then_else (match_operator 0 "vax_<mode>_comparison_operator"
				      [(reg:VAXcc VAX_PSL_REGNUM)
				       (const_int 0)])
		      (label_ref (match_operand 1 "" ""))
		      (pc)))]
  "reload_completed"
  "j%k0 %l1")

;; Recognize reversed jumps.
(define_insn "*branch_<mode>_reversed"
  [(set (pc)
	(if_then_else (match_operator 0 "vax_<mode>_comparison_operator"
				      [(reg:VAXcc VAX_PSL_REGNUM)
				       (const_int 0)])
		      (pc)
		      (label_ref (match_operand 1 "" ""))))]
  "reload_completed"
  "j%K0 %l1") ; %K0 negates condition

;; Recognize jbs, jlbs, jbc and jlbc instructions.  Note that the operand
;; of jlbs and jlbc insns are SImode in the hardware.  However, if it is
;; memory, we use QImode in the insn.  So we can't use those instructions
;; for mode-dependent addresses.

(define_insn ""
  [(set (pc)
	(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,nrmT"))
	     (const_int 0))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))]
  ""
  "@
   jlbs %0,%l2
   jbs %1,%0,%l2")

(define_insn ""
  [(set (pc)
	(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,nrmT"))
	     (const_int 0))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))]
  ""
  "@
   jlbc %0,%l2
   jbc %1,%0,%l2")

(define_insn ""
  [(set (pc)
	(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,nrmT"))
	     (const_int 0))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))]
  ""
  "@
   jlbs %0,%l2
   jbs %1,%0,%l2")

(define_insn ""
  [(set (pc)
	(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,nrmT"))
	     (const_int 0))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))]
  ""
  "@
   jlbc %0,%l2
   jbc %1,%0,%l2")

;; Subtract-and-jump and Add-and-jump insns.
;; These are not used when output is for the Unix assembler
;; because it does not know how to modify them to reach far.

;; Normal sob insns.

(define_insn_and_split "*jsobgtr"
  [(set (pc)
	(if_then_else
	 (gt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int -1))
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))]
  "!TARGET_UNIX_ASM"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (gt (plus:SI (match_dup 0)
			 (const_int -1))
		(const_int 0))
	    (label_ref (match_dup 1))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int -1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jsobgtr_2"
  [(set (pc)
	(if_then_else
	 (gt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int -1))
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && reload_completed"
  "jsobgtr %0,%l1")

(define_insn_and_split "*jsobgeq"
  [(set (pc)
	(if_then_else
	 (ge (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int -1))
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))]
  "!TARGET_UNIX_ASM"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (ge (plus:SI (match_dup 0)
			 (const_int -1))
		(const_int 0))
	    (label_ref (match_dup 1))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int -1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jsobgeq_2"
  [(set (pc)
	(if_then_else
	 (ge (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int -1))
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && reload_completed"
  "jsobgeq %0,%l1")

;; Normal aob insns.  Define a version for when operands[1] is a constant.
(define_insn_and_split "*jaoblss"
  [(set (pc)
	(if_then_else
	 (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int 1))
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))]
  "!TARGET_UNIX_ASM"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (lt (plus:SI (match_dup 0)
			 (const_int 1))
		(match_dup 1))
	    (label_ref (match_dup 2))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jaoblss_2"
  [(set (pc)
	(if_then_else
	 (lt (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int 1))
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && reload_completed"
  "jaoblss %1,%0,%l2")

(define_insn_and_split "*jaoblss_const"
  [(set (pc)
	(if_then_else
	 (lt (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))]
  "!TARGET_UNIX_ASM && CONST_INT_P (operands[1])"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (lt (match_dup 0)
		(match_dup 1))
	    (label_ref (match_dup 2))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jaoblss_const_2"
  [(set (pc)
	(if_then_else
	 (lt (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && CONST_INT_P (operands[1]) && reload_completed"
  "jaoblss %P1,%0,%l2")

(define_insn_and_split "*jaobleq"
  [(set (pc)
	(if_then_else
	 (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int 1))
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))]
  "!TARGET_UNIX_ASM"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (le (plus:SI (match_dup 0)
			 (const_int 1))
		(match_dup 1))
	    (label_ref (match_dup 2))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jaobleq_2"
  [(set (pc)
	(if_then_else
	 (le (plus:SI (match_operand:SI 0 "nonimmediate_operand" "+g")
		      (const_int 1))
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && reload_completed"
  "jaobleq %1,%0,%l2")

(define_insn_and_split "*jaobleq_const"
  [(set (pc)
	(if_then_else
	 (le (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))]
  "!TARGET_UNIX_ASM && CONST_INT_P (operands[1])"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (le (match_dup 0)
		(match_dup 1))
	    (label_ref (match_dup 2))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int 1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jaobleq_const_2"
  [(set (pc)
	(if_then_else
	 (le (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (match_operand:SI 1 "general_operand" "nrmT"))
	 (label_ref (match_operand 2 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "!TARGET_UNIX_ASM && CONST_INT_P (operands[1]) && reload_completed"
  "jaobleq %P1,%0,%l2")

;; Something like a sob insn, but compares against -1.
;; This finds `while (foo--)' which was changed to `while (--foo != -1)'.

(define_insn_and_split "*jsobneq_minus_one"
  [(set (pc)
	(if_then_else
	 (ne (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (pc)
	   (if_then_else
	    (ne (match_dup 0)
		(const_int 0))
	    (label_ref (match_dup 1))
	    (pc)))
      (set (match_dup 0)
	   (plus:SI (match_dup 0)
		    (const_int -1)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*jsobneq_minus_one_2"
  [(set (pc)
	(if_then_else
	 (ne (match_operand:SI 0 "nonimmediate_operand" "+g")
	     (const_int 0))
	 (label_ref (match_operand 1 "" ""))
	 (pc)))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "decl %0\;jgequ %l1")

(define_expand "call_pop"
  [(parallel [(call (match_operand:QI 0 "memory_operand" "")
		    (match_operand:SI 1 "const_int_operand" ""))
	      (set (reg:SI VAX_SP_REGNUM)
		   (plus:SI (reg:SI VAX_SP_REGNUM)
			    (match_operand:SI 3 "immediate_operand" "")))])]
  ""
{
  gcc_assert (INTVAL (operands[3]) <= 255 * 4 && INTVAL (operands[3]) % 4 == 0);

  /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size
     during EH unwinding.  We must include the argument count pushed by
     the calls instruction.  */
  operands[1] = GEN_INT (INTVAL (operands[3]) + 4);
})

(define_insn "*call_pop"
  [(call (match_operand:QI 0 "memory_operand" "m")
	 (match_operand:SI 1 "const_int_operand" "n"))
   (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM)
					(match_operand:SI 2 "immediate_operand" "i")))]
  ""
{
  operands[1] = GEN_INT ((INTVAL (operands[1]) - 4) / 4);
  return "calls %1,%0";
})

(define_expand "call_value_pop"
  [(parallel [(set (match_operand 0 "" "")
		   (call (match_operand:QI 1 "memory_operand" "")
			 (match_operand:SI 2 "const_int_operand" "")))
	      (set (reg:SI VAX_SP_REGNUM)
		   (plus:SI (reg:SI VAX_SP_REGNUM)
			    (match_operand:SI 4 "immediate_operand" "")))])]
  ""
{
  gcc_assert (INTVAL (operands[4]) <= 255 * 4 && INTVAL (operands[4]) % 4 == 0);

  /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size
     during EH unwinding.  We must include the argument count pushed by
     the calls instruction.  */
  operands[2] = GEN_INT (INTVAL (operands[4]) + 4);
})

(define_insn "*call_value_pop"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "memory_operand" "m")
	      (match_operand:SI 2 "const_int_operand" "n")))
   (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM)
					(match_operand:SI 3 "immediate_operand" "i")))]
  ""
  "*
{
  operands[2] = GEN_INT ((INTVAL (operands[2]) - 4) / 4);
  return \"calls %2,%1\";
}")

(define_expand "call"
  [(call (match_operand:QI 0 "memory_operand" "")
      (match_operand:SI 1 "const_int_operand" ""))]
  ""
  "
{
  /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size
     during EH unwinding.  We must include the argument count pushed by
     the calls instruction.  */
  operands[1] = GEN_INT (INTVAL (operands[1]) + 4);
}")

(define_insn "*call"
   [(call (match_operand:QI 0 "memory_operand" "m")
	  (match_operand:SI 1 "const_int_operand" ""))]
  ""
  "calls $0,%0")

(define_expand "call_value"
  [(set (match_operand 0 "" "")
      (call (match_operand:QI 1 "memory_operand" "")
	    (match_operand:SI 2 "const_int_operand" "")))]
  ""
  "
{
  /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size
     during EH unwinding.  We must include the argument count pushed by
     the calls instruction.  */
  operands[2] = GEN_INT (INTVAL (operands[2]) + 4);
}")

(define_insn "*call_value"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "memory_operand" "m")
	      (match_operand:SI 2 "const_int_operand" "")))]
  ""
  "calls $0,%1")

;; Call subroutine returning any type.

(define_expand "untyped_call"
  [(parallel [(call (match_operand 0 "" "")
	      (const_int 0))
	      (match_operand 1 "" "")
	      (match_operand 2 "" "")])]
  ""
  "
{
  int i;

  emit_call_insn (gen_call_pop (operands[0], const0_rtx, NULL, const0_rtx));

  for (i = 0; i < XVECLEN (operands[2], 0); i++)
    {
      rtx set = XVECEXP (operands[2], 0, i);
      emit_move_insn (SET_DEST (set), SET_SRC (set));
    }

  /* The optimizer does not know that the call sets the function value
     registers we stored in the result block.  We avoid problems by
     claiming that all hard registers are used and clobbered at this
     point.  */
  emit_insn (gen_blockage ());

  DONE;
}")

;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory.  This blocks insns from being moved across this point.

(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)]
  ""
  "")

(define_insn "procedure_entry_mask"
  [(unspec_volatile [(match_operand 0 "const_int_operand")] VUNSPEC_PEM)]
  ""
  ".word %x0")

(define_insn "return"
  [(return)]
  ""
  "ret")

(define_expand "prologue"
  [(const_int 0)]
  ""
{
  vax_expand_prologue ();
  DONE;
})

(define_expand "epilogue"
  [(return)]
  ""
  "
{
  emit_jump_insn (gen_return ());
  DONE;
}")

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop")

;; This had a wider constraint once, and it had trouble.
;; If you are tempted to try `g', please don't--it's not worth
;; the risk we will reopen the same bug.
(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
  ""
  "jmp (%0)")

;; This is here to accept 5 arguments (as passed by expand_end_case)
;; and pass the first 4 along to the casesi1 pattern that really does
;; the actual casesi work.  We emit a jump here to the default label
;; _before_ the casesi so that we can be sure that the casesi never
;; drops through.
;; This is suboptimal perhaps, but so is much of the rest of this
;; machine description.  For what it's worth, HPPA uses the same trick.
;;
;; operand 0 is index
;; operand 1 is the minimum bound (a const_int)
;; operand 2 is the maximum bound - minimum bound + 1 (also a const_int)
;; operand 3 is CODE_LABEL for the table;
;; operand 4 is the CODE_LABEL to go to if index out of range (ie. default).
;;
;; We emit:
;;	i = index - minimum_bound
;;	if (i > (maximum_bound - minimum_bound + 1) goto default;
;;	casesi (i, 0, table);
;;
(define_expand "casesi"
  [(match_operand:SI 0 "general_operand" "")
   (match_operand:SI 1 "general_operand" "")
   (match_operand:SI 2 "general_operand" "")
   (match_operand 3 "" "")
   (match_operand 4 "" "")]
  ""
{
  rtx test;

  /* i = index - minimum_bound;
     But only if the lower bound is not already zero.  */
  if (operands[1] != const0_rtx)
    {
      rtx index = gen_reg_rtx (SImode);
      emit_insn (gen_addsi3 (index,
			     operands[0],
			     gen_int_mode (-INTVAL (operands[1]), SImode)));
      operands[0] = index;
    }

  /* 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]));
  DONE;
})

;; This insn is a bit of a lier.  It actually falls through if no case
;; matches.  But, we prevent that from ever happening by emitting a jump
;; before this, see the define_expand above.
(define_insn_and_split "casesi1"
  [(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" "nrmT")
			       (const_int 2))
			     (pc))))
		 (label_ref:SI (match_operand 2 "" ""))))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(match_dup 1)
      (set (pc)
	   (plus:SI (sign_extend:SI
		      (mem:HI (plus:SI
				(mult:SI
				  (match_dup 0)
				  (const_int 2))
				(pc))))
		    (label_ref:SI (match_dup 2))))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*casesi1"
  [(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" "nrmT")
			       (const_int 2))
			     (pc))))
		 (label_ref:SI (match_operand 2 "" ""))))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "casel %0,$0,%1")

(define_insn_and_split "*pushsym"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:SI 1 "pic_symbolic_operand" "A"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*pushsym_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:SI 1 "pic_symbolic_operand" "A"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "pushab %a1")

(define_insn_and_split "*movsym"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:SI 1 "pic_symbolic_operand" "A"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movsym_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:SI 1 "pic_symbolic_operand" "A"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "movab %a1,%0")

(define_insn_and_split "*pushsymreg"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(plus:SI (match_operand:SI 1 "register_operand" "%r")
		 (match_operand:SI 2 "pic_symbolic_operand" "A")))]
  "flag_pic"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:SI (match_dup 1)
		    (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*pushsymreg_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(plus:SI (match_operand:SI 1 "register_operand" "%r")
		 (match_operand:SI 2 "pic_symbolic_operand" "A")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "flag_pic && reload_completed"
  "pushab %a2[%1]")

(define_insn_and_split "*movsymreg"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(plus:SI (match_operand:SI 1 "register_operand" "%r")
		 (match_operand:SI 2 "pic_symbolic_operand" "A")))]
  "flag_pic"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (plus:SI (match_dup 1)
		    (match_dup 2)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movsymreg_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(plus:SI (match_operand:SI 1 "register_operand" "%r")
		 (match_operand:SI 2 "pic_symbolic_operand" "A")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "flag_pic && reload_completed"
  "movab %a2[%1],%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.
;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3.

;; It does not work to use constraints to distinguish pushes from moves,
;; because < matches any autodecrement, not just a push.

(define_insn_and_split "pushaddr<mode>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:VAXintQHSD 1 "address_operand" "p"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*pushaddr<mode><ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:VAXintQHSD 1 "address_operand" "p"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "pusha<VAXintQHSD:isfx> %a1")

(define_insn_and_split "movaddr<mode>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:VAXintQHSD 1 "address_operand" "p"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movaddr<mode><ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:VAXintQHSD 1 "address_operand" "p"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "mova<VAXintQHSD:isfx> %a1,%0")

(define_insn_and_split "pushaddr<mode>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:VAXfp 1 "address_operand" "p"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*pushaddr<mode><ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "push_operand" "=g")
	(match_operand:VAXfp 1 "address_operand" "p"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "pusha<VAXfp:fsfx> %a1")

(define_insn_and_split "movaddr<mode>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:VAXfp 1 "address_operand" "p"))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (match_dup 1))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*movaddr<mode>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:VAXfp 1 "address_operand" "p"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "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
;; if it is not an offsettable address so that we know that we can assign
;; to it twice.

;; If we had a good way of evaluating the relative costs, these could be
;; machine-independent.

;; Optimize   extzv ...,z;    andl2 ...,z
;; or	      ashl ...,z;     andl2 ...,z
;; with other operands constant.  This is what the combiner converts the
;; above sequences to before attempting to recognize the new insn.

(define_insn_and_split "*andashlnegsi4"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
	(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"
  "#"
  "&& reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (and:SI (ashiftrt:SI (match_dup 1)
				(match_dup 2))
		   (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*andashlnegsi4_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
	(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")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "(INTVAL (operands[3]) & ~((1 << (32 - INTVAL (operands[2]))) - 1)) == 0
   && reload_completed"
  "*
{
  unsigned long mask1 = INTVAL (operands[3]);
  unsigned long mask2 = (1 << (32 - INTVAL (operands[2]))) - 1;

  if ((mask1 & mask2) != mask1)
    operands[3] = GEN_INT (mask1 & mask2);

  return \"rotl %R2,%1,%0\;bicl2 %N3,%0\";
}")

;; left-shift and mask
;; The only case where `ashl' is better is if the mask only turns off
;; bits that the ashl would anyways, in which case it should have been
;; optimized away.

(define_insn_and_split "*andashlsi4"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
	(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")))]
  ""
  "#"
  "reload_completed"
  [(parallel
     [(set (match_dup 0)
	   (and:SI (ashift:SI (match_dup 1)
			      (match_dup 2))
		   (match_dup 3)))
      (clobber (reg:CC VAX_PSL_REGNUM))])]
  "")

(define_insn "*andashlsi4_2<ccn><ccnz><ccz>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=ro")
	(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")))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "*
{
  operands[3]
    = GEN_INT (INTVAL (operands[3]) & ~((1 << INTVAL (operands[2])) - 1));
  return \"rotl %2,%1,%0\;bicl2 %N3,%0\";
}")

;; Instruction sequence to sync the VAX instruction stream.
(define_insn "sync_istream"
  [(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);

  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;
})

(include "builtins.md")
