On Thu, Apr 11, 2019 at 09:54:24AM +0200, Richard Biener wrote: > > The following patch just punts if we find loads from stack slots in between > > where they are pushed and the const/pure call. In addition to that, I've > > outlined the same largish sequence that had 3 copies in the function already > > and I'd need to add 4th copy, so in the end the dce.c changes are removing > > more than adding: > > 1 file changed, 118 insertions(+), 135 deletions(-) > > The refactoring itself is probably OK (and if done separately > makes reviewing easier).
Here is just the refactoring, ok for trunk? 2019-04-11 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/89965 * dce.c (sp_based_mem_offset): New function. (find_call_stack_args): Use sp_based_mem_offset. --- gcc/dce.c.jj 2019-04-11 10:26:18.509365653 +0200 +++ gcc/dce.c 2019-04-11 10:30:00.436705065 +0200 @@ -272,6 +272,58 @@ check_argument_store (HOST_WIDE_INT size return true; } +/* If MEM has sp address, return 0, if it has sp + const address, + return that const, if it has reg address where reg is set to sp + const + and FAST is false, return const, otherwise return + INTTYPE_MINUMUM (HOST_WIDE_INT). */ + +static HOST_WIDE_INT +sp_based_mem_offset (rtx_call_insn *call_insn, const_rtx mem, bool fast) +{ + HOST_WIDE_INT off = 0; + rtx addr = XEXP (mem, 0); + if (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) + && CONST_INT_P (XEXP (addr, 1))) + { + off = INTVAL (XEXP (addr, 1)); + addr = XEXP (addr, 0); + } + if (addr == stack_pointer_rtx) + return off; + + if (!REG_P (addr) || fast) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + /* If not fast, use chains to see if addr wasn't set to sp + offset. */ + df_ref use; + FOR_EACH_INSN_USE (use, call_insn) + if (rtx_equal_p (addr, DF_REF_REG (use))) + break; + + if (use == NULL) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + struct df_link *defs; + for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) + if (! DF_REF_IS_ARTIFICIAL (defs->ref)) + break; + + if (defs == NULL) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + rtx set = single_set (DF_REF_INSN (defs->ref)); + if (!set) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + if (GET_CODE (SET_SRC (set)) != PLUS + || XEXP (SET_SRC (set), 0) != stack_pointer_rtx + || !CONST_INT_P (XEXP (SET_SRC (set), 1))) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + off += INTVAL (XEXP (SET_SRC (set), 1)); + return off; +} /* Try to find all stack stores of CALL_INSN arguments if ACCUMULATE_OUTGOING_ARGS. If all stack stores have been found @@ -309,58 +361,13 @@ find_call_stack_args (rtx_call_insn *cal if (GET_CODE (XEXP (p, 0)) == USE && MEM_P (XEXP (XEXP (p, 0), 0))) { - rtx mem = XEXP (XEXP (p, 0), 0), addr; - HOST_WIDE_INT off = 0, size; + rtx mem = XEXP (XEXP (p, 0), 0); + HOST_WIDE_INT size; if (!MEM_SIZE_KNOWN_P (mem) || !MEM_SIZE (mem).is_constant (&size)) return false; - addr = XEXP (mem, 0); - if (GET_CODE (addr) == PLUS - && REG_P (XEXP (addr, 0)) - && CONST_INT_P (XEXP (addr, 1))) - { - off = INTVAL (XEXP (addr, 1)); - addr = XEXP (addr, 0); - } - if (addr != stack_pointer_rtx) - { - if (!REG_P (addr)) - return false; - /* If not fast, use chains to see if addr wasn't set to - sp + offset. */ - if (!fast) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, call_insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - if (use == NULL) - return false; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - if (defs == NULL) - return false; - - set = single_set (DF_REF_INSN (defs->ref)); - if (!set) - return false; - - if (GET_CODE (SET_SRC (set)) != PLUS - || XEXP (SET_SRC (set), 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (SET_SRC (set), 1))) - return false; - - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - else - return false; - } + HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); + if (off == INTTYPE_MINIMUM (HOST_WIDE_INT)) + return false; min_sp_off = MIN (min_sp_off, off); max_sp_off = MAX (max_sp_off, off + size); } @@ -376,51 +383,19 @@ find_call_stack_args (rtx_call_insn *cal if (GET_CODE (XEXP (p, 0)) == USE && MEM_P (XEXP (XEXP (p, 0), 0))) { - rtx mem = XEXP (XEXP (p, 0), 0), addr; - HOST_WIDE_INT off = 0, byte, size; + rtx mem = XEXP (XEXP (p, 0), 0); /* Checked in the previous iteration. */ - size = MEM_SIZE (mem).to_constant (); - addr = XEXP (mem, 0); - if (GET_CODE (addr) == PLUS - && REG_P (XEXP (addr, 0)) - && CONST_INT_P (XEXP (addr, 1))) - { - off = INTVAL (XEXP (addr, 1)); - addr = XEXP (addr, 0); - } - if (addr != stack_pointer_rtx) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, call_insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - set = single_set (DF_REF_INSN (defs->ref)); - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - for (byte = off; byte < off + size; byte++) - { - if (!bitmap_set_bit (sp_bytes, byte - min_sp_off)) - gcc_unreachable (); - } + HOST_WIDE_INT size = MEM_SIZE (mem).to_constant (); + HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); + gcc_checking_assert (off != INTTYPE_MINIMUM (HOST_WIDE_INT)); + for (HOST_WIDE_INT byte = off; byte < off + size; byte++) + if (!bitmap_set_bit (sp_bytes, byte - min_sp_off)) + gcc_unreachable (); } - /* Walk backwards, looking for argument stores. The search stops - when seeing another call, sp adjustment or memory store other than - argument store. */ ret = false; for (insn = PREV_INSN (call_insn); insn; insn = prev_insn) { - rtx set, mem, addr; - HOST_WIDE_INT off; - if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn))) prev_insn = NULL; else @@ -432,61 +407,17 @@ find_call_stack_args (rtx_call_insn *cal if (!NONDEBUG_INSN_P (insn)) continue; - set = single_set (insn); + rtx set = single_set (insn); if (!set || SET_DEST (set) == stack_pointer_rtx) break; if (!MEM_P (SET_DEST (set))) continue; - mem = SET_DEST (set); - addr = XEXP (mem, 0); - off = 0; - if (GET_CODE (addr) == PLUS - && REG_P (XEXP (addr, 0)) - && CONST_INT_P (XEXP (addr, 1))) - { - off = INTVAL (XEXP (addr, 1)); - addr = XEXP (addr, 0); - } - if (addr != stack_pointer_rtx) - { - if (!REG_P (addr)) - break; - if (!fast) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - if (use == NULL) - break; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - if (defs == NULL) - break; - - set = single_set (DF_REF_INSN (defs->ref)); - if (!set) - break; - - if (GET_CODE (SET_SRC (set)) != PLUS - || XEXP (SET_SRC (set), 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (SET_SRC (set), 1))) - break; - - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - else - break; - } + rtx mem = SET_DEST (set); + HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); + if (off == INTTYPE_MINIMUM (HOST_WIDE_INT)) + break; HOST_WIDE_INT size; if (!MEM_SIZE_KNOWN_P (mem) Jakub