aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/stormy16/stormy16.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/stormy16/stormy16.md')
-rw-r--r--gcc-4.9/gcc/config/stormy16/stormy16.md1250
1 files changed, 1250 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/stormy16/stormy16.md b/gcc-4.9/gcc/config/stormy16/stormy16.md
new file mode 100644
index 000000000..c19321365
--- /dev/null
+++ b/gcc-4.9/gcc/config/stormy16/stormy16.md
@@ -0,0 +1,1250 @@
+;; XSTORMY16 Machine description template
+;; Copyright (C) 1997-2014 Free Software Foundation, Inc.
+;; Contributed by Red Hat, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; Constraints
+;; a $0
+;; b $1
+;; c $2
+;; d $8
+;; e $0..$7
+;; t $0..$1
+;; z $8..$9
+;; I 0..3
+;; J 2**N mask
+;; K 2**N antimask
+;; L 0..255
+;; M -255..0
+;; N -3..0
+;; O 1..4
+;; P -4..-1
+;; Q post-inc mem (push)
+;; R pre-dec mem (pop)
+;; S immediate mem
+;; T Rx
+;; U -inf..1 or 16..inf
+;; Z 0
+
+(define_constants
+ [
+ (CARRY_REG 16)
+ ]
+)
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Attributes
+;; ::
+;; ::::::::::::::::::::
+
+; Categorize branches for the conditional in the length attribute.
+(define_attr "branch_class" "notdirectbranch,br12,bcc12,bcc8p2,bcc8p4"
+ (const_string "notdirectbranch"))
+
+; The length of an instruction, used for branch shortening.
+(define_attr "length" ""
+ (cond
+ [(eq_attr "branch_class" "br12")
+ (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2046))
+ (lt (minus (match_dup 0) (pc)) (const_int 2048)))
+ (const_int 2)
+ (const_int 4))
+ (eq_attr "branch_class" "bcc12")
+ (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
+ (lt (minus (match_dup 0) (pc)) (const_int 2048)))
+ (const_int 4)
+ (const_int 8))
+ (eq_attr "branch_class" "bcc8p2")
+ (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -124))
+ (lt (minus (match_dup 0) (pc)) (const_int 128)))
+ (const_int 4)
+ (const_int 8))
+ (eq_attr "branch_class" "bcc8p4")
+ (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -122))
+ (lt (minus (match_dup 0) (pc)) (const_int 128)))
+ (const_int 6)
+ (const_int 10))]
+ (const_int 2)))
+
+; The operand which determines the setting of Rpsw.
+; The numbers indicate the operand number,
+; 'clobber' indicates it is changed in some unspecified way
+; 'nop' means it is not changed.
+(define_attr "psw_operand" "clobber,nop,0,1,2,3,4" (const_string "0"))
+
+(define_asm_attributes [(set_attr "length" "4")
+ (set_attr "psw_operand" "clobber")])
+
+(include "predicates.md")
+(include "constraints.md")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Moves
+;; ::
+;; ::::::::::::::::::::
+;; push/pop qi and hi are here as separate insns rather than part of
+;; the movqi/hi patterns because we need to ensure that reload isn't
+;; passed anything it can't cope with. Without these patterns, we
+;; might end up with
+
+;; (set (mem (post_inc (sp))) mem (post_inc (reg)))
+
+;; If, in this example, reg needs reloading, reload will read reg from
+;; the stack , adjust sp, and store reg back at what is now the wrong
+;; offset. By using separate patterns for push and pop we ensure that
+;; insns like this one are never generated.
+
+(define_insn "pushqi1"
+ [(set (mem:QI (post_inc:HI (reg:HI 15)))
+ (match_operand:QI 0 "register_operand" "r"))]
+ ""
+ "push %0"
+ [(set_attr "psw_operand" "nop")
+ (set_attr "length" "2")])
+
+(define_insn "popqi1"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (pre_dec:HI (reg:HI 15))))]
+ ""
+ "pop %0"
+ [(set_attr "psw_operand" "nop")
+ (set_attr "length" "2")])
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_nonstack_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ { xstormy16_expand_move (QImode, operands[0], operands[1]);
+ DONE;
+ })
+
+(define_insn "movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S,W,e")
+ (match_operand:QI 1 "general_operand" "r,e,m,i,i,i,i,ie,W"))]
+ ""
+ "@
+ mov %0,%1
+ mov.b %0,%1
+ mov.b %0,%1
+ mov %0,%1
+ mov Rx,%1
+ mov %0,%1
+ mov.b %0,%1
+ mov.b %0,%1
+ mov.b %0,%1"
+ [(set_attr_alternative "length"
+ [(const_int 2)
+ (if_then_else (match_operand:QI 0 "short_memory_operand" "")
+ (const_int 2)
+ (const_int 4))
+ (if_then_else (match_operand:QI 1 "short_memory_operand" "")
+ (const_int 2)
+ (const_int 4))
+ (const_int 2)
+ (const_int 2)
+ (const_int 4)
+ (const_int 4)
+ (const_int 2)
+ (const_int 2)])
+ (set_attr "psw_operand" "0,0,0,0,nop,0,nop,0,0")])
+
+(define_insn "pushhi1"
+ [(set (mem:HI (post_inc:HI (reg:HI 15)))
+ (match_operand:HI 0 "register_operand" "r"))]
+ ""
+ "push %0"
+ [(set_attr "psw_operand" "nop")
+ (set_attr "length" "2")])
+
+(define_insn "pophi1"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (pre_dec:HI (reg:HI 15))))]
+ ""
+ "pop %0"
+ [(set_attr "psw_operand" "nop")
+ (set_attr "length" "2")])
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_nonstack_operand" "")
+ (match_operand:HI 1 "xs_hi_general_operand" ""))]
+ ""
+ { xstormy16_expand_move (HImode, operands[0], operands[1]);
+ DONE;
+ })
+
+(define_insn "movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_nonstack_operand" "=r,m,e,e,T,r,S,W,e")
+ (match_operand:HI 1 "xs_hi_general_operand" "r,e,m,L,L,i,i,ie,W"))]
+ ""
+ "@
+ mov %0,%1
+ mov.w %0,%1
+ mov.w %0,%1
+ mov.w %0,%1
+ mov.w Rx,%1
+ mov.w %0,%1
+ mov.w %0,%1
+ mov.w %0,%1
+ mov.w %0,%1"
+ [(set_attr_alternative "length"
+ [(const_int 2)
+ (if_then_else (match_operand:QI 0 "short_memory_operand" "")
+ (const_int 2)
+ (const_int 4))
+ (if_then_else (match_operand:QI 1 "short_memory_operand" "")
+ (const_int 2)
+ (const_int 4))
+ (const_int 2)
+ (const_int 2)
+ (const_int 4)
+ (const_int 4)
+ (const_int 4)
+ (const_int 4)])
+ (set_attr "psw_operand" "0,0,0,0,nop,0,nop,0,0")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ { xstormy16_expand_move (SImode, operands[0], operands[1]);
+ DONE;
+ })
+
+(define_insn_and_split "*movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Q,r,m,e,&e,e,r,S")
+ (match_operand:SI 1 "general_operand" "r,r,R,e,o, V,L,i,i"))]
+ ""
+ "#"
+ "reload_completed"
+ [(pc)]
+ { xstormy16_split_move (SImode, operands[0], operands[1]);
+ DONE;
+ }
+ [(set_attr_alternative "length"
+ [(const_int 4)
+ (const_int 4)
+ (const_int 4)
+ (if_then_else (match_operand:QI 0 "short_memory_operand" "")
+ (const_int 6)
+ (const_int 8))
+ (if_then_else (match_operand:QI 1 "short_memory_operand" "")
+ (const_int 6)
+ (const_int 8))
+ (if_then_else (match_operand:QI 1 "short_memory_operand" "")
+ (const_int 6)
+ (const_int 8))
+ (const_int 4)
+ (const_int 8)
+ (const_int 8)])])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Conversions
+;; ::
+;; ::::::::::::::::::::
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "cbw %0")
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=e,r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,0")))]
+ ""
+ "@
+ mov.b %0, %1
+ shl %0,#8\n\tshr %0,#8"
+ [(set_attr "psw_operand" "nop,0")
+ (set_attr_alternative "length"
+ [(const_int 4)
+ (const_int 8)])])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Bit field extraction
+;; ::
+;; ::::::::::::::::::::
+
+;; Extract an unsigned bit field
+;(define_insn "extzv"
+; [(set (match_operand:SI 0 "register_operand" "=r")
+; (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+; (match_operand:SI 2 "const_int_operand" "n")
+; (match_operand:SI 3 "const_int_operand" "n")))]
+; ""
+; "extzv %0,%1,%2,%3"
+; [(set_attr "length" "4")])
+
+;; Insert a bit field
+;(define_insn "insv"
+; [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
+; (match_operand:SI 1 "const_int_operand" "n")
+; (match_operand:SI 2 "const_int_operand" "n"))
+; (match_operand:SI 3 "nonmemory_operand" "ri"))]
+; ""
+; "insv %0,%1,%2,%3"
+; [(set_attr "length" "4")])
+
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 16-bit Integer arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+; Note - the early clobber modifier is no longer needed on operand 3
+; and in fact can cause some reload spill failures if it is present.
+; Note that the 'Z' constraint matches "add $reg,0", which reload
+; will occasionally emit. We avoid the "add $reg,imm" match because
+; it clobbers the carry.
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,T,T,r,r,r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,0,0")
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "O,P,Z,L,M,Ir,N,i")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "@
+ inc %0,%o2
+ dec %0,%O2
+ ;
+ add Rx,%2
+ sub Rx,#%n2
+ add %0,%2
+ sub %0,#%n2
+ add %0,%2"
+ [(set_attr "length" "2,2,0,2,2,2,2,4")])
+
+(define_insn "addchi4"
+ [(set (match_operand:HI 0 "register_operand" "=T,r,r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "L,Ir,i")))
+ (set (reg:BI CARRY_REG)
+ (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1))
+ (zero_extend:SI (match_dup 2)))
+ (const_int 16))))]
+ ""
+ "@
+ add Rx,%2
+ add %0,%2
+ add %0,%2"
+ [(set_attr "length" "2,2,4")])
+
+(define_insn "addchi5"
+ [(set (match_operand:HI 0 "register_operand" "=T,r,r")
+ (plus:HI (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+ (zero_extend:HI (reg:BI CARRY_REG)))
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "L,Ir,i")))
+ (set (reg:BI CARRY_REG)
+ (truncate:BI (lshiftrt:SI (plus:SI (plus:SI
+ (zero_extend:SI (match_dup 1))
+ (zero_extend:SI (reg:BI CARRY_REG)))
+ (zero_extend:SI (match_dup 2)))
+ (const_int 16))))]
+ ""
+ "@
+ adc Rx,%2
+ adc %0,%2
+ adc %0,%2"
+ [(set_attr "length" "2,2,4")])
+
+;; Subtraction
+; Operand 3 is marked earlyclobber because that helps reload
+; to generate better code---this pattern will never need the
+; carry register as an input, and some output reloads or input
+; reloads might need to use it. In fact, without the '&' reload
+; will fail in some cases.
+(define_insn "subhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,T,T,r,r,r")
+ (minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0,0,0,0")
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "O,P,L,M,rI,M,i")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "@
+ dec %0,%o2
+ inc %0,%O2
+ sub Rx,%2
+ add Rx,#%n2
+ sub %0,%2
+ add %0,#%n2
+ sub %0,%2"
+ [(set_attr "length" "2,2,2,2,2,2,4")])
+
+(define_insn "subchi4"
+ [(set (match_operand:HI 0 "register_operand" "=T,r,r")
+ (minus:HI (match_operand:HI 1 "register_operand" "0,0,0")
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "L,Ir,i")))
+ (set (reg:BI CARRY_REG)
+ (truncate:BI (lshiftrt:SI (minus:SI (zero_extend:SI (match_dup 1))
+ (zero_extend:SI (match_dup 2)))
+ (const_int 16))))]
+ ""
+ "@
+ sub Rx,%2
+ sub %0,%2
+ sub %0,%2"
+ [(set_attr "length" "2,2,4")])
+
+(define_insn "subchi5"
+ [(set (match_operand:HI 0 "register_operand" "=T,r,r")
+ (minus:HI (minus:HI (match_operand:HI 1 "register_operand" "0,0,0")
+ (zero_extend:HI (reg:BI CARRY_REG)))
+ (match_operand:HI 2 "xs_hi_nonmemory_operand" "L,Ir,i")))
+ (set (reg:BI CARRY_REG)
+ (truncate:BI (lshiftrt:SI (minus:SI (minus:SI
+ (zero_extend:SI (match_dup 1))
+ (zero_extend:SI (reg:BI CARRY_REG)))
+ (zero_extend:SI (match_dup 2)))
+ (const_int 16))))]
+ ""
+ "@
+ sbc Rx,%2
+ sbc %0,%2
+ sbc %0,%2"
+ [(set_attr "length" "2,2,4")])
+
+; Basic multiplication
+(define_insn "mulhi3"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (mult:HI (match_operand:HI 1 "register_operand" "%a")
+ (match_operand:HI 2 "register_operand" "c")))
+ (clobber (match_scratch:HI 3 "=b"))
+ ]
+ ""
+ "mul"
+ [(set_attr "psw_operand" "nop")])
+
+;; Unsigned multiplication producing 64-bit results from 32-bit inputs
+; The constraint on operand 0 is 't' because it is actually two regs
+; long, and both regs must match the constraint.
+(define_insn "umulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=t")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%a"))
+ (zero_extend:SI (match_operand:HI 2 "register_operand" "c"))))
+ ]
+ ""
+ "mul"
+ [(set_attr "psw_operand" "nop")])
+
+;; Unsigned division giving both quotient and remainder
+(define_insn "udivmodhi4"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (udiv:HI (match_operand:HI 1 "register_operand" "a")
+ (match_operand:HI 2 "register_operand" "c")))
+ (set (match_operand:HI 3 "register_operand" "=b")
+ (umod:HI (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "div"
+ [(set_attr "psw_operand" "nop")])
+
+;; Signed division giving both quotient and remainder
+(define_insn "divmodhi4"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (div:HI (match_operand:HI 1 "register_operand" "a")
+ (match_operand:HI 2 "register_operand" "c")))
+ (set (match_operand:HI 3 "register_operand" "=b")
+ (mod:HI (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "sdiv"
+ [(set_attr "psw_operand" "nop")])
+
+;; Signed 32/16 division
+(define_insn "sdivlh"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (div:HI (match_operand:SI 2 "register_operand" "t")
+ (match_operand:HI 3 "register_operand" "c")))
+ (set (match_operand:HI 1 "register_operand" "=b")
+ (mod:HI (match_dup 2)
+ (match_dup 3)))]
+ ""
+ "sdivlh"
+ [(set_attr "psw_operand" "nop")])
+
+;; Unsigned 32/16 division
+(define_insn "udivlh"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (udiv:HI (match_operand:SI 2 "register_operand" "t")
+ (match_operand:HI 3 "register_operand" "c")))
+ (set (match_operand:HI 1 "register_operand" "=b")
+ (umod:HI (match_dup 2)
+ (match_dup 3)))]
+ ""
+ "divlh"
+ [(set_attr "psw_operand" "nop")])
+
+;; Negation
+
+(define_expand "neghi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (not:HI (match_operand:HI 1 "register_operand" "")))
+ (parallel [(set (match_dup 0) (plus:HI (match_dup 0) (const_int 1)))
+ (clobber (reg:BI CARRY_REG))])]
+ ""
+ "")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 16-bit Integer Shifts and Rotates
+;; ::
+;; ::::::::::::::::::::
+
+;; Arithmetic Shift Left
+(define_insn "ashlhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (ashift:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "nonmemory_operand" "ri")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "shl %0,%2")
+
+;; Arithmetic Shift Right
+(define_insn "ashrhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "nonmemory_operand" "ri")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "asr %0,%2")
+
+;; Logical Shift Right
+(define_insn "lshrhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "nonmemory_operand" "ri")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "shr %0,%2")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 16-Bit Integer Logical operations
+;; ::
+;; ::::::::::::::::::::
+
+;; Logical AND, 16-bit integers
+(define_insn "andhi3"
+ [(set (match_operand:HI 0 "xstormy16_splittable_below100_or_register" "=T,r,r,r,W")
+ (and:HI (match_operand:HI 1 "xstormy16_below100_or_register" "%0,0,0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "L,r,K,i,K")))]
+ ""
+ "@
+ and Rx,%2
+ and %0,%2
+ clr1 %0,%B2
+ and %0,%2
+ #"
+ [(set_attr "length" "2,2,2,4,2")])
+
+(define_split
+ [(set (match_operand:HI 0 "xstormy16_below100_operand" "")
+ (and:HI (match_operand:HI 1 "xstormy16_below100_operand" "")
+ (match_operand:HI 2 "xstormy16_onebit_clr_operand" "")))]
+ ""
+ [(set (match_dup 3)
+ (and:QI (match_dup 4)
+ (match_dup 5)))]
+ { int s = ((INTVAL (operands[2]) & 0xff) == 0xff) ? 1 : 0;
+ operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, s);
+ operands[4] = simplify_gen_subreg (QImode, operands[1], HImode, s);
+ operands[5] = simplify_gen_subreg (QImode, operands[2], HImode, s);
+ operands[5] = GEN_INT (INTVAL (operands[5]) | ~ (HOST_WIDE_INT) 0xff);
+ })
+
+;; Inclusive OR, 16-bit integers
+(define_insn "iorhi3"
+ [(set (match_operand:HI 0 "xstormy16_splittable_below100_or_register" "=T,r,r,r,W")
+ (ior:HI (match_operand:HI 1 "xstormy16_below100_or_register" "%0,0,0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "L,r,J,i,J")))]
+ ""
+ "@
+ or Rx,%2
+ or %0,%2
+ set1 %0,%B2
+ or %0,%2
+ #"
+ [(set_attr "length" "2,2,2,4,2")])
+
+(define_split
+ [(set (match_operand:HI 0 "xstormy16_below100_operand" "")
+ (ior:HI (match_operand:HI 1 "xstormy16_below100_operand" "")
+ (match_operand:HI 2 "xstormy16_onebit_set_operand" "")))]
+ ""
+ [(set (match_dup 3)
+ (ior:QI (match_dup 4)
+ (match_dup 5)))]
+ { int s = ((INTVAL (operands[2]) & 0xff) == 0x00) ? 1 : 0;
+ operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, s);
+ operands[4] = simplify_gen_subreg (QImode, operands[1], HImode, s);
+ operands[5] = simplify_gen_subreg (QImode, operands[2], HImode, s);
+ operands[5] = GEN_INT (INTVAL (operands[5]) & 0xff);
+ })
+
+;; Exclusive OR, 16-bit integers
+(define_insn "xorhi3"
+ [(set (match_operand:HI 0 "register_operand" "=T,r,r")
+ (xor:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "L,r,i")))]
+ ""
+ "@
+ xor Rx,%2
+ xor %0,%2
+ xor %0,%2"
+ [(set_attr "length" "2,2,4")])
+
+;; One's complement, 16-bit integers
+(define_insn "one_cmplhi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (not:HI (match_operand:HI 1 "register_operand" "0")))]
+ ""
+ "not %0")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 32-bit Integer arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn_and_split "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "nonmemory_operand" "ri")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(pc)]
+ { xstormy16_expand_arith (SImode, PLUS, operands[0], operands[1],
+ operands[2]);
+ DONE;
+ }
+ [(set_attr "length" "4")])
+
+;; Subtraction
+(define_insn_and_split "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "nonmemory_operand" "ri")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(pc)]
+ { xstormy16_expand_arith (SImode, MINUS, operands[0], operands[1],
+ operands[2]);
+ DONE;
+ }
+ [(set_attr "length" "4")])
+
+(define_expand "negsi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (neg:SI (match_operand:SI 1 "register_operand" "")))
+ (clobber (reg:BI CARRY_REG))])]
+ ""
+ { operands[2] = gen_reg_rtx (HImode); })
+
+(define_insn_and_split "*negsi2_internal"
+ [(set (match_operand:SI 0 "register_operand" "=&r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(pc)]
+ { xstormy16_expand_arith (SImode, NEG, operands[0], operands[0],
+ operands[1]);
+ DONE;
+ })
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 32-bit Integer Shifts and Rotates
+;; ::
+;; ::::::::::::::::::::
+
+;; Arithmetic Shift Left
+(define_expand "ashlsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashift:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (reg:BI CARRY_REG))
+ (clobber (match_dup 3))])]
+ ""
+ { if (! const_int_operand (operands[2], SImode))
+ FAIL;
+ operands[3] = gen_reg_rtx (HImode);
+ })
+
+;; Arithmetic Shift Right
+(define_expand "ashrsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (reg:BI CARRY_REG))
+ (clobber (match_dup 3))])]
+ ""
+ { if (! const_int_operand (operands[2], SImode))
+ FAIL;
+ operands[3] = gen_reg_rtx (HImode);
+ })
+
+;; Logical Shift Right
+(define_expand "lshrsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (reg:BI CARRY_REG))
+ (clobber (match_dup 3))])]
+ ""
+ { if (! const_int_operand (operands[2], SImode))
+ FAIL;
+ operands[3] = gen_reg_rtx (HImode);
+ })
+
+(define_insn "*shiftsi"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "const_int_operand" "U,n")]))
+ (clobber (reg:BI CARRY_REG))
+ (clobber (match_operand:HI 3 "" "=X,r"))]
+ ""
+ "* return xstormy16_output_shift (SImode, GET_CODE (operands[4]),
+ operands[0], operands[2], operands[3]);"
+ [(set_attr "length" "6,10")
+ (set_attr "psw_operand" "clobber,clobber")])
+
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Branches
+;; ::
+;; ::::::::::::::::::::
+
+(define_expand "cbranchhi4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ {
+ xstormy16_emit_cbranch (GET_CODE (operands[0]), operands[1], operands[2],
+ operands[3]);
+ DONE;
+})
+
+(define_insn "cbranchhi"
+ [(set (pc)
+ (if_then_else (match_operator:HI 1 "comparison_operator"
+ [(match_operand:HI 2 "nonmemory_operand"
+ "r,e,L")
+ (match_operand:HI 3 "nonmemory_operand"
+ "r,L,e")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "*
+{
+ return xstormy16_output_cbranch_hi (operands[1], \"%l0\", 0, insn);
+}"
+ [(set_attr "branch_class" "bcc12")
+ (set_attr "psw_operand" "0,0,1")])
+
+(define_insn "cbranchhi_neg"
+ [(set (pc)
+ (if_then_else (match_operator:HI 1 "comparison_operator"
+ [(match_operand:HI 2 "nonmemory_operand"
+ "r,e,L")
+ (match_operand:HI 3 "nonmemory_operand"
+ "r,L,e")])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "*
+{
+ return xstormy16_output_cbranch_hi (operands[1], \"%l0\", 1, insn);
+}"
+ [(set_attr "branch_class" "bcc12")
+ (set_attr "psw_operand" "0,0,1")])
+
+(define_insn "*eqbranchsi"
+ [(set (pc)
+ (if_then_else (match_operator:SI 1 "equality_operator"
+ [(match_operand:SI 2 "register_operand"
+ "r")
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (match_operand:SI 3 "register_operand" "=2"))]
+ ""
+ "*
+{
+ return xstormy16_output_cbranch_si (operands[1], \"%l0\", 0, insn);
+}"
+ [(set_attr "branch_class" "bcc8p2")
+ (set_attr "psw_operand" "clobber")])
+
+(define_insn "*ineqbranch_1"
+ [(set (pc)
+ (if_then_else (match_operator:HI 4 "xstormy16_ineqsi_operator"
+ [(minus:HI (match_operand:HI 1 "register_operand" "T,r,r")
+ (zero_extend:HI (reg:BI CARRY_REG)))
+ (match_operand:HI 3 "nonmemory_operand" "L,r,i")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:HI 2 "register_operand" "=1,1,1")
+ (minus:HI (minus:HI (match_dup 1) (zero_extend:HI (reg:BI CARRY_REG)))
+ (match_dup 3)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "*
+{
+ return xstormy16_output_cbranch_si (operands[4], \"%l0\", 0, insn);
+}"
+ [(set_attr "branch_class" "bcc8p2,bcc8p2,bcc8p4")
+ (set_attr "psw_operand" "2,2,2")])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Call and branch instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Subroutine call instruction returning no value. Operand 0 is the function
+;; to call; operand 1 is the number of bytes of arguments pushed (in mode
+;; `SImode', except it is normally a `const_int'); operand 2 is the number of
+;; registers used as operands.
+
+;; On most machines, operand 2 is not actually stored into the RTL pattern. It
+;; is supplied for the sake of some RISC machines which need to put this
+;; information into the assembler code; they can put it in the RTL instead of
+;; operand 1.
+
+(define_expand "call"
+ [(call (match_operand:HI 0 "memory_operand" "m")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "immediate_operand" ""))]
+ ""
+ "xstormy16_expand_call (NULL_RTX, operands[0], operands[1]); DONE;")
+
+;; Subroutine call instruction returning a value. Operand 0 is the hard
+;; register in which the value is returned. There are three more operands, the
+;; same as the three operands of the `call' instruction (but with numbers
+;; increased by one).
+
+;; Subroutines that return `BLKmode' objects use the `call' insn.
+
+(define_expand "call_value"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (match_operand:HI 1 "memory_operand" "m")
+ (match_operand:SI 2 "" "")))
+ (use (match_operand 3 "immediate_operand" ""))]
+ ""
+ "xstormy16_expand_call (operands[0], operands[1], operands[2]); DONE;")
+
+(define_insn "*call_internal"
+ [(call (mem:HI (match_operand:HI 0 "nonmemory_operand" "i,r"))
+ (match_operand 1 "" ""))
+ (use (match_operand:HI 2 "nonmemory_operand" "X,z"))]
+ ""
+ "@
+ callf %C0
+ call %2,%0"
+ [(set_attr "length" "4,2")
+ (set_attr "psw_operand" "clobber")])
+
+(define_insn "*call_value_internal"
+ [(set (match_operand 3 "register_operand" "=r,r")
+ (call (mem:HI (match_operand:HI 0 "nonmemory_operand" "i,r"))
+ (match_operand 1 "" "")))
+ (use (match_operand:HI 2 "nonmemory_operand" "X,z"))]
+ ""
+ "@
+ callf %C0
+ call %2,%0"
+ [(set_attr "length" "4,2")
+ (set_attr "psw_operand" "clobber")])
+
+;; Subroutine return
+(define_expand "return"
+ [(return)]
+ "direct_return()"
+ "")
+
+(define_insn "return_internal"
+ [(return)]
+ ""
+ "ret"
+ [(set_attr "psw_operand" "nop")])
+
+(define_insn "return_internal_interrupt"
+ [(return)
+ (unspec_volatile [(const_int 0)] 1)]
+ ""
+ "iret"
+ [(set_attr "psw_operand" "clobber")])
+
+;; Normal unconditional jump
+(define_insn "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+{
+ return xstormy16_output_cbranch_hi (NULL_RTX, \"%l0\", 0, insn);
+}"
+ [(set_attr "branch_class" "br12")
+ (set_attr "psw_operand" "nop")])
+
+;; Indirect jump through a register
+(define_expand "indirect_jump"
+ [(set (match_dup 1) (const_int 0))
+ (parallel [(set (pc) (match_operand:HI 0 "register_operand" ""))
+ (use (match_dup 1))])]
+ ""
+ "operands[1] = gen_reg_rtx (HImode);")
+
+(define_insn ""
+ [(set (pc) (match_operand:HI 0 "register_operand" "r"))
+ (use (match_operand:HI 1 "register_operand" "z"))]
+ ""
+ "jmp %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+;; Table-based switch statements.
+(define_expand "casesi"
+ [(use (match_operand:SI 0 "register_operand" ""))
+ (use (match_operand:SI 1 "immediate_operand" ""))
+ (use (match_operand:SI 2 "immediate_operand" ""))
+ (use (label_ref (match_operand 3 "" "")))
+ (use (label_ref (match_operand 4 "" "")))]
+ ""
+ "
+{
+ xstormy16_expand_casesi (operands[0], operands[1], operands[2],
+ operands[3], operands[4]);
+ DONE;
+}")
+
+(define_insn "tablejump_pcrel"
+ [(set (pc) (mem:HI (plus:HI (pc)
+ (match_operand:HI 0 "register_operand" "r"))))
+ (use (label_ref:SI (match_operand 1 "" "")))]
+ ""
+ "br %0"
+ [(set_attr "psw_operand" "nop")])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Prologue and Epilogue instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; Called after register allocation to add any instructions needed for
+;; the prologue. Using a prologue insn is favored compared to putting
+;; all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE macro,
+;; since it allows the scheduler to intermix instructions with the
+;; saves of the caller saved registers. In some cases, it might be
+;; necessary to emit a barrier instruction as the last insn to prevent
+;; such scheduling.
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+ {
+ xstormy16_expand_prologue ();
+ DONE;
+ })
+
+;; Called after register allocation to add any instructions needed for
+;; the epilogue. Using an epilogue insn is favored compared to putting
+;; all of the instructions in the TARGET_ASM_FUNCTION_EPILOGUE macro,
+;; since it allows the scheduler to intermix instructions with the
+;; restores of the caller saved registers. In some cases, it might be
+;; necessary to emit a barrier instruction as the first insn to
+;; prevent such scheduling.
+(define_expand "epilogue"
+ [(const_int 2)]
+ ""
+ {
+ xstormy16_expand_epilogue ();
+ DONE;
+ })
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Miscellaneous instructions
+;; ::
+;; ::::::::::::::::::::
+
+;; No operation, needed in case the user uses -g but not -O.
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "psw_operand" "nop")])
+
+;; Pseudo instruction that prevents the scheduler from moving code above this
+;; point.
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ ""
+ [(set_attr "length" "0")
+ (set_attr "psw_operand" "nop")])
+
+;;---------------------------------------------------------------------------
+
+(define_expand "iorqi3"
+ [(match_operand:QI 0 "xstormy16_below100_or_register" "")
+ (match_operand:QI 1 "xstormy16_below100_or_register" "")
+ (match_operand:QI 2 "nonmemory_operand" "")]
+ ""
+ {
+ xstormy16_expand_iorqi3 (operands);
+ DONE;
+ })
+
+(define_insn "iorqi3_internal"
+ [(set (match_operand:QI 0 "xstormy16_below100_or_register" "=Wr")
+ (ior:QI (match_operand:QI 1 "xstormy16_below100_or_register" "0")
+ (match_operand:QI 2 "xstormy16_onebit_set_operand" "i")))]
+ ""
+ "set1 %0,%B2"
+ [(set_attr "length" "2")
+ (set_attr "psw_operand" "0")])
+
+(define_peephole2
+ [(set (match_operand:QI 0 "register_operand" "")
+ (match_operand:QI 1 "xstormy16_below100_operand" ""))
+ (set (match_operand:HI 2 "register_operand" "")
+ (ior:HI (match_operand:HI 3 "register_operand" "")
+ (match_operand:QI 4 "xstormy16_onebit_set_operand" "")))
+ (set (match_operand:QI 5 "xstormy16_below100_operand" "")
+ (match_operand:QI 6 "register_operand" ""))
+ ]
+ "REGNO (operands[0]) == REGNO (operands[2])
+ && REGNO (operands[0]) == REGNO (operands[3])
+ && REGNO (operands[0]) == REGNO (operands[6])
+ && rtx_equal_p (operands[1], operands[5])"
+ [(set (match_dup 1)
+ (ior:QI (match_dup 1)
+ (match_dup 4)))
+ ]
+ "")
+
+
+(define_expand "andqi3"
+ [(match_operand:QI 0 "xstormy16_below100_or_register" "")
+ (match_operand:QI 1 "xstormy16_below100_or_register" "")
+ (match_operand:QI 2 "nonmemory_operand" "")]
+ ""
+ {
+ xstormy16_expand_andqi3 (operands);
+ DONE;
+ })
+
+(define_insn "andqi3_internal"
+ [(set (match_operand:QI 0 "xstormy16_below100_or_register" "=Wr")
+ (and:QI (match_operand:QI 1 "xstormy16_below100_or_register" "0")
+ (match_operand:QI 2 "xstormy16_onebit_clr_operand" "i")))]
+ ""
+ "clr1 %0,%B2"
+ [(set_attr "length" "2")
+ (set_attr "psw_operand" "0")])
+
+(define_peephole2
+ [(set (match_operand:HI 0 "register_operand" "")
+ (and:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand 2 "immediate_operand" "")))
+ (set (match_operand:HI 3 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 4 "register_operand" "")));
+ ]
+ "REGNO (operands[0]) == REGNO (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[3])
+ && REGNO (operands[0]) == REGNO (operands[4])"
+ [(set (match_dup 0)
+ (and:HI (match_dup 1)
+ (match_dup 5)))
+ ]
+ "operands[5] = GEN_INT (INTVAL (operands[2]) & 0xff);")
+
+(define_peephole2
+ [(set (match_operand:QI 0 "register_operand" "")
+ (match_operand:QI 1 "xstormy16_below100_operand" ""))
+ (set (match_operand:HI 2 "register_operand" "")
+ (and:HI (match_operand:HI 3 "register_operand" "")
+ (match_operand:QI 4 "xstormy16_onebit_clr_operand" "")))
+ (set (match_operand:QI 5 "xstormy16_below100_operand" "")
+ (match_operand:QI 6 "register_operand" ""))
+ ]
+ "REGNO (operands[0]) == REGNO (operands[2])
+ && REGNO (operands[0]) == REGNO (operands[3])
+ && REGNO (operands[0]) == REGNO (operands[6])
+ && rtx_equal_p (operands[1], operands[5])"
+ [(set (match_dup 1)
+ (and:QI (match_dup 1)
+ (match_dup 4)))
+ ]
+ "")
+
+;; GCC uses different techniques to optimize MSB and LSB accesses, so
+;; we have to code those separately.
+
+(define_insn "*bclrx"
+ [(set (pc)
+ (if_then_else (eq:HI (and:QI (match_operand:QI 1 "xstormy16_below100_operand" "W")
+ (match_operand:HI 2 "immediate_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bn %1,%B2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bclrx2"
+ [(set (pc)
+ (if_then_else (zero_extract:HI
+ (xor:HI (subreg:HI
+ (match_operand:QI 1 "xstormy16_below100_operand" "W") 0)
+ (match_operand:HI 2 "xstormy16_onebit_set_operand" "J"))
+ (const_int 1)
+ (match_operand:HI 3 "immediate_operand" "i"))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bn %1,%B2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bclrx3"
+ [(set (pc)
+ (if_then_else (eq:HI (and:HI (zero_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W"))
+ (match_operand:HI 2 "immediate_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bn %1,%B2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bclr7"
+ [(set (pc)
+ (if_then_else (xor:HI (lshiftrt:HI (subreg:HI
+ (match_operand:QI 1 "xstormy16_below100_operand" "W") 0)
+ (const_int 7))
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bn %1,#7,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bclr15"
+ [(set (pc)
+ (if_then_else (ge:HI (sign_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bn %1,#7,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bsetx"
+ [(set (pc)
+ (if_then_else (ne:HI (and:QI (match_operand:QI 1 "xstormy16_below100_operand" "W")
+ (match_operand:HI 2 "immediate_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bp %1,%B2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bsetx2"
+ [(set (pc)
+ (if_then_else (zero_extract:HI (match_operand:QI 1 "xstormy16_below100_operand" "W")
+ (const_int 1)
+ (match_operand:HI 2 "immediate_operand" "i"))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bp %1,%b2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bsetx3"
+ [(set (pc)
+ (if_then_else (ne:HI (and:HI (zero_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W"))
+ (match_operand:HI 2 "immediate_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bp %1,%B2,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bset7"
+ [(set (pc)
+ (if_then_else (lshiftrt:HI (subreg:HI (match_operand:QI 1 "xstormy16_below100_operand" "W") 0)
+ (const_int 7))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bp %1,#7,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])
+
+(define_insn "*bset15"
+ [(set (pc)
+ (if_then_else (lt:HI (sign_extend:HI (match_operand:QI 1 "xstormy16_below100_operand" "W"))
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (clobber (reg:BI CARRY_REG))]
+ ""
+ "bp %1,#7,%l0"
+ [(set_attr "length" "4")
+ (set_attr "psw_operand" "nop")])