;; Machine description of the ARC cpu for GNU C compiler ;; Copyright (C) 1994, 1997 Free Software Foundation, Inc.

;; This file is part of GNU CC.

;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version.

;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA.

;; See file “rtl.def” for documentation on define_insn, match_*, et. al.

;; ??? This is an old port, and is undoubtedly suffering from bit rot. ;; Insn type. Used to default other attribute values.

(define_attr “type” “move,load,store,cmove,unary,binary,compare,shift,mul,uncond_branch,branch,call,call_no_delay_slot,multi,misc” (const_string “binary”))

;; Length (in # of insns, long immediate constants counted too). ;; ??? There's a nasty interaction between the conditional execution fsm ;; and insn lengths: insns with shimm values cannot be conditionally executed. (define_attr “length” "" (cond [(eq_attr “type” “load”) (if_then_else (match_operand 1 “long_immediate_loadstore_operand” "") (const_int 2) (const_int 1))

 (eq_attr "type" "store")
 (if_then_else (match_operand 0 "long_immediate_loadstore_operand" "")
	       (const_int 2) (const_int 1))

 (eq_attr "type" "move,unary,compare")
 (if_then_else (match_operand 1 "long_immediate_operand" "")
	       (const_int 2) (const_int 1))

 (eq_attr "type" "binary,mul")
 (if_then_else (match_operand 2 "long_immediate_operand" "")
	       (const_int 2) (const_int 1))

 (eq_attr "type" "cmove")
 (if_then_else (match_operand 2 "register_operand" "")
	       (const_int 1) (const_int 2))

 (eq_attr "type" "multi") (const_int 2)
]

(const_int 1)))

;; The length here is the length of a single asm. Unfortunately it might be ;; 1 or 2 so we must allow for 2. That‘s ok though. How often will users ;; lament asm’s not being put in delay slots? (define_asm_attributes [(set_attr “length” “2”) (set_attr “type” “multi”)])

;; Condition codes: this one is used by final_prescan_insn to speed up ;; conditionalizing instructions. It saves having to scan the rtl to see if ;; it uses or alters the condition codes.

;; USE: This insn uses the condition codes (eg: a conditional branch). ;; CANUSE: This insn can use the condition codes (for conditional execution). ;; SET: All condition codes are set by this insn. ;; SET_ZN: the Z and N flags are set by this insn. ;; SET_ZNC: the Z, N, and C flags are set by this insn. ;; CLOB: The condition codes are set to unknown values by this insn. ;; NOCOND: This insn can‘t use and doesn’t affect the condition codes.

(define_attr “cond” “use,canuse,set,set_zn,set_znc,clob,nocond” (cond [(and (eq_attr “type” “unary,binary,move”) (eq_attr “length” “1”)) (const_string “canuse”)

 (eq_attr "type" "compare")
 (const_string "set")

 (eq_attr "type" "cmove,branch")
 (const_string "use")

 (eq_attr "type" "multi,misc")
 (const_string "clob")
 ]

 (const_string "nocond")))

;; Delay slots.

(define_attr “in_delay_slot” “false,true” (cond [(eq_attr “type” “uncond_branch,branch,call,call_no_delay_slot,multi”) (const_string “false”) ]

 (if_then_else (eq_attr "length" "1")
	       (const_string "true")
	       (const_string "false"))))

(define_delay (eq_attr “type” “call”) [(eq_attr “in_delay_slot” “true”) (eq_attr “in_delay_slot” “true”) (eq_attr “in_delay_slot” “true”)])

(define_delay (eq_attr “type” “branch,uncond_branch”) [(eq_attr “in_delay_slot” “true”) (eq_attr “in_delay_slot” “true”) (eq_attr “in_delay_slot” “true”)])
;; Function units of the ARC

;; (define_function_unit {name} {num-units} {n-users} {test} ;; {ready-delay} {issue-delay} [{conflict-list}])

;; 1) A conditional jump cannot immediately follow the insn setting the flags. ;; This isn‘t a complete solution as it doesn’t come with guarantees. That ;; is done in the branch patterns and in arc_print_operand. This exists to ;; avoid inserting a nop when we can. (define_function_unit “compare” 1 0 (eq_attr “type” “compare”) 2 2 [(eq_attr “type” “branch”)])

;; 2) References to loaded registers should wait a cycle.

;; Memory with load-delay of 1 (i.e., 2 cycle load). (define_function_unit “memory” 1 1 (eq_attr “type” “load”) 2 0)

;; Units that take one cycle do not need to be specified. ;; Move instructions.

(define_expand “movqi” [(set (match_operand:QI 0 “general_operand” "") (match_operand:QI 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (QImode, operands[1]); }")

(define_insn “*movqi_insn” [(set (match_operand:QI 0 “move_dest_operand” “=r,r,r,m”) (match_operand:QI 1 “move_src_operand” “rI,Ji,m,r”))] ;; ??? Needed? “register_operand (operands[0], QImode) || register_operand (operands[1], QImode)” “@ mov%? %0,%1 mov%? %0,%1 ldb%U1%V1 %0,%1 stb%U0%V0 %1,%0” [(set_attr “type” “move,move,load,store”)])

;; ??? This may never match since there's no cmpqi insn.

(define_insn “*movqi_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:QI 1 “move_src_operand” “rIJi”)) (const_int 0))) (set (match_operand:QI 0 “move_dest_operand” “=r”) (match_dup 1))] "" “mov%?.f %0,%1” [(set_attr “type” “move”) (set_attr “cond” “set_zn”)])

