;; XSTORMY16 Machine description template ;; Copyright (C) 1997-2021 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 2N mask ;; K 2N 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 “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 “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”)])