;; GCC machine description for Hitachi H8/300 ;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, ;; 2001, 2002, 2003 Free Software Foundation, Inc. ;; Contributed by Steve Chamberlain (sac@cygnus.com), ;; Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com). ;; 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. ;; Some of the extend instructions accept a general_operand_src, which ;; allows all the normal memory addressing modes. The length computations ;; don't take this into account. The lengths in the MD file should be ;; "worst case" and then be adjusted to their correct values by ;; h8300_adjust_insn_length. ;; On the H8/300H and H8S, adds/subs operate on the 32bit "er" ;; registers. Right now GCC doesn't expose the "e" half to the ;; compiler, so using add/subs for addhi and subhi is safe. Long ;; term, we want to expose the "e" half to the compiler (gives us 8 ;; more 16bit registers). At that point addhi and subhi can't use ;; adds/subs. ;; There's currently no way to have an insv/extzv expander for the H8/300H ;; because word_mode is different for the H8/300 and H8/300H. ;; Shifts/rotates by small constants should be handled by special ;; patterns so we get the length and cc status correct. ;; Bitfield operations no longer accept memory operands. We need ;; to add variants which operate on memory back to the MD. ;; ??? Implement remaining bit ops available on the h8300 ;; ---------------------------------------------------------------------- ;; CONSTANTS ;; ---------------------------------------------------------------------- (define_constants [(SC_REG 3) (FP_REG 6) (SP_REG 7) (MAC_REG 8) (AP_REG 9) (RAP_REG 10)]) ;; ---------------------------------------------------------------------- ;; ATTRIBUTES ;; ---------------------------------------------------------------------- (define_attr "cpu" "h8300,h8300h" (const (symbol_ref "cpu_type"))) (define_attr "type" "branch,arith" (const_string "arith")) ;; The size of instructions in bytes. (define_attr "length" "" (cond [(eq_attr "type" "branch") (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -126)) (le (minus (match_dup 0) (pc)) (const_int 126))) (const_int 2) (if_then_else (and (eq_attr "cpu" "h8300h") (and (ge (minus (pc) (match_dup 0)) (const_int -32000)) (le (minus (pc) (match_dup 0)) (const_int 32000)))) (const_int 4) (const_int 6)))] (const_int 200))) ;; The necessity of instruction length adjustment. (define_attr "adjust_length" "yes,no" (cond [(eq_attr "type" "branch") (const_string "no")] (const_string "yes"))) ;; Condition code settings. ;; ;; none - insn does not affect cc ;; none_0hit - insn does not affect cc but it does modify operand 0 ;; This attribute is used to keep track of when operand 0 changes. ;; See the description of NOTICE_UPDATE_CC for more info. ;; set_znv - insn sets z,n,v to usable values (like a tst insn); c is unknown. ;; set_zn - insn sets z,n to usable values; v,c are unknown. ;; compare - compare instruction ;; clobber - value of cc is unknown (define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber" (const_string "clobber")) ;; ---------------------------------------------------------------------- ;; MOVE INSTRUCTIONS ;; ---------------------------------------------------------------------- ;; movqi (define_insn "pushqi1_h8300" [(parallel [(set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2))) (set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -1))) (match_operand:QI 0 "register_operand" "r"))])] "TARGET_H8300 && REGNO (operands[0]) != SP_REG" "mov.w\\t%T0,@-r7" [(set_attr "length" "2") (set_attr "cc" "clobber")]) (define_insn "pushqi1_h8300hs" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:QI (plus:SI (reg:SI SP_REG) (const_int -3))) (match_operand:QI 0 "register_operand" "r"))])] "(TARGET_H8300H || TARGET_H8300S) && REGNO (operands[0]) != SP_REG" "mov.l\\t%S0,@-er7" [(set_attr "length" "4") (set_attr "cc" "clobber")]) (define_expand "pushqi1" [(use (match_operand:QI 0 "register_operand" ""))] "" " { if (TARGET_H8300) emit_insn (gen_pushqi1_h8300 (operands[0])); else emit_insn (gen_pushqi1_h8300hs (operands[0])); DONE; }") (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,<,r,r,m") (match_operand:QI 1 "general_operand_src" " I,r>,r,n,m,r"))] "TARGET_H8300 && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" "@ sub.b %X0,%X0 mov.b %R1,%X0 mov.b %X1,%R0 mov.b %R1,%X0 mov.b %R1,%X0 mov.b %X1,%R0" [(set_attr "length" "2,2,2,2,4,4") (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,<,r,r,m") (match_operand:QI 1 "general_operand_src" " I,r>,r,n,m,r"))] "(TARGET_H8300H || TARGET_H8300S) && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" "@ sub.b %X0,%X0 mov.b %R1,%X0 mov.b %X1,%R0 mov.b %R1,%X0 mov.b %R1,%X0 mov.b %X1,%R0" [(set_attr "length" "2,2,2,2,8,8") (set_attr "cc" "set_zn,set_znv,set_znv,clobber,set_znv,set_znv")]) (define_expand "movqi" [(set (match_operand:QI 0 "general_operand_dst" "") (match_operand:QI 1 "general_operand_src" ""))] "" " { /* One of the ops has to be in a register. */ if (!register_operand (operand0, QImode) && !register_operand (operand1, QImode)) { operands[1] = copy_to_mode_reg (QImode, operand1); } }") (define_insn "movstrictqi" [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "+r,r,r,r")) (match_operand:QI 1 "general_operand_src" "I,r,n,m"))] "" "@ sub.b %X0,%X0 mov.b %X1,%X0 mov.b %R1,%X0 mov.b %R1,%X0" [(set_attr_alternative "length" [(const_int 2) (const_int 2) (const_int 2) (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))]) (set_attr "cc" "set_zn,set_znv,set_znv,set_znv")]) ;; movhi (define_expand "pushhi1_h8300" [(set (mem:HI (pre_dec:HI (reg:HI SP_REG))) (match_operand:HI 0 "register_operand" ""))] "TARGET_H8300 && REGNO (operands[0]) != SP_REG" "") (define_insn "pushhi1_h8300hs" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:HI (plus:SI (reg:SI SP_REG) (const_int -2))) (match_operand:HI 0 "register_operand" "r"))])] "(TARGET_H8300H || TARGET_H8300S) && REGNO (operands[0]) != SP_REG" "mov.l\\t%S0,@-er7" [(set_attr "length" "4") (set_attr "cc" "clobber")]) (define_expand "pushhi1" [(use (match_operand:HI 0 "register_operand" ""))] "" " { if (TARGET_H8300) emit_insn (gen_pushhi1_h8300 (operands[0])); else emit_insn (gen_pushhi1_h8300hs (operands[0])); DONE; }") (define_insn "" [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m") (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r"))] "TARGET_H8300 && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode)) && !(GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC && GET_CODE (XEXP (XEXP (operands[0], 0), 0)) == REG && GET_CODE (operands[1]) == REG && REGNO (XEXP (XEXP (operands[0], 0), 0)) == REGNO (operands[1]))" "@ sub.w %T0,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr "length" "2,2,2,4,4,4") (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) (define_insn "" [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m") (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r"))] "(TARGET_H8300H || TARGET_H8300S) && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" "@ sub.w %T0,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr "length" "2,2,2,4,8,8") (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) (define_expand "movhi" [(set (match_operand:HI 0 "general_operand_dst" "") (match_operand:HI 1 "general_operand_src" ""))] "" " { /* One of the ops has to be in a register. */ if (!register_operand (operand1, HImode) && !register_operand (operand0, HImode)) { operands[1] = copy_to_mode_reg (HImode, operand1); } }") (define_insn "movstricthi" [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "+r,r,r,r")) (match_operand:HI 1 "general_operand_src" "I,r,i,m"))] "" "@ sub.w %T0,%T0 mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr_alternative "length" [(const_int 2) (const_int 2) (const_int 4) (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))]) (set_attr "cc" "set_zn,set_znv,set_znv,set_znv")]) ;; movsi (define_expand "movsi" [(set (match_operand:SI 0 "general_operand_dst" "") (match_operand:SI 1 "general_operand_src" ""))] "" " { if (TARGET_H8300) { if (do_movsi (operands)) DONE; } else { /* One of the ops has to be in a register. */ if (!register_operand (operand1, SImode) && !register_operand (operand0, SImode)) { operands[1] = copy_to_mode_reg (SImode, operand1); } } }") (define_expand "movsf" [(set (match_operand:SF 0 "general_operand_dst" "") (match_operand:SF 1 "general_operand_src" ""))] "" " { if (TARGET_H8300) { if (do_movsi (operands)) DONE; } else { /* One of the ops has to be in a register. */ if (!register_operand (operand1, SFmode) && !register_operand (operand0, SFmode)) { operands[1] = copy_to_mode_reg (SFmode, operand1); } } }") (define_insn "movsi_h8300" [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r") (match_operand:SI 1 "general_operand_src" "I,r,io,r,r,>"))] "TARGET_H8300 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" "* { int rn = -1; switch (which_alternative) { case 0: return \"sub.w %e0,%e0\;sub.w %f0,%f0\"; case 1: if (REGNO (operands[0]) < REGNO (operands[1])) return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; else return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; case 2: /* Make sure we don't trample the register we index with. */ if (GET_CODE (operands[1]) == MEM) { rtx inside = XEXP (operands[1], 0); if (REG_P (inside)) { rn = REGNO (inside); } else if (GET_CODE (inside) == PLUS) { rtx lhs = XEXP (inside, 0); rtx rhs = XEXP (inside, 1); if (REG_P (lhs)) rn = REGNO (lhs); if (REG_P (rhs)) rn = REGNO (rhs); } } if (rn == REGNO (operands[0])) { /* Move the second word first. */ return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; } else { /* See if either half is zero. If so, use sub.w to clear that half. */ if (GET_CODE (operands[1]) == CONST_INT) { if ((INTVAL (operands[1]) & 0xffff) == 0) return \"mov.w %e1,%e0\;sub.w %f0,%f0\"; if (((INTVAL (operands[1]) >> 16) & 0xffff) == 0) return \"sub.w %e0,%e0\;mov.w %f1,%f0\"; } return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; } case 3: return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; case 4: return \"mov.w %f1,%T0\;mov.w %e1,%T0\"; case 5: return \"mov.w %T1,%e0\;mov.w %T1,%f0\"; default: abort (); } }" [(set_attr "length" "4,4,8,8,4,4") (set_attr "cc" "clobber")]) (define_insn "movsf_h8300" [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r") (match_operand:SF 1 "general_operand_src" "I,r,io,r,r,>"))] "TARGET_H8300 && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "* { /* Copy of the movsi stuff. */ int rn = -1; switch (which_alternative) { case 0: return \"sub.w %e0,%e0\;sub.w %f0,%f0\"; case 1: if (REGNO (operands[0]) < REGNO (operands[1])) return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; else return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; case 2: /* Make sure we don't trample the register we index with. */ if (GET_CODE (operands[1]) == MEM) { rtx inside = XEXP (operands[1], 0); if (REG_P (inside)) { rn = REGNO (inside); } else if (GET_CODE (inside) == PLUS) { rtx lhs = XEXP (inside, 0); rtx rhs = XEXP (inside, 1); if (REG_P (lhs)) rn = REGNO (lhs); if (REG_P (rhs)) rn = REGNO (rhs); } } if (rn == REGNO (operands[0])) /* Move the second word first. */ return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; else /* Move the first word first. */ return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; case 3: return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; case 4: return \"mov.w %f1,%T0\;mov.w %e1,%T0\"; case 5: return \"mov.w %T1,%e0\;mov.w %T1,%f0\"; default: abort (); } }" [(set_attr "length" "4,4,8,8,4,4") (set_attr "cc" "clobber")]) (define_insn "movsi_h8300hs" [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,<,r,r,m,*a,*a,r") (match_operand:SI 1 "general_operand_src" "I,r,i,r,>,m,r,I,r,*a"))] "(TARGET_H8300S || TARGET_H8300H) && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode)) && !(GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC && GET_CODE (XEXP (XEXP (operands[0], 0), 0)) == REG && GET_CODE (operands[1]) == REG && REGNO (XEXP (XEXP (operands[0], 0), 0)) == REGNO (operands[1]))" "* { switch (which_alternative) { case 0: return \"sub.l %S0,%S0\"; case 7: return \"clrmac\"; case 8: return \"clrmac\;ldmac %1,macl\"; case 9: return \"stmac macl,%0\"; default: if (GET_CODE (operands[1]) == CONST_INT) { int val = INTVAL (operands[1]); /* Look for constants which can be made by adding an 8-bit number to zero in one of the two low bytes. */ if (val == (val & 0xff)) { operands[1] = GEN_INT ((char) val & 0xff); return \"sub.l\\t%S0,%S0\;add.b\\t%1,%w0\"; } if (val == (val & 0xff00)) { operands[1] = GEN_INT ((char) (val >> 8) & 0xff); return \"sub.l\\t%S0,%S0\;add.b\\t%1,%x0\"; } /* Look for constants that can be obtained by subs, inc, and dec to 0. */ switch (val & 0xffffffff) { case 0xffffffff: return \"sub.l\\t%S0,%S0\;subs\\t#1,%S0\"; case 0xfffffffe: return \"sub.l\\t%S0,%S0\;subs\\t#2,%S0\"; case 0xfffffffc: return \"sub.l\\t%S0,%S0\;subs\\t#4,%S0\"; case 0x0000ffff: return \"sub.l\\t%S0,%S0\;dec.w\\t#1,%f0\"; case 0x0000fffe: return \"sub.l\\t%S0,%S0\;dec.w\\t#2,%f0\"; case 0xffff0000: return \"sub.l\\t%S0,%S0\;dec.w\\t#1,%e0\"; case 0xfffe0000: return \"sub.l\\t%S0,%S0\;dec.w\\t#2,%e0\"; case 0x00010000: return \"sub.l\\t%S0,%S0\;inc.w\\t#1,%e0\"; case 0x00020000: return \"sub.l\\t%S0,%S0\;inc.w\\t#2,%e0\"; } } } return \"mov.l %S1,%S0\"; }" [(set_attr "length" "2,2,6,4,4,10,10,2,6,4") (set_attr "cc" "set_zn,set_znv,clobber,set_znv,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")]) (define_insn "movsf_h8300h" [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r") (match_operand:SF 1 "general_operand_src" "I,r,im,r,r,>"))] "(TARGET_H8300H || TARGET_H8300S) && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "@ sub.l %S0,%S0 mov.l %S1,%S0 mov.l %S1,%S0 mov.l %S1,%S0 mov.l %S1,%S0 mov.l %S1,%S0" [(set_attr "length" "2,2,10,10,4,4") (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) ;; ---------------------------------------------------------------------- ;; TEST INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "" [(set (cc0) (zero_extract:HI (match_operand:QI 0 "bit_memory_operand" "r,U") (const_int 1) (match_operand 1 "const_int_operand" "n,n")))] "TARGET_H8300" "btst %Z1,%Y0" [(set_attr "length" "2,4") (set_attr "cc" "set_zn,set_zn")]) (define_insn "" [(set (cc0) (zero_extract:HI (match_operand:HI 0 "register_operand" "r") (const_int 1) (match_operand 1 "const_int_operand" "n")))] "TARGET_H8300" "btst %Z1,%Y0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "*tst_extzv_bitqi_1_n" [(set (cc0) (zero_extract:SI (match_operand:QI 0 "bit_operand" "r,U") (const_int 1) (match_operand 1 "const_int_operand" "n,n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) != 7" "btst %Z1,%Y0" [(set_attr "length" "2,8") (set_attr "cc" "set_zn,set_zn")]) (define_insn_and_split "*tst_extzv_memqi_1_n" [(set (cc0) (zero_extract:SI (match_operand:QI 0 "memory_operand" "m") (const_int 1) (match_operand 1 "const_int_operand" "n"))) (clobber (match_scratch:QI 2 "=&r"))] "(TARGET_H8300H || TARGET_H8300S) && !EXTRA_CONSTRAINT (operands[0], 'U') && INTVAL (operands[1]) != 7" "#" "&& reload_completed" [(set (match_dup 2) (match_dup 0)) (set (cc0) (zero_extract:SI (match_dup 2) (const_int 1) (match_dup 1)))] "") (define_insn "" [(set (cc0) (zero_extract:SI (match_operand:SI 0 "register_operand" "r") (const_int 1) (match_operand 1 "const_int_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) <= 15" "btst %Z1,%Y0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "" [(set (cc0) (and:HI (match_operand:HI 0 "register_operand" "r") (match_operand:HI 1 "single_one_operand" "n")))] "" "* { operands[1] = GEN_INT (INTVAL (operands[1]) & 0xffff); if (INTVAL (operands[1]) > 128) { operands[1] = GEN_INT (INTVAL (operands[1]) >> 8); return \"btst\\t%V1,%t0\"; } return \"btst\\t%V1,%s0\"; }" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "" [(set (cc0) (and:SI (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "single_one_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && (INTVAL (operands[1]) & 0xffff) != 0" "* { operands[1] = GEN_INT (INTVAL (operands[1]) & 0xffff); if (INTVAL (operands[1]) > 128) { operands[1] = GEN_INT (INTVAL (operands[1]) >> 8); return \"btst\\t%V1,%x0\"; } return \"btst\\t%V1,%w0\"; }" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "tstqi" [(set (cc0) (match_operand:QI 0 "register_operand" "r"))] "" "mov.b %X0,%X0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "tsthi" [(set (cc0) (match_operand:HI 0 "register_operand" "r"))] "" "mov.w %T0,%T0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (and:HI (match_operand:HI 0 "register_operand" "r") (const_int -256)))] "" "mov.b %t0,%t0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "r"))] "TARGET_H8300H || TARGET_H8300S" "mov.l %S0,%S0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (and:SI (match_operand:SI 0 "register_operand" "r") (const_int -65536)))] "" "mov.w %e0,%e0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "cmpqi" [(set (cc0) (compare:QI (match_operand:QI 0 "register_operand" "r") (match_operand:QI 1 "nonmemory_operand" "rn")))] "" "cmp.b %X1,%X0" [(set_attr "length" "2") (set_attr "cc" "compare")]) (define_expand "cmphi" [(set (cc0) (compare:HI (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "nonmemory_operand" "")))] "" " { /* Force operand1 into a register if we're compiling for the H8/300. */ if (GET_CODE (operands[1]) != REG && TARGET_H8300) operands[1] = force_reg (HImode, operands[1]); }") (define_insn "" [(set (cc0) (compare:HI (match_operand:HI 0 "register_operand" "r") (match_operand:HI 1 "register_operand" "r")))] "TARGET_H8300" "cmp.w %T1,%T0" [(set_attr "length" "2") (set_attr "cc" "compare")]) (define_insn "" [(set (cc0) (compare:HI (match_operand:HI 0 "register_operand" "r,r") (match_operand:HI 1 "nonmemory_operand" "r,n")))] "TARGET_H8300H || TARGET_H8300S" "cmp.w %T1,%T0" [(set_attr "length" "2,4") (set_attr "cc" "compare,compare")]) (define_insn "cmpsi" [(set (cc0) (compare:SI (match_operand:SI 0 "register_operand" "r,r") (match_operand:SI 1 "nonmemory_operand" "r,i")))] "TARGET_H8300H || TARGET_H8300S" "cmp.l %S1,%S0" [(set_attr "length" "2,6") (set_attr "cc" "compare,compare")]) ;; ---------------------------------------------------------------------- ;; ADD INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "addqi3" [(set (match_operand:QI 0 "register_operand" "=r") (plus:QI (match_operand:QI 1 "register_operand" "%0") (match_operand:QI 2 "nonmemory_operand" "rn")))] "" "add.b %X2,%X0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_expand "addhi3" [(set (match_operand:HI 0 "register_operand" "") (plus:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" "") (define_insn "*addhi3_h8300" [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r") (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0") (match_operand:HI 2 "nonmemory_operand" "L,N,J,n,r")))] "TARGET_H8300" "@ adds %2,%T0 subs %G2,%T0 add.b %t2,%t0 add.b %s2,%s0\;addx %t2,%t0 add.w %T2,%T0" [(set_attr "length" "2,2,2,4,2") (set_attr "cc" "none_0hit,none_0hit,clobber,clobber,set_zn")]) ;; This splitter is very important to make the stack adjustment ;; interrupt-safe. The combination of add.b and addx is unsafe! ;; ;; We apply this split after the peephole2 pass so that we won't end ;; up creating too many adds/subs when a scratch register is ;; available, which is actually a common case because stack unrolling ;; tends to happen immediately after a function call. (define_split [(set (match_operand:HI 0 "stack_pointer_operand" "") (plus:HI (match_dup 0) (match_operand 1 "const_int_gt_2_operand" "")))] "TARGET_H8300 && flow2_completed" [(const_int 0)] "split_adds_subs (HImode, operands); DONE;") (define_peephole2 [(match_scratch:HI 2 "r") (set (match_operand:HI 0 "stack_pointer_operand" "") (plus:HI (match_dup 0) (match_operand:HI 1 "const_int_ge_8_operand" "")))] "TARGET_H8300" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 2)))] "") (define_insn "*addhi3_h8300hs" [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r") (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0") (match_operand:HI 2 "nonmemory_operand" "L,N,J,n,r")))] "TARGET_H8300H || TARGET_H8300S" "@ adds %2,%S0 subs %G2,%S0 add.b %t2,%t0 add.w %T2,%T0 add.w %T2,%T0" [(set_attr "length" "2,2,2,4,2") (set_attr "cc" "none_0hit,none_0hit,clobber,set_zn,set_zn")]) (define_split [(set (match_operand:HI 0 "register_operand" "") (plus:HI (match_dup 0) (match_operand:HI 1 "two_insn_adds_subs_operand" "")))] "" [(const_int 0)] "split_adds_subs (HImode, operands); DONE;") (define_expand "addsi3" [(set (match_operand:SI 0 "register_operand" "") (plus:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))] "" "") (define_insn "addsi_h8300" [(set (match_operand:SI 0 "register_operand" "=r,r,&r") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,r") (match_operand:SI 2 "nonmemory_operand" "n,r,r")))] "TARGET_H8300" "@ add %w2,%w0\;addx %x2,%x0\;addx %y2,%y0\;addx %z2,%z0 add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0 mov.w %f1,%f0\;mov.w %e1,%e0\;add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0" [(set_attr "length" "8,6,10") (set_attr "cc" "clobber")]) (define_insn "addsi_h8300h" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0") (match_operand:SI 2 "nonmemory_operand" "L,N,i,r")))] "TARGET_H8300H || TARGET_H8300S" "@ adds %2,%S0 subs %G2,%S0 add.l %S2,%S0 add.l %S2,%S0" [(set_attr "length" "2,2,6,2") (set_attr "cc" "none_0hit,none_0hit,set_zn,set_zn")]) (define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (match_dup 0) (match_operand:SI 1 "two_insn_adds_subs_operand" "")))] "TARGET_H8300H || TARGET_H8300S" [(const_int 0)] "split_adds_subs (SImode, operands); DONE;") ;; ---------------------------------------------------------------------- ;; SUBTRACT INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "subqi3" [(set (match_operand:QI 0 "register_operand" "=r") (minus:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "register_operand" "r")))] "" "sub.b %X2,%X0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_expand "subhi3" [(set (match_operand:HI 0 "register_operand" "") (minus:HI (match_operand:HI 1 "general_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" "") (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,&r") (minus:HI (match_operand:HI 1 "general_operand" "0,0") (match_operand:HI 2 "nonmemory_operand" "r,n")))] "TARGET_H8300" "@ sub.w %T2,%T0 add.b %E2,%s0\;addx %F2,%t0" [(set_attr "length" "2,4") (set_attr "cc" "set_zn,clobber")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,&r") (minus:HI (match_operand:HI 1 "general_operand" "0,0") (match_operand:HI 2 "nonmemory_operand" "r,n")))] "TARGET_H8300H || TARGET_H8300S" "@ sub.w %T2,%T0 sub.w %T2,%T0" [(set_attr "length" "2,4") (set_attr "cc" "set_zn,set_zn")]) (define_expand "subsi3" [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))] "" "") (define_insn "subsi3_h8300" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "register_operand" "r")))] "TARGET_H8300" "sub.w %f2,%f0\;subx %y2,%y0\;subx %z2,%z0" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "subsi3_h8300h" [(set (match_operand:SI 0 "register_operand" "=r,r") (minus:SI (match_operand:SI 1 "general_operand" "0,0") (match_operand:SI 2 "nonmemory_operand" "r,i")))] "TARGET_H8300H || TARGET_H8300S" "@ sub.l %S2,%S0 sub.l %S2,%S0" [(set_attr "length" "2,6") (set_attr "cc" "set_zn,set_zn")]) ;; ---------------------------------------------------------------------- ;; MULTIPLY INSTRUCTIONS ;; ---------------------------------------------------------------------- ;; Note that the H8/300 can only handle umulqihi3. (define_insn "mulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0")) (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))] "TARGET_H8300H || TARGET_H8300S" "mulxs.b %X2,%T0" [(set_attr "length" "4") (set_attr "cc" "set_zn")]) (define_insn "mulhisi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] "TARGET_H8300H || TARGET_H8300S" "mulxs.w %T2,%S0" [(set_attr "length" "4") (set_attr "cc" "set_zn")]) (define_insn "umulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0")) (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] "" "mulxu %X2,%T0" [(set_attr "length" "2") (set_attr "cc" "none_0hit")]) (define_insn "umulhisi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] "TARGET_H8300H || TARGET_H8300S" "mulxu.w %T2,%S0" [(set_attr "length" "2") (set_attr "cc" "none_0hit")]) ;; This is a "bridge" instruction. Combine can't cram enough insns ;; together to crate a MAC instruction directly, but it can create ;; this instruction, which then allows combine to create the real ;; MAC insn. ;; ;; Unfortunately, if combine doesn't create a MAC instruction, this ;; insn must generate reasonably correct code. Egad. (define_insn "" [(set (match_operand:SI 0 "register_operand" "=a") (mult:SI (sign_extend:SI (mem:HI (post_inc:SI (match_operand:SI 1 "register_operand" "r")))) (sign_extend:SI (mem:HI (post_inc:SI (match_operand:SI 2 "register_operand" "r"))))))] "TARGET_MAC" "clrmac\;mac @%2+,@%1+" [(set_attr "length" "6") (set_attr "cc" "none_0hit")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=a") (plus:SI (mult:SI (sign_extend:SI (mem:HI (post_inc:SI (match_operand:SI 1 "register_operand" "r")))) (sign_extend:SI (mem:HI (post_inc:SI (match_operand:SI 2 "register_operand" "r"))))) (match_operand:SI 3 "register_operand" "0")))] "TARGET_MAC" "mac @%2+,@%1+" [(set_attr "length" "4") (set_attr "cc" "none_0hit")]) ;; ---------------------------------------------------------------------- ;; DIVIDE/MOD INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "udivmodqi4" [(set (match_operand:QI 0 "register_operand" "=r") (truncate:QI (udiv:HI (match_operand:HI 1 "register_operand" "0") (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))) (set (match_operand:QI 3 "register_operand" "=r") (truncate:QI (umod:HI (match_dup 1) (zero_extend:HI (match_dup 2)))))] "" "* { if (find_reg_note (insn, REG_UNUSED, operands[3])) return \"divxu.b\\t%X2,%T0\"; else return \"divxu.b\\t%X2,%T0\;mov.b\\t%t0,%s3\"; }" [(set_attr "length" "4") (set_attr "cc" "clobber")]) (define_insn "divmodqi4" [(set (match_operand:QI 0 "register_operand" "=r") (truncate:QI (div:HI (match_operand:HI 1 "register_operand" "0") (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))) (set (match_operand:QI 3 "register_operand" "=r") (truncate:QI (mod:HI (match_dup 1) (sign_extend:HI (match_dup 2)))))] "TARGET_H8300H || TARGET_H8300S" "* { if (find_reg_note (insn, REG_UNUSED, operands[3])) return \"divxs.b\\t%X2,%T0\"; else return \"divxs.b\\t%X2,%T0\;mov.b\\t%t0,%s3\"; }" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "udivmodhi4" [(set (match_operand:HI 0 "register_operand" "=r") (truncate:HI (udiv:SI (match_operand:SI 1 "register_operand" "0") (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))) (set (match_operand:HI 3 "register_operand" "=r") (truncate:HI (umod:SI (match_dup 1) (zero_extend:SI (match_dup 2)))))] "TARGET_H8300H || TARGET_H8300S" "* { if (find_reg_note (insn, REG_UNUSED, operands[3])) return \"divxu.w\\t%T2,%S0\"; else return \"divxu.w\\t%T2,%S0\;mov.w\\t%e0,%f3\"; }" [(set_attr "length" "4") (set_attr "cc" "clobber")]) (define_insn "divmodhi4" [(set (match_operand:HI 0 "register_operand" "=r") (truncate:HI (div:SI (match_operand:SI 1 "register_operand" "0") (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))) (set (match_operand:HI 3 "register_operand" "=r") (truncate:HI (mod:SI (match_dup 1) (sign_extend:SI (match_dup 2)))))] "TARGET_H8300H || TARGET_H8300S" "* { if (find_reg_note (insn, REG_UNUSED, operands[3])) return \"divxs.w\\t%T2,%S0\"; else return \"divxs.w\\t%T2,%S0\;mov.w\\t%e0,%f3\"; }" [(set_attr "length" "6") (set_attr "cc" "clobber")]) ;; ---------------------------------------------------------------------- ;; AND INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "" [(set (match_operand:QI 0 "bit_operand" "=r,U") (and:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "nonmemory_operand" "rn,n")))] "register_operand (operands[0], QImode) || single_zero_operand (operands[2], QImode)" "@ and %X2,%X0 bclr %W2,%R0" [(set_attr "length" "2,8") (set_attr "adjust_length" "no") (set_attr "cc" "set_znv,none_0hit")]) (define_expand "andqi3" [(set (match_operand:QI 0 "bit_operand" "") (and:QI (match_operand:QI 1 "bit_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" " { if (fix_bit_operand (operands, 0, AND)) DONE; }") (define_expand "andhi3" [(set (match_operand:HI 0 "register_operand" "") (and:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" "") (define_insn "*andorqi3" [(set (match_operand:QI 0 "register_operand" "=r") (ior:QI (and:QI (match_operand:QI 2 "register_operand" "r") (match_operand:QI 3 "single_one_operand" "n")) (match_operand:QI 1 "register_operand" "0")))] "" "bld\\t%V3,%X2\;bor\\t%V3,%X0\;bst\\t%V3,%X0" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "*andorhi3" [(set (match_operand:HI 0 "register_operand" "=r") (ior:HI (and:HI (match_operand:HI 2 "register_operand" "r") (match_operand:HI 3 "single_one_operand" "n")) (match_operand:HI 1 "register_operand" "0")))] "" "* { operands[3] = GEN_INT (INTVAL (operands[3]) & 0xffff); if (INTVAL (operands[3]) > 128) { operands[3] = GEN_INT (INTVAL (operands[3]) >> 8); return \"bld\\t%V3,%t2\;bor\\t%V3,%t0\;bst\\t%V3,%t0\"; } return \"bld\\t%V3,%s2\;bor\\t%V3,%s0\;bst\\t%V3,%s0\"; }" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "*andorsi3" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (match_operand:SI 2 "register_operand" "r") (match_operand:SI 3 "single_one_operand" "n")) (match_operand:SI 1 "register_operand" "0")))] "(INTVAL (operands[3]) & 0xffff) != 0" "* { operands[3] = GEN_INT (INTVAL (operands[3]) & 0xffff); if (INTVAL (operands[3]) > 128) { operands[3] = GEN_INT (INTVAL (operands[3]) >> 8); return \"bld\\t%V3,%x2\;bor\\t%V3,%x0\;bst\\t%V3,%x0\"; } return \"bld\\t%V3,%w2\;bor\\t%V3,%w0\;bst\\t%V3,%w0\"; }" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "*andorsi3_shift_8" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (ashift:SI (match_operand:SI 2 "register_operand" "r") (const_int 8)) (const_int 65280)) (match_operand:SI 1 "register_operand" "0")))] "" "or.b\\t%w2,%x0" [(set_attr "length" "2") (set_attr "cc" "clobber")]) (define_expand "andsi3" [(set (match_operand:SI 0 "register_operand" "") (and:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; OR INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "" [(set (match_operand:QI 0 "bit_operand" "=r,U") (ior:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "nonmemory_operand" "rn,n")))] "register_operand (operands[0], QImode) || single_one_operand (operands[2], QImode)" "@ or\\t%X2,%X0 bset\\t%V2,%R0" [(set_attr "length" "2,8") (set_attr "adjust_length" "no") (set_attr "cc" "set_znv,none_0hit")]) (define_expand "iorqi3" [(set (match_operand:QI 0 "bit_operand" "") (ior:QI (match_operand:QI 1 "bit_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" " { if (fix_bit_operand (operands, 1, IOR)) DONE; }") (define_expand "iorhi3" [(set (match_operand:HI 0 "register_operand" "") (ior:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" "") (define_expand "iorsi3" [(set (match_operand:SI 0 "register_operand" "") (ior:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; XOR INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "" [(set (match_operand:QI 0 "bit_operand" "=r,U") (xor:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "nonmemory_operand" "rn,n")))] "register_operand (operands[0], QImode) || single_one_operand (operands[2], QImode)" "@ xor\\t%X2,%X0 bnot\\t%V2,%R0" [(set_attr "length" "2,8") (set_attr "adjust_length" "no") (set_attr "cc" "set_znv,none_0hit")]) (define_expand "xorqi3" [(set (match_operand:QI 0 "bit_operand" "") (xor:QI (match_operand:QI 1 "bit_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" " { if (fix_bit_operand (operands, 1, XOR)) DONE; }") (define_expand "xorhi3" [(set (match_operand:HI 0 "register_operand" "") (xor:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" "") (define_expand "xorsi3" [(set (match_operand:SI 0 "register_operand" "") (xor:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonmemory_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; {AND,IOR,XOR}{HI3,SI3} PATTERNS ;; ---------------------------------------------------------------------- (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (match_operator:HI 3 "bit_operator" [(match_operand:HI 1 "register_operand" "%0") (match_operand:HI 2 "nonmemory_operand" "rn")]))] "" "* return output_logical_op (HImode, operands);" [(set (attr "length") (symbol_ref "compute_logical_op_length (HImode, operands)")) (set (attr "cc") (symbol_ref "compute_logical_op_cc (HImode, operands)"))]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 3 "bit_operator" [(match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "nonmemory_operand" "rn")]))] "" "* return output_logical_op (SImode, operands);" [(set (attr "length") (symbol_ref "compute_logical_op_length (SImode, operands)")) (set (attr "cc") (symbol_ref "compute_logical_op_cc (SImode, operands)"))]) ;; ---------------------------------------------------------------------- ;; NEGATION INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "negqi2" [(set (match_operand:QI 0 "register_operand" "=r") (neg:QI (match_operand:QI 1 "register_operand" "0")))] "" "neg %X0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_expand "neghi2" [(set (match_operand:HI 0 "register_operand" "") (neg:HI (match_operand:HI 1 "register_operand" "")))] "" " { if (TARGET_H8300) { emit_insn (gen_neghi2_h8300 (operands[0], operands[1])); DONE; } }") (define_expand "neghi2_h8300" [(set (match_dup 2) (not:HI (match_operand:HI 1 "register_operand" ""))) (set (match_dup 2) (plus:HI (match_dup 2) (const_int 1))) (set (match_operand:HI 0 "register_operand" "") (match_dup 2))] "" "operands[2] = gen_reg_rtx (HImode);") (define_insn "neghi2_h8300h" [(set (match_operand:HI 0 "register_operand" "=r") (neg:HI (match_operand:HI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "neg %T0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_expand "negsi2" [(set (match_operand:SI 0 "register_operand" "") (neg:SI (match_operand:SI 1 "register_operand" "")))] "" " { if (TARGET_H8300) { emit_insn (gen_negsi2_h8300 (operands[0], operands[1])); DONE; } }") (define_expand "negsi2_h8300" [(set (match_dup 2) (not:SI (match_operand:SI 1 "register_operand" ""))) (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1))) (set (match_operand:SI 0 "register_operand" "") (match_dup 2))] "" "operands[2] = gen_reg_rtx (SImode);") (define_insn "negsi2_h8300h" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "neg %S0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) ;; ---------------------------------------------------------------------- ;; NOT INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "one_cmplqi2" [(set (match_operand:QI 0 "register_operand" "=r") (not:QI (match_operand:QI 1 "register_operand" "0")))] "" "not %X0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_expand "one_cmplhi2" [(set (match_operand:HI 0 "register_operand" "=r") (not:HI (match_operand:HI 1 "register_operand" "0")))] "" "") (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (not:HI (match_operand:HI 1 "register_operand" "0")))] "TARGET_H8300" "not %s0\;not %t0" [(set_attr "cc" "clobber") (set_attr "length" "4")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (not:HI (match_operand:HI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "not %T0" [(set_attr "cc" "set_znv") (set_attr "length" "2")]) (define_expand "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "0")))] "" "") (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "0")))] "TARGET_H8300" "not %w0\;not %x0\;not %y0\;not %z0" [(set_attr "cc" "clobber") (set_attr "length" "8")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "not %S0" [(set_attr "cc" "set_znv") (set_attr "length" "2")]) ;; ---------------------------------------------------------------------- ;; JUMP INSTRUCTIONS ;; ---------------------------------------------------------------------- ;; Conditional jump instructions (define_expand "ble" [(set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bleu" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bge" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bgeu" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "blt" [(set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bltu" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bgt" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bgtu" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "beq" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_expand "bne" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "") (define_insn "branch_true" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" "* { if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LT)) { cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; return 0; } if (get_attr_length (insn) == 2) return \"b%j1 %l0\"; else if (get_attr_length (insn) == 4) return \"b%j1 %l0:16\"; else return \"b%k1 .Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:\"; }" [(set_attr "type" "branch") (set_attr "cc" "none")]) (define_insn "branch_false" [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] "" "* { if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LT)) { cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; return 0; } if (get_attr_length (insn) == 2) return \"b%k1 %l0\"; else if (get_attr_length (insn) == 4) return \"b%k1 %l0:16\"; else return \"b%j1 .Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:\"; }" [(set_attr "type" "branch") (set_attr "cc" "none")]) ;; Unconditional and other jump instructions. (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "* { if (get_attr_length (insn) == 2) return \"bra %l0\"; else if (get_attr_length (insn) == 4) return \"bra %l0:16\"; else return \"jmp @%l0\"; }" [(set_attr "type" "branch") (set_attr "cc" "none")]) ;; This is a define expand, because pointers may be either 16 or 32 bits. (define_expand "tablejump" [(parallel [(set (pc) (match_operand 0 "register_operand" "")) (use (label_ref (match_operand 1 "" "")))])] "" "") (define_insn "tablejump_h8300" [(set (pc) (match_operand:HI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "TARGET_H8300" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "tablejump_h8300h" [(set (pc) (match_operand:SI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "TARGET_H8300H || TARGET_H8300S" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "tablejump_normal_mode" [(set (pc) (match_operand:HI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "(TARGET_H8300H || TARGET_H8300S) && TARGET_NORMAL_MODE" "jmp @%S0" [(set_attr "cc" "none") (set_attr "length" "2")]) ;; This is a define expand, because pointers may be either 16 or 32 bits. (define_expand "indirect_jump" [(set (pc) (match_operand 0 "jump_address_operand" ""))] "" "") (define_insn "indirect_jump_h8300" [(set (pc) (match_operand:HI 0 "jump_address_operand" "Vr"))] "TARGET_H8300" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "indirect_jump_h8300h" [(set (pc) (match_operand:SI 0 "jump_address_operand" "Vr"))] "TARGET_H8300H || TARGET_H8300S" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "indirect_jump_normal_mode" [(set (pc) (match_operand:HI 0 "jump_address_operand" "Vr"))] "(TARGET_H8300H || TARGET_H8300S) && TARGET_NORMAL_MODE" "jmp @%S0" [(set_attr "cc" "none") (set_attr "length" "2")]) ;; Call subroutine with no return value. ;; ??? Even though we use HImode here, this works on the H8/300H and H8S. (define_insn "call" [(call (match_operand:QI 0 "call_insn_operand" "or") (match_operand:HI 1 "general_operand" "g"))] "" "* { if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF && SYMBOL_REF_FLAG (XEXP (operands[0], 0))) return \"jsr\\t@%0:8\"; else return \"jsr\\t%0\"; }" [(set_attr "cc" "clobber") (set (attr "length") (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") (const_int 4) (const_int 8)))]) ;; Call subroutine, returning value in operand 0 ;; (which must be a hard register). ;; ??? Even though we use HImode here, this works on the H8/300H and H8S. (define_insn "call_value" [(set (match_operand 0 "" "=r") (call (match_operand:QI 1 "call_insn_operand" "or") (match_operand:HI 2 "general_operand" "g")))] "" "* { if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF && SYMBOL_REF_FLAG (XEXP (operands[1], 0))) return \"jsr\\t@%1:8\"; else return \"jsr\\t%1\"; }" [(set_attr "cc" "clobber") (set (attr "length") (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") (const_int 4) (const_int 8)))]) (define_insn "nop" [(const_int 0)] "" "nop" [(set_attr "cc" "none") (set_attr "length" "2")]) ;; ---------------------------------------------------------------------- ;; PROLOGUE/EPILOGUE-RELATED INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "*stm_h8300s_2" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_operand:SI 1 "register_operand" ""))])] "TARGET_H8300S && ((REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1) || (REGNO (operands[0]) == 2 && REGNO (operands[1]) == 3) || (REGNO (operands[0]) == 4 && REGNO (operands[1]) == 5))" "stm.l\\t%S0-%S1,@-er7" [(set_attr "cc" "none") (set_attr "length" "4")]) (define_insn "*stm_h8300s_3" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -12))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12))) (match_operand:SI 2 "register_operand" ""))])] "TARGET_H8300S && ((REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1 && REGNO (operands[2]) == 2) || (REGNO (operands[0]) == 4 && REGNO (operands[1]) == 5 && REGNO (operands[2]) == 6))" "stm.l\\t%S0-%S2,@-er7" [(set_attr "cc" "none") (set_attr "length" "4")]) (define_insn "*stm_h8300s_4" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -16))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12))) (match_operand:SI 2 "register_operand" "")) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -16))) (match_operand:SI 3 "register_operand" ""))])] "TARGET_H8300S && REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1 && REGNO (operands[2]) == 2 && REGNO (operands[3]) == 3" "stm.l\\t%S0-%S3,@-er7" [(set_attr "cc" "none") (set_attr "length" "4")]) ;; ---------------------------------------------------------------------- ;; EXTEND INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_expand "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "general_operand_src" "")))] "" "") (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,r") (zero_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))] "TARGET_H8300" "@ mov.b #0,%t0 mov.b %R1,%s0\;mov.b #0,%t0" [(set_attr "length" "2,10") (set_attr "cc" "clobber,clobber")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,r") (zero_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))] "TARGET_H8300H || TARGET_H8300S" "@ extu.w %T0 mov.b %R1,%s0\;extu.w %T0" [(set_attr "length" "2,10") (set_attr "cc" "set_znv,set_znv")]) ;; The compiler can synthesize a H8/300H variant of this which is ;; just as efficient as one that we'd create (define_insn "zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))] "TARGET_H8300" "@ mov.b #0,%x0\;sub.w %e0,%e0 mov.b %R1,%w0\;mov.b #0,%x0\;sub.w %e0,%e0" [(set_attr "length" "4,8") (set_attr "cc" "clobber,clobber")]) (define_expand "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:HI 1 "register_operand" "")))] "" "") ;; %e prints the high part of a CONST_INT, not the low part. Arggh. (define_insn "*zero_extendhisi2_h8300" [(set (match_operand:SI 0 "register_operand" "=r,r,r") (zero_extend:SI (match_operand:HI 1 "general_operand_src" "0,i,g>")))] "TARGET_H8300" "@ sub.w %e0,%e0 mov.w %f1,%f0\;sub.w %e0,%e0 mov.w %e1,%f0\;sub.w %e0,%e0" [(set_attr "length" "2,4,6") (set_attr "cc" "clobber,clobber,clobber")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "extu.l %S0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_expand "extendqihi2" [(set (match_operand:HI 0 "register_operand" "") (sign_extend:HI (match_operand:QI 1 "register_operand" "")))] "" "") (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,r") (sign_extend:HI (match_operand:QI 1 "general_operand_src" "0,g>")))] "TARGET_H8300" "@ bld #7,%s0\;subx %t0,%t0 mov.b %R1,%s0\;bld #7,%s0\;subx %t0,%t0" [(set_attr "length" "4,8") (set_attr "cc" "clobber,clobber")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (sign_extend:HI (match_operand:QI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "exts.w %T0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) ;; The compiler can synthesize a H8/300H variant of this which is ;; just as efficient as one that we'd create (define_insn "extendqisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))] "TARGET_H8300" "@ bld #7,%w0\;subx %x0,%x0\;subx %y0,%y0\;subx %z0,%z0 mov.b %R1,%w0\;bld #7,%w0\;subx %x0,%x0\;subx %y0,%y0\;subx %z0,%z0" [(set_attr "length" "8,12") (set_attr "cc" "clobber,clobber")]) (define_expand "extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] "" "") (define_insn "*extendhisi2_h8300" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:HI 1 "general_operand_src" "0,g>")))] "TARGET_H8300" "@ bld #7,%x0\;subx %y0,%y0\;subx %z0,%z0 mov.w %T1,%f0\;bld #7,%x0\;subx %y0,%y0\;subx %z0,%z0" [(set_attr "length" "6,10") (set_attr "cc" "clobber,clobber")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "exts.l %S0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) ;; ---------------------------------------------------------------------- ;; SHIFTS ;; ---------------------------------------------------------------------- ;; ;; We make some attempt to provide real efficient shifting. One example is ;; doing an 8 bit shift of a 16 bit value by moving a byte reg into the other ;; reg and moving 0 into the former reg. ;; ;; We also try to achieve this in a uniform way. IE: We don't try to achieve ;; this in both rtl and at insn emit time. Ideally, we'd use rtl as that would ;; give the optimizer more cracks at the code. However, we wish to do things ;; like optimizing shifting the sign bit to bit 0 by rotating the other way. ;; There is rtl to handle this (rotate + and), but the H8/300 doesn't handle ;; 16 bit rotates. Also, if we emit complicated rtl, combine may not be able ;; to detect cases it can optimize. ;; ;; For these and other fuzzy reasons, I've decided to go the less pretty but ;; easier "do it at insn emit time" route. ;; QI BIT SHIFTS (define_expand "ashlqi3" [(set (match_operand:QI 0 "register_operand" "") (ashift:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (QImode, ASHIFT, operands)) DONE; else FAIL;") (define_expand "ashrqi3" [(set (match_operand:QI 0 "register_operand" "") (ashiftrt:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (QImode, ASHIFTRT, operands)) DONE; else FAIL;") (define_expand "lshrqi3" [(set (match_operand:QI 0 "register_operand" "") (lshiftrt:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE; else FAIL;") (define_insn "" [(set (match_operand:QI 0 "register_operand" "=r,r") (match_operator:QI 3 "nshift_operator" [ (match_operand:QI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "R,rn")])) (clobber (match_scratch:QI 4 "=X,&r"))] "" "* return output_a_shift (operands);" [(set (attr "length") (symbol_ref "compute_a_shift_length (insn, operands)")) (set_attr "cc" "clobber")]) ;; HI BIT SHIFTS (define_expand "ashlhi3" [(set (match_operand:HI 0 "register_operand" "") (ashift:HI (match_operand:HI 1 "nonmemory_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (HImode, ASHIFT, operands)) DONE; else FAIL;") (define_expand "lshrhi3" [(set (match_operand:HI 0 "register_operand" "") (lshiftrt:HI (match_operand:HI 1 "general_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE; else FAIL;") (define_expand "ashrhi3" [(set (match_operand:HI 0 "register_operand" "") (ashiftrt:HI (match_operand:HI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE; else FAIL;") (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r,r") (match_operator:HI 3 "nshift_operator" [ (match_operand:HI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "S,rn")])) (clobber (match_scratch:QI 4 "=X,&r"))] "" "* return output_a_shift (operands);" [(set (attr "length") (symbol_ref "compute_a_shift_length (insn, operands)")) (set_attr "cc" "clobber")]) ;; SI BIT SHIFTS (define_expand "ashlsi3" [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_operand:SI 1 "general_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (SImode, ASHIFT, operands)) DONE; else FAIL;") (define_expand "lshrsi3" [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_operand:SI 1 "general_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (SImode, LSHIFTRT, operands)) DONE; else FAIL;") (define_expand "ashrsi3" [(set (match_operand:SI 0 "register_operand" "") (ashiftrt:SI (match_operand:SI 1 "general_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE; else FAIL;") (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r,r") (match_operator:SI 3 "nshift_operator" [ (match_operand:SI 1 "register_operand" "0,0") (match_operand:QI 2 "nonmemory_operand" "T,rn")])) (clobber (match_scratch:QI 4 "=X,&r"))] "" "* return output_a_shift (operands);" [(set (attr "length") (symbol_ref "compute_a_shift_length (insn, operands)")) (set_attr "cc" "clobber")]) ;; ---------------------------------------------------------------------- ;; ROTATIONS ;; ---------------------------------------------------------------------- (define_expand "rotlqi3" [(set (match_operand:QI 0 "register_operand" "") (rotate:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_rotate (ROTATE, operands)) DONE; else FAIL;") (define_insn "*rotlqi3_1" [(set (match_operand:QI 0 "register_operand" "=r") (rotate:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "immediate_operand" "")))] "" "* return emit_a_rotate (ROTATE, operands);" [(set_attr "length" "20") (set_attr "cc" "clobber")]) (define_expand "rotlhi3" [(set (match_operand:HI 0 "register_operand" "") (rotate:HI (match_operand:HI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" "if (expand_a_rotate (ROTATE, operands)) DONE; else FAIL;") (define_insn "*rotlhi3_1" [(set (match_operand:HI 0 "register_operand" "=r") (rotate:HI (match_operand:HI 1 "register_operand" "0") (match_operand:QI 2 "immediate_operand" "")))] "" "* return emit_a_rotate (ROTATE, operands);" [(set_attr "length" "20") (set_attr "cc" "clobber")]) (define_expand "rotlsi3" [(set (match_operand:SI 0 "register_operand" "") (rotate:SI (match_operand:SI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "TARGET_H8300H || TARGET_H8300S" "if (expand_a_rotate (ROTATE, operands)) DONE; else FAIL;") (define_insn "*rotlsi3_1" [(set (match_operand:SI 0 "register_operand" "=r") (rotate:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "immediate_operand" "")))] "TARGET_H8300H || TARGET_H8300S" "* return emit_a_rotate (ROTATE, operands);" [(set_attr "length" "20") (set_attr "cc" "clobber")]) ;; ----------------------------------------------------------------- ;; BIT FIELDS ;; ----------------------------------------------------------------- ;; The H8/300 has given 1/8th of its opcode space to bitfield ;; instructions so let's use them as well as we can. ;; You'll never believe all these patterns perform one basic action -- ;; load a bit from the source, optionally invert the bit, then store it ;; in the destination (which is known to be zero). ;; ;; Combine obviously need some work to better identify this situation and ;; canonicalize the form better. ;; ;; Normal loads with a 16bit destination. ;; (define_insn "" [(set (match_operand:HI 0 "register_operand" "=&r") (zero_extract:HI (match_operand:HI 1 "register_operand" "r") (const_int 1) (match_operand:HI 2 "immediate_operand" "n")))] "TARGET_H8300" "sub.w %0,%0\;bld %Z2,%Y1\;bst #0,%X0" [(set_attr "cc" "clobber") (set_attr "length" "6")]) ;; ;; Inverted loads with a 16bit destination. ;; (define_insn "" [(set (match_operand:HI 0 "register_operand" "=&r") (zero_extract:HI (xor:HI (match_operand:HI 1 "register_operand" "r") (match_operand:HI 3 "const_int_operand" "n")) (const_int 1) (match_operand:HI 2 "const_int_operand" "n")))] "TARGET_H8300 && (1 << INTVAL (operands[2])) == INTVAL (operands[3])" "sub.w %0,%0\;bild %Z2,%Y1\;bst #0,%X0" [(set_attr "cc" "clobber") (set_attr "length" "8")]) ;; ;; Normal loads with a 32bit destination. ;; (define_insn "*extzv_1_r_h8300" [(set (match_operand:SI 0 "register_operand" "=&r") (zero_extract:SI (match_operand:HI 1 "register_operand" "r") (const_int 1) (match_operand 2 "const_int_operand" "n")))] "TARGET_H8300 && INTVAL (operands[2]) < 16" "* return output_simode_bld (0, operands);" [(set_attr "cc" "clobber") (set_attr "length" "8")]) (define_insn "*extzv_1_r_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (match_operand:SI 1 "register_operand" "r") (const_int 1) (match_operand 2 "const_int_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[2]) < 16" "* return output_simode_bld (0, operands);" [(set_attr "cc" "clobber") (set_attr "length" "8")]) ;; ;; Inverted loads with a 32bit destination. ;; (define_insn "*extzv_1_r_inv_h8300" [(set (match_operand:SI 0 "register_operand" "=&r") (zero_extract:SI (xor:HI (match_operand:HI 1 "register_operand" "r") (match_operand:HI 3 "const_int_operand" "n")) (const_int 1) (match_operand 2 "const_int_operand" "n")))] "TARGET_H8300 && INTVAL (operands[2]) < 16 && (1 << INTVAL (operands[2])) == INTVAL (operands[3])" "* return output_simode_bld (1, operands);" [(set_attr "cc" "clobber") (set_attr "length" "8")]) (define_insn "*extzv_1_r_inv_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (xor:SI (match_operand:SI 1 "register_operand" "r") (match_operand 3 "const_int_operand" "n")) (const_int 1) (match_operand 2 "const_int_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[2]) < 16 && (1 << INTVAL (operands[2])) == INTVAL (operands[3])" "* return output_simode_bld (1, operands);" [(set_attr "cc" "clobber") (set_attr "length" "8")]) (define_expand "insv" [(set (zero_extract:HI (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" "") (match_operand:HI 2 "general_operand" "")) (match_operand:HI 3 "general_operand" ""))] "TARGET_H8300" " { /* We only have single bit bit-field instructions. */ if (INTVAL (operands[1]) != 1) FAIL; /* For now, we don't allow memory operands. */ if (GET_CODE (operands[0]) == MEM || GET_CODE (operands[3]) == MEM) FAIL; }") (define_insn "" [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r") (const_int 1) (match_operand:HI 1 "immediate_operand" "n")) (match_operand:HI 2 "register_operand" "r"))] "" "bld #0,%R2\;bst %Z1,%Y0 ; i1" [(set_attr "cc" "clobber") (set_attr "length" "4")]) (define_expand "extzv" [(set (match_operand:HI 0 "register_operand" "") (zero_extract:HI (match_operand:HI 1 "bit_operand" "") (match_operand:HI 2 "general_operand" "") (match_operand:HI 3 "general_operand" "")))] "TARGET_H8300" " { /* We only have single bit bit-field instructions. */ if (INTVAL (operands[2]) != 1) FAIL; /* For now, we don't allow memory operands. */ if (GET_CODE (operands[1]) == MEM) FAIL; }") ;; BAND, BOR, and BXOR patterns (define_insn "" [(set (match_operand:HI 0 "bit_operand" "=Ur") (match_operator:HI 4 "bit_operator" [(zero_extract:HI (match_operand:HI 1 "register_operand" "r") (const_int 1) (match_operand:HI 2 "immediate_operand" "n")) (match_operand:HI 3 "bit_operand" "0")]))] "" "bld %Z2,%Y1\;%b4 #0,%R0\;bst #0,%R0; bl1" [(set_attr "cc" "clobber") (set_attr "length" "6") (set_attr "adjust_length" "no")]) (define_insn "" [(set (match_operand:HI 0 "bit_operand" "=Ur") (match_operator:HI 5 "bit_operator" [(zero_extract:HI (match_operand:HI 1 "register_operand" "r") (const_int 1) (match_operand:HI 2 "immediate_operand" "n")) (zero_extract:HI (match_operand:HI 3 "register_operand" "r") (const_int 1) (match_operand:HI 4 "immediate_operand" "n"))]))] "" "bld %Z2,%Y1\;%b5 %Z4,%Y3\;bst #0,%R0; bl3" [(set_attr "cc" "clobber") (set_attr "length" "6") (set_attr "adjust_length" "no")]) ;; ----------------------------------------------------------------- ;; COMBINE PATTERNS ;; ----------------------------------------------------------------- (define_insn "*extzv_8_8" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (match_operand:SI 1 "register_operand" "r") (const_int 8) (const_int 8)))] "TARGET_H8300H || TARGET_H8300S" "mov.b\\t%x1,%w0\;extu.w\\t%f0\;extu.l\\t%S0" [(set_attr "cc" "set_znv") (set_attr "length" "6")]) (define_insn "*extzv_8_16" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (match_operand:SI 1 "register_operand" "r") (const_int 8) (const_int 16)))] "TARGET_H8300H || TARGET_H8300S" "mov.w\\t%e1,%f0\;extu.w\\t%f0\;extu.l\\t%S0" [(set_attr "cc" "set_znv") (set_attr "length" "6")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (ior:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) (match_operand:HI 2 "register_operand" "0")))] "REG_P (operands[0]) && REG_P (operands[1]) && REGNO (operands[0]) != REGNO (operands[1])" "or\\t%X1,%s0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) (match_operand:SI 2 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && REG_P (operands[0]) && REG_P (operands[1]) && (REGNO (operands[0]) != REGNO (operands[1]))" "or.w\\t%T1,%f0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) (match_operand:SI 2 "register_operand" "0")))] "" "or\\t%X1,%w0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (xor:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) (match_operand:HI 2 "register_operand" "0")))] "REG_P (operands[0]) && REG_P (operands[1]) && REGNO (operands[0]) != REGNO (operands[1])" "xor\\t%X1,%s0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (xor:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) (match_operand:SI 2 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && REG_P (operands[0]) && REG_P (operands[1]) && (REGNO (operands[0]) != REGNO (operands[1]))" "xor.w\\t%T1,%f0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (xor:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "r")) (match_operand:SI 2 "register_operand" "0")))] "REG_P (operands[0]) && REG_P (operands[1]) && REGNO (operands[0]) != REGNO (operands[1])" "xor\\t%X1,%w0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (ior:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "0")) (ashift:HI (match_operand:HI 2 "register_operand" "r") (const_int 8))))] "REG_P (operands[0]) && REG_P (operands[2]) && REGNO (operands[0]) != REGNO (operands[2])" "mov.b\\t%s2,%t0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "*iorhi_shift_8" [(set (match_operand:HI 0 "register_operand" "=r") (ior:HI (ashift:HI (match_operand:HI 1 "register_operand" "r") (const_int 8)) (match_operand:HI 2 "register_operand" "0")))] "" "or.b\\t%s1,%t0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "0")) (ashift:SI (match_operand:SI 2 "register_operand" "r") (const_int 16))))] "TARGET_H8300H || TARGET_H8300S" "mov.w\\t%f2,%e0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") (const_int 16)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "or.w\\t%f1,%e0" [(set_attr "cc" "clobber") (set_attr "length" "2")]) ;; Storing a part of HImode to QImode. (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=rm<") (subreg:QI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r") (const_int 8)) 1))] "" "mov.b\\t%t1,%R0" [(set_attr "cc" "set_znv") (set_attr "length" "8")]) ;; Storing a part of SImode to QImode. (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=rm<") (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 8)) 3))] "" "mov.b\\t%x1,%R0" [(set_attr "cc" "set_znv") (set_attr "length" "8")]) (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=rm<") (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 16)) 3)) (clobber (match_scratch:SI 2 "=&r"))] "TARGET_H8300H || TARGET_H8300S" "mov.w\\t%e1,%f2\;mov.b\\t%w2,%R0" [(set_attr "cc" "set_znv") (set_attr "length" "10")]) (define_insn "" [(set (match_operand:QI 0 "general_operand_dst" "=rm<") (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 24)) 3)) (clobber (match_scratch:SI 2 "=&r"))] "TARGET_H8300H || TARGET_H8300S" "mov.w\\t%e1,%f2\;mov.b\\t%x2,%R0" [(set_attr "cc" "set_znv") (set_attr "length" "10")]) (define_insn_and_split "" [(set (pc) (if_then_else (eq (zero_extract:SI (subreg:SI (match_operand:QI 0 "register_operand" "") 0) (const_int 1) (const_int 7)) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "#" "" [(set (cc0) (match_dup 0)) (set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_dup 1)) (pc)))] "") (define_insn_and_split "" [(set (pc) (if_then_else (ne (zero_extract:SI (subreg:SI (match_operand:QI 0 "register_operand" "") 0) (const_int 1) (const_int 7)) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc)))] "" "#" "" [(set (cc0) (match_dup 0)) (set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_dup 1)) (pc)))] "") ;; ----------------------------------------------------------------- ;; PEEPHOLE PATTERNS ;; ----------------------------------------------------------------- ;; Convert (A >> B) & C to (A & 255) >> B if C == 255 >> B. (define_peephole2 [(parallel [(set (match_operand:HI 0 "register_operand" "") (lshiftrt:HI (match_dup 0) (match_operand:HI 1 "const_int_operand" ""))) (clobber (match_operand:HI 2 "" ""))]) (set (match_dup 0) (and:HI (match_dup 0) (match_operand:HI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (255 >> INTVAL (operands[1]))" [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255))) (parallel [(set (match_dup 0) (lshiftrt:HI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert (A << B) & C to (A & 255) << B if C == 255 << B. (define_peephole2 [(parallel [(set (match_operand:HI 0 "register_operand" "") (ashift:HI (match_dup 0) (match_operand:HI 1 "const_int_operand" ""))) (clobber (match_operand:HI 2 "" ""))]) (set (match_dup 0) (and:HI (match_dup 0) (match_operand:HI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (255 << INTVAL (operands[1]))" [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255))) (parallel [(set (match_dup 0) (ashift:HI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert (A >> B) & C to (A & 255) >> B if C == 255 >> B. (define_peephole2 [(parallel [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))) (clobber (match_operand:SI 2 "" ""))]) (set (match_dup 0) (and:SI (match_dup 0) (match_operand:SI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (255 >> INTVAL (operands[1]))" [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255))) (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert (A << B) & C to (A & 255) << B if C == 255 << B. (define_peephole2 [(parallel [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))) (clobber (match_operand:SI 2 "" ""))]) (set (match_dup 0) (and:SI (match_dup 0) (match_operand:SI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (255 << INTVAL (operands[1]))" [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255))) (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert (A >> B) & C to (A & 65535) >> B if C == 65535 >> B. (define_peephole2 [(parallel [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))) (clobber (match_operand:SI 2 "" ""))]) (set (match_dup 0) (and:SI (match_dup 0) (match_operand:SI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (65535 >> INTVAL (operands[1]))" [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert (A << B) & C to (A & 65535) << B if C == 65535 << B. (define_peephole2 [(parallel [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))) (clobber (match_operand:SI 2 "" ""))]) (set (match_dup 0) (and:SI (match_dup 0) (match_operand:SI 3 "const_int_operand" "")))] "INTVAL (operands[3]) == (65535 << INTVAL (operands[1]))" [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 1))) (clobber (match_dup 2))])] "") ;; Convert a QImode push into an SImode push so that the ;; define_peephole2 below can cram multiple pushes into one stm.l. (define_peephole2 [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:QI (plus:SI (reg:SI SP_REG) (const_int -3))) (match_operand:QI 0 "register_operand" ""))])] "TARGET_H8300S" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));") ;; Convert a HImode push into an SImode push so that the ;; define_peephole2 below can cram multiple pushes into one stm.l. (define_peephole2 [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:HI (plus:SI (reg:SI SP_REG) (const_int -2))) (match_operand:HI 0 "register_operand" ""))])] "TARGET_H8300S" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));") ;; Cram four pushes into stm.l. (define_peephole2 [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 2 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 3 "register_operand" ""))] "TARGET_H8300S && REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1 && REGNO (operands[2]) == 2 && REGNO (operands[3]) == 3" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -16))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_dup 1)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12))) (match_dup 2)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -16))) (match_dup 3))])] "") ;; Cram three pushes into stm.l. (define_peephole2 [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 2 "register_operand" ""))] "TARGET_H8300S && ((REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1 && REGNO (operands[2]) == 2) || (REGNO (operands[0]) == 4 && REGNO (operands[1]) == 5 && REGNO (operands[2]) == 6))" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -12))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_dup 1)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12))) (match_dup 2))])] "") ;; Cram two pushes into stm.l. (define_peephole2 [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 1 "register_operand" ""))] "TARGET_H8300S && ((REGNO (operands[0]) == 0 && REGNO (operands[1]) == 1) || (REGNO (operands[0]) == 2 && REGNO (operands[1]) == 3) || (REGNO (operands[0]) == 4 && REGNO (operands[1]) == 5))" [(parallel [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8))) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8))) (match_dup 1))])] "") ;; Turn ;; ;; mov.w #2,r0 ;; add.w r7,r0 (6 bytes) ;; ;; into ;; ;; mov.w r7,r0 ;; adds #2,r0 (4 bytes) (define_peephole2 [(set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "const_int_operand" "")) (set (match_dup 0) (plus:HI (match_dup 0) (match_operand:HI 2 "register_operand" "")))] "REG_P (operands[0]) && REG_P (operands[2]) && REGNO (operands[0]) != REGNO (operands[2]) && (CONST_OK_FOR_J (INTVAL (operands[1])) || CONST_OK_FOR_L (INTVAL (operands[1])) || CONST_OK_FOR_N (INTVAL (operands[1])))" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (plus:HI (match_dup 0) (match_dup 1)))] "") ;; Turn ;; ;; sub.l er0,er0 ;; add.b #4,r0l ;; add.l er7,er0 (6 bytes) ;; ;; into ;; ;; mov.l er7,er0 ;; adds #4,er0 (4 bytes) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" "")) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))] "(TARGET_H8300H || TARGET_H8300S) && REG_P (operands[0]) && REG_P (operands[2]) && REGNO (operands[0]) != REGNO (operands[2]) && (CONST_OK_FOR_L (INTVAL (operands[1])) || CONST_OK_FOR_N (INTVAL (operands[1])))" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] "") ;; Turn ;; ;; mov.l er7,er0 ;; add.l #10,er0 (takes 8 bytes) ;; ;; into ;; ;; sub.l er0,er0 ;; add.b #10,r0l ;; add.l er7,er0 (takes 6 bytes) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "register_operand" "")) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand:SI 2 "const_int_operand" "")))] "(TARGET_H8300H || TARGET_H8300S) && REG_P (operands[0]) && REG_P (operands[1]) && REGNO (operands[0]) != REGNO (operands[1]) && !CONST_OK_FOR_L (INTVAL (operands[2])) && !CONST_OK_FOR_N (INTVAL (operands[2])) && ((INTVAL (operands[2]) & 0xff) == INTVAL (operands[2]) || (INTVAL (operands[2]) & 0xff00) == INTVAL (operands[2]) || INTVAL (operands[2]) == 0xffff || INTVAL (operands[2]) == 0xfffe)" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] "")