diff options
author | Jeff Law <law@gcc.gnu.org> | 1996-04-13 00:37:29 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 1996-04-13 00:37:29 -0600 |
commit | 3b7d443c2cc40d48c9a8cb9bebfda792a07c4b22 (patch) | |
tree | 5b90be234951b6d64f687c60bed87b17b1000245 | |
parent | 2ca96cdfebda96a7a10b7df909251a75b7552b7e (diff) | |
download | gcc-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.c | 83 | ||||
-rw-r--r-- | gcc/config/h8300/h8300.h | 10 | ||||
-rw-r--r-- | gcc/config/h8300/h8300.md | 212 |
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 |