diff mbox

[PATCH:,ARM] PR 45335 Use ldrd and strd to access two consecutive words

Message ID AANLkTim+nD_6m5PwDBkz0BVz1Ftr+DYyih17nXX5LMue@mail.gmail.com
State New
Headers show

Commit Message

Carrot Wei Aug. 22, 2010, 5:28 a.m. UTC
Hi

Current arm compiler can't merge the two consecutive load or store into ldrd or
strd. This patch adds new patterns of ldrd and strd, and new peephole2 rules to
do the optimization.

This patch handles thumb2 instructions only. For arm instructions there are more
constraints on the register usage, it's better to be handled before register
allocation.

This patch has been tested on qemu with thumb2 instructions.

ChangeLog:
2010-08-22  Wei Guozhi  <carrot@google.com>

        PR target/45335
        * gcc/config/arm/thumb2.md (*thumb2_ldrd and peephole2): New insn
        pattern and related peephole2.
        (*thumb2_strd and peephole2): New insn pattern and related peephole2.
        * gcc/config/arm/arm.c (thumb2_ldrd_addr): New function.
        * gcc/config/arm/arm-protos.h (thumb2_ldrd_addr): New prototype.

		
2010-08-22  Wei Guozhi  <carrot@google.com>

        PR target/45335
        * gcc.target/arm/pr45335.c: New test.

thanks
Wei Guozhi
diff mbox

Patch

Index: thumb2.md
===================================================================
--- thumb2.md   (revision 163363)
+++ thumb2.md   (working copy)
@@ -1257,3 +1257,69 @@ 
   "
   operands[2] = GEN_INT (32 - INTVAL (operands[2]));
   ")
+
+(define_insn "*thumb2_ldrd"
+  [(parallel [(set (match_operand:SI 0 "s_register_operand" "")
+                  (mem:SI (match_operand:SI 2 "" "")))
+             (set (match_operand:SI 1 "s_register_operand" "")
+                  (mem:SI (match_operand:SI 3 "" "")))])]
+  "TARGET_THUMB2 &&
+   thumb2_ldrd_addr (operands[0], operands[1], operands[2], operands[3], 1)"
+  "*
+  {
+    rtx ldrd_addr = thumb2_ldrd_addr (operands[0], operands[1],
+                                     operands[2], operands[3], 1);
+    operands[4] = gen_rtx_MEM (SImode, ldrd_addr);
+    if (ldrd_addr == operands[3])
+      return \"ldrd\\t%1, %0, %4\";
+    else
+      return \"ldrd\\t%0, %1, %4\";
+  }"
+)
+
+(define_peephole2
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (mem:SI (match_operand:SI 2 "" "")))
+   (set (match_operand:SI 1 "s_register_operand" "")
+       (mem:SI (match_operand:SI 3 "" "")))]
+  "TARGET_THUMB2 &&
+   thumb2_ldrd_addr (operands[0], operands[1], operands[2], operands[3], 1)"
+  [(parallel [(set (match_operand:SI 0 "s_register_operand" "")
+                  (mem:SI (match_operand:SI 2 "" "")))
+             (set (match_operand:SI 1 "s_register_operand" "")
+                  (mem:SI (match_operand:SI 3 "" "")))])]
+  ""
+)
+
+(define_insn "*thumb2_strd"
+  [(parallel [(set (mem:SI (match_operand:SI 2 "" ""))
+                  (match_operand:SI 0 "s_register_operand" ""))
+             (set (mem:SI (match_operand:SI 3 "" ""))
+                  (match_operand:SI 1 "s_register_operand" ""))])]
+  "TARGET_THUMB2 &&
+   thumb2_ldrd_addr (operands[0], operands[1], operands[2], operands[3], 0)"
+  "*
+  {
+    rtx strd_addr = thumb2_ldrd_addr (operands[0], operands[1],
+                                     operands[2], operands[3], 0);
+    operands[4] = gen_rtx_MEM (SImode, strd_addr);
+    if (strd_addr == operands[3])
+      return \"strd\\t%1, %0, %4\";
+    else
+      return \"strd\\t%0, %1, %4\";
+  }"
+)
+
+(define_peephole2
+  [(set (mem:SI (match_operand:SI 2 "" ""))
+       (match_operand:SI 0 "s_register_operand" ""))
+   (set (mem:SI (match_operand:SI 3 "" ""))
+       (match_operand:SI 1 "s_register_operand" ""))]
+  "TARGET_THUMB2 &&
+   thumb2_ldrd_addr (operands[0], operands[1], operands[2], operands[3], 0)"
+  [(parallel [(set (mem:SI (match_operand:SI 2 "" ""))
+                  (match_operand:SI 0 "s_register_operand" ""))
+             (set (mem:SI (match_operand:SI 3 "" ""))
+                  (match_operand:SI 1 "s_register_operand" ""))])]
+  ""
+)
Index: arm.c
===================================================================
--- arm.c       (revision 163363)
+++ arm.c       (working copy)
@@ -22959,4 +22959,76 @@  arm_expand_sync (enum machine_mode mode,
     }
 }