(define_expand “movhi” [(set (match_operand:HI 0 “general_operand” "") (match_operand:HI 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (HImode, operands[1]); }")

(define_insn “*movhi_insn” [(set (match_operand:HI 0 “move_dest_operand” “=r,r,r,m”) (match_operand:HI 1 “move_src_operand” “rI,Ji,m,r”))] “register_operand (operands[0], HImode) || register_operand (operands[1], HImode)” “@ mov%? %0,%1 mov%? %0,%1 ldw%U1%V1 %0,%1 stw%U0%V0 %1,%0” [(set_attr “type” “move,move,load,store”)])

;; ??? Will this ever match?

(define_insn “*movhi_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:HI 1 “move_src_operand” “rIJi”)) (const_int 0))) (set (match_operand:HI 0 “move_dest_operand” “=r”) (match_dup 1))] ;; ??? Needed? “register_operand (operands[0], HImode) || register_operand (operands[1], HImode)” “mov%?.f %0,%1” [(set_attr “type” “move”) (set_attr “cond” “set_zn”)])

(define_expand “movsi” [(set (match_operand:SI 0 “general_operand” "") (match_operand:SI 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (SImode, operands[1]); }")

(define_insn “*movsi_insn” [(set (match_operand:SI 0 “move_dest_operand” “=r,r,r,m”) (match_operand:SI 1 “move_src_operand” “rI,GJi,m,r”))] “register_operand (operands[0], SImode) || register_operand (operands[1], SImode)” “@ mov%? %0,%1 mov%? %0,%S1 ld%U1%V1 %0,%1 st%U0%V0 %1,%0” [(set_attr “type” “move,move,load,store”)])

(define_insn “*movsi_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (match_operand:SI 1 “move_src_operand” “rIJi”) (const_int 0))) (set (match_operand:SI 0 “move_dest_operand” “=r”) (match_dup 1))] “register_operand (operands[0], SImode) || register_operand (operands[1], SImode)” “mov%?.f %0,%S1” [(set_attr “type” “move”) (set_attr “cond” “set_zn”)])

(define_expand “movdi” [(set (match_operand:DI 0 “general_operand” "") (match_operand:DI 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DImode, operands[1]); }")

(define_insn “*movdi_insn” [(set (match_operand:DI 0 “move_dest_operand” “=r,r,r,m”) (match_operand:DI 1 “move_double_src_operand” “r,HK,m,r”))] “register_operand (operands[0], DImode) || register_operand (operands[1], DImode)” “* { switch (which_alternative) { case 0 : /* We normally copy the low-numbered register first. However, if the first register operand 0 is the same as the second register of operand 1, we must copy in the opposite order. / if (REGNO (operands[0]) == REGNO (operands[1]) + 1) return "mov %R0,%R1;mov %0,%1"; else return "mov %0,%1;mov %R0,%R1"; case 1 : return "mov %0,%L1;mov %R0,%H1"; case 2 : / If the low-address word is used in the address, we must load it last. Otherwise, load it first. Note that we cannot have auto-increment in that case since the address register is known to be dead. */ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, operands [1], 0)) return "ld%V1 %R0,%R1;ld%V1 %0,%1"; else return "ld%V1 %0,%1;ld%V1 %R0,%R1"; case 3 : return "st%V0 %1,%0;st%V0 %R1,%R0"; } }” [(set_attr “type” “move,move,load,store”) ;; ??? The ld/st values could be 4 if it's [reg,bignum]. (set_attr “length” “2,4,2,2”)])

;(define_expand “movdi” ; [(set (match_operand:DI 0 “general_operand” "") ; (match_operand:DI 1 “general_operand” "“))] ; "" ; " ;{ ; /* Flow doesn‘t understand that this is effectively a DFmode move. ; It doesn’t know that all of `operands[0]' is set. / ; emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0])); ; ; / Emit insns that movsi_insn can handle. */ ; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DImode), ; operand_subword (operands[1], 0, 0, DImode))); ; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DImode), ; operand_subword (operands[1], 1, 0, DImode))); ; DONE; ;}”) ;; Floating point move insns.

