Commit 3b7d443c by Jeff Law

h8300.md: Add more comments about things which seem wrong...

        * h8300.md: Add more comments about things which seem
        wrong, stupid, or just don't make any sense yet.

        * h8300.c (adds_subs_operand): New function.
        (output_adds_subs): New function.
        * h8300.md (addhi3): Turn into a define_expand.
        (addhi3 using adds_subs): New pattern.
        (H8300 addhi): Derived from old addhi pattern.  Simplified.
        (H8300H addhi): Likewise.
        (addsi using adds_subs): New pattern.  Only used on H8300H.
        (addsi_h8300): Allow "a" registers as destination.
        (addsi_h8300h):  Simplify.  Allow "a" registers as destination.

        * h8300.md (bcs): New attribute type.
        (default_length): Compute correct length for bcs insns.
        (bcs_qiqi, bcs_hihi, bs_hiqi): Use new type and update
        to account for correct length computation.

        * h8300.md (movhi_internal): Demand at least one operand to
        be a register.
        (movsi_h8300): Optimize loading certain constants.
        (movsi_h8300h): Likewise.

        * h8300.h (NO_FUNCTION_CSE): Comment out.
        (FUNCTION_ARG_REGNO_P): Properly define for TARGET_QUICKCALL.
        (RETURN_IN_MEMORY): Don't return small structs in regs.

From-SVN: r11751
parent 2ca96cdf
......@@ -431,6 +431,89 @@ call_insn_operand (op, mode)
return 0;
}
int
adds_subs_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
{
if (INTVAL (op) <= 4 && INTVAL (op) >= 0)
return 1;
if (INTVAL (op) >= -4 && INTVAL (op) <= 0)
return 1;
if (TARGET_H8300H
&& INTVAL (op) != 7
&& (INTVAL (op) <= 8 || INTVAL (op) >= 0))
return 1;
if (TARGET_H8300H
&& INTVAL (op) != -7
&& (INTVAL (op) >= -8 || INTVAL (op) <= 0))
return 1;
}
return 0;
}
char *
output_adds_subs (operands)
rtx *operands;
{
int val = INTVAL (operands[2]);
/* First get the value into the range -4..4 inclusive.
The only way it can be out of this range is when TARGET_H8300H
is true, thus it is safe to use adds #4 and subs #4. */
if (val > 4)
{
output_asm_insn ("adds #4,%A0", operands);
val -= 4;
}
if (val < -4)
{
output_asm_insn ("subs #4,%A0", operands);
val += 4;
}
/* Handle case were val == 4 or val == -4 and we're compiling
for TARGET_H8300H. */
if (TARGET_H8300H && val == 4)
return "adds #4,%A0";
if (TARGET_H8300H && val == -4)
return "subs #4,%A0";
if (val > 2)
{
output_asm_insn ("adds #2,%A0", operands);
val -= 2;
}
if (val < -2)
{
output_asm_insn ("subs #2,%A0", operands);
val += 2;
}
/* val should be one or two now. */
if (val == 2)
return "adds #2,%A0";
if (val == -2)
return "subs #2,%A0";
/* val should be one now. */
if (val == 1)
return "adds #1,%A0";
if (val == -1)
return "subs #1,%A0";
/* In theory, this can't happen. */
abort ();
}
/* Return true if OP is a valid call operand, and OP represents
an operand for a small call (4 bytes instead of 6 bytes). */
......
......@@ -126,7 +126,7 @@ do { \
shouldn't be put through pseudo regs where they can be cse'd.
Desirable on machines where ordinary constants are expensive
but a CALL with constant address is cheap. */
#define NO_FUNCTION_CSE
/* #define NO_FUNCTION_CSE */
/* Target machine storage layout */
......@@ -541,9 +541,8 @@ enum reg_class {
/* 1 if N is a possible register number for function argument passing.
On the H8, no registers are used in this way. */
/* ??? What about TARGET_QUICKCALL? */
#define FUNCTION_ARG_REGNO_P(N) 0
#define FUNCTION_ARG_REGNO_P(N) (TARGET_QUICKCALL ? N < 3 : 0)
/* Register in which address to store a structure value
is passed to a function. */
......@@ -551,8 +550,8 @@ enum reg_class {
#define STRUCT_VALUE 0
/* Return true if X should be returned in memory. */
/* ??? This will return small structs in regs. */
#define RETURN_IN_MEMORY(X) (GET_MODE_SIZE (TYPE_MODE (X)) > 4)
#define RETURN_IN_MEMORY(X) \
(TYPE_MODE (X) == BLKmode || GET_MODE_SIZE (TYPE_MODE (X)) > 4)
/* When defined, the compiler allows registers explicitly used in the
rtl to be used as spill registers but prevents the compiler from
......@@ -1342,3 +1341,4 @@ do { char dstr[30]; \
/* Declarations for functions used in insn-output.c. */
char *emit_a_shift ();
int h8300_funcvec_function_p ();
char *output_adds_subs();
......@@ -31,6 +31,10 @@
;; ??? 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?
......@@ -42,7 +46,7 @@
;; 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.
......@@ -61,6 +65,28 @@
(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)
......@@ -150,6 +176,8 @@
;; 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"))]
......@@ -168,7 +196,8 @@
(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
......@@ -299,11 +328,19 @@
}
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:
......@@ -380,13 +417,38 @@
"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")])
......@@ -514,23 +576,49 @@
;; 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" "")
......@@ -539,8 +627,20 @@
""
"")
;; 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"
......@@ -552,25 +652,17 @@
(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
......@@ -1676,15 +1768,23 @@
""
"*
{
/* 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"
......@@ -1700,15 +1800,23 @@
""
"*
{
/* 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"
......@@ -1724,15 +1832,23 @@
""
"*
{
/* 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment