From 125b98b127933b7c2d375d3471dc24afa2825993 Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Wed, 13 Feb 2019 16:22:25 +0000 Subject: [PATCH] [ARM] Fix Thumb-1 ldm (PR89190) This patch fixes an ICE in the Thumb-1 LDM peepholer. Thumb-1 LDMs always update the base register except if the base is loaded. The current implementation rejects LDMs where the base is not dead, however this doesn't exclude the case where the base is loaded as well as dead. Fix this by explicitly checking whether the base is loaded. Also enable LDMs which load the first register. gcc/ PR target/89190 * config/arm/arm.c (ldm_stm_operation_p) Set addr_reg_in_reglist correctly for first register. (load_multiple_sequence): Remove dead base check. (gen_ldm_seq): Correctly set write_back for Thumb-1. testsuite/ PR target/89190 * gcc.target/arm/pr89190.c: New test. From-SVN: r268848 --- gcc/ChangeLog | 8 ++++++++ gcc/config/arm/arm.c | 24 ++++++++++++++---------- gcc/testsuite/ChangeLog | 5 +++++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 76cef68bed1..6729c6d3869 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2019-02-13 Wilco Dijkstra + + PR target/89190 + * config/arm/arm.c (ldm_stm_operation_p) Set + addr_reg_in_reglist correctly for first register. + (load_multiple_sequence): Remove dead base check. + (gen_ldm_seq): Correctly set write_back for Thumb-1. + 2019-02-13 Tamar Christina PR target/88847 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index e9aba65c705..f07f4cc47b6 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -13191,6 +13191,9 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode, if (load && (REGNO (reg) == SP_REGNUM) && (REGNO (addr) != SP_REGNUM)) return false; + if (regno == REGNO (addr)) + addr_reg_in_reglist = true; + for (; i < count; i++) { elt = XVECEXP (op, 0, i); @@ -13385,7 +13388,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order, int unsorted_regs[MAX_LDM_STM_OPS]; HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS]; int order[MAX_LDM_STM_OPS]; - rtx base_reg_rtx = NULL; int base_reg = -1; int i, ldm_case; @@ -13430,7 +13432,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order, if (i == 0) { base_reg = REGNO (reg); - base_reg_rtx = reg; if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM) return 0; } @@ -13489,10 +13490,6 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order, *load_offset = unsorted_offsets[order[0]]; } - if (TARGET_THUMB1 - && !peep2_reg_dead_p (nops, base_reg_rtx)) - return 0; - if (unsorted_offsets[order[0]] == 0) ldm_case = 1; /* ldmia */ else if (TARGET_ARM && unsorted_offsets[order[0]] == 4) @@ -13868,9 +13865,17 @@ gen_ldm_seq (rtx *operands, int nops, bool sort_regs) if (TARGET_THUMB1) { - gcc_assert (peep2_reg_dead_p (nops, base_reg_rtx)); gcc_assert (ldm_case == 1 || ldm_case == 5); - write_back = TRUE; + + /* Thumb-1 ldm uses writeback except if the base is loaded. */ + write_back = true; + for (i = 0; i < nops; i++) + if (base_reg == regs[i]) + write_back = false; + + /* Ensure the base is dead if it is updated. */ + if (write_back && !peep2_reg_dead_p (nops, base_reg_rtx)) + return false; } if (ldm_case == 5) @@ -13878,8 +13883,7 @@ gen_ldm_seq (rtx *operands, int nops, bool sort_regs) rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG (SImode, regs[0]); emit_insn (gen_addsi3 (newbase, base_reg_rtx, GEN_INT (offset))); offset = 0; - if (!TARGET_THUMB1) - base_reg_rtx = newbase; + base_reg_rtx = newbase; } for (i = 0; i < nops; i++) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 583b0452d61..f1a8295aef9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-02-13 Wilco Dijkstra + + PR target/89190 + * gcc.target/arm/pr89190.c: New test. + 2019-02-13 David Malcolm PR c++/89036 -- 2.30.2