(define_expand “movsf” [(set (match_operand:SF 0 “general_operand” "") (match_operand:SF 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT if (GET_CODE (operands[1]) == CONST_DOUBLE) operands[1] = force_const_mem (SFmode, operands[1]); #endif

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }")

(define_insn “*movsf_insn” [(set (match_operand:SF 0 “move_dest_operand” “=r,r,r,m”) (match_operand:SF 1 “move_src_operand” “r,E,m,r”))] “register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)” “@ mov%? %0,%1 mov%? %0,%1 ; %A1 ld%U1%V1 %0,%1 st%U0%V0 %1,%0” [(set_attr “type” “move,move,load,store”)])

(define_expand “movdf” [(set (match_operand:DF 0 “general_operand” "") (match_operand:DF 1 “general_operand” ""))] "" " { /* Everything except mem = const or mem = mem can be done easily. */

#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT if (GET_CODE (operands[1]) == CONST_DOUBLE) operands[1] = force_const_mem (DFmode, operands[1]); #endif

if (GET_CODE (operands[0]) == MEM) operands[1] = force_reg (DFmode, operands[1]); }")

(define_insn “*movdf_insn” [(set (match_operand:DF 0 “move_dest_operand” “=r,r,r,m”) (match_operand:DF 1 “move_double_src_operand” “r,E,m,r”))] “register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)” “* { switch (which_alternative) { case 0 : /* We normally copy the low-numbered register first. However, if the first register operand 0 is the same as the second register of operand 1, we must copy in the opposite order. / if (REGNO (operands[0]) == REGNO (operands[1]) + 1) return "mov %R0,%R1;mov %0,%1"; else return "mov %0,%1;mov %R0,%R1"; case 1 : return "mov %0,%L1;mov %R0,%H1 ; %A1"; case 2 : / If the low-address word is used in the address, we must load it last. Otherwise, load it first. Note that we cannot have auto-increment in that case since the address register is known to be dead. */ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1, operands [1], 0)) return "ld%V1 %R0,%R1;ld%V1 %0,%1"; else return "ld%V1 %0,%1;ld%V1 %R0,%R1"; case 3 : return "st%V0 %1,%0;st%V0 %R1,%R0"; } }” [(set_attr “type” “move,move,load,store”) ;; ??? The ld/st values could be 4 if it's [reg,bignum]. (set_attr “length” “2,4,2,2”)])

;(define_expand “movdf” ; [(set (match_operand:DF 0 “general_operand” "") ; (match_operand:DF 1 “general_operand” "“))] ; "" ; " ;{ ; /* Flow doesn‘t understand that this is effectively a DFmode move. ; It doesn’t know that all of `operands[0]' is set. / ; emit_insn (gen_rtx (CLOBBER, VOIDmode, operands[0])); ; ; / Emit insns that movsi_insn can handle. */ ; emit_insn (gen_movsi (operand_subword (operands[0], 0, 0, DFmode), ; operand_subword (operands[1], 0, 0, DFmode))); ; emit_insn (gen_movsi (operand_subword (operands[0], 1, 0, DFmode), ; operand_subword (operands[1], 1, 0, DFmode))); ; DONE; ;}”) ;; Load/Store with update instructions. ;; ;; Some of these we can get by using pre-decrement or pre-increment, but the ;; hardware can also do cases where the increment is not the size of the ;; object. ;; ;; In all these cases, we use operands 0 and 1 for the register being ;; incremented because those are the operands that local-alloc will ;; tie and these are the pair most likely to be tieable (and the ones ;; that will benefit the most). ;; ;; We use match_operator here because we need to know whether the memory ;; object is volatile or not.

(define_insn “*loadqi_update” [(set (match_operand:QI 3 “register_operand” “=r,r”) (match_operator:QI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)])) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldb.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*load_zeroextendqisi_update” [(set (match_operand:SI 3 “register_operand” “=r,r”) (zero_extend:SI (match_operator:QI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)]))) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldb.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*load_signextendqisi_update” [(set (match_operand:SI 3 “register_operand” “=r,r”) (sign_extend:SI (match_operator:QI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)]))) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldb.x.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*storeqi_update” [(set (match_operator:QI 4 “store_update_operand” [(match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “short_immediate_operand” “I”)]) (match_operand:QI 3 “register_operand” “r”)) (set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “stb.a%V4 %3,[%0,%2]” [(set_attr “type” “store”) (set_attr “length” “1”)])

(define_insn “*loadhi_update” [(set (match_operand:HI 3 “register_operand” “=r,r”) (match_operator:HI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)])) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldw.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*load_zeroextendhisi_update” [(set (match_operand:SI 3 “register_operand” “=r,r”) (zero_extend:SI (match_operator:HI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)]))) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldw.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*load_signextendhisi_update” [(set (match_operand:SI 3 “register_operand” “=r,r”) (sign_extend:SI (match_operator:HI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)]))) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ldw.x.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*storehi_update” [(set (match_operator:HI 4 “store_update_operand” [(match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “short_immediate_operand” “I”)]) (match_operand:HI 3 “register_operand” “r”)) (set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “stw.a%V4 %3,[%0,%2]” [(set_attr “type” “store”) (set_attr “length” “1”)])

(define_insn “*loadsi_update” [(set (match_operand:SI 3 “register_operand” “=r,r”) (match_operator:SI 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)])) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ld.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*storesi_update” [(set (match_operator:SI 4 “store_update_operand” [(match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “short_immediate_operand” “I”)]) (match_operand:SI 3 “register_operand” “r”)) (set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “st.a%V4 %3,[%0,%2]” [(set_attr “type” “store”) (set_attr “length” “1”)])

(define_insn “*loadsf_update” [(set (match_operand:SF 3 “register_operand” “=r,r”) (match_operator:SF 4 “load_update_operand” [(match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “nonmemory_operand” “rI,J”)])) (set (match_operand:SI 0 “register_operand” “=r,r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “ld.a%V4 %3,[%0,%2]” [(set_attr “type” “load,load”) (set_attr “length” “1,2”)])

(define_insn “*storesf_update” [(set (match_operator:SF 4 “store_update_operand” [(match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “short_immediate_operand” “I”)]) (match_operand:SF 3 “register_operand” “r”)) (set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “st.a%V4 %3,[%0,%2]” [(set_attr “type” “store”) (set_attr “length” “1”)]) ;; Conditional move instructions.

(define_expand “movsicc” [(set (match_operand:SI 0 “register_operand” "") (if_then_else (match_operand 1 “comparison_operator” "") (match_operand:SI 2 “nonmemory_operand” "") (match_operand:SI 3 “register_operand” "")))] "" " { enum rtx_code code = GET_CODE (operands[1]); rtx ccreg = gen_rtx (REG, SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), 61);

operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); }")

;(define_expand “movdicc” ; [(set (match_operand:DI 0 “register_operand” "") ; (if_then_else (match_operand 1 “comparison_operator” "") ; (match_operand:DI 2 “nonmemory_operand” "") ; (match_operand:DI 3 “register_operand” "“)))] ; “0 /* ??? this would work better if we had cmpdi */” ; " ;{ ; enum rtx_code code = GET_CODE (operands[1]); ; rtx ccreg = gen_rtx (REG, ; SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), ; 61); ; ; operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); ;}”)

(define_expand “movsfcc” [(set (match_operand:SF 0 “register_operand” "") (if_then_else (match_operand 1 “comparison_operator” "") (match_operand:SF 2 “nonmemory_operand” "") (match_operand:SF 3 “register_operand” "")))] "" " { enum rtx_code code = GET_CODE (operands[1]); rtx ccreg = gen_rtx (REG, SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), 61);

operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); }")

;(define_expand “movdfcc” ; [(set (match_operand:DF 0 “register_operand” "") ; (if_then_else (match_operand 1 “comparison_operator” "") ; (match_operand:DF 2 “nonmemory_operand” "") ; (match_operand:DF 3 “register_operand” "“)))] ; “0 /* ??? can generate less efficient code if constants involved */” ; " ;{ ; enum rtx_code code = GET_CODE (operands[1]); ; rtx ccreg = gen_rtx (REG, ; SELECT_CC_MODE (code, arc_compare_op0, arc_compare_op1), ; 61); ; ; operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx); ;}”)

(define_insn “*movsicc_insn” [(set (match_operand:SI 0 “register_operand” “=r”) (if_then_else (match_operand 1 “comparison_operator” "") (match_operand:SI 2 “nonmemory_operand” “rJi”) (match_operand:SI 3 “register_operand” “0”)))] "" “mov.%d1 %0,%S2” [(set_attr “type” “cmove”)])

; ??? This doesn't properly handle constants. ;(define_insn “*movdicc_insn” ; [(set (match_operand:DI 0 “register_operand” “=r,r”) ; (if_then_else (match_operand 1 “comparison_operator” "") ; (match_operand:DI 2 “nonmemory_operand” “r,Ji”) ; (match_operand:DI 3 “register_operand” “0,0”)))] ; “0” ; “* ;{ ; switch (which_alternative) ; { ; case 0 : ; /* We normally copy the low-numbered register first. However, if ; the first register operand 0 is the same as the second register of ; operand 1, we must copy in the opposite order. */ ; if (REGNO (operands[0]) == REGNO (operands[2]) + 1) ; return "mov.%d1 %R0,%R2;mov.%d1 %0,%2"; ; else ; return "mov.%d1 %0,%2;mov.%d1 %R0,%R2"; ; case 1 : ; return "mov.%d1 %0,%2;mov.%d1 %R0,%R2"; ; } ;}” ; [(set_attr “type” “cmove,cmove”) ; (set_attr “length” “2,4”)])

(define_insn “*movsfcc_insn” [(set (match_operand:SF 0 “register_operand” “=r,r”) (if_then_else (match_operand 1 “comparison_operator” "") (match_operand:SF 2 “nonmemory_operand” “r,E”) (match_operand:SF 3 “register_operand” “0,0”)))] "" “@ mov.%d1 %0,%2 mov.%d1 %0,%2 ; %A2” [(set_attr “type” “cmove,cmove”)])

;(define_insn “*movdfcc_insn” ; [(set (match_operand:DF 0 “register_operand” “=r,r”) ; (if_then_else (match_operand 1 “comparison_operator” "") ; (match_operand:DF 2 “nonmemory_operand” “r,E”) ; (match_operand:DF 3 “register_operand” “0,0”)))] ; “0” ; “* ;{ ; switch (which_alternative) ; { ; case 0 : ; /* We normally copy the low-numbered register first. However, if ; the first register operand 0 is the same as the second register of ; operand 1, we must copy in the opposite order. */ ; if (REGNO (operands[0]) == REGNO (operands[2]) + 1) ; return "mov.%d1 %R0,%R2;mov.%d1 %0,%2"; ; else ; return "mov.%d1 %0,%2;mov.%d1 %R0,%R2"; ; case 1 : ; return "mov.%d1 %0,%L2;mov.%d1 %R0,%H2 ; %A2"; ; } ;}” ; [(set_attr “type” “cmove,cmove”) ; (set_attr “length” “2,4”)]) ;; Zero extension instructions. ;; ??? We don‘t support volatile memrefs here, but I’m not sure why.

(define_insn “zero_extendqihi2” [(set (match_operand:HI 0 “register_operand” “=r,r”) (zero_extend:HI (match_operand:QI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ extb%? %0,%1 ldb%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*zero_extendqihi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (zero_extend:SI (match_operand:QI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:HI 0 “register_operand” “=r”) (zero_extend:HI (match_dup 1)))] "" “extb%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)])

(define_insn “zero_extendqisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (zero_extend:SI (match_operand:QI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ extb%? %0,%1 ldb%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*zero_extendqisi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (zero_extend:SI (match_operand:QI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (zero_extend:SI (match_dup 1)))] "" “extb%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)])

(define_insn “zero_extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (zero_extend:SI (match_operand:HI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ extw%? %0,%1 ldw%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*zero_extendhisi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (zero_extend:SI (match_operand:HI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (zero_extend:SI (match_dup 1)))] "" “extw%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)]) ;; Sign extension instructions.

(define_insn “extendqihi2” [(set (match_operand:HI 0 “register_operand” “=r,r”) (sign_extend:HI (match_operand:QI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ sexb%? %0,%1 ldb.x%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*extendqihi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:QI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:HI 0 “register_operand” “=r”) (sign_extend:HI (match_dup 1)))] "" “sexb%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)])

(define_insn “extendqisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (sign_extend:SI (match_operand:QI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ sexb%? %0,%1 ldb.x%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*extendqisi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:QI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (sign_extend:SI (match_dup 1)))] "" “sexb%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)])

(define_insn “extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r,r”) (sign_extend:SI (match_operand:HI 1 “nonvol_nonimm_operand” “r,m”)))] "" “@ sexw%? %0,%1 ldw.x%U1 %0,%1” [(set_attr “type” “unary,load”)])

(define_insn “*extendhisi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (sign_extend:SI (match_operand:HI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (sign_extend:SI (match_dup 1)))] "" “sexw%?.f %0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)]) ;; Arithmetic instructions.

(define_insn “addsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)))] "" “add%? %0,%1,%2”)

