summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>2015-07-16 15:26:35 +0000
committerH.J. Lu <hjl.tools@gmail.com>2015-09-25 14:26:02 -0700
commit1541140124035332398333a8f169791059a7c366 (patch)
treef6765cbdf226a9fbf304f231fc4101b4afd62aee
parent44f9e0b8eda2a1820c2e45efcf676047335f1c59 (diff)
downloadgcc-1541140124035332398333a8f169791059a7c366.tar.gz
More fix for PR rtl-optimization/66626
* ira.h: Include "function.h". 2015-07-16 Vladimir Makarov <vmakarov@redhat.com> PR rtl-optimization/66626 * ira.h (emit-rtl.h): Include. (non_spilled_static_chain_regno_p): New. * ira-color.c (setup_profitable_hard_regs): Clear profitable regs unless it is non spilled static chain pseudo. (assign_hard_rego): Spill memory profitable allocno unless it is non spilled static chain pseudo. (allocno_spill_priority_compare): Put non spilled static chain pseudo at the end of sorted array. (improve_allocation): Do nothing if we have static chain and non-local goto. (allocno__priority_compare_func): Put non spilled static chain pseudo at the beginning of sorted array. (move_spill_restore): Ignore non spilled static chain pseudo. * ira-costs.c (find_costs_and_classes): Don't assign class NO_REGS to non spilled static chain pseudo. * lra-assigns.c (pseudo_compare_func): Put non spilled static chain pseudo at the beginning of sorted array. (spill_for): Spill non spilled static chain pseudo last. * lra-constraints.c (lra_constraints): Remove static chain pseudo check for equivalence. 2015-07-16 Vladimir Makarov <vmakarov@redhat.com> PR rtl-optimization/66626 * gcc.target/i386/pr66626-2.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@225891 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ira-color.c42
-rw-r--r--gcc/ira-costs.c12
-rw-r--r--gcc/ira.h14
-rw-r--r--gcc/lra-assigns.c27
-rw-r--r--gcc/lra-constraints.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr66626-2.c26
6 files changed, 109 insertions, 20 deletions
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index ff1fe8a78ad..05627ad4e9b 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -1063,7 +1063,10 @@ setup_profitable_hard_regs (void)
continue;
data = ALLOCNO_COLOR_DATA (a);
if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) == NULL
- && ALLOCNO_CLASS_COST (a) > ALLOCNO_MEMORY_COST (a))
+ && ALLOCNO_CLASS_COST (a) > ALLOCNO_MEMORY_COST (a)
+ /* Do not empty profitable regs for static chain pointer
+ pseudo when non-local goto is used. */
+ && ! non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a)))
CLEAR_HARD_REG_SET (data->profitable_hard_regs);
else
{
@@ -1145,7 +1148,10 @@ setup_profitable_hard_regs (void)
if (! TEST_HARD_REG_BIT (data->profitable_hard_regs,
hard_regno))
continue;
- if (ALLOCNO_UPDATED_MEMORY_COST (a) < costs[j])
+ if (ALLOCNO_UPDATED_MEMORY_COST (a) < costs[j]
+ /* Do not remove HARD_REGNO for static chain pointer
+ pseudo when non-local goto is used. */
+ && ! non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a)))
CLEAR_HARD_REG_BIT (data->profitable_hard_regs,
hard_regno);
else if (min_cost > costs[j])
@@ -1153,7 +1159,10 @@ setup_profitable_hard_regs (void)
}
}
else if (ALLOCNO_UPDATED_MEMORY_COST (a)
- < ALLOCNO_UPDATED_CLASS_COST (a))
+ < ALLOCNO_UPDATED_CLASS_COST (a)
+ /* Do not empty profitable regs for static chain
+ pointer pseudo when non-local goto is used. */
+ && ! non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a)))
CLEAR_HARD_REG_SET (data->profitable_hard_regs);
if (ALLOCNO_UPDATED_CLASS_COST (a) > min_cost)
ALLOCNO_UPDATED_CLASS_COST (a) = min_cost;
@@ -1875,7 +1884,10 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
ira_assert (hard_regno >= 0);
}
}
- if (min_full_cost > mem_cost)
+ if (min_full_cost > mem_cost
+ /* Do not spill static chain pointer pseudo when non-local goto
+ is used. */
+ && ! non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a)))
{
if (! retry_p && internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
fprintf (ira_dump_file, "(memory is more profitable %d vs %d) ",
@@ -2501,6 +2513,12 @@ allocno_spill_priority_compare (ira_allocno_t a1, ira_allocno_t a2)
{
int pri1, pri2, diff;
+ /* Avoid spilling static chain pointer pseudo when non-local goto is
+ used. */
+ if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a1)))
+ return 1;
+ else if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a2)))
+ return -1;
if (ALLOCNO_BAD_SPILL_P (a1) && ! ALLOCNO_BAD_SPILL_P (a2))
return 1;
if (ALLOCNO_BAD_SPILL_P (a2) && ! ALLOCNO_BAD_SPILL_P (a1))
@@ -2753,6 +2771,11 @@ improve_allocation (void)
ira_allocno_t a;
bitmap_iterator bi;
+ /* Don't bother to optimize the code with static chain pointer and
+ non-local goto in order not to spill the chain pointer
+ pseudo. */
+ if (cfun->static_chain_decl && crtl->has_nonlocal_goto)
+ return;
/* Clear counts used to process conflicting allocnos only once for
each allocno. */
EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi)
@@ -2959,6 +2982,12 @@ allocno_priority_compare_func (const void *v1p, const void *v2p)
ira_allocno_t a2 = *(const ira_allocno_t *) v2p;
int pri1, pri2;
+ /* Assign hard reg to static chain pointer pseudo first when
+ non-local goto is used. */
+ if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a1)))
+ return 1;
+ else if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a2)))
+ return -1;
pri1 = allocno_priorities[ALLOCNO_NUM (a1)];
pri2 = allocno_priorities[ALLOCNO_NUM (a2)];
if (pri2 != pri1)
@@ -3400,7 +3429,10 @@ move_spill_restore (void)
by copy although the allocno will not get memory
slot. */
|| ira_equiv_no_lvalue_p (regno)
- || !bitmap_bit_p (loop_node->border_allocnos, ALLOCNO_NUM (a)))
+ || !bitmap_bit_p (loop_node->border_allocnos, ALLOCNO_NUM (a))
+ /* Do not spill static chain pointer pseudo when
+ non-local goto is used. */
+ || non_spilled_static_chain_regno_p (regno))
continue;
mode = ALLOCNO_MODE (a);
rclass = ALLOCNO_CLASS (a);
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 354ba6ba063..8ced91d39f4 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -1855,7 +1855,8 @@ find_costs_and_classes (FILE *dump_file)
alt_class = reg_class_subunion[alt_class][rclass];
}
alt_class = ira_allocno_class_translate[alt_class];
- if (best_cost > i_mem_cost)
+ if (best_cost > i_mem_cost
+ && ! non_spilled_static_chain_regno_p (i))
regno_aclass[i] = NO_REGS;
else if (!optimize && !targetm.class_likely_spilled_p (best))
/* Registers in the alternative class are likely to need
@@ -1882,7 +1883,10 @@ find_costs_and_classes (FILE *dump_file)
}
if (pass == flag_expensive_optimizations)
{
- if (best_cost > i_mem_cost)
+ if (best_cost > i_mem_cost
+ /* Do not assign NO_REGS to static chain pointer
+ pseudo when non-local goto is used. */
+ && ! non_spilled_static_chain_regno_p (i))
best = alt_class = NO_REGS;
else if (best == alt_class)
alt_class = NO_REGS;
@@ -1897,7 +1901,9 @@ find_costs_and_classes (FILE *dump_file)
regno_best_class[i] = best;
if (! allocno_p)
{
- pref[i] = best_cost > i_mem_cost ? NO_REGS : best;
+ pref[i] = (best_cost > i_mem_cost
+ && ! non_spilled_static_chain_regno_p (i)
+ ? NO_REGS : best);
continue;
}
for (a = ira_regno_allocno_map[i];
diff --git a/gcc/ira.h b/gcc/ira.h
index 19797809292..cdd26a7cf65 100644
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -22,6 +22,9 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_IRA_H
#define GCC_IRA_H
+#include "function.h"
+#include "emit-rtl.h"
+
/* True when we use LRA instead of reload pass for the current
function. */
extern bool ira_use_lra_p;
@@ -209,4 +212,15 @@ extern void ira_adjust_equiv_reg_cost (unsigned, int);
/* ira-costs.c */
extern void ira_costs_c_finalize (void);
+/* Spilling static chain pseudo may result in generation of wrong
+ non-local goto code using frame-pointer to address saved stack
+ pointer value after restoring old frame pointer value. The
+ function returns TRUE if REGNO is such a static chain pseudo. */
+static inline bool
+non_spilled_static_chain_regno_p (int regno)
+{
+ return (cfun->static_chain_decl && crtl->has_nonlocal_goto
+ && REG_EXPR (regno_reg_rtx[regno]) == cfun->static_chain_decl);
+}
+
#endif /* GCC_IRA_H */
diff --git a/gcc/lra-assigns.c b/gcc/lra-assigns.c
index 994b04fc643..4e3f2885ed3 100644
--- a/gcc/lra-assigns.c
+++ b/gcc/lra-assigns.c
@@ -269,6 +269,13 @@ pseudo_compare_func (const void *v1p, const void *v2p)
int r1 = *(const int *) v1p, r2 = *(const int *) v2p;
int diff;
+ /* Assign hard reg to static chain pointer first pseudo when
+ non-local goto is used. */
+ if (non_spilled_static_chain_regno_p (r1))
+ return -1;
+ else if (non_spilled_static_chain_regno_p (r2))
+ return 1;
+
/* Prefer to assign more frequently used registers first. */
if ((diff = lra_reg_info[r2].freq - lra_reg_info[r1].freq) != 0)
return diff;
@@ -906,6 +913,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
{
int i, j, n, p, hard_regno, best_hard_regno, cost, best_cost, rclass_size;
int reload_hard_regno, reload_cost;
+ bool static_p, best_static_p;
machine_mode mode;
enum reg_class rclass;
unsigned int spill_regno, reload_regno, uid;
@@ -928,6 +936,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
}
best_hard_regno = -1;
best_cost = INT_MAX;
+ best_static_p = TRUE;
best_insn_pseudos_num = INT_MAX;
smallest_bad_spills_num = INT_MAX;
rclass_size = ira_class_hard_regs_num[rclass];
@@ -950,6 +959,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
&try_hard_reg_pseudos[hard_regno + j]);
}
/* Spill pseudos. */
+ static_p = false;
EXECUTE_IF_SET_IN_BITMAP (&spill_pseudos_bitmap, 0, spill_regno, bi)
if ((pic_offset_table_rtx != NULL
&& spill_regno == REGNO (pic_offset_table_rtx))
@@ -959,6 +969,8 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
&& ! bitmap_bit_p (&lra_subreg_reload_pseudos, spill_regno)
&& ! bitmap_bit_p (&lra_optional_reload_pseudos, spill_regno)))
goto fail;
+ else if (non_spilled_static_chain_regno_p (spill_regno))
+ static_p = true;
insn_pseudos_num = 0;
bad_spills_num = 0;
if (lra_dump_file != NULL)
@@ -1038,14 +1050,19 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
x = x->next ())
cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (x->insn ()));
}
- if (best_insn_pseudos_num > insn_pseudos_num
- || (best_insn_pseudos_num == insn_pseudos_num
- && (bad_spills_num < smallest_bad_spills_num
- || (bad_spills_num == smallest_bad_spills_num
- && best_cost > cost))))
+ /* Avoid spilling static chain pointer pseudo when non-local
+ goto is used. */
+ if ((! static_p && best_static_p)
+ || (static_p == best_static_p
+ && (best_insn_pseudos_num > insn_pseudos_num
+ || (best_insn_pseudos_num == insn_pseudos_num
+ && (bad_spills_num < smallest_bad_spills_num
+ || (bad_spills_num == smallest_bad_spills_num
+ && best_cost > cost))))))
{
best_insn_pseudos_num = insn_pseudos_num;
smallest_bad_spills_num = bad_spills_num;
+ best_static_p = static_p;
best_cost = cost;
best_hard_regno = hard_regno;
bitmap_copy (&best_spill_pseudos_bitmap, &spill_pseudos_bitmap);
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index bd1209f82ee..5a1c25a05f4 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -4328,13 +4328,7 @@ lra_constraints (bool first_p)
&& ((CONST_POOL_OK_P (PSEUDO_REGNO_MODE (i), x)
&& (targetm.preferred_reload_class
(x, lra_get_allocno_class (i)) == NO_REGS))
- || contains_symbol_ref_p (x)))
- /* Static chain equivalence may contain eliminable
- regs and the result of elimination might be wrong
- after restoring frame pointer for a nonlocal
- goto. */
- || (cfun->static_chain_decl && crtl->has_nonlocal_goto
- && REG_EXPR (reg) == cfun->static_chain_decl))
+ || contains_symbol_ref_p (x))))
ira_reg_equiv[i].defined_p = false;
if (contains_reg_p (x, false, true))
ira_reg_equiv[i].profitable_p = false;
diff --git a/gcc/testsuite/gcc.target/i386/pr66626-2.c b/gcc/testsuite/gcc.target/i386/pr66626-2.c
new file mode 100644
index 00000000000..feba6a6223c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66626-2.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mregparm=3" } */
+/* { dg-require-effective-target ia32 } */
+extern void abort (void);
+
+int s (int i)
+{
+ __label__ l1;
+ int f (int i)
+ {
+ if (i == 2)
+ goto l1;
+ return 0;
+ }
+ return f (i);
+ l1:;
+ return 1;
+}
+
+int main ()
+{
+ if (s (2) != 1)
+ abort ();
+
+ return 0;
+}