diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index 8355ac82f0a..5c5c3ae69d0 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -1,5 +1,8 @@ -;;- Machine description for the Hitachi H8/300 for the GNU C compiler -;; Copyright (C) 1992, 1993 Free Software Foundation, Inc. +;; GCC machine description for Hitachi H8/300 +;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. + +;; Contributed by Steve Chamberlain (sac@cygnus.com), +;; Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com). ;; This file is part of GNU CC. @@ -23,6 +26,12 @@ ;; See file "rtl.def" for documentation on define_insn, match_*, et. al. +(define_attr "cpu" "h8300,h8300h" + (const (symbol_ref "cpu_type"))) + +;; ??? If we can remove the operand type on all the insns, do it. +;; ??? Otherwise, try to have the operand type on all the insns. + (define_attr "type" "branch,return,call,arith,move,float,multi" (const_string "arith")) @@ -31,53 +40,119 @@ (define_attr "length" "" (cond [(eq_attr "type" "branch") (if_then_else (and (ge (minus (pc) (match_dup 0)) - (const_int -128)) + (const_int -120)) (le (minus (pc) (match_dup 0)) - (const_int 128))) + (const_int 120))) (const_int 2) - (const_int 6)) + (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" "move") (const_int 4) (eq_attr "type" "return") (const_int 2) (eq_attr "type" "float") (const_int 12) (eq_attr "type" "call") (const_int 4)] (const_int 200))) - -(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops" +(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops,cbit" (const_string "whoops")) - + ;; ---------------------------------------------------------------------- -;; move instructions +;; MOVE INSTRUCTIONS ;; ---------------------------------------------------------------------- +;; movqi + +(define_insn "movqi_push" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "register_operand" "r"))] + "" + "* +{ + if (TARGET_H8300) + return \"push.w %T1\"; + else + return \"push.l %S1\"; +}" + [(set_attr "type" "move") + (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))) + (set_attr "cc" "set")]) + +(define_insn "movqi_internal" + [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<,r") + (match_operand:QI 1 "general_operand_src" "I,r>,io,r,r,c"))] + "register_operand (operands[0],QImode) || register_operand (operands[1], QImode)" + "@ + sub.b %X0,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0 + xor %X0,%X0\;bst #0,%X0" + [(set_attr "type" "move") + (set_attr_alternative "length" + [(const_int 2) (const_int 2) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)) + (const_int 4)]) + (set_attr "cc" "set,set,set,set,set,none")]) + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand_dst" "") + (match_operand:QI 1 "general_operand_src" ""))] + "" + " +{ + /* One of the ops has to be in a register */ + if (!register_operand(operand0, QImode) + && !register_operand(operand1, QImode)) + { + operands[1] = copy_to_mode_reg(QImode, operand1); + } +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<")) + (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))] + "" + "@ + sub.b %X0,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0 + mov.b %X1,%X0" + [(set_attr "type" "move") + (set_attr_alternative "length" + [(const_int 2) (const_int 2) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))]) + (set_attr "cc" "set")]) + ;; movhi -(define_insn "" +(define_insn "movhi_push" [(set (match_operand:HI 0 "push_operand" "=<") (match_operand:HI 1 "register_operand" "ra"))] "" - "mov.w %T1,%T0" + "* +{ + if (TARGET_H8300) + return \"push.w %T1\"; + else + return \"push.l %S1\"; +}" [(set_attr "type" "move") - (set_attr "length" "2") + (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))) (set_attr "cc" "set")]) -(define_insn "movstricthi" - [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,o,<")) - (match_operand:HI 1 "general_operand_src" "I,r,io,r,r"))] - "" - "@ - sub.w %T0,%T0 - mov.w %T1,%T0 - mov.w %T1,%T0 - mov.w %T1,%T0 - mov.w %T1,%T0" - [(set_attr "type" "move") - (set_attr "length" "2,2,4,4,2") - (set_attr "cc" "set")]) - -(define_insn "" +(define_insn "movhi_internal" [(set (match_operand:HI 0 "general_operand_dst" "=ra,ra,ra,o,<") - (match_operand:HI 1 "general_operand_src" "I,ra,ion,ra,ra"))] + (match_operand:HI 1 "general_operand_src" "I,ra>,ion,ra,ra"))] "" "@ sub.w %T0,%T0 @@ -86,7 +161,11 @@ mov.w %T1,%T0 mov.w %T1,%T0" [(set_attr "type" "move") - (set_attr "length" "2,2,4,4,2") + (set_attr_alternative "length" + [(const_int 2) (const_int 2) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))]) (set_attr "cc" "set")]) (define_expand "movhi" @@ -95,262 +174,289 @@ "" " { - /* One of the ops has to be in a register. */ - if (! register_operand (operand1, HImode) - && ! register_operand (operand0, HImode)) - operands[1] = copy_to_mode_reg (HImode, operand1); + /* One of the ops has to be in a register */ + if (!register_operand(operand1, HImode) + && !register_operand(operand0, HImode)) + { + operands[1] = copy_to_mode_reg(HImode, operand1); + } }") -(define_insn "" - [(set (match_operand:HI 0 "register_operand" "=&ra") - (plus:HI (match_operand:HI 1 "general_operand_src" "g") - (match_operand:HI 2 "register_operand" "ra")))] - "" - "mov.w %T1,%T0\;add.w %T2,%T0" - [(set_attr "type" "arith") - (set_attr "length" "6") - (set_attr "cc" "set")]) - -;; movqi - -(define_insn "" - [(set (match_operand:QI 0 "push_operand" "=<") - (match_operand:QI 1 "register_operand" "r"))] - "" - "mov.w %T1,%T0" - [(set_attr "type" "move") - (set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_insn "movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<")) - (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))] +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "=r,r,r,o,<")) + (match_operand:HI 1 "general_operand_src" "I,r,io,r,r"))] "" "@ - sub.b %X0,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0" + sub.w %T0,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0" [(set_attr "type" "move") - (set_attr "length" "2,2,4,4,2") + (set_attr_alternative "length" + [(const_int 2) (const_int 2) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8)) + (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))]) (set_attr "cc" "set")]) -(define_insn "" - [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<") - (match_operand:QI 1 "general_operand_src" "I,r,io,r,r"))] - "" - "@ - sub.b %X0,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0 - mov.b %X1,%X0" - [(set_attr "type" "move") - (set_attr "length" "2,2,4,4,2") - (set_attr "cc" "set")]) - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand_dst" "") - (match_operand:QI 1 "general_operand_src" ""))] - "" - " -{ - /* One of the ops has to be in a register. */ - if (! register_operand (operand0, QImode) - && ! register_operand (operand1, QImode)) - operands[1] = copy_to_mode_reg (QImode, operand1); -}") - ;; movsi -(define_insn "" - [(set (match_operand:SI 0 "general_operand_dst" "=l,l,l,o,<") - (match_operand:SI 1 "general_operand_src" "I,l,ion,l,l"))] - "" - "* -{ - int rn = -1; - switch (which_alternative) - { - case 0: - return \"sub.w %e0,%e0\;sub.w %f0,%f0\"; - case 1: - return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; - 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 - 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\"; - } -}" - [(set_attr "type" "move") - (set_attr "length" "4,4,8,8,4") - (set_attr "cc" "clobber")]) - -(define_insn "" - [(set (match_operand:SI 0 "push_operand" "=<") - (match_operand:SI 1 "register_operand" "l"))] - "" - "mov.w %f1,%T0\;mov.w %e1,%T0" - [(set_attr "type" "move") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - (define_expand "movsi" [(set (match_operand:SI 0 "general_operand_dst" "") (match_operand:SI 1 "general_operand_src" ""))] - "" - "if (domovsi (operands)) DONE;") - -(define_insn "" - [(set (match_operand:SF 0 "general_operand_dst" "=l,l,l,o,<") - (match_operand:SF 1 "general_operand_src" "I,l,ion,l,l"))] "" + " +{ + if (TARGET_H8300) + { + if (do_movsi (operands)) + DONE; + } + else /* TARGET_H8300H */ + { + /* One of the ops has to be in a register. */ + if (!register_operand (operand1, SImode) + && !register_operand (operand0, SImode)) + { + operands[1] = copy_to_mode_reg (SImode, operand1); + } + } +}") + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand_dst" "") + (match_operand:SF 1 "general_operand_src" ""))] + "" + " +{ + if (TARGET_H8300) + { + if (do_movsi (operands)) + DONE; + } + else /* TARGET_H8300H */ + { + /* One of the ops has to be in a register. */ + if (!register_operand (operand1, SFmode) + && !register_operand (operand0, SFmode)) + { + operands[1] = copy_to_mode_reg (SFmode, operand1); + } + } +}") + +(define_insn "movsi_h8300" + [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,o,<,r") + (match_operand:SI 1 "general_operand_src" "I,r,ion,r,r,>"))] + "TARGET_H8300 + && (register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" "* { - /* This is a copy of the movsi stuff. */ int rn = -1; switch (which_alternative) { case 0: return \"sub.w %e0,%e0\;sub.w %f0,%f0\"; case 1: - return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; + 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) + if (GET_CODE(operands[1]) == MEM) { - rtx inside = XEXP (operands[1], 0); - if (REG_P (inside)) - rn = REGNO (inside); + 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); + 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\"; + if (rn == REGNO (operands[0])) + { + /* Move the second word first. */ + return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; + } else - return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; + { + return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; + } case 3: return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; case 4: return \"mov.w %f1,%T0\;mov.w %e1,%T0\"; - } + case 5: + return \"mov.w %T1,%e0\;mov.w %T1,%f0\"; + } }" [(set_attr "type" "move") - (set_attr "length" "4,4,8,8,4") + (set_attr "length" "4,4,8,8,4,4") (set_attr "cc" "clobber")]) -(define_insn "" - [(set (match_operand:SF 0 "push_operand" "=<") - (match_operand:SF 1 "register_operand" "l"))] - "" - "mov.w %f1,%T0\;mov.w %e1,%T0" - [(set_attr "type" "move") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand_dst" "") - (match_operand:SF 1 "general_operand_src" ""))] - "" - "if (domovsi (operands)) DONE;") - -;; Block move - -(define_expand "movstrhi" - [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) - (mem:BLK (match_operand:BLK 1 "general_operand" ""))) - (use (match_operand:HI 2 "general_operand" "")) - (use (match_operand:HI 3 "immediate_operand" "")) - (clobber (match_dup 3)) - ])] - "" - " +(define_insn "movsf_h8300" + [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r") + (match_operand:SF 1 "general_operand_src" "I,r,ion,r,r,>"))] + "TARGET_H8300 + && (register_operand (operands[0], SFmode) + || register_operand (operands[1], SFmode))" + "* { - rtx src_ptr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); - rtx dst_ptr = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + /* Copy of the movsi stuff */ + int rn = -1; + switch (which_alternative) + { + case 0: + return \"sub.w %e0,%e0\;sub.w %f0,%f0\"; + case 1: + if (REGNO(operands[0]) < REGNO(operands[1])) + return \"mov.w %e1,%e0\;mov.w %f1,%f0\"; + else + return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; + case 2: + /* Make sure we don't trample the register we index with. */ + + if (GET_CODE (operands[1]) == MEM) + { + rtx inside = XEXP (operands[1],0); + if (REG_P (inside)) + { + rn = REGNO (inside); + } + else if (GET_CODE (inside) == PLUS) + { + rtx lhs = XEXP (inside,0); + rtx rhs = XEXP (inside,1); + if (REG_P (lhs)) rn = REGNO (lhs); + if (REG_P (rhs)) rn = REGNO (rhs); + } + } + if (rn == REGNO (operands[0])) + { + /* move the second word first */ + return \"mov.w %f1,%f0\;mov.w %e1,%e0\"; + } + else + { + 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\"; - enum machine_mode mode = INTVAL (operands[3]) >=2 ? HImode : QImode; - rtx tmpreg = gen_reg_rtx (mode); - rtx increment = mode == QImode ? const1_rtx : const2_rtx; - rtx length = operands[2]; - rtx label = gen_label_rtx (); - rtx end_src_ptr = gen_reg_rtx (Pmode); + } +}" + [(set_attr "type" "move") + (set_attr "length" "4,4,8,8,4,4") + (set_attr "cc" "clobber")]) - emit_insn (gen_rtx (SET, VOIDmode, end_src_ptr, - gen_rtx (PLUS, Pmode, src_ptr, length))); +(define_insn "movsi_h8300h" + [(set (match_operand:SI 0 "general_operand_dst" "=ra,ra,ra,o,<,ra") + (match_operand:SI 1 "general_operand_src" "I,ra,ion,ra,ra,>"))] + "TARGET_H8300H + && (register_operand (operands[0], SImode) + || register_operand (operands[1], SImode))" + "@ + 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 "type" "move") + (set_attr "length" "2,2,8,8,4,4") + (set_attr "cc" "set")]) - emit_label (label); - emit_move_insn (tmpreg, gen_rtx (MEM, mode, src_ptr)); - emit_move_insn (gen_rtx (MEM, mode, dst_ptr), tmpreg); - emit_insn (gen_rtx (SET, VOIDmode, src_ptr, - gen_rtx (PLUS, Pmode, src_ptr, increment))); - emit_insn (gen_rtx (SET, VOIDmode, dst_ptr, - gen_rtx (PLUS, Pmode, dst_ptr, increment))); +(define_insn "movsf_h8300h" + [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<") + (match_operand:SF 1 "general_operand_src" "I,r,ion,r,r"))] + "TARGET_H8300H + && (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" + [(set_attr "type" "move") + (set_attr "length" "2,2,8,8,4") + (set_attr "cc" "set")]) - emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, - gen_rtx (COMPARE, HImode, src_ptr, end_src_ptr))); - emit_jump_insn (gen_bne (label)); - - DONE; -} -") - ;; ---------------------------------------------------------------------- -;; Test instructions +;; TEST INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "tstqi" - [(set (cc0) - (match_operand:QI 0 "register_operand" "ra"))] + [(set (cc0) (match_operand:QI 0 "register_operand" "ra"))] "" - "cmp.b #0,%X0" + "* +{ + /* ??? I don't think this is right. --Jim */ + if (cc_prev_status.flags & CC_DONE_CBIT) + return \"btst #0,%X0\"; + else + return \"cmp.b #0,%X0\"; +}" [(set_attr "type" "arith") - (set_attr "length" "2") + (set_attr "length" "4") (set_attr "cc" "set")]) (define_insn "tsthi" - [(set (cc0) - (match_operand:HI 0 "register_operand" "ra"))] + [(set (cc0) (match_operand:HI 0 "general_operand" "ra"))] "" - "mov.w %T0,%T0" + "* +{ + /* ??? I don't think this is right. --Jim */ + if (cc_prev_status.flags & CC_DONE_CBIT) + return \"btst #0,%0l\"; + else + return \"mov.w %T0,%T0\"; +}" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "cc" "set")]) + +(define_insn "tstsi" + [(set (cc0) (match_operand:SI 0 "general_operand" "ra"))] + "TARGET_H8300H" + "* +{ + /* ??? I don't think this is right. --Jim */ + if (cc_prev_status.flags & CC_DONE_CBIT) + return \"btst #0,%0l\"; + else + return \"mov.l %S0,%S0\"; +}" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "cc" "set")]) + +(define_insn "cmpqi" + [(set (cc0) + (compare:QI (match_operand:QI 0 "register_operand" "ra") + (match_operand:QI 1 "nonmemory_operand" "rai")))] + "" + "cmp.b %X1,%X0" [(set_attr "type" "arith") (set_attr "length" "2") - (set_attr "cc" "set")]) + (set_attr "cc" "compare")]) + +;; ??? 300h can have an immediate operand here. (define_insn "cmphi" [(set (cc0) @@ -362,46 +468,21 @@ (set_attr "length" "2") (set_attr "cc" "compare")]) -(define_insn "cmpqi" +;; ??? 300h can have an immediate operand here. + +(define_insn "cmpsi" [(set (cc0) - (compare:QI (match_operand:QI 0 "register_operand" "ra") - (match_operand:QI 1 "nonmemory_operand" "rai")))] - "" - "cmp.b %X1,%X0" + (compare:SI (match_operand:SI 0 "register_operand" "ra") + (match_operand:SI 1 "register_operand" "ra")))] + "TARGET_H8300H" + "cmp.l %S1,%S0" [(set_attr "type" "arith") (set_attr "length" "2") (set_attr "cc" "compare")]) - -;; ---------------------------------------------------------------------- -;; Add instructions -;; ---------------------------------------------------------------------- -(define_insn "" - [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra") - (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0") - (match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))] - "" - "@ - adds %T2,%T0 - adds #2,%T0\;adds %C2,%T0 - subs %M2,%T0 - subs #2,%T0\;subs %M2,%T0 - add.b %s2,%s0\;addx %t2,%t0 - add.w %T2,%T0" - [(set_attr "type" "multi,multi,multi,multi,multi,arith") - (set_attr "length" "2,4,2,4,4,2") - (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")]) - -(define_expand "addhi3" - [(set (match_operand:HI 0 "register_operand" "") - (plus:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "nonmemory_operand" "")))] - "" - " -{ - if (operands[0] != operands[1]) - emit_move_insn (operands[0], operands[1]); -}") +;; ---------------------------------------------------------------------- +;; ADD INSTRUCTIONS +;; ---------------------------------------------------------------------- (define_insn "addqi3" [(set (match_operand:QI 0 "register_operand" "=r") @@ -413,60 +494,77 @@ (set_attr "length" "2") (set_attr "cc" "set")]) -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "nonmemory_operand" "l,n"))) - (clobber (match_operand:HI 3 "register_operand" "=&l,l"))] - "" - "@ - add %w2,%w0\;addx %x2,%x0\;addx %y2,%y0\;addx %z2,%z0 - add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0" - [(set_attr "type" "multi") - (set_attr "length" "8,6") - (set_attr "cc" "clobber")]) +;; ??? adds operates on the 32bit register. We can use it because we don't +;; use the e0-7 registers. +;; ??? 4 can be handled in one insn on the 300h. -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "nonmemory_operand" "n,r")))] +(define_insn "addhi3_internal" + [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra") + (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))] "" "@ - add %w2,%w0\;addx %x2,%x0\;addx %y2,%y0\;addx %z2,%z0 - add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0" - [(set_attr "type" "arith") - (set_attr "length" "8,6") - (set_attr "cc" "clobber")]) + adds %T2,%A0 + adds #2,%A0\;adds %C2,%A0 + subs %M2,%A0 + subs #2,%A0\;subs %M2,%A0 + add.b %s2,%s0\;addx %t2,%t0 + add.w %T2,%T0" + [(set_attr "type" "arith,multi,arith,multi,multi,arith") + (set_attr "length" "2,4,2,4,4,2") + (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")]) + +;; ??? Why is this here? +(define_expand "addhi3" + [(set (match_operand:HI 0 "register_operand" "") + (plus:HI (match_operand:HI 1 "register_operand" "") + (match_operand:HI 2 "nonmemory_operand" "")))] + "" + "") (define_expand "addsi3" - [(set (match_dup 3) (match_operand:SI 1 "register_operand" "")) - (set (match_dup 3) - (plus:SI (match_dup 3) - (match_operand:SI 2 "nonmemory_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") (match_dup 3))] + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] "" - " -{ - operands[3] = gen_rtx (REG, SImode, 0); -}") - -;; ----------------------------------------------------------------------; -;; Subtract instructions -;; ---------------------------------------------------------------------- + "") -(define_insn "" - [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r") - (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") - (match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))] - "" +(define_insn "addsi_h8300" + [(set (match_operand:SI 0 "register_operand" "=r,r,&r") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" "n,r,r")))] + "TARGET_H8300" "@ - subs %T2,%T0 - subs #2,%T0\;subs %E2,%T0 - sub.w %T2,%T0 - add.b %E2,%s0\;addx %F2,%t0 ; -%0" - [(set_attr "type" "multi") - (set_attr "length" "2,4,2,4") - (set_attr "cc" "none_0hit,none_0hit,set,clobber")]) + add %w2,%w0\;addx %x2,%x0\;addx %y2,%y0\;addx %z2,%z0 + add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0 + mov %f1,%f0\;mov %e1,%e0\;add.w %f2,%f0\;addx %y2,%y0\;addx %z2,%z0" + [(set_attr "type" "arith") + (set_attr "length" "8,6,20") + (set_attr "cc" "clobber")]) + +;; ??? 4 can be handled in one insn on the 300h. +;; ??? Should the 'n' constraint be 'i' here? +;; ??? We don't handle (reg + symbol_ref) which the 300h can handle. + +(define_insn "addsi_h8300h" + [(set (match_operand:SI 0 "register_operand" "=ra,ra,ra,ra,r,ra") + (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "nonmemory_operand" "K,M,L,N,n,ra")))] + "TARGET_H8300H" + "@ + adds %S2,%S0 + adds #2,%S0\;adds %C2,%S0 + subs %M2,%S0 + subs #2,%S0\;subs %M2,%S0 + add.l %S2,%S0 + add.l %S2,%S0" + [(set_attr "type" "multi,multi,multi,multi,arith,arith") + (set_attr "length" "2,4,2,4,6,2") + (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,clobber")]) + +;; ---------------------------------------------------------------------- +;; SUBTRACT INSTRUCTIONS +;; ---------------------------------------------------------------------- (define_insn "subqi3" [(set (match_operand:QI 0 "register_operand" "=r,r") @@ -480,52 +578,115 @@ (set_attr "length" "2") (set_attr "cc" "set")]) +;; ??? subs operates on the 32bit register. We can use it because we don't +;; use the e0-7 registers. +;; ??? 4 can be handled in one insn on the 300h. +;; ??? The fourth alternative can use sub.w on the 300h. +;; ??? Should the 'n' constraint be an 'i' here? + +(define_insn "subhi3_internal" + [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") + (match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))] + "" + "@ + subs %T2,%T0 + subs #2,%T0\;subs %M2,%T0 + sub.w %T2,%T0 + add.b %E2,%s0\;addx %F2,%t0 ; -%0" + [(set_attr "type" "multi") + (set_attr "length" "2,4,2,4") + (set_attr "cc" "none_0hit,none_0hit,set,clobber")]) + +;; ??? Why is this here? (define_expand "subhi3" [(set (match_operand:HI 0 "register_operand" "") (minus:HI (match_operand:HI 1 "register_operand" "") (match_operand:HI 2 "nonmemory_operand" "")))] "" - " -{ - if (operands[0] != operands[1]) - emit_move_insn (operands[0], operands[1]); -}") + "") -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=l") - (minus:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "register_operand" "l")))] +(define_expand "subsi3" + [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] "" + "") + +(define_insn "subsi3_h8300" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_H8300" "sub.w %f2,%f0\;subx %y2,%y0\;subx %z2,%z0" [(set_attr "type" "arith") (set_attr "length" "6") (set_attr "cc" "clobber")]) -(define_expand "subsi3" - [(set (match_dup 3) (match_operand:SI 1 "register_operand" "")) - (set (match_dup 3) - (minus:SI (match_dup 3) - (match_operand:SI 2 "nonmemory_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") (match_dup 3))] - "" - "operands[3] = gen_rtx (REG, SImode, 0);") +;; ??? 4 can be handled in one insn on the 300h. + +(define_insn "subsi3_h8300h" + [(set (match_operand:SI 0 "register_operand" "=ra,ra,ra,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") + (match_operand:SI 2 "nonmemory_operand" "K,M,ra,n")))] + "TARGET_H8300H" + "@ + subs %T2,%T0 + subs #2,%T0\;subs %E2,%T0 + sub.l %S2,%S0 + sub.l %S2,%S0" + [(set_attr "type" "multi") + (set_attr "length" "2,4,2,6") + (set_attr "cc" "none_0hit,none_0hit,set,set")]) ;; ---------------------------------------------------------------------- -;; Multiply instruction +;; MULTIPLY INSTRUCTIONS ;; ---------------------------------------------------------------------- +;; Note that the h8/300 can only handle umulqihi3. + +(define_insn "mulqihi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%0")) + (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))] + "TARGET_H8300H" + "mulxs.b %X2,%T0" + [(set_attr "type" "multi") + (set_attr "length" "4") + (set_attr "cc" "set")]) + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "%0")) + (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] + "TARGET_H8300H" + "mulxs.w %T2,%S0" + [(set_attr "type" "multi") + (set_attr "length" "4") + (set_attr "cc" "set")]) + (define_insn "umulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") - (mult:HI (match_operand:QI 1 "general_operand" "%0") - (match_operand:QI 2 "register_operand" "r")))] + (mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%0")) + (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))] "" "mulxu %X2,%T0" [(set_attr "type" "multi") (set_attr "length" "2") (set_attr "cc" "none_0hit")]) +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "%0")) + (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] + "TARGET_H8300H" + "mulxu.w %T2,%S0" + [(set_attr "type" "multi") + (set_attr "length" "2") + (set_attr "cc" "none_0hit")]) + ;; ---------------------------------------------------------------------- -;; Divide instructions +;; DIVIDE INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "udivqi3" @@ -538,6 +699,8 @@ (set_attr "length" "2") (set_attr "cc" "clobber")]) +;; ??? Will divxu always work here? + (define_insn "divqi3" [(set (match_operand:QI 0 "register_operand" "=r") (div:QI (match_operand:HI 1 "general_operand" "0") @@ -547,85 +710,286 @@ [(set_attr "type" "multi") (set_attr "length" "2") (set_attr "cc" "clobber")]) - + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "register_operand" "r")))] + "TARGET_H8300H" + "divxu.w %T2,%S0" + [(set_attr "type" "multi") + (set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "divhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "register_operand" "r")))] + "TARGET_H8300H" + "divxs.w %T2,%S0" + [(set_attr "type" "multi") + (set_attr "length" "4") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; And instructions +;; MOD INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_insn "andqi3" - [(set (match_operand:QI 0 "general_operand" "=r") - (and:QI (match_operand:QI 1 "general_operand" "%0") - (match_operand:QI 2 "general_operand" "rn")))] +(define_insn "umodqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (umod:QI (match_operand:HI 1 "general_operand" "0") + (match_operand:QI 2 "register_operand" "r")))] "" - "and %X2,%X0" + "divxu %X2,%T0\;mov %t0,%s0" + [(set_attr "type" "multi") + (set_attr "length" "4") + (set_attr "cc" "clobber")]) + +(define_insn "modqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (mod:QI (match_operand:HI 1 "general_operand" "0") + (match_operand:QI 2 "register_operand" "r")))] + "TARGET_H8300H" + "divxs.b %X2,%T0\;mov %t0,%s0" + [(set_attr "type" "multi") + (set_attr "length" "6") + (set_attr "cc" "clobber")]) + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "register_operand" "r")))] + "TARGET_H8300H" + "divxu.w %T2,%S0\;mov %e0,%f0" + [(set_attr "type" "multi") + (set_attr "length" "4") + (set_attr "cc" "clobber")]) + +(define_insn "modhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "register_operand" "r")))] + "TARGET_H8300H" + "divxs.w %T2,%S0\;mov %e0,%f0" + [(set_attr "type" "multi") + (set_attr "length" "6") + (set_attr "cc" "clobber")]) + +;; ---------------------------------------------------------------------- +;; AND INSTRUCTIONS +;; ---------------------------------------------------------------------- + +(define_insn "andqi3_internal" + [(set (match_operand:QI 0 "bit_operand" "=r,U") + (and:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "rn,O")))] + "register_operand (operands[0], QImode) || o_operand (operands[2], QImode)" + "@ + and %X2,%X0 + bclr %W2,%X0" [(set_attr "type" "arith") - (set_attr "length" "2") - (set_attr "cc" "set")]) + (set_attr "length" "2,4") + (set_attr "cc" "set,none_0hit")]) + +(define_expand "andqi3" + [(set (match_operand:QI 0 "bit_operand" "=r,U") + (and:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "rn,O")))] + "" + " +{ + if (fix_bit_operand (operands, 'O', AND)) + DONE; +}") + +;; ??? Should have a bclr case here also. (define_insn "andhi3" [(set (match_operand:HI 0 "register_operand" "=r") (and:HI (match_operand:HI 1 "register_operand" "%0") - (match_operand:HI 2 "general_operand" "ri")))] + (match_operand:HI 2 "nonmemory_operand" "ri")))] "" - "and %s2,%s0\;and %t2,%t0" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if ((i & 0x00ff) != 0x00ff) + output_asm_insn (\"and %s2,%s0\", operands); + if ((i & 0xff00) != 0xff00) + output_asm_insn (\"and %t2,%t0\", operands); + return \"\"; + } + return \"and %s2,%s0\;and %t2,%t0;\"; +}" [(set_attr "type" "multi") (set_attr "length" "4") (set_attr "cc" "clobber")]) - + +;; ??? There is an iorsi3 for TARGET_H8300. Should we have andsi3? + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "r,i")))] + "TARGET_H8300H" + "@ + and %S2,%S0 + and %S2,%S0" + [(set_attr "type" "arith") + (set_attr "length" "4,6") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; Or instructions +;; OR INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_insn "iorqi3" - [(set (match_operand:QI 0 "general_operand" "=r,U") - (ior:QI (match_operand:QI 1 "general_operand" "%0,0") - (match_operand:QI 2 "general_operand" "rn,P")))] - "" +(define_insn "iorqi3_internal" + [(set (match_operand:QI 0 "bit_operand" "=U,r") + (ior:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "P,rn")))] + "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)" "@ - or %X2,%X0 - bset %V2,%X0" + bset %V2,%X0 + or %X2,%X0" [(set_attr "type" "arith") - (set_attr "length" "2,4") - (set_attr "cc" "set,none_0hit")]) + (set_attr "length" "4,2") + (set_attr "cc" "none_0hit,set")]) + +(define_expand "iorqi3" + [(set (match_operand:QI 0 "bit_operand" "=r,U") + (ior:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "rn,P")))] + "" + " +{ + if (fix_bit_operand (operands, 'P', IOR)) + DONE; +}") + +;; ??? Should have a bset case here also. (define_insn "iorhi3" [(set (match_operand:HI 0 "general_operand" "=r,r") (ior:HI (match_operand:HI 1 "general_operand" "%0,0") (match_operand:HI 2 "general_operand" "J,ri")))] "" - "@ - or %s2,%s0 - or %s2,%s0\;or %t2,%t0" + "* +{ + if (TARGET_H8300) + { + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if ((i & 0x00ff) != 0) + output_asm_insn (\"or %s2,%s0\", operands); + if ((i & 0xff00) != 0) + output_asm_insn (\"or %t2,%t0\", operands); + return \"\"; + } + return \"or %s2,%s0\;or %t2,%t0; %2 or2\"; + } + else + { + return \"or %S2,%S0\"; + } +}" [(set_attr "type" "multi") (set_attr "length" "2,4") (set_attr "cc" "clobber,clobber")]) - + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "nonmemory_operand" "ri")))] + "" + "* +{ + if (TARGET_H8300) + { + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if ((i & 0x000000ff) != 0) + output_asm_insn (\"or %w2,%w0\", operands); + if ((i & 0x0000ff00) != 0) + output_asm_insn (\"or %x2,%x0\", operands); + if ((i & 0x00ff0000) != 0) + output_asm_insn (\"or %y2,%y0\", operands); + if ((i & 0xff000000) != 0) + output_asm_insn (\"or %z2,%z0\", operands); + return \"\"; + } + return \"or %w2,%w0\;or %x2,%x0\;or %y2,%y0\;or %z2,%z0\;\"; + } + else + { + return \"or %S2,%S0\"; + } +}" + [(set_attr "type" "multi") + (set_attr "length" "8") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; Xor instructions +;; XOR INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_insn "xorqi3" - [(set (match_operand:QI 0 "general_operand" "=r") - (xor:QI (match_operand:QI 1 "general_operand" "%0") - (match_operand:QI 2 "nonmemory_operand" "ri")))] - "" - "xor %X2,%X0" +(define_insn "xorqi3_internal" + [(set (match_operand:QI 0 "bit_operand" "=r,U") + (xor:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "rn,P")))] + "register_operand (operands[0], QImode) || p_operand (operands[2], QImode)" + "@ + xor %X2,%X0 + bnot %V2,%X0" [(set_attr "type" "arith") - (set_attr "length" "2") - (set_attr "cc" "set")]) + (set_attr "length" "2,4") + (set_attr "cc" "set,none_0hit")]) + +(define_expand "xorqi3" + [(set (match_operand:QI 0 "bit_operand" "=r,U") + (xor:QI (match_operand:QI 1 "bit_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "rn,O")))] + "" + " +{ + if (fix_bit_operand (operands, 'O', XOR)) + DONE; +}") (define_insn "xorhi3" - [(set (match_operand:HI 0 "general_operand" "=r") + [(set (match_operand:HI 0 "register_operand" "=r") (xor:HI (match_operand:HI 1 "general_operand" "%0") (match_operand:HI 2 "nonmemory_operand" "ri")))] "" - "xor %s2,%s0\;xor %t2,%t0" + "* +{ + if (TARGET_H8300) + return \"xor %s2,%s0\;xor %t2,%t0\"; + else + return \"xor %S2,%S0\"; +}" [(set_attr "type" "multi") (set_attr "length" "4") (set_attr "cc" "clobber")]) - + +;; ??? There is an iorsi3 for TARGET_H8300. Should we have xorsi3? + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "r,i")))] + "TARGET_H8300H" + "@ + xor %S2,%S0 + xor %S2,%S0" + [(set_attr "type" "arith") + (set_attr "length" "4,6") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; Negation instructions +;; NEGATION INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "negqi2" @@ -635,28 +999,72 @@ "neg %X0" [(set_attr "type" "arith") (set_attr "length" "2") - (set_attr "cc" "set")]) + (set_attr "cc" "clobber")]) (define_expand "neghi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + " +{ + 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" "r"))) (set (match_dup 2) (plus:HI (match_dup 2) (const_int 1))) (set (match_operand:HI 0 "register_operand" "=r") (match_dup 2))] "" - "operands[2] = gen_reg_rtx (HImode);") + "{ operands[2] = gen_reg_rtx (HImode); }") + +(define_insn "neghi2_h8300h" + [(set (match_operand:HI 0 "register_operand" "=r") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "TARGET_H8300H" + "neg %T0" + [(set_attr "type" "arith") + (set_attr "length" "2") + (set_attr "cc" "clobber")]) (define_expand "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + " +{ + 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" "r"))) (set (match_dup 2) (plus:SI (match_dup 2) (const_int 1))) (set (match_operand:SI 0 "register_operand" "=r") (match_dup 2))] "" - "operands[2] = gen_reg_rtx (SImode);") - + "{ operands[2] = gen_reg_rtx(SImode); }") + +(define_insn "negsi2_h8300h" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "TARGET_H8300H" + "neg %S0" + [(set_attr "type" "arith") + (set_attr "length" "2") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; Not instructions +;; NOT INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "one_cmplqi2" @@ -672,7 +1080,13 @@ [(set (match_operand:HI 0 "register_operand" "=r") (not:HI (match_operand:HI 1 "general_operand" "0")))] "" - "not %s0\;not %t0" + "* +{ + if (TARGET_H8300) + return \"not %s0\;not %t0\"; + else + return \"not %T0\"; +}" [(set_attr "type" "arith") (set_attr "length" "4") (set_attr "cc" "clobber")]) @@ -681,15 +1095,24 @@ [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "general_operand" "0")))] "" - "not %w0\;not %x0\;not %y0\;not %z0" + "* +{ + if (TARGET_H8300) + return \"not %w0\;not %x0\;not %y0\;not %z0\"; + else + return \"not %S0\"; +}" [(set_attr "type" "arith") +;; ??? length is wrong for 300h (set_attr "length" "8") (set_attr "cc" "clobber")]) - + ;; ---------------------------------------------------------------------- -;; Conditional branches +;; JUMP INSTRUCTIONS ;; ---------------------------------------------------------------------- +;; Conditional jump instructions + (define_expand "ble" [(set (pc) (if_then_else (le (cc0) @@ -780,43 +1203,46 @@ "" "") -(define_insn "" +(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_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] "" "* { if (get_attr_length (insn) == 2) - return \"b%j1 %l0\"; + return \"b%j1 %l0\"; + else if (get_attr_length (insn) == 4) + return \"b%j1 %l0:16\"; else - return \"b%k1 %L0\;jmp @%l0\;%L0:\"; + return \"b%k1 %L0\;jmp @%l0\;%L0:\"; }" - [(set_attr "type" "branch") + [(set_attr "type" "branch") (set_attr "cc" "none")]) -(define_insn "" +(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_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] "" +;; ??? We don't take advantage of 16 bit relative jumps in the 300h. "* { if (get_attr_length (insn) == 2) - return \"b%k1 %l0\"; + return \"b%k1 %l0\"; + else if (get_attr_length (insn) == 4) + return \"b%k1 %l0:16\"; else - return \"b%j1 %L0\;jmp @%l0\;%L0:\"; + return \"b%j1 %L0\;jmp @%l0\;%L0:\"; }" [(set_attr "type" "branch") (set_attr "cc" "none")]) - -;; ---------------------------------------------------------------------- -;; Unconditional branches -;; ---------------------------------------------------------------------- + +;; Unconditional and other jump instructions. (define_insn "jump" [(set (pc) @@ -824,27 +1250,83 @@ "" "* { - if (get_attr_length (insn) == 2) - return \"bra %l0\"; + if (get_attr_length (insn) == 2) + return \"bra %l0\"; + else if (get_attr_length (insn) == 4) + return \"bra %l0:16\"; else - return \"jmp @%l0\"; + return \"jmp @%l0\"; }" [(set_attr "type" "branch") (set_attr "cc" "none")]) -(define_insn "tablejump" +;; 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" "r")) + (use (label_ref (match_operand 1 "" "")))])] + "" + "") + +(define_insn "tablejump_h8300" [(set (pc) (match_operand:HI 0 "register_operand" "")) (use (label_ref (match_operand 1 "" "")))] - "" + "TARGET_H8300" "jmp @%0" [(set_attr "type" "branch") (set_attr "cc" "none") (set_attr "length" "2")]) +(define_insn "tablejump_h8300h" + [(set (pc) (match_operand:SI 0 "register_operand" "")) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_H8300H" + "jmp @%0" + [(set_attr "type" "branch") + (set_attr "cc" "none") + (set_attr "length" "2")]) + +;; This is a define expand, because pointers may be either 16 or 32 bits. + +;(define_insn "indirect_jump" +; [(set (pc) (match_operand:HI 0 "register_operand" "r"))] +; "" +; "jmp @%0" +; [(set_attr "type" "branch") +; (set_attr "cc" "none") +; (set_attr "length" "2")]) + +(define_expand "indirect_jump" + [(set (pc) (match_operand 0 "jump_address_operand" "Vr"))] + "" + "") + +(define_insn "indirect_jump_h8300" + [(set (pc) (match_operand:HI 0 "jump_address_operand" "V,r"))] + "TARGET_H8300" + "@ + jmp @%0 + jmp @%0" + [(set_attr "type" "branch") + (set_attr "cc" "none") + (set_attr "length" "2")]) + +(define_insn "indirect_jump_h8300h" + [(set (pc) (match_operand:SI 0 "jump_address_operand" "V,r"))] + "TARGET_H8300H" + "@ + jmp @%0 + jmp @%0" + [(set_attr "type" "branch") + (set_attr "cc" "none") + (set_attr "length" "2")]) + ;; Call subroutine with no return value. +;; ??? Even though we use HImode here, this works for the 300h. + (define_insn "call" - [(call (match_operand:QI 0 "memory_operand" "o") + [(call (match_operand:QI 0 "call_insn_operand" "or") (match_operand:HI 1 "general_operand" "g"))] "" "jsr %0" @@ -855,9 +1337,11 @@ ;; Call subroutine, returning value in operand 0 ;; (which must be a hard register). +;; ??? Even though we use HImode here, this works on the 300h. + (define_insn "call_value" [(set (match_operand 0 "" "=r") - (call (match_operand:QI 1 "memory_operand" "o") + (call (match_operand:QI 1 "call_insn_operand" "or") (match_operand:HI 2 "general_operand" "g")))] "" "jsr %1" @@ -873,440 +1357,634 @@ (set_attr "cc" "none") (set_attr "length" "2")]) -(define_insn "indirect_jump" - [(set (pc) (match_operand:HI 0 "register_operand" "r"))] - "" - "jmp @%0" - [(set_attr "type" "branch") - (set_attr "cc" "none") - (set_attr "length" "2")]) - -;; ----------------------------------------------------------------- -;; Shifts -;; ----------------------------------------------------------------- - -;; All H8 shifts go one bit at a time, here they are defined with names -;; so can use them in the expands.. - -;; QI BIT SHIFTS - -(define_insn "ashlqi3_one" - [(set (match_operand:QI 0 "register_operand" "=r") - (ashift:QI (match_operand:QI 1 "register_operand" "0") - (const_int 1)))] - "" - "shal %X0" - [(set_attr "type" "arith") - (set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_insn "ashrqi3_one" - [(set (match_operand:QI 0 "register_operand" "=r") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") - (const_int 1)))] - "" - "shar %X0" - [(set_attr "type" "arith") - (set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_insn "lshrqi3_one" - [(set (match_operand:QI 0 "register_operand" "=r") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") - (const_int 1)))] - "" - "shlr %X0" - [(set_attr "type" "arith") - (set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_expand "ashlqi3" - [(set (match_operand:QI 0 "register_operand" "=r") - (ashift:QI (match_operand:QI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "rn")))] - "" - " -{ - if (can_shift (ASHIFT, operands, gen_ashlqi3_one, 4, 0)) - DONE; - else - FAIL; -}") - -(define_expand "ashrqi3" - [(set (match_operand:QI 0 "register_operand" "=r") - (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "rn")))] - "" - " -{ - if (can_shift (ASHIFTRT, operands, gen_ashrqi3_one, 4, 0)) - DONE; - else - FAIL; -}") - -(define_expand "lshrqi3" - [(set (match_operand:QI 0 "register_operand" "=r") - (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "rn")))] - "" - " -{ - if (can_shift (LSHIFTRT, operands, gen_lshrqi3_one, 4, 0)) - DONE; - else - FAIL; -}") - -;; HI BIT SHIFTS - -(define_insn "ashlhi3_one" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashift:HI (match_operand:HI 1 "register_operand" "0") - (const_int 1)))] - "" - "add.w %T1,%T0" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "set")]) - -(define_insn "ashlhi3_eight" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashift:HI (match_operand:HI 1 "register_operand" "0") - (const_int 8)))] - "" - "mov.b %s1,%t0\;mov.b #0,%s0" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -(define_expand "ashlhi3" - [(set (match_operand:HI 0 "register_operand" "") - (ashift:HI - (match_operand:HI 1 "general_operand_src" "") - (match_operand:HI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (ASHIFT, operands, gen_ashlhi3_one, 4, gen_ashlhi3_eight)) - DONE; - else - FAIL; -}") - -(define_insn "lshrhi3_one" - [(set (match_operand:HI 0 "register_operand" "=r") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") - (const_int 1)))] - "" - "shlr %t0\;rotxr %s0" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -(define_insn "lshrhi3_eight" - [(set (match_operand:HI 0 "register_operand" "=r") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") - (const_int 8)))] - "" - "mov.b %t1,%s0\;mov.b #0,%t0" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -(define_expand "lshrhi3" - [(set (match_operand:HI 0 "register_operand" "") - (lshiftrt:HI - (match_operand:HI 1 "general_operand_src" "") - (match_operand:HI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (LSHIFTRT, operands, gen_lshrhi3_one, 4, gen_lshrhi3_eight)) - DONE; - else - FAIL; -}") - -(define_insn "ashrhi3_one" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") - (const_int 1)))] - "" - "shar %t0\;rotxr %s0" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -; signed shift right by 8 bits -; fetch the carry bit from the top, copy the byte right, subtract the -; top byte from itself - carry. - -(define_insn "ashrhi3_eight" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") - (const_int 8)))] - "" - "bld #7,%t0\;mov.b %t0,%s0\;subx %t0,%t0" - [(set_attr "type" "multi") - (set_attr "length" "6") - (set_attr "cc" "clobber")]) - -(define_expand "ashrhi3" - [(set (match_operand:HI 0 "register_operand" "") - (ashiftrt:HI - (match_operand:HI 1 "general_operand_src" "") - (match_operand:HI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (ASHIFTRT, operands, gen_ashrhi3_one, 4, gen_ashrhi3_eight)) - DONE; - else - FAIL; -}") - -;; SI BIT SHIFTS - -(define_insn "ashlsi3_one" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashift:SI (match_operand:SI 1 "register_operand" "0") - (const_int 1)))] - "" - "add.w %f1,%f0\;addx %y1,%y0\;addx %z1,%z0" - [(set_attr "type" "multi") - (set_attr "length" "6") - (set_attr "cc" "clobber")]) - -(define_expand "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "") - (ashift:SI - (match_operand:SI 1 "general_operand_src" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (ASHIFT, operands, gen_ashlsi3_one, 1, 0)) - DONE; - else - FAIL; -}") - -(define_insn "lshrsi3_one" - [(set (match_operand:SI 0 "register_operand" "=r") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") - (const_int 1)))] - "" - "shlr %z0\;rotxr %y0\;rotxr %x0\;rotxr %w0" - [(set_attr "type" "multi") - (set_attr "length" "8") - (set_attr "cc" "clobber")]) - -(define_expand "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI - (match_operand:SI 1 "general_operand_src" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (LSHIFTRT, operands, gen_lshrsi3_one, 1, 0)) - DONE; - else - FAIL; -}") - -(define_insn "ashrsi3_one" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") - (const_int 1)))] - "" - "shar %z0\;rotxr %y0\;rotxr %x0\;rotxr %w0" - [(set_attr "type" "multi") - (set_attr "length" "16") - (set_attr "cc" "clobber")]) - -(define_expand "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "") - (ashiftrt:SI - (match_operand:SI 1 "general_operand_src" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " -{ - if (can_shift (ASHIFTRT, operands, gen_ashrsi3_one, 1, 0)) - DONE; - else - FAIL; -}") - ;; ---------------------------------------------------------------------- -;; BIT FIELDS -;; ---------------------------------------------------------------------- - -(define_insn "" - [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r") - (const_int 1) - (match_operand:HI 2 "general_operand" "g")) - (match_operand:HI 3 "general_operand" "r"))] - "" - "bld #0,%3l\;bst %Z2,%0%Y1" - [(set_attr "type" "multi") - (set_attr "length" "4") - (set_attr "cc" "clobber")]) - -(define_expand "insv" - [(set (zero_extract:HI (match_operand:HI 0 "register_operand" "+r") - (match_operand:HI 1 "general_operand" "g") - (match_operand:HI 2 "general_operand" "g")) - (match_operand:HI 3 "general_operand" "r"))] - "" - "if (INTVAL (operands[1]) != 1) FAIL;") - -(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 3 "general_operand" "g")))] - "" - "sub.w %T0,%T0\;bld %Z3,%T1%Y1\;rotxl %T0l" - [(set_attr "type" "multi") - (set_attr "length" "6") - (set_attr "cc" "clobber")]) - -(define_insn "" - [(set (match_operand:HI 0 "register_operand" "=r") - (sign_extract:HI (match_operand:HI 1 "register_operand" "r") - (const_int 1) - (match_operand:HI 3 "general_operand" "g")))] - "" - "bld %Z3,%1%Y1\;sub.x %0l,%0l\;mov.b %0l,%0h" - [(set_attr "type" "multi") - (set_attr "length" "6") - (set_attr "cc" "clobber")]) - -(define_expand "extzv" - [(set (match_operand:HI 0 "register_operand" "") - (zero_extract:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "") - (match_operand:HI 3 "general_operand" "")))] - "" - "if (INTVAL (operands[2]) != 1) FAIL;") - -(define_expand "extv" - [(set (match_operand:HI 0 "register_operand" "") - (sign_extract:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" "") - (match_operand:HI 3 "immediate_operand" "")))] - "" - "if (INTVAL (operands[2]) != 1) FAIL;") - -;; ---------------------------------------------------------------------- -;; Conversions +;; EXTEND INSTRUCTIONS ;; ---------------------------------------------------------------------- (define_insn "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r") - (zero_extend:HI - (match_operand:QI 1 "general_operand" "g")))] + [(set (match_operand:HI 0 "register_operand" "=r,r") + (zero_extend:HI (match_operand:QI 1 "general_operand" "0,g")))] "" - "mov.b %X1,%s0\;mov.b #0,%t0" + "* +{ + if (which_alternative==0) + return \"mov.b #0,%t0\"; + + if (TARGET_H8300) + return \"mov.b %X1,%s0\;mov.b #0,%t0\"; + else + { + /* ??? See how often this gets optimized. */ + if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0]))) + return \"extu.w %T0\"; + else + return \"mov.b %X1,%s0\;extu.w %T0\"; + } +}" [(set_attr "type" "multi") +;; ??? This length is wrong for one case. + (set_attr "length" "4") + (set_attr "cc" "clobber")]) + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "TARGET_H8300H" + "* +{ + /* ??? See how often this gets optimized. */ + if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0]))) + return \"extu.l %S0\"; + else + return \"mov.w %T1,%T0\;extu.l %S0\"; +}" + [(set_attr "type" "multi") +;; ??? This length is wrong for one case. (set_attr "length" "4") (set_attr "cc" "clobber")]) (define_insn "extendqihi2" [(set (match_operand:HI 0 "register_operand" "=r") - (sign_extend:HI - (match_operand:QI 1 "register_operand" "r")))] + (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] "" "* { - if (REGNO (operands[1]) != REGNO (operands[0])) - return \"mov.b %X1,%s0\;bld #7,%s0\;subx %t0,%t0\"; + if (TARGET_H8300) + { + /* ??? See how often this gets optimized. */ + if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0]))) + return \"bld #7,%s0\;subx %t0,%t0\"; + else + return \"mov.b %X1,%s0\;bld #7,%s0\;subx %t0,%t0\"; + } else - return \"bld #7,%s0\;subx %t0,%t0\"; + { + /* ??? See how often this gets optimized. */ + if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0]))) + return \"exts.w %T0\"; + else + return \"mov.b %X1,%s0\;exts.w %T0\"; + } }" [(set_attr "type" "multi") +;; ??? Length is wrong in some cases. (set_attr "length" "6") (set_attr "cc" "clobber")]) -(define_insn "extendhisi2_one" - [(set (match_operand:SI 0 "register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))] +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "general_operand" "")))] "" + " +{ + if (TARGET_H8300) + emit_insn (gen_extendhisi2_h8300 (operands[0], operands[1])); + else + emit_insn (gen_extendhisi2_h8300h (operands[0], operands[1])); + DONE; +}") + +(define_expand "extendhisi2_h8300" + [(set (reg:HI 1) (match_operand:HI 1 "general_operand" "")) + (set (reg:SI 0) (sign_extend:SI (reg:HI 1))) + (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))] + "TARGET_H8300" + "") + +(define_expand "extendhisi2_h8300h" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "general_operand" "")))] + "TARGET_H8300H" + "") + +(define_insn "extendhisi2_h8300_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))] + "TARGET_H8300" "mov.w %T1,%f0\;bld #7,%x0\;subx %y0,%y0\;subx %z0,%z0" [(set_attr "length" "10") (set_attr "cc" "clobber")]) -(define_expand "extendhisi2" - [(set (reg:HI 1) (match_operand:HI 1 "general_operand" "")) - (set (reg:SI 0) (sign_extend:SI (reg:HI 1))) - (set (match_operand:SI 0 "general_operand" "" ) (reg:SI 0))] - "" - "") - +(define_insn "extendhisi2_h8300h_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "TARGET_H8300H" + "* +{ + /* ??? See how often this gets optimized. */ + if (REG_P (operands[1]) && (REGNO (operands[1]) == REGNO (operands[0]))) + return \"exts.l %S0\"; + else + return \"mov.w %T1,%T0\;exts.l %S0\"; +}" + [(set_attr "length" "10") + (set_attr "cc" "clobber")]) + ;; ---------------------------------------------------------------------- -;; peepholes +;; 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. -;; notice a move which could be predecremented +;; QI BIT SHIFTS -(define_peephole - [(set (match_operand:HI 1 "register_operand" "") - (plus:HI (match_dup 1) (const_int -1))) - (set (mem:HI (match_dup 1)) - (match_operand:HI 0 "register_operand" ""))] - "REGNO (operands[1]) != REGNO (operands[0])" - "mov.w %T0,@-%T1" - [(set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_peephole - [(set (match_operand:HI 1 "register_operand" "") - (plus:HI (match_dup 1) (const_int -1))) - (set (mem:QI (match_dup 1)) - (match_operand:QI 0 "register_operand" ""))] - "REGNO (operands[1]) != REGNO (operands[0])" - "mov.b %X0,@-%T1" - [(set_attr "length" "2") - (set_attr "cc" "set")]) - -;; notice a move which could be post incremented - -(define_peephole - [(set (match_operand:HI 0 "register_operand" "") - (mem:HI (match_operand:HI 1 "register_operand" ""))) - (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))] - "REGNO (operands[1]) != REGNO (operands[0])" - "mov.w @%T1+,%T0" - [(set_attr "length" "2") - (set_attr "cc" "set")]) - -(define_peephole +(define_expand "ashlqi3" [(set (match_operand:QI 0 "register_operand" "") - (mem:QI (match_operand:HI 1 "register_operand" ""))) - (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] - "REGNO (operands[1]) != REGNO (operands[0])" - "mov.b @%T1+,%X0" - [(set_attr "length" "2") + (ashift:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (QImode, ASHIFT, operands)) DONE;else FAIL;") + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "register_operand" "") + (ashiftrt:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (QImode, ASHIFTRT, operands)) DONE;else FAIL;") + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "register_operand" "") + (lshiftrt:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE;else FAIL;") + +;; WARNING: The constraints on the scratch register say one is not needed +;; for constant shifts of 1,2,3,4. Emit_a_shift() must know this. + +(define_insn "shiftbyn_QI" + [(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" "IKM,rn")])) + (clobber (match_scratch:QI 4 "=X,&r"))] + "" + "* return emit_a_shift (insn, operands);" + [(set_attr "type" "arith") + (set_attr "length" "20") +;; ??? We'd like to indicate that cc is set here, and it is for simple shifts. +;; However, for cases that loop or are done in pieces, cc does not contain +;; what we want. Emit_a_shift is free to tweak cc_status as desired. + (set_attr "cc" "clobber")]) + +;; HI BIT SHIFTS + +(define_expand "ashlhi3" + [(set (match_operand:HI 0 "register_operand" "") + (ashift:HI (match_operand:HI 1 "nonmemory_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (HImode, ASHIFT, operands)) DONE;else FAIL;") + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "register_operand" "") + (lshiftrt:HI (match_operand:HI 1 "general_operand_src" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;else FAIL;") + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "register_operand" "") + (ashiftrt:HI (match_operand:HI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE;else FAIL;") + +;; WARNING: The constraints on the scratch register say one is not needed +;; for constant shifts of 1,2,3,4. Emit_a_shift() must know this. + +(define_insn "shiftbyn_HI" + [(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" "IKM,rn")])) + (clobber (match_scratch:QI 4 "=X,&r"))] + "" + "* return emit_a_shift (insn, operands);" + [(set_attr "type" "arith") + (set_attr "length" "20") +;; ??? We'd like to indicate that cc is set here, and it is for simple shifts. +;; However, for cases that loop or are done in pieces, cc does not contain +;; what we want. Emit_a_shift is free to tweak cc_status as desired. + (set_attr "cc" "clobber")]) + +;; SI BIT SHIFTS + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI + (match_operand:SI 1 "general_operand_src" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (SImode, ASHIFT, operands)) DONE;else FAIL;") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI + (match_operand:SI 1 "general_operand_src" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (SImode, LSHIFTRT, operands)) DONE;else FAIL;") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashiftrt:SI + (match_operand:SI 1 "general_operand_src" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE;else FAIL;") + +;; WARNING: The constraints on the scratch register say one is not needed +;; for constant shifts of 1,2. Emit_a_shift() must know this. + +(define_insn "shiftbyn_SI" + [(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" "IK,rn")])) + (clobber (match_scratch:QI 4 "=X,&r"))] + "" + "* return emit_a_shift (insn, operands);" + [(set_attr "type" "arith") + (set_attr "length" "20") +;; ??? We'd like to indicate that cc is set here, and it is for simple shifts. +;; However, for cases that loop or are done in pieces, cc does not contain +;; what we want. Emit_a_shift is free to tweak cc_status as desired. + (set_attr "cc" "clobber")]) + +;; ----------------------------------------------------------------- +;; BIT FIELDS +;; ----------------------------------------------------------------- +;; The H8/300 has given 1/8th of its opcode space to bitfield +;; instuctions so let's use them as well as we can + +;; BCC and BCS patterns. + +(define_insn "bcs_qiqi" + [(set (pc) + (if_then_else + (match_operator 1 "eq_operator" + [(zero_extract:QI (match_operand:QI 2 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 3 "immediate_operand" "i")) + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + output_asm_insn(\"bld %Z3,%Y2\", operands); + if (get_attr_length (insn) == 2) + return \"b%d1 %l0\"; + else if (get_attr_length (insn) == 4) + return \"b%d1 %l0:16\"; + else + return \"b%g1 %L0\;jmp @%l0\;%L0:\"; +}" + [(set_attr "type" "branch") + (set_attr "cc" "clobber")]) + +(define_insn "bcs_hihi" + [(set (pc) + (if_then_else + (match_operator 1 "eq_operator" + [(zero_extract:HI (match_operand:HI 2 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 3 "immediate_operand" "i")) + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + output_asm_insn(\"bld %Z3,%Y2\", operands); + if (get_attr_length (insn) == 2) + return \"%d1 %l0\"; + else if (get_attr_length (insn) == 4) + return \"%d1 %l0:16\"; + else + return \"%g1 %L0\;jmp @%l0\;%L0:\"; +}" + [(set_attr "type" "branch") + (set_attr "cc" "clobber")]) + +(define_insn "bcs_hiqi" + [(set (pc) + (if_then_else + (match_operator 1 "eq_operator" + [(zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 3 "immediate_operand" "i")) + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + output_asm_insn(\"bld %Z3,%Y2\", operands); + if (get_attr_length (insn) == 2) + return \"%d1 %l0\"; + else if (get_attr_length (insn) == 4) + return \"%d1 %l0:16\"; + else + return \"%g1 %L0\;jmp @%l0\;%L0:\"; +}" + [(set_attr "type" "branch") + (set_attr "cc" "clobber")]) + +;; BLD and BST patterns + +(define_insn "extract_1" + [(set (match_operand:HI 0 "register_operand" "=&r") + (zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")))] + "" + "sub.w %0,%0\;bld %Z2,%Y1\;bst #0,%X0") + +(define_insn "extract_1_hi" + [(set (match_operand:HI 0 "register_operand" "=&r") + (zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")))] + "" + "sub.w %0,%0\;bld %Z2,%Y1\;bst #0,%X0") + +(define_insn "insert_1" + [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "+Ur") + (const_int 1) + (match_operand:HI 1 "immediate_operand" "i")) + (zero_extract:HI (match_operand:QI 2 "bit_operand" "Ur") + (const_int 1) + (const_int 0)))] + "" + "bld #0,%X2\;bst %Z1,%Y0 ; i1") + +;; This is how combine canonicalizes this pattern. This is perhaps a bug +;; in combine.c, but there is no problem with writing it this way so we do. +(define_insn "extract_insert_1" + [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur") + (const_int 1) + (match_operand:HI 1 "immediate_operand" "i")) + (lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur") + (match_operand:HI 3 "immediate_operand" "i")))] + "" + "bld %Z3,%Y2\;bst %Z1,%Y0; ei1") + +;; BAND, BOR, and BXOR patterns + +(define_insn "bitlogical_1" + [(set (match_operand:HI 0 "bit_operand" "=Ur") + (match_operator:HI 4 "bit_operator" + [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")) + (match_operand:HI 3 "bit_operand" "0")]))] + "" + "bld %Z2,%Y1\;%b4 #0,%X0\;bst #0,%X0; bl1") + +(define_insn "bitlogical_1_hi" + [(set (match_operand:HI 0 "bit_operand" "=Ur") + (match_operator:HI 4 "bit_operator" + [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")) + (match_operand:HI 3 "bit_operand" "0")]))] + "" + "bld %Z2,%Y1\;%b4 #0,%X0\;bst #0,%X0; bl2") + +(define_insn "bitlogical_2" + [(set (match_operand:HI 0 "bit_operand" "=Ur") + (match_operator:HI 5 "bit_operator" + [(zero_extract:HI (match_operand:QI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")) + (zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 4 "immediate_operand" "i"))]))] + "" + "bld %Z2,%Y1\;%b5 %Z4,%Y3\;bst #0,%X0; bl3") + +(define_insn "bitlogical_2_hi" + [(set (match_operand:HI 0 "bit_operand" "=Ur") + (match_operator:HI 5 "bit_operator" + [(zero_extract:HI (match_operand:HI 1 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 2 "immediate_operand" "i")) + (zero_extract:HI (match_operand:HI 3 "bit_operand" "Ur") + (const_int 1) + (match_operand:HI 4 "immediate_operand" "i"))]))] + "" + "bld %Z2,%Y1\;%b5 %Z4,%Y3\;bst #0,%X0; bl3") + +;; This is how combine canonicalizes this pattern. This is perhaps a bug +;; in combine.c, but there is no problem with writing it this way so we do. +(define_insn "bitlogical_3" + [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "+Ur") + (const_int 1) + (match_operand:HI 1 "immediate_operand" "i")) + (match_operator:QI 6 "bit_operator" + [(lshiftrt:QI (match_operand:QI 2 "bit_operand" "Ur") + (match_operand:HI 3 "immediate_operand" "i")) + (lshiftrt:QI (match_operand:QI 4 "bit_operand" "Ur") + (match_operand:HI 5 "immediate_operand" "i"))]))] + "" + "bld %Z3,%Y2\;%b6 %Z5,%Y4\;bst %Z1,%Y0; bl5") + +;; This is how combine canonicalizes this pattern. This is perhaps a bug +;; in combine.c, but there is no problem with writing it this way so we do. +(define_insn "bitnot_1" + [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=Ur") + (const_int 1) + (match_operand:HI 1 "immediate_operand" "i")) + (lshiftrt:QI (xor:QI (match_operand:QI 2 "bit_operand" "0") + (match_operand:HI 3 "immediate_operand" "i")) + (match_operand:HI 4 "immediate_operand" "1")))] + "GET_CODE (operands[3]) == CONST_INT && GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[3])) == INTVAL (operands[1])" + "bnot %Z1,%Y0") + +;; ??? Implement BIAND, BIOR, BIXOR + +;; ??? Implement BILD, BIST + +;; ??? Apparently general_operand for the 1st and 2nd operands is useful, +;; but I don't know why. --Jim + +(define_expand "insv" + [(set (zero_extract:HI (match_operand:QI 0 "bit_operand" "Ur") + (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")) + (zero_extract:HI (match_operand:QI 3 "bit_operand" "Ur") + (const_int 1) + (const_int 0)))] +;; ??? This should have word mode which is SImode for the h8/300h. + "TARGET_H8300" + " +{ + if (INTVAL (operands[1]) != 1) + FAIL; + + /* ??? HACK ??? + This INSV pattern is wrong. It should use HImode for operand 3. + Also, the zero_extract around operand 3 is superfluous and should be + deleted. Fixing this is more work than we care to do for the moment, + because it means most of the above patterns would need to be rewritten, + and we also need more combine.c patches to make this work. + + So, for now, we work around this bug by simply not accepting any bitfield + inserts that have a position greater than fits in QImode. */ + + if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) >= 8) + FAIL; + + /* The bit_operand predicate accepts any memory durint RTL generation, but + only 'U' memory afterwards, so if this is a MEM operand, we must force + it to be valid for 'U' by reloading the address. */ + + if (GET_CODE (operands[0]) == MEM && ! EXTRA_CONSTRAINT (operands[0], 'U')) + { + rtx mem; + mem = gen_rtx (MEM, GET_MODE (operands[0]), + copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); + RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[0]); + MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[0]); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]); + operands[0] = mem; + } + + /* Likewise for operands[3]. */ + + if (GET_CODE (operands[3]) == MEM && ! EXTRA_CONSTRAINT (operands[3], 'U')) + { + rtx mem; + mem = gen_rtx (MEM, GET_MODE (operands[3]), + copy_to_mode_reg (Pmode, XEXP (operands[3], 0))); + RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[3]); + MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[3]); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + operands[3] = mem; + } +}") + +;; ??? Apparently general_operand for the 2nd and 3rd operands is useful, +;; but I don't know why. --Jim + +(define_expand "extzv" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extract:HI (match_operand:QI 1 "bit_operand" "") + (match_operand:HI 2 "general_operand" "g") + (match_operand:HI 3 "general_operand" "g")))] +;; ??? This should have word mode which is SImode for the h8/300h. + "TARGET_H8300" + " +{ + if (INTVAL (operands[2]) != 1) + FAIL; + + /* The bit_operand predicate accepts any memory durint RTL generation, but + only 'U' memory afterwards, so if this is a MEM operand, we must force + it to be valid for 'U' by reloading the address. */ + + if (GET_CODE (operands[1]) == MEM && ! EXTRA_CONSTRAINT (operands[1], 'U')) + { + rtx mem; + mem = gen_rtx (MEM, GET_MODE (operands[1]), + copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); + RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (operands[1]); + MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (operands[1]); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + operands[1] = mem; + } +}") + +;; ----------------------------------------------------------------- +;; STACK POINTER MANIPULATIONS +;; ----------------------------------------------------------------- + +;; This pattern is needed because there is no way on the H8/300 +;; to add a 16 bit immediate value to the stack pointer in one +;; instruction, which could leave an invalid instruction if interrupted +;; half way through. Here we add to the stack pointer from a +;; register. + +(define_insn "stack_pointer_manip" + [(set (match_operand:HI 0 "register_operand" "=&ra") + (plus:HI (match_operand:HI 1 "general_operand_src" "g") + (match_operand:HI 2 "register_operand" "ra")))] + "TARGET_H8300" + "mov.w %T1,%T0\;add.w %T2,%T0" + [(set_attr "type" "arith") + (set_attr "length" "6") (set_attr "cc" "set")]) -;; notice when two byte moves in a row could be a word move -(define_peephole - [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra") - (match_operand:HI 2 "immediate_operand" "n"))) - (match_operand:QI 0 "register_operand" "r")) - (set (mem:QI (plus:HI (match_dup 1) - (match_operand:HI 4 "immediate_operand" "n"))) - (match_operand:QI 3 "register_operand" "r"))] - "(INTVAL (operands[2]) == INTVAL (operands[4]) + 1) - && (REGNO (operands[0]) + 1 == REGNO (operands[3]))" - "mov.w %T0,@(%u4,%T1)" - [(set_attr "length" "6") - (set_attr "cc" "set")]) +;; ------------------------------------------- +;; BLK moves +;; ------------------------------------------- + +(define_expand "movstrhi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) + (mem:BLK (match_operand:BLK 1 "general_operand" ""))) + (use (match_operand:HI 2 "general_operand" "")) + (use (match_operand:HI 3 "immediate_operand" "")) + (clobber (match_dup 3)) + ])] + "" + " +{ + rtx src_ptr = copy_to_mode_reg (Pmode, XEXP(operands[1], 0)); + rtx dst_ptr = copy_to_mode_reg (Pmode, XEXP(operands[0], 0)); + + int max = GET_CODE (operands[2]) == CONST_INT + ? MIN (INTVAL (operands[2]), INTVAL (operands[3])) : 1; + enum machine_mode mode = max >= 2 ? HImode : QImode; + rtx tmpreg = gen_reg_rtx (mode); + rtx increment = mode == QImode ? const1_rtx : const2_rtx; + rtx length = operands[2]; + rtx label = gen_label_rtx (); + rtx end_src_ptr = gen_reg_rtx (Pmode); + +/* emit_move_insn (length, gen_rtx(MINUS, HImode, length, increment));*/ + FAIL; + if (Pmode == HImode) + emit_insn (gen_addhi3 (end_src_ptr, src_ptr, length)); + else + emit_insn (gen_addsi3 (end_src_ptr, src_ptr, length)); + + emit_label (label); + emit_move_insn (tmpreg, gen_rtx (MEM, mode, src_ptr)); + emit_move_insn (gen_rtx (MEM, mode, dst_ptr), tmpreg); + emit_insn (gen_rtx (SET, VOIDmode, src_ptr, + gen_rtx (PLUS, Pmode, src_ptr, increment))); + emit_insn (gen_rtx (SET, VOIDmode, dst_ptr, + gen_rtx (PLUS, Pmode, dst_ptr, increment))); + + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, Pmode, src_ptr, end_src_ptr))); + emit_jump_insn (gen_bne (label)); + + DONE; +}") + +;; ---------------------------------------------- +;; Peepholes go at the end. +;; ---------------------------------------------- + +;; Notice when two byte moves in a row could be a word move. (define_peephole [(set (match_operand:QI 0 "register_operand" "=r") @@ -1315,8 +1993,226 @@ (set (match_operand:QI 3 "register_operand" "=r") (mem:QI (plus:HI (match_dup 1) (match_operand:HI 4 "immediate_operand" "n"))))] - "(INTVAL (operands[2]) == INTVAL (operands[4]) + 1) - && (REGNO (operands[0]) + 1 == REGNO (operands[3]))" + "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])" "mov.w @(%u4,%T1),%T0" [(set_attr "length" "6") (set_attr "cc" "set")]) + +(define_peephole + [(set (mem:QI (plus:HI (match_operand:HI 1 "register_operand" "ra") + (match_operand:HI 2 "immediate_operand" "n"))) + (match_operand:QI 0 "register_operand" "r")) + (set (mem:QI (plus:HI (match_dup 1) + (match_operand:HI 4 "immediate_operand" "n"))) + (match_operand:QI 3 "register_operand" "r"))] + "(INTVAL(operands[2]) == INTVAL(operands[4])+1) && REGNO(operands[0]) +1 == REGNO(operands[3])" + "mov.w %T0,@(%u4,%T1)" + [(set_attr "length" "6") + (set_attr "cc" "set")]) + +;; Notice a move which could be post incremented. + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "") + (mem:QI (match_operand:HI 1 "register_operand" ""))) + (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] + "REGNO(operands[1]) != REGNO(operands[0])" + "mov.b @%T1+,%X0" + [(set_attr "length" "2") + (set_attr "cc" "set")]) + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "") + (mem:HI (match_operand:HI 1 "register_operand" ""))) + (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))] + "REGNO(operands[1]) != REGNO(operands[0])" + "mov.w @%T1+,%T0" + [(set_attr "length" "2") + (set_attr "cc" "set")]) + +;; Notice a move which could be predecremented. + +(define_peephole + [(set (match_operand:HI 1 "register_operand" "") + (plus:HI (match_dup 1) (const_int -1))) + (set (mem:QI (match_dup 1)) + (match_operand:QI 0 "register_operand" ""))] + "REGNO(operands[1]) != REGNO(operands[0])" + "mov.b %X0,@-%T1" + [(set_attr "length" "2") + (set_attr "cc" "set")]) + +(define_peephole + [(set (match_operand:HI 1 "register_operand" "") + (plus:HI (match_dup 1) (const_int -1))) + (set (mem:HI (match_dup 1)) + (match_operand:HI 0 "register_operand" ""))] + "REGNO(operands[1]) != REGNO(operands[0])" + "mov.w %T0,@-%T1" + [(set_attr "length" "2") + (set_attr "cc" "set")]) + +;(define_insn "" +; [(set (match_operand:HI 0 "register_operand" "=r") +; (MEM:HI (match_operand:HI 1 "register_operand" "r"))) +; (set (match_operand:HI 3 "register_operand" "=r") +; (zero_extract:HI (match_dup 0) +; (const_int 1) +; (match_operand:HI 2 "general_operand" "g"))) +; (set (MEM:HI (match_dup 1) (match_dup 3)))] +; "" +; "bld #0,%3l\;bst %Z2,%0%Y1" +; [(set_attr "type" "multi") +; (set_attr "length" "4") +; (set_attr "cc" "clobber")]) + +(define_insn "fancybset1" + [(set (match_operand:QI 0 "bit_operand" "=Ur") + (ior:QI (subreg:QI + (ashift:HI (const_int 1) + (subreg:QI (match_operand:HI 1 "register_operand" "ri") 0)) 0) + (match_dup 0)))] + "" + "bset %X1,%X0") + +(define_insn "fancybset" + [(set (match_operand:QI 0 "bit_operand" "=Ur") + (ior:QI (subreg:QI + (ashift:HI (const_int 1) + (match_operand:HI 1 "nonmemory_operand" "ri") ) 0) + (match_operand:QI 2 "general_operand" "Ur")))] + "" + "mov.b %X2,%X0\;bset %X1,%X0") + + +(define_insn "fancybclr4" + [(set (match_operand:QI 0 "general_operand" "=Ur,Ur") + (and:QI + (subreg:QI + (rotate:HI (const_int -2) + (match_operand:HI 2 "nonmemory_operand" "ri,ri") ) 0) + (match_operand:QI 1 "general_operand" "0,Ur"))) + (clobber (match_scratch:HI 3 "=X,&r"))] + "" + "@ + bclr %X2,%X0; l1 + mov.b %X1,%X3\;mov.b %3,%0\;bclr %X2,%X0; l3") + +(define_insn "fancybclr5" + [(set (match_operand:QI 0 "general_operand" "=Ur,Ur") + (and:QI + (subreg:QI + (rotate:HI (const_int -2) + (match_operand:QI 2 "nonmemory_operand" "ri,ri")) 0) + (match_operand:QI 1 "general_operand" "0,Ur"))) + (clobber (match_scratch:HI 3 "=X,&r"))] + "" + "@ + bclr %X2,%X0; l1 + mov.b %X1,%X3\;mov.b %3,%0\;bclr %X2,%X0;l2") + +(define_insn "fancybclr2" + [(set (match_operand:QI 0 "general_operand" "=U,r") + (and:QI + (subreg:QI + (rotate:HI (const_int -2) + (match_operand:HI 2 "nonmemory_operand" "ri,ri") ) 0) + (match_operand:QI 1 "general_operand" "0,0")))] + "" + "bclr %X2,%X0") + +(define_insn "fancybclr3" + [(set (match_operand:QI 0 "general_operand" "=U,r") + (and:QI + (subreg:QI + (rotate:HI (const_int -2) + (match_operand:QI 2 "nonmemory_operand" "ri,ri")) 0) + (match_operand:QI 1 "general_operand" "0,0")))] + "" + "bclr %X2,%X0") + +(define_insn "fancybclr" + [(set (match_operand:QI 0 "general_operand" "=r") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "0")) + (match_operand:QI 2 "general_operand" "r")))] + "" + "not %X0\;and %X2,%X0") + +(define_insn "fancybsetp3" + [(set (match_operand:QI 0 "bit_operand" "=Ur") + (ior:QI (subreg:QI (ashift:HI (const_int 1) + (match_operand:QI 1 "register_operand" "r")) 0) + (match_operand:QI 2 "bit_operand" "0")))] + "" + "bset %X1,%X0") + +(define_insn "fancybsetp2" + [(set (match_operand:QI 0 "general_operand" "=r,U") + (ior:QI (subreg:QI (ashift:HI (const_int 1) + (match_operand:QI 1 "register_operand" "r,r")) 0) + (match_operand:QI 2 "general_operand" "U,r")))] + "" + "mov.b %X2,%X0\;bset %X1,%X0") + +(define_insn "fancybnot" + [(set (match_operand:QI 0 "bit_operand" "=Ur") + (xor:QI (subreg:QI (ashift:HI (const_int 1) + (match_operand:QI 1 "register_operand" "r")) 0) + (match_operand:QI 2 "bit_operand" "0")))] + + "" + "bnot %X1,%X0") + +(define_insn "fancy_btst" + [(set (pc) + (if_then_else (eq (zero_extract:HI (zero_extend:HI (match_operand:QI 0 "general_operand" "Ur")) + (const_int 1) + (match_operand:HI 1 "nonmemory_operand" "rn")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* +{ + if (get_attr_length (insn) == 2) + return \"btst %X1,%X0\;beq %l2\"; + else if (get_attr_length (insn) == 4) + return \"btst %X1,%X0\;beq %l2:16\"; + else + return \"btst %X1,%X0\;bne %L0\;jmp @%l2\;%L0:\"; +}" + [(set_attr "type" "branch") + (set_attr "cc" "clobber")]) + +(define_insn "fancy_btst1" + [(set (pc) + (if_then_else (ne (zero_extract:HI (zero_extend:HI (match_operand:QI 0 "general_operand" "Ur")) + (const_int 1) + (match_operand:HI 1 "nonmemory_operand" "rn")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* +{ + if (get_attr_length (insn) == 2) + return \"btst %X1,%X0\;bne %l2\"; + else if (get_attr_length (insn) == 4) + return \"btst %X1,%X0\;bne %l2:16\"; + else + return \"btst %X1,%X0\;beq %L0\;jmp @%l2\;%L0:\"; +}" + [(set_attr "type" "branch") + (set_attr "cc" "clobber")]) + +(define_insn "pxor" + [(set (zero_extract:QI (match_operand:QI 0 "bit_operand" "=r,U") + (const_int 1) + (match_operand 1 "immediate_operand" "n,n")) + (and:QI (not:QI (match_operand:QI 2 "bit_operand" "r,U")) + (const_int 1)))] + "" + "bld #0,%X2\;bist %1,%0" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "cc" "clobber")])