;;- Machine description for GNU compiler -- System/370 version.
;;  Copyright (C) 1989, 93, 94, 95, 1997 Free Software Foundation, Inc.
;;  Contributed by Jan Stein (jan@cd.chalmers.se).
;;  Modified for OS/390 LanguageEnvironment C by Dave Pitts (dpitts@cozx.com)
;;  Lots of Bug Fixes & Enhancements by Linas Vepstas (linas@linas.org)

;; This file is part of GNU CC.

;; GNU CC 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 2, or (at your option)
;; any later version.

;; GNU CC 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 GNU CC; see the file COPYING.  If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; =======================================================================
;; Condition codes for some of the instructions (in particular, for 
;; add, sub, shift, abs, etc. are handled with the cpp macro NOTICE_UPDATE_CC 
;;
;; Special constraints for 370 machine description:
;;
;;    a -- Any address register from 1 to 15.
;;    d -- Any register from 0 to 15.
;;    I -- An 8-bit constant (0..255).
;;    J -- A 12-bit constant (0..4095).
;;    K -- A 16-bit constant (-32768..32767).
;;    R -- a valid S operand in an RS, SI or SS instruction, or register
;;    S -- a valid S operand in an RS, SI or SS instruction
;;
;; Note this well: 
;; When defining an instruction, e.g. the movsi pattern:
;; 
;;    (define_insn ""
;;        [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm")
;;            (match_operand:SI 1 "r_or_s_operand" "diR,dim,*fF"))]
;;
;; The "r_or_s_operand" predicate is used to recognize the instruction;
;; however, it is not further used to enforce a constraint at later stages.
;; Thus, for example, although "r_or_s_operand" bars operands of the form
;; base+index+displacement, such operands can none-the-less show up during
;; post-instruction-recog processing: thus, for example, garbage like
;; MVC     152(4,r13),0(r5,r13) might be generated if both op0 and op1 are 
;; mem operands.   To avoid this, use the S constraint.
;; 
;;
;; Special formats used for outputting 370 instructions.
;;
;;   %B -- Print a constant byte integer.
;;   %H -- Print a signed 16-bit constant.
;;   %K -- Print a signed 16-bit constant signed-extended to 32-bits.
;;   %L -- Print least significant word of a CONST_DOUBLE.
;;   %M -- Print most significant word of a CONST_DOUBLE.
;;   %N -- Print next register (second word of a DImode reg).
;;   %O -- Print the offset of a memory reference (PLUS (REG) (CONST_INT)).
;;   %R -- Print the register of a memory reference (PLUS (REG) (CONST_INT)).
;;   %X -- Print a constant byte integer in hex.
;;   %W -- Print a signed 32-bit int sign-extended to 64-bits.
;;
;; We have a special constraint for pattern matching.
;;
;;   s_operand -- Matches a valid S operand in a RS, SI or SS type instruction.
;;
;;   r_or_s_operand -- Matches a register or a valid S operand in a RS, SI
;;		       or SS type instruction or a register
;;
;; For MVS C/370 we use the following stack locations for:
;;
;;   136 - internal function result buffer
;;   140 - numeric conversion buffer
;;   144 - pointer to internal function result buffer
;;   148 - start of automatic variables and function arguments
;;
;; To support programs larger than a page, 4096 bytes, PAGE_REGISTER points
;; to a page origin table, all internal labels are generated to reload the
;; BASE_REGISTER knowing what page it is on and all branch instructions go
;; directly to the target if it is known that the target is on the current
;; page (essentially backward references).  All forward references and off
;; page references are handled by loading the address of target into a
;; register and branching indirectly.
;;
;; Some *di patterns have been commented out per advice from RMS, as gcc
;; will generate the right things to do.
;;
;; See the note in i370.h about register 14, clobbering it, and optimization.
;; Basically, using clobber in egcs-1.1.1 will ruin ability to optimize around
;; branches, so don't do it.
;;
;; We use the "length" attirbute to store the max possible code size of an
;; insn.  We use this length to estimate the length of forward branches, to
;; determine if they're on page or off.

(define_attr "length" "" (const_int 0))

;;
;;- Test instructions.
;;

;
; tstdi instruction pattern(s).
;

(define_insn "tstdi"
  [(set (cc0)
	(match_operand:DI 0 "register_operand" "d"))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  return \"SRDA	%0,0\";
}"
   [(set_attr "length" "4")]
)

;
; tstsi instruction pattern(s).
;

(define_insn "tstsi"
  [(set (cc0)
	(match_operand:SI 0 "register_operand" "d"))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LTR	%0,%0\";
}"
   [(set_attr "length" "2")]
)

;
; tsthi instruction pattern(s).
;

(define_insn "tsthi"
  [(set (cc0)
	(match_operand:HI 0 "register_operand" "d"))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 2);
  return \"CH	%0,=H'0'\";
}"
   [(set_attr "length" "4")]
)

;
; tstqi instruction pattern(s).
;

(define_insn ""
  [(set (cc0)
	(match_operand:QI 0 "r_or_s_operand" "dm"))]
  "unsigned_jump_follows_p (insn)"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      /* an unsigned compare to zero is always zero/not-zero... */
      mvs_check_page (0, 4, 4);
      return \"N	%0,=X'000000FF'\";
    }
  mvs_check_page (0, 4, 0);
  return \"CLI	%0,0\";
}"
   [(set_attr "length" "4")]
)

(define_insn "tstqi"
  [(set (cc0)
     (match_operand:QI 0 "register_operand" "d"))]
  ""
  "*
{
  check_label_emit ();
  if (unsigned_jump_follows_p (insn))
    {
      /* an unsigned compare to zero is always zero/not-zero... */
      mvs_check_page (0, 4, 4);
      return \"N	%0,=X'000000FF'\";
    }
  mvs_check_page (0, 8, 0);
  return \"SLL	%0,24\;SRA	%0,24\";
}"
   [(set_attr "length" "8")]
)

;
; tstdf instruction pattern(s).
;

(define_insn "tstdf"
  [(set (cc0)
	(match_operand:DF 0 "general_operand" "f"))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LTDR	%0,%0\";
}"
   [(set_attr "length" "2")]
)

;
; tstsf instruction pattern(s).
;

(define_insn "tstsf"
  [(set (cc0)
	(match_operand:SF 0 "general_operand" "f"))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LTER	%0,%0\";
}"
   [(set_attr "length" "2")]
)

;;
;;- Compare instructions.
;;

;
; cmpdi instruction pattern(s).
;

;(define_insn "cmpdi"
;  [(set (cc0)
;	(compare (match_operand:DI 0 "register_operand" "d")
;		 (match_operand:DI 1 "general_operand" "")))]
;  ""
;  "*
;{
;  check_label_emit ();
;  if (REG_P (operands[1]))
;    {
;      mvs_check_page (0, 8, 0);
;      if (unsigned_jump_follows_p (insn))
;        return \"CLR	%0,%1\;BNE	*+6\;CLR	%N0,%N1\";
;      return \"CR	%0,%1\;BNE	*+6\;CLR	%N0,%N1\";
;    }
;  mvs_check_page (0, 12, 0);
;  if (unsigned_jump_follows_p (insn))
;    return \"CL	%0,%M1\;BNE	*+8\;CL	%N0,%L1\";
;  return \"C	%0,%M1\;BNE	*+8\;CL	%N0,%L1\";
;}")

;
; cmpsi instruction pattern(s).
;

(define_insn "cmpsi"
  [(set (cc0)
	(compare (match_operand:SI 0 "register_operand" "d")
		 (match_operand:SI 1 "general_operand" "md")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 2, 0);
      if (unsigned_jump_follows_p (insn))
	return \"CLR	%0,%1\";
      return \"CR	%0,%1\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 4);
      if (unsigned_jump_follows_p (insn))
	 return \"CL	%0,=F'%c1'\";
      return \"C	%0,=F'%c1'\";
    }
  mvs_check_page (0, 4, 0);
  if (unsigned_jump_follows_p (insn))
    return \"CL	%0,%1\";
  return \"C	%0,%1\";
}"
   [(set_attr "length" "4")]
)

;
; cmphi instruction pattern(s).
;

; depricate constraint d because it takes multiple instructions
; and a memeory access ...
(define_insn "cmphi"
  [(set (cc0)
	(compare (match_operand:HI 0 "register_operand" "d")
		 (match_operand:HI 1 "general_operand" "???dim")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      if (unsigned_jump_follows_p (insn))
	return \"STH	%1,140(,13)\;CLM	%0,3,140(13)\";
      return \"STH	%1,140(,13)\;CH	%0,140(,13)\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"CH	%0,%H1\";
    }
  mvs_check_page (0, 4, 0);
  return \"CH	%0,%1\";
}"
   [(set_attr "length" "8")]
)

;
; cmpqi instruction pattern(s).
;

(define_insn ""
  [(set (cc0)
	(compare (match_operand:QI 0 "r_or_s_operand" "dS")
		 (match_operand:QI 1 "r_or_s_operand" "diS")))]
  "unsigned_jump_follows_p (insn)"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
          return \"STC	%1,140(,13)\;CLM	%0,1,140(13)\";
        }
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  mvs_check_page (0, 4, 1);
          return \"CLM	%0,1,=X'%X1'\";
        }
      mvs_check_page (0, 4, 0);
      return \"CLM	%0,1,%1\";
    }
  else if (GET_CODE (operands[0]) == CONST_INT)
    {
      cc_status.flags |= CC_REVERSED;
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 4, 1);
          return \"CLM	%1,1,=X'%X0'\";
        }
      mvs_check_page (0, 4, 0);
      return \"CLI	%1,%B0\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"CLI	%0,%B1\";
    }
  if (GET_CODE (operands[1]) == MEM)
    {
      mvs_check_page (0, 6, 0);
      return \"CLC	%O0(1,%R0),%1\";
    }
  cc_status.flags |= CC_REVERSED;
  mvs_check_page (0, 4, 0);
  return \"CLM	%1,1,%0\";
}"
   [(set_attr "length" "8")]
)

(define_insn "cmpqi"
  [(set (cc0)
	(compare (match_operand:QI 0 "register_operand" "d")
		 (match_operand:QI 1 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  if (unsigned_jump_follows_p (insn))
    {
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  mvs_check_page (0, 4, 1);
          return \"CLM	%0,1,=X'%X1'\";
        }
      if (!(REG_P (operands[1])))
	{
	  mvs_check_page (0, 4, 0);
          return \"CLM	%0,1,%1\";
        }
      mvs_check_page (0, 8, 0);
      return \"STC	%1,140(,13)\;CLM	%0,1,140(13)\";
    }
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 18, 0);
      return \"SLL	%0,24\;SRA	%0,24\;SLL	%1,24\;SRA	%1,24\;CR	%0,%1\";
    }
  mvs_check_page (0, 12, 0);
  return \"SLL	%0,24\;SRA	%0,24\;C	%0,%1\";
}"
   [(set_attr "length" "18")]
)

;
; cmpdf instruction pattern(s).
;

(define_insn "cmpdf"
  [(set (cc0)
	(compare (match_operand:DF 0 "general_operand" "f,mF")
		 (match_operand:DF 1 "general_operand" "fmF,f")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"CDR	%0,%1\";
	}
      mvs_check_page (0, 4, 0);
      return \"CD	%0,%1\";
    }
  cc_status.flags |= CC_REVERSED;
  mvs_check_page (0, 4, 0);
  return \"CD	%1,%0\";
}"
   [(set_attr "length" "4")]
)

