[PATCH, GCC, stage1] Fallback to copy-prop if constant-prop not possible
Richard Biener
rguenther@suse.de
Mon Feb 16 10:54:00 GMT 2015
On Mon, 16 Feb 2015, Thomas Preud'homme wrote:
> Hi,
>
> The RTL cprop pass in GCC operates by doing a local constant/copy
> propagation first and then a global one. In the local one, if a constant
> cannot be propagated (eg. due to constraints of the destination
> instruction) a copy propagation is done instead. However, at the global
> level copy propagation is only tried if no constant can be propagated,
> ie. if a constant can be propagated but the constraints of the
> destination instruction forbids it, no copy propagation will be tried.
> This patch fixes this issue. This solves the redundant ldr problem in
> GCC32RM-439.
I think Steven is more familiar with this code.
Richard.
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2015-01-21 Thomas Preud'homme thomas.preudhomme@arm.com
>
> * cprop.c (find_avail_set): Return up to two sets, one whose source is
> a register and one whose source is a constant. Sets are returned in
> an array passed as parameter rather than as a return value.
> (cprop_insn): Use a do while loop rather than a goto. Try each of the
> sets returned by find_avail_set, starting with the one whose source is
> a constant.
>
>
> *** gcc/testsuite/ChangeLog ***
>
> 2015-01-21 Thomas Preud'homme thomas.preudhomme@arm.com
>
> * gcc.target/arm/pr64616.c: New file.
>
> Following testing was done:
>
> Bootstrapped on x86_64 and ran the testsuite without regression
> Build an arm-none-eabi cross-compilers and ran the testsuite without regression with QEMU emulating a Cortex-M3
> Compiled CSiBE targeting x86_64 and Cortex-M3 arm-none-eabi without regression
>
> diff --git a/gcc/cprop.c b/gcc/cprop.c
> index 4538291..c246d4b 100644
> --- a/gcc/cprop.c
> +++ b/gcc/cprop.c
> @@ -815,15 +815,15 @@ try_replace_reg (rtx from, rtx to, rtx_insn *insn)
> return success;
> }
>
> -/* Find a set of REGNOs that are available on entry to INSN's block. Return
> - NULL no such set is found. */
> +/* Find a set of REGNOs that are available on entry to INSN's block. If found,
> + SET_RET[0] will be assigned a set with a register source and SET_RET[1] a
> + set with a constant source. If not found the corresponding entry is set to
> + NULL. */
>
> -static struct cprop_expr *
> -find_avail_set (int regno, rtx_insn *insn)
> +static void
> +find_avail_set (int regno, rtx_insn *insn, struct cprop_expr *set_ret[2])
> {
> - /* SET1 contains the last set found that can be returned to the caller for
> - use in a substitution. */
> - struct cprop_expr *set1 = 0;
> + set_ret[0] = set_ret[1] = NULL;
>
> /* Loops are not possible here. To get a loop we would need two sets
> available at the start of the block containing INSN. i.e. we would
> @@ -863,8 +863,10 @@ find_avail_set (int regno, rtx_insn *insn)
> If the source operand changed, we may still use it for the next
> iteration of this loop, but we may not use it for substitutions. */
>
> - if (cprop_constant_p (src) || reg_not_set_p (src, insn))
> - set1 = set;
> + if (cprop_constant_p (src))
> + set_ret[1] = set;
> + else if (reg_not_set_p (src, insn))
> + set_ret[0] = set;
>
> /* If the source of the set is anything except a register, then
> we have reached the end of the copy chain. */
> @@ -875,10 +877,6 @@ find_avail_set (int regno, rtx_insn *insn)
> and see if we have an available copy into SRC. */
> regno = REGNO (src);
> }
> -
> - /* SET1 holds the last set that was available and anticipatable at
> - INSN. */
> - return set1;
> }
>
> /* Subroutine of cprop_insn that tries to propagate constants into
> @@ -1044,40 +1042,41 @@ cprop_insn (rtx_insn *insn)
> int changed = 0, changed_this_round;
> rtx note;
>
> -retry:
> - changed_this_round = 0;
> - reg_use_count = 0;
> - note_uses (&PATTERN (insn), find_used_regs, NULL);
> + do
> + {
> + changed_this_round = 0;
> + reg_use_count = 0;
> + note_uses (&PATTERN (insn), find_used_regs, NULL);
>
> - /* We may win even when propagating constants into notes. */
> - note = find_reg_equal_equiv_note (insn);
> - if (note)
> - find_used_regs (&XEXP (note, 0), NULL);
> + /* We may win even when propagating constants into notes. */
> + note = find_reg_equal_equiv_note (insn);
> + if (note)
> + find_used_regs (&XEXP (note, 0), NULL);
>
> - for (i = 0; i < reg_use_count; i++)
> - {
> - rtx reg_used = reg_use_table[i];
> - unsigned int regno = REGNO (reg_used);
> - rtx src;
> - struct cprop_expr *set;
> + for (i = 0; i < reg_use_count; i++)
> + {
> + rtx reg_used = reg_use_table[i];
> + unsigned int regno = REGNO (reg_used);
> + rtx src_cst = NULL, src_reg = NULL;
> + struct cprop_expr *set[2];
>
> - /* If the register has already been set in this block, there's
> - nothing we can do. */
> - if (! reg_not_set_p (reg_used, insn))
> - continue;
> + /* If the register has already been set in this block, there's
> + nothing we can do. */
> + if (! reg_not_set_p (reg_used, insn))
> + continue;
>
> - /* Find an assignment that sets reg_used and is available
> - at the start of the block. */
> - set = find_avail_set (regno, insn);
> - if (! set)
> - continue;
> + /* Find an assignment that sets reg_used and is available
> + at the start of the block. */
> + find_avail_set (regno, insn, set);
>
> - src = set->src;
> + if (set[0])
> + src_reg = set[0]->src;
> + if (set[1])
> + src_cst = set[1]->src;
>
> - /* Constant propagation. */
> - if (cprop_constant_p (src))
> - {
> - if (constprop_register (reg_used, src, insn))
> + /* Constant propagation. */
> + if (src_cst && cprop_constant_p (src_cst)
> + && constprop_register (reg_used, src_cst, insn))
> {
> changed_this_round = changed = 1;
> global_const_prop_count++;
> @@ -1087,18 +1086,16 @@ retry:
> "GLOBAL CONST-PROP: Replacing reg %d in ", regno);
> fprintf (dump_file, "insn %d with constant ",
> INSN_UID (insn));
> - print_rtl (dump_file, src);
> + print_rtl (dump_file, src_cst);
> fprintf (dump_file, "\n");
> }
> if (insn->deleted ())
> return 1;
> }
> - }
> - else if (REG_P (src)
> - && REGNO (src) >= FIRST_PSEUDO_REGISTER
> - && REGNO (src) != regno)
> - {
> - if (try_replace_reg (reg_used, src, insn))
> + else if (src_reg && REG_P (src_reg)
> + && REGNO (src_reg) >= FIRST_PSEUDO_REGISTER
> + && REGNO (src_reg) != regno
> + && try_replace_reg (reg_used, src_reg, insn))
> {
> changed_this_round = changed = 1;
> global_copy_prop_count++;
> @@ -1107,22 +1104,20 @@ retry:
> fprintf (dump_file,
> "GLOBAL COPY-PROP: Replacing reg %d in insn %d",
> regno, INSN_UID (insn));
> - fprintf (dump_file, " with reg %d\n", REGNO (src));
> + fprintf (dump_file, " with reg %d\n", REGNO (src_reg));
> }
>
> /* The original insn setting reg_used may or may not now be
> deletable. We leave the deletion to DCE. */
> - /* FIXME: If it turns out that the insn isn't deletable,
> - then we may have unnecessarily extended register lifetimes
> + /* FIXME: If it turns out that the insn isn't deletable, then we
> + then we may have unnecessarily extended register lifetimes and
> and made things worse. */
> }
> }
> -
> - /* If try_replace_reg simplified the insn, the regs found
> - by find_used_regs may not be valid anymore. Start over. */
> - if (changed_this_round)
> - goto retry;
> }
> + /* If try_replace_reg simplified the insn, the regs found
> + by find_used_regs may not be valid anymore. Start over. */
> + while (changed_this_round);
>
> if (changed && DEBUG_INSN_P (insn))
> return 0;
> diff --git a/gcc/testsuite/gcc.target/arm/pr64616.c b/gcc/testsuite/gcc.target/arm/pr64616.c
> new file mode 100644
> index 0000000..c686ffa
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/pr64616.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +int f (int);
> +unsigned int glob;
> +
> +void
> +g ()
> +{
> + while (f (glob));
> + glob = 5;
> +}
> +
> +/* { dg-final { scan-assembler-times "ldr" 2 } } */
>
> Is this ok for stage1?
>
> Best regards,
>
> Thomas
>
>
>
>
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Jennifer Guild,
Dilip Upmanyu, Graham Norton HRB 21284 (AG Nuernberg)
More information about the Gcc-patches
mailing list