Commit 8ffa3150 by Richard Sandiford Committed by Richard Sandiford

Record equivalences for spill registers

If we decide to allocate a call-clobbered register R to a value that
is live across a call, LRA will create a new spill register TMPR,
insert:

   TMPR <- R

before the call and

   R <- TMPR

after it.  But if we then failed to allocate a register to TMPR, we would
always spill it to the stack, even if R was known to be equivalent to
a constant or to some existing memory location.  And on AArch64, we'd
always fail to allocate such a register for 128-bit Advanced SIMD modes,
since no registers of those modes are call-preserved.

This patch avoids the problem by copying the equivalence information
from the original pseudo to the spill register.  It means that the
code for the testcase is as good with -O2 as it is with -O,
whereas previously the -O code was better.

[Based on the code ARM contributed in branches/ARM/sve-branch@247248]

2017-05-06  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
	* lra-constraints.c (lra_copy_reg_equiv): New function.
	(split_reg): Use it to copy equivalence information from the
	original register to the spill register.

gcc/testsuite/
	* gcc.target/aarch64/spill_1.c: New test.

From-SVN: r247720
parent 2a3f7997
2017-05-06 Richard Sandiford <richard.sandiford@linaro.org>
* lra-constraints.c (lra_copy_reg_equiv): New function.
(split_reg): Use it to copy equivalence information from the
original register to the spill register.
2017-05-06 Richard Sandiford <richard.sandiford@linaro.org>
PR rtl-optimization/75964
* simplify-rtx.c (simplify_const_relational_operation): Remove
invalid handling of comparisons of integer ABS.
......
......@@ -5394,6 +5394,29 @@ choose_split_class (enum reg_class allocno_class,
#endif
}
/* Copy any equivalence information from ORIGINAL_REGNO to NEW_REGNO.
It only makes sense to call this function if NEW_REGNO is always
equal to ORIGINAL_REGNO. */
static void
lra_copy_reg_equiv (unsigned int new_regno, unsigned int original_regno)
{
if (!ira_reg_equiv[original_regno].defined_p)
return;
ira_expand_reg_equiv ();
ira_reg_equiv[new_regno].defined_p = true;
if (ira_reg_equiv[original_regno].memory)
ira_reg_equiv[new_regno].memory
= copy_rtx (ira_reg_equiv[original_regno].memory);
if (ira_reg_equiv[original_regno].constant)
ira_reg_equiv[new_regno].constant
= copy_rtx (ira_reg_equiv[original_regno].constant);
if (ira_reg_equiv[original_regno].invariant)
ira_reg_equiv[new_regno].invariant
= copy_rtx (ira_reg_equiv[original_regno].invariant);
}
/* Do split transformations for insn INSN, which defines or uses
ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which instruction in
the EBB next uses ORIGINAL_REGNO; it has the same form as the
......@@ -5515,6 +5538,7 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn,
new_reg = lra_create_new_reg (mode, original_reg, rclass, "split");
reg_renumber[REGNO (new_reg)] = hard_regno;
}
int new_regno = REGNO (new_reg);
save = emit_spill_move (true, new_reg, original_reg);
if (NEXT_INSN (save) != NULL_RTX && !call_save_p)
{
......@@ -5523,7 +5547,7 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn,
fprintf
(lra_dump_file,
" Rejecting split %d->%d resulting in > 2 save insns:\n",
original_regno, REGNO (new_reg));
original_regno, new_regno);
dump_rtl_slim (lra_dump_file, save, NULL, -1, 0);
fprintf (lra_dump_file,
" ))))))))))))))))))))))))))))))))))))))))))))))))\n");
......@@ -5538,18 +5562,24 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn,
fprintf (lra_dump_file,
" Rejecting split %d->%d "
"resulting in > 2 restore insns:\n",
original_regno, REGNO (new_reg));
original_regno, new_regno);
dump_rtl_slim (lra_dump_file, restore, NULL, -1, 0);
fprintf (lra_dump_file,
" ))))))))))))))))))))))))))))))))))))))))))))))))\n");
}
return false;
}
/* Transfer equivalence information to the spill register, so that
if we fail to allocate the spill register, we have the option of
rematerializing the original value instead of spilling to the stack. */
if (!HARD_REGISTER_NUM_P (original_regno)
&& mode == PSEUDO_REGNO_MODE (original_regno))
lra_copy_reg_equiv (new_regno, original_regno);
after_p = usage_insns[original_regno].after_p;
lra_reg_info[REGNO (new_reg)].restore_rtx = regno_reg_rtx[original_regno];
bitmap_set_bit (&check_only_regs, REGNO (new_reg));
lra_reg_info[new_regno].restore_rtx = regno_reg_rtx[original_regno];
bitmap_set_bit (&check_only_regs, new_regno);
bitmap_set_bit (&check_only_regs, original_regno);
bitmap_set_bit (&lra_split_regs, REGNO (new_reg));
bitmap_set_bit (&lra_split_regs, new_regno);
for (;;)
{
if (GET_CODE (next_usage_insns) != INSN_LIST)
......@@ -5565,7 +5595,7 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn,
if (lra_dump_file != NULL)
{
fprintf (lra_dump_file, " Split reuse change %d->%d:\n",
original_regno, REGNO (new_reg));
original_regno, new_regno);
dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
}
}
......
2017-05-06 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.target/aarch64/spill_1.c: New test.
2017-05-06 Richard Sandiford <richard.sandiford@linaro.org>
PR rtl-optimization/75964
* gcc.dg/torture/pr75964.c: New test.
......
/* { dg-do compile } */
/* { dg-options "-O2" } */
typedef int v4si __attribute__ ((vector_size (16)));
void bar (void);
void
foo (void)
{
v4si x = { 1, 1, 1, 1 };
asm ("# %0" :: "w" (x));
bar ();
asm ("# %0" :: "w" (x));
}
/* { dg-final { scan-assembler-times {\tmovi\tv[0-9]+\.4s,} 2 } } */
/* { dg-final { scan-assembler-not {\tldr\t} } } */
/* { dg-final { scan-assembler-not {\tstr\t} } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment