;; GCC machine description for Renesas H8/300 ;; Copyright (C) 1992-2013 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 GCC. ;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; . ;; We compute exact length on each instruction for most of the time. ;; In some case, most notably bit operations that may involve memory ;; operands, the lengths in this file are "worst case". ;; 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 [(UNSPEC_INCDEC 0) (UNSPEC_MONITOR 1)]) (define_constants [(UNSPEC_MOVMD 100) (UNSPEC_STPCPY 101)]) (define_constants [(R0_REG 0) (SC_REG 3) (COUNTER_REG 4) (SOURCE_REG 5) (DESTINATION_REG 6) (HFP_REG 6) (SP_REG 7) (MAC_REG 8) (AP_REG 9) (RAP_REG 10) (FP_REG 11)]) ;; ---------------------------------------------------------------------- ;; ATTRIBUTES ;; ---------------------------------------------------------------------- (define_attr "cpu" "h8300,h8300h" (const (symbol_ref "cpu_type"))) (define_attr "type" "branch,arith,bitbranch,call" (const_string "arith")) (define_attr "length_table" "none,addb,addw,addl,logicb,movb,movw,movl,mova_zero,mova,unary,mov_imm4,short_immediate,bitfield,bitbranch" (const_string "none")) ;; The size of instructions in bytes. (define_attr "length" "" (cond [(eq_attr "type" "branch") ;; In a forward delayed branch, (pc) represents the end of the ;; delay sequence, not the end of the branch itself. (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -126)) (le (plus (minus (match_dup 0) (pc)) (symbol_ref "DELAY_SLOT_LENGTH (insn)")) (const_int 125))) (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))) (eq_attr "type" "bitbranch") (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -126)) (le (minus (match_dup 0) (pc)) (const_int 126))) (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)") (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)))) (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)") (const_int 4)) (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)") (const_int 6)))) (eq_attr "length_table" "!none") (symbol_ref "h8300_insn_length_from_table (insn, operands)")] (const_int 200))) ;; 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")) ;; Type of delay slot. NONE means the instruction has no delay slot. ;; JUMP means it is an unconditional jump that (if short enough) ;; could be implemented using bra/s. (define_attr "delay_slot" "none,jump" (const_string "none")) ;; "yes" if the instruction can be put into a delay slot. It's not ;; entirely clear that jsr is not valid in delay slots, but it ;; definitely doesn't have the effect of causing the called function ;; to return to the target of the delayed branch. (define_attr "can_delay" "no,yes" (cond [(eq_attr "type" "branch,bitbranch,call") (const_string "no") (geu (symbol_ref "get_attr_length (insn)") (const_int 2)) (const_string "no")] (const_string "yes"))) ;; Only allow jumps to have a delay slot if we think they might ;; be short enough. This is just an optimization: we don't know ;; for certain whether they will be or not. (define_delay (and (eq_attr "delay_slot" "jump") (eq (symbol_ref "get_attr_length (insn)") (const_int 2))) [(eq_attr "can_delay" "yes") (nil) (nil)]) ;; Provide the maximum length of an assembly instruction in an asm ;; statement. The maximum length of 14 bytes is achieved on H8SX. (define_asm_attributes [(set (attr "length") (cond [(match_test "TARGET_H8300") (const_int 4) (match_test "TARGET_H8300H") (const_int 10) (match_test "TARGET_H8300S") (const_int 10)] (const_int 14)))]) (include "predicates.md") (include "constraints.md") ;; ---------------------------------------------------------------------- ;; MACRO DEFINITIONS ;; ---------------------------------------------------------------------- ;; This mode iterator allows :P to be used for patterns that operate on ;; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_iterator P [(HI "Pmode == HImode") (SI "Pmode == SImode")]) ;; ---------------------------------------------------------------------- ;; MOVE INSTRUCTIONS ;; ---------------------------------------------------------------------- ;; movqi (define_insn "*movqi_h8300" [(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 && h8300_move_ok (operands[0], operands[1])" "@ 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 "*movqi_h8300hs" [(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) && !TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" "@ 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") (symbol_ref "compute_mov_length (operands)")) (set_attr "cc" "set_zn,set_znv,set_znv,clobber,set_znv,set_znv")]) (define_insn "*movqi_h8sx" [(set (match_operand:QI 0 "general_operand_dst" "=Z,rQ") (match_operand:QI 1 "general_operand_src" "P4>X,rQi"))] "TARGET_H8300SX" "@ mov.b %X1:4,%X0 mov.b %X1,%X0" [(set_attr "length_table" "mov_imm4,movb") (set_attr "cc" "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 (!TARGET_H8300SX && !h8300_move_ok (operands[0], operands[1])) operands[1] = copy_to_mode_reg (QImode, operands[1]); }) (define_insn "movstrictqi" [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "+r,r")) (match_operand:QI 1 "general_operand_src" "I,rmi>"))] "" "@ sub.b %X0,%X0 mov.b %X1,%X0" [(set_attr "length" "2,*") (set_attr "length_table" "*,movb") (set_attr "cc" "set_zn,set_znv")]) ;; movhi (define_insn "*movhi_h8300" [(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 && h8300_move_ok (operands[0], 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") (symbol_ref "compute_mov_length (operands)")) (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) (define_insn "*movhi_h8300hs" [(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) && !TARGET_H8300SX && h8300_move_ok (operands[0], 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") (symbol_ref "compute_mov_length (operands)")) (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) (define_insn "*movhi_h8sx" [(set (match_operand:HI 0 "general_operand_dst" "=r,r,Z,Q,rQ") (match_operand:HI 1 "general_operand_src" "I,P3>X,P4>X,IP8>X,rQi"))] "TARGET_H8300SX" "@ sub.w %T0,%T0 mov.w %T1:3,%T0 mov.w %T1:4,%T0 mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr "length_table" "*,*,mov_imm4,short_immediate,movw") (set_attr "length" "2,2,*,*,*") (set_attr "cc" "set_zn,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 (!h8300_move_ok (operands[0], operands[1])) 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")) (match_operand:HI 1 "general_operand_src" "I,P3>X,rmi"))] "" "@ sub.w %T0,%T0 mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr "length" "2,2,*") (set_attr "length_table" "*,*,movw") (set_attr "cc" "set_zn,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 (h8300_expand_movsi (operands)) DONE; } else if (!TARGET_H8300SX) { /* One of the ops has to be in a register. */ if (!h8300_move_ok (operands[0], operands[1])) operands[1] = copy_to_mode_reg (SImode, 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 && h8300_move_ok (operands[0], operands[1])" { unsigned 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 { if (GET_CODE (operands[1]) == CONST_INT) { /* If either half is zero, use sub.w to clear that half. */ 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"; /* If the upper half and the lower half are the same, copy one half to the other. */ if ((INTVAL (operands[1]) & 0xffff) == ((INTVAL (operands[1]) >> 16) & 0xffff)) return "mov.w\\t%e1,%e0\;mov.w\\t%e0,%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: gcc_unreachable (); } } [(set (attr "length") (symbol_ref "compute_mov_length (operands)"))]) (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) && !TARGET_H8300SX && h8300_move_ok (operands[0], 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") (symbol_ref "compute_mov_length (operands)")) (set_attr "cc" "set_zn,set_znv,clobber,set_znv,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")]) (define_insn "*movsi_h8sx" [(set (match_operand:SI 0 "general_operand_dst" "=r,r,Q,rQ,*a,*a,r") (match_operand:SI 1 "general_operand_src" "I,P3>X,IP8>X,rQi,I,r,*a"))] "TARGET_H8300SX" "@ sub.l %S0,%S0 mov.l %S1:3,%S0 mov.l %S1,%S0 mov.l %S1,%S0 clrmac clrmac\;ldmac %1,macl stmac macl,%0" [(set_attr "length_table" "*,*,short_immediate,movl,*,*,*") (set_attr "length" "2,2,*,*,2,6,4") (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")]) (define_insn "*movsf_h8sx" [(set (match_operand:SF 0 "general_operand_dst" "=r,rQ") (match_operand:SF 1 "general_operand_src" "G,rQi"))] "TARGET_H8300SX" "@ sub.l %S0,%S0 mov.l %S1,%S0" [(set_attr "length" "2,*") (set_attr "length_table" "*,movl") (set_attr "cc" "set_zn,set_znv")]) ;; Implement block moves using movmd. Defining movmemsi allows the full ;; range of constant lengths (up to 0x40000 bytes when using movmd.l). ;; See h8sx_emit_movmd for details. (define_expand "movmemsi" [(use (match_operand:BLK 0 "memory_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:SI 2 "" "")) (use (match_operand:SI 3 "const_int_operand" ""))] "TARGET_H8300SX" { if (h8sx_emit_movmd (operands[0], operands[1], operands[2], INTVAL (operands[3]))) DONE; else FAIL; }) ;; Expander for generating movmd insns. Operand 0 is the destination ;; memory region, operand 1 is the source, operand 2 is the counter ;; register and operand 3 is the chunk size (1, 2 or 4). (define_expand "movmd" [(parallel [(set (match_operand:BLK 0 "memory_operand" "") (match_operand:BLK 1 "memory_operand" "")) (unspec [(match_operand:HI 2 "register_operand" "") (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD) (clobber (match_dup 4)) (clobber (match_dup 5)) (set (match_dup 2) (const_int 0))])] "TARGET_H8300SX" { operands[4] = copy_rtx (XEXP (operands[0], 0)); operands[5] = copy_rtx (XEXP (operands[1], 0)); }) ;; This is a difficult instruction to reload since operand 0 must be the ;; frame pointer. See h8300_reg_class_from_letter for an explanation. (define_insn "movmd_internal_normal" [(set (mem:BLK (match_operand:HI 3 "register_operand" "0,r")) (mem:BLK (match_operand:HI 4 "register_operand" "1,1"))) (unspec [(match_operand:HI 5 "register_operand" "2,2") (match_operand:HI 6 "const_int_operand" "n,n")] UNSPEC_MOVMD) (clobber (match_operand:HI 0 "register_operand" "=d,??D")) (clobber (match_operand:HI 1 "register_operand" "=f,f")) (set (match_operand:HI 2 "register_operand" "=c,c") (const_int 0))] "TARGET_H8300SX && TARGET_NORMAL_MODE" "@ movmd%m6 #" [(set_attr "length" "2,14") (set_attr "can_delay" "no") (set_attr "cc" "none,clobber")]) (define_insn "movmd_internal" [(set (mem:BLK (match_operand:SI 3 "register_operand" "0,r")) (mem:BLK (match_operand:SI 4 "register_operand" "1,1"))) (unspec [(match_operand:HI 5 "register_operand" "2,2") (match_operand:HI 6 "const_int_operand" "n,n")] UNSPEC_MOVMD) (clobber (match_operand:SI 0 "register_operand" "=d,??D")) (clobber (match_operand:SI 1 "register_operand" "=f,f")) (set (match_operand:HI 2 "register_operand" "=c,c") (const_int 0))] "TARGET_H8300SX && !TARGET_NORMAL_MODE" "@ movmd%m6 #" [(set_attr "length" "2,14") (set_attr "can_delay" "no") (set_attr "cc" "none,clobber")]) ;; Split the above instruction if the destination register isn't er6. ;; We need a sequence like: ;; ;; mov.l er6,@-er7 ;; mov.l ,er6 ;; movmd.sz ;; mov.l er6, ;; mov.l @er7+,er6 ;; ;; where is the current destination register (operand 4). ;; The fourth instruction will be deleted if dies here. (define_split [(set (match_operand:BLK 0 "memory_operand" "") (match_operand:BLK 1 "memory_operand" "")) (unspec [(match_operand:HI 2 "register_operand" "") (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD) (clobber (match_operand:HI 4 "register_operand" "")) (clobber (match_operand:HI 5 "register_operand" "")) (set (match_dup 2) (const_int 0))] "TARGET_H8300SX && TARGET_NORMAL_MODE && reload_completed && REGNO (operands[4]) != DESTINATION_REG" [(const_int 0)] { rtx dest; h8300_swap_into_er6 (XEXP (operands[0], 0)); dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx); emit_insn (gen_movmd (dest, operands[1], operands[2], operands[3])); h8300_swap_out_of_er6 (operands[4]); DONE; }) (define_split [(set (match_operand:BLK 0 "memory_operand" "") (match_operand:BLK 1 "memory_operand" "")) (unspec [(match_operand:HI 2 "register_operand" "") (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD) (clobber (match_operand:SI 4 "register_operand" "")) (clobber (match_operand:SI 5 "register_operand" "")) (set (match_dup 2) (const_int 0))] "TARGET_H8300SX && !TARGET_NORMAL_MODE && reload_completed && REGNO (operands[4]) != DESTINATION_REG" [(const_int 0)] { rtx dest; h8300_swap_into_er6 (XEXP (operands[0], 0)); dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx); emit_insn (gen_movmd (dest, operands[1], operands[2], operands[3])); h8300_swap_out_of_er6 (operands[4]); DONE; }) ;; Expand a call to stpcpy() using movsd. Operand 0 should point to ;; the final character, but movsd leaves it pointing to the character ;; after that. (define_expand "movstr" [(use (match_operand 0 "register_operand" "")) (use (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:BLK 2 "memory_operand" ""))] "TARGET_H8300SX" { operands[1] = replace_equiv_address (operands[1], copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); operands[2] = replace_equiv_address (operands[2], copy_to_mode_reg (Pmode, XEXP (operands[2], 0))); emit_insn (gen_movsd (operands[1], operands[2], gen_reg_rtx (Pmode))); emit_insn (gen_add3_insn (operands[0], XEXP (operands[1], 0), constm1_rtx)); DONE; }) ;; Expander for generating a movsd instruction. Operand 0 is the ;; destination string, operand 1 is the source string and operand 2 ;; is a scratch register. (define_expand "movsd" [(parallel [(set (match_operand:BLK 0 "memory_operand" "") (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY)) (clobber (match_dup 3)) (clobber (match_dup 4)) (clobber (match_operand 2 "register_operand" ""))])] "TARGET_H8300SX" { operands[3] = copy_rtx (XEXP (operands[0], 0)); operands[4] = copy_rtx (XEXP (operands[1], 0)); }) ;; See comments above memcpy_internal(). (define_insn "stpcpy_internal_normal" [(set (mem:BLK (match_operand:HI 3 "register_operand" "0,r")) (unspec:BLK [(mem:BLK (match_operand:HI 4 "register_operand" "1,1"))] UNSPEC_STPCPY)) (clobber (match_operand:HI 0 "register_operand" "=d,??D")) (clobber (match_operand:HI 1 "register_operand" "=f,f")) (clobber (match_operand:HI 2 "register_operand" "=c,c"))] "TARGET_H8300SX && TARGET_NORMAL_MODE" "@ \n1:\tmovsd\t2f\;bra\t1b\n2: #" [(set_attr "length" "6,18") (set_attr "cc" "none,clobber")]) (define_insn "stpcpy_internal" [(set (mem:BLK (match_operand:SI 3 "register_operand" "0,r")) (unspec:BLK [(mem:BLK (match_operand:SI 4 "register_operand" "1,1"))] UNSPEC_STPCPY)) (clobber (match_operand:SI 0 "register_operand" "=d,??D")) (clobber (match_operand:SI 1 "register_operand" "=f,f")) (clobber (match_operand:SI 2 "register_operand" "=c,c"))] "TARGET_H8300SX && !TARGET_NORMAL_MODE" "@ \n1:\tmovsd\t2f\;bra\t1b\n2: #" [(set_attr "length" "6,18") (set_attr "cc" "none,clobber")]) ;; Split the above instruction if the destination isn't er6. This works ;; in the same way as the movmd splitter. (define_split [(set (match_operand:BLK 0 "memory_operand" "") (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY)) (clobber (match_operand:HI 2 "register_operand" "")) (clobber (match_operand:HI 3 "register_operand" "")) (clobber (match_operand:HI 4 "register_operand" ""))] "TARGET_H8300SX && TARGET_NORMAL_MODE && reload_completed && REGNO (operands[2]) != DESTINATION_REG" [(const_int 0)] { rtx dest; h8300_swap_into_er6 (XEXP (operands[0], 0)); dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx); emit_insn (gen_movsd (dest, operands[1], operands[4])); h8300_swap_out_of_er6 (operands[2]); DONE; }) (define_split [(set (match_operand:BLK 0 "memory_operand" "") (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY)) (clobber (match_operand:SI 2 "register_operand" "")) (clobber (match_operand:SI 3 "register_operand" "")) (clobber (match_operand:SI 4 "register_operand" ""))] "TARGET_H8300SX && !TARGET_NORMAL_MODE && reload_completed && REGNO (operands[2]) != DESTINATION_REG" [(const_int 0)] { rtx dest; h8300_swap_into_er6 (XEXP (operands[0], 0)); dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx); emit_insn (gen_movsd (dest, operands[1], operands[4])); h8300_swap_out_of_er6 (operands[2]); DONE; }) (include "mova.md") (define_expand "movsf" [(set (match_operand:SF 0 "general_operand_dst" "") (match_operand:SF 1 "general_operand_src" ""))] "" { if (TARGET_H8300) { if (h8300_expand_movsi (operands)) DONE; } else if (!TARGET_H8300SX) { /* 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 "*movsf_h8300" [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r") (match_operand:SF 1 "general_operand_src" "G,r,io,r,r,>"))] "TARGET_H8300 && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" { /* Copy of the movsi stuff. */ unsigned 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: gcc_unreachable (); } } [(set (attr "length") (symbol_ref "compute_mov_length (operands)"))]) (define_insn "*movsf_h8300hs" [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r") (match_operand:SF 1 "general_operand_src" "G,r,im,r,r,>"))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX && (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") (symbol_ref "compute_mov_length (operands)")) (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")]) ;; ---------------------------------------------------------------------- ;; PUSH INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "*pushqi1_h8300" [(set (mem:QI (pre_modify:HI (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))) (match_operand:QI 0 "register_no_sp_elim_operand" "r"))] "TARGET_H8300" "mov.w\\t%T0,@-r7" [(set_attr "length" "2")]) (define_insn "*pushqi1_h8300hs_" [(set (mem:QI (pre_modify:P (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -4)))) (match_operand:QI 0 "register_no_sp_elim_operand" "r"))] "TARGET_H8300H || TARGET_H8300S" "mov.l\\t%S0,@-er7" [(set_attr "length" "4")]) (define_insn "*pushhi1_h8300hs_" [(set (mem:HI (pre_modify:P (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -4)))) (match_operand:HI 0 "register_no_sp_elim_operand" "r"))] "TARGET_H8300H || TARGET_H8300S" "mov.l\\t%S0,@-er7" [(set_attr "length" "4")]) ;; ---------------------------------------------------------------------- ;; TEST INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "" [(set (cc0) (compare (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "r,U") (const_int 1) (match_operand 1 "const_int_operand" "n,n")) (const_int 0)))] "TARGET_H8300" "btst %Z1,%Y0" [(set_attr "length" "2,4") (set_attr "cc" "set_zn,set_zn")]) (define_insn "" [(set (cc0) (compare (zero_extract:HI (match_operand:HI 0 "register_operand" "r") (const_int 1) (match_operand 1 "const_int_operand" "n")) (const_int 0)))] "TARGET_H8300" "btst %Z1,%Y0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn_and_split "*tst_extzv_1_n" [(set (cc0) (compare (zero_extract:SI (match_operand:QI 0 "general_operand_src" "r,U,mn>") (const_int 1) (match_operand 1 "const_int_operand" "n,n,n")) (const_int 0))) (clobber (match_scratch:QI 2 "=X,X,&r"))] "TARGET_H8300H || TARGET_H8300S" "@ btst\\t%Z1,%Y0 btst\\t%Z1,%Y0 #" "&& reload_completed && !satisfies_constraint_U (operands[0])" [(set (match_dup 2) (match_dup 0)) (parallel [(set (cc0) (compare (zero_extract:SI (match_dup 2) (const_int 1) (match_dup 1)) (const_int 0))) (clobber (scratch:QI))])] "" [(set_attr "length" "2,8,10") (set_attr "cc" "set_zn,set_zn,set_zn")]) (define_insn "" [(set (cc0) (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "r") (const_int 1) (match_operand 1 "const_int_operand" "n")) (const_int 0)))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) <= 15" "btst %Z1,%Y0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn_and_split "*tstsi_upper_bit" [(set (cc0) (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "r") (const_int 1) (match_operand 1 "const_int_operand" "n")) (const_int 0))) (clobber (match_scratch:SI 2 "=&r"))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) >= 16" "#" "&& reload_completed" [(set (match_dup 2) (ior:SI (and:SI (match_dup 2) (const_int -65536)) (lshiftrt:SI (match_dup 0) (const_int 16)))) (set (cc0) (compare (zero_extract:SI (match_dup 2) (const_int 1) (match_dup 3)) (const_int 0)))] { operands[3] = GEN_INT (INTVAL (operands[1]) - 16); }) (define_insn "*tstsi_variable_bit" [(set (cc0) (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "r") (const_int 1) (and:SI (match_operand:SI 1 "register_operand" "r") (const_int 7))) (const_int 0)))] "TARGET_H8300H || TARGET_H8300S" "btst %w1,%w0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn_and_split "*tstsi_variable_bit_qi" [(set (cc0) (compare (zero_extract:SI (zero_extend:SI (match_operand:QI 0 "general_operand_src" "r,U,mn>")) (const_int 1) (and:SI (match_operand:SI 1 "register_operand" "r,r,r") (const_int 7))) (const_int 0))) (clobber (match_scratch:QI 2 "=X,X,&r"))] "TARGET_H8300H || TARGET_H8300S" "@ btst\\t%w1,%X0 btst\\t%w1,%X0 #" "&& reload_completed && !satisfies_constraint_U (operands[0])" [(set (match_dup 2) (match_dup 0)) (parallel [(set (cc0) (compare (zero_extract:SI (zero_extend:SI (match_dup 2)) (const_int 1) (and:SI (match_dup 1) (const_int 7))) (const_int 0))) (clobber (scratch:QI))])] "" [(set_attr "length" "2,8,10") (set_attr "cc" "set_zn,set_zn,set_zn")]) (define_insn "*tstqi" [(set (cc0) (compare (match_operand:QI 0 "register_operand" "r") (const_int 0)))] "" "mov.b %X0,%X0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "*tsthi" [(set (cc0) (compare (match_operand:HI 0 "register_operand" "r") (const_int 0)))] "" "mov.w %T0,%T0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "*tsthi_upper" [(set (cc0) (compare (and:HI (match_operand:HI 0 "register_operand" "r") (const_int -256)) (const_int 0)))] "" "mov.b %t0,%t0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "*tstsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "r") (const_int 0)))] "TARGET_H8300H || TARGET_H8300S" "mov.l %S0,%S0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "*tstsi_upper" [(set (cc0) (compare (and:SI (match_operand:SI 0 "register_operand" "r") (const_int -65536)) (const_int 0)))] "" "mov.w %e0,%e0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (define_insn "*cmpqi" [(set (cc0) (compare (match_operand:QI 0 "h8300_dst_operand" "rQ") (match_operand:QI 1 "h8300_src_operand" "rQi")))] "" "cmp.b %X1,%X0" [(set_attr "length_table" "addb") (set_attr "cc" "compare")]) (define_insn "*cmphi_h8300_znvc" [(set (cc0) (compare (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 "*cmphi_h8300hs_znvc" [(set (cc0) (compare (match_operand:HI 0 "h8300_dst_operand" "rU,rQ") (match_operand:HI 1 "h8300_src_operand" "P3>X,rQi")))] "TARGET_H8300H || TARGET_H8300S" { switch (which_alternative) { case 0: if (!TARGET_H8300SX) return "cmp.w %T1,%T0"; else return "cmp.w %T1:3,%T0"; case 1: return "cmp.w %T1,%T0"; default: gcc_unreachable (); } } [(set_attr "length_table" "short_immediate,addw") (set_attr "cc" "compare,compare")]) (define_insn "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "h8300_dst_operand" "r,rQ") (match_operand:SI 1 "h8300_src_operand" "P3>X,rQi")))] "TARGET_H8300H || TARGET_H8300S" { switch (which_alternative) { case 0: if (!TARGET_H8300SX) return "cmp.l %S1,%S0"; else return "cmp.l %S1:3,%S0"; case 1: return "cmp.l %S1,%S0"; default: gcc_unreachable (); } } [(set_attr "length" "2,*") (set_attr "length_table" "*,addl") (set_attr "cc" "compare,compare")]) ;; ---------------------------------------------------------------------- ;; ADD INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_expand "addqi3" [(set (match_operand:QI 0 "register_operand" "") (plus:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "h8300_src_operand" "")))] "" "") (define_insn "*addqi3" [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ") (plus:QI (match_operand:QI 1 "h8300_dst_operand" "%0") (match_operand:QI 2 "h8300_src_operand" "rQi")))] "h8300_operands_match_p (operands)" "add.b %X2,%X0" [(set_attr "length_table" "addb") (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 "h8300_src_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 "h8300_src_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 && epilogue_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 "h8300_src_operand" "L,N,J,n,r")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX" "@ 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_insn "*addhi3_incdec" [(set (match_operand:HI 0 "register_operand" "=r,r") (unspec:HI [(match_operand:HI 1 "register_operand" "0,0") (match_operand:HI 2 "incdec_operand" "M,O")] UNSPEC_INCDEC))] "TARGET_H8300H || TARGET_H8300S" "@ inc.w %2,%T0 dec.w %G2,%T0" [(set_attr "length" "2,2") (set_attr "cc" "set_zn,set_zn")]) (define_insn "*addhi3_h8sx" [(set (match_operand:HI 0 "h8300_dst_operand" "=rU,rU,r,rQ") (plus:HI (match_operand:HI 1 "h8300_dst_operand" "%0,0,0,0") (match_operand:HI 2 "h8300_src_operand" "P3>X,P3X")))] "TARGET_H8300SX" "mulxs.b %X2,%T0" [(set_attr "length" "4") (set_attr "cc" "set_zn")]) (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_expand "mulhisi3" [(set (match_operand:SI 0 "register_operand" "") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "")) ;; intentionally-mismatched modes (match_operand:HI 2 "reg_or_nibble_operand" "")))] "TARGET_H8300H || TARGET_H8300S" { if (GET_MODE (operands[2]) != VOIDmode) operands[2] = gen_rtx_SIGN_EXTEND (SImode, operands[2]); }) (define_insn "*mulhisi3_const" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) (match_operand:SI 2 "nibble_operand" "IP4>X")))] "TARGET_H8300SX" "mulxs.w %T2,%S0" [(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_expand "umulqihi3" [(set (match_operand:HI 0 "register_operand" "") (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "")) ;; intentionally-mismatched modes (match_operand:QI 2 "reg_or_nibble_operand" "")))] "TARGET_H8300H || TARGET_H8300S" { if (GET_MODE (operands[2]) != VOIDmode) operands[2] = gen_rtx_ZERO_EXTEND (HImode, operands[2]); }) (define_insn "*umulqihi3_const" [(set (match_operand:HI 0 "register_operand" "=r") (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0")) (match_operand:QI 2 "nibble_operand" "IP4>X")))] "TARGET_H8300SX" "mulxu.b %X2,%T0" [(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.b %X2,%T0" [(set_attr "length" "2") (set_attr "cc" "none_0hit")]) (define_expand "umulhisi3" [(set (match_operand:SI 0 "register_operand" "") (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "")) ;; intentionally-mismatched modes (match_operand:HI 2 "reg_or_nibble_operand" "")))] "TARGET_H8300H || TARGET_H8300S" { if (GET_MODE (operands[2]) != VOIDmode) operands[2] = gen_rtx_ZERO_EXTEND (SImode, operands[2]); }) (define_insn "*umulhisi3_const" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) (match_operand:SI 2 "nibble_operand" "IP4>X")))] "TARGET_H8300SX" "mulxu.w %T2,%S0" [(set_attr "length" "4") (set_attr "cc" "set_zn")]) (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")]) ;; We could have used mulu.[wl] here, but mulu.[lw] is only available ;; on a H8SX with a multiplier, whereas muls.w seems to be available ;; on all H8SX variants. (define_insn "mulhi3" [(set (match_operand:HI 0 "register_operand" "=r") (mult:HI (match_operand:HI 1 "register_operand" "%0") (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "muls.w\\t%T2,%T0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "muls.l\\t%S2,%S0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "smulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) (sign_extend:DI (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X"))) (const_int 32))))] "TARGET_H8300SXMUL" "muls/u.l\\t%S2,%S0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]) (define_insn "umulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=r") (truncate:SI (ashiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) (zero_extend:DI (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X"))) (const_int 32))))] "TARGET_H8300SX" "mulu/u.l\\t%S2,%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 "udivhi3" [(set (match_operand:HI 0 "register_operand" "=r") (udiv:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "divu.w\\t%T2,%T0" [(set_attr "length" "2")]) (define_insn "divhi3" [(set (match_operand:HI 0 "register_operand" "=r") (div:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "divs.w\\t%T2,%T0" [(set_attr "length" "2")]) (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=r") (udiv:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "divu.l\\t%S2,%S0" [(set_attr "length" "2")]) (define_insn "divsi3" [(set (match_operand:SI 0 "register_operand" "=r") (div:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))] "TARGET_H8300SX" "divs.l\\t%S2,%S0" [(set_attr "length" "2")]) (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")]) (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")]) (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")]) (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")]) ;; ---------------------------------------------------------------------- ;; AND INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "bclrqi_msx" [(set (match_operand:QI 0 "bit_register_indirect_operand" "=WU") (and:QI (match_operand:QI 1 "bit_register_indirect_operand" "%0") (match_operand:QI 2 "single_zero_operand" "Y0")))] "TARGET_H8300SX && rtx_equal_p (operands[0], operands[1])" "bclr\\t%W2,%0" [(set_attr "length" "8")]) (define_split [(set (match_operand:HI 0 "bit_register_indirect_operand" "=U") (and:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_zero_operand" "Y0")))] "TARGET_H8300SX" [(set (match_dup 0) (and:QI (match_dup 1) (match_dup 2)))] { if (abs (INTVAL (operands[2])) > 0xFF) { operands[0] = adjust_address (operands[0], QImode, 0); operands[1] = adjust_address (operands[1], QImode, 0); operands[2] = GEN_INT ((INTVAL (operands[2])) >> 8); } else { operands[0] = adjust_address (operands[0], QImode, 1); operands[1] = adjust_address (operands[1], QImode, 1); } }) (define_insn "bclrhi_msx" [(set (match_operand:HI 0 "bit_register_indirect_operand" "=m") (and:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_zero_operand" "Y0")))] "TARGET_H8300SX" "bclr\\t%W2,%0" [(set_attr "length" "8")]) (define_insn "*andqi3_2" [(set (match_operand:QI 0 "bit_operand" "=U,rQ,r") (and:QI (match_operand:QI 1 "bit_operand" "%0,0,WU") (match_operand:QI 2 "h8300_src_operand" "Y0,rQi,IP1>X")))] "TARGET_H8300SX" "@ bclr\\t %W2,%R0 and %X2,%X0 bfld %2,%1,%R0" [(set_attr "length" "8,*,8") (set_attr "length_table" "*,logicb,*") (set_attr "cc" "none_0hit,set_znv,none_0hit")]) (define_insn "andqi3_1" [(set (match_operand:QI 0 "bit_operand" "=U,r") (and:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "h8300_src_operand" "Y0,rn")))] "register_operand (operands[0], QImode) || single_zero_operand (operands[2], QImode)" "@ bclr %W2,%R0 and %X2,%X0" [(set_attr "length" "2,8") (set_attr "cc" "none_0hit,set_znv")]) (define_expand "andqi3" [(set (match_operand:QI 0 "register_operand" "") (and:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "h8300_src_operand" "")))] "" "") (define_expand "andhi3" [(set (match_operand:HI 0 "register_operand" "") (and:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "h8300_src_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")]) (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")]) (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")]) (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")]) (define_expand "andsi3" [(set (match_operand:SI 0 "register_operand" "") (and:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "h8300_src_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; OR INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "bsetqi_msx" [(set (match_operand:QI 0 "bit_register_indirect_operand" "=WU") (ior:QI (match_operand:QI 1 "bit_register_indirect_operand" "%0") (match_operand:QI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX && rtx_equal_p (operands[0], operands[1])" "bset\\t%V2,%0" [(set_attr "length" "8")]) (define_split [(set (match_operand:HI 0 "bit_register_indirect_operand" "=U") (ior:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX" [(set (match_dup 0) (ior:QI (match_dup 1) (match_dup 2)))] { if (abs (INTVAL (operands[2])) > 0xFF) { operands[0] = adjust_address (operands[0], QImode, 0); operands[1] = adjust_address (operands[1], QImode, 0); operands[2] = GEN_INT ((INTVAL (operands[2])) >> 8); } else { operands[0] = adjust_address (operands[0], QImode, 1); operands[1] = adjust_address (operands[1], QImode, 1); } }) (define_insn "bsethi_msx" [(set (match_operand:HI 0 "bit_register_indirect_operand" "=m") (ior:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX" "bset\\t%V2,%0" [(set_attr "length" "8")]) (define_insn "iorqi3_1" [(set (match_operand:QI 0 "bit_operand" "=U,rQ") (ior:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "h8300_src_operand" "Y2,rQi")))] "TARGET_H8300SX || register_operand (operands[0], QImode) || single_one_operand (operands[2], QImode)" "@ bset\\t%V2,%R0 or\\t%X2,%X0" [(set_attr "length" "8,*") (set_attr "length_table" "*,logicb") (set_attr "cc" "none_0hit,set_znv")]) (define_expand "iorqi3" [(set (match_operand:QI 0 "register_operand" "") (ior:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "h8300_src_operand" "")))] "" "") (define_expand "iorhi3" [(set (match_operand:HI 0 "register_operand" "") (ior:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "h8300_src_operand" "")))] "" "") (define_expand "iorsi3" [(set (match_operand:SI 0 "register_operand" "") (ior:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "h8300_src_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; XOR INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "bnotqi_msx" [(set (match_operand:QI 0 "bit_register_indirect_operand" "=WU") (xor:QI (match_operand:QI 1 "bit_register_indirect_operand" "%0") (match_operand:QI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX && rtx_equal_p (operands[0], operands[1])" "bnot\\t%V2,%0" [(set_attr "length" "8")]) (define_split [(set (match_operand:HI 0 "bit_register_indirect_operand" "=U") (xor:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX" [(set (match_dup 0) (xor:QI (match_dup 1) (match_dup 2)))] { if (abs (INTVAL (operands[2])) > 0xFF) { operands[0] = adjust_address (operands[0], QImode, 0); operands[1] = adjust_address (operands[1], QImode, 0); operands[2] = GEN_INT ((INTVAL (operands[2])) >> 8); } else { operands[0] = adjust_address (operands[0], QImode, 1); operands[1] = adjust_address (operands[1], QImode, 1); } }) (define_insn "bnothi_msx" [(set (match_operand:HI 0 "bit_register_indirect_operand" "=m") (xor:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") (match_operand:HI 2 "single_one_operand" "Y2")))] "TARGET_H8300SX" "bnot\\t%V2,%0" [(set_attr "length" "8")]) (define_insn "xorqi3_1" [(set (match_operand:QI 0 "bit_operand" "=U,r") (xor:QI (match_operand:QI 1 "bit_operand" "%0,0") (match_operand:QI 2 "h8300_src_operand" "Y2,rQi")))] "TARGET_H8300SX || register_operand (operands[0], QImode) || single_one_operand (operands[2], QImode)" "@ bnot\\t%V2,%R0 xor\\t%X2,%X0" [(set_attr "length" "8,*") (set_attr "length_table" "*,logicb") (set_attr "cc" "none_0hit,set_znv")]) (define_expand "xorqi3" [(set (match_operand:QI 0 "register_operand" "") (xor:QI (match_operand:QI 1 "register_operand" "") (match_operand:QI 2 "h8300_src_operand" "")))] "" "") (define_expand "xorhi3" [(set (match_operand:HI 0 "register_operand" "") (xor:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "h8300_src_operand" "")))] "" "") (define_expand "xorsi3" [(set (match_operand:SI 0 "register_operand" "") (xor:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "h8300_src_operand" "")))] "" "") ;; ---------------------------------------------------------------------- ;; {AND,IOR,XOR}{HI3,SI3} PATTERNS ;; ---------------------------------------------------------------------- ;; We need a separate pattern here because machines other than the ;; original H8300 don't have to split the 16-bit operand into a pair ;; of high/low instructions, so we can accept literal addresses, that ;; have to be loaded into a register on H8300. (define_insn "*logicalhi3_sn" [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ") (match_operator:HI 3 "bit_operator" [(match_operand:HI 1 "h8300_dst_operand" "%0") (match_operand:HI 2 "h8300_src_operand" "rQi")]))] "(TARGET_H8300S || TARGET_H8300H) && h8300_operands_match_p (operands)" { 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 "*logicalsi3_sn" [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ") (match_operator:SI 3 "bit_operator" [(match_operand:SI 1 "h8300_dst_operand" "%0") (match_operand:SI 2 "h8300_src_operand" "rQi")]))] "(TARGET_H8300S || TARGET_H8300H) && h8300_operands_match_p (operands)" { 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)"))]) (define_insn "*logicalhi3" [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ") (match_operator:HI 3 "bit_operator" [(match_operand:HI 1 "h8300_dst_operand" "%0") (match_operand:HI 2 "h8300_src_operand" "rQi")]))] "h8300_operands_match_p (operands)" { 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 "*logicalsi3" [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ") (match_operator:SI 3 "bit_operator" [(match_operand:SI 1 "h8300_dst_operand" "%0") (match_operand:SI 2 "h8300_src_operand" "rQi")]))] "h8300_operands_match_p (operands)" { 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_expand "negqi2" [(set (match_operand:QI 0 "register_operand" "") (neg:QI (match_operand:QI 1 "register_operand" "")))] "" "") (define_insn "*negqi2" [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ") (neg:QI (match_operand:QI 1 "h8300_dst_operand" "0")))] "" "neg %X0" [(set_attr "length_table" "unary") (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_h8300hs" [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ") (neg:HI (match_operand:HI 1 "h8300_dst_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)" "neg.w %T0" [(set_attr "length_table" "unary") (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_h8300hs" [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ") (neg:SI (match_operand:SI 1 "h8300_dst_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)" "neg.l %S0" [(set_attr "length_table" "unary") (set_attr "cc" "set_zn")]) (define_expand "negsf2" [(set (match_operand:SF 0 "register_operand" "") (neg:SF (match_operand:SF 1 "register_operand" "")))] "" "") (define_insn "*negsf2_h8300" [(set (match_operand:SF 0 "register_operand" "=r") (neg:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_H8300" "xor.b\\t#128,%z0" [(set_attr "length" "2")]) (define_insn "*negsf2_h8300hs" [(set (match_operand:SF 0 "register_operand" "=r") (neg:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "xor.w\\t#32768,%e0" [(set_attr "length" "4")]) ;; ---------------------------------------------------------------------- ;; ABSOLUTE VALUE INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_expand "abssf2" [(set (match_operand:SF 0 "register_operand" "") (abs:SF (match_operand:SF 1 "register_operand" "")))] "" "") (define_insn "*abssf2_h8300" [(set (match_operand:SF 0 "register_operand" "=r") (abs:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_H8300" "and.b\\t#127,%z0" [(set_attr "length" "2")]) (define_insn "*abssf2_h8300hs" [(set (match_operand:SF 0 "register_operand" "=r") (abs:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "and.w\\t#32767,%e0" [(set_attr "length" "4")]) ;; ---------------------------------------------------------------------- ;; NOT INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_expand "one_cmplqi2" [(set (match_operand:QI 0 "register_operand" "") (not:QI (match_operand:QI 1 "register_operand" "")))] "" "") (define_insn "*one_cmplqi2" [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ") (not:QI (match_operand:QI 1 "h8300_dst_operand" "0")))] "" "not %X0" [(set_attr "length_table" "unary") (set_attr "cc" "set_znv")]) (define_expand "one_cmplhi2" [(set (match_operand:HI 0 "register_operand" "") (not:HI (match_operand:HI 1 "register_operand" "")))] "" "") (define_insn "*one_cmplhi2_h8300" [(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 "length" "4")]) (define_insn "*one_cmplhi2_h8300hs" [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ") (not:HI (match_operand:HI 1 "h8300_dst_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)" "not.w %T0" [(set_attr "cc" "set_znv") (set_attr "length_table" "unary")]) (define_expand "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "") (not:SI (match_operand:SI 1 "register_operand" "")))] "" "") (define_insn "*one_cmplsi2_h8300" [(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 "length" "8")]) (define_insn "*one_cmplsi2_h8300hs" [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ") (not:SI (match_operand:SI 1 "h8300_dst_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)" "not.l %S0" [(set_attr "cc" "set_znv") (set_attr "length_table" "unary")]) ;; ---------------------------------------------------------------------- ;; JUMP INSTRUCTIONS ;; ---------------------------------------------------------------------- ;; Conditional jump instructions (define_expand "cbranchqi4" [(use (match_operator 0 "ordered_comparison_operator" [(match_operand:QI 1 "h8300_dst_operand" "") (match_operand:QI 2 "h8300_src_operand" "")])) (use (match_operand 3 ""))] "" { h8300_expand_branch (operands); DONE; }) (define_expand "cbranchhi4" [(use (match_operator 0 "ordered_comparison_operator" [(match_operand:HI 1 "h8300_dst_operand" "") (match_operand:HI 2 "h8300_src_operand" "")])) (use (match_operand 3 ""))] "" { /* Force operand1 into a register if we're compiling for the H8/300. */ if ((GET_CODE (operands[2]) != REG && operands[2] != const0_rtx) && TARGET_H8300) operands[2] = force_reg (HImode, operands[2]); h8300_expand_branch (operands); DONE; }) (define_expand "cbranchsi4" [(use (match_operator 0 "ordered_comparison_operator" [(match_operand:SI 1 "h8300_dst_operand" "") (match_operand:SI 2 "h8300_src_operand" "")])) (use (match_operand 3 ""))] "TARGET_H8300H || TARGET_H8300S" { h8300_expand_branch (operands); DONE; }) (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")]) (define_insn "*brabc" [(set (pc) (if_then_else (eq (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU") (const_int 1) (match_operand:QI 2 "immediate_operand" "n")) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "TARGET_H8300SX" { switch (get_attr_length (insn) - h8300_insn_length_from_table (insn, operands)) { case 2: return "bra/bc %2,%R1,%l0"; case 4: return "bra/bc %2,%R1,%l0:16"; default: return "bra/bs %2,%R1,.Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:"; } } [(set_attr "type" "bitbranch") (set_attr "length_table" "bitbranch") (set_attr "cc" "none")]) (define_insn "*brabs" [(set (pc) (if_then_else (ne (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU") (const_int 1) (match_operand:QI 2 "immediate_operand" "n")) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "TARGET_H8300SX" { switch (get_attr_length (insn) - h8300_insn_length_from_table (insn, operands)) { case 2: return "bra/bs %2,%R1,%l0"; case 4: return "bra/bs %2,%R1,%l0:16"; default: return "bra/bc %2,%R1,.Lh8BR%=\;jmp @%l0\\n.Lh8BR%=:"; } } [(set_attr "type" "bitbranch") (set_attr "length_table" "bitbranch") (set_attr "cc" "none")]) ;; Unconditional and other jump instructions. (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" { if (final_sequence != 0) { if (get_attr_length (insn) == 2) return "bra/s %l0"; else { /* The branch isn't short enough to use bra/s. Output the branch and delay slot in their normal order. If this is a backward branch, it will now be branching two bytes further than previously thought. The length-based test for bra vs. jump is very conservative though, so the branch will still be within range. */ rtvec vec; int seen; vec = XVEC (final_sequence, 0); final_sequence = 0; final_scan_insn (RTVEC_ELT (vec, 1), asm_out_file, optimize, 1, & seen); final_scan_insn (RTVEC_ELT (vec, 0), asm_out_file, optimize, 1, & seen); INSN_DELETED_P (RTVEC_ELT (vec, 1)) = 1; return ""; } } else 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 "delay_slot") (if_then_else (match_test "TARGET_H8300SX") (const_string "jump") (const_string "none"))) (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_h8300hs_advanced" [(set (pc) (match_operand:SI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_NORMAL_MODE" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "*tablejump_h8300hs_normal" [(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_h8300hs_advanced" [(set (pc) (match_operand:SI 0 "jump_address_operand" "Vr"))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_NORMAL_MODE" "jmp @%0" [(set_attr "cc" "none") (set_attr "length" "2")]) (define_insn "*indirect_jump_h8300hs_normal" [(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 "type" "call") (set (attr "length") (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") (const_int 2) (const_int 4)))]) ;; 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 "type" "call") (set (attr "length") (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") (const_int 2) (const_int 4)))]) (define_insn "nop" [(const_int 0)] "" "nop" [(set_attr "cc" "none") (set_attr "length" "2")]) ;; ---------------------------------------------------------------------- ;; PROLOGUE/EPILOGUE-RELATED INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_expand "push_h8300" [(set (mem:HI (pre_dec:HI (reg:HI SP_REG))) (match_operand:HI 0 "register_operand" ""))] "TARGET_H8300" "") (define_expand "push_h8300hs_advanced" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_operand:SI 0 "register_operand" ""))] "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE" "") (define_expand "push_h8300hs_normal" [(set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 0 "register_operand" ""))] "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE" "") (define_expand "pop_h8300" [(set (match_operand:HI 0 "register_operand" "") (mem:HI (post_inc:HI (reg:HI SP_REG))))] "TARGET_H8300" "") (define_expand "pop_h8300hs_advanced" [(set (match_operand:SI 0 "register_operand" "") (mem:SI (post_inc:SI (reg:SI SP_REG))))] "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE" "") (define_expand "pop_h8300hs_normal" [(set (match_operand:SI 0 "register_operand" "") (mem:SI (post_inc:HI (reg:HI SP_REG))))] "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE" "") (define_insn "ldm_h8300sx" [(match_parallel 0 "h8300_ldm_parallel" [(set (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "memory_operand" ""))])] "TARGET_H8300S" { operands[3] = SET_DEST (XVECEXP (operands[0], 0, XVECLEN (operands[0], 0) - 2)); return "ldm.l\t@er7+,%S1-%S3"; } [(set_attr "cc" "none") (set_attr "length" "4")]) (define_insn "stm_h8300sx" [(match_parallel 0 "h8300_stm_parallel" [(set (match_operand:SI 1 "memory_operand" "") (match_operand:SI 2 "register_operand" ""))])] "TARGET_H8300S" { operands[3] = SET_SRC (XVECEXP (operands[0], 0, XVECLEN (operands[0], 0) - 2)); return "stm.l\t%S2-%S3,@-er7"; } [(set_attr "cc" "none") (set_attr "length" "4")]) (define_insn "return_h8sx" [(match_parallel 0 "h8300_return_parallel" [(return) (set (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "memory_operand" ""))])] "TARGET_H8300SX" { operands[3] = SET_DEST (XVECEXP (operands[0], 0, XVECLEN (operands[0], 0) - 2)); if (h8300_current_function_interrupt_function_p () || h8300_current_function_monitor_function_p ()) return "rte/l\t%S1-%S3"; else return "rts/l\t%S1-%S3"; } [(set_attr "cc" "none") (set_attr "can_delay" "no") (set_attr "length" "2")]) (define_expand "return" [(return)] "h8300_can_use_return_insn_p ()" "") (define_insn "*return_1" [(return)] "reload_completed" { if (h8300_current_function_interrupt_function_p () || h8300_current_function_monitor_function_p ()) return "rte"; else return "rts"; } [(set_attr "cc" "none") (set_attr "can_delay" "no") (set_attr "length" "2")]) (define_expand "prologue" [(const_int 0)] "" { h8300_expand_prologue (); DONE; }) (define_expand "epilogue" [(return)] "" { h8300_expand_epilogue (); DONE; }) (define_insn "monitor_prologue" [(unspec_volatile [(const_int 0)] UNSPEC_MONITOR)] "" { if (TARGET_H8300) return "subs\\t#2,r7\;mov.w\\tr0,@-r7\;stc\\tccr,r0l\;mov.b\tr0l,@(2,r7)\;mov.w\\t@r7+,r0\;orc\t#128,ccr"; else if (TARGET_H8300H && TARGET_NORMAL_MODE) return "subs\\t#2,er7\;mov.l\\ter0,@-er7\;stc\\tccr,r0l\;mov.b\\tr0l,@(4,er7)\;mov.l\\t@er7+,er0\;orc\\t#128,ccr"; else if (TARGET_H8300H) return "mov.l\\ter0,@-er7\;stc\\tccr,r0l\;mov.b\\tr0l,@(4,er7)\;mov.l\\t@er7+,er0\;orc\\t#128,ccr"; else if (TARGET_H8300S && TARGET_NEXR ) return "mov.l\\ter0,@-er7\;stc\tccr,r0l\;mov.b\tr0l,@(4,er7)\;mov.l\\t@er7+,er0\;orc\t#128,ccr"; else if (TARGET_H8300S && TARGET_NEXR && TARGET_NORMAL_MODE) return "subs\\t#2,er7\;mov.l\\ter0,@-er7\;stc\tccr,r0l\;mov.b\tr0l,@(4,er7)\;mov.l\\t@er7+,er0\;orc\t#128,ccr"; else if (TARGET_H8300S && TARGET_NORMAL_MODE) return "subs\\t#2,er7\;stc\texr,@-er7\;mov.l\\ter0,@-er7\;stc\tccr,r0l\;mov.b\tr0l,@(6,er7)\;mov.l\\t@er7+,er0\;orc\t#128,ccr"; else if (TARGET_H8300S) return "stc\texr,@-er7\;mov.l\\ter0,@-er7\;stc\tccr,r0l\;mov.b\tr0l,@(6,er7)\;mov.l\\t@er7+,er0\;orc\t#128,ccr"; gcc_unreachable (); } [(set_attr "length" "20")]) ;; ---------------------------------------------------------------------- ;; 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 "*zero_extendqihi2_h8300" [(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 #" [(set_attr "length" "2,10")]) (define_insn "*zero_extendqihi2_h8300hs" [(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 #" [(set_attr "length" "2,10") (set_attr "cc" "set_znv,set_znv")]) ;; Split the zero extension of a general operand (actually a memory ;; operand) into a load of the operand and the actual zero extension ;; so that 1) the length will be accurate, and 2) the zero extensions ;; appearing at the end of basic blocks may be merged. (define_split [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "general_operand_src" "")))] "reload_completed" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (zero_extend:HI (match_dup 2)))] { operands[2] = gen_rtx_REG (QImode, REGNO (operands[0])); }) (define_expand "zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))] "" { if (TARGET_H8300SX) operands[1] = force_reg (QImode, operands[1]); }) (define_insn "*zero_extendqisi2_h8300" [(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")]) (define_insn "*zero_extendqisi2_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX" "#") (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX && reg_overlap_mentioned_p (operands[0], operands[1]) && reload_completed" [(set (match_dup 2) (match_dup 1)) (set (match_dup 3) (zero_extend:HI (match_dup 2))) (set (match_dup 0) (zero_extend:SI (match_dup 3)))] { operands[2] = gen_lowpart (QImode, operands[0]); operands[3] = gen_lowpart (HImode, operands[0]); }) (define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX && !reg_overlap_mentioned_p (operands[0], operands[1]) && reload_completed" [(set (match_dup 0) (const_int 0)) (set (strict_low_part (match_dup 2)) (match_dup 1))] { operands[2] = gen_rtx_REG (QImode, REGNO (operands[0])); }) (define_insn "*zero_extendqisi2_h8sx" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))] "TARGET_H8300SX" "extu.l\t#2,%0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (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")]) (define_insn "*zero_extendhisi2_h8300hs" [(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 "*extendqihi2_h8300" [(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")]) (define_insn "*extendqihi2_h8300hs" [(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")]) (define_expand "extendqisi2" [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] "" "") (define_insn "*extendqisi2_h8300" [(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")]) ;; The following pattern is needed because without the pattern, the ;; combiner would split (sign_extend:SI (reg:QI)) into two 24-bit ;; shifts, one ashift and one ashiftrt. (define_insn_and_split "*extendqisi2_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX" "#" "&& reload_completed" [(set (match_dup 2) (sign_extend:HI (match_dup 1))) (set (match_dup 0) (sign_extend:SI (match_dup 2)))] { operands[2] = gen_rtx_REG (HImode, REGNO (operands[0])); }) (define_insn "*extendqisi2_h8sx" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))] "TARGET_H8300SX" "exts.l\t#2,%0" [(set_attr "length" "2") (set_attr "cc" "set_znv")]) (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")]) (define_insn "*extendhisi2_h8300hs" [(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; }) (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; }) (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; }) (define_insn "" [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ") (match_operator:QI 3 "h8sx_unary_shift_operator" [(match_operand:QI 1 "h8300_dst_operand" "0") (match_operand:QI 2 "const_int_operand" "")]))] "h8300_operands_match_p (operands)" { return output_h8sx_shift (operands, 'b', 'X'); } [(set_attr "length_table" "unary") (set_attr "cc" "set_znv")]) (define_insn "" [(set (match_operand:QI 0 "register_operand" "=r") (match_operator:QI 3 "h8sx_binary_shift_operator" [(match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "r P3>X")]))] "" { return output_h8sx_shift (operands, 'b', 'X'); } [(set_attr "length" "4") (set_attr "cc" "set_znv")]) (define_insn "*shiftqi" [(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") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) ;; HI BIT SHIFTS (define_expand "ashlhi3" [(set (match_operand:HI 0 "register_operand" "") (ashift:HI (match_operand:HI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (expand_a_shift (HImode, ASHIFT, operands)) DONE; }) (define_expand "lshrhi3" [(set (match_operand:HI 0 "register_operand" "") (lshiftrt:HI (match_operand:HI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE; }) (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; }) (define_insn "" [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ") (match_operator:HI 3 "h8sx_unary_shift_operator" [(match_operand:HI 1 "h8300_dst_operand" "0") (match_operand:QI 2 "const_int_operand" "")]))] "h8300_operands_match_p (operands)" { return output_h8sx_shift (operands, 'w', 'T'); } [(set_attr "length_table" "unary") (set_attr "cc" "set_znv")]) (define_insn "" [(set (match_operand:HI 0 "register_operand" "=r") (match_operator:HI 3 "h8sx_binary_shift_operator" [(match_operand:HI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "r P4>X")]))] "" { return output_h8sx_shift (operands, 'w', 'T'); } [(set_attr "length" "4") (set_attr "cc" "set_znv")]) (define_insn "*shifthi" [(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") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) ;; SI BIT SHIFTS (define_expand "ashlsi3" [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_operand:SI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (expand_a_shift (SImode, ASHIFT, operands)) DONE; }) (define_expand "lshrsi3" [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_operand:SI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (expand_a_shift (SImode, LSHIFTRT, operands)) DONE; }) (define_expand "ashrsi3" [(set (match_operand:SI 0 "register_operand" "") (ashiftrt:SI (match_operand:SI 1 "register_operand" "") (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE; }) (define_insn "" [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ") (match_operator:SI 3 "h8sx_unary_shift_operator" [(match_operand:SI 1 "h8300_dst_operand" "0") (match_operand:QI 2 "const_int_operand" "")]))] "h8300_operands_match_p (operands)" { return output_h8sx_shift (operands, 'l', 'S'); } [(set_attr "length_table" "unary") (set_attr "cc" "set_znv")]) (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 3 "h8sx_binary_shift_operator" [(match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "r P5>X")]))] "" { return output_h8sx_shift (operands, 'l', 'S'); } [(set_attr "length" "4") (set_attr "cc" "set_znv")]) (define_insn "*shiftsi" [(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") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) ;; Split a variable shift into a loop. If the register containing ;; the shift count dies, then we just use that register. (define_split [(set (match_operand 0 "register_operand" "") (match_operator 2 "nshift_operator" [(match_dup 0) (match_operand:QI 1 "register_operand" "")])) (clobber (match_operand:QI 3 "register_operand" ""))] "epilogue_completed && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))" [(set (cc0) (compare (match_dup 1) (const_int 0))) (set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_dup 5)) (pc))) (match_dup 4) (parallel [(set (match_dup 0) (match_op_dup 2 [(match_dup 0) (const_int 1)])) (clobber (scratch:QI))]) (set (match_dup 1) (plus:QI (match_dup 1) (const_int -1))) (set (cc0) (compare (match_dup 1) (const_int 0))) (set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_dup 4)) (pc))) (match_dup 5)] { operands[4] = gen_label_rtx (); operands[5] = gen_label_rtx (); }) (define_split [(set (match_operand 0 "register_operand" "") (match_operator 2 "nshift_operator" [(match_dup 0) (match_operand:QI 1 "register_operand" "")])) (clobber (match_operand:QI 3 "register_operand" ""))] "epilogue_completed && !find_regno_note (insn, REG_DEAD, REGNO (operands[1]))" [(set (match_dup 3) (match_dup 1)) (set (cc0) (compare (match_dup 3) (const_int 0))) (set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_dup 5)) (pc))) (match_dup 4) (parallel [(set (match_dup 0) (match_op_dup 2 [(match_dup 0) (const_int 1)])) (clobber (scratch:QI))]) (set (match_dup 3) (plus:QI (match_dup 3) (const_int -1))) (set (cc0) (compare (match_dup 3) (const_int 0))) (set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_dup 4)) (pc))) (match_dup 5)] { operands[4] = gen_label_rtx (); operands[5] = gen_label_rtx (); }) ;; ---------------------------------------------------------------------- ;; 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 (operands)) DONE; }) (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 output_a_rotate (ROTATE, operands); } [(set (attr "length") (symbol_ref "compute_a_rotate_length (operands)"))]) (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 (operands)) DONE; }) (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 output_a_rotate (ROTATE, operands); } [(set (attr "length") (symbol_ref "compute_a_rotate_length (operands)"))]) (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 (operands)) DONE; }) (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 output_a_rotate (ROTATE, operands); } [(set (attr "length") (symbol_ref "compute_a_rotate_length (operands)"))]) ;; ----------------------------------------------------------------- ;; 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 "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 || TARGET_H8300SX) && (1 << INTVAL (operands[2])) == INTVAL (operands[3])" "sub.w %0,%0\;bild %Z2,%Y1\;bst #0,%X0" [(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 "length" "8")]) (define_insn "*extzv_1_r_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extract:SI (match_operand:SI 1 "register_operand" "?0,r") (const_int 1) (match_operand 2 "const_int_operand" "n,n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[2]) < 16" { return output_simode_bld (0, operands); } [(set_attr "cc" "set_znv,set_znv") (set_attr "length" "8,6")]) ;; ;; 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 "length" "8")]) (define_insn "*extzv_1_r_inv_h8300hs" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extract:SI (xor:SI (match_operand:SI 1 "register_operand" "?0,r") (match_operand 3 "const_int_operand" "n,n")) (const_int 1) (match_operand 2 "const_int_operand" "n,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" "set_znv,set_znv") (set_attr "length" "8,6")]) (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 || TARGET_H8300SX" { if (TARGET_H8300SX) { if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[1]) <= 8 && INTVAL (operands[2]) >= 0 && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8 && memory_operand (operands[0], GET_MODE (operands[0]))) { /* If the source operand is zero, it's better to use AND rather than BFST. Likewise OR if the operand is all ones. */ if (GET_CODE (operands[3]) == CONST_INT) { HOST_WIDE_INT mask = (1 << INTVAL (operands[1])) - 1; if ((INTVAL (operands[3]) & mask) == 0) FAIL; if ((INTVAL (operands[3]) & mask) == mask) FAIL; } if (! bit_memory_operand (operands[0], GET_MODE (operands[0]))) { if (!can_create_pseudo_p ()) FAIL; operands[0] = replace_equiv_address (operands[0], force_reg (Pmode, XEXP (operands[0], 0))); } operands[3] = gen_lowpart (QImode, operands[3]); if (! operands[3]) FAIL; if (! register_operand (operands[3], QImode)) { if (!can_create_pseudo_p ()) FAIL; operands[3] = force_reg (QImode, operands[3]); } emit_insn (gen_bfst (adjust_address (operands[0], QImode, 0), operands[3], operands[1], operands[2])); DONE; } FAIL; } /* 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; if (GET_CODE (operands[3]) != REG) operands[3] = force_reg (HImode, operands[3]); }) (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 "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 || TARGET_H8300SX" { if (TARGET_H8300SX) { if (GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT && INTVAL (operands[2]) <= 8 && INTVAL (operands[3]) >= 0 && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8 && memory_operand (operands[1], QImode)) { rtx temp; /* Optimize the case where we're extracting into a paradoxical subreg. It's only necessary to extend to the inner reg. */ if (GET_CODE (operands[0]) == SUBREG && subreg_lowpart_p (operands[0]) && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) < GET_MODE_SIZE (GET_MODE (operands[0]))) && (GET_MODE_CLASS (GET_MODE (SUBREG_REG (operands[0]))) == MODE_INT)) operands[0] = SUBREG_REG (operands[0]); if (!can_create_pseudo_p ()) temp = gen_lowpart (QImode, operands[0]); else temp = gen_reg_rtx (QImode); if (! temp) FAIL; if (! bit_memory_operand (operands[1], QImode)) { if (!can_create_pseudo_p ()) FAIL; operands[1] = replace_equiv_address (operands[1], force_reg (Pmode, XEXP (operands[1], 0))); } emit_insn (gen_bfld (temp, operands[1], operands[2], operands[3])); convert_move (operands[0], temp, 1); DONE; } FAIL; } /* 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\;b%c4 #0,%R0\;bst #0,%R0; bl1" [(set_attr "length" "6")]) (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\;b%c5 %Z4,%Y3\;bst #0,%R0; bl3" [(set_attr "length" "6")]) (define_insn "bfld" [(set (match_operand:QI 0 "register_operand" "=r") (zero_extract:QI (match_operand:QI 1 "bit_memory_operand" "WU") (match_operand:QI 2 "immediate_operand" "n") (match_operand:QI 3 "immediate_operand" "n")))] "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8" { operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3]))) - (1 << INTVAL (operands[3]))); return "bfld %2,%1,%R0"; } [(set_attr "cc" "none_0hit") (set_attr "length_table" "bitfield")]) (define_insn "bfst" [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU") (match_operand:QI 2 "immediate_operand" "n") (match_operand:QI 3 "immediate_operand" "n")) (match_operand:QI 1 "register_operand" "r"))] "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8" { operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3]))) - (1 << INTVAL (operands[3]))); return "bfst %R1,%2,%0"; } [(set_attr "cc" "none_0hit") (set_attr "length_table" "bitfield")]) (define_expand "cstoreqi4" [(use (match_operator 1 "eqne_operator" [(match_operand:QI 2 "h8300_dst_operand" "") (match_operand:QI 3 "h8300_src_operand" "")])) (clobber (match_operand:HI 0 "register_operand"))] "TARGET_H8300SX" { h8300_expand_store (operands); DONE; }) (define_expand "cstorehi4" [(use (match_operator 1 "eqne_operator" [(match_operand:HI 2 "h8300_dst_operand" "") (match_operand:HI 3 "h8300_src_operand" "")])) (clobber (match_operand:HI 0 "register_operand"))] "TARGET_H8300SX" { h8300_expand_store (operands); DONE; }) (define_expand "cstoresi4" [(use (match_operator 1 "eqne_operator" [(match_operand:SI 2 "h8300_dst_operand" "") (match_operand:SI 3 "h8300_src_operand" "")])) (clobber (match_operand:HI 0 "register_operand"))] "TARGET_H8300SX" { h8300_expand_store (operands); DONE; }) (define_insn "*bstzhireg" [(set (match_operand:HI 0 "register_operand" "=r") (match_operator:HI 1 "eqne_operator" [(cc0) (const_int 0)]))] "TARGET_H8300SX" "mulu.w #0,%T0\;b%k1 .Lh8BR%=\;inc.w #1,%T0\\n.Lh8BR%=:" [(set_attr "cc" "clobber")]) (define_insn_and_split "*cmpstz" [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU,+WU") (const_int 1) (match_operand:QI 1 "immediate_operand" "n,n")) (match_operator:QI 2 "eqne_operator" [(match_operand 3 "h8300_dst_operand" "r,rQ") (match_operand 4 "h8300_src_operand" "I,rQi")]))] "TARGET_H8300SX && (GET_MODE (operands[3]) == GET_MODE (operands[4]) || GET_CODE (operands[4]) == CONST_INT) && GET_MODE_CLASS (GET_MODE (operands[3])) == MODE_INT && GET_MODE_SIZE (GET_MODE (operands[3])) <= 4" "#" "reload_completed" [(set (cc0) (match_dup 5)) (set (zero_extract:QI (match_dup 0) (const_int 1) (match_dup 1)) (match_op_dup:QI 2 [(cc0) (const_int 0)]))] { operands[5] = gen_rtx_COMPARE (VOIDmode, operands[3], operands[4]); } [(set_attr "cc" "set_znv,compare")]) (define_insn "*bstz" [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU") (const_int 1) (match_operand:QI 1 "immediate_operand" "n")) (eq:QI (cc0) (const_int 0)))] "TARGET_H8300SX && reload_completed" "bstz %1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "unary")]) (define_insn "*bistz" [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU") (const_int 1) (match_operand:QI 1 "immediate_operand" "n")) (ne:QI (cc0) (const_int 0)))] "TARGET_H8300SX && reload_completed" "bistz %1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "unary")]) (define_insn_and_split "*cmpcondbset" [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU") (if_then_else:QI (match_operator 1 "eqne_operator" [(match_operand 2 "h8300_dst_operand" "r,rQ") (match_operand 3 "h8300_src_operand" "I,rQi")]) (ior:QI (match_operand:QI 4 "bit_memory_operand" "0,0") (match_operand:QI 5 "single_one_operand" "n,n")) (match_dup 4)))] "TARGET_H8300SX" "#" "reload_completed" [(set (cc0) (match_dup 6)) (set (match_dup 0) (if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)]) (ior:QI (match_dup 4) (match_dup 5)) (match_dup 4)))] { operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]); } [(set_attr "cc" "set_znv,compare")]) (define_insn "*condbset" [(set (match_operand:QI 0 "bit_memory_operand" "=WU") (if_then_else:QI (match_operator:QI 2 "eqne_operator" [(cc0) (const_int 0)]) (ior:QI (match_operand:QI 3 "bit_memory_operand" "0") (match_operand:QI 1 "single_one_operand" "n")) (match_dup 3)))] "TARGET_H8300SX && reload_completed" "bset/%j2\t%V1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "logicb")]) (define_insn_and_split "*cmpcondbclr" [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU") (if_then_else:QI (match_operator 1 "eqne_operator" [(match_operand 2 "h8300_dst_operand" "r,rQ") (match_operand 3 "h8300_src_operand" "I,rQi")]) (and:QI (match_operand:QI 4 "bit_memory_operand" "0,0") (match_operand:QI 5 "single_zero_operand" "n,n")) (match_dup 4)))] "TARGET_H8300SX" "#" "reload_completed" [(set (cc0) (match_dup 6)) (set (match_dup 0) (if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)]) (and:QI (match_dup 4) (match_dup 5)) (match_dup 4)))] { operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]); } [(set_attr "cc" "set_znv,compare")]) (define_insn "*condbclr" [(set (match_operand:QI 0 "bit_memory_operand" "=WU") (if_then_else:QI (match_operator:QI 2 "eqne_operator" [(cc0) (const_int 0)]) (and:QI (match_operand:QI 3 "bit_memory_operand" "0") (match_operand:QI 1 "single_zero_operand" "n")) (match_dup 3)))] "TARGET_H8300SX && reload_completed" "bclr/%j2\t%W1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "logicb")]) (define_insn_and_split "*cmpcondbsetreg" [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU") (if_then_else:QI (match_operator 1 "eqne_operator" [(match_operand 2 "h8300_dst_operand" "r,rQ") (match_operand 3 "h8300_src_operand" "I,rQi")]) (ior:QI (match_operand:QI 4 "bit_memory_operand" "0,0") (ashift:QI (const_int 1) (match_operand:QI 5 "register_operand" "r,r"))) (match_dup 4)))] "TARGET_H8300SX" "#" "reload_completed" [(set (cc0) (match_dup 6)) (set (match_dup 0) (if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)]) (ior:QI (match_dup 4) (ashift:QI (const_int 1) (match_operand:QI 5 "register_operand" "r,r"))) (match_dup 4)))] { operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]); } [(set_attr "cc" "set_znv,compare")]) (define_insn "*condbsetreg" [(set (match_operand:QI 0 "bit_memory_operand" "=WU") (if_then_else:QI (match_operator:QI 2 "eqne_operator" [(cc0) (const_int 0)]) (ior:QI (match_operand:QI 3 "bit_memory_operand" "0") (ashift:QI (const_int 1) (match_operand:QI 1 "register_operand" "r"))) (match_dup 3)))] "TARGET_H8300SX && reload_completed" "bset/%j2\t%R1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "logicb")]) (define_insn_and_split "*cmpcondbclrreg" [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU") (if_then_else:QI (match_operator 1 "eqne_operator" [(match_operand 2 "h8300_dst_operand" "r,rQ") (match_operand 3 "h8300_src_operand" "I,rQi")]) (and:QI (match_operand:QI 4 "bit_memory_operand" "0,0") (ashift:QI (const_int 1) (match_operand:QI 5 "register_operand" "r,r"))) (match_dup 4)))] "TARGET_H8300SX" "#" "reload_completed" [(set (cc0) (match_dup 6)) (set (match_dup 0) (if_then_else:QI (match_op_dup 1 [(cc0) (const_int 0)]) (and:QI (match_dup 4) (ashift:QI (const_int 1) (match_operand:QI 5 "register_operand" "r,r"))) (match_dup 4)))] { operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]); } [(set_attr "cc" "set_znv,compare")]) (define_insn "*condbclrreg" [(set (match_operand:QI 0 "bit_memory_operand" "=WU") (if_then_else:QI (match_operator:QI 2 "eqne_operator" [(cc0) (const_int 0)]) (and:QI (match_operand:QI 3 "bit_memory_operand" "0") (ashift:QI (const_int 1) (match_operand:QI 1 "register_operand" "r"))) (match_dup 3)))] "TARGET_H8300SX && reload_completed" "bclr/%j2\t%R1,%0" [(set_attr "cc" "none_0hit") (set_attr "length_table" "logicb")]) ;; ----------------------------------------------------------------- ;; COMBINE PATTERNS ;; ----------------------------------------------------------------- ;; insv:SI (define_insn "*insv_si_1_n" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") (const_int 1) (match_operand:SI 1 "const_int_operand" "n")) (match_operand:SI 2 "register_operand" "r"))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) < 16" "bld\\t#0,%w2\;bst\\t%Z1,%Y0" [(set_attr "length" "4")]) (define_insn "*insv_si_1_n_lshiftrt" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") (const_int 1) (match_operand:SI 1 "const_int_operand" "n")) (lshiftrt:SI (match_operand:SI 2 "register_operand" "r") (match_operand:SI 3 "const_int_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) < 16 && INTVAL (operands[3]) < 16" "bld\\t%Z3,%Y2\;bst\\t%Z1,%Y0" [(set_attr "length" "4")]) (define_insn "*insv_si_1_n_lshiftrt_16" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") (const_int 1) (match_operand:SI 1 "const_int_operand" "n")) (lshiftrt:SI (match_operand:SI 2 "register_operand" "r") (const_int 16)))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) < 16" "rotr.w\\t%e2\;rotl.w\\t%e2\;bst\\t%Z1,%Y0" [(set_attr "length" "6")]) (define_insn "*insv_si_8_8" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") (const_int 8) (const_int 8)) (match_operand:SI 1 "register_operand" "r"))] "TARGET_H8300H || TARGET_H8300S" "mov.b\\t%w1,%x0" [(set_attr "length" "2")]) (define_insn "*insv_si_8_8_lshiftrt_8" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") (const_int 8) (const_int 8)) (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 8)))] "TARGET_H8300H || TARGET_H8300S" "mov.b\\t%x1,%x0" [(set_attr "length" "2")]) ;; extzv:SI (define_insn "*extzv_8_8" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extract:SI (match_operand:SI 1 "register_operand" "?0,r") (const_int 8) (const_int 8)))] "TARGET_H8300H || TARGET_H8300S" "@ mov.b\\t%x1,%w0\;extu.w\\t%f0\;extu.l\\t%S0 sub.l\\t%S0,%S0\;mov.b\\t%x1,%w0" [(set_attr "cc" "set_znv,clobber") (set_attr "length" "6,4")]) (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 "*extzv_16_8" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (match_operand:SI 1 "register_operand" "r") (const_int 16) (const_int 8))) (clobber (match_scratch:SI 2 "=&r"))] "TARGET_H8300H" "mov.w\\t%e1,%f2\;mov.b\\t%x1,%w0\;mov.b\\t%w2,%x0\;extu.l\\t%S0" [(set_attr "length" "8") (set_attr "cc" "set_znv")]) ;; Extract the exponent of a float. (define_insn_and_split "*extzv_8_23" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extract:SI (match_operand:SI 1 "register_operand" "0") (const_int 8) (const_int 23)))] "(TARGET_H8300H || TARGET_H8300S)" "#" "&& reload_completed" [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 1))) (clobber (scratch:QI))]) (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 24))) (clobber (scratch:QI))])] "") ;; and:SI ;; ((SImode) HImode) << 15 (define_insn_and_split "*twoshifts_l16_r1" [(set (match_operand:SI 0 "register_operand" "=r") (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0") (const_int 15)) (const_int 2147450880)))] "(TARGET_H8300H || TARGET_H8300S)" "#" "&& reload_completed" [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16))) (clobber (scratch:QI))]) (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 1))) (clobber (scratch:QI))])] "") ;; Transform (SImode << B) & 0xffff into (SImode) (HImode << B). (define_insn_and_split "*andsi3_ashift_n_lower" [(set (match_operand:SI 0 "register_operand" "=r,r") (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0,0") (match_operand:QI 2 "const_int_operand" "S,n")) (match_operand:SI 3 "const_int_operand" "n,n"))) (clobber (match_scratch:QI 4 "=X,&r"))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[2]) <= 15 && INTVAL (operands[3]) == ((-1 << INTVAL (operands[2])) & 0xffff)" "#" "&& reload_completed" [(parallel [(set (match_dup 5) (ashift:HI (match_dup 5) (match_dup 2))) (clobber (match_dup 4))]) (set (match_dup 0) (zero_extend:SI (match_dup 5)))] { operands[5] = gen_rtx_REG (HImode, REGNO (operands[0])); }) ;; Accept (A >> 30) & 2 and the like. (define_insn "*andsi3_lshiftrt_n_sb" [(set (match_operand:SI 0 "register_operand" "=r") (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "const_int_operand" "n")) (match_operand:SI 3 "single_one_operand" "n")))] "(TARGET_H8300H || TARGET_H8300S) && exact_log2 (INTVAL (operands[3])) < 16 && INTVAL (operands[2]) + exact_log2 (INTVAL (operands[3])) == 31" { operands[3] = GEN_INT (exact_log2 (INTVAL (operands[3]))); return "shll.l\\t%S0\;xor.l\\t%S0,%S0\;bst\\t%Z3,%Y0"; } [(set_attr "length" "8")]) (define_insn_and_split "*andsi3_lshiftrt_9_sb" [(set (match_operand:SI 0 "register_operand" "=r") (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (const_int 9)) (const_int 4194304)))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (match_dup 0) (and:SI (lshiftrt:SI (match_dup 0) (const_int 25)) (const_int 64))) (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16))) (clobber (scratch:QI))])] "") ;; plus:SI (define_insn "*addsi3_upper" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") (const_int 65536)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "add.w\\t%f1,%e0" [(set_attr "length" "2")]) (define_insn "*addsi3_lshiftrt_16_zexthi" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 16)) (zero_extend:SI (match_operand:HI 2 "register_operand" "0"))))] "TARGET_H8300H || TARGET_H8300S" "add.w\\t%e1,%f0\;xor.w\\t%e0,%e0\;rotxl.w\\t%e0" [(set_attr "length" "6")]) (define_insn_and_split "*addsi3_and_r_1" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (and:SI (match_operand:SI 1 "register_operand" "r") (const_int 1)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (cc0) (compare (zero_extract:SI (match_dup 1) (const_int 1) (const_int 0)) (const_int 0))) (set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_dup 3)) (pc))) (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1))) (match_dup 3)] { operands[3] = gen_label_rtx (); }) (define_insn_and_split "*addsi3_and_not_r_1" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (and:SI (not:SI (match_operand:SI 1 "register_operand" "r")) (const_int 1)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (cc0) (compare (zero_extract:SI (match_dup 1) (const_int 1) (const_int 0)) (const_int 0))) (set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_dup 3)) (pc))) (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1))) (match_dup 3)] { operands[3] = gen_label_rtx (); }) ;; [ix]or:HI (define_insn "*ixorhi3_zext" [(set (match_operand:HI 0 "register_operand" "=r") (match_operator:HI 1 "iorxor_operator" [(zero_extend:HI (match_operand:QI 2 "register_operand" "r")) (match_operand:HI 3 "register_operand" "0")]))] "" "%c1.b\\t%X2,%s0" [(set_attr "length" "2")]) ;; [ix]or:SI (define_insn "*ixorsi3_zext_qi" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "iorxor_operator" [(zero_extend:SI (match_operand:QI 2 "register_operand" "r")) (match_operand:SI 3 "register_operand" "0")]))] "" "%c1.b\\t%X2,%w0" [(set_attr "length" "2")]) (define_insn "*ixorsi3_zext_hi" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "iorxor_operator" [(zero_extend:SI (match_operand:HI 2 "register_operand" "r")) (match_operand:SI 3 "register_operand" "0")]))] "TARGET_H8300H || TARGET_H8300S" "%c1.w\\t%T2,%f0" [(set_attr "length" "2")]) (define_insn "*ixorsi3_ashift_16" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "iorxor_operator" [(ashift:SI (match_operand:SI 2 "register_operand" "r") (const_int 16)) (match_operand:SI 3 "register_operand" "0")]))] "TARGET_H8300H || TARGET_H8300S" "%c1.w\\t%f2,%e0" [(set_attr "length" "2")]) (define_insn "*ixorsi3_lshiftrt_16" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "iorxor_operator" [(lshiftrt:SI (match_operand:SI 2 "register_operand" "r") (const_int 16)) (match_operand:SI 3 "register_operand" "0")]))] "TARGET_H8300H || TARGET_H8300S" "%c1.w\\t%e2,%f0" [(set_attr "length" "2")]) ;; ior:HI (define_insn "*iorhi3_ashift_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 "length" "2")]) (define_insn "*iorhi3_lshiftrt_8" [(set (match_operand:HI 0 "register_operand" "=r") (ior:HI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r") (const_int 8)) (match_operand:HI 2 "register_operand" "0")))] "" "or.b\\t%t1,%s0" [(set_attr "length" "2")]) (define_insn "*iorhi3_two_qi" [(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))))] "" "mov.b\\t%s2,%t0" [(set_attr "length" "2")]) (define_insn "*iorhi3_two_qi_mem" [(set (match_operand:HI 0 "register_operand" "=&r") (ior:HI (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")) (ashift:HI (subreg:HI (match_operand:QI 2 "memory_operand" "m") 0) (const_int 8))))] "" "mov.b\\t%X2,%t0\;mov.b\\t%X1,%s0" [(set_attr "length" "16")]) (define_split [(set (match_operand:HI 0 "register_operand" "") (ior:HI (zero_extend:HI (match_operand:QI 1 "memory_operand" "")) (ashift:HI (subreg:HI (match_operand:QI 2 "memory_operand" "") 0) (const_int 8))))] "(TARGET_H8300H || TARGET_H8300S) && reload_completed && byte_accesses_mergeable_p (XEXP (operands[2], 0), XEXP (operands[1], 0))" [(set (match_dup 0) (match_dup 3))] { operands[3] = gen_rtx_MEM (HImode, XEXP (operands[2], 0)); }) ;; ior:SI (define_insn "*iorsi3_two_hi" [(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 "length" "2")]) (define_insn_and_split "*iorsi3_two_qi_zext" [(set (match_operand:SI 0 "register_operand" "=&r") (ior:SI (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")) (and:SI (ashift:SI (subreg:SI (match_operand:QI 2 "memory_operand" "m") 0) (const_int 8)) (const_int 65280))))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (match_dup 3) (ior:HI (zero_extend:HI (match_dup 1)) (ashift:HI (subreg:HI (match_dup 2) 0) (const_int 8)))) (set (match_dup 0) (zero_extend:SI (match_dup 3)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); }) (define_insn "*iorsi3_e2f" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0") (const_int -65536)) (lshiftrt:SI (match_operand:SI 2 "register_operand" "r") (const_int 16))))] "TARGET_H8300H || TARGET_H8300S" "mov.w\\t%e2,%f0" [(set_attr "length" "2")]) (define_insn_and_split "*iorsi3_two_qi_sext" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (zero_extend:SI (match_operand:QI 1 "register_operand" "0")) (ashift:SI (sign_extend:SI (match_operand:QI 2 "register_operand" "r")) (const_int 8))))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (match_dup 3) (ior:HI (zero_extend:HI (match_dup 1)) (ashift:HI (match_dup 4) (const_int 8)))) (set (match_dup 0) (sign_extend:SI (match_dup 3)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); operands[4] = gen_rtx_REG (HImode, REGNO (operands[2])); }) (define_insn "*iorsi3_w" [(set (match_operand:SI 0 "register_operand" "=r,&r") (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0,0") (const_int -256)) (zero_extend:SI (match_operand:QI 2 "general_operand_src" "r,g>"))))] "TARGET_H8300H || TARGET_H8300S" "mov.b\\t%X2,%w0" [(set_attr "length" "2,8")]) (define_insn "*iorsi3_ashift_31" [(set (match_operand:SI 0 "register_operand" "=&r") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") (const_int 31)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "rotxl.l\\t%S0\;bor\\t#0,%w1\;rotxr.l\\t%S0" [(set_attr "length" "6") (set_attr "cc" "set_znv")]) (define_insn "*iorsi3_and_ashift" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "const_int_operand" "n")) (match_operand:SI 3 "single_one_operand" "n")) (match_operand:SI 4 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && (INTVAL (operands[3]) & ~0xffff) == 0" { rtx srcpos = GEN_INT (exact_log2 (INTVAL (operands[3])) - INTVAL (operands[2])); rtx dstpos = GEN_INT (exact_log2 (INTVAL (operands[3]))); operands[2] = srcpos; operands[3] = dstpos; return "bld\\t%Z2,%Y1\;bor\\t%Z3,%Y0\;bst\\t%Z3,%Y0"; } [(set_attr "length" "6")]) (define_insn "*iorsi3_and_lshiftrt" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "const_int_operand" "n")) (match_operand:SI 3 "single_one_operand" "n")) (match_operand:SI 4 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && ((INTVAL (operands[3]) << INTVAL (operands[2])) & ~0xffff) == 0" { rtx srcpos = GEN_INT (exact_log2 (INTVAL (operands[3])) + INTVAL (operands[2])); rtx dstpos = GEN_INT (exact_log2 (INTVAL (operands[3]))); operands[2] = srcpos; operands[3] = dstpos; return "bld\\t%Z2,%Y1\;bor\\t%Z3,%Y0\;bst\\t%Z3,%Y0"; } [(set_attr "length" "6")]) (define_insn "*iorsi3_zero_extract" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (zero_extract:SI (match_operand:SI 1 "register_operand" "r") (const_int 1) (match_operand:SI 2 "const_int_operand" "n")) (match_operand:SI 3 "register_operand" "0")))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[2]) < 16" "bld\\t%Z2,%Y1\;bor\\t#0,%w0\;bst\\t#0,%w0" [(set_attr "length" "6")]) (define_insn "*iorsi3_and_lshiftrt_n_sb" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 30)) (const_int 2)) (match_operand:SI 2 "register_operand" "0")))] "TARGET_H8300H || TARGET_H8300S" "rotl.l\\t%S1\;rotr.l\\t%S1\;bor\\t#1,%w0\;bst\\t#1,%w0" [(set_attr "length" "8")]) (define_insn "*iorsi3_and_lshiftrt_9_sb" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") (const_int 9)) (const_int 4194304)) (match_operand:SI 2 "register_operand" "0"))) (clobber (match_scratch:HI 3 "=&r"))] "TARGET_H8300H || TARGET_H8300S" { if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) return "shll.l\\t%S1\;xor.w\\t%T3,%T3\;bst\\t#6,%s3\;or.w\\t%T3,%e0"; else return "rotl.l\\t%S1\;rotr.l\\t%S1\;xor.w\\t%T3,%T3\;bst\\t#6,%s3\;or.w\\t%T3,%e0"; } [(set_attr "length" "10")]) ;; Used to OR the exponent of a float. (define_insn "*iorsi3_shift" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") (const_int 23)) (match_operand:SI 2 "register_operand" "0"))) (clobber (match_scratch:SI 3 "=&r"))] "TARGET_H8300H || TARGET_H8300S" "#") (define_split [(set (match_operand:SI 0 "register_operand" "") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "") (const_int 23)) (match_dup 0))) (clobber (match_operand:SI 2 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && epilogue_completed && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1])" [(parallel [(set (match_dup 3) (ashift:HI (match_dup 3) (const_int 7))) (clobber (scratch:QI))]) (set (match_dup 0) (ior:SI (ashift:SI (match_dup 1) (const_int 16)) (match_dup 0)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[1])); }) (define_split [(set (match_operand:SI 0 "register_operand" "") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "") (const_int 23)) (match_dup 0))) (clobber (match_operand:SI 2 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && epilogue_completed && !(find_regno_note (insn, REG_DEAD, REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]))" [(set (match_dup 2) (match_dup 1)) (parallel [(set (match_dup 3) (ashift:HI (match_dup 3) (const_int 7))) (clobber (scratch:QI))]) (set (match_dup 0) (ior:SI (ashift:SI (match_dup 2) (const_int 16)) (match_dup 0)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[2])); }) (define_insn "*iorsi2_and_1_lshiftrt_1" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0") (const_int 1)) (lshiftrt:SI (match_dup 1) (const_int 1))))] "TARGET_H8300H || TARGET_H8300S" "shlr.l\\t%S0\;bor\\t#0,%w0\;bst\\t#0,%w0" [(set_attr "length" "6")]) (define_insn_and_split "*iorsi3_ashift_16_ashift_24" [(set (match_operand:SI 0 "register_operand" "=r") (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "0") (const_int 16)) (ashift:SI (match_operand:SI 2 "register_operand" "r") (const_int 24))))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (match_dup 3) (ior:HI (ashift:HI (match_dup 4) (const_int 8)) (match_dup 3))) (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16))) (clobber (scratch:QI))])] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); operands[4] = gen_rtx_REG (HImode, REGNO (operands[2])); }) (define_insn_and_split "*iorsi3_ashift_16_ashift_24_mem" [(set (match_operand:SI 0 "register_operand" "=&r") (ior:SI (and:SI (ashift:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0) (const_int 16)) (const_int 16711680)) (ashift:SI (subreg:SI (match_operand:QI 2 "memory_operand" "m") 0) (const_int 24))))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(set (match_dup 3) (ior:HI (zero_extend:HI (match_dup 1)) (ashift:HI (subreg:HI (match_dup 2) 0) (const_int 8)))) (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16))) (clobber (scratch:QI))])] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[0])); }) ;; Used to add the exponent of a float. (define_insn "*addsi3_shift" [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") (const_int 8388608)) (match_operand:SI 2 "register_operand" "0"))) (clobber (match_scratch:SI 3 "=&r"))] "TARGET_H8300H || TARGET_H8300S" "#") (define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") (const_int 8388608)) (match_dup 0))) (clobber (match_operand:SI 2 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && epilogue_completed && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1])" [(parallel [(set (match_dup 3) (ashift:HI (match_dup 3) (const_int 7))) (clobber (scratch:QI))]) (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 65536)) (match_dup 0)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[1])); }) (define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") (const_int 8388608)) (match_dup 0))) (clobber (match_operand:SI 2 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && epilogue_completed && !(find_regno_note (insn, REG_DEAD, REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]))" [(set (match_dup 2) (match_dup 1)) (parallel [(set (match_dup 3) (ashift:HI (match_dup 3) (const_int 7))) (clobber (scratch:QI))]) (set (match_dup 0) (plus:SI (mult:SI (match_dup 2) (const_int 65536)) (match_dup 0)))] { operands[3] = gen_rtx_REG (HImode, REGNO (operands[2])); }) ;; ashift:SI (define_insn_and_split "*ashiftsi_sextqi_7" [(set (match_operand:SI 0 "register_operand" "=r") (ashift:SI (sign_extend:SI (match_operand:QI 1 "register_operand" "0")) (const_int 7)))] "TARGET_H8300H || TARGET_H8300S" "#" "&& reload_completed" [(parallel [(set (match_dup 2) (ashift:HI (match_dup 2) (const_int 8))) (clobber (scratch:QI))]) (set (match_dup 0) (sign_extend:SI (match_dup 2))) (parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 1))) (clobber (scratch:QI))])] { operands[2] = gen_rtx_REG (HImode, REGNO (operands[0])); }) ;; 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) (compare (match_dup 0) (const_int 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) (compare (match_dup 0) (const_int 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 && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] { operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); }) (define_peephole2 [(parallel [(set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -4))) (set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -3))) (match_operand:QI 0 "register_operand" ""))])] "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (mem:SI (pre_dec:HI (reg:HI 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 && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] { operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); }) (define_peephole2 [(parallel [(set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -4))) (set (mem:HI (plus:HI (reg:HI SP_REG) (const_int -2))) (match_operand:HI 0 "register_operand" ""))])] "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (mem:SI (pre_dec:HI (reg:HI 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 && !TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[3])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && REGNO (operands[2]) == REGNO (operands[0]) + 2 && REGNO (operands[3]) == REGNO (operands[0]) + 3 && (TARGET_H8300SX || REGNO (operands[0]) == 0))" [(parallel [(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)) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -16)))])] "") (define_peephole2 [(set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 2 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 3 "register_operand" ""))] "TARGET_H8300S && TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[3])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && REGNO (operands[2]) == REGNO (operands[0]) + 2 && REGNO (operands[3]) == REGNO (operands[0]) + 3 && (TARGET_H8300SX || REGNO (operands[0]) == 0))" [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8))) (match_dup 1)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12))) (match_dup 2)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -16))) (match_dup 3)) (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -16)))])] "") ;; 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 && !TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[2])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && REGNO (operands[2]) == REGNO (operands[0]) + 2 && (TARGET_H8300SX || (REGNO (operands[0]) & 3) == 0))" [(parallel [(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 (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -12)))])] "") (define_peephole2 [(set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 1 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 2 "register_operand" ""))] "TARGET_H8300S && TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[2])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && REGNO (operands[2]) == REGNO (operands[0]) + 2 && (TARGET_H8300SX || (REGNO (operands[0]) & 3) == 0))" [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8))) (match_dup 1)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12))) (match_dup 2)) (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -12)))])] "") ;; 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 && !TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[1])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && (TARGET_H8300SX || (REGNO (operands[0]) & 1) == 0))" [(parallel [(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 (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -8)))])] "") (define_peephole2 [(set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 0 "register_operand" "")) (set (mem:SI (pre_dec:HI (reg:HI SP_REG))) (match_operand:SI 1 "register_operand" ""))] "TARGET_H8300S && TARGET_NORMAL_MODE && (REGNO_REG_CLASS (REGNO (operands[1])) == GENERAL_REGS && REGNO (operands[1]) == REGNO (operands[0]) + 1 && (TARGET_H8300SX || (REGNO (operands[0]) & 1) == 0))" [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4))) (match_dup 0)) (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8))) (match_dup 1)) (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -8)))])] "") ;; 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]) && (satisfies_constraint_J (operands[1]) || satisfies_constraint_L (operands[1]) || satisfies_constraint_N (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]) && (satisfies_constraint_L (operands[1]) || satisfies_constraint_N (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]) && !satisfies_constraint_L (operands[2]) && !satisfies_constraint_N (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)))] "") ;; Turn ;; ;; subs #1,er4 ;; mov.w r4,r4 ;; bne .L2028 ;; ;; into ;; ;; dec.w #1,r4 ;; bne .L2028 (define_peephole2 [(set (match_operand:HI 0 "register_operand" "") (plus:HI (match_dup 0) (match_operand 1 "incdec_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (match_operand:HI 0 "register_operand" "") (unspec:HI [(match_dup 0) (match_dup 1)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] "") ;; The SImode version of the previous pattern. (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (plus:SI (match_dup 0) (match_operand 1 "incdec_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (match_operand:SI 0 "register_operand" "") (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] "") (define_peephole2 [(parallel [(set (cc0) (compare (zero_extract:SI (match_operand:QI 0 "register_operand" "") (const_int 1) (const_int 7)) (const_int 0))) (clobber (scratch:QI))]) (set (pc) (if_then_else (match_operator 1 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[3] = ((GET_CODE (operands[1]) == EQ) ? gen_rtx_GE (VOIDmode, cc0_rtx, const0_rtx) : gen_rtx_LT (VOIDmode, cc0_rtx, const0_rtx)); }) ;; The next three peephole2's will try to transform ;; ;; mov.b A,r0l (or mov.l A,er0) ;; and.l #CST,er0 ;; ;; into ;; ;; sub.l er0 ;; mov.b A,r0l ;; and.b #CST,r0l (if CST is not 255) (define_peephole2 [(set (match_operand:QI 0 "register_operand" "") (match_operand:QI 1 "general_operand" "")) (set (match_operand:SI 2 "register_operand" "") (and:SI (match_dup 2) (const_int 255)))] "(TARGET_H8300H || TARGET_H8300S) && !reg_overlap_mentioned_p (operands[2], operands[1]) && REGNO (operands[0]) == REGNO (operands[2])" [(set (match_dup 2) (const_int 0)) (set (strict_low_part (match_dup 0)) (match_dup 1))] "") (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "general_operand" "")) (set (match_dup 0) (and:SI (match_dup 0) (const_int 255)))] "(TARGET_H8300H || TARGET_H8300S) && !reg_overlap_mentioned_p (operands[0], operands[1]) && !(GET_CODE (operands[1]) == MEM && !offsettable_memref_p (operands[1])) && !(GET_CODE (operands[1]) == MEM && MEM_VOLATILE_P (operands[1]))" [(set (match_dup 0) (const_int 0)) (set (strict_low_part (match_dup 2)) (match_dup 3))] { operands[2] = gen_lowpart (QImode, operands[0]); operands[3] = gen_lowpart (QImode, operands[1]); }) (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "general_operand" "")) (set (match_operand:SI 2 "register_operand" "") (and:SI (match_dup 2) (match_operand:SI 3 "const_int_qi_operand" "")))] "(TARGET_H8300H || TARGET_H8300S) && (GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode || GET_MODE (operands[0]) == SImode) && GET_MODE (operands[0]) == GET_MODE (operands[1]) && REGNO (operands[0]) == REGNO (operands[2]) && !reg_overlap_mentioned_p (operands[2], operands[1]) && !(GET_MODE (operands[1]) != QImode && GET_CODE (operands[1]) == MEM && !offsettable_memref_p (operands[1])) && !(GET_MODE (operands[1]) != QImode && GET_CODE (operands[1]) == MEM && MEM_VOLATILE_P (operands[1]))" [(set (match_dup 2) (const_int 0)) (set (strict_low_part (match_dup 4)) (match_dup 5)) (set (match_dup 2) (and:SI (match_dup 2) (match_dup 6)))] { operands[4] = gen_lowpart (QImode, operands[0]); operands[5] = gen_lowpart (QImode, operands[1]); operands[6] = GEN_INT (~0xff | INTVAL (operands[3])); }) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "register_operand" "")) (set (match_dup 0) (and:SI (match_dup 0) (const_int 65280)))] "(TARGET_H8300H || TARGET_H8300S) && !reg_overlap_mentioned_p (operands[0], operands[1])" [(set (match_dup 0) (const_int 0)) (set (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)) (lshiftrt:SI (match_dup 1) (const_int 8)))] "") ;; If a load of mem:SI is followed by an AND that turns off the upper ;; half, then we can load mem:HI instead. (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "memory_operand" "")) (set (match_dup 0) (and:SI (match_dup 0) (match_operand:SI 2 "const_int_operand" "")))] "(TARGET_H8300H || TARGET_H8300S) && !MEM_VOLATILE_P (operands[1]) && offsettable_memref_p (operands[1]) && (INTVAL (operands[2]) & ~0xffff) == 0 && INTVAL (operands[2]) != 255" [(set (match_dup 3) (match_dup 4)) (set (match_dup 0) (and:SI (match_dup 0) (match_dup 2)))] { operands[3] = gen_lowpart (HImode, operands[0]); operands[4] = gen_lowpart (HImode, operands[1]); }) ;; Convert a memory comparison to a move if there is a scratch register. (define_peephole2 [(match_scratch:QI 1 "r") (set (cc0) (compare (match_operand:QI 0 "memory_operand" "") (const_int 0)))] "" [(set (match_dup 1) (match_dup 0)) (set (cc0) (compare (match_dup 1) (const_int 0)))] "") (define_peephole2 [(match_scratch:HI 1 "r") (set (cc0) (compare (match_operand:HI 0 "memory_operand" "") (const_int 0)))] "TARGET_H8300H || TARGET_H8300S" [(set (match_dup 1) (match_dup 0)) (set (cc0) (compare (match_dup 1) (const_int 0)))] "") (define_peephole2 [(match_scratch:SI 1 "r") (set (cc0) (compare (match_operand:SI 0 "memory_operand" "") (const_int 0)))] "TARGET_H8300H || TARGET_H8300S" [(set (match_dup 1) (match_dup 0)) (set (cc0) (compare (match_dup 1) (const_int 0)))] "") ;; (compare (reg:HI) (const_int)) takes 4 bytes, so we try to achieve ;; the equivalent with shorter sequences. Here is the summary. Cases ;; are grouped for each define_peephole2. ;; ;; reg const_int use insn ;; -------------------------------------------------------- ;; dead -2 eq/ne inc.l ;; dead -1 eq/ne inc.l ;; dead 1 eq/ne dec.l ;; dead 2 eq/ne dec.l ;; ;; dead 1 ge/lt shar.l ;; dead 3 (H8S) ge/lt shar.l ;; ;; dead 1 geu/ltu shar.l ;; dead 3 (H8S) geu/ltu shar.l ;; ;; ---- 255 ge/lt mov.b ;; ;; ---- 255 geu/ltu mov.b ;; Transform ;; ;; cmp.w #1,r0 ;; bne .L1 ;; ;; into ;; ;; dec.w #1,r0 ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "incdec_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) != 0 && peep2_reg_dead_p (1, operands[0])" [(set (match_dup 0) (unspec:HI [(match_dup 0) (match_dup 4)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = GEN_INT (- INTVAL (operands[1])); }) ;; Transform ;; ;; cmp.w #1,r0 ;; bgt .L1 ;; ;; into ;; ;; shar.w r0 ;; bgt .L1 (define_peephole2 [(set (cc0) (compare (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3))" [(parallel [(set (match_dup 0) (ashiftrt:HI (match_dup 0) (match_dup 4))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 2) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); }) ;; Transform ;; ;; cmp.w #1,r0 ;; bhi .L1 ;; ;; into ;; ;; shar.w r0 ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3))" [(parallel [(set (match_dup 0) (ashiftrt:HI (match_dup 0) (match_dup 4))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 5) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[2]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; Transform ;; ;; cmp.w #255,r0 ;; bgt .L1 ;; ;; into ;; ;; mov.b r0h,r0h ;; bgt .L1 (define_peephole2 [(set (cc0) (compare (match_operand:HI 0 "register_operand" "") (const_int 255))) (set (pc) (if_then_else (match_operator 1 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (cc0) (compare (and:HI (match_dup 0) (const_int -256)) (const_int 0))) (set (pc) (if_then_else (match_dup 1) (label_ref (match_dup 2)) (pc)))] "") ;; Transform ;; ;; cmp.w #255,r0 ;; bhi .L1 ;; ;; into ;; ;; mov.b r0h,r0h ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:HI 0 "register_operand" "") (const_int 255))) (set (pc) (if_then_else (match_operator 1 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (cc0) (compare (and:HI (match_dup 0) (const_int -256)) (const_int 0))) (set (pc) (if_then_else (match_dup 3) (label_ref (match_dup 2)) (pc)))] { operands[3] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; (compare (reg:SI) (const_int)) takes 6 bytes, so we try to achieve ;; the equivalent with shorter sequences. Here is the summary. Cases ;; are grouped for each define_peephole2. ;; ;; reg const_int use insn ;; -------------------------------------------------------- ;; live -2 eq/ne copy and inc.l ;; live -1 eq/ne copy and inc.l ;; live 1 eq/ne copy and dec.l ;; live 2 eq/ne copy and dec.l ;; ;; dead -2 eq/ne inc.l ;; dead -1 eq/ne inc.l ;; dead 1 eq/ne dec.l ;; dead 2 eq/ne dec.l ;; ;; dead -131072 eq/ne inc.w and test ;; dead -65536 eq/ne inc.w and test ;; dead 65536 eq/ne dec.w and test ;; dead 131072 eq/ne dec.w and test ;; ;; dead 0x000000?? except 1 and 2 eq/ne xor.b and test ;; dead 0x0000??00 eq/ne xor.b and test ;; dead 0x0000ffff eq/ne not.w and test ;; ;; dead 0xffffff?? except -1 and -2 eq/ne xor.b and not.l ;; dead 0xffff??ff eq/ne xor.b and not.l ;; dead 0x40000000 (H8S) eq/ne rotl.l and dec.l ;; dead 0x80000000 eq/ne rotl.l and dec.l ;; ;; live 1 ge/lt copy and shar.l ;; live 3 (H8S) ge/lt copy and shar.l ;; ;; live 1 geu/ltu copy and shar.l ;; live 3 (H8S) geu/ltu copy and shar.l ;; ;; dead 1 ge/lt shar.l ;; dead 3 (H8S) ge/lt shar.l ;; ;; dead 1 geu/ltu shar.l ;; dead 3 (H8S) geu/ltu shar.l ;; ;; dead 3 (H8/300H) ge/lt and.b and test ;; dead 7 ge/lt and.b and test ;; dead 15 ge/lt and.b and test ;; dead 31 ge/lt and.b and test ;; dead 63 ge/lt and.b and test ;; dead 127 ge/lt and.b and test ;; dead 255 ge/lt and.b and test ;; ;; dead 3 (H8/300H) geu/ltu and.b and test ;; dead 7 geu/ltu and.b and test ;; dead 15 geu/ltu and.b and test ;; dead 31 geu/ltu and.b and test ;; dead 63 geu/ltu and.b and test ;; dead 127 geu/ltu and.b and test ;; dead 255 geu/ltu and.b and test ;; ;; ---- 65535 ge/lt mov.w ;; ;; ---- 65535 geu/ltu mov.w ;; Transform ;; ;; cmp.l #1,er0 ;; beq .L1 ;; ;; into ;; ;; dec.l #1,er0 ;; beq .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "incdec_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) != 0 && peep2_reg_dead_p (1, operands[0])" [(set (match_dup 0) (unspec:SI [(match_dup 0) (match_dup 4)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = GEN_INT (- INTVAL (operands[1])); }) ;; Transform ;; ;; cmp.l #65536,er0 ;; beq .L1 ;; ;; into ;; ;; dec.l #1,e0 ;; beq .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == -131072 || INTVAL (operands[1]) == -65536 || INTVAL (operands[1]) == 65536 || INTVAL (operands[1]) == 131072)" [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = GEN_INT (- INTVAL (operands[1])); }) ;; Transform ;; ;; cmp.l #100,er0 ;; beq .L1 ;; ;; into ;; ;; xor.b #100,er0 ;; mov.l er0,er0 ;; beq .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && ((INTVAL (operands[1]) & 0x00ff) == INTVAL (operands[1]) || (INTVAL (operands[1]) & 0xff00) == INTVAL (operands[1]) || INTVAL (operands[1]) == 0x0000ffff) && INTVAL (operands[1]) != 0 && INTVAL (operands[1]) != 1 && INTVAL (operands[1]) != 2" [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] "") ;; Transform ;; ;; cmp.l #-100,er0 ;; beq .L1 ;; ;; into ;; ;; xor.b #99,er0 ;; not.l er0 ;; beq .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && ((INTVAL (operands[1]) | 0x00ff) == -1 || (INTVAL (operands[1]) | 0xff00) == -1) && INTVAL (operands[1]) != -1 && INTVAL (operands[1]) != -2" [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 4))) (set (match_dup 0) (not:SI (match_dup 0))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = GEN_INT (INTVAL (operands[1]) ^ -1); }) ;; Transform ;; ;; cmp.l #-2147483648,er0 ;; beq .L1 ;; ;; into ;; ;; rotl.l er0 ;; dec.l #1,er0 ;; beq .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == -2147483647 - 1 || (TARGET_H8300S && INTVAL (operands[1]) == 1073741824))" [(set (match_dup 0) (rotate:SI (match_dup 0) (match_dup 4))) (set (match_dup 0) (unspec:SI [(match_dup 0) (const_int -1)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = GEN_INT (INTVAL (operands[1]) == -2147483647 - 1 ? 1 : 2); }) ;; Transform ;; ;; cmp.l #1,er0 ;; bgt .L1 ;; ;; into ;; ;; mov.l er0,er1 ;; shar.l er1 ;; bgt .L1 ;; We avoid this transformation if we see more than one copy of the ;; same compare insn immediately before this one. (define_peephole2 [(match_scratch:SI 4 "r") (set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && !peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3)) && !same_cmp_preceding_p (insn)" [(set (match_dup 4) (match_dup 0)) (parallel [(set (match_dup 4) (ashiftrt:SI (match_dup 4) (match_dup 5))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_dup 2) (label_ref (match_dup 3)) (pc)))] { operands[5] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); }) ;; Transform ;; ;; cmp.l #1,er0 ;; bhi .L1 ;; ;; into ;; ;; mov.l er0,er1 ;; shar.l er1 ;; bne .L1 ;; We avoid this transformation if we see more than one copy of the ;; same compare insn immediately before this one. (define_peephole2 [(match_scratch:SI 4 "r") (set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && !peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3)) && !same_cmp_preceding_p (insn)" [(set (match_dup 4) (match_dup 0)) (parallel [(set (match_dup 4) (ashiftrt:SI (match_dup 4) (match_dup 5))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_dup 6) (label_ref (match_dup 3)) (pc)))] { operands[5] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[2]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; Transform ;; ;; cmp.l #1,er0 ;; bgt .L1 ;; ;; into ;; ;; shar.l er0 ;; bgt .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3))" [(parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 4))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 2) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); }) ;; Transform ;; ;; cmp.l #1,er0 ;; bhi .L1 ;; ;; into ;; ;; shar.l er0 ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && (INTVAL (operands[1]) == 1 || (TARGET_H8300S && INTVAL (operands[1]) == 3))" [(parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 4))) (clobber (scratch:QI))]) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 5) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[2]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; Transform ;; ;; cmp.l #15,er0 ;; bgt .L1 ;; ;; into ;; ;; and #240,r0l ;; mov.l er0,er0 ;; bgt .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && ((TARGET_H8300H && INTVAL (operands[1]) == 3) || INTVAL (operands[1]) == 7 || INTVAL (operands[1]) == 15 || INTVAL (operands[1]) == 31 || INTVAL (operands[1]) == 63 || INTVAL (operands[1]) == 127 || INTVAL (operands[1]) == 255)" [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 4))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 2) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (~INTVAL (operands[1])); }) ;; Transform ;; ;; cmp.l #15,er0 ;; bhi .L1 ;; ;; into ;; ;; and #240,r0l ;; mov.l er0,er0 ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))) (set (pc) (if_then_else (match_operator 2 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && peep2_reg_dead_p (1, operands[0]) && ((TARGET_H8300H && INTVAL (operands[1]) == 3) || INTVAL (operands[1]) == 7 || INTVAL (operands[1]) == 15 || INTVAL (operands[1]) == 31 || INTVAL (operands[1]) == 63 || INTVAL (operands[1]) == 127 || INTVAL (operands[1]) == 255)" [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 4))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_dup 5) (label_ref (match_dup 3)) (pc)))] { operands[4] = GEN_INT (~INTVAL (operands[1])); operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[2]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; Transform ;; ;; cmp.l #65535,er0 ;; bgt .L1 ;; ;; into ;; ;; mov.l e0,e0 ;; bgt .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (const_int 65535))) (set (pc) (if_then_else (match_operator 1 "gtle_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (cc0) (compare (and:SI (match_dup 0) (const_int -65536)) (const_int 0))) (set (pc) (if_then_else (match_dup 1) (label_ref (match_dup 2)) (pc)))] "") ;; Transform ;; ;; cmp.l #65535,er0 ;; bhi .L1 ;; ;; into ;; ;; mov.l e0,e0 ;; bne .L1 (define_peephole2 [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (const_int 65535))) (set (pc) (if_then_else (match_operator 1 "gtuleu_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "TARGET_H8300H || TARGET_H8300S" [(set (cc0) (compare (and:SI (match_dup 0) (const_int -65536)) (const_int 0))) (set (pc) (if_then_else (match_dup 3) (label_ref (match_dup 2)) (pc)))] { operands[3] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == GTU ? NE : EQ, VOIDmode, cc0_rtx, const0_rtx); }) ;; Transform ;; ;; cmp.l #1,er0 ;; beq .L1 ;; ;; into ;; ;; mov.l er0,er1 ;; dec.l #1,er1 ;; beq .L1 ;; We avoid this transformation if we see more than one copy of the ;; same compare insn. (define_peephole2 [(match_scratch:SI 4 "r") (set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "incdec_operand" ""))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "(TARGET_H8300H || TARGET_H8300S) && INTVAL (operands[1]) != 0 && !peep2_reg_dead_p (1, operands[0]) && !same_cmp_following_p (insn)" [(set (match_dup 4) (match_dup 0)) (set (match_dup 4) (unspec:SI [(match_dup 4) (match_dup 5)] UNSPEC_INCDEC)) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[5] = GEN_INT (- INTVAL (operands[1])); }) ;; Narrow the mode of testing if possible. (define_peephole2 [(set (match_operand:HI 0 "register_operand" "") (and:HI (match_dup 0) (match_operand:HI 1 "const_int_qi_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "peep2_reg_dead_p (2, operands[0])" [(set (match_dup 4) (and:QI (match_dup 4) (match_dup 5))) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = gen_rtx_REG (QImode, REGNO (operands[0])); operands[5] = gen_int_mode (INTVAL (operands[1]), QImode); }) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (and:SI (match_dup 0) (match_operand:SI 1 "const_int_qi_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "peep2_reg_dead_p (2, operands[0])" [(set (match_dup 4) (and:QI (match_dup 4) (match_dup 5))) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = gen_rtx_REG (QImode, REGNO (operands[0])); operands[5] = gen_int_mode (INTVAL (operands[1]), QImode); }) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (and:SI (match_dup 0) (match_operand:SI 1 "const_int_hi_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 3 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "peep2_reg_dead_p (2, operands[0])" [(set (match_dup 4) (and:HI (match_dup 4) (match_dup 5))) (set (cc0) (compare (match_dup 4) (const_int 0))) (set (pc) (if_then_else (match_op_dup 3 [(cc0) (const_int 0)]) (label_ref (match_dup 2)) (pc)))] { operands[4] = gen_rtx_REG (HImode, REGNO (operands[0])); operands[5] = gen_int_mode (INTVAL (operands[1]), HImode); }) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (and:SI (match_dup 0) (match_operand:SI 1 "const_int_qi_operand" ""))) (set (match_dup 0) (xor:SI (match_dup 0) (match_operand:SI 2 "const_int_qi_operand" ""))) (set (cc0) (compare (match_dup 0) (const_int 0))) (set (pc) (if_then_else (match_operator 4 "eqne_operator" [(cc0) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "peep2_reg_dead_p (3, operands[0]) && (~INTVAL (operands[1]) & INTVAL (operands[2])) == 0" [(set (match_dup 5) (and:QI (match_dup 5) (match_dup 6))) (set (match_dup 5) (xor:QI (match_dup 5) (match_dup 7))) (set (cc0) (compare (match_dup 5) (const_int 0))) (set (pc) (if_then_else (match_op_dup 4 [(cc0) (const_int 0)]) (label_ref (match_dup 3)) (pc)))] { operands[5] = gen_rtx_REG (QImode, REGNO (operands[0])); operands[6] = gen_int_mode (INTVAL (operands[1]), QImode); operands[7] = gen_int_mode (INTVAL (operands[2]), QImode); }) ;; These triggers right at the end of allocation of locals in the ;; prologue (and possibly at other places). ;; stack adjustment of -4, generate one push ;; ;; before : 6 bytes, 10 clocks ;; after : 4 bytes, 10 clocks (define_peephole2 [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:SI (reg:SI SP_REG)) (match_operand:SI 0 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] "") ;; stack adjustment of -12, generate one push ;; ;; before : 10 bytes, 14 clocks ;; after : 8 bytes, 14 clocks (define_peephole2 [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -12))) (set (mem:SI (reg:SI SP_REG)) (match_operand:SI 0 "register_operand" ""))] "(TARGET_H8300H || TARGET_H8300S) && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG" [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) (set (mem:SI (pre_dec:SI (reg:SI SP_REG))) (match_dup 0))] "") ;; Transform ;; ;; mov dst,reg ;; op src,reg ;; mov reg,dst ;; ;; into ;; ;; op src,dst ;; ;; if "reg" dies at the end of the sequence. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "memory_operand" "")) (set (match_dup 0) (match_operator 2 "h8sx_binary_memory_operator" [(match_dup 0) (match_operand 3 "h8300_src_operand" "")])) (set (match_operand 4 "memory_operand" "") (match_dup 0))] "0 /* Disable because it breaks compiling fp-bit.c. */ && TARGET_H8300SX && peep2_reg_dead_p (3, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[3]) && !reg_overlap_mentioned_p (operands[0], operands[4]) && h8sx_mergeable_memrefs_p (operands[4], operands[1])" [(set (match_dup 4) (match_dup 5))] { operands[5] = shallow_copy_rtx (operands[2]); XEXP (operands[5], 0) = operands[1]; }) ;; Transform ;; ;; mov src,reg ;; op reg,dst ;; ;; into ;; ;; op src,dst ;; ;; if "reg" dies in the second insn. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "h8300_src_operand" "")) (set (match_operand 2 "h8300_dst_operand" "") (match_operator 3 "h8sx_binary_memory_operator" [(match_operand 4 "h8300_dst_operand" "") (match_dup 0)]))] "0 /* Disable because it breaks compiling fp-bit.c. */ && TARGET_H8300SX && peep2_reg_dead_p (2, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[4])" [(set (match_dup 2) (match_dup 5))] { operands[5] = shallow_copy_rtx (operands[3]); XEXP (operands[5], 1) = operands[1]; }) ;; Transform ;; ;; mov dst,reg ;; op reg ;; mov reg,dst ;; ;; into ;; ;; op dst ;; ;; if "reg" dies at the end of the sequence. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "memory_operand" "")) (set (match_dup 0) (match_operator 2 "h8sx_unary_memory_operator" [(match_dup 0)])) (set (match_operand 3 "memory_operand" "") (match_dup 0))] "TARGET_H8300SX && peep2_reg_dead_p (3, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[3]) && h8sx_mergeable_memrefs_p (operands[3], operands[1])" [(set (match_dup 3) (match_dup 4))] { operands[4] = shallow_copy_rtx (operands[2]); XEXP (operands[4], 0) = operands[1]; }) ;; Transform ;; ;; mov src1,reg ;; cmp reg,src2 ;; ;; into ;; ;; cmp src1,src2 ;; ;; if "reg" dies in the comparison. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "h8300_dst_operand" "")) (set (cc0) (compare (match_dup 0) (match_operand 2 "h8300_src_operand" "")))] "TARGET_H8300SX && peep2_reg_dead_p (2, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[2]) && operands[2] != const0_rtx" [(set (cc0) (compare (match_dup 1) (match_dup 2)))]) ;; Likewise for the second operand. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "h8300_src_operand" "")) (set (cc0) (compare (match_operand 2 "h8300_dst_operand" "") (match_dup 0)))] "TARGET_H8300SX && peep2_reg_dead_p (2, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[2])" [(set (cc0) (compare (match_dup 2) (match_dup 1)))]) ;; Combine two moves. (define_peephole2 [(set (match_operand 0 "register_operand" "") (match_operand 1 "h8300_src_operand" "")) (set (match_operand 2 "h8300_dst_operand" "") (match_dup 0))] "TARGET_H8300SX && peep2_reg_dead_p (2, operands[0]) && !reg_overlap_mentioned_p (operands[0], operands[2])" [(set (match_dup 2) (match_dup 1))])