;; ??? If we can remove the operand type on all the insns, do it.
;; ??? Otherwise, try to have the operand type on all the insns.
+;; ??? Many patterns have overly conservative lengths. In particular:
+;;
+;; * movXX insns using register indirect addressing.
+;; * insns referencing the 8-bit area with an 8-bit address.
;; Some move patterns have conditions which check that one operand
;; is a register. Shouldn't all of them have such a condition?
;; can be found using bit-set insns dec, etc
-(define_attr "type" "branch,return,call,arith,move,float,multi"
+(define_attr "type" "branch,bcs,return,call,arith,move,float,multi"
(const_string "arith"))
;; The size of instructions in bytes.
(const_int 32000))))
(const_int 4)
(const_int 6)))
+ (eq_attr "type" "bcs")
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -120))
+ (le (minus (pc) (match_dup 0))
+ (const_int 120)))
+ (if_then_else
+ (match_operand 2 "register_operand" "")
+ (const_int 4)
+ (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))))
+ (if_then_else
+ (match_operand 2 "register_operand" "")
+ (const_int 6)
+ (const_int 8))
+ (if_then_else
+ (match_operand 2 "register_operand" "")
+ (const_int 8)
+ (const_int 10))))
(eq_attr "type" "move") (const_int 4)
(eq_attr "type" "return") (const_int 2)
(eq_attr "type" "float") (const_int 12)
;; movhi
+;; ??? We use push.l on the h8300h to push a 16bit value?!? We have
+;; 16bit push insns!
(define_insn "movhi_push"
[(set (match_operand:HI 0 "push_operand" "=<")
(match_operand:HI 1 "register_operand" "ra"))]
(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>,ra,ion,ra"))]
- ""
+ "register_operand (operands[0],HImode)
+ || register_operand (operands[1], HImode)"
"@
sub.w %T0,%T0
mov.w %T1,%T0
}
else
{
- return \"mov.w %e1,%e0\;mov.w %f1,%f0\";
+ /* See if either half is zero. If so, use sub.w to clear
+ that half. */
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ if ((INTVAL (operands[1]) & 0xffff) == 0)
+ return \"mov.w %e1,%e0\;sub.w %f0,%f0\";
+ if (((INTVAL (operands[1]) >> 16) & 0xffff) == 0)
+ return \"sub.w %e0,%e0\;mov.w %f1,%f0\";
+ }
+ return \"mov.w %e1,%e0\;mov.w %f1,%f0\";
}
-
case 3:
- return \"mov.w %e1,%e0\;mov.w %f1,%f0\";
+ return \"mov.w %e1,%e0\;mov.w %f1,%f0\";
case 4:
return \"mov.w %f1,%T0\;mov.w %e1,%T0\";
case 5:
"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"
+ "*
+{
+ if (which_alternative == 0)
+ return \"sub.l %S0,%S0\";
+ 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 %S0,%S0\;add.b %1,%w0\";
+ }
+
+ if (val == (val & 0xff00))
+ {
+ operands[1] = GEN_INT ((char)(val >> 8) & 0xff);
+ return \"sub.l %S0,%S0\;add.b %1,%x0\";
+ }
+
+ /* Now look for small negative numbers. We can subtract them
+ from zero to get the desired constant. */
+ if (val == -4 || val == -2 || val == -1)
+ {
+ operands[1] = GEN_INT (-INTVAL (operands[1]));
+ return \"sub.l %S0,%S0\;subs %1,%S0\";
+ }
+ }
+ return \"mov.l %S1,%S0\";
+}"
[(set_attr "type" "move")
(set_attr "length" "2,2,10,10,4,4")
(set_attr "cc" "set_zn_c0,set,set,set,set,set")])
;; h8300h: 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 "addhi3"
- [(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")))]
+(define_expand "addhi3"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (plus:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))]
+ ""
+ "")
+
+;; Specialized version using adds/subs. This must come before
+;; the more general patterns below.
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=ra")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0")
+ (match_operand:HI 2 "adds_subs_operand" "i")))]
""
+ "* return output_adds_subs (operands);"
+ [(set_attr "type" "arith")
+ (set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=&ra,ra")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
+ (match_operand:HI 2 "nonmemory_operand" "n,ra")))]
+ "TARGET_H8300"
"@
- 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_zn_c0")])
+ [(set_attr "type" "multi,arith")
+ (set_attr "length" "4,2")
+ (set_attr "cc" "clobber,set_zn_c0")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=ra,ra")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
+ (match_operand:HI 2 "nonmemory_operand" "i,ra")))]
+ "TARGET_H8300H"
+ "@
+ add.w %T2,%T0
+ add.w %T2,%T0"
+ [(set_attr "type" "arith,arith")
+ (set_attr "length" "4,2")
+ (set_attr "cc" "set_zn_c0,set_zn_c0")])
(define_expand "addsi3"
[(set (match_operand:SI 0 "register_operand" "")
""
"")
+;; Specialized version using adds/subs. This must come before
+;; the more general patterns below.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=ra")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "adds_subs_operand" "i")))]
+ "TARGET_H8300H"
+ "* return output_adds_subs (operands);"
+ [(set_attr "type" "arith")
+ (set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
(define_insn "addsi_h8300"
- [(set (match_operand:SI 0 "register_operand" "=r,r,&r")
+ [(set (match_operand:SI 0 "register_operand" "=ra,ra,&ra")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,r")
(match_operand:SI 2 "nonmemory_operand" "n,r,r")))]
"TARGET_H8300"
(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")))]
+ [(set (match_operand:SI 0 "register_operand" "=ra,ra")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "nonmemory_operand" "i,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,set_zn_c0,set_zn_c0")])
+ [(set_attr "type" "arith,arith")
+ (set_attr "length" "6,2")
+ (set_attr "cc" "set_zn_c0,set_zn_c0")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
""
"*
{
+ /* The length of this insn includes the bld insn below. We
+ compute the length of the branch without the bld so we
+ can easily choose the right branch length. */
+ int branch_length = get_attr_length (insn);
+
+ if (! register_operand (operands[2], QImode))
+ branch_length -= 2;
+
output_asm_insn(\"bld %Z3,%Y2\", operands);
- if (get_attr_length (insn) == 2)
+ if (branch_length == 2)
return \"b%d1 %l0\";
- else if (get_attr_length (insn) == 4)
+ else if (branch_length == 4)
return \"b%d1 %l0:16\";
else
return \"b%g1 %L0\;jmp @%l0\;%L0:\";
}"
- [(set_attr "type" "branch")
+ [(set_attr "type" "bcs")
(set_attr "cc" "clobber")])
(define_insn "bcs_hihi"
""
"*
{
+ /* The length of this insn includes the bld insn below. We
+ compute the length of the branch without the bld so we
+ can easily choose the right branch length. */
+ int branch_length = get_attr_length (insn);
+
+ if (! register_operand (operands[2], QImode))
+ branch_length -= 2;
+
output_asm_insn(\"bld %Z3,%Y2\", operands);
- if (get_attr_length (insn) == 2)
+ if (branch_length == 2)
return \"b%d1 %l0\";
- else if (get_attr_length (insn) == 4)
+ else if (branch_length == 4)
return \"b%d1 %l0:16\";
else
return \"b%g1 %L0\;jmp @%l0\;%L0:\";
}"
- [(set_attr "type" "branch")
+ [(set_attr "type" "bcs")
(set_attr "cc" "clobber")])
(define_insn "bcs_hiqi"
""
"*
{
+ /* The length of this insn includes the bld insn below. We
+ compute the length of the branch without the bld so we
+ can easily choose the right branch length. */
+ int branch_length = get_attr_length (insn);
+
+ if (! register_operand (operands[2], QImode))
+ branch_length -= 2;
+
output_asm_insn(\"bld %Z3,%Y2\", operands);
- if (get_attr_length (insn) == 2)
+ if (branch_length == 2)
return \"b%d1 %l0\";
- else if (get_attr_length (insn) == 4)
+ else if (branch_length == 4)
return \"b%d1 %l0:16\";
else
return \"b%g1 %L0\;jmp @%l0\;%L0:\";
}"
- [(set_attr "type" "branch")
+ [(set_attr "type" "bcs")
(set_attr "cc" "clobber")])
;; BLD and BST patterns