;;- Machine description for GNU compiler
;;- MIL-STD-1750A version.
;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
;; Contributed by O.M.Kellogg, DASA (oliver.kellogg@space.otn.dasa.de).

;; 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 1, 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.


;;- instruction definitions

;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.

;;- When naming insn's (operand 0 of define_insn) be careful about using
;;- names from other targets machine descriptions.

;; MIL-STD-1750 specific remarks:
;;
;; 1) BITS_PER_UNIT = 16
;;
;; 2) GCC   to    MIL-STD-1750       data type mappings:
;;    QImode => single integer (16 bits or 1 reg).
;;    HImode => double integer (32 bits or 2 regs).
;;    HFmode => single precision float (32 bits or 2 regs).
;;    TQFmode => extended precision float (48 bits or 3 regs).
;; 
;; 3) Immediate integer operands Constraints:
;;    'I'  1 .. 16
;;    'J' -1 ..-16
;;    'K'  0 .. 15
;;    'L'  0 .. 255
;;    'M' -32768 .. 32767
;;    'O' => 0  (for optimizations and GCC quirks)
;;
;; Further notes:
;;-  Assembly output ending in ".M" are macros in file M1750.INC


;; stackpush
(define_insn ""
  [(set (match_operand:QI 0 "push_operand" "=<")
        (match_operand:QI 1 "general_operand" "r"))]
  ""
  "pshm r%1,r%1  ; stackptr = R%0")

(define_insn ""
  [(set (match_operand:HI 0 "push_operand" "=<")
        (match_operand:HI 1 "general_operand" "r"))]
  ""
  "*
   { 
        rtx new_operands[3];
        new_operands[2] = operands[0];
        new_operands[0] = operands[1];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[1])+1);
        output_asm_insn(\"pshm r%0,r%1  ; stackptr = r%2\",new_operands);
        return \";\";
   } ")

(define_insn ""
  [(set (match_operand:HF 0 "push_operand" "=<")
        (match_operand:HF 1 "general_operand" "r"))]
  ""
  "*
  { 
        rtx new_operands[3];
        new_operands[2] = operands[0];
        new_operands[0] = operands[1];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[1])+1);
        output_asm_insn(\"pshm r%0,r%1  ; stackptr = r%2\",new_operands);
        return \";\";
   } ")

(define_insn ""
  [(set (match_operand:TQF 0 "push_operand" "=<")
        (match_operand:TQF 1 "general_operand" "r"))]
  ""
  "*
   { 
        rtx new_operands[3];
        new_operands[2] = operands[0];
        new_operands[0] = operands[1];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[1])+2);
        output_asm_insn(\"pshm r%0,r%1  ; stackptr = r%2\",new_operands);
        return \";\";
   } ")

;; stackpop
(define_insn ""
  [(set (match_operand:QI 0 "general_operand" "=r")
        (match_operand:QI 1 "push_operand" ">"))]
  ""
  "popm r%1,r%1")

(define_insn ""
  [(set (match_operand:HI 0 "general_operand" "=r")
        (match_operand:HI 1 "push_operand" ">"))]
  ""
  "*
   { 
        rtx new_operands[2];
        new_operands[0] = operands[0];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[0])+1);
        output_asm_insn(\"popm r%0,r%1\",new_operands);
        return \";\";
   } ")

(define_insn ""
  [(set (match_operand:HF 0 "general_operand" "=r")
        (match_operand:HF 1 "push_operand" ">"))]
  ""
  "*
   { 
        rtx new_operands[2];
        new_operands[0] = operands[0];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[0])+1);
        output_asm_insn(\"popm r%0,r%1\",new_operands);
        return \";\";
   } ")

