On 08/04/11 10:57, Carrot Wei wrote:
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.


Sorry, no. This is potentially a maintenance pain. It hardcodes alternatives from a pattern elsewhere in the C file. I don't like doing this unless we have to with the sync primitives or with push_multi. In this case I'm not convinced we need such functions in the .c file.

Why can't we use the "enabled" attribute here with appropriate constraints for everything other than the memory cases (even there we might be able to invent some new constraints) ?

Also a note about programming style. There are the helper macros like REG_P, CONST_INT_P and MEM_P which remove the necessity for checks like

GET_CODE (x) == y where y E { REG, CONST_INT, MEM}


cheers
Ramana


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