Hi

This is the second part of the fixing for

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47855

This patch contains the length computation for insn patterns "*arm_movqi_insn"
and "*arm_addsi3". Since the alternatives and encodings are much more complex,
the attribute length is computed in separate C functions.

The patch has been tested on qemu with both ARM and thumb mode.

thanks
Carrot

ChangeLog:
2011-04-08  Wei Guozhi  <car...@google.com>

        PR target/47855
        * config/arm/arm-protos.h (arm_attr_length_movqi): New prototype.
        (arm_attr_length_addsi3): Likewise.
        * config/arm/arm.c (arm_attr_length_movqi): New function.
        (arm_attr_length_addsi3): Likewise.
        * config/arm/arm.md (*arm_movqi_insn): Compute attr "length".
        (*arm_addsi3): Change "length" computation by calling C function.


Index: arm.c
===================================================================
--- arm.c       (revision 172017)
+++ arm.c       (working copy)
@@ -23694,4 +23694,179 @@ arm_preferred_rename_class (reg_class_t
     return NO_REGS;
 }

+/* Compute the atrribute "length" of insn "*arm_movqi_insn".
+   So this function MUST be kept in sync with that insn pattern.  */
+int
+arm_attr_length_movqi (rtx dst, rtx src)
+{
+  enum rtx_code dst_code = GET_CODE (dst);
+  enum rtx_code src_code = GET_CODE (src);
+  rtx address, reg_op, base;
+
+  /* ARM mode.  */
+  if (TARGET_ARM)
+    return 4;
+
+  /* Thumb2 mode.  */
+  /* Register move.  */
+  if ((dst_code == REG) && (src_code == REG))
+    return 2;
+
+  /* Load an immediate.  */
+  if ((dst_code == REG) && (src_code == CONST_INT))
+    {
+      HOST_WIDE_INT i = INTVAL (src);
+      if ((arm_regno_class (REGNO (dst)) == LO_REGS) && (i >= 0) && (i <= 255))
+       return 2;
+      else
+       return 4;
+    }
+
+  /* Load/store a byte from/to memory.  */
+  if ((dst_code == REG) && (src_code == MEM))
+    {
+      reg_op = dst;
+      address = XEXP (src, 0);
+    }
+  else
+    {
+      gcc_assert ((dst_code == MEM) && (src_code == REG));
+      reg_op = src;
+      address = XEXP (dst, 0);
+    }
+
+  if (GET_CODE (address) == PLUS)
+    {
+      rtx op1 = XEXP (address, 1);
+      base = XEXP (address, 0);
+      if (GET_CODE (op1) == REG)
+       {
+         if (arm_regno_class (REGNO (op1)) != LO_REGS)
+           return 4;
+       }
+      else if ((GET_CODE (op1) != CONST_INT)
+              || (INTVAL (op1) < 0) || (INTVAL (op1) > 31))
+       return 4;
+    }
+  else
+    base = address;
+
+  if (GET_CODE (base) != REG)
+    return 4;
+  if ((arm_regno_class (REGNO (base)) == LO_REGS)
+      && (arm_regno_class (REGNO (reg_op)) == LO_REGS))
+    return 2;
+
+  return 4;
+}
+
+/* Compute the atrribute "length" of insn "*arm_addsi3".
+   So this function MUST be kept in sync with that insn pattern.  */
+int
+arm_attr_length_addsi3 (rtx dst, rtx src1, rtx src2)
+{
+  HOST_WIDE_INT v;
+
+  /* The splite case.  */
+  if (which_alternative == 5)
+    return 16;
+
+  /* ARM mode.  */
+  if (TARGET_ARM)
+    return 4;
+
+  /* Thumb2 mode.  */
+  if (which_alternative == 4)
+    {
+      /* SUB (SP minus immediate).  */
+      v = -INTVAL (src2);
+      gcc_assert (v >= 0);
+      if (((v & 3) == 0) && (v < 512))
+       return 2;
+      return 4;
+    }
+  else if (which_alternative == 3)
+    {
+      /* SUB immediate.  */
+      HOST_WIDE_INT max_offset = 7;
+      v = -INTVAL (src2);
+      gcc_assert (v >= 0);
+      if (REGNO (dst) == REGNO (src1))
+       max_offset = 255;
+      if ((arm_regno_class (REGNO (dst)) == LO_REGS)
+         && (arm_regno_class (REGNO (src1)) == LO_REGS)
+         && (v <= max_offset))
+       return 2;
+      return 4;
+    }
+  else if (which_alternative == 1)
+    {
+      if (REG_P (src2))                    /* ADD SP,SP,<Rm>*/
+       return 2;
+      v = INTVAL (src2);
+      if (((v & 3) == 0) && (v < 1024))    /* ADD SP,SP,#<imm>  */
+       return 2;
+      return 4;
+    }
+  else
+    {
+      if (which_alternative == 2)
+       {
+         rtx tmp = src1; src1 = src2; src2 = tmp;
+       }
+      /* Now we are in the most general case, (which_alternative == 0).  */
+      gcc_assert (REG_P (src1));
+      if (REGNO (src1) == SP_REGNUM)
+       {
+         if (REG_P (src2))
+           {
+             /* ADD <Rdm>, SP, <Rdm>  */
+             if (REGNO (src2) == REGNO (src1))
+               return 2;
+             return 4;
+           }
+         else
+           {
+             gcc_assert (GET_CODE (src2) == CONST_INT);
+             v = INTVAL (src2);
+             /* ADD <Rd>, SP, #<imm>  */
+             if ((arm_regno_class (REGNO (dst)) == LO_REGS)
+                 && ((v & 3) == 0) && (v < 1024))
+               return 2;
+             return 4;
+           }
+       }
+      else
+       {
+         if (REG_P (src2))
+           {
+             /* ADD <Rdn>, <Rm>  */
+             if ((REGNO (dst) == REGNO (src1))
+                 || (REGNO (dst) == REGNO (src2)))
+               return 2;
+             /* ADDS <Rd>, <Rn>, <Rm>  */
+             else if ((arm_regno_class (REGNO (dst)) == LO_REGS)
+                      && (arm_regno_class (REGNO (src1)) == LO_REGS)
+                      && (arm_regno_class (REGNO (src2)) == LO_REGS))
+               return 2;
+             return 4;
+           }
+         else
+           {
+             /* ADD immediate.  */
+             HOST_WIDE_INT max_offset = 7;
+             gcc_assert (GET_CODE (src2) == CONST_INT);
+             v = INTVAL (src2);
+             if (REGNO (dst) == REGNO (src1))
+               max_offset = 255;
+             if ((arm_regno_class (REGNO (dst)) == LO_REGS)
+                 && (arm_regno_class (REGNO (src1)) == LO_REGS)
+                 && (v <= max_offset))
+               return 2;
+             return 4;
+           }
+       }
+    }
+}
+
 #include "gt-arm.h"
