Alex Coplan writes:
> Hi,
>
> In PR112906 we ICE because we try to use force_reg to reload an
> auto-increment address, but force_reg can't do this.
>
> With the aim of fixing the PR by supporting reloading arbitrary
> addresses in pre-RA splitters, this patch generalizes
> lra-constraints.cc:emit_inc and makes it available to the rest of the
> compiler by moving the generalized version to emit-rtl.cc.
>
> We observe that the separate IN parameter to LRA's emit_inc is
> redundant, since the function is static and is only (statically) called
> once in lra-constraints.cc, with in == value. As such, we drop the IN
> parameter and simplify the code accordingly.
>
> We wrap the emit_inc code in a virtual class to allow LRA to override
> how reload pseudos are created, thereby preserving the existing LRA
> behaviour as much as possible.
>
> We then add a second (higher-level) routine to emit-rtl.cc,
> force_reload_address, which can reload arbitrary addresses. This uses
> the generalized emit_inc code to handle the RTX_AUTOINC case. The
> second patch in this series uses force_reload_address to fix PR112906.
>
> Since we intend to call address_reload_context::emit_autoinc from within
> splitters, and the code lifted from LRA calls recog, we have to avoid
> clobbering recog_data. We do this by introducing a new RAII class for
> saving/restoring recog_data on the stack.
>
> Bootstrapped/regtested on aarch64-linux-gnu, bootstrapped on
> x86_64-linux-gnu, OK for trunk?
>
> Thanks,
> Alex
>
> gcc/ChangeLog:
>
> PR target/112906
> * emit-rtl.cc (address_reload_context::emit_autoinc): New.
> (force_reload_address): New.
> * emit-rtl.h (struct address_reload_context): Declare.
> (force_reload_address): Declare.
> * lra-constraints.cc (class lra_autoinc_reload_context): New.
> (emit_inc): Drop IN parameter, invoke
> code moved to emit-rtl.cc:address_reload_context::emit_autoinc.
> (curr_insn_transform): Drop redundant IN parameter in call to
> emit_inc.
> * recog.h (class recog_data_saver): New.
LGTM, and looks like it should functionally be a no-op for LRA.
So OK, but please give Vlad 24 hours to comment, or to ask for more time.
Thanks,
Richard
>
> diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
> index 4a7e420e7c0..ce7b98bf006 100644
> --- a/gcc/emit-rtl.cc
> +++ b/gcc/emit-rtl.cc
> @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see
> #include "rtl-iter.h"
> #include "stor-layout.h"
> #include "opts.h"
> +#include "optabs.h"
> #include "predict.h"
> #include "rtx-vector-builder.h"
> #include "gimple.h"
> @@ -2576,6 +2577,140 @@ replace_equiv_address_nv (rtx memref, rtx addr, bool
> inplace)
>return change_address_1 (memref, VOIDmode, addr, 0, inplace);
> }
>
> +
> +/* Emit insns to reload VALUE into a new register. VALUE is an
> + auto-increment or auto-decrement RTX whose operand is a register or
> + memory location; so reloading involves incrementing that location.
> +
> + INC_AMOUNT is the number to increment or decrement by (always
> + positive and ignored for POST_MODIFY/PRE_MODIFY).
> +
> + Return a pseudo containing the result. */
> +rtx
> +address_reload_context::emit_autoinc (rtx value, poly_int64 inc_amount)
> +{
> + /* Since we're going to call recog, and might be called within recog,
> + we need to ensure we save and restore recog_data. */
> + recog_data_saver recog_save;
> +
> + /* REG or MEM to be copied and incremented. */
> + rtx incloc = XEXP (value, 0);
> +
> + const rtx_code code = GET_CODE (value);
> + const bool post_p
> += code == POST_DEC || code == POST_INC || code == POST_MODIFY;
> +
> + bool plus_p = true;
> + rtx inc;
> + if (code == PRE_MODIFY || code == POST_MODIFY)
> +{
> + gcc_assert (GET_CODE (XEXP (value, 1)) == PLUS
> + || GET_CODE (XEXP (value, 1)) == MINUS);
> + gcc_assert (rtx_equal_p (XEXP (XEXP (value, 1), 0), XEXP (value, 0)));
> + plus_p = GET_CODE (XEXP (value, 1)) == PLUS;
> + inc = XEXP (XEXP (value, 1), 1);
> +}
> + else
> +{
> + if (code == PRE_DEC || code == POST_DEC)
> + inc_amount = -inc_amount;
> +
> + inc = gen_int_mode (inc_amount, GET_MODE (value));
> +}
> +
> + rtx result;
> + if (!post_p && REG_P (incloc))
> +result = incloc;
> + else
> +{
> + result = get_reload_reg ();
> + /* First copy the location to the result register. */
> + emit_insn (gen_move_insn (result, incloc));
> +}
> +
> + /* See if we can directly increment INCLOC. */
> + rtx_insn *last = get_last_insn ();
> + rtx_insn *add_insn = emit_insn (plus_p
> + ? gen_add2_insn (incloc, inc)
> + : gen_sub2_insn (incloc, inc));
> + const int icode = recog_memoized (add_insn);
> + if (icode >= 0)
> +{
> + if (!post_p && result != incloc)
> + emit_insn (gen_move_insn (result, incloc));
> + return res