aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1996-04-13 00:37:29 -0600
committerJeff Law <law@gcc.gnu.org>1996-04-13 00:37:29 -0600
commit3b7d443c2cc40d48c9a8cb9bebfda792a07c4b22 (patch)
tree5b90be234951b6d64f687c60bed87b17b1000245
parent2ca96cdfebda96a7a10b7df909251a75b7552b7e (diff)
downloadgcc-3b7d443c2cc40d48c9a8cb9bebfda792a07c4b22.zip
gcc-3b7d443c2cc40d48c9a8cb9bebfda792a07c4b22.tar.gz
gcc-3b7d443c2cc40d48c9a8cb9bebfda792a07c4b22.tar.bz2
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
-rw-r--r--gcc/config/h8300/h8300.c83
-rw-r--r--gcc/config/h8300/h8300.h10
-rw-r--r--gcc/config/h8300/h8300.md212
3 files changed, 252 insertions, 53 deletions
diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index 165d993..af452f9 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -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). */
diff --git a/gcc/config/h8300/h8300.h b/gcc/config/h8300/h8300.h
index c6d6b92..40768c4 100644
--- a/gcc/config/h8300/h8300.h
+++ b/gcc/config/h8300/h8300.h
@@ -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();
diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md
index ccd51b5d..833264c 100644
--- a/gcc/config/h8300/h8300.md
+++ b/gcc/config/h8300/h8300.md
@@ -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