===================================================================
@@ -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" ""))])]
+ ""
+)
===================================================================
@@ -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"
===================================================================
@@ -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
===================================================================
@@ -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);
+}
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