(define_insn “*addsi3_set_cc_insn” [(set (reg:CC 61) (compare:CC (plus:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (plus:SI (match_dup 1) (match_dup 2)))] "" “add%?.f %0,%1,%2” [(set_attr “cond” “set”)])

(define_insn “adddi3” [(set (match_operand:DI 0 “register_operand” “=r”) (plus:DI (match_operand:DI 1 “nonmemory_operand” “%r”) (match_operand:DI 2 “nonmemory_operand” “ri”))) (clobber (reg:CC 61))] "" "* { rtx op2 = operands[2];

if (GET_CODE (op2) == CONST_INT) { int sign = INTVAL (op2); if (sign < 0) return "add.f %L0,%L1,%2;adc %H0,%H1,-1"; else return "add.f %L0,%L1,%2;adc %H0,%H1,0"; } else return "add.f %L0,%L1,%L2;adc %H0,%H1,%H2"; }" [(set_attr “length” “2”)])

(define_insn “subsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (minus:SI (match_operand:SI 1 “register_operand” “r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)))] "" “sub%? %0,%1,%2”)

(define_insn “*subsi3_set_cc_insn” [(set (reg:CC 61) (compare:CC (minus:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (minus:SI (match_dup 1) (match_dup 2)))] "" “sub%?.f %0,%1,%2” [(set_attr “cond” “set”)])

(define_insn “subdi3” [(set (match_operand:DI 0 “register_operand” “=r”) (minus:DI (match_operand:DI 1 “nonmemory_operand” “r”) (match_operand:DI 2 “nonmemory_operand” “ri”))) (clobber (reg:CC 61))] "" "* { rtx op2 = operands[2];

if (GET_CODE (op2) == CONST_INT) { int sign = INTVAL (op2); if (sign < 0) return "sub.f %L0,%L1,%2;sbc %H0,%H1,-1"; else return "sub.f %L0,%L1,%2;sbc %H0,%H1,0"; } else return "sub.f %L0,%L1,%L2;sbc %H0,%H1,%H2"; }" [(set_attr “length” “2”)]) ;; Boolean instructions. ;; ;; We don't define the DImode versions as expand_binop does a good enough job.

(define_insn “andsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (and:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)))] "" “and%? %0,%1,%2”)

