The following patch fixes PR66626 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66626
The previous patch solved only one problem (the 2nd test case in the PR). The following patch solves the all test cases.
The patch was tested and bootstrapped on x86/x86-64. Committed as rev. 225891. 2015-07-16 Vladimir Makarov <vmaka...@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 <vmaka...@redhat.com> PR rtl-optimization/66626 * gcc.target/i386/pr66626-2.c: New.
Index: ira-color.c =================================================================== --- ira-color.c (revision 225618) +++ ira-color.c (working copy) @@ -1058,7 +1058,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 { @@ -1140,7 +1143,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]) @@ -1148,7 +1154,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; @@ -1868,7 +1877,10 @@ assign_hard_reg (ira_allocno_t a, bool r 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) ", @@ -2494,6 +2506,12 @@ allocno_spill_priority_compare (ira_allo { 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)) @@ -2746,6 +2764,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) @@ -2952,6 +2975,12 @@ allocno_priority_compare_func (const voi 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) @@ -3393,7 +3422,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); Index: ira-costs.c =================================================================== --- ira-costs.c (revision 225618) +++ ira-costs.c (working copy) @@ -1835,7 +1835,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 @@ -1874,7 +1875,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; @@ -1889,7 +1893,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]; Index: ira.h =================================================================== --- ira.h (revision 225618) +++ ira.h (working copy) @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. #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 (u /* 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 */ Index: lra-assigns.c =================================================================== --- lra-assigns.c (revision 225618) +++ lra-assigns.c (working copy) @@ -254,6 +254,13 @@ pseudo_compare_func (const void *v1p, co 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; @@ -891,6 +898,7 @@ spill_for (int regno, bitmap spilled_pse { 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; @@ -913,6 +921,7 @@ spill_for (int regno, bitmap spilled_pse } 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]; @@ -935,6 +944,7 @@ spill_for (int regno, bitmap spilled_pse &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)) @@ -944,6 +954,8 @@ spill_for (int regno, bitmap spilled_pse && ! 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) @@ -1023,14 +1035,19 @@ spill_for (int regno, bitmap spilled_pse 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); Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 225789) +++ lra-constraints.c (working copy) @@ -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; Index: testsuite/gcc.target/i386/pr66626-2.c =================================================================== --- testsuite/gcc.target/i386/pr66626-2.c (revision 0) +++ testsuite/gcc.target/i386/pr66626-2.c (working copy) @@ -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; +}