;
; cmpsf instruction pattern(s).
;

(define_insn "cmpsf"
  [(set (cc0)
	(compare (match_operand:SF 0 "general_operand" "f,mF")
		 (match_operand:SF 1 "general_operand" "fmF,f")))]
  ""
  "*
{
check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"CER	%0,%1\";
	}
      mvs_check_page (0, 4, 0);
      return \"CE	%0,%1\";
    }
  cc_status.flags |= CC_REVERSED;
  mvs_check_page (0, 4, 0);
  return \"CE	%1,%0\";
}"
   [(set_attr "length" "4")]
)

;
; cmpstrsi instruction pattern(s).
;

(define_expand "cmpstrsi"
  [(set (match_operand:SI 0 "general_operand" "")
	  (compare (match_operand:BLK 1 "general_operand" "")
		   (match_operand:BLK 2 "general_operand" "")))
     (use (match_operand:SI 3 "general_operand" ""))
     (use (match_operand:SI 4 "" ""))]
   ""
   "
{
  rtx op1, op2;

  op1 = XEXP (operands[1], 0);
  if (GET_CODE (op1) == REG
      || (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1, 0)) == REG
	  && GET_CODE (XEXP (op1, 1)) == CONST_INT
	  && (unsigned) INTVAL (XEXP (op1, 1)) < 4096))
    {
      op1 = operands[1];
    }
  else
    {
      op1 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op1));
    }

  op2 = XEXP (operands[2], 0);
  if (GET_CODE (op2) == REG
      || (GET_CODE (op2) == PLUS && GET_CODE (XEXP (op2, 0)) == REG
	  && GET_CODE (XEXP (op2, 1)) == CONST_INT
	  && (unsigned) INTVAL (XEXP (op2, 1)) < 4096))
    {
      op2 = operands[2];
    }
  else
    {
      op2 = gen_rtx_MEM (BLKmode, copy_to_mode_reg (SImode, op2));
    }
      
  if (GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[3]) < 256)
    {
      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
		gen_rtx_SET (VOIDmode, operands[0], 
			gen_rtx_COMPARE (VOIDmode, op1, op2)),
		gen_rtx_USE (VOIDmode, operands[3]))));
    }
  else
    {
        /* implementation suggested by  Richard Henderson <rth@cygnus.com> */
        rtx reg1 = gen_reg_rtx (DImode);
        rtx reg2 = gen_reg_rtx (DImode);
        rtx result = operands[0];
        rtx mem1 = operands[1];
        rtx mem2 = operands[2];
        rtx len = operands[3];
        if (!CONSTANT_P (len))
          len = force_reg (SImode, len);

        /* Load up the address+length pairs.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
                        force_operand (XEXP (mem1, 0), NULL_RTX));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);

        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0),
                        force_operand (XEXP (mem2, 0), NULL_RTX));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len);

        /* Compare! */
        emit_insn (gen_cmpstrsi_1 (result, reg1, reg2));
    }
  DONE;
}")

; Compare a block that is less than 256 bytes in length.

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "d")
	(compare (match_operand:BLK 1 "s_operand" "m")
		 (match_operand:BLK 2 "s_operand" "m")))
   (use (match_operand:QI 3 "immediate_operand" "I"))]
  "((unsigned) INTVAL (operands[3]) < 256)"
  "*
{
  check_label_emit ();
  mvs_check_page (0, 22, 0);
  return \"LA	%0,%1\;CLC	%O1(%c3,%R1),%2\;BH	*+12\;BL	*+6\;SLR	%0,%0\;LNR	%0,%0\";
}"
   [(set_attr "length" "22")]
)

; Compare a block that is larger than 255 bytes in length.

(define_insn "cmpstrsi_1"
  [(set (match_operand:SI 0 "register_operand" "+d")
        (compare
        (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0))
        (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "+d") 0))))
   (use (match_dup 1))
   (use (match_dup 2))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 18, 0);
  return \"LA	%0,1(0,0)\;CLCL	%1,%2\;BH	*+12\;BL	*+6\;SLR	%0,%0\;LNR	%0,%0\";
}"
   [(set_attr "length" "18")]
)

;;
;;- Move instructions.
;;

;
; movdi instruction pattern(s).
;

(define_insn ""
;;  [(set (match_operand:DI 0 "r_or_s_operand" "=dm")
;;        (match_operand:DI 1 "r_or_s_operand" "dim*fF"))]
  [(set (match_operand:DI 0 "r_or_s_operand" "=dS,m")
        (match_operand:DI 1 "r_or_s_operand" "diS*fF,d*fF"))]

  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STD	%1,140(,13)\;LM	%0,%N0,140(13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 4, 0);
	  return \"LR	%0,%1\;LR	%N0,%N1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 4, 0);
	  return \"SLR	%0,%0\;SLR	%N0,%N0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
  	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 6, 0);
	  return \"SLR	%0,%0\;LA	%N0,%c1(0,0)\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 8, 0);
	  return \"L	%0,%1\;SRDA	%0,32\";
	}
      mvs_check_page (0, 4, 0);
      return \"LM	%0,%N0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STD	%1,%0\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STM	%1,%N1,%0\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(8,%R0),%W1\";
}"
   [(set_attr "length" "8")]
)

(define_insn "movdi"
;;  [(set (match_operand:DI 0 "general_operand" "=d,dm")
;;	(match_operand:DI 1 "general_operand" "dimF,*fd"))]
  [(set (match_operand:DI 0 "general_operand" "=d,dm")
	(match_operand:DI 1 "r_or_s_operand" "diSF,*fd"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STD	%1,140(,13)\;LM	%0,%N0,140(13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 4, 0);
	  return \"LR	%0,%1\;LR	%N0,%N1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 4, 0);
	  return \"SLR	%0,%0\;SLR	%N0,%N0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
  	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 6, 0);
	  return \"SLR	%0,%0\;LA	%N0,%c1(0,0)\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 8, 0);
	  return \"L	%0,%1\;SRDA	%0,32\";
	}
      mvs_check_page (0, 4, 0);
      return \"LM	%0,%N0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STD	%1,%0\";
    }
  else if (REG_P (operands[1]))
    {
      /* hack alert -- for some reason, %N0 doesn't work 
       * when the mem ref is e.g. 168(r13,r1) ...  
       * add 4 and pray for the best .. */
      mvs_check_page (0, 8, 0);
      return \"ST	%1,%0\;ST	%N1,4+%N0\";
    }
  /* this is almost certainly not what is desired, let it break ... */
  mvs_check_page (0, 8, 0);
  return \"xxxST	%1,%0\;ST	%N1,%N0\";
}"
   [(set_attr "length" "8")]
)

;; we have got to provide a movdi alternative that will go from 
;; register to memory & back in its full glory.  However, we try to 
;; discourage its use by listing this alternative last.
;; The problem is that the instructions above only provide 
;; S-form style (base + displacement) mem access, while the
;; below provvides the full (base+index+displacement) RX-form.
;; These are rarely needed, but when needed they're needed.

(define_insn ""
  [(set (match_operand:DI 0 "general_operand" "=d,???m")
        (match_operand:DI 1 "general_operand" "???m,d"))]

  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 8, 0);
      return \"L	%0,%1\;L	%N0,4+%N1\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"ST	%1,%0\;ST	%N1,4+%N0\";
    }
  mvs_check_page (0, 6, 0);
  /* should never get here ... */
  return \"xxxxxxMVC	%O0(8,%R0),%W1\";
}"
   [(set_attr "length" "8")]
)

;
; movsi instruction pattern(s).
;

(define_insn ""
;;  [(set (match_operand:SI 0 "r_or_s_operand" "=dm,d,dm")
;;        (match_operand:SI 1 "r_or_s_operand" "diR,dim,*fF"))]
  [(set (match_operand:SI 0 "r_or_s_operand" "=d,dS,dm")
        (match_operand:SI 1 "general_operand" "dim,diS,di*fF"))]

  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STE	%1,140(,13)\;L	%0,140(,13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
 	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LA	%0,%c1(0,0)\";
	}
      mvs_check_page (0, 4, 0);
      return \"L	%0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STE	%1,%0\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"ST	%1,%0\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(4,%R0),%1\";
}"
   [(set_attr "length" "8")]
)

(define_insn "movsi"
  [(set (match_operand:SI 0 "general_operand" "=d,dm")
	(match_operand:SI 1 "general_operand" "dimF,*fd"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STE	%1,140(,13)\;L	%0,140(,13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LA	%0,%c1(0,0)\";
	}
      mvs_check_page (0, 4, 0);
      return \"L	%0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STE	%1,%0\";
    }
  mvs_check_page (0, 4, 0);
  return \"ST	%1,%0\";
}"
   [(set_attr "length" "8")]
)

;(define_expand "movsi"
;  [(set (match_operand:SI 0 "general_operand" "=d,dm")
;	(match_operand:SI 1 "general_operand" "dimF,*fd"))]
;  ""
;  "
;{
;  rtx op0, op1;
;
;  op0 = operands[0];
;  if (GET_CODE (op0) == CONST
;      && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SYMBOL_REF
;      && SYMBOL_REF_FLAG (XEXP (XEXP (op0, 0), 0)))
;    {
;      op0 = gen_rtx_MEM (SImode, copy_to_mode_reg (SImode, XEXP (op0, 0)));
;    }
;
;  op1 = operands[1];
;  if (GET_CODE (op1) == CONST
;      && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF
;      && SYMBOL_REF_FLAG (XEXP (XEXP (op1, 0), 0)))
;    {
;      op1 = gen_rtx_MEM (SImode, copy_to_mode_reg (SImode, XEXP (op1, 0)));
;    }
;
;  emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
;  DONE;
;}")

;
; movhi instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:HI 0 "r_or_s_operand" "=g")
        (match_operand:HI 1 "r_or_s_operand" "g"))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LA	%0,%c1(0,0)\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LH	%0,%H1\";
	}
      mvs_check_page (0, 4, 0);
      return \"LH	%0,%1\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STH	%1,%0\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 6, 0);
      return \"MVC	%O0(2,%R0),%H1\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(2,%R0),%1\";
}"
   [(set_attr "length" "6")]
)

(define_insn "movhi"
  [(set (match_operand:HI 0 "general_operand" "=d,m")
	(match_operand:HI 1 "general_operand" "g,d"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LA	%0,%c1(0,0)\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LH	%0,%H1\";
	}
      mvs_check_page (0, 4, 0);
      return \"LH	%0,%1\";
    }
  mvs_check_page (0, 4, 0);
  return \"STH	%1,%0\";
}"
   [(set_attr "length" "4")]
)

;
; movqi instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:QI 0 "r_or_s_operand" "=g")
	(match_operand:QI 1 "r_or_s_operand" "g"))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  if ((INTVAL (operands[1]) >= 0)
  	      && (unsigned) INTVAL (operands[1]) < 4096)
	    {
	      mvs_check_page (0, 4, 0);
	      return \"LA	%0,%c1(0,0)\";
	    }
	  mvs_check_page (0, 4, 0);
	  return \"L	%0,=F'%c1'\";
	}
      mvs_check_page (0, 4, 0);
      return \"IC	%0,%1\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STC	%1,%0\";
    }
  else if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"MVI	%0,%B1\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(1,%R0),%1\";
}"
   [(set_attr "length" "6")]
)