(define_insn “*andsi3_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (and:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (and:SI (match_dup 1) (match_dup 2)))] "" “and%?.f %0,%1,%2” [(set_attr “cond” “set_zn”)])

(define_insn “*bicsi3_insn” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (and:SI (match_operand:SI 1 “nonmemory_operand” “r,r,I,J”) (not:SI (match_operand:SI 2 “nonmemory_operand” “rI,J,r,r”))))] "" “bic%? %0,%1,%2” [(set_attr “length” “1,2,1,2”)])

(define_insn “*bicsi3_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (and:SI (match_operand:SI 1 “register_operand” “%r”) (not:SI (match_operand:SI 2 “nonmemory_operand” “rIJ”))) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (and:SI (match_dup 1) (not:SI (match_dup 2))))] "" “bic%?.f %0,%1,%2” [(set_attr “cond” “set_zn”)])

(define_insn “iorsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (ior:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)))] "" “or%? %0,%1,%2”)

(define_insn “*iorsi3_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (ior:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (ior:SI (match_dup 1) (match_dup 2)))] "" “or%?.f %0,%1,%2” [(set_attr “cond” “set_zn”)])

(define_insn “xorsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (xor:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)))] "" “xor%? %0,%1,%2”)

(define_insn “*xorsi3_set_cc_insn” [(set (reg:CCZN 61) (compare:CCZN (xor:SI (match_operand:SI 1 “register_operand” “%r”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (xor:SI (match_dup 1) (match_dup 2)))] "" “xor%?.f %0,%1,%2” [(set_attr “cond” “set_zn”)])

(define_insn “negsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (neg:SI (match_operand:SI 1 “register_operand” “r”)))] "" “sub%? %0,0,%1” [(set_attr “type” “unary”)])

(define_insn “*negsi2_set_cc_insn” [(set (reg:CC 61) (compare:CC (neg:SI (match_operand:SI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (neg:SI (match_dup 1)))] "" “sub%?.f %0,0,%1” [(set_attr “type” “unary”) (set_attr “cond” “set”)])

(define_insn “negdi2” [(set (match_operand:DI 0 “register_operand” “=r”) (neg:DI (match_operand:DI 1 “register_operand” “r”))) (clobber (reg:SI 61))] "" “sub.f %L0,0,%L1;sbc %H0,0,%H1” [(set_attr “type” “unary”) (set_attr “length” “2”)])

(define_insn “one_cmplsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (not:SI (match_operand:SI 1 “register_operand” “r”)))] "" “xor%? %0,%1,-1” [(set_attr “type” “unary”)])

(define_insn “*one_cmplsi2_set_cc_insn” [(set (reg:CCZN 61) (compare:CC (not:SI (match_operand:SI 1 “register_operand” “r”)) (const_int 0))) (set (match_operand:SI 0 “register_operand” “=r”) (not:SI (match_dup 1)))] "" “xor%?.f %0,%1,-1” [(set_attr “type” “unary”) (set_attr “cond” “set_zn”)]) ;; Shift instructions.

(define_expand “ashlsi3” [(set (match_operand:SI 0 “register_operand” "") (ashift:SI (match_operand:SI 1 “register_operand” "") (match_operand:SI 2 “nonmemory_operand” "“)))] "" " { if (! TARGET_SHIFTER) { emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (ASHIFT, SImode, operands[1], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, SImode, 0))))); DONE; } }”)

(define_expand “ashrsi3” [(set (match_operand:SI 0 “register_operand” "") (ashiftrt:SI (match_operand:SI 1 “register_operand” "") (match_operand:SI 2 “nonmemory_operand” "“)))] "" " { if (! TARGET_SHIFTER) { emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (ASHIFTRT, SImode, operands[1], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, SImode, 0))))); DONE; } }”)

(define_expand “lshrsi3” [(set (match_operand:SI 0 “register_operand” "") (lshiftrt:SI (match_operand:SI 1 “register_operand” "") (match_operand:SI 2 “nonmemory_operand” "“)))] "" " { if (! TARGET_SHIFTER) { emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (LSHIFTRT, SImode, operands[1], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, SImode, 0))))); DONE; } }”)

(define_insn “*ashlsi3_insn” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (ashift:SI (match_operand:SI 1 “nonmemory_operand” “r,r,I,J”) (match_operand:SI 2 “nonmemory_operand” “rI,J,r,r”)))] “TARGET_SHIFTER” “asl%? %0,%1,%2” [(set_attr “type” “shift”) (set_attr “length” “1,2,1,2”)])

