From 8ffa3150d30b90a11aba7d7bba3c6462b6461101 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sat, 6 May 2017 07:46:48 +0000 Subject: [PATCH] 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 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 --- gcc/ChangeLog | 6 ++++ gcc/lra-constraints.c | 42 ++++++++++++++++++---- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.target/aarch64/spill_1.c | 18 ++++++++++ 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/spill_1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 58f09a19f6d..b0c253b09ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-05-06 Richard Sandiford + + * 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 PR rtl-optimization/75964 diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index c8bc9b9a66f..b0ae0fe3d9a 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -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 (usage_insn)); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 587e4821b65..fca5b87e798 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-05-06 Richard Sandiford + + * gcc.target/aarch64/spill_1.c: New test. + 2017-05-06 Richard Sandiford PR rtl-optimization/75964 diff --git a/gcc/testsuite/gcc.target/aarch64/spill_1.c b/gcc/testsuite/gcc.target/aarch64/spill_1.c new file mode 100644 index 00000000000..847425895d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/spill_1.c @@ -0,0 +1,18 @@ +/* { 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} } } */ -- 2.30.2