(define_insn "movqi"
  [(set (match_operand:QI 0 "general_operand" "=d,m")
	(match_operand:QI 1 "general_operand" "g,d"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  if ((INTVAL (operands[1]) >= 0)
  	      && (unsigned) INTVAL (operands[1]) < 4096)
	    {
	      mvs_check_page (0, 4, 0);
	      return \"LA	%0,%c1(0,0)\";
	    }
	  mvs_check_page (0, 4, 0);
	  return \"L	%0,=F'%c1'\";
	}
      mvs_check_page (0, 4, 0);
      return \"IC	%0,%1\";
    }
  mvs_check_page (0, 4, 0);
  return \"STC	%1,%0\";
}"
   [(set_attr "length" "4")]
)

;
; movstrictqi instruction pattern(s).
;

(define_insn "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "general_operand" "=d"))
	(match_operand:QI 1 "general_operand" "g"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"STC	%1,140(,13)\;IC	%0,140(,13)\";
    }
  mvs_check_page (0, 4, 0);
  return \"IC	%0,%1\";
}"
   [(set_attr "length" "8")]
)

;
; movstricthi instruction pattern(s).
;

(define_insn ""
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "=d"))
	(match_operand:HI 1 "r_or_s_operand" "g"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"STH	%1,140(,13)\;ICM	%0,3,140(13)\";
    }
  else if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"ICM	%0,3,%H1\";
    }
  mvs_check_page (0, 4, 0);
  return \"ICM	%0,3,%1\";
}"
   [(set_attr "length" "8")]
)

(define_insn "movstricthi"
  [(set (strict_low_part (match_operand:HI 0 "general_operand" "=dm"))
	(match_operand:HI 1 "general_operand" "d"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 8, 0);
      return \"STH	%1,140(,13)\;ICM	%0,3,140(13)\";
    }
  mvs_check_page (0, 4, 0);
  return \"STH	%1,%0\";
}"
   [(set_attr "length" "8")]
)

;
; movdf instruction pattern(s).
;

(define_insn ""
;;  [(set (match_operand:DF 0 "r_or_s_operand" "=fm,fm,*dm")
;;        (match_operand:DF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
  [(set (match_operand:DF 0 "general_operand" "=f,m,fS,*dS,???d")
      (match_operand:DF 1 "general_operand" "fmF,fF,*dS,fSF,???d"))]

  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LDR	%0,%1\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STM	%1,%N1,140(13)\;LD	%0,140(,13)\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 2, 0);
	  return \"SDR	%0,%0\";
	}
      mvs_check_page (0, 4, 0);
      return \"LD	%0,%1\";
    }
  if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 12, 0);
	  return \"STD	%1,140(,13)\;LM	%0,%N0,140(13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 4, 0);
	  return \"LR	%0,%1\;LR	%N0,%N1\";
	}
      mvs_check_page (0, 4, 0);
      return \"LM	%0,%N0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STD	%1,%0\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STM	%1,%N1,%0\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(8,%R0),%W1\";
}"
   [(set_attr "length" "12")]
)

(define_insn "movdf"
;;  [(set (match_operand:DF 0 "general_operand" "=f,fm,m,*d")
;;	(match_operand:DF 1 "general_operand" "fmF,*d,f,fmF"))]
  [(set (match_operand:DF 0 "general_operand" "=f,m,fS,*d,???d")
      (match_operand:DF 1 "general_operand" "fmF,f,*d,SfF,???d"))]

  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LDR	%0,%1\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STM	%1,%N1,140(13)\;LD	%0,140(,13)\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 2, 0);
	  return \"SDR	%0,%0\";
	}
      mvs_check_page (0, 4, 0);
      return \"LD	%0,%1\";
    }
  else if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 12, 0);
	  return \"STD	%1,140(,13)\;LM	%0,%N0,140(13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 4, 0);
	  return \"LR	%0,%1\;LR	%N0,%N1\";
	}
      mvs_check_page (0, 4, 0);
      return \"LM	%0,%N0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STD	%1,%0\";
    }
  mvs_check_page (0, 4, 0);
  return \"STM	%1,%N1,%0\";
}"
   [(set_attr "length" "12")]
)

;
; movsf instruction pattern(s).
;

(define_insn ""
;;  [(set (match_operand:SF 0 "r_or_s_operand" "=fm,fm,*dm")
;;        (match_operand:SF 1 "r_or_s_operand" "fmF,*dm,fmF"))]
;;  [(set (match_operand:SF 0 "general_operand" "=f,m,fm,*d,S")
;;         (match_operand:SF 1 "general_operand" "fmF,fF,*d,fmF,S"))]
  [(set (match_operand:SF 0 "general_operand" "=f*d,fm,S,???d")
        (match_operand:SF 1 "general_operand" "fmF,fF*d,S,???d"))]

  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LER	%0,%1\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"ST	%1,140(,13)\;LE	%0,140(,13)\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 2, 0);
	  return \"SER	%0,%0\";
	}
      mvs_check_page (0, 4, 0);
      return \"LE	%0,%1\";
    }
  else if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STE	%1,140(,13)\;L	%0,140(,13)\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LR	%0,%1\";
	}
      mvs_check_page (0, 4, 0);
      return \"L	%0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STE	%1,%0\";
    }
  else if (REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"ST	%1,%0\";
    }
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(4,%R0),%1\";
}"
   [(set_attr "length" "8")]
)

(define_insn "movsf"
  [(set (match_operand:SF 0 "general_operand" "=f,fm,m,*d")
	(match_operand:SF 1 "general_operand" "fmF,*d,f,fmF"))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 2, 0);
	  return \"LER	%0,%1\";
	}
      if (REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"ST	%1,140(,13)\;LE	%0,140(,13)\";
	}
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_SET (operands[0], operands[1]);
	  mvs_check_page (0, 2, 0);
	  return \"SER	%0,%0\";
	}
      mvs_check_page (0, 4, 0);
      return \"LE	%0,%1\";
    }
  else if (REG_P (operands[0]))
    {
      if (FP_REG_P (operands[1]))
	{
	  mvs_check_page (0, 8, 0);
	  return \"STE	%1,140(,13)\;L	%0,140(,13)\";
	}
      mvs_check_page (0, 4, 0);
      return \"L	%0,%1\";
    }
  else if (FP_REG_P (operands[1]))
    {
      mvs_check_page (0, 4, 0);
      return \"STE	%1,%0\";
    }
  mvs_check_page (0, 4, 0);
  return \"ST	%1,%0\";
}"
   [(set_attr "length" "8")]
)

;
; clrstrsi instruction pattern(s).
; memset a block of bytes to zero.
; block must be less than 16M (24 bits) in length
;
(define_expand "clrstrsi"
  [(set (match_operand:BLK 0 "general_operand" "g")
        (const_int 0)) 
   (use (match_operand:SI  1 "general_operand" ""))
   (match_operand 2 "" "")]
   ""
   "
{
/*
  XXX bogus, i think, unless change_address has a side effet we need
  rtx op0;

  op0 = XEXP (operands[0], 0);
  if (GET_CODE (op0) == REG
      || (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == REG
	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
	  && (unsigned) INTVAL (XEXP (op0, 1)) < 4096))
    op0 = operands[0];
  else
    op0 = change_address (operands[0], VOIDmode,
			  copy_to_mode_reg (SImode, op0));

*/
  {
        /* implementation suggested by  Richard Henderson <rth@cygnus.com> */
        rtx reg1 = gen_reg_rtx (DImode);
        rtx reg2 = gen_reg_rtx (DImode);
        rtx mem1 = operands[0];
        rtx zippo = gen_rtx_CONST_INT (SImode, 0);
        rtx len = operands[1];
        if (!CONSTANT_P (len))
          len = force_reg (SImode, len);

        /* Load up the address+length pairs.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
                        force_operand (XEXP (mem1, 0), NULL_RTX));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);

        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), zippo);
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), zippo);

        /* Copy! */
        emit_insn (gen_movstrsi_1 (reg1, reg2));
  }
  DONE;
}")

;
; movstrsi instruction pattern(s).
; block must be less than 16M (24 bits) in length

(define_expand "movstrsi"
  [(set (match_operand:BLK 0 "general_operand" "")
        (match_operand:BLK 1 "general_operand" ""))
   (use (match_operand:SI  2 "general_operand" ""))
   (match_operand 3 "" "")]
   ""
   "
{
  rtx op0, op1;

  op0 = XEXP (operands[0], 0);
  if (GET_CODE (op0) == REG
      || (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == REG
	  && GET_CODE (XEXP (op0, 1)) == CONST_INT
	  && (unsigned) INTVAL (XEXP (op0, 1)) < 4096))
    op0 = operands[0];
  else
    op0 = change_address (operands[0], VOIDmode,
			  copy_to_mode_reg (SImode, op0));

  op1 = XEXP (operands[1], 0);
  if (GET_CODE (op1) == REG
      || (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1, 0)) == REG
	  && GET_CODE (XEXP (op1, 1)) == CONST_INT
	  && (unsigned) INTVAL (XEXP (op1, 1)) < 4096))
    op1 = operands[1];
  else
    op1 = change_address (operands[1], VOIDmode,
			  copy_to_mode_reg (SImode, op1));

  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 256)
    emit_insn (gen_rtx_PARALLEL (VOIDmode,
			gen_rtvec (2,
				   gen_rtx_SET (VOIDmode, op0, op1),
				   gen_rtx_USE (VOIDmode, operands[2]))));

  else
    {
        /* implementation provided by  Richard Henderson <rth@cygnus.com> */
        rtx reg1 = gen_reg_rtx (DImode);
        rtx reg2 = gen_reg_rtx (DImode);
        rtx mem1 = operands[0];
        rtx mem2 = operands[1];
        rtx len = operands[2];
        if (!CONSTANT_P (len))
          len = force_reg (SImode, len);

        /* Load up the address+length pairs.  */
        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0),
                        force_operand (XEXP (mem1, 0), NULL_RTX));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len);

        emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0),
                        force_operand (XEXP (mem2, 0), NULL_RTX));
        emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len);

        /* Copy! */
        emit_insn (gen_movstrsi_1 (reg1, reg2));
    }
  DONE;
}")

; Move a block that is less than 256 bytes in length.

(define_insn ""
  [(set (match_operand:BLK 0 "s_operand" "=m")
	(match_operand:BLK 1 "s_operand" "m"))
   (use (match_operand 2 "immediate_operand" "I"))]
  "((unsigned) INTVAL (operands[2]) < 256)"
  "*
{
  check_label_emit ();
  mvs_check_page (0, 6, 0);
  return \"MVC	%O0(%c2,%R0),%1\";
}"
   [(set_attr "length" "6")]
)

; Move a block that is larger than 255 bytes in length.

(define_insn "movstrsi_1"
  [(set (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "+d") 0))
        (mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "+d") 0)))
   (use (match_dup 0))
   (use (match_dup 1))
   (clobber (match_dup 0))
   (clobber (match_dup 1))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"MVCL	%0,%1\";
}"
   [(set_attr "length" "2")]
)

;;
;;- Conversion instructions.
;;

;
; extendsidi2 instruction pattern(s).
;

(define_expand "extendsidi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
        (sign_extend:DI (match_operand:SI 1 "general_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[1]) != CONST_INT)
    {
      emit_insn (gen_rtx_SET (VOIDmode,
		  operand_subword (operands[0], 0, 1, DImode), operands[1]));
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_ASHIFTRT (DImode, operands[0],
				gen_rtx_CONST_INT (SImode, 32))));
    }
  else
    {
      if (INTVAL (operands[1]) < 0)
	{
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (operands[0], 0, 1, DImode),
			       gen_rtx_CONST_INT (SImode, -1)));
        }
      else
	{
	  emit_insn (gen_rtx_SET (VOIDmode,
				operand_subword (operands[0], 0, 1, DImode),
			       gen_rtx_CONST_INT (SImode, 0)));
        }
      emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (SImode, operands[0]),
			   operands[1]));
    }
  DONE;
}")

