Commit b81a2f0d by Vladimir Makarov Committed by Vladimir Makarov

re PR rtl-optimization/66626 (gcc.dg/torture/stackalign/non-local-goto-5.c…

re PR rtl-optimization/66626 (gcc.dg/torture/stackalign/non-local-goto-5.c segfaults w/ -mregparm=3 or -miamcu)

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.

From-SVN: r225891
parent a7d1f3fe
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 Martin Liska <mliska@suse.cz> 2015-07-16 Martin Liska <mliska@suse.cz>
PR ipa/66896. PR ipa/66896.
......
...@@ -1044,7 +1044,10 @@ setup_profitable_hard_regs (void) ...@@ -1044,7 +1044,10 @@ setup_profitable_hard_regs (void)
continue; continue;
data = ALLOCNO_COLOR_DATA (a); data = ALLOCNO_COLOR_DATA (a);
if (ALLOCNO_UPDATED_HARD_REG_COSTS (a) == NULL 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); CLEAR_HARD_REG_SET (data->profitable_hard_regs);
else else
{ {
...@@ -1126,7 +1129,10 @@ setup_profitable_hard_regs (void) ...@@ -1126,7 +1129,10 @@ setup_profitable_hard_regs (void)
if (! TEST_HARD_REG_BIT (data->profitable_hard_regs, if (! TEST_HARD_REG_BIT (data->profitable_hard_regs,
hard_regno)) hard_regno))
continue; 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, CLEAR_HARD_REG_BIT (data->profitable_hard_regs,
hard_regno); hard_regno);
else if (min_cost > costs[j]) else if (min_cost > costs[j])
...@@ -1134,7 +1140,10 @@ setup_profitable_hard_regs (void) ...@@ -1134,7 +1140,10 @@ setup_profitable_hard_regs (void)
} }
} }
else if (ALLOCNO_UPDATED_MEMORY_COST (a) 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); CLEAR_HARD_REG_SET (data->profitable_hard_regs);
if (ALLOCNO_UPDATED_CLASS_COST (a) > min_cost) if (ALLOCNO_UPDATED_CLASS_COST (a) > min_cost)
ALLOCNO_UPDATED_CLASS_COST (a) = min_cost; ALLOCNO_UPDATED_CLASS_COST (a) = min_cost;
...@@ -1854,7 +1863,10 @@ assign_hard_reg (ira_allocno_t a, bool retry_p) ...@@ -1854,7 +1863,10 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
ira_assert (hard_regno >= 0); 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) if (! retry_p && internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
fprintf (ira_dump_file, "(memory is more profitable %d vs %d) ", fprintf (ira_dump_file, "(memory is more profitable %d vs %d) ",
...@@ -2480,6 +2492,12 @@ allocno_spill_priority_compare (ira_allocno_t a1, ira_allocno_t a2) ...@@ -2480,6 +2492,12 @@ allocno_spill_priority_compare (ira_allocno_t a1, ira_allocno_t a2)
{ {
int pri1, pri2, diff; 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)) if (ALLOCNO_BAD_SPILL_P (a1) && ! ALLOCNO_BAD_SPILL_P (a2))
return 1; return 1;
if (ALLOCNO_BAD_SPILL_P (a2) && ! ALLOCNO_BAD_SPILL_P (a1)) if (ALLOCNO_BAD_SPILL_P (a2) && ! ALLOCNO_BAD_SPILL_P (a1))
...@@ -2732,6 +2750,11 @@ improve_allocation (void) ...@@ -2732,6 +2750,11 @@ improve_allocation (void)
ira_allocno_t a; ira_allocno_t a;
bitmap_iterator bi; 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 /* Clear counts used to process conflicting allocnos only once for
each allocno. */ each allocno. */
EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi) EXECUTE_IF_SET_IN_BITMAP (coloring_allocno_bitmap, 0, i, bi)
...@@ -2938,6 +2961,12 @@ allocno_priority_compare_func (const void *v1p, const void *v2p) ...@@ -2938,6 +2961,12 @@ allocno_priority_compare_func (const void *v1p, const void *v2p)
ira_allocno_t a2 = *(const ira_allocno_t *) v2p; ira_allocno_t a2 = *(const ira_allocno_t *) v2p;
int pri1, pri2; 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)]; pri1 = allocno_priorities[ALLOCNO_NUM (a1)];
pri2 = allocno_priorities[ALLOCNO_NUM (a2)]; pri2 = allocno_priorities[ALLOCNO_NUM (a2)];
if (pri2 != pri1) if (pri2 != pri1)
...@@ -3379,7 +3408,10 @@ move_spill_restore (void) ...@@ -3379,7 +3408,10 @@ move_spill_restore (void)
by copy although the allocno will not get memory by copy although the allocno will not get memory
slot. */ slot. */
|| ira_equiv_no_lvalue_p (regno) || 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; continue;
mode = ALLOCNO_MODE (a); mode = ALLOCNO_MODE (a);
rclass = ALLOCNO_CLASS (a); rclass = ALLOCNO_CLASS (a);
......
...@@ -1836,7 +1836,8 @@ find_costs_and_classes (FILE *dump_file) ...@@ -1836,7 +1836,8 @@ find_costs_and_classes (FILE *dump_file)
alt_class = reg_class_subunion[alt_class][rclass]; alt_class = reg_class_subunion[alt_class][rclass];
} }
alt_class = ira_allocno_class_translate[alt_class]; 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; regno_aclass[i] = NO_REGS;
else if (!optimize && !targetm.class_likely_spilled_p (best)) else if (!optimize && !targetm.class_likely_spilled_p (best))
/* Registers in the alternative class are likely to need /* Registers in the alternative class are likely to need
...@@ -1875,7 +1876,10 @@ find_costs_and_classes (FILE *dump_file) ...@@ -1875,7 +1876,10 @@ find_costs_and_classes (FILE *dump_file)
} }
if (pass == flag_expensive_optimizations) 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; best = alt_class = NO_REGS;
else if (best == alt_class) else if (best == alt_class)
alt_class = NO_REGS; alt_class = NO_REGS;
...@@ -1890,7 +1894,9 @@ find_costs_and_classes (FILE *dump_file) ...@@ -1890,7 +1894,9 @@ find_costs_and_classes (FILE *dump_file)
regno_best_class[i] = best; regno_best_class[i] = best;
if (! allocno_p) 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; continue;
} }
for (a = ira_regno_allocno_map[i]; for (a = ira_regno_allocno_map[i];
......
...@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_IRA_H #ifndef GCC_IRA_H
#define GCC_IRA_H #define GCC_IRA_H
#include "emit-rtl.h"
/* True when we use LRA instead of reload pass for the current /* True when we use LRA instead of reload pass for the current
function. */ function. */
extern bool ira_use_lra_p; extern bool ira_use_lra_p;
...@@ -209,4 +211,15 @@ extern void ira_adjust_equiv_reg_cost (unsigned, int); ...@@ -209,4 +211,15 @@ extern void ira_adjust_equiv_reg_cost (unsigned, int);
/* ira-costs.c */ /* ira-costs.c */
extern void ira_costs_c_finalize (void); 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 */ #endif /* GCC_IRA_H */
...@@ -255,6 +255,13 @@ pseudo_compare_func (const void *v1p, const void *v2p) ...@@ -255,6 +255,13 @@ pseudo_compare_func (const void *v1p, const void *v2p)
int r1 = *(const int *) v1p, r2 = *(const int *) v2p; int r1 = *(const int *) v1p, r2 = *(const int *) v2p;
int diff; 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. */ /* Prefer to assign more frequently used registers first. */
if ((diff = lra_reg_info[r2].freq - lra_reg_info[r1].freq) != 0) if ((diff = lra_reg_info[r2].freq - lra_reg_info[r1].freq) != 0)
return diff; return diff;
...@@ -892,6 +899,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p) ...@@ -892,6 +899,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 i, j, n, p, hard_regno, best_hard_regno, cost, best_cost, rclass_size;
int reload_hard_regno, reload_cost; int reload_hard_regno, reload_cost;
bool static_p, best_static_p;
machine_mode mode; machine_mode mode;
enum reg_class rclass; enum reg_class rclass;
unsigned int spill_regno, reload_regno, uid; unsigned int spill_regno, reload_regno, uid;
...@@ -914,6 +922,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p) ...@@ -914,6 +922,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
} }
best_hard_regno = -1; best_hard_regno = -1;
best_cost = INT_MAX; best_cost = INT_MAX;
best_static_p = TRUE;
best_insn_pseudos_num = INT_MAX; best_insn_pseudos_num = INT_MAX;
smallest_bad_spills_num = INT_MAX; smallest_bad_spills_num = INT_MAX;
rclass_size = ira_class_hard_regs_num[rclass]; rclass_size = ira_class_hard_regs_num[rclass];
...@@ -936,6 +945,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p) ...@@ -936,6 +945,7 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
&try_hard_reg_pseudos[hard_regno + j]); &try_hard_reg_pseudos[hard_regno + j]);
} }
/* Spill pseudos. */ /* Spill pseudos. */
static_p = false;
EXECUTE_IF_SET_IN_BITMAP (&spill_pseudos_bitmap, 0, spill_regno, bi) EXECUTE_IF_SET_IN_BITMAP (&spill_pseudos_bitmap, 0, spill_regno, bi)
if ((pic_offset_table_rtx != NULL if ((pic_offset_table_rtx != NULL
&& spill_regno == REGNO (pic_offset_table_rtx)) && spill_regno == REGNO (pic_offset_table_rtx))
...@@ -945,6 +955,8 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p) ...@@ -945,6 +955,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_subreg_reload_pseudos, spill_regno)
&& ! bitmap_bit_p (&lra_optional_reload_pseudos, spill_regno))) && ! bitmap_bit_p (&lra_optional_reload_pseudos, spill_regno)))
goto fail; goto fail;
else if (non_spilled_static_chain_regno_p (spill_regno))
static_p = true;
insn_pseudos_num = 0; insn_pseudos_num = 0;
bad_spills_num = 0; bad_spills_num = 0;
if (lra_dump_file != NULL) if (lra_dump_file != NULL)
...@@ -1024,14 +1036,19 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p) ...@@ -1024,14 +1036,19 @@ spill_for (int regno, bitmap spilled_pseudo_bitmap, bool first_p)
x = x->next ()) x = x->next ())
cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (x->insn ())); cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (x->insn ()));
} }
if (best_insn_pseudos_num > insn_pseudos_num /* Avoid spilling static chain pointer pseudo when non-local
|| (best_insn_pseudos_num == insn_pseudos_num goto is used. */
&& (bad_spills_num < smallest_bad_spills_num if ((! static_p && best_static_p)
|| (bad_spills_num == smallest_bad_spills_num || (static_p == best_static_p
&& best_cost > cost)))) && (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; best_insn_pseudos_num = insn_pseudos_num;
smallest_bad_spills_num = bad_spills_num; smallest_bad_spills_num = bad_spills_num;
best_static_p = static_p;
best_cost = cost; best_cost = cost;
best_hard_regno = hard_regno; best_hard_regno = hard_regno;
bitmap_copy (&best_spill_pseudos_bitmap, &spill_pseudos_bitmap); bitmap_copy (&best_spill_pseudos_bitmap, &spill_pseudos_bitmap);
......
...@@ -4306,13 +4306,7 @@ lra_constraints (bool first_p) ...@@ -4306,13 +4306,7 @@ lra_constraints (bool first_p)
&& ((CONST_POOL_OK_P (PSEUDO_REGNO_MODE (i), x) && ((CONST_POOL_OK_P (PSEUDO_REGNO_MODE (i), x)
&& (targetm.preferred_reload_class && (targetm.preferred_reload_class
(x, lra_get_allocno_class (i)) == NO_REGS)) (x, lra_get_allocno_class (i)) == NO_REGS))
|| contains_symbol_ref_p (x))) || 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))
ira_reg_equiv[i].defined_p = false; ira_reg_equiv[i].defined_p = false;
if (contains_reg_p (x, false, true)) if (contains_reg_p (x, false, true))
ira_reg_equiv[i].profitable_p = false; ira_reg_equiv[i].profitable_p = false;
......
2015-07-16 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/66626
* gcc.target/i386/pr66626-2.c: New.
2015-07-16 Martin Liska <mliska@suse.cz> 2015-07-16 Martin Liska <mliska@suse.cz>
* g++.dg/ipa/pr66896.c: New test. * g++.dg/ipa/pr66896.c: New test.
......
/* { 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;
}
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