Hi! As mentioned in the PR, armv7hl-linux-gnueabi doesn't currently bootstrap with --enable-checking=release (and profiledbootstrap is broken too), the problem is that e.g. tree-ssa-sccvn.c is miscompiled.
The problem is that the various ldrdstrd.md peephole2s generate for non-thumb{1,2} DImode loads and stores, but just use whatever alias set and MEM_EXPR and other MEM attributes the first of the two MEMs had. That is wrong e.g. for alias oracle and during the tree-ssa-sccvn.c compilation sched2 because of that reorders ldrd with another store that must not be reordered. One possibility is to force alias set of 0 and clear MEM_EXPR, but that pessimizes code too much (there is a patch in the PR that I've bootstrapped/regtested and we are using temporarily in Fedora). The following patch instead creates new patterns that keep referencing the two original MEMs, so no unification of alias sets or MEM_EXPRs is needed. Bootstrapped/regtested on armv7hl-linux-gnueabi (c,c++ only), distro build (all languages) still ongoing (25 hours and hasn't even finished bootstrap), ok for trunk? In the PR, Matthew Malcomson suggested some changes, I'm fine e.g. with adding && arm_legitimate_address_p (DImode, XEXP (operands[?], 0), true) to the conditions (or add some helper function that calls this and checks other stuff), but I really don't have access to hw where I can reasonably test this. There is also a question whether ldm2_* or ldrd are preferrable, etc. If ldrd is faster, then e.g. ldrdstrd.md is missing a peephole2 that would handle reg1 = const1; reg2 = const2; mem1 = reg1; mem2 = reg2;, it only handles reg1 = const1; mem1 = reg1; reg2 = const2; mem2 = reg2; but sched1 in many cases reorders that. Or if somebody wants to take the patch over from here, fine with me too. As I wrote in the PR, I see also some cleanup possibilities for GCC10 in the ARM backend, something that has been done a few years ago in x86 and recently e.g. also in rs6000, removals of "" constraints from match_operand, use of REG_P/MEM_P etc. macros, formatting fixes. 2019-01-31 Jakub Jelinek <ja...@redhat.com> PR bootstrap/88714 * config/arm/arm.c (gen_operands_ldrd_strd): If successful, for TARGET_ARM adjust operands[3] to be always PLUS of operands[2] and 4. Formatting fixes. * config/arm/ldrdstrd.md: Handle TARGET_ARM like TARGET_THUMB2 in all peephole2s, use peephole2 patterns where possible instead of generating code by hand + DONE. Formatting fixes. * config/arm/arm.md (*arm_ldrd, *arm_strd): New define_insns. (*thumb2_ldrd, *thumb2_ldrd_base, *thumb2_ldrd_base_neg, *thumb2_strd, *thumb2_strd_base, *thumb2_strd_base_neg): Formatting fixes. * config/arm/vfd.md (*ldrd_vfp, *strd_vfp): New define_insns. * config/arm/iwmmxt.md (*iwmmxt_arm_ldrd, *iwmmxt_arm_strd): Likewise. * gcc.c-torture/execute/pr88714.c: New test. --- gcc/config/arm/arm.c.jj 2019-01-22 23:26:46.815210588 +0100 +++ gcc/config/arm/arm.c 2019-01-30 11:31:58.626214346 +0100 @@ -15748,7 +15748,7 @@ gen_operands_ldrd_strd (rtx *operands, b /* Make sure we generate legal instructions. */ if (operands_ok_ldrd_strd (operands[0], operands[1], base, offset, false, load)) - return true; + goto ok; /* In Thumb state, where registers are almost unconstrained, there is little hope to fix it. */ @@ -15761,7 +15761,7 @@ gen_operands_ldrd_strd (rtx *operands, b std::swap (operands[0], operands[1]); if (operands_ok_ldrd_strd (operands[0], operands[1], base, offset, false, load)) - return true; + goto ok; } if (const_store) @@ -15785,10 +15785,10 @@ gen_operands_ldrd_strd (rtx *operands, b strd r0, [r2] */ if (operands_ok_ldrd_strd (operands[1], operands[0], base, offset, - false, false)) + false, false)) { std::swap (operands[0], operands[1]); - return true; + goto ok; } /* Try to find a free DI register. */ @@ -15810,13 +15810,22 @@ gen_operands_ldrd_strd (rtx *operands, b gcc_assert (REGNO (operands[0]) % 2 == 0); gcc_assert (REGNO (operands[0]) + 1 == REGNO (operands[1])); - return (operands_ok_ldrd_strd (operands[0], operands[1], - base, offset, - false, load)); + if (operands_ok_ldrd_strd (operands[0], operands[1], + base, offset, false, load)) + goto ok; } } return false; + + ok: + if (TARGET_ARM) + { + rtx a = gen_rtx_PLUS (SImode, copy_rtx (XEXP (operands[nops], 0)), + GEN_INT (4)); + operands[nops + 1] = replace_equiv_address_nv (operands[nops + 1], a); + } + return true; } --- gcc/config/arm/ldrdstrd.md.jj 2019-01-18 00:33:18.292022358 +0100 +++ gcc/config/arm/ldrdstrd.md 2019-01-30 11:52:00.726149716 +0100 @@ -26,34 +26,15 @@ (define_peephole2 ; ldrd [(set (match_operand:SI 0 "arm_general_register_operand" "") - (match_operand:SI 2 "memory_operand" "")) + (match_operand:SI 2 "memory_operand" "")) (set (match_operand:SI 1 "arm_general_register_operand" "") - (match_operand:SI 3 "memory_operand" ""))] + (match_operand:SI 3 "memory_operand" ""))] "TARGET_LDRD" - [(const_int 0)] + [(parallel [(set (match_dup 0) (match_dup 2)) + (set (match_dup 1) (match_dup 3))])] { if (!gen_operands_ldrd_strd (operands, true, false, false)) FAIL; - else if (TARGET_ARM) - { - /* In ARM state, the destination registers of LDRD/STRD must be - consecutive. We emit DImode access. */ - operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - /* Emit [(set (match_dup 0) (match_dup 2))] */ - emit_insn (gen_rtx_SET (operands[0], operands[2])); - DONE; - } - else if (TARGET_THUMB2) - { - /* Emit the pattern: - [(parallel [(set (match_dup 0) (match_dup 2)) - (set (match_dup 1) (match_dup 3))])] */ - rtx t1 = gen_rtx_SET (operands[0], operands[2]); - rtx t2 = gen_rtx_SET (operands[1], operands[3]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, t1, t2))); - DONE; - } }) (define_peephole2 ; strd @@ -62,117 +43,50 @@ (define_peephole2 ; strd (set (match_operand:SI 3 "memory_operand" "") (match_operand:SI 1 "arm_general_register_operand" ""))] "TARGET_LDRD" - [(const_int 0)] + [(parallel [(set (match_dup 2) (match_dup 0)) + (set (match_dup 3) (match_dup 1))])] { if (!gen_operands_ldrd_strd (operands, false, false, false)) FAIL; - else if (TARGET_ARM) - { - /* In ARM state, the destination registers of LDRD/STRD must be - consecutive. We emit DImode access. */ - operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - /* Emit [(set (match_dup 2) (match_dup 0))] */ - emit_insn (gen_rtx_SET (operands[2], operands[0])); - DONE; - } - else if (TARGET_THUMB2) - { - /* Emit the pattern: - [(parallel [(set (match_dup 2) (match_dup 0)) - (set (match_dup 3) (match_dup 1))])] */ - rtx t1 = gen_rtx_SET (operands[2], operands[0]); - rtx t2 = gen_rtx_SET (operands[3], operands[1]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, t1, t2))); - DONE; - } }) ;; The following peepholes reorder registers to enable LDRD/STRD. (define_peephole2 ; strd of constants [(set (match_operand:SI 0 "arm_general_register_operand" "") - (match_operand:SI 4 "const_int_operand" "")) + (match_operand:SI 4 "const_int_operand" "")) (set (match_operand:SI 2 "memory_operand" "") - (match_dup 0)) + (match_dup 0)) (set (match_operand:SI 1 "arm_general_register_operand" "") - (match_operand:SI 5 "const_int_operand" "")) + (match_operand:SI 5 "const_int_operand" "")) (set (match_operand:SI 3 "memory_operand" "") - (match_dup 1))] + (match_dup 1))] "TARGET_LDRD" - [(const_int 0)] + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 1) (match_dup 5)) + (parallel [(set (match_dup 2) (match_dup 0)) + (set (match_dup 3) (match_dup 1))])] { if (!gen_operands_ldrd_strd (operands, false, true, false)) FAIL; - else if (TARGET_ARM) - { - rtx tmp = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - /* Emit the pattern: - [(set (match_dup 0) (match_dup 4)) - (set (match_dup 1) (match_dup 5)) - (set (match_dup 2) tmp)] */ - emit_insn (gen_rtx_SET (operands[0], operands[4])); - emit_insn (gen_rtx_SET (operands[1], operands[5])); - emit_insn (gen_rtx_SET (operands[2], tmp)); - DONE; - } - else if (TARGET_THUMB2) - { - /* Emit the pattern: - [(set (match_dup 0) (match_dup 4)) - (set (match_dup 1) (match_dup 5)) - (parallel [(set (match_dup 2) (match_dup 0)) - (set (match_dup 3) (match_dup 1))])] */ - emit_insn (gen_rtx_SET (operands[0], operands[4])); - emit_insn (gen_rtx_SET (operands[1], operands[5])); - rtx t1 = gen_rtx_SET (operands[2], operands[0]); - rtx t2 = gen_rtx_SET (operands[3], operands[1]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, t1, t2))); - DONE; - } }) (define_peephole2 ; strd of constants [(set (match_operand:SI 0 "arm_general_register_operand" "") - (match_operand:SI 4 "const_int_operand" "")) + (match_operand:SI 4 "const_int_operand" "")) (set (match_operand:SI 1 "arm_general_register_operand" "") - (match_operand:SI 5 "const_int_operand" "")) + (match_operand:SI 5 "const_int_operand" "")) (set (match_operand:SI 2 "memory_operand" "") - (match_dup 0)) + (match_dup 0)) (set (match_operand:SI 3 "memory_operand" "") - (match_dup 1))] + (match_dup 1))] "TARGET_LDRD" - [(const_int 0)] + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 1) (match_dup 5)) + (parallel [(set (match_dup 2) (match_dup 0)) + (set (match_dup 3) (match_dup 1))])] { if (!gen_operands_ldrd_strd (operands, false, true, false)) FAIL; - else if (TARGET_ARM) - { - rtx tmp = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - /* Emit the pattern - [(set (match_dup 0) (match_dup 4)) - (set (match_dup 1) (match_dup 5)) - (set (match_dup 2) tmp)] */ - emit_insn (gen_rtx_SET (operands[0], operands[4])); - emit_insn (gen_rtx_SET (operands[1], operands[5])); - emit_insn (gen_rtx_SET (operands[2], tmp)); - DONE; - } - else if (TARGET_THUMB2) - { - /* Emit the pattern: - [(set (match_dup 0) (match_dup 4)) - (set (match_dup 1) (match_dup 5)) - (parallel [(set (match_dup 2) (match_dup 0)) - (set (match_dup 3) (match_dup 1))])] */ - emit_insn (gen_rtx_SET (operands[0], operands[4])); - emit_insn (gen_rtx_SET (operands[1], operands[5])); - rtx t1 = gen_rtx_SET (operands[2], operands[0]); - rtx t2 = gen_rtx_SET (operands[3], operands[1]); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, t1, t2))); - DONE; - } }) ;; The following two peephole optimizations are only relevant for ARM @@ -181,67 +95,60 @@ (define_peephole2 ; strd of constants (define_peephole2 ; swap the destination registers of two loads ; before a commutative operation. [(set (match_operand:SI 0 "arm_general_register_operand" "") - (match_operand:SI 2 "memory_operand" "")) + (match_operand:SI 2 "memory_operand" "")) (set (match_operand:SI 1 "arm_general_register_operand" "") - (match_operand:SI 3 "memory_operand" "")) + (match_operand:SI 3 "memory_operand" "")) (set (match_operand:SI 4 "arm_general_register_operand" "") - (match_operator:SI 5 "commutative_binary_operator" - [(match_operand 6 "arm_general_register_operand" "") - (match_operand 7 "arm_general_register_operand" "") ]))] + (match_operator:SI 5 "commutative_binary_operator" + [(match_operand 6 "arm_general_register_operand" "") + (match_operand 7 "arm_general_register_operand" "")]))] "TARGET_LDRD && TARGET_ARM - && ( ((rtx_equal_p(operands[0], operands[6])) && (rtx_equal_p(operands[1], operands[7]))) - ||((rtx_equal_p(operands[0], operands[7])) && (rtx_equal_p(operands[1], operands[6])))) - && (peep2_reg_dead_p (3, operands[0]) || rtx_equal_p (operands[0], operands[4])) - && (peep2_reg_dead_p (3, operands[1]) || rtx_equal_p (operands[1], operands[4]))" - [(set (match_dup 0) (match_dup 2)) + && ((rtx_equal_p (operands[0], operands[6]) + && rtx_equal_p (operands[1], operands[7])) + || (rtx_equal_p (operands[0], operands[7]) + && rtx_equal_p (operands[1], operands[6]))) + && (peep2_reg_dead_p (3, operands[0]) + || rtx_equal_p (operands[0], operands[4])) + && (peep2_reg_dead_p (3, operands[1]) + || rtx_equal_p (operands[1], operands[4]))" + [(parallel [(set (match_dup 0) (match_dup 2)) + (set (match_dup 1) (match_dup 3))]) (set (match_dup 4) (match_op_dup 5 [(match_dup 6) (match_dup 7)]))] - { - if (!gen_operands_ldrd_strd (operands, true, false, true)) - { - FAIL; - } - else - { - operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - } - } -) +{ + if (!gen_operands_ldrd_strd (operands, true, false, true)) + FAIL; +}) (define_peephole2 ; swap the destination registers of two loads ; before a commutative operation that sets the flags. [(set (match_operand:SI 0 "arm_general_register_operand" "") - (match_operand:SI 2 "memory_operand" "")) + (match_operand:SI 2 "memory_operand" "")) (set (match_operand:SI 1 "arm_general_register_operand" "") - (match_operand:SI 3 "memory_operand" "")) + (match_operand:SI 3 "memory_operand" "")) (parallel [(set (match_operand:SI 4 "arm_general_register_operand" "") (match_operator:SI 5 "commutative_binary_operator" - [(match_operand 6 "arm_general_register_operand" "") - (match_operand 7 "arm_general_register_operand" "") ])) + [(match_operand 6 "arm_general_register_operand" "") + (match_operand 7 "arm_general_register_operand" "")])) (clobber (reg:CC CC_REGNUM))])] "TARGET_LDRD && TARGET_ARM - && ( ((rtx_equal_p(operands[0], operands[6])) && (rtx_equal_p(operands[1], operands[7]))) - ||((rtx_equal_p(operands[0], operands[7])) && (rtx_equal_p(operands[1], operands[6])))) - && (peep2_reg_dead_p (3, operands[0]) || rtx_equal_p (operands[0], operands[4])) - && (peep2_reg_dead_p (3, operands[1]) || rtx_equal_p (operands[1], operands[4]))" + && ((rtx_equal_p (operands[0], operands[6]) + && rtx_equal_p (operands[1], operands[7])) + || (rtx_equal_p (operands[0], operands[7]) + && rtx_equal_p (operands[1], operands[6]))) + && (peep2_reg_dead_p (3, operands[0]) + || rtx_equal_p (operands[0], operands[4])) + && (peep2_reg_dead_p (3, operands[1]) + || rtx_equal_p (operands[1], operands[4]))" [(set (match_dup 0) (match_dup 2)) (parallel [(set (match_dup 4) (match_op_dup 5 [(match_dup 6) (match_dup 7)])) (clobber (reg:CC CC_REGNUM))])] - { - if (!gen_operands_ldrd_strd (operands, true, false, true)) - { - FAIL; - } - else - { - operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); - operands[2] = adjust_address (operands[2], DImode, 0); - } - } -) +{ + if (!gen_operands_ldrd_strd (operands, true, false, true)) + FAIL; +}) ;; TODO: Handle LDRD/STRD with writeback: ;; (a) memory operands can be POST_INC, POST_DEC, PRE_MODIFY, POST_MODIFY --- gcc/config/arm/arm.md.jj 2019-01-10 11:43:20.102283812 +0100 +++ gcc/config/arm/arm.md 2019-01-30 11:56:52.749274712 +0100 @@ -5940,6 +5940,44 @@ (define_split " ) +(define_insn "*arm_ldrd" + [(set (match_operand:SI 0 "s_register_operand" "=q,q") + (match_operand:SI 1 "memory_operand" "m,m")) + (set (match_operand:SI 2 "s_register_operand" "=q,q") + (mem:SI (plus:SI (match_operand:SI 3 "address_operand" "p,p") + (const_int 4))))] + "TARGET_ARM && !TARGET_HARD_FLOAT && !TARGET_IWMMXT && TARGET_LDRD + && reload_completed + && REGNO (operands[0]) + 1 == REGNO (operands[2]) + && rtx_equal_p (XEXP (operands[1], 0), operands[3])" +{ + rtx op[2]; + op[0] = gen_rtx_REG (DImode, REGNO (operands[0])); + op[1] = adjust_address (operands[1], DImode, 0); + return output_move_double (op, true, NULL); +} + [(set_attr "length" "8") + (set_attr "type" "load_8")]) + +(define_insn "*arm_strd" + [(set (match_operand:SI 0 "memory_operand" "=m,m") + (match_operand:SI 1 "s_register_operand" "q,q")) + (set (mem:SI (plus:SI (match_operand:SI 2 "address_operand" "p,p") + (const_int 4))) + (match_operand:SI 3 "s_register_operand" "q,q"))] + "TARGET_ARM && !TARGET_HARD_FLOAT && !TARGET_IWMMXT && TARGET_LDRD + && reload_completed + && REGNO (operands[1]) + 1 == REGNO (operands[3]) + && rtx_equal_p (XEXP (operands[0], 0), operands[2])" +{ + rtx op[2]; + op[0] = adjust_address (operands[0], DImode, 0); + op[1] = gen_rtx_REG (DImode, REGNO (operands[1])); + return output_move_double (op, true, NULL); +} + [(set_attr "length" "8") + (set_attr "type" "store_8")]) + (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] @@ -11931,10 +11969,10 @@ (define_insn "*thumb2_ldrd" (mem:SI (plus:SI (match_dup 1) (match_operand:SI 4 "const_int_operand" ""))))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && ((INTVAL (operands[2]) + 4) == INTVAL (operands[4])) - && (operands_ok_ldrd_strd (operands[0], operands[3], - operands[1], INTVAL (operands[2]), - false, true))" + && INTVAL (operands[2]) + 4 == INTVAL (operands[4]) + && operands_ok_ldrd_strd (operands[0], operands[3], + operands[1], INTVAL (operands[2]), + false, true)" "ldrd%?\t%0, %3, [%1, %2]" [(set_attr "type" "load_8") (set_attr "predicable" "yes")]) @@ -11946,8 +11984,8 @@ (define_insn "*thumb2_ldrd_base" (mem:SI (plus:SI (match_dup 1) (const_int 4))))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && (operands_ok_ldrd_strd (operands[0], operands[2], - operands[1], 0, false, true))" + && operands_ok_ldrd_strd (operands[0], operands[2], + operands[1], 0, false, true)" "ldrd%?\t%0, %2, [%1]" [(set_attr "type" "load_8") (set_attr "predicable" "yes")]) @@ -11959,8 +11997,8 @@ (define_insn "*thumb2_ldrd_base_neg" (set (match_operand:SI 2 "s_register_operand" "=r") (mem:SI (match_dup 1)))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && (operands_ok_ldrd_strd (operands[0], operands[2], - operands[1], -4, false, true))" + && operands_ok_ldrd_strd (operands[0], operands[2], + operands[1], -4, false, true)" "ldrd%?\t%0, %2, [%1, #-4]" [(set_attr "type" "load_8") (set_attr "predicable" "yes")]) @@ -11973,10 +12011,10 @@ (define_insn "*thumb2_strd" (match_operand:SI 3 "const_int_operand" ""))) (match_operand:SI 4 "s_register_operand" "r"))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && ((INTVAL (operands[1]) + 4) == INTVAL (operands[3])) - && (operands_ok_ldrd_strd (operands[2], operands[4], - operands[0], INTVAL (operands[1]), - false, false))" + && INTVAL (operands[1]) + 4 == INTVAL (operands[3]) + && operands_ok_ldrd_strd (operands[2], operands[4], + operands[0], INTVAL (operands[1]), + false, false)" "strd%?\t%2, %4, [%0, %1]" [(set_attr "type" "store_8") (set_attr "predicable" "yes")]) @@ -11988,8 +12026,8 @@ (define_insn "*thumb2_strd_base" (const_int 4))) (match_operand:SI 2 "s_register_operand" "r"))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && (operands_ok_ldrd_strd (operands[1], operands[2], - operands[0], 0, false, false))" + && operands_ok_ldrd_strd (operands[1], operands[2], + operands[0], 0, false, false)" "strd%?\t%1, %2, [%0]" [(set_attr "type" "store_8") (set_attr "predicable" "yes")]) @@ -12001,8 +12039,8 @@ (define_insn "*thumb2_strd_base_neg" (set (mem:SI (match_dup 0)) (match_operand:SI 2 "s_register_operand" "r"))] "TARGET_LDRD && TARGET_THUMB2 && reload_completed - && (operands_ok_ldrd_strd (operands[1], operands[2], - operands[0], -4, false, false))" + && operands_ok_ldrd_strd (operands[1], operands[2], + operands[0], -4, false, false)" "strd%?\t%1, %2, [%0, #-4]" [(set_attr "type" "store_8") (set_attr "predicable" "yes")]) --- gcc/config/arm/vfp.md.jj 2019-01-16 09:35:03.887334295 +0100 +++ gcc/config/arm/vfp.md 2019-01-30 11:57:58.450177904 +0100 @@ -365,6 +365,47 @@ (define_insn "*movdi_vfp" (set_attr "arch" "t2,any,any,any,a,t2,any,any,any,any,any,any")] ) +(define_insn "*ldrd_vfp" + [(set (match_operand:SI 0 "s_register_operand" "=q,q") + (match_operand:SI 1 "memory_operand" "m,m")) + (set (match_operand:SI 2 "s_register_operand" "=q,q") + (mem:SI (plus:SI (match_operand:SI 3 "address_operand" "p,p") + (const_int 4))))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_LDRD + && reload_completed + && REGNO (operands[0]) + 1 == REGNO (operands[2]) + && rtx_equal_p (XEXP (operands[1], 0), operands[3])" +{ + rtx op[2]; + op[0] = gen_rtx_REG (DImode, REGNO (operands[0])); + op[1] = adjust_address (operands[1], DImode, 0); + return output_move_double (op, true, NULL); +} + [(set_attr "type" "load_8") + (set (attr "length") (symbol_ref "arm_count_output_move_double_insns (operands) * 4")) + (set (attr "ce_count") (symbol_ref "get_attr_length (insn) / 4")) + (set_attr "arch" "a,t2")]) + +(define_insn "*strd_vfp" + [(set (match_operand:SI 0 "memory_operand" "=m,m") + (match_operand:SI 1 "s_register_operand" "q,q")) + (set (mem:SI (plus:SI (match_operand:SI 2 "address_operand" "p,p") + (const_int 4))) + (match_operand:SI 3 "s_register_operand" "q,q"))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_LDRD + && reload_completed + && REGNO (operands[1]) + 1 == REGNO (operands[3]) + && rtx_equal_p (XEXP (operands[0], 0), operands[2])" +{ + rtx op[2]; + op[0] = adjust_address (operands[0], DImode, 0); + op[1] = gen_rtx_REG (DImode, REGNO (operands[1])); + return output_move_double (op, true, NULL); +} + [(set_attr "type" "store_8") + (set (attr "length") (symbol_ref "arm_count_output_move_double_insns (operands) * 4")) + (set (attr "ce_count") (symbol_ref "get_attr_length (insn) / 4"))]) + ;; HFmode moves (define_insn "*movhf_vfp_fp16" --- gcc/config/arm/iwmmxt.md.jj 2019-01-01 12:37:26.903815045 +0100 +++ gcc/config/arm/iwmmxt.md 2019-01-30 11:57:31.846622019 +0100 @@ -161,6 +161,44 @@ (define_insn "*iwmmxt_arm_movdi" (set_attr "arm_neg_pool_range" "*,*,*,1008,*,*,*,*,*,*,*,*,*,1008,*")] ) +(define_insn "*iwmmxt_arm_ldrd" + [(set (match_operand:SI 0 "s_register_operand" "=r,r") + (match_operand:SI 1 "memory_operand" "m,m")) + (set (match_operand:SI 2 "s_register_operand" "=r,r") + (mem:SI (plus:SI (match_operand:SI 3 "address_operand" "p,p") + (const_int 4))))] + "TARGET_REALLY_IWMMXT && TARGET_ARM && TARGET_LDRD + && reload_completed + && REGNO (operands[0]) + 1 == REGNO (operands[2]) + && rtx_equal_p (XEXP (operands[1], 0), operands[3])" +{ + rtx op[2]; + op[0] = gen_rtx_REG (DImode, REGNO (operands[0])); + op[1] = adjust_address (operands[1], DImode, 0); + return output_move_double (op, true, NULL); +} + [(set_attr "length" "8") + (set_attr "type" "load_8")]) + +(define_insn "*iwmmxt_arm_strd" + [(set (match_operand:SI 0 "memory_operand" "=m,m") + (match_operand:SI 1 "s_register_operand" "r,r")) + (set (mem:SI (plus:SI (match_operand:SI 2 "address_operand" "p,p") + (const_int 4))) + (match_operand:SI 3 "s_register_operand" "r,r"))] + "TARGET_REALLY_IWMMXT && TARGET_ARM && TARGET_LDRD + && reload_completed + && REGNO (operands[1]) + 1 == REGNO (operands[3]) + && rtx_equal_p (XEXP (operands[0], 0), operands[2])" +{ + rtx op[2]; + op[0] = adjust_address (operands[0], DImode, 0); + op[1] = gen_rtx_REG (DImode, REGNO (operands[1])); + return output_move_double (op, true, NULL); +} + [(set_attr "length" "8") + (set_attr "type" "store_8")]) + (define_insn "*iwmmxt_movsi_insn" [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,r,r,rk, m,z,r,?z,?Uy,*t, r,*t,*t ,*Uv") (match_operand:SI 1 "general_operand" " rk,I,K,j,mi,rk,r,z,Uy, z, r,*t,*t,*Uvi, *t"))] --- gcc/testsuite/gcc.c-torture/execute/pr88714.c.jj 2019-01-30 12:08:33.534524511 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr88714.c 2019-01-30 12:08:33.534524511 +0100 @@ -0,0 +1,43 @@ +/* PR bootstrap/88714 */ + +struct S { int a, b, c; int *d; }; +struct T { int *e, *f, *g; } *t = 0; +int *o = 0; + +__attribute__((noipa)) +void bar (int *x, int y, int z, int w) +{ + if (w == -1) + { + if (x != 0 || y != 0 || z != 0) + __builtin_abort (); + } + else if (w != 0 || x != t->g || y != 0 || z != 12) + __builtin_abort (); +} + +__attribute__((noipa)) void +foo (struct S *x, struct S *y, int *z, int w) +{ + *o = w; + if (w) + bar (0, 0, 0, -1); + x->d = z; + if (y->d) + y->c = y->c + y->d[0]; + bar (t->g, 0, y->c, 0); +} + +int +main () +{ + int a[4] = { 8, 9, 10, 11 }; + struct S s = { 1, 2, 3, &a[0] }; + struct T u = { 0, 0, &a[3] }; + o = &a[2]; + t = &u; + foo (&s, &s, &a[1], 5); + if (s.c != 12 || s.d != &a[1]) + __builtin_abort (); + return 0; +} Jakub