h8300.md: Add more comments about things which seem wrong...
authorJeff Law <law@gcc.gnu.org>
Sat, 13 Apr 1996 06:37:29 +0000 (00:37 -0600)
committerJeff Law <law@gcc.gnu.org>
Sat, 13 Apr 1996 06:37:29 +0000 (00:37 -0600)
        * 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

gcc/config/h8300/h8300.c
gcc/config/h8300/h8300.h
gcc/config/h8300/h8300.md

index 165d993798b503a7b7da28daaf141adab38aa8d2..af452f95eff2e47310f7ca1841e48c6dcc5af108 100644 (file)
@@ -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).  */
 
index c6d6b924fc12e58b1aab3a6d321803a1c4f1ae4c..40768c45296c3fcb822d33f6d18d9b7aa7422a03 100644 (file)
@@ -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 */
 \f
 /* 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();
index ccd51b5db23d39001d9dca4a8e07c12b407fd644..833264cea70c9db40e0bcf2ce9954f96b0765af1 100644 (file)
 
 ;; ??? 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.
                                                   (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