diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/config/stormy16/stormy16.md | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'gcc/config/stormy16/stormy16.md')
-rw-r--r-- | gcc/config/stormy16/stormy16.md | 1251 |
1 files changed, 1251 insertions, 0 deletions
diff --git a/gcc/config/stormy16/stormy16.md b/gcc/config/stormy16/stormy16.md new file mode 100644 index 000000000..3eb74b72e --- /dev/null +++ b/gcc/config/stormy16/stormy16.md @@ -0,0 +1,1251 @@ +;; XSTORMY16 Machine description template +;; Copyright (C) 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2007, 2008, +;; 2010 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 (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 (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 (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 (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")]) |