(define_insn “*ashrsi3_insn” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (ashiftrt:SI (match_operand:SI 1 “nonmemory_operand” “r,r,I,J”) (match_operand:SI 2 “nonmemory_operand” “rI,J,r,r”)))] “TARGET_SHIFTER” “asr%? %0,%1,%2” [(set_attr “type” “shift”) (set_attr “length” “1,2,1,2”)])

(define_insn “*lshrsi3_insn” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (lshiftrt:SI (match_operand:SI 1 “nonmemory_operand” “r,r,I,J”) (match_operand:SI 2 “nonmemory_operand” “rI,J,r,r”)))] “TARGET_SHIFTER” “lsr%? %0,%1,%2” [(set_attr “type” “shift”) (set_attr “length” “1,2,1,2”)])

(define_insn “*shift_si3” [(set (match_operand:SI 0 “register_operand” “=r”) (match_operator:SI 3 “shift_operator” [(match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “nonmemory_operand” “rIJ”)])) (clobber (match_scratch:SI 4 “=&r”))] “! TARGET_SHIFTER” “* return output_shift (operands);” [(set_attr “type” “shift”) (set_attr “length” “8”)]) ;; Compare instructions. ;; This controls RTL generation and register allocation.

;; We generate RTL for comparisons and branches by having the cmpxx ;; patterns store away the operands. Then, the scc and bcc patterns ;; emit RTL for both the compare and the branch.