+/* Check if the two memory addresses can be accessed by an ldrd instruction.
+   That is they use the same base register, and the gap between constant
+   offsets should be 4. It can also be used for strd instruction.
+   If so return the lower address, otherwise return NULL.  */
+rtx
+thumb2_ldrd_addr (rtx dest1, rtx dest2, rtx addr1, rtx addr2, bool ldrd)
+{
+  rtx reg1, reg2, op0, op1;
+  rtx addr = NULL;
+  HOST_WIDE_INT offset1 = 0;
+  HOST_WIDE_INT offset2 = 0;
+
+  switch (GET_CODE (addr1))
+    {
+    case REG:
+      reg1 = addr1;
+      break;
+
+    case PLUS:
+      op0 = XEXP (addr1, 0);
+      op1 = XEXP (addr1, 1);
+      if ((GET_CODE (op0) != REG) || (GET_CODE (op1) != CONST_INT))
+       return NULL;
+      reg1 = op0;
+      offset1 = INTVAL (op1);
+      break;
+
+    default:
+      return NULL;
+    }
+
+  switch (GET_CODE (addr2))
+    {
+    case REG:
+      reg2 = addr2;
+      break;
+
+    case PLUS:
+      op0 = XEXP (addr2, 0);
+      op1 = XEXP (addr2, 1);
+      if ((GET_CODE (op0) != REG) || (GET_CODE (op1) != CONST_INT))
+       return NULL;
+      reg2 = op0;
+      offset2 = INTVAL (op1);
+      break;
+
+    default:
+      return NULL;
+    }
+
+  if (reg1 != reg2)
+    return NULL;
+
+  if (ldrd && ((dest1 == dest2) || (dest1 == reg1)))
+    return NULL;
+
+  if ((offset1 + 4) == offset2)
+    addr = addr1;
+  else if ((offset2 + 4) == offset1)
+  {
+      addr = addr2;
+      offset1 = offset2;
+  }
+  else
+    return NULL;
+
+  if (((offset1 % 4) != 0) || (offset1 > 1020) || (offset1 < -1020))
+    return NULL;
+
+  return addr;
+}
+
 #include "gt-arm.h"
Index: arm-protos.h
===================================================================
--- arm-protos.h        (revision 163363)
+++ arm-protos.h        (working copy)
@@ -149,7 +149,7 @@  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 rtx thumb2_ldrd_addr (rtx, rtx, rtx, rtx, bool);
 extern bool arm_output_addr_const_extra (FILE *, rtx);

 #if defined TREE_CODE


Index: pr45335.c
===================================================================
--- pr45335.c   (revision 0)
+++ pr45335.c   (revision 0)
@@ -0,0 +1,20 @@ 
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-final { scan-assembler "ldrd" } } */
+/* { dg-final { scan-assembler "strd" } } */
+
+struct S
+{
+    void* p1;
+    void* p2;
+    void* p3;
+    void* p4;
+};
+
+void foo1(struct S* fp, struct S* otherSaveArea)
+{
+    struct S* saveA = fp - 1;
+    printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveA, otherSaveArea);
+    printf("prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+        saveA->p1, saveA->p2, saveA->p3, saveA->p4, *(unsigned int*)fp);
+}