From patchwork Sun Aug 22 05:28:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [PATCH:, ARM] PR 45335 Use ldrd and strd to access two consecutive words From: Carrot Wei X-Patchwork-Id: 62360 Message-Id: To: gcc-patches@gcc.gnu.org Date: Sun, 22 Aug 2010 13:28:50 +0800 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 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 PR target/45335 * gcc.target/arm/pr45335.c: New test. thanks Wei Guozhi 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); +}