(define_expand “cmpsi” [(set (reg:CC 61) (compare:CC (match_operand:SI 0 “register_operand” "") (match_operand:SI 1 “nonmemory_operand” "“)))] "" " { arc_compare_op0 = operands[0]; arc_compare_op1 = operands[1]; DONE; }”)

;; ??? We may be able to relax this a bit by adding a new constant ‘K’ for 0. ;; This assumes sub.f 0,symbol,0 is a valid insn. ;; Note that “sub.f 0,r0,1” is an 8 byte insn. To avoid unnecessarily ;; creating 8 byte insns we duplicate %1 in the destination reg of the insn ;; if it's a small constant.

(define_insn “*cmpsi_cc_insn” [(set (reg:CC 61) (compare:CC (match_operand:SI 0 “register_operand” “r,r,r”) (match_operand:SI 1 “nonmemory_operand” “r,I,J”)))] "" “@ sub.f 0,%0,%1 sub.f %1,%0,%1 sub.f 0,%0,%1” [(set_attr “type” “compare,compare,compare”)])

(define_insn “*cmpsi_cczn_insn” [(set (reg:CCZN 61) (compare:CCZN (match_operand:SI 0 “register_operand” “r,r,r”) (match_operand:SI 1 “nonmemory_operand” “r,I,J”)))] "" “@ sub.f 0,%0,%1 sub.f %1,%0,%1 sub.f 0,%0,%1” [(set_attr “type” “compare,compare,compare”)])

(define_insn “*cmpsi_ccznc_insn” [(set (reg:CCZNC 61) (compare:CCZNC (match_operand:SI 0 “register_operand” “r,r,r”) (match_operand:SI 1 “nonmemory_operand” “r,I,J”)))] "" “@ sub.f 0,%0,%1 sub.f %1,%0,%1 sub.f 0,%0,%1” [(set_attr “type” “compare,compare,compare”)])

;; Next come the scc insns.

(define_expand “seq” [(set (match_operand:SI 0 “register_operand” “=r”) (eq:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (EQ, arc_compare_op0, arc_compare_op1); }")

(define_expand “sne” [(set (match_operand:SI 0 “register_operand” “=r”) (ne:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (NE, arc_compare_op0, arc_compare_op1); }")

(define_expand “sgt” [(set (match_operand:SI 0 “register_operand” “=r”) (gt:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (GT, arc_compare_op0, arc_compare_op1); }")

(define_expand “sle” [(set (match_operand:SI 0 “register_operand” “=r”) (le:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (LE, arc_compare_op0, arc_compare_op1); }")

(define_expand “sge” [(set (match_operand:SI 0 “register_operand” “=r”) (ge:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (GE, arc_compare_op0, arc_compare_op1); }")

(define_expand “slt” [(set (match_operand:SI 0 “register_operand” “=r”) (lt:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (LT, arc_compare_op0, arc_compare_op1); }")

(define_expand “sgtu” [(set (match_operand:SI 0 “register_operand” “=r”) (gtu:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (GTU, arc_compare_op0, arc_compare_op1); }")

(define_expand “sleu” [(set (match_operand:SI 0 “register_operand” “=r”) (leu:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (LEU, arc_compare_op0, arc_compare_op1); }")

(define_expand “sgeu” [(set (match_operand:SI 0 “register_operand” “=r”) (geu:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (GEU, arc_compare_op0, arc_compare_op1); }")

(define_expand “sltu” [(set (match_operand:SI 0 “register_operand” “=r”) (ltu:SI (match_dup 1) (const_int 0)))] "" " { operands[1] = gen_compare_reg (LTU, arc_compare_op0, arc_compare_op1); }")

(define_insn “*scc_insn” [(set (match_operand:SI 0 “register_operand” “=r”) (match_operator:SI 1 “comparison_operator” [(reg 61) (const_int 0)]))] "" “mov %0,1;sub.%D1 %0,%0,%0” [(set_attr “type” “unary”) (set_attr “length” “2”)])

;; ??? Look up negscc insn. See pa.md for example. (define_insn “*neg_scc_insn” [(set (match_operand:SI 0 “register_operand” “=r”) (neg:SI (match_operator:SI 1 “comparison_operator” [(reg 61) (const_int 0)])))] "" “mov %0,-1;sub.%D1 %0,%0,%0” [(set_attr “type” “unary”) (set_attr “length” “2”)])

(define_insn “*not_scc_insn” [(set (match_operand:SI 0 “register_operand” “=r”) (not:SI (match_operator:SI 1 “comparison_operator” [(reg 61) (const_int 0)])))] "" “mov %0,1;sub.%d1 %0,%0,%0” [(set_attr “type” “unary”) (set_attr “length” “2”)]) ;; These control RTL generation for conditional jump insns

(define_expand “beq” [(set (pc) (if_then_else (eq (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (EQ, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bne” [(set (pc) (if_then_else (ne (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (NE, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bgt” [(set (pc) (if_then_else (gt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (GT, arc_compare_op0, arc_compare_op1); }”)

(define_expand “ble” [(set (pc) (if_then_else (le (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (LE, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bge” [(set (pc) (if_then_else (ge (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (GE, arc_compare_op0, arc_compare_op1); }”)

(define_expand “blt” [(set (pc) (if_then_else (lt (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (LT, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bgtu” [(set (pc) (if_then_else (gtu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (GTU, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bleu” [(set (pc) (if_then_else (leu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (LEU, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bgeu” [(set (pc) (if_then_else (geu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (GEU, arc_compare_op0, arc_compare_op1); }”)

(define_expand “bltu” [(set (pc) (if_then_else (ltu (match_dup 1) (const_int 0)) (label_ref (match_operand 0 "" "“)) (pc)))] "" " { operands[1] = gen_compare_reg (LTU, arc_compare_op0, arc_compare_op1); }”)

;; Now match both normal and inverted jump.

(define_insn “*branch_insn” [(set (pc) (if_then_else (match_operator 1 “proper_comparison_operator” [(reg 61) (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" “* { if (arc_ccfsm_branch_deleted_p ()) { arc_ccfsm_record_branch_deleted (); return "; branch deleted, next insns conditionalized"; } else return "%~b%d1%# %l0"; }” [(set_attr “type” “branch”)])

(define_insn “*rev_branch_insn” [(set (pc) (if_then_else (match_operator 1 “proper_comparison_operator” [(reg 61) (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] “REVERSIBLE_CC_MODE (GET_MODE (XEXP (operands[1], 0)))” “* { if (arc_ccfsm_branch_deleted_p ()) { arc_ccfsm_record_branch_deleted (); return "; branch deleted, next insns conditionalized"; } else return "%~b%D1%# %l0"; }” [(set_attr “type” “branch”)]) ;; Unconditional and other jump instructions.

(define_insn “jump” [(set (pc) (label_ref (match_operand 0 "" "")))] "" “b%* %l0” [(set_attr “type” “uncond_branch”)])

(define_insn “indirect_jump” [(set (pc) (match_operand:SI 0 “address_operand” “p”))] "" “j%* %a0” [(set_attr “type” “uncond_branch”)])

;; Implement a switch statement. ;; This wouldn‘t be necessary in the non-pic case if we could distinguish ;; label refs of the jump table from other label refs. The problem is that ;; label refs are output as “%st(.LL42)” but we don’t want the %st - we want ;; the real address since it's the address of the table.

(define_expand “casesi” [(set (match_dup 5) (minus:SI (match_operand:SI 0 “register_operand” "") (match_operand:SI 1 “nonmemory_operand” ""))) (set (reg:CC 61) (compare:CC (match_dup 5) (match_operand:SI 2 “nonmemory_operand” ""))) (set (pc) (if_then_else (gtu (reg:CC 61) (const_int 0)) (label_ref (match_operand 4 "" "")) (pc))) (parallel [(set (pc) (mem:SI (plus:SI (mult:SI (match_dup 5) (const_int 4)) (label_ref (match_operand 3 "" ""))))) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 "“))])] "" " { operands[5] = gen_reg_rtx (SImode); }”)

(define_insn “*casesi_insn” [(set (pc) (mem:SI (plus:SI (mult:SI (match_operand:SI 0 “register_operand” “r”) (const_int 4)) (label_ref (match_operand 1 "" ""))))) (clobber (match_scratch:SI 2 “=r”)) (clobber (match_scratch:SI 3 “=r”))] "" “* { output_asm_insn ("mov %2,%1", operands); if (TARGET_SHIFTER) output_asm_insn ("asl %3,%0,2", operands); else output_asm_insn ("asl %3,%0;asl %3,%3", operands); output_asm_insn ("ld %2,[%2,%3]", operands); output_asm_insn ("j.nd %a2", operands); return ""; }” [(set_attr “type” “uncond_branch”) (set_attr “length” “6”)])

(define_insn “tablejump” [(set (pc) (match_operand:SI 0 “address_operand” “p”)) (use (label_ref (match_operand 1 "" "")))] “0 /* disabled -> using casesi now */” “j%* %a0” [(set_attr “type” “uncond_branch”)])

(define_expand “call” ;; operands[1] is stack_size_rtx ;; operands[2] is next_arg_register [(parallel [(call (match_operand:SI 0 “call_operand” "") (match_operand 1 "" "")) (clobber (reg:SI 31))])] "" "")

(define_insn “*call_via_reg” [(call (mem:SI (match_operand:SI 0 “register_operand” “r”)) (match_operand 1 "" "")) (clobber (reg:SI 31))] "" “lr blink,[status];j.d %0;add blink,blink,2” [(set_attr “type” “call_no_delay_slot”) (set_attr “length” “3”)])

(define_insn “*call_via_label” [(call (mem:SI (match_operand:SI 0 “call_address_operand” "")) (match_operand 1 "" "")) (clobber (reg:SI 31))] "" ; The %~ is necessary in case this insn gets conditionalized and the previous ; insn is the cc setter. “%~bl%!%* %0” [(set_attr “type” “call”) (set_attr “cond” “canuse”)])

(define_expand “call_value” ;; operand 2 is stack_size_rtx ;; operand 3 is next_arg_register [(parallel [(set (match_operand 0 “register_operand” “=r”) (call (match_operand:SI 1 “call_operand” "") (match_operand 2 "" ""))) (clobber (reg:SI 31))])] "" "")

(define_insn “*call_value_via_reg” [(set (match_operand 0 “register_operand” “=r”) (call (mem:SI (match_operand:SI 1 “register_operand” “r”)) (match_operand 2 "" ""))) (clobber (reg:SI 31))] "" “lr blink,[status];j.d %1;add blink,blink,2” [(set_attr “type” “call_no_delay_slot”) (set_attr “length” “3”)])

(define_insn “*call_value_via_label” [(set (match_operand 0 “register_operand” “=r”) (call (mem:SI (match_operand:SI 1 “call_address_operand” "")) (match_operand 2 "" ""))) (clobber (reg:SI 31))] "" ; The %~ is necessary in case this insn gets conditionalized and the previous ; insn is the cc setter. “%~bl%!%* %1” [(set_attr “type” “call”) (set_attr “cond” “canuse”)]) (define_insn “nop” [(const_int 0)] "" “nop” [(set_attr “type” “misc”)])

;; Special pattern to flush the icache. ;; ??? Not sure what to do here. Some ARC's are known to support this.

(define_insn “flush_icache” [(unspec_volatile [(match_operand 0 “memory_operand” “m”)] 0)] "" “* return "";” [(set_attr “type” “misc”)]) ;; Split up troublesome insns for better scheduling. ;; Peepholes go at the end.