;
; extendhisi2 instruction pattern(s).
;

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "general_operand" "=d,m")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "g,d")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      if (REG_P (operands[1]))
        if (REGNO (operands[0]) != REGNO (operands[1]))
	  {
	    mvs_check_page (0, 10, 0);
            return \"LR	%0,%1\;SLL	%0,16\;SRA	%0,16\";
	  }
        else
          return \"\"; /* Should be empty.  16-bits regs are always 32-bits.  */
      if (operands[1] == const0_rtx)
	{
	  CC_STATUS_INIT;
	  mvs_check_page (0, 2, 0);
	  return \"SLR	%0,%0\";
	}
      if (GET_CODE (operands[1]) == CONST_INT
 	  && (unsigned) INTVAL (operands[1]) < 4096)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LA	%0,%c1(0,0)\";
	}
      if (GET_CODE (operands[1]) == CONST_INT)
	{
	  mvs_check_page (0, 4, 0);
	  return \"LH	%0,%H1\";
	}
      mvs_check_page (0, 4, 0);
      return \"LH	%0,%1\";
    }
  mvs_check_page (0, 12, 0);
  return \"SLL	%1,16\;SRA	%1,16\;ST	%1,%0\";
}"
   [(set_attr "length" "12")]
)

;
; extendqisi2 instruction pattern(s).
;

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(sign_extend:SI (match_operand:QI 1 "general_operand" "0mi")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_SET (operands[0], operands[1]);
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"SLL	%0,24\;SRA	%0,24\";
    }
  if (s_operand (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"ICM	%0,8,%1\;SRA	%0,24\";
    }
  mvs_check_page (0, 12, 0);
  return \"IC	%0,%1\;SLL	%0,24\;SRA	%0,24\";
}"
   [(set_attr "length" "12")]
)

;
; extendqihi2 instruction pattern(s).
;

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(sign_extend:HI (match_operand:QI 1 "general_operand" "0m")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_SET (operands[0], operands[1]);
  if (REG_P (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"SLL	%0,24\;SRA	%0,24\";
    }
  if (s_operand (operands[1]))
    {
      mvs_check_page (0, 8, 0);
      return \"ICM	%0,8,%1\;SRA	%0,24\";
    }
  mvs_check_page (0, 12, 0);
  return \"IC	%0,%1\;SLL	%0,24\;SRA	%0,24\";
}"
   [(set_attr "length" "12")]
)

;
; zero_extendsidi2 instruction pattern(s).
;

(define_expand "zero_extendsidi2"
  [(set (match_operand:DI 0 "register_operand" "=d")
        (zero_extend:DI (match_operand:SI 1 "general_operand" "")))]
  ""
  "
{
      emit_insn (gen_rtx_SET (VOIDmode,
		  operand_subword (operands[0], 0, 1, DImode), operands[1]));
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_LSHIFTRT (DImode, operands[0],
				gen_rtx_CONST_INT (SImode, 32))));
  DONE;
}")

;
; zero_extendhisi2 instruction pattern(s).
;

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(zero_extend:SI (match_operand:HI 1 "general_operand" "0")))]
  ""
  "*
{
  check_label_emit ();
  /* AND only sets zero/not-zero bits not the arithmetic bits ... */
  CC_STATUS_INIT;
  mvs_check_page (0, 4, 4);
  return \"N	%1,=X'0000FFFF'\";
}"
   [(set_attr "length" "4")]
)

;
; zero_extendqisi2 instruction pattern(s).
;

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "general_operand" "=d,&d")
	(zero_extend:SI (match_operand:QI 1 "general_operand" "0i,m")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      /* AND only sets zero/not-zero bits not the arithmetic bits ... */
      CC_STATUS_INIT;
      mvs_check_page (0, 4, 4);
      return \"N	%0,=X'000000FF'\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"LA	%0,%c1(0,0)\";
    }
  CC_STATUS_INIT;
  mvs_check_page (0, 8, 0);
  return \"SLR	%0,%0\;IC	%0,%1\";
}"
   [(set_attr "length" "8")]
)

;
; zero_extendqihi2 instruction pattern(s).
;

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "general_operand" "=d,&d")
	(zero_extend:HI (match_operand:QI 1 "general_operand" "0i,m")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[1]))
    {
      /* AND only sets zero/not-zero bits not the arithmetic bits ... */
      CC_STATUS_INIT;
      mvs_check_page (0, 4, 4);
      return \"N	%0,=X'000000FF'\";
    }
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"LA	%0,%c1(0,0)\";
    }
  CC_STATUS_INIT;
  mvs_check_page (0, 8, 0);
  return \"SLR	%0,%0\;IC	%0,%1\";
}"
   [(set_attr "length" "8")]
)

;
; truncsihi2 instruction pattern(s).
;

(define_insn "truncsihi2"
  [(set (match_operand:HI 0 "general_operand" "=d,m")
	(truncate:HI (match_operand:SI 1 "general_operand" "0,d")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      CC_STATUS_SET (operands[0], operands[1]);
      mvs_check_page (0, 8, 0);
      return \"SLL	%0,16\;SRA	%0,16\";
    }
  mvs_check_page (0, 4, 0);
  return \"STH	%1,%0\";
}"
   [(set_attr "length" "8")]
)

;
; fix_truncdfsi2 instruction pattern(s).
;

(define_insn "fix_truncdfsi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
        (fix:SI (truncate:DF (match_operand:DF 1 "general_operand" "+f"))))
	(clobber (reg:DF 16))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;
  if (REGNO (operands[1]) == 16)
    {
      mvs_check_page (0, 12, 8);
      return \"AD	0,=XL8'4F08000000000000'\;STD	0,140(,13)\;L	%0,144(,13)\";
    }
  mvs_check_page (0, 14, 8);
  return \"LDR	0,%1\;AD	0,=XL8'4F08000000000000'\;STD	0,140(,13)\;L	%0,144(,13)\";
}"
   [(set_attr "length" "14")]
)

;
; floatsidf2 instruction pattern(s).
;
; Uses the float field of the TCA.
;

(define_insn "floatsidf2"
  [(set (match_operand:DF 0 "general_operand" "=f")
        (float:DF (match_operand:SI 1 "general_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;
  mvs_check_page (0, 16, 8);
  return \"ST	%1,508(,12)\;XI	508(12),128\;LD	%0,504(,12)\;SD	%0,=XL8'4E00000080000000'\";
}"
   [(set_attr "length" "16")]
)

;
; truncdfsf2 instruction pattern(s).
;

(define_insn "truncdfsf2"
  [(set (match_operand:SF 0 "general_operand" "=f")
        (float_truncate:SF (match_operand:DF 1 "general_operand" "f")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LRER	%0,%1\";
}"
   [(set_attr "length" "2")]
)

;
; extendsfdf2 instruction pattern(s).
; 

(define_insn "extendsfdf2"
  [(set (match_operand:DF 0 "general_operand" "=f")
        (float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_SET (0, const0_rtx);
  if (FP_REG_P (operands[1]))
    {
      if (REGNO (operands[0]) == REGNO (operands[1]))
	{
	  mvs_check_page (0, 10, 0);
	  return \"STE	%1,140(,13)\;SDR	%0,%0\;LE	%0,140(,13)\";
	}
      mvs_check_page (0, 4, 0);
      return \"SDR	%0,%0\;LER	%0,%1\";
    }
  mvs_check_page (0, 6, 0);
  return \"SDR	%0,%0\;LE	%0,%1\";
}"
   [(set_attr "length" "10")]
)

;;
;;- Add instructions.
;;

;
; adddi3 instruction pattern(s).
;
;
;(define_expand "adddi3"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(plus:DI (match_operand:DI 1 "general_operand" "")
;		 (match_operand:DI 2 "general_operand" "")))]
;  ""
;  "
;{
;  rtx label = gen_label_rtx ();
;  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
;  rtx op0_low = gen_lowpart (SImode, operands[0]);
;	
;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
;		    gen_rtx_PLUS (SImode,
;			    operand_subword (operands[1], 0, 1, DImode),
;			    operand_subword (operands[2], 0, 1, DImode))));
;  emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
;	      gen_rtx_SET (VOIDmode, op0_low,
;		      gen_rtx_PLUS (SImode, gen_lowpart (SImode, operands[1]),
;			      gen_lowpart (SImode, operands[2]))),
;	      gen_rtx_USE (VOIDmode, gen_rtx_LABEL_REF (VOIDmode, label)))));
;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
;		    gen_rtx_PLUS (SImode, op0_high,
;			    gen_rtx_CONST_INT (SImode, 1))));
;  emit_label (label);
;  DONE;
;}")

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=d")
	(plus:SI (match_operand:SI 1 "general_operand" "%0")
		 (match_operand:SI 2 "general_operand" "g")))
   (use (label_ref (match_operand 3 "" "")))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  int onpage;

  check_label_emit ();
  onpage = mvs_check_label (CODE_LABEL_NUMBER (operands[3]));
  if (REG_P (operands[2]))
    {
      if (!onpage)
	{
	  mvs_check_page (0, 8, 4);
	  return \"ALR	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
	}
      if (mvs_check_page (0, 6, 0))
	{
	  mvs_check_page (0, 2, 4);
	  return \"ALR	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
	}
      return \"ALR	%0,%2\;BC	12,%l3\";
    }
  if (!onpage)
    {
      mvs_check_page (0, 10, 4);
      return \"AL	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
    }
  if (mvs_check_page (0, 8 ,0))
    {
      mvs_check_page (0, 2, 4);
      return \"AL	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
    }
  return \"AL	%0,%2\;BC	12,%l3\";
}"
   [(set_attr "length" "10")]
)

;
; addsi3 instruction pattern(s).
;
; The following insn is used when it is known that operand one is an address,
; frame, stack or argument pointer, and operand two is a constant that is
; small enough to fit in the displacement field.
; Notice that we can't allow the frame pointer to used as a normal register
; because of this insn.
;

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d")
	(plus:SI (match_operand:SI 1 "general_operand" "%a")
		 (match_operand:SI 2 "immediate_operand" "J")))]
  "((REGNO (operands[1]) == FRAME_POINTER_REGNUM || REGNO (operands[1]) == ARG_POINTER_REGNUM || REGNO (operands[1]) == STACK_POINTER_REGNUM) && (unsigned) INTVAL (operands[2]) < 4096)"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* add assumes CC but LA doesnt set CC */
  mvs_check_page (0, 4, 0);
  return \"LA	%0,%c2(,%1)\";
}"
   [(set_attr "length" "4")]
)

; This insn handles additions that are relative to the frame pointer.

(define_insn ""
  [(set (match_operand:SI 0 "register_operand" "=d")
         (plus:SI (match_operand:SI 1 "register_operand" "%a")
                  (match_operand:SI 2 "immediate_operand" "i")))]
  "REGNO (operands[1]) == FRAME_POINTER_REGNUM"
  "*
{
  check_label_emit ();
  if ((unsigned) INTVAL (operands[2]) < 4096)
    {
      CC_STATUS_INIT;  /* add assumes CC but LA doesnt set CC */
      mvs_check_page (0, 4, 0);
      return \"LA	%0,%c2(,%1)\";
    }
  if (REGNO (operands[1]) == REGNO (operands[0]))
    {
      CC_STATUS_INIT;
      mvs_check_page (0, 4, 0);
      return \"A	%0,%2\";
    }
  mvs_check_page (0, 6, 0);
  return \"L	%0,%2\;AR	%0,%1\";
}"
   [(set_attr "length" "6")]
)

