return 4;
}
-/* Check the validity of operands in an ldrd/strd instruction. */
-bool
-arm_check_ldrd_operands (rtx reg1, rtx reg2, rtx off1, rtx off2)
-{
- HOST_WIDE_INT offset1 = 0;
- HOST_WIDE_INT offset2 = 0;
- int regno1 = REGNO (reg1);
- int regno2 = REGNO (reg2);
- HOST_WIDE_INT max_offset = 1020;
-
- if (TARGET_ARM)
- max_offset = 255;
-
- if (off1 != NULL_RTX)
- offset1 = INTVAL (off1);
- if (off2 != NULL_RTX)
- offset2 = INTVAL (off2);
-
- /* The offset range of LDRD is [-max_offset, max_offset]. Here we check if
- both offsets lie in the range [-max_offset, max_offset+4]. If one of the
- offsets is max_offset+4, the following condition
- ((offset1 + 4) == offset2)
- will ensure offset1 to be max_offset, suitable for instruction LDRD. */
- if ((offset1 > (max_offset + 4)) || (offset1 < -max_offset)
- || ((offset1 & 3) != 0))
- return false;
- if ((offset2 > (max_offset + 4)) || (offset2 < -max_offset)
- || ((offset2 & 3) != 0))
- return false;
-
- if ((offset1 + 4) == offset2)
- {
- if (TARGET_THUMB2)
- return true;
-
- /* TARGET_ARM */
- if (((regno1 & 1) == 0) && ((regno1 + 1) == regno2)) /* ldrd */
- return true;
-
- if ((regno1 < regno2) && ((offset1 <= 4) && (offset1 >= -8))) /* ldm */
- return true;
- }
- if ((offset2 + 4) == offset1)
- {
- if (TARGET_THUMB2)
- return true;
-
- /* TARGET_ARM */
- if (((regno2 & 1) == 0) && ((regno2 + 1) == regno1)) /* ldrd */
- return true;
-
- if ((regno2 < regno1) && ((offset2 <= 4) && (offset2 >= -8))) /* ldm */
- return true;
- }
-
- return false;
-}
-
-/* Check if the two memory accesses can be merged to an ldrd/strd instruction.
- That is they use the same base register, and the gap between constant
- offsets should be 4. */
-bool
-arm_legitimate_ldrd_p (rtx reg1, rtx reg2, rtx mem1, rtx mem2, bool ldrd)
-{
- rtx base1, base2;
- rtx offset1 = NULL_RTX;
- rtx offset2 = NULL_RTX;
- rtx addr1 = XEXP (mem1, 0);
- rtx addr2 = XEXP (mem2, 0);
-
- if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
- return false;
-
- if (REG_P (addr1))
- base1 = addr1;
- else if (GET_CODE (addr1) == PLUS)
- {
- base1 = XEXP (addr1, 0);
- offset1 = XEXP (addr1, 1);
- if (!REG_P (base1) || (GET_CODE (offset1) != CONST_INT))
- return false;
- }
- else
- return false;
-
- if (REG_P (addr2))
- base2 = addr2;
- else if (GET_CODE (addr2) == PLUS)
- {
- base2 = XEXP (addr2, 0);
- offset2 = XEXP (addr2, 1);
- if (!REG_P (base2) || (GET_CODE (offset2) != CONST_INT))
- return false;
- }
- else
- return false;
-
- if (base1 != base2)
- return false;
-
- if (ldrd && ((reg1 == reg2) || (reg1 == base1)))
- return false;
-
- return arm_check_ldrd_operands (reg1, reg2, offset1, offset2);
-}
-
-/* Output instructions for ldrd and count the number of bytes has been
- outputted. Do not actually output instructions if EMIT_P is false. */
-int
-arm_output_ldrd (rtx reg1, rtx reg2, rtx base, rtx off1, rtx off2, bool emit_p)
-{
- int length = 0;
- rtx operands[5];
- HOST_WIDE_INT offset1 = 0;
- HOST_WIDE_INT offset2 = 0;
-
- if (off1 != NULL_RTX)
- offset1 = INTVAL (off1);
- else
- off1 = GEN_INT (0);
- if (off2 != NULL_RTX)
- offset2 = INTVAL (off2);
- else
- off2 = GEN_INT (0);
- if (offset1 > offset2)
- {
- rtx tmp;
- HOST_WIDE_INT t = offset1; offset1 = offset2; offset2 = t;
- tmp = off1; off1 = off2; off2 = tmp;
- tmp = reg1; reg1 = reg2; reg2 = tmp;
- }
-
- operands[0] = reg1;
- operands[1] = reg2;
- operands[2] = base;
- operands[3] = off1;
- operands[4] = off2;
-
- if (TARGET_THUMB2)
- {
- if (fix_cm3_ldrd && (base == reg1))
- {
- if (offset1 <= -256)
- {
- if (emit_p)
- output_asm_insn ("sub\t%2, %2, %n3", operands);
- length = 4;
-
- if (emit_p)
- output_asm_insn ("ldr\t%1, [%2, #4]", operands);
- if (low_register_operand (reg2, SImode)
- && low_register_operand (base, SImode))
- length += 2;
- else
- length += 4;
-
- if (emit_p)
- output_asm_insn ("ldr\t%0, [%2]", operands);
- if (low_register_operand (base, SImode))
- length += 2;
- else
- length += 4;
- }
- else
- {
- if (emit_p)
- output_asm_insn ("ldr\t%1, [%2, %4]", operands);
- if (low_register_operand (reg2, SImode) && (offset2 >= 0)
- && low_register_operand (base, SImode) && (offset2 < 128))
- length += 2;
- else
- length += 4;
-
- if (emit_p)
- output_asm_insn ("ldr\t%0, [%2, %3]", operands);
- if (low_register_operand (base, SImode)
- && (offset1 >= 0) && (offset1 < 128))
- length += 2;
- else
- length += 4;
- }
- }
- else
- {
- if (emit_p)
- output_asm_insn ("ldrd\t%0, %1, [%2, %3]", operands);
- length = 4;
- }
- }
- else /* TARGET_ARM */
- {
- if ((REGNO (reg2) == (REGNO (reg1) + 1)) && ((REGNO (reg1) & 1) == 0))
- {
- if (emit_p)
- output_asm_insn ("ldrd\t%0, %1, [%2, %3]", operands);
- length = 4;
- }
- else
- {
- if (emit_p)
- {
- switch (offset1)
- {
- case -8:
- output_asm_insn ("ldm%(db%)\t%2, {%0, %1}", operands);
- break;
-
- case -4:
- output_asm_insn ("ldm%(da%)\t%2, {%0, %1}", operands);
- break;
-
- case 0:
- output_asm_insn ("ldm%(ia%)\t%2, {%0, %1}", operands);
- break;
-
- case 4:
- output_asm_insn ("ldm%(ib%)\t%2, {%0, %1}", operands);
- break;
-
- default:
- gcc_unreachable ();
- }
- }
- length = 4;
- }
- }
-
- return length;
-}
-
#include "gt-arm.h"
(set (match_operand:SI 2 "arm_hard_register_operand" "")
(mem:SI (plus:SI (match_dup 3)
(const_int 4))))])]
- "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
"ldm%(ia%)\t%3, {%1, %2}"
[(set_attr "type" "load2")
(set_attr "predicable" "yes")])
(match_operand:SI 1 "arm_hard_register_operand" ""))
(set (mem:SI (plus:SI (match_dup 3) (const_int 4)))
(match_operand:SI 2 "arm_hard_register_operand" ""))])]
- "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
"stm%(ia%)\t%3, {%1, %2}"
[(set_attr "type" "store2")
(set_attr "predicable" "yes")])
(set (match_operand:SI 2 "arm_hard_register_operand" "")
(mem:SI (plus:SI (match_dup 3)
(const_int 8))))])]
- "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
"ldm%(ib%)\t%3, {%1, %2}"
[(set_attr "type" "load2")
(set_attr "predicable" "yes")])
(match_operand:SI 1 "arm_hard_register_operand" ""))
(set (mem:SI (plus:SI (match_dup 3) (const_int 8)))
(match_operand:SI 2 "arm_hard_register_operand" ""))])]
- "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
"stm%(ib%)\t%3, {%1, %2}"
[(set_attr "type" "store2")
(set_attr "predicable" "yes")])
(const_int -4))))
(set (match_operand:SI 2 "arm_hard_register_operand" "")
(mem:SI (match_dup 3)))])]
- "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
"ldm%(da%)\t%3, {%1, %2}"
[(set_attr "type" "load2")
(set_attr "predicable" "yes")])
(match_operand:SI 1 "arm_hard_register_operand" ""))
(set (mem:SI (match_dup 3))
(match_operand:SI 2 "arm_hard_register_operand" ""))])]
- "TARGET_ARM && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
"stm%(da%)\t%3, {%1, %2}"
[(set_attr "type" "store2")
(set_attr "predicable" "yes")])
(set (match_operand:SI 2 "arm_hard_register_operand" "")
(mem:SI (plus:SI (match_dup 3)
(const_int -4))))])]
- "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
"ldm%(db%)\t%3, {%1, %2}"
[(set_attr "type" "load2")
(set_attr "predicable" "yes")])
(match_operand:SI 1 "arm_hard_register_operand" ""))
(set (mem:SI (plus:SI (match_dup 3) (const_int -4)))
(match_operand:SI 2 "arm_hard_register_operand" ""))])]
- "TARGET_32BIT && !arm_arch7 && XVECLEN (operands[0], 0) == 2"
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
"stm%(db%)\t%3, {%1, %2}"
[(set_attr "type" "store2")
(set_attr "predicable" "yes")])
FAIL;
})
-(define_insn "*ldrd"
- [(set (match_operand:SI 0 "arm_hard_register_operand" "")
- (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
- (match_operand:SI 3 "const_int_operand" ""))))
- (set (match_operand:SI 1 "arm_hard_register_operand" "")
- (mem:SI (plus:SI (match_dup 2)
- (match_operand:SI 4 "const_int_operand" ""))))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1],
- operands[3], operands[4])"
- "*
- arm_output_ldrd (operands[0], operands[1],
- operands[2], operands[3], operands[4], true);
- return \"\";
- "
- [(set (attr "length")
- (symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
- operands[3], operands[4], false)")))]
-)
-
-(define_insn "*ldrd_reg1"
- [(set (match_operand:SI 0 "arm_hard_register_operand" "")
- (mem:SI (match_operand:SI 2 "s_register_operand" "rk")))
- (set (match_operand:SI 1 "arm_hard_register_operand" "")
- (mem:SI (plus:SI (match_dup 2)
- (match_operand:SI 3 "const_int_operand" ""))))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1], NULL_RTX, operands[3])"
- "*
- arm_output_ldrd (operands[0], operands[1],
- operands[2], NULL_RTX, operands[3], true);
- return \"\";
- "
- [(set (attr "length")
- (symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
- NULL_RTX, operands[3], false)")))]
-)
-
-(define_insn "*ldrd_reg2"
- [(set (match_operand:SI 0 "arm_hard_register_operand" "")
- (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
- (match_operand:SI 3 "const_int_operand" ""))))
- (set (match_operand:SI 1 "arm_hard_register_operand" "")
- (mem:SI (match_dup 2)))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1], operands[3], NULL_RTX)"
- "*
- arm_output_ldrd (operands[0], operands[1],
- operands[2], operands[3], NULL_RTX, true);
- return \"\";
- "
- [(set (attr "length")
- (symbol_ref ("arm_output_ldrd (operands[0], operands[1], operands[2],
- operands[3], NULL_RTX, false)")))]
-)
-
-(define_peephole2
- [(set (match_operand:SI 0 "arm_general_register_operand" "")
- (match_operand:SI 2 "memory_operand" ""))
- (set (match_operand:SI 1 "arm_general_register_operand" "")
- (match_operand:SI 3 "memory_operand" ""))]
- "TARGET_32BIT && arm_arch7
- && arm_legitimate_ldrd_p (operands[0], operands[1],
- operands[2], operands[3], true)"
- [(parallel [(set (match_operand:SI 0 "arm_general_register_operand" "")
- (match_operand:SI 2 "memory_operand" ""))
- (set (match_operand:SI 1 "arm_general_register_operand" "")
- (match_operand:SI 3 "memory_operand" ""))])]
- ""
-)
-
-(define_insn "*strd"
- [(set (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
- (match_operand:SI 3 "const_int_operand" "")))
- (match_operand:SI 0 "arm_hard_register_operand" ""))
- (set (mem:SI (plus:SI (match_dup 2)
- (match_operand:SI 4 "const_int_operand" "")))
- (match_operand:SI 1 "arm_hard_register_operand" ""))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1],
- operands[3], operands[4])"
- "*
- {
- HOST_WIDE_INT offset1 = INTVAL (operands[3]);
- HOST_WIDE_INT offset2 = INTVAL (operands[4]);
- if (offset1 > offset2)
- {
- rtx tmp = operands[0]; operands[0] = operands[1]; operands[1] = tmp;
- tmp = operands[3]; operands[3] = operands[4]; operands[4] = tmp;
- offset1 = INTVAL (operands[3]);
- offset2 = INTVAL (operands[4]);
- }
- if (TARGET_THUMB2)
- return \"strd\\t%0, %1, [%2, %3]\";
- else /* TARGET_ARM */
- {
- if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
- && ((REGNO (operands[0]) & 1) == 0))
- return \"strd\\t%0, %1, [%2, %3]\";
- else if (offset1 == -8)
- return \"stm%(db%)\\t%2, {%0, %1}\";
- else /* offset1 == 4 */
- return \"stm%(ib%)\\t%2, {%0, %1}\";
- }
- }"
- [(set_attr "length" "4")]
-)
-
-(define_insn "*strd_reg1"
- [(set (mem:SI (match_operand:SI 2 "s_register_operand" "rk"))
- (match_operand:SI 0 "arm_hard_register_operand" ""))
- (set (mem:SI (plus:SI (match_dup 2)
- (match_operand:SI 3 "const_int_operand" "")))
- (match_operand:SI 1 "arm_hard_register_operand" ""))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1], NULL_RTX, operands[3])"
- "*
- {
- HOST_WIDE_INT offset2 = INTVAL (operands[3]);
- if (TARGET_THUMB2)
- {
- if (offset2 == 4)
- return \"strd\\t%0, %1, [%2]\";
- else
- return \"strd\\t%1, %0, [%2, %3]\";
- }
- else /* TARGET_ARM */
- {
- if (offset2 == 4)
- {
- if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
- && ((REGNO (operands[0]) & 1) == 0))
- return \"strd\\t%0, %1, [%2]\";
- else
- return \"stm%(ia%)\\t%2, {%0, %1}\";
- }
- else /* offset2 == -4 */
- {
- if ((REGNO (operands[0]) == (REGNO (operands[1]) + 1))
- && ((REGNO (operands[1]) & 1) == 0))
- return \"strd\\t%1, %0, [%2, %3]\";
- else
- return \"stm%(da%)\\t%2, {%1, %0}\";
- }
- }
- }"
- [(set_attr "length" "4")]
-)
-
-(define_insn "*strd_reg2"
- [(set (mem:SI (plus:SI (match_operand:SI 2 "s_register_operand" "rk")
- (match_operand:SI 3 "const_int_operand" "")))
- (match_operand:SI 0 "arm_hard_register_operand" ""))
- (set (mem:SI (match_dup 2))
- (match_operand:SI 1 "arm_hard_register_operand" ""))]
- "TARGET_32BIT && arm_arch7
- && arm_check_ldrd_operands (operands[0], operands[1], operands[3], NULL_RTX)"
- "*
- {
- HOST_WIDE_INT offset1 = INTVAL (operands[3]);
- if (TARGET_THUMB2)
- {
- if (offset1 == -4)
- return \"strd\\t%0, %1, [%2, %3]\";
- else
- return \"strd\\t%1, %0, [%2]\";
- }
- else /* TARGET_ARM */
- {
- if (offset1 == -4)
- {
- if ((REGNO (operands[1]) == (REGNO (operands[0]) + 1))
- && ((REGNO (operands[0]) & 1) == 0))
- return \"strd\\t%0, %1, [%2, %3]\";
- else
- return \"stm%(da%)\\t%2, {%0, %1}\";
- }
- else
- {
- if ((REGNO (operands[0]) == (REGNO (operands[1]) + 1))
- && ((REGNO (operands[1]) & 1) == 0))
- return \"strd\\t%1, %0, [%2]\";
- else
- return \"stm%(ia%)\\t%2, {%1, %0}\";
- }
- }
- }"
- [(set_attr "length" "4")]
-)
-
-(define_peephole2
- [(set (match_operand:SI 2 "memory_operand" "")
- (match_operand:SI 0 "arm_general_register_operand" ""))
- (set (match_operand:SI 3 "memory_operand" "")
- (match_operand:SI 1 "arm_general_register_operand" ""))]
- "TARGET_32BIT && arm_arch7
- && arm_legitimate_ldrd_p (operands[0], operands[1],
- operands[2], operands[3], false)"
- [(parallel [(set (match_operand:SI 2 "memory_operand" "")
- (match_operand:SI 0 "arm_general_register_operand" ""))
- (set (match_operand:SI 3 "memory_operand" "")
- (match_operand:SI 1 "arm_general_register_operand" ""))])]
- ""
-)