The following patch fixes http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57091
The problem was in choosing alternative with AREG class in an insn and AREG lives through the insn (until call insn). Reload chooses alternative with GENERAL_REGS. The problem was solved by tweaking alternative costs in process_alt_operands. Generally speaking, in such case LRA could split AREG but because only one insn needs AREG it decides that is not profitable.
Successfully bootstrapped and tested on x86/x86-64. Committed as rev. 198503. 2013-05-01 Vladimir Makarov <vmaka...@redhat.com> PR target/57091 * lra-constraints.c (best_small_class_operands_num): Remove. (process_alt_operands): Remove small_class_operands_num. Take small classes operands into losers and only if the operand is not matched. Modify debugging output. (curr_insn_transform): Remove best_small_class_operands_num. Print insn name. 2013-05-01 Vladimir Makarov <vmaka...@redhat.com> PR target/57091 * gcc.target/i386/pr57091.c: New test.
Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 198432) +++ lra-constraints.c (working copy) @@ -1048,9 +1048,6 @@ static int goal_alt_number; /* Number of necessary reloads and overall cost reflecting the previous value and other unpleasantness of the best alternative. */ static int best_losers, best_overall; -/* Number of small register classes used for operands of the best - alternative. */ -static int best_small_class_operands_num; /* Overall number hard registers used for reloads. For example, on some targets we need 2 general registers to reload DFmode and only one floating point register. */ @@ -1326,7 +1323,7 @@ static bool process_alt_operands (int only_alternative) { bool ok_p = false; - int nop, small_class_operands_num, overall, nalt; + int nop, overall, nalt; int n_alternatives = curr_static_id->n_alternatives; int n_operands = curr_static_id->n_operands; /* LOSERS counts the operands that don't fit this alternative and @@ -1405,6 +1402,7 @@ process_alt_operands (int only_alternati if (only_alternative >= 0 && nalt != only_alternative) continue; + overall = losers = reject = reload_nregs = reload_sum = 0; for (nop = 0; nop < n_operands; nop++) reject += (curr_static_id @@ -2006,6 +2004,9 @@ process_alt_operands (int only_alternati if (! no_regs_p) reload_nregs += ira_reg_class_max_nregs[this_alternative][mode]; + + if (SMALL_REGISTER_CLASS_P (this_alternative)) + reject += LRA_LOSER_COST_FACTOR / 2; } /* We are trying to spill pseudo into memory. It is @@ -2033,6 +2034,7 @@ process_alt_operands (int only_alternati reloads. */ if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN) reject++; + } if (early_clobber_p) @@ -2178,15 +2180,9 @@ process_alt_operands (int only_alternati overall += LRA_LOSER_COST_FACTOR - 1; } } - small_class_operands_num = 0; - for (nop = 0; nop < n_operands; nop++) - small_class_operands_num - += SMALL_REGISTER_CLASS_P (curr_alt[nop]) ? 1 : 0; - if (lra_dump_file != NULL) - fprintf (lra_dump_file, " alt=%d,overall=%d,losers=%d," - "small_class_ops=%d,rld_nregs=%d\n", - nalt, overall, losers, small_class_operands_num, reload_nregs); + fprintf (lra_dump_file, " alt=%d,overall=%d,losers=%d,rld_nregs=%d\n", + nalt, overall, losers, reload_nregs); /* If this alternative can be made to work by reloading, and it needs less reloading than the others checked so far, record @@ -2198,17 +2194,10 @@ process_alt_operands (int only_alternati || (best_overall == overall /* If the cost of the reloads is the same, prefer alternative which requires minimal - number of small register classes for the - operands. This improves chances of reloads - for insn requiring small register - classes. */ - && (small_class_operands_num - < best_small_class_operands_num - || (small_class_operands_num - == best_small_class_operands_num - && (reload_nregs < best_reload_nregs - || (reload_nregs == best_reload_nregs - && best_reload_sum < reload_sum)))))))) + number of reload regs. */ + && (reload_nregs < best_reload_nregs + || (reload_nregs == best_reload_nregs + && best_reload_sum < reload_sum)))))) { for (nop = 0; nop < n_operands; nop++) { @@ -2224,7 +2213,6 @@ process_alt_operands (int only_alternati goal_alt_swapped = curr_swapped; best_overall = overall; best_losers = losers; - best_small_class_operands_num = small_class_operands_num; best_reload_nregs = reload_nregs; best_reload_sum = reload_sum; goal_alt_number = nalt; @@ -2826,7 +2814,7 @@ curr_insn_transform (void) operands together against the register constraints. */ best_losers = best_overall = INT_MAX; - best_small_class_operands_num = best_reload_sum = 0; + best_reload_sum = 0; curr_swapped = false; goal_alt_swapped = false; @@ -3033,7 +3021,10 @@ curr_insn_transform (void) for (; *p != '\0' && *p != ',' && *p != '#'; p++) fputc (*p, lra_dump_file); } - fprintf (lra_dump_file, "\n"); + if (INSN_CODE (curr_insn) >= 0 + && (p = get_insn_name (INSN_CODE (curr_insn))) != NULL) + fprintf (lra_dump_file, " {%s}", p); + fprintf (lra_dump_file, "\n"); } /* Right now, for any pair of operands I and J that are required to Index: testsuite/gcc.target/i386/pr57091.c =================================================================== --- testsuite/gcc.target/i386/pr57091.c (revision 0) +++ testsuite/gcc.target/i386/pr57091.c (working copy) @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O -mcmodel=large" { target lp64 } } */ +void (*bar)(); + +void foo (void) +{ + bar (); +}