;;
;; The CC status bits for the arithmetic instructions are handled
;; in the NOTICE_UPDATE_CC macro (yeah???) and so they do not need
;; to be set below.  They only need to be invalidated if *not* set 
;; (e.g. by BCTR) ... yeah I think that's right ...
;; 

(define_insn "addsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(plus:SI (match_operand:SI 1 "general_operand" "%0")
		 (match_operand:SI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"AR	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) == -1)
	{
          CC_STATUS_INIT;  /* add assumes CC but BCTR doesnt set CC */
	  mvs_check_page (0, 2, 0);
	  return \"BCTR	%0,0\";
	}
    }
  mvs_check_page (0, 4, 0);
  return \"A	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; addhi3 instruction pattern(s).
;

(define_insn "addhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(plus:HI (match_operand:HI 1 "general_operand" "%0")
		 (match_operand:HI 2 "general_operand" "dmi")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 8, 0);
      return \"STH	%2,140(,13)\;AH	%0,140(,13)\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) == -1)
	{
          CC_STATUS_INIT;  /* add assumes CC but BCTR doesnt set CC */
	  mvs_check_page (0, 2, 0);
	  return \"BCTR	%0,0\";
	}
      mvs_check_page (0, 4, 0);
      return \"AH	%0,%H2\";
    }
  mvs_check_page (0, 4, 0);
  return \"AH	%0,%2\";
}"
   [(set_attr "length" "8")]
)

;
; addqi3 instruction pattern(s).
;

(define_insn "addqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(plus:QI (match_operand:QI 1 "general_operand" "%a")
		 (match_operand:QI 2 "general_operand" "ai")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* add assumes CC but LA doesnt set CC */
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2]))
    return \"LA	%0,0(%1,%2)\";
  return \"LA	%0,%B2(,%1)\";
}"
   [(set_attr "length" "4")]
)

;
; adddf3 instruction pattern(s).
;

(define_insn "adddf3"
  [(set (match_operand:DF 0 "general_operand" "=f")
	(plus:DF (match_operand:DF 1 "general_operand" "%0")
		 (match_operand:DF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"ADR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"AD	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; addsf3 instruction pattern(s).
;

(define_insn "addsf3"
  [(set (match_operand:SF 0 "general_operand" "=f")
	(plus:SF (match_operand:SF 1 "general_operand" "%0")
		 (match_operand:SF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"AER	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"AE	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Subtract instructions.
;;

;
; subdi3 instruction pattern(s).
;
;
;(define_expand "subdi3"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(minus:DI (match_operand:DI 1 "general_operand" "")
;		  (match_operand:DI 2 "general_operand" "")))]
;  ""
;  "
;{
;  rtx label = gen_label_rtx ();
;  rtx op0_high = operand_subword (operands[0], 0, 1, DImode);
;  rtx op0_low = gen_lowpart (SImode, operands[0]);
;	
;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
;		    gen_rtx_MINUS (SImode,
;			      operand_subword (operands[1], 0, 1, DImode),
;			      operand_subword (operands[2], 0, 1, DImode))));
;  emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
;		    gen_rtx_SET (VOIDmode, op0_low,
;			      gen_rtx_MINUS (SImode,
;				      gen_lowpart (SImode, operands[1]),
;				      gen_lowpart (SImode, operands[2]))),
;		    gen_rtx_USE (VOIDmode,
;			      gen_rtx_LABEL_REF (VOIDmode, label)))));
;  emit_insn (gen_rtx_SET (VOIDmode, op0_high,
;		      gen_rtx_MINUS (SImode, op0_high,
;			      gen_rtx_CONST_INT (SImode, 1))));
;  emit_label (label);
;  DONE;
;}")

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=d")
	(minus:SI (match_operand:SI 1 "general_operand" "0")
		  (match_operand:SI 2 "general_operand" "g")))
   (use (label_ref (match_operand 3 "" "")))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  int onpage;

  check_label_emit ();
  CC_STATUS_INIT;
  onpage = mvs_check_label (CODE_LABEL_NUMBER (operands[3]));
  if (REG_P (operands[2]))
    {
      if (!onpage)
	{
	  mvs_check_page (0, 8, 4);
	  return \"SLR	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
	}
      if (mvs_check_page (0, 6, 0))
	{
	  mvs_check_page (0, 2, 4);
	  return \"SLR	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
	}
      return \"SLR	%0,%2\;BC	12,%l3\";
    }
  if (!onpage)
    {
      mvs_check_page (0, 10, 4);
      return \"SL	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
    }
  if (mvs_check_page (0, 8, 0))
    {
      mvs_check_page (0, 2, 4);
      return \"SL	%0,%2\;L	14,=A(%l3)\;BCR	12,14\";
    }
  return \"SL	%0,%2\;BC	12,%l3\";
}"
   [(set_attr "length" "10")]
)

;
; subsi3 instruction pattern(s).
;

(define_insn "subsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(minus:SI (match_operand:SI 1 "general_operand" "0")
		  (match_operand:SI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"SR	%0,%2\";
    }
  if (operands[2] == const1_rtx)
    {
      CC_STATUS_INIT;  /* subtract assumes CC but BCTR doesnt set CC */
      mvs_check_page (0, 2, 0);
      return \"BCTR	%0,0\";
    }
  mvs_check_page (0, 4, 0);
  return \"S	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; subhi3 instruction pattern(s).
;

(define_insn "subhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(minus:HI (match_operand:HI 1 "general_operand" "0")
		  (match_operand:HI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 8, 0);
      return \"STH	%2,140(,13)\;SH	%0,140(,13)\";
    }
  if (operands[2] == const1_rtx)
    {
      CC_STATUS_INIT;  /* subtract assumes CC but BCTR doesnt set CC */
      mvs_check_page (0, 2, 0);
      return \"BCTR	%0,0\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"SH	%0,%H2\";
    }
  mvs_check_page (0, 4, 0);
  return \"SH	%0,%2\";
}"
   [(set_attr "length" "8")]
)

;
; subqi3 instruction pattern(s).
;

(define_expand "subqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(minus:QI (match_operand:QI 1 "general_operand" "0")
		  (match_operand:QI 2 "general_operand" "di")))]
  ""
  "
{
  if (REG_P (operands[2]))
    {
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_MINUS (QImode, operands[1], operands[2])));
    }
  else
    {
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_PLUS (QImode, operands[1],
				 negate_rtx (QImode, operands[2]))));
    }
  DONE;
}")

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=d")
	(minus:QI (match_operand:QI 1 "register_operand" "0")
		 (match_operand:QI 2 "register_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"SR	%0,%2\";
}"
   [(set_attr "length" "2")]
)

;
; subdf3 instruction pattern(s).
;

(define_insn "subdf3"
  [(set (match_operand:DF 0 "general_operand" "=f")
	(minus:DF (match_operand:DF 1 "general_operand" "0")
		  (match_operand:DF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"SDR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"SD	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; subsf3 instruction pattern(s).
;

(define_insn "subsf3"
  [(set (match_operand:SF 0 "general_operand" "=f")
	(minus:SF (match_operand:SF 1 "general_operand" "0")
		  (match_operand:SF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"SER	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"SE	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Multiply instructions.
;;

;
; mulsi3 instruction pattern(s).
;

(define_expand "mulsi3"
  [(set (match_operand:SI 0 "general_operand" "")
	(mult:SI (match_operand:SI 1 "general_operand" "")
		 (match_operand:SI 2 "general_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[1]) == CONST_INT
      && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
    {
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			  gen_rtx_MULT (SImode, operands[2], operands[1])));
    }
  else if (GET_CODE (operands[2]) == CONST_INT
	   && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))
    {
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			  gen_rtx_MULT (SImode, operands[1], operands[2])));
    }
  else
    {
      rtx r = gen_reg_rtx (DImode);

      /* XXX trouble.  Below we generate some rtx's that model what
       * is really supposed to happen with multiply on the 370/390
       * hardware, and that is all well & god.  However, during optimization
       * it can happen that the two operands are exchanged (after all, 
       * multiplication is commutitive), in which case the doubleword
       * ends up in memory and everything is hosed.  The gen_reg_rtx
       * should have kept it in a reg ...  We hack around this
       * below, in the M/MR isntruction pattern, and constrain it to
       * \"di\" instead of \"g\".  But this still ends up with lots & lots of
       * movement between registers & memory and is an awful waste.
       * Dunno how to untwist it elegantly; but it seems to work for now.
       */
      emit_insn (gen_rtx_SET (VOIDmode,
			  gen_rtx_SUBREG (SImode, r, 1), operands[1]));
      emit_insn (gen_rtx_SET (VOIDmode, r,
			  gen_rtx_MULT (SImode, r, operands[2])));
      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			  gen_rtx_SUBREG (SImode, r, 1)));
    }
  DONE;
}")

(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=d")
	(mult:SI (match_operand:SI 1 "general_operand" "%0")
		 (match_operand:SI 2 "immediate_operand" "K")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  return \"MH	%0,%H2\";
}"
   [(set_attr "length" "4")]
)

;; XXX see comments in mulsi above.
(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(mult:SI (match_operand:DI 1 "general_operand" "%0")
;; XXX see above (match_operand:SI 2 "general_operand" "g")))]
		 (match_operand:SI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"MR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"M	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; muldf3 instruction pattern(s).
;

(define_insn "muldf3"
  [(set (match_operand:DF 0 "general_operand" "=f")
	(mult:DF (match_operand:DF 1 "general_operand" "%0")
		 (match_operand:DF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"MDR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"MD	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; mulsf3 instruction pattern(s).
;

(define_insn "mulsf3"
  [(set (match_operand:SF 0 "general_operand" "=f")
	(mult:SF (match_operand:SF 1 "general_operand" "%0")
		 (match_operand:SF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"MER	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"ME	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Divide instructions.
;;

;
; divsi3 instruction pattern(s).
;

(define_expand "divsi3"
  [(set (match_operand:SI 0 "general_operand" "")
	(div:SI (match_operand:SI 1 "general_operand" "")
		(match_operand:SI 2 "general_operand" "")))]
  ""
  "
{
  rtx r = gen_reg_rtx (DImode);

  emit_insn (gen_extendsidi2 (r, operands[1]));
  emit_insn (gen_rtx_SET (VOIDmode, r,
			gen_rtx_DIV (SImode, r, operands[2])));
  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_SUBREG (SImode, r, 1)));
  DONE;
}")


;
; udivsi3 instruction pattern(s).
;

(define_expand "udivsi3"
  [(set (match_operand:SI 0 "general_operand" "")
	(udiv:SI (match_operand:SI 1 "general_operand" "")
		 (match_operand:SI 2 "general_operand" "")))]
  ""
  "
{
  rtx dr = gen_reg_rtx (DImode);
  rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
  rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1);


  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) > 0)
	{
	  emit_insn (gen_zero_extendsidi2 (dr, operands[1]));
	  emit_insn (gen_rtx_SET (VOIDmode, dr,
			gen_rtx_DIV (SImode, dr, operands[2])));
	}
      else
	{
	  rtx label1 = gen_label_rtx ();

	  emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
	  emit_insn (gen_rtx_SET (VOIDmode, dr_1, const0_rtx));
	  emit_insn (gen_cmpsi (dr_0, operands[2]));
	  emit_jump_insn (gen_bltu (label1));
	  emit_insn (gen_rtx_SET (VOIDmode, dr_1, const1_rtx));
	  emit_label (label1);
	}
    }
  else
    {
      rtx label1 = gen_label_rtx ();
      rtx label2 = gen_label_rtx ();
      rtx label3 = gen_label_rtx ();
      rtx sr = gen_reg_rtx (SImode);

      emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
      emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
      emit_insn (gen_rtx_SET (VOIDmode, dr_1, const0_rtx));
      emit_insn (gen_cmpsi (sr, dr_0));
      emit_jump_insn (gen_bgtu (label3));
      emit_insn (gen_cmpsi (sr, const1_rtx));
      emit_jump_insn (gen_blt (label2));
      emit_insn (gen_cmpsi (sr, const1_rtx));
      emit_jump_insn (gen_beq (label1));
      emit_insn (gen_rtx_SET (VOIDmode, dr,
			  gen_rtx_LSHIFTRT (DImode, dr,
				    gen_rtx_CONST_INT (SImode, 32))));
      emit_insn (gen_rtx_SET (VOIDmode, dr,
		    gen_rtx_DIV (SImode, dr, sr)));
      emit_jump_insn (gen_jump (label3));
      emit_label (label1);
      emit_insn (gen_rtx_SET (VOIDmode, dr_1, dr_0));
      emit_jump_insn (gen_jump (label3));
      emit_label (label2);
      emit_insn (gen_rtx_SET (VOIDmode, dr_1, const1_rtx));
      emit_label (label3);
    }
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_1));

  DONE;
}")

; This is used by divsi3 & udivsi3.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(div:SI (match_operand:DI 1 "register_operand" "0")
		(match_operand:SI 2 "general_operand" "dm")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"DR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"D	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; divdf3 instruction pattern(s).
;

(define_insn "divdf3"
  [(set (match_operand:DF 0 "general_operand" "=f")
        (div:DF (match_operand:DF 1 "general_operand" "0")
                (match_operand:DF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"DDR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"DD	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; divsf3 instruction pattern(s).
;

(define_insn "divsf3"
  [(set (match_operand:SF 0 "general_operand" "=f")
        (div:SF (match_operand:SF 1 "general_operand" "0")
                (match_operand:SF 2 "general_operand" "fmF")))]
  ""
  "*
{
  check_label_emit ();
  if (FP_REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"DER	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"DE	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Modulo instructions.
;;

;
; modsi3 instruction pattern(s).
;

(define_expand "modsi3"
  [(set (match_operand:SI 0 "general_operand" "")
	(mod:SI (match_operand:SI 1 "general_operand" "")
		(match_operand:SI 2 "general_operand" "")))]
  ""
  "
{
  rtx r = gen_reg_rtx (DImode);

  emit_insn (gen_extendsidi2 (r, operands[1]));
  emit_insn (gen_rtx_SET (VOIDmode, r,
			gen_rtx_MOD (SImode, r, operands[2])));
  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
			gen_rtx_SUBREG (SImode, r, 0)));
  DONE;
}")

;
; umodsi3 instruction pattern(s).
;

(define_expand "umodsi3"
  [(set (match_operand:SI 0 "general_operand" "")
	(umod:SI (match_operand:SI 1 "general_operand" "")
		 (match_operand:SI 2 "general_operand" "")))]
  ""
  "
{
  rtx dr = gen_reg_rtx (DImode);
  rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0);
  rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1);

  emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));

  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) > 0)
	{
	  emit_insn (gen_rtx_SET (VOIDmode, dr,
			      gen_rtx_LSHIFTRT (DImode, dr,
					gen_rtx_CONST_INT (SImode, 32))));
	  emit_insn (gen_rtx_SET (VOIDmode, dr,
			gen_rtx_MOD (SImode, dr, operands[2])));
	}
      else
	{
	  rtx label1 = gen_label_rtx ();
	  rtx sr = gen_reg_rtx (SImode);

	  emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
	  emit_insn (gen_cmpsi (dr_0, sr));
	  emit_jump_insn (gen_bltu (label1));
	  emit_insn (gen_rtx_SET (VOIDmode, sr, gen_rtx_ABS (SImode, sr)));
	  emit_insn (gen_rtx_SET (VOIDmode, dr_0,
			      gen_rtx_PLUS (SImode, dr_0, sr)));
	  emit_label (label1);
	}
    }
  else
    {
      rtx label1 = gen_label_rtx ();
      rtx label2 = gen_label_rtx ();
      rtx label3 = gen_label_rtx ();
      rtx sr = gen_reg_rtx (SImode);

      emit_insn (gen_rtx_SET (VOIDmode, dr_0, operands[1]));
      emit_insn (gen_rtx_SET (VOIDmode, sr, operands[2]));
      emit_insn (gen_cmpsi (sr, dr_0));
      emit_jump_insn (gen_bgtu (label3));
      emit_insn (gen_cmpsi (sr, const1_rtx));
      emit_jump_insn (gen_blt (label2));
      emit_insn (gen_cmpsi (sr, const1_rtx));
      emit_jump_insn (gen_beq (label1));
      emit_insn (gen_rtx_SET (VOIDmode, dr,
			  gen_rtx_LSHIFTRT (DImode, dr,
				    gen_rtx_CONST_INT (SImode, 32))));
      emit_insn (gen_rtx_SET (VOIDmode, dr, gen_rtx_MOD (SImode, dr, sr)));
      emit_jump_insn (gen_jump (label3));
      emit_label (label1);
      emit_insn (gen_rtx_SET (VOIDmode, dr_0, const0_rtx));
      emit_jump_insn (gen_jump (label3));
      emit_label (label2);
      emit_insn (gen_rtx_SET (VOIDmode, dr_0,
			  gen_rtx_MINUS (SImode, dr_0, sr)));
      emit_label (label3);

    }
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], dr_0));

  DONE;
}")

; This is used by modsi3 & umodsi3.

(define_insn ""
  [(set (match_operand:DI 0 "register_operand" "=d")
	(mod:SI (match_operand:DI 1 "register_operand" "0")
		(match_operand:SI 2 "general_operand" "dm")))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"DR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"D	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- And instructions.
;;

;
; anddi3 instruction pattern(s).
;

;(define_expand "anddi3"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(and:DI (match_operand:DI 1 "general_operand" "")
;		(match_operand:DI 2 "general_operand" "")))]
;  ""
;  "
;{
;  rtx gen_andsi3();
;
;  emit_insn (gen_andsi3 (operand_subword (operands[0], 0, 1, DImode),
;			 operand_subword (operands[1], 0, 1, DImode),
;			 operand_subword (operands[2], 0, 1, DImode)));
;  emit_insn (gen_andsi3 (gen_lowpart (SImode, operands[0]),
;			 gen_lowpart (SImode, operands[1]),
;			 gen_lowpart (SImode, operands[2])));
;  DONE;
;}")

;
; andsi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:SI 0 "r_or_s_operand" "=d,m")
	(and:SI (match_operand:SI 1 "r_or_s_operand" "%0,0")
		(match_operand:SI 2 "r_or_s_operand" "g,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"NR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"N	%0,%2\";
    }
  mvs_check_page (0, 6, 0);
  return \"NC	%O0(4,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "andsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(and:SI (match_operand:SI 1 "general_operand" "%0")
		(match_operand:SI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"NR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"N	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; andhi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:HI 0 "r_or_s_operand" "=d,m")
	(and:HI (match_operand:HI 1 "r_or_s_operand" "%0,0")
		(match_operand:HI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"NR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      /* %K2 == sign extend operand to 32 bits so that CH works */
      mvs_check_page (0, 4, 0);
      if (GET_CODE (operands[2]) == CONST_INT)
         return \"N	%0,%K2\";
      return \"N	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 6, 0);
      return \"NC	%O0(2,%R0),%H2\";
    }
  mvs_check_page (0, 6, 0);
  return \"NC	%O0(2,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "andhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(and:HI (match_operand:HI 1 "general_operand" "%0")
		(match_operand:HI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      /* %K2 == sign extend operand to 32 bits so that CH works */
      mvs_check_page (0, 4, 0);
      return \"N	%0,%K2\";
    }
  mvs_check_page (0, 2, 0);
  return \"NR	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; andqi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:QI 0 "r_or_s_operand" "=d,m")
	(and:QI (match_operand:QI 1 "r_or_s_operand" "%0,0")
		(match_operand:QI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"NR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"N	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"NI	%0,%B2\";
    }
  mvs_check_page (0, 6, 0);
  return \"NC	%O0(1,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "andqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(and:QI (match_operand:QI 1 "general_operand" "%0")
		(match_operand:QI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* and sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"N	%0,%2\";
    }
  mvs_check_page (0, 2, 0);
  return \"NR	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Bit set (inclusive or) instructions.
;;

;
; iordi3 instruction pattern(s).
;

;(define_expand "iordi3"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(ior:DI (match_operand:DI 1 "general_operand" "")
;		(match_operand:DI 2 "general_operand" "")))]
;  ""
;  "
;{
;  rtx gen_iorsi3();
;
;  emit_insn (gen_iorsi3 (operand_subword (operands[0], 0, 1, DImode),
;			 operand_subword (operands[1], 0, 1, DImode),
;			 operand_subword (operands[2], 0, 1, DImode)));
;  emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]),
;			 gen_lowpart (SImode, operands[1]),
;			 gen_lowpart (SImode, operands[2])));
;  DONE;
;}")

;
; iorsi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:SI 0 "r_or_s_operand" "=d,m")
	(ior:SI (match_operand:SI 1 "r_or_s_operand" "%0,0")
		(match_operand:SI 2 "r_or_s_operand" "g,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"OR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"O	%0,%2\";
    }
  mvs_check_page (0, 6, 0);
  return \"OC	%O0(4,%R0),%2\";
}"
  [(set_attr "length" "6")]
)

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(ior:SI (match_operand:SI 1 "general_operand" "%0")
		(match_operand:SI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"OR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"O	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; iorhi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:HI 0 "r_or_s_operand" "=d,m")
	(ior:HI (match_operand:HI 1 "r_or_s_operand" "%0,0")
		(match_operand:HI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"OR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"O	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 6, 0);
      return \"OC	%O0(2,%R0),%H2\";
    }
  mvs_check_page (0, 6, 0);
  return \"OC	%O0(2,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(ior:HI (match_operand:HI 1 "general_operand" "%0")
		(match_operand:HI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"O	%0,%2\";
    }
  mvs_check_page (0, 2, 0);
  return \"OR	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;
; iorqi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:QI 0 "r_or_s_operand" "=d,m")
	(ior:QI (match_operand:QI 1 "r_or_s_operand" "%0,0")
		(match_operand:QI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"OR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"O	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"OI	%0,%B2\";
    }
  mvs_check_page (0, 6, 0);
  return \"OC	%O0(1,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "iorqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(ior:QI (match_operand:QI 1 "general_operand" "%0")
		(match_operand:QI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* OR sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"O	%0,%2\";
    }
  mvs_check_page (0, 2, 0);
  return \"OR	%0,%2\";
}"
   [(set_attr "length" "4")]
)

;;
;;- Xor instructions.
;;

;
; xordi3 instruction pattern(s).
;

;(define_expand "xordi3"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(xor:DI (match_operand:DI 1 "general_operand" "")
;		(match_operand:DI 2 "general_operand" "")))]
;  ""
;  "
;{
;  rtx gen_xorsi3();
;
;  emit_insn (gen_xorsi3 (operand_subword (operands[0], 0, 1, DImode),
;			 operand_subword (operands[1], 0, 1, DImode),
;			 operand_subword (operands[2], 0, 1, DImode)));
;  emit_insn (gen_xorsi3 (gen_lowpart (SImode, operands[0]),
;			 gen_lowpart (SImode, operands[1]),
;			 gen_lowpart (SImode, operands[2])));
;  DONE;
;}")

;
; xorsi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:SI 0 "r_or_s_operand" "=d,m")
	(xor:SI (match_operand:SI 1 "r_or_s_operand" "%0,0")
		(match_operand:SI 2 "r_or_s_operand" "g,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"XR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"X	%0,%2\";
    }
  mvs_check_page (0, 6, 0);
  return \"XC	%O0(4,%R0),%2\";
}"
   [(set_attr "length" "6")]
)

(define_insn "xorsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(xor:SI (match_operand:SI 1 "general_operand" "%0")
		(match_operand:SI 2 "general_operand" "g")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"XR	%0,%2\";
    }
  mvs_check_page (0, 4, 0);
  return \"X	%0,%2\";
}"
  [(set_attr "length" "4")]
)

;
; xorhi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:HI 0 "r_or_s_operand" "=d,m")
	(xor:HI (match_operand:HI 1 "r_or_s_operand" "%0,0")
		(match_operand:HI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"XR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"X	%0,%H2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 6, 0);
      return \"XC	%O0(2,%R0),%H2\";
    }
  mvs_check_page (0, 6, 0);
  return \"XC	%O0(2,%R0),%2\";
}"
  [(set_attr "length" "6")]
)

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(xor:HI (match_operand:HI 1 "general_operand" "%0")
		(match_operand:HI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"X	%0,%H2\";
    }
  mvs_check_page (0, 2, 0);
  return \"XR	%0,%2\";
}"
  [(set_attr "length" "4")]
)

;
; xorqi3 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:QI 0 "r_or_s_operand" "=d,m")
	(xor:QI (match_operand:QI 1 "r_or_s_operand" "%0,0")
		(match_operand:QI 2 "r_or_s_operand" "di,mi")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 2, 0);
      return \"XR	%0,%2\";
    }
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 0);
      return \"X	%0,%2\";
    }
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"XI	%0,%B2\";
    }
  mvs_check_page (0, 6, 0);
  return \"XC	%O0(1,%R0),%2\";
}"
  [(set_attr "length" "6")]
)

(define_insn "xorqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(xor:QI (match_operand:QI 1 "general_operand" "%0")
		(match_operand:QI 2 "general_operand" "di")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      mvs_check_page (0, 4, 0);
      return \"X	%0,%2\";
    }
  mvs_check_page (0, 2, 0);
  return \"XR	%0,%2\";
}"
  [(set_attr "length" "4")]
)

;;
;;- Negate instructions.
;;

;
; negsi2 instruction pattern(s).
;

(define_insn "negsi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(neg:SI (match_operand:SI 1 "general_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LCR	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;
; neghi2 instruction pattern(s).
;

(define_insn "neghi2"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(neg:HI (match_operand:HI 1 "general_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 10, 0);
  return \"SLL	%1,16\;SRA	%1,16\;LCR	%0,%1\";
}"
  [(set_attr "length" "10")]
)

;
; negdf2 instruction pattern(s).
;

(define_insn "negdf2"
  [(set (match_operand:DF 0 "general_operand" "=f")
	(neg:DF (match_operand:DF 1 "general_operand" "f")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LCDR	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;
; negsf2 instruction pattern(s).
;

(define_insn "negsf2"
  [(set (match_operand:SF 0 "general_operand" "=f")
	(neg:SF (match_operand:SF 1 "general_operand" "f")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LCER	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;;
;;- Absolute value instructions.
;;

;
; abssi2 instruction pattern(s).
;

(define_insn "abssi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(abs:SI (match_operand:SI 1 "general_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LPR	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;
; abshi2 instruction pattern(s).
;

(define_insn "abshi2"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(abs:HI (match_operand:HI 1 "general_operand" "d")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 10, 0);
  return \"SLL	%1,16\;SRA	%1,16\;LPR	%0,%1\";
}"
  [(set_attr "length" "10")]
)

;
; absdf2 instruction pattern(s).
;

(define_insn "absdf2"
  [(set (match_operand:DF 0 "general_operand" "=f")
	(abs:DF (match_operand:DF 1 "general_operand" "f")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LPDR	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;
; abssf2 instruction pattern(s).
;

(define_insn "abssf2"
  [(set (match_operand:SF 0 "general_operand" "=f")
	(abs:SF (match_operand:SF 1 "general_operand" "f")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LPER	%0,%1\";
}"
  [(set_attr "length" "2")]
)

;;
;;- One complement instructions.
;;

;
; one_cmpldi2 instruction pattern(s).
;

;(define_expand "one_cmpldi2"
;  [(set (match_operand:DI 0 "general_operand" "")
;	(not:DI (match_operand:DI 1 "general_operand" "")))]
;  ""
;  "
;{
;  rtx gen_one_cmplsi2();
;
;  emit_insn (gen_one_cmplsi2 (operand_subword (operands[0], 0, 1, DImode),
;			      operand_subword (operands[1], 0, 1, DImode)));
;  emit_insn (gen_one_cmplsi2 (gen_lowpart (SImode, operands[0]),
;			      gen_lowpart (SImode, operands[1])));
;  DONE;
;}")

;
; one_cmplsi2 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:SI 0 "r_or_s_operand" "=dm")
	(not:SI (match_operand:SI 1 "r_or_s_operand" "0")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 4);
      return \"X	%0,=F'-1'\";
    }
  CC_STATUS_INIT;
  mvs_check_page (0, 6, 4);
  return \"XC	%O0(4,%R0),=F'-1'\";
}"
  [(set_attr "length" "6")]
)

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(not:SI (match_operand:SI 1 "general_operand" "0")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  mvs_check_page (0, 4, 4);
  return \"X	%0,=F'-1'\";
}"
  [(set_attr "length" "4")]
)

;
; one_cmplhi2 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:HI 0 "r_or_s_operand" "=dm")
	(not:HI (match_operand:HI 1 "r_or_s_operand" "0")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 4);
      return \"X	%0,=F'-1'\";
    }
  mvs_check_page (0, 6, 4);
  return \"XC	%O0(2,%R0),=X'FFFF'\";
}"
  [(set_attr "length" "6")]
)

(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(not:HI (match_operand:HI 1 "general_operand" "0")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  mvs_check_page (0, 4, 4);
  return \"X	%0,=F'-1'\";
}"
  [(set_attr "length" "4")]
)

;
; one_cmplqi2 instruction pattern(s).
;

(define_insn ""
  [(set (match_operand:QI 0 "r_or_s_operand" "=dm")
	(not:QI (match_operand:QI 1 "r_or_s_operand" "0")))]
  "TARGET_CHAR_INSTRUCTIONS"
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 4, 4);
      return \"X	%0,=F'-1'\";
    }
  mvs_check_page (0, 4, 0);
  return \"XI	%0,255\";
}"
  [(set_attr "length" "4")]
)

(define_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(not:QI (match_operand:QI 1 "general_operand" "0")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT;  /* XOR sets CC but not how we want it */
  mvs_check_page (0, 4, 4);
  return \"X	%0,=F'-1'\";
}"
  [(set_attr "length" "4")]
)

;;
;;- Arithmetic shift instructions.
;;

;
; ashldi3 instruction pattern(s).
;

(define_insn "ashldi3"
  [(set (match_operand:DI 0 "general_operand" "=d")
	(ashift:DI (match_operand:DI 1 "general_operand" "0")
		   (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  /* this status set seems not have the desired effect,
   * proably because the 64-bit long-long test is emulated ?! */
  CC_STATUS_SET (operands[0], operands[1]);
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2]))
    return \"SLDA	%0,0(%2)\";
  return \"SLDA	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; ashrdi3 instruction pattern(s).
;

(define_insn "ashrdi3"
  [(set (match_operand:DI 0 "register_operand" "=d")
	(ashiftrt:DI (match_operand:DI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  /* this status set seems not have the desired effect,
   * proably because the 64-bit long-long test is emulated ?! */
  CC_STATUS_SET (operands[0], operands[1]);
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SRDA	%0,0(%2)\";
  return \"SRDA	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; ashlsi3 instruction pattern(s).
;

(define_insn "ashlsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(ashift:SI (match_operand:SI 1 "general_operand" "0")
		   (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SLL	%0,0(%2)\";
  return \"SLL	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; ashrsi3 instruction pattern(s).
;

(define_insn "ashrsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_SET (operands[0], operands[1]);
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SRA	%0,0(%2)\";
  return \"SRA	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; ashlhi3 instruction pattern(s).
;

(define_insn "ashlhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(ashift:HI (match_operand:HI 1 "general_operand" "0")
		   (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 8, 0);
  if (REG_P (operands[2])) 
    return \"SLL	%0,16(%2)\;SRA	%0,16\";
  return \"SLL	%0,16+%c2\;SRA	%0,16\";
}"
  [(set_attr "length" "8")]
)

;
; ashrhi3 instruction pattern(s).
;

(define_insn "ashrhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 8, 0);
  if (REG_P (operands[2])) 
    return \"SLL	%0,16\;SRA	%0,16(%2)\";
  return \"SLL	%0,16\;SRA	%0,16+%c2\";
}"
  [(set_attr "length" "8")]
)

;
; ashlqi3 instruction pattern(s).
;

(define_insn "ashlqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(ashift:QI (match_operand:QI 1 "general_operand" "0")
		   (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SLL	%0,0(%2)\";
  return \"SLL	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; ashrqi3 instruction pattern(s).
;

(define_insn "ashrqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 8, 0);
  if (REG_P (operands[2])) 
    return \"SLL	%0,24\;SRA	%0,24(%2)\";
  return \"SLL	%0,24\;SRA	%0,24+%c2\";
}"
  [(set_attr "length" "8")]
)

;;
;;- Logical shift instructions.
;;

;
; lshrdi3 instruction pattern(s).
;

(define_insn "lshrdi3"
  [(set (match_operand:DI 0 "general_operand" "=d")
	(lshiftrt:DI (match_operand:DI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SRDL	%0,0(%2)\";
  return \"SRDL	%0,%c2\";
}"
  [(set_attr "length" "4")]
)


;
; lshrsi3 instruction pattern(s).
;

(define_insn "lshrsi3"
  [(set (match_operand:SI 0 "general_operand" "=d")
	(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (REG_P (operands[2])) 
    return \"SRL	%0,0(%2)\";
  return \"SRL	%0,%c2\";
}"
  [(set_attr "length" "4")]
)

;
; lshrhi3 instruction pattern(s).
;

(define_insn "lshrhi3"
  [(set (match_operand:HI 0 "general_operand" "=d")
	(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT; /* AND sets the CC but not how we want it */
  if (REG_P (operands[2]))
    {
      mvs_check_page (0, 8, 4);
      return \"N	%0,=X'0000FFFF'\;SRL	%0,0(%2)\";
    }
  mvs_check_page (0, 8, 4);
  return \"N	%0,=X'0000FFFF'\;SRL	%0,%c2\";
}"
  [(set_attr "length" "8")]
)

;
; lshrqi3 instruction pattern(s).
;

(define_insn "lshrqi3"
  [(set (match_operand:QI 0 "general_operand" "=d")
	(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
		     (match_operand:SI 2 "general_operand" "Ja")))]
  ""
  "*
{
  check_label_emit ();
  CC_STATUS_INIT; /* AND sets the CC but not how we want it */
  mvs_check_page (0, 8, 4);
  if (REG_P (operands[2])) 
    return \"N	%0,=X'000000FF'\;SRL	%0,0(%2)\";
  return \"N	%0,=X'000000FF'\;SRL	%0,%c2\";
}"
  [(set_attr "length" "8")]
)

;; =======================================================================
;;- Conditional jump instructions.
;; =======================================================================

;
; beq instruction pattern(s).
;

(define_insn "beq"
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BE	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BER	14\";
}"
  [(set_attr "length" "6")]
)

;
; bne instruction pattern(s).
;

(define_insn "bne"
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNE	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNER	14\";
}"
  [(set_attr "length" "6")]
)

;
; bgt instruction pattern(s).
;

(define_insn "bgt"
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BHR	14\";
}"
  [(set_attr "length" "6")]
)

;
; bgtu instruction pattern(s).
;

(define_insn "bgtu"
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BHR	14\";
}"
  [(set_attr "length" "6")]
)

;
; blt instruction pattern(s).
;

(define_insn "blt"
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BLR	14\";
}"
  [(set_attr "length" "6")]
)

;
; bltu instruction pattern(s).
;

(define_insn "bltu"
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BLR	14\";
}"
  [(set_attr "length" "6")]
)

;
; bge instruction pattern(s).
;

(define_insn "bge"
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNLR	14\";
}"
  [(set_attr "length" "6")]
)

;
; bgeu instruction pattern(s).
;

(define_insn "bgeu"
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNLR	14\";
}"
  [(set_attr "length" "6")]
)

;
; ble instruction pattern(s).
;

(define_insn "ble"
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNHR	14\";
}"
  [(set_attr "length" "6")]
)

;
; bleu instruction pattern(s).
;

(define_insn "bleu"
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNHR	14\";
}"
  [(set_attr "length" "6")]
)

;;
;;- Negated conditional jump instructions.
;;

(define_insn ""
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNE	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNER	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BE	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BER	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNHR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNHR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNLR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BNL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BNLR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BLR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BL	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BLR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BHR	14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    { 
      return \"BH	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BHR	14\";
}"
  [(set_attr "length" "6")]
)

;; ==============================================================
;;- Subtract one and jump if not zero.
;; These insns seem to not be getting matched ...
;; XXX should fix this, as it would improve for loops

(define_insn ""
  [(set (pc)
	(if_then_else
	 (ne (plus:SI (match_operand:SI 0 "register_operand" "+d")
		      (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:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
    {
      return \"BCT	%0,%l1\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l1)\;BCTR	%0,14\";
}"
  [(set_attr "length" "6")]
)

(define_insn ""
  [(set (pc)
	(if_then_else
	 (eq (plus:SI (match_operand:SI 0 "register_operand" "+d")
		      (const_int -1))
	     (const_int 0))
	 (pc)
	 (label_ref (match_operand 1 "" ""))))
   (set (match_dup 0)
	(plus:SI (match_dup 0)
		 (const_int -1)))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (mvs_check_label (CODE_LABEL_NUMBER (operands[1])))
    {
      return \"BCT	%0,%l1\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l1)\;BCTR	%0,14\";
}"
  [(set_attr "length" "6")]
)

;; =============================================================
;;- Unconditional jump instructions.
;;

;
; jump instruction pattern(s).
;

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 4, 0);
  if (i370_short_branch(insn) || mvs_check_label (CODE_LABEL_NUMBER (operands[0])))
    {
      return \"B	%l0\";
    }
  mvs_check_page (0, 2, 4);
  return \"L	14,=A(%l0)\;BR	14\";
}"
  [(set_attr "length" "6")]
)

;
; indirect-jump instruction pattern(s).
; hack alert -- should check that displacement is < 4096

(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 2, 0);
      return \"BR	%0\";
    }
  mvs_check_page (0, 4, 0);
  return \"B	%0\";
}"
  [(set_attr "length" "4")]
)

;
; tablejump instruction pattern(s).
;

(define_insn "tablejump"
  [(set (pc)
	(match_operand:SI 0 "general_operand" "am"))
   (use (label_ref (match_operand 1 "" "")))
;   (clobber (reg:SI 14))
   ]
  ""
  "*
{
  check_label_emit ();
  if (REG_P (operands[0]))
    {
      mvs_check_page (0, 6, 0);
      return \"BR	%0\;DS	0F\";
    }
  mvs_check_page (0, 10, 0);
  return \"L	14,%0\;BR	14\;DS	0F\";
}"
  [(set_attr "length" "10")]
)

;;
;;- Jump to subroutine.
;;
;; For the C/370 environment the internal functions, ie. sqrt, are called with
;; a non-standard form.  So, we must fix it here.  There's no BM like IBM.
;;
;; The ELF ABI is different from the C/370 ABI because we have a simpler,
;; more powerful way of dealing with structure-value returns.  Basically, 
;; we use R1 to point at structure returns (64-bit and larger returns)
;; and R11 to point at the args.  Note that this handles double-precision
;; (64-bit) values just fine, in a less-kludged manner than the C/370 ABI.
;; Since R1 is used, we use R2 to pass the argument pointer to the routine.

;
; call instruction pattern(s).
;
; We define four call instruction patterns below. The first two patterns,
; although general, end up matching (only?) calls through function pointers.  
; The last two, which require a symbol-ref to match, get used for all
; ordinary subroutine calls.

(define_insn "call"
  [(call (match_operand:QI 0 "memory_operand" "m")
	 (match_operand:SI 1 "immediate_operand" "i"))
   (clobber (reg:SI 2))
   ]
  ""
  "*
{
  static char temp[128];
  int i = STACK_POINTER_OFFSET;
  CC_STATUS_INIT;

  check_label_emit ();
#ifdef TARGET_ELF_ABI
  mvs_check_page (0, 10, 4);
  sprintf ( temp, \"LA	r2,%d(,sp)\;LA	15,%%0\;BASR	14,15\", i );
  return temp;
#else
  if (mvs_function_check (XSTR (operands[0], 0)))
    {
      mvs_check_page (0, 22, 4);
      sprintf ( temp, \"LA	1,136(,13)\;ST	1,%d(,13)\;LA 1,%d(,13)\;LA	15,%%0\;BALR	14,15\;LD	0,136(,13)\",
	     i - 4, i - 4 );
    }
  else
    {
      mvs_check_page (0, 10, 4);
      sprintf ( temp, \"LA	1,%d(,13)\;LA	15,%%0\;BALR	14,15\", i );
    }
  return temp;
#endif
}"
  [(set_attr "length" "22")]
)

;
; call_value instruction pattern(s).
;

(define_insn "call_value"
  [(set (match_operand 0 "" "rf")
 	(call (match_operand:QI 1 "memory_operand" "m")
 	      (match_operand:SI 2 "general_operand" "i")))
   (clobber (reg:SI 2))
   ]
  ""
  "*
{
  static char temp[128];
  int i = STACK_POINTER_OFFSET;
  CC_STATUS_INIT;

  check_label_emit ();
#ifdef TARGET_ELF_ABI
  mvs_check_page (0, 10, 4);
  sprintf ( temp, \"LA	r2,%d(,sp)\;LA	15,%%1\;BASR	14,15\", i );
  return temp;
#else
  if (mvs_function_check (XSTR (operands[1], 0)))
    {
      mvs_check_page (0, 22, 4);
      sprintf ( temp, \"LA	1,136(,13)\;ST	1,%d(,13)\;LA 1,%d(,13)\;LA	15,%%1\;BALR	14,15\;LD	0,136(,13)\",
	   i - 4, i - 4 );
    }
  else
    {
      mvs_check_page (0, 10, 4);
      sprintf ( temp, \"LA	1,%d(,13)\;LA	15,%%1\;BALR	14,15\", i );
    }
  return temp;
#endif
}"
  [(set_attr "length" "22")]
)

(define_insn ""
  [(call (mem:QI (match_operand:SI 0 "" "i"))
	 (match_operand:SI 1 "general_operand" "g"))
   (clobber (reg:SI 2))
   ]
  "GET_CODE (operands[0]) == SYMBOL_REF"
  "*
{
  static char temp[128];
  int i = STACK_POINTER_OFFSET;
  CC_STATUS_INIT;

  check_label_emit ();
#ifdef TARGET_ELF_ABI
  mvs_check_page (0, 10, 4);
  sprintf ( temp, \"LA	r2,%d(,sp)\;L	15,%%0\;BASR	14,15\", i );
  return temp;
#else
  if (mvs_function_check (XSTR (operands[0], 0)))
    {
      mvs_check_page (0, 22, 4);
      sprintf ( temp, \"LA	1,136(,13)\;ST	1,%d(,13)\;LA	1,%d(,13)\;L	15,%%0\;BALR	14,15\;LD	0,136(,13)\",
	   i - 4, i - 4 );
    }
  else
    {
      mvs_check_page (0, 10, 4);
      sprintf ( temp, \"LA	1,%d(,13)\;L	15,%%0\;BALR	14,15\", i );
    }
  return temp;
#endif
}"
  [(set_attr "length" "22")]
)

(define_insn ""
  [(set (match_operand 0 "" "rf")
	(call (mem:QI (match_operand:SI 1 "" "i"))
	      (match_operand:SI 2 "general_operand" "g")))
   (clobber (reg:SI 2))
   ]
  "GET_CODE (operands[1]) == SYMBOL_REF"
  "*
{
  static char temp[128];
  int i = STACK_POINTER_OFFSET;
  CC_STATUS_INIT;

  check_label_emit ();
#ifdef TARGET_ELF_ABI
  mvs_check_page (0, 10, 4);
  sprintf ( temp, \"LA	r2,%d(,sp)\;L	15,%%1\;BASR	14,15\", i );
  return temp;
#else
  if (mvs_function_check (XSTR (operands[1], 0)))
    {
      mvs_check_page (0, 22, 4);
      sprintf ( temp, \"LA	1,136(,13)\;ST	1,%d(,13)\;LA	1,%d(,13)\;L	15,%%1\;BALR	14,15\;LD	0,136(,13)\",
	   i - 4, i - 4 );
    }
  else
    {
      mvs_check_page (0, 10, 4);
      sprintf ( temp, \"LA	1,%d(,13)\;L	15,%%1\;BALR	14,15\", i );
    }
  return temp;
#endif
}"
  [(set_attr "length" "22")]
)

;;
;; Call subroutine returning any type.
;; This instruction pattern appears to be used only by the
;; expand_builtin_apply definition for __builtin_apply.  It is needed
;; since call_value might return an in in r15 or a float in fpr0 (r16)
;; and the builtin code calla abort since the reg is ambiguous. Well,
;; the below is probably broken anyway, we just want to go for now.
;;
(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 (operands[0], const0_rtx, const0_rtx, 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;
}")


;;
;;- Miscellaneous instructions.
;;

;
; nop instruction pattern(s).
;

(define_insn "nop"
  [(const_int 0)]
  ""
  "*
{
  check_label_emit ();
  mvs_check_page (0, 2, 0);
  return \"LR	0,0\";
}"
  [(set_attr "length" "2")]
)
