From b81a2f0dbcf13e72503c05420e399d7edf23384b Mon Sep 17 00:00:00 2001 From: Vladimir Makarov Date: Thu, 16 Jul 2015 15:26:35 +0000 Subject: [PATCH] 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 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 PR rtl-optimization/66626 * gcc.target/i386/pr66626-2.c: New. From-SVN: r225891 --- gcc/ChangeLog | 24 +++++++++++++ gcc/ira-color.c | 42 ++++++++++++++++++++--- gcc/ira-costs.c | 12 +++++-- gcc/ira.h | 13 +++++++ gcc/lra-assigns.c | 27 ++++++++++++--- gcc/lra-constraints.c | 8 +---- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.target/i386/pr66626-2.c | 26 ++++++++++++++ 8 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr66626-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fa938d880ef..a7949ece808 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2015-07-16 Vladimir Makarov + + 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 PR ipa/66896. diff --git a/gcc/ira-color.c b/gcc/ira-color.c index b2b1b7e93c3..74d2c2ed608 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -1044,7 +1044,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 { @@ -1126,7 +1129,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]) @@ -1134,7 +1140,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; @@ -1854,7 +1863,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) ", @@ -2480,6 +2492,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)) @@ -2732,6 +2750,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) @@ -2938,6 +2961,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) @@ -3379,7 +3408,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 0a5b1e12964..eded4d9f525 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -1836,7 +1836,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 @@ -1875,7 +1876,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; @@ -1890,7 +1894,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 5b52cb1980c..504b5e6a93b 100644 --- a/gcc/ira.h +++ b/gcc/ira.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_IRA_H #define GCC_IRA_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 +211,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 839036c79e7..2986f578438 100644 --- a/gcc/lra-assigns.c +++ b/gcc/lra-assigns.c @@ -255,6 +255,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; @@ -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 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; @@ -914,6 +922,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]; @@ -936,6 +945,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)) @@ -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_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) @@ -1024,14 +1036,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 58a388fa9e8..ddb91dd49cf 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -4306,13 +4306,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/ChangeLog b/gcc/testsuite/ChangeLog index aa807cc2bfe..527fe0ffd21 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-07-16 Vladimir Makarov + + PR rtl-optimization/66626 + * gcc.target/i386/pr66626-2.c: New. + 2015-07-16 Martin Liska * g++.dg/ipa/pr66896.c: New test. 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; +} -- 2.30.2