Index: arm-protos.h
===================================================================
--- arm-protos.h        (revision 172017)
+++ arm-protos.h        (working copy)
@@ -152,6 +152,8 @@ extern void arm_expand_sync (enum machin
 extern const char *arm_output_memory_barrier (rtx *);
 extern const char *arm_output_sync_insn (rtx, rtx *);
 extern unsigned int arm_sync_loop_insns (rtx , rtx *);
+extern int arm_attr_length_movqi (rtx, rtx);
+extern int arm_attr_length_addsi3 (rtx, rtx, rtx);

 #if defined TREE_CODE
 extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
Index: arm.md
===================================================================
--- arm.md      (revision 172017)
+++ arm.md      (working copy)
@@ -730,8 +730,10 @@
                      operands[1], 0);
   DONE;
   "
-  [(set_attr "length" "4,4,4,4,4,16")
-   (set_attr "predicable" "yes")]
+  [(set_attr "predicable" "yes")
+   (set (attr "length")
+       (symbol_ref
+         "arm_attr_length_addsi3 (operands[0], operands[1], operands[2])"))]
 )

 (define_insn_and_split "*thumb1_addsi3"
@@ -5958,7 +5960,9 @@
    str%(b%)\\t%1, %0"
   [(set_attr "type" "*,*,load1,store1")
    (set_attr "insn" "mov,mvn,*,*")
-   (set_attr "predicable" "yes")]
+   (set_attr "predicable" "yes")
+   (set (attr "length")
+       (symbol_ref "arm_attr_length_movqi (operands[0], operands[1])"))]
 )

 (define_insn "*thumb1_movqi_insn"

Reply via email to