(define_insn ""
  [(set (match_operand:TQF 0 "general_operand" "=r")
        (match_operand:TQF 1 "push_operand" ">"))]
  ""
  "*
   { 
        rtx new_operands[2];
        new_operands[0] = operands[0];
        new_operands[1] = gen_rtx(CONST_INT,VOIDmode,REGNO(operands[0])+2);
        output_asm_insn(\"popm r%0,r%1\",new_operands);
        return \";\";
   } ")

;; Test operations. These shouldn't really occur for 1750:
;; all important instructions set the cc's (see NOTICE_UPDATE_CC)

(define_insn "tstqi"
  [(set (cc0)
        (match_operand:QI 0 "register_operand" "r"))]
  ""
  "lr r%0,r%0   ; from tstqi")

(define_insn "tsthi"
  [(set (cc0)
        (match_operand:HI 0 "register_operand" "r"))]
  ""
  "dlr r%0,r%0   ; from tsthi")

(define_insn "tsthf"
  [(set (cc0)
        (match_operand:HF 0 "register_operand" "r"))]
  ""
  "dlr r%0,r%0   ; from tsthf")

;; This one is happy with "roughly zero" :-)  (should be improved)
(define_insn "tsttqf"
  [(set (cc0)
        (match_operand:TQF 0 "register_operand" "r"))]
  ""
  "dlr r%0,r%0   ; from tsttqf")


;; block move.

(define_insn "movstrqi"
  [(set (match_operand:BLK 0 "mov_memory_operand" "m")
	(match_operand:BLK 1 "mov_memory_operand" "m"))
   (use (match_operand:QI 2 "general_operand" "r"))
   (match_operand 3 "" "")
   (clobber (match_dup 0))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  "*
   {
     rtx regops[3];
     regops[0] = XEXP(operands[0],0);
     regops[1] = XEXP(operands[1],0);
     regops[2] = operands[2];
     return (char *)movcnt_regno_adjust(regops);
   } ")


;; compare instructions.

(define_insn "cmpqi"
  [(set (cc0)
        (compare (match_operand:QI 0 "register_operand" "r,r,r,r,r")
                 (match_operand:QI 1 "general_operand"  "I,J,i,r,m")))]
  ""
  "*
   {
     if (next_cc_user_is_unsigned (insn))
       switch (which_alternative)
	 {
	 case 0:
	 case 1:
	 case 2:
	   return \"ucim.m %0,%1\";
	 case 3:
	   return \"ucr.m %0,%1\";
	 case 4:
	   return \"uc.m %0,%1\";
	 }
     else
       switch (which_alternative)
	 {
	 case 0:
	   return \"cisp r%0,%1\";
	 case 1:
	   return \"cisn r%0,%J1\";
	 case 2:
	   return \"cim  r%0,%1\";
	 case 3:
	   return \"cr   r%0,r%1\";
	 case 4:
	   return \"c    r%0,%1\";
	 }
   } ")

(define_insn "cmphi"
  [(set (cc0)
        (compare (match_operand:HI 0 "general_operand" "r,r")
                 (match_operand:HI 1 "general_operand" "r,m")))]
  ""
  "@
    dcr r%0,r%1
    dc  r%0,%1 ")

(define_insn "cmphf"
 [(set (cc0)
       (compare (match_operand:HF 0 "general_operand" "r,r")
                (match_operand:HF 1 "general_operand" "r,m")))]
 ""
 "@
   fcr r%0,r%1
   fc  r%0,%1 ")

(define_insn "cmptqf"
  [(set (cc0)
        (compare (match_operand:TQF 0 "general_operand" "r,r")
                 (match_operand:TQF 1 "general_operand" "r,m")))]
  ""
  "@
    efcr r%0,r%1
    efc  r%0,%1 ")


;; truncation instructions
;;- 1750: any needed?

(define_insn "trunchiqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
        (truncate:QI
         (match_operand:HI 1 "register_operand" "r")))]
  ""
  "*
     {
	rtx new_operands[2];
	new_operands[0] = operands[0];
	new_operands[1] = gen_rtx (REG, QImode, REGNO(operands[1]) + 1);
        output_asm_insn(\"lr r%0,r%1  ;trunchiqi2\",new_operands);
        return \";\";
     } ")

;; zero extension instructions: not defined, GCC can synthesize

;; sign extension instructions

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (sign_extend:HI (match_operand:QI 1 "general_operand" "r,m,i")) )]
  ""
  "@
    lr  r%0,r%1 ;extendqihi2\;dsra r%0,16
    l   r%0,%1  ;extendqihi2\;dsra r%0,16
    lim r%0,%1  ;extendqihi2\;dsra r%0,16 ")


;; Conversions between float and double.

; 1750 HF-to-TQF extend: just append 16 bits (least signif.) with all bits zero
(define_insn "extendhftqf2"
  [(set (match_operand:TQF 0 "register_operand" "=r,r")
        (float_extend:TQF (match_operand:HF 1 "general_operand" "r,m")))]
  ""
  "*
      {
	rtx new_opnds[2];
	new_opnds[0] = gen_rtx (REG, QImode, REGNO(operands[0]) + 2);
	new_opnds[1] = operands[1];
        output_asm_insn(\"xorr r%0,r%0   ;extendhftqf2\",new_opnds);
        if (which_alternative == 0)
          return \"dlr r%0,r%1\";
        else
          return \"dl  r%0,%1\";
      } ")

; 1750 TQF-to-HF truncate is a no-op: just leave away the least signif. 16 bits
(define_insn "trunctqfhf2"
  [(set (match_operand:HF 0 "register_operand" "=r,r")
        (float_truncate:HF
          (match_operand:TQF 1 "general_operand" "r,m")))]
  ""
  "@
     dlr r%0,r%1  ;trunctqfhf2
     dl  r%0,%1   ;trunctqfhf2 ")


;; Conversion between fixed point and floating point.

(define_insn "floatqihf2"
  [(set           (match_operand:HF 0 "register_operand" "=r")
        (float:HF (match_operand:QI 1 "register_operand" "r")))]
  ""
  "flt r%0,r%1")

(define_insn "floathitqf2"
  [(set           (match_operand:TQF 0 "register_operand" "=r")
        (float:TQF (match_operand:HI 1 "register_operand" "r")))]
  ""
  "eflt r%0,r%1")


;; Convert floats to ints

(define_insn "fix_trunchfqi2"
  [(set                 (match_operand:QI 0 "register_operand" "=r")
        (fix:QI (fix:HF (match_operand:HF 1 "register_operand" "r"))))]
  ""
  "fix r%0,r%1")

(define_insn "fix_trunctqfhi2"
  [(set                 (match_operand:HI 0 "register_operand" "=r")
        (fix:HI (fix:TQF (match_operand:TQF 1 "register_operand" "r"))))]
  ""
  "efix r%0,r%1")


;; Move instructions

;; We can't deal with normal byte-size characters, only with WIDE characters!
;; This may appear as a serious restriction, but it also opens the doors
;; for ISO 10646  :-)

;; 16-bit moves

(define_insn "movqi"
  [(set (match_operand:QI 0 "general_operand" "=r,r,r,r,r,r,r,m,m")
        (match_operand:QI 1 "general_operand"  "O,I,J,M,i,r,m,r,K"))]
  ""
  "@
     xorr r%0,r%0
     lisp r%0,%1
     lisn r%0,%J1
     lim  r%0,%1  ; 'M' constraint
     lim  r%0,%1  ; 'i' constraint
     lr   r%0,r%1
     l    r%0,%1
     st   r%1,%0
     stc  %1,%0   ")

;; 32-bit moves

; Set HIreg to constant
(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
        (match_operand:HI 1 "immediate_operand" "i"))]
  ""
  "*
      {
        rtx new_opnds[2];
        int val = INTVAL(operands[1]);
        if (val >= 0)
          {
            if (val <= 65535)
              {
                new_opnds[0] = gen_rtx(REG,QImode,REGNO(operands[0]));
                new_opnds[1] = operands[1];
                output_asm_insn(\"xorr   r%0,r%0 ;movhi cst->reg\",new_opnds);
                REGNO(new_opnds[0]) += 1;
                if (val == 0)
                  output_asm_insn(\"xorr r%0,r%0\",new_opnds);
                else if (val <= 16)
                  output_asm_insn(\"lisp r%0,%1\",new_opnds);
                else
                  output_asm_insn(\"lim  r%0,%1\",new_opnds);
                return \";\";
              }
          }
        else if (val >= -16)
          return \"lisn r%0,%J1\;dsra r%0,16 ;movhi cst\";
	new_opnds[0] = gen_rtx(REG, QImode, REGNO(operands[0]));
	new_opnds[1] = gen_rtx(CONST_INT,VOIDmode,(INTVAL(operands[1])) >> 16);
        output_asm_insn(\"lim r%0,%1 ;movhi cst->reg\",new_opnds);
        INTVAL(new_opnds[1]) = val & 0xFFFF;
        REGNO(new_opnds[0]) += 1;
        output_asm_insn(\"lim r%0,%1\",new_opnds);
        return \";\";
      }
  ")

; Move small constant to memory, HImode
(define_insn ""
  [(set (match_operand:HI 0 "memory_operand" "=m")
        (match_operand:HI 1 "small_nonneg_const" "K"))]
  ""
  "*
      {
	rtx new_opnds[2];
	new_opnds[0] = operands[0];
	new_opnds[1] = operands[1];
	output_asm_insn (\"stc 0,%0 ;movhi cst->mem\", new_opnds);
	add_1_to_mem (new_opnds[0]);
	output_asm_insn (\"stc %1,%0\", new_opnds);
	return \";\";
      }
  ")

(define_insn "movhi"
  [(set (match_operand:HI 0 "general_operand" "=r,r,m")
        (match_operand:HI 1 "general_operand"  "r,m,r"))]
  ""
  "@
    dlr  r%0,r%1
    dl   r%0,%1
    dst  r%1,%0 ")


;; Single-Float moves are similar to HImode moves

; Move HFmode zero to memory
(define_insn ""
  [(set (match_operand:HF 0 "memory_operand" "=m")
        (match_operand:HF 1 "zero_operand" "G"))]
  ""
  "*
      {
	rtx new_opnds[2];
	new_opnds[0] = operands[0];
	new_opnds[1] = operands[1];
	output_asm_insn (\"stc 0,%0 ;movhf 0.0->mem\", new_opnds);
	add_1_to_mem (new_opnds[0]);
	output_asm_insn (\"stc 0,%0\", new_opnds);
	return \";\";
      }
  ")

(define_insn "movhf"
  [(set (match_operand:HF 0 "general_operand" "=r,r,m")
        (match_operand:HF 1 "general_operand"  "r,m,r"))]
  ""
  "@
    dlr  r%0,r%1
    dl   r%0,%1
    dst  r%1,%0 ")


;; Longfloat moves

; Move TQFmode zero to memory
(define_insn ""
  [(set (match_operand:TQF 0 "memory_operand" "=m")
        (match_operand:TQF 1 "zero_operand" "G"))]
  ""
  "*
      {
	rtx new_opnds[2];
	new_opnds[0] = operands[0];
	new_opnds[1] = operands[1];
	output_asm_insn (\"stc 0,%0 ;movtqf 0.0->mem\", new_opnds);
	add_1_to_mem (new_opnds[0]);
	output_asm_insn (\"stc 0,%0\", new_opnds);
	add_1_to_mem (new_opnds[0]);
	output_asm_insn (\"stc 0,%0\", new_opnds);
	return \";\";
      }
  ")

(define_insn "movtqf"
  [(set (match_operand:TQF 0 "general_operand" "=r,r,m")
        (match_operand:TQF 1 "general_operand"  "r,m,r"))]
  ""
  "@
    eflr.m %0,%1
    efl  r%0,%1
    efst r%1,%0 ")


;; add instructions 

;; single integer

(define_insn "addqi3"
  [(set (match_operand:QI 0 "general_operand" "=r,r,r,r,r,m,m")
        (plus:QI (match_operand:QI 1 "general_operand" "%0,0,0,0,0,0,0")
                 (match_operand:QI 2 "general_operand"  "I,J,i,r,m,I,J")))]
  ""
  "*
    switch (which_alternative)
      {
        case 0:
          return \"aisp r%0,%2\";
        case 1:
          return \"sisp r%0,%J2\";
        case 2:
          if (INTVAL(operands[2]) < 0)
            return \"sim r%0,%J2\";
          else
            return \"aim r%0,%2\";
        case 3:
          return \"ar r%0,r%2\";
        case 4:
          return \"a r%0,%2\";
        case 5:
          return \"incm %2,%0\";
        case 6:
          return \"decm %J2,%0\";
      } ")

;; double integer
(define_insn "addhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
                 (match_operand:HI 2 "general_operand" "r,m")))]
  ""
  "@
    dar r%0,r%2
    da  r%0,%2 ")

(define_insn "addhf3"
  [(set (match_operand:HF 0 "register_operand" "=r,r")
        (plus:HF (match_operand:HF 1 "register_operand" "%0,0")
                 (match_operand:HF 2 "general_operand" "r,m")))]
  ""
  "@
    far r%0,r%2
    fa  r%0,%2 ")

(define_insn "addtqf3"
  [(set (match_operand:TQF 0 "register_operand" "=r,r")
        (plus:TQF (match_operand:TQF 1 "register_operand" "%0,0")
                 (match_operand:TQF 2 "general_operand" "r,m")))]
  ""
  "@
    efar r%0,r%2
    efa  r%0,%2 ")


;; subtract instructions

;; single integer
(define_insn "subqi3"
  [(set (match_operand:QI 0 "general_operand" "=r,r,r,r,m")
        (minus:QI (match_operand:QI 1 "general_operand" "0,0,0,0,0")
                  (match_operand:QI 2 "general_operand"  "I,i,r,m,I")))]
  ""
  "@
    sisp r%0,%2
    sim  r%0,%2
    sr   r%0,r%2
    s    r%0,%2
    decm %2,%0 ")

;; double integer
(define_insn "subhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (minus:HI (match_operand:HI 1 "register_operand" "0,0")
                  (match_operand:HI 2 "general_operand" "r,m")))]
  ""
  "@
    dsr r%0,r%2
    ds  r%0,%2 ")

(define_insn "subhf3"
  [(set (match_operand:HF 0 "register_operand" "=r,r")
        (minus:HF (match_operand:HF 1 "register_operand" "0,0")
                  (match_operand:HF 2 "general_operand" "r,m")))]
  ""
  "@
    fsr r%0,r%2
    fs  r%0,%2 ")

(define_insn "subtqf3"
  [(set (match_operand:TQF 0 "register_operand" "=r,r")
        (minus:TQF (match_operand:TQF 1 "register_operand" "0,0")
                  (match_operand:TQF 2 "general_operand" "r,m")))]
  ""
  "@
    efsr r%0,r%2
    efs  r%0,%2 ")


;; multiply instructions

(define_insn "mulqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
        (mult:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0")
                 (match_operand:QI 2 "general_operand"  "I,J,M,r,m")))]
  ""
  "@
     misp r%0,%2
     misn r%0,%J2
     msim r%0,%2
     msr  r%0,r%2
     ms   r%0,%2  ")


; 32-bit product
(define_insn "mulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (mult:HI (match_operand:QI 1 "register_operand" "%0,0,0")
                 (match_operand:QI 2 "general_operand" "M,r,m")))]
  ""
  "@
    mim r%0,%1
    mr  r%0,r%2
    m   r%0,%2 ")

(define_insn "mulhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (mult:HI (match_operand:HI 1 "register_operand" "%0,0")
                 (match_operand:HI 2 "general_operand" "r,m")))]
  ""
  "@
    dmr r%0,r%2
    dm  r%0,%2 ")

; not available on 1750: "umulhi3","umulhisi3","umulsi3" (unsigned multiply's)

(define_insn "mulhf3"
  [(set (match_operand:HF 0 "register_operand" "=r,r")
        (mult:HF (match_operand:HF 1 "register_operand" "%0,0")
                 (match_operand:HF 2 "general_operand" "r,m")))]
  ""
  "@
    fmr r%0,r%2
    fm  r%0,%2 ")

(define_insn "multqf3"
  [(set (match_operand:TQF 0 "register_operand" "=r,r")
        (mult:TQF (match_operand:TQF 1 "register_operand" "%0,0")
                 (match_operand:TQF 2 "general_operand" "r,m")))]
  ""
  "@
    efmr r%0,r%2
    efm  r%0,%2 ")


;; divide instructions
;; The 1750 16bit integer division instructions deliver a 16-bit
;; quotient and a 16-bit remainder, where the remainder is in the next higher
;; register number above the quotient. For now, we haven't found a way
;; to give the reload pass knowledge of this property. So we make do with
;; whatever registers the allocator wants, and willy-nilly output a pair of
;; register-copy ops when needed. (See mod_regno_adjust() in file aux-output.c)
;; A comment in the description of `divmodM4' suggests that one leave the divM3
;; undefined when there is a divmodM4 available.

(define_insn "divmodqi4"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
        (div:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0")
                (match_operand:QI 2 "general_operand"  "I,J,M,r,m")))
   (set (match_operand:QI 3 "register_operand" "=r,r,r,r,r")
        (mod:QI (match_dup 1) (match_dup 2)))]
  ""
  "*
   {
     char *istr;
     switch(which_alternative)
       {
       case 0:
         istr = \"disp\";
         break;
       case 1:
	 {
	   rtx new_opnds[4];
	   new_opnds[0] = operands[0];
	   new_opnds[1] = operands[1];
	   new_opnds[2] = gen_rtx (CONST_INT, VOIDmode, -INTVAL(operands[2]));
	   new_opnds[3] = operands[3];
           istr = \"disn\";
	   return (char *)mod_regno_adjust(istr,new_opnds);
	 }
         break;
       case 2:
         istr = \"dvim\";
         break;
       case 3:
         istr = \"dvr \";
         break;
       case 4:
         istr = \"dv  \";
         break;
      }
      return (char *)mod_regno_adjust(istr,operands);
     }")

;; Division for other types is straightforward.

(define_insn "divhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (div:HI (match_operand:HI 1 "register_operand" "0,0")
                (match_operand:HI 2 "general_operand" "r,m")))]
  ""
  "@
    ddr r%0,r%2
    dd  r%0,%2 ")

(define_insn "divhf3"
  [(set (match_operand:HF 0 "register_operand" "=r,r")
        (div:HF (match_operand:HF 1 "register_operand" "0,0")
                (match_operand:HF 2 "general_operand" "r,m")))]
  ""
  "@
    fdr r%0,r%2
    fd  r%0,%2 ")

(define_insn "divtqf3"
  [(set (match_operand:TQF 0 "register_operand" "=r,r")
        (div:TQF (match_operand:TQF 1 "register_operand" "0,0")
                (match_operand:TQF 2 "general_operand" "r,m")))]
  ""
  "@
    efdr r%0,r%2
    efd  r%0,%2 ")


;; Other arithmetic instructions:

;; Absolute value

(define_insn "absqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
        (abs:QI (match_operand:QI 1 "register_operand" "r")))]
  ""
  "abs r%0,r%1")

(define_insn "abshi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (abs:HI (match_operand:HI 1 "register_operand" "r")))]
  ""
  "dabs r%0,r%1")

(define_insn "abshf2"
  [(set (match_operand:HF 0 "register_operand" "=r")
        (abs:HF (match_operand:HF 1 "register_operand" "r")))]
  ""
  "fabs r%0,r%1")


;; Negation

(define_insn "negqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
        (neg:QI (match_operand:QI 1 "register_operand" "r")))]
  ""
  "neg r%0,r%1")

(define_insn "neghi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (neg:HI (match_operand:HI 1 "register_operand" "r")))]
  ""
  "dneg r%0,r%1")

(define_insn "neghf2"
  [(set (match_operand:HF 0 "register_operand" "=r")
        (neg:HF (match_operand:HF 1 "register_operand" "r")))]
  ""
  "fneg r%0,r%1")

; The 1750A does not have an extended float negate instruction, so simulate.
(define_expand "negtqf2"
  [(set (match_operand:TQF 0 "register_operand" "=&r")
        (neg:TQF (match_operand:TQF 1 "register_operand" "r")))]
  ""
  "
   emit_insn(gen_rtx(SET,VOIDmode,operands[0],CONST0_RTX(TQFmode)));
   emit_insn(gen_rtx(SET,VOIDmode,operands[0],
             gen_rtx(MINUS,TQFmode,operands[0],operands[1])));
   DONE;
  ")


;; bit-logical instructions

;; AND

(define_insn "andqi3"
  [(set (match_operand:QI 0 "general_operand" "=r,r,r")
        (and:QI (match_operand:QI 1 "general_operand" "%0,0,0")
                (match_operand:QI 2 "general_operand" "M,r,m")))]
  ""
  "@
    andm r%0,%2
    andr r%0,r%2
    and  r%0,%2 ")

; This sets incorrect condition codes. See notice_update_cc()
(define_insn "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (and:HI (match_operand:HI 1 "register_operand" "%0")
                (match_operand:HI 2 "register_operand" "r")))]
  ""
  "danr.m %0,%2")

;; OR

(define_insn "iorqi3"
  [(set (match_operand:QI 0 "general_operand" "=r,r,r")
        (ior:QI  (match_operand:QI 1 "general_operand" "%0,0,0")
                 (match_operand:QI 2 "general_operand" "M,r,m")))]
  ""
  "@
    orim r%0,%2
    orr  r%0,r%2
    or   r%0,%2 ")

; This sets incorrect condition codes. See notice_update_cc()
(define_insn "iorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (ior:HI (match_operand:HI 1 "register_operand" "%0")
                (match_operand:HI 2 "register_operand" "r")))]
  ""
  "dorr.m %0,%2")

;; XOR

(define_insn "xorqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
        (xor:QI (match_operand:QI 1 "register_operand" "%0,0,0")
                (match_operand:QI 2 "general_operand"  "M,r,m")))]
  ""
  "@
    xorm r%0,%2
    xorr r%0,r%2
    xor  r%0,%2 ")

; This sets incorrect condition codes. See notice_update_cc()
(define_insn "xorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (xor:HI (match_operand:HI 1 "register_operand" "%0")
                (match_operand:HI 2 "register_operand" "r")))]
  ""
  "dxrr.m %0,%2")

;; NAND

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
	(ior:QI (not:QI (match_operand:QI 1 "register_operand" "%0,0,0"))
		(not:QI (match_operand:QI 2 "general_operand" "M,r,m"))))]
  ""
  "@
    nim r%0,%2
    nr  r%0,r%2
    n   r%0,%2 ")

; This sets incorrect condition codes. See notice_update_cc()
(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ior:HI (not:HI (match_operand:HI 1 "register_operand" "%0"))
		(not:HI (match_operand:HI 2 "register_operand" "r"))))]
  ""
  "dnr.m %0,%2")

;; NOT

(define_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
        (not:QI (match_operand:QI 1 "register_operand" "0")))]
  ""
  "nr r%0,r%0")

; This sets incorrect condition codes. See notice_update_cc()
(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (not:HI (match_operand:HI 1 "register_operand" "0")))]
  ""
  "dnr.m %0,%0")


;; Shift instructions

; (What to the 1750 is logical-shift-left, GCC likes to call "arithmetic")
(define_insn "ashlqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
        (ashift:QI (match_operand:QI 1 "register_operand" "0,0")
                   (match_operand:QI 2 "nonmemory_operand" "I,r")))]
  ""
  "@
    sll r%0,%2
    slr r%0,r%2 ")

(define_insn "ashlhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (ashift:HI (match_operand:HI 1 "register_operand" "0,0")
                   (match_operand:QI 2 "nonmemory_operand" "L,r")))]
  ""                        ; the 'L' constraint is a slight imprecise...
  "*
  if (which_alternative == 1)
    return \"dslr r%0,r%2\";
  else if (INTVAL(operands[2]) <= 16)
    return \"dsll r%0,%2\";
  else
  {
    rtx new_opnds[2];
    output_asm_insn(\"dsll r%0,16  ; ashlhi3 shiftcount > 16\",operands);
    new_opnds[0] = operands[0];
    new_opnds[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL(operands[2]) - 16);
    output_asm_insn(\"sll r%0,%1\",new_opnds);
    return \";\";
  } ")


;; Right shift by a variable shiftcount works by negating the shift count,
;; then emitting a right shift with the shift count negated.  This means
;; that all actual shift counts in the RTL will be positive.  This 
;; prevents converting shifts to ZERO_EXTRACTs with negative positions,
;; which isn't valid.
(define_expand "lshrqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "g")))]
  ""
  "
{
  if (GET_CODE (operands[2]) != CONST_INT)
    operands[2] = gen_rtx (NEG, QImode, negate_rtx (QImode, operands[2]));
}")

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "I")))]
  ""
  "srl r%0,%2")

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
  ""
  "slr r%0,r%2 ")

;; Same thing for HImode.

(define_expand "lshrhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "g")))]
  ""
  "
  {
    if (GET_CODE (operands[2]) != CONST_INT)
      operands[2] = gen_rtx (NEG, QImode, negate_rtx (QImode, operands[2]));
  }")

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "L")))]
  ""
  "*
  {
    rtx new_opnds[2];
    int amount = INTVAL(operands[2]);
    if (amount <= 16)
      return \"dsrl r%0,%2\";
    output_asm_insn(\"dsrl r%0,16  ; lshrhi3 shiftcount > 16\",operands);
    new_opnds[0] = gen_rtx (REG, QImode, REGNO(operands[0]) + 1);
    new_opnds[1] = gen_rtx (CONST_INT, VOIDmode, amount - 16);
    output_asm_insn(\"srl  r%0,%1\",new_opnds);
    return \";\";
  } ")

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
  ""
  "dslr r%0,r%2 ")

;; Same applies for arithmetic shift right.
(define_expand "ashrqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "g")))]
  ""
  "
  {
    if (GET_CODE (operands[2]) != CONST_INT)
      operands[2] = gen_rtx (NEG, QImode, negate_rtx (QImode, operands[2]));
  }")

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "I")))]
  ""
  "sra r%0,%2")

(define_insn ""
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
  ""
  "sar r%0,r%2 ")

;; HImode arithmetic shift right.
(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "g")))]
  ""
  "
  {
    if (GET_CODE (operands[2]) != CONST_INT)
      operands[2] = gen_rtx (NEG, QImode, negate_rtx (QImode, operands[2]));
  }")

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "L")))]
  ""
  "*
  {
    rtx new_opnds[2];
    int amount = INTVAL(operands[2]);
    if (amount <= 16)
      return \"dsra r%0,%2\";
    output_asm_insn(\"dsra r%0,16  ; ashrhi3 shiftcount > 16\",operands);
    new_opnds[0] = gen_rtx (REG, QImode, REGNO(operands[0]) + 1);
    new_opnds[1] = gen_rtx (CONST_INT, VOIDmode, amount - 16);
    output_asm_insn(\"sra  r%0,%1\",new_opnds);
    return \";\";
  } ")

(define_insn ""
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
  ""
  "dsar r%0,r%2 ")


;; rotate instructions

(define_insn "rotlqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
        (rotate:QI (match_operand:QI 1 "register_operand" "0,0")
                   (match_operand:QI 2 "nonmemory_operand" "I,r")))]
  ""
  "@
    slc r%0,%2
    scr r%0,r%2 ")

(define_insn "rotlhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
        (rotate:HI (match_operand:HI 1 "register_operand" "0,0")
                   (match_operand:QI 2 "nonmemory_operand" "I,r")))]
  ""
  "@
    dslc r%0,%2
    dscr r%0,r%2 ")

(define_insn "rotrqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
        (rotatert:QI (match_operand:QI 1 "register_operand" "0")
                     (match_operand:QI 2 "register_operand" "r")))]
  ""
  "neg r%2,r%2\;scr r%0,r%2 ")

(define_insn "rotrhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
        (rotatert:HI (match_operand:HI 1 "register_operand" "0")
                     (match_operand:QI 2 "nonmemory_operand" "r")))]
  ""
  "neg  r%2,r%2\;dscr r%0,r%2 ")



;; Special cases of bit-field insns which we should
;; recognize in preference to the general case.
;; These handle aligned 8-bit and 16-bit fields,
;; which can usually be done with move instructions.
;    1750: t.b.d.
;********************

;; Bit field instructions, general cases.
;; "o,d" constraint causes a nonoffsetable memref to match the "o"
;; so that its address is reloaded.

;; (define_insn "extv" ...

;; (define_insn "extzv" ...

;; (define_insn "insv" ...

;; Now recognize bit field insns that operate on registers
;; (or at least were intended to do so).
;[unnamed only]

;; Special patterns for optimizing bit-field instructions.
;**************************************

; cc status test ops n.a. on 1750 ......... e.g. "sleu" on 68k:
;  [(set (match_operand:QI 0 "general_operand" "=d")
;        (leu (cc0) (const_int 0)))]
;  ""
;  "* cc_status = cc_prev_status;
;     return \"sls %0\"; ")


;; Basic conditional jump instructions.

(define_insn "beq"
  [(set (pc)
        (if_then_else (eq (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"ez\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn "bne"
  [(set (pc)
        (if_then_else (ne (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"nz\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn "bgt"
  [(set (pc)
        (if_then_else (gt (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"gt\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn "blt"
  [(set (pc)
        (if_then_else (lt (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"lt\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn "bge"
  [(set (pc)
        (if_then_else (ge (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"ge\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn "ble"
  [(set (pc)
        (if_then_else (le (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "* return (char *)branch_or_jump(\"le\",CODE_LABEL_NUMBER(operands[0]));
  ")


; no unsigned branches available on 1750. But GCC still needs them, so faking:

(define_insn "bgtu"
  [(set (pc)
        (if_then_else (gtu (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "jc gt,%l0 ; Warning: this should be an *unsigned* test!")

(define_insn "bltu"
  [(set (pc)
        (if_then_else (ltu (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "jc lt,%l0 ; Warning: this should be an *unsigned* test!")

(define_insn "bgeu"
  [(set (pc)
        (if_then_else (geu (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "jc ge,%l0 ; Warning: this should be an *unsigned* test!")

(define_insn "bleu"
  [(set (pc)
        (if_then_else (leu (cc0)
                          (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  ""
  "jc le,%l0 ; Warning: this should be an *unsigned* test!")


;; Negated conditional jump instructions.

(define_insn ""
  [(set (pc)
        (if_then_else (eq (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"nz\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn ""
  [(set (pc)
        (if_then_else (ne (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"ez\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn ""
  [(set (pc)
        (if_then_else (gt (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"le\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn ""
  [(set (pc)
        (if_then_else (lt (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"ge\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn ""
  [(set (pc)
        (if_then_else (ge (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"lt\",CODE_LABEL_NUMBER(operands[0]));
  ")

(define_insn ""
  [(set (pc)
        (if_then_else (le (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "* return (char *)branch_or_jump(\"gt\",CODE_LABEL_NUMBER(operands[0]));
  ")


;; Negated unsigned conditional jump instructions (faked for 1750).

(define_insn ""
  [(set (pc)
        (if_then_else (gtu (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "jc le,%l0 ;inv.cond. ;Warning: this should be an *unsigned* test!")

(define_insn ""
  [(set (pc)
        (if_then_else (ltu (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "jc ge,%l0 ;inv.cond. ;Warning: this should be an *unsigned* test!")

(define_insn ""
  [(set (pc)
        (if_then_else (geu (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "jc lt,%l0 ;inv.cond. ;Warning: this should be an *unsigned* test!")

(define_insn ""
  [(set (pc)
        (if_then_else (leu (cc0)
                          (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
  ""
  "jc gt,%l0 ;inv.cond. ;Warning: this should be an *unsigned* test!")

;; Tablejump 
;; 1750 note: CASE_VECTOR_PC_RELATIVE is not defined
(define_insn "tablejump"
  [(set (pc)
        (match_operand:QI 0 "register_operand" "b"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jc 15,0,r%0   ; tablejump label_ref=%1")


;; Unconditional jump
(define_insn "jump"
  [(set (pc)
        (label_ref (match_operand 0 "" "")))]
  ""
  "jc 15,%0")

;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(define_insn "call_value"
  [(set (match_operand 0 "register_operand" "r")
        (call (match_operand:QI 1 "memory_operand" "m")
              (match_operand:QI 2 "general_operand" "g")))]
  ;; Operand 2 not really used for 1750.
  ""
  "sjs r15,%1   ; return value in R0")

;; Call subroutine with no return value.

;;  Operand 1 not really used in MIL-STD-1750.
(define_insn ""
  [(call (match_operand:QI 0 "memory_operand" "mp")
         (match_operand:QI 1 "general_operand" ""))]
  ""
  "sjs r15,%0   ; no return value")

;;;;;;;;;;;; 1750: NOT READY YET.
(define_insn "call"
  [(call (match_operand:QI 0 "" "")
         (match_operand:QI 1 "" ""))]
  ""
  "ANYCALL %0")


; (define_insn "return"
;   [(return)]
;   ""
;   "*
;    { 
;         rtx oprnd = gen_rtx(CONST_INT,VOIDmode,get_frame_size());
;         output_asm_insn(\"ret.m  %0\",&oprnd);
;         return \"\;\";
;    } ")

(define_insn "indirect_jump"
  [(set (pc) (match_operand:QI 0 "address_operand" "p"))]
  ""
  "jci 15,%0")

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


;; Subtract One and Jump (if non-zero)
(define_peephole 
  [(set (match_operand:QI 0 "register_operand" "=r")
        (plus:QI (match_operand:QI 1 "register_operand" "%0")
                 (match_operand:QI 2 "immediate_operand" "J")))
   (set (cc0) (match_dup 0))
   (set (pc)
        (if_then_else (ne (cc0) (const_int 0))
         (label_ref (match_operand 3 "" ""))
         (pc)))
   ]
  "INTVAL(operands[2]) == -1"
  "soj r%0,%3")

;; Combine a Load Register with subsequent increment/decrement into a LIM
(define_peephole 
  [(set (match_operand:QI 0 "register_operand" "=r")
        (match_operand:QI 1 "register_operand" "b"))
   (set (match_dup 0)
        (plus:QI (match_dup 0)
                 (match_operand:QI 2 "immediate_operand" "i")))]
  "REGNO(operands[1]) > 0"
  "lim r%0,%2,r%1  ; LR,inc/dec peephole")

;; Eliminate the redundant load in a store/load sequence
(define_peephole 
  [(set (mem:QI (plus:QI (match_operand:QI 0 "register_operand" "r")
			  (match_operand:QI 1 "immediate_operand" "i")))
	(match_operand:QI 2 "register_operand" "r"))
   (set (match_operand:QI 3 "register_operand" "=r")
	(mem:QI (plus:QI (match_dup 0)
			 (match_dup 1))))
   ]
  "REGNO(operands[2]) == REGNO(operands[3])"
  "st r%2,%1,r%0  ; eliminated previous redundant load")

;;;End.
