From patchwork Mon Sep 12 15:25:20 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Makarov X-Patchwork-Id: 114385 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id BD79FB70C0 for ; Tue, 13 Sep 2011 01:25:56 +1000 (EST) Received: (qmail 14432 invoked by alias); 12 Sep 2011 15:25:51 -0000 Received: (qmail 14238 invoked by uid 22791); 12 Sep 2011 15:25:47 -0000 X-SWARE-Spam-Status: No, hits=-6.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 12 Sep 2011 15:25:22 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p8CFPLNs026175 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 12 Sep 2011 11:25:21 -0400 Received: from toll.yyz.redhat.com (toll.yyz.redhat.com [10.15.16.165]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p8CFPLIx027171 for ; Mon, 12 Sep 2011 11:25:21 -0400 Message-ID: <4E6E2460.8040008@redhat.com> Date: Mon, 12 Sep 2011 11:25:20 -0400 From: Vladimir Makarov User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.1.11-1.fc14 Thunderbird/3.1.11 MIME-Version: 1.0 To: gcc-patches Subject: [lra] patch to solve code size regression on ppc32 SPEC2000 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org The following patch fixes ppc32 code size regression on SPEC2000. I already posted an analogous patch http://gcc.gnu.org/ml/gcc-patches/2011-08/msg02208.html but it resulted in wrong code generation on x86. The original patch was reworked to fix the x86 code generation. To do this, classes with constraints '*' are made more costly. This is different from reload approach which ignores such constraint. I believe taking the constraint into account will help to make LRA more stable to order of alternatives in the insn descriptions making them more descriptive. The patch was successfully bootstrapped on x86/x86-64 and ppc32. 2011-09-12 Vladimir Makarov * lra-constraints.c (best_reload_nregs): New variable. (process_alt_operands): Add heuristics based on number regs involved in relaods and based on '*' constraints. Increase reject for all failed non registers. (curr_insn_transform, lra_inheritance): Formatting. * lra-eliminations.c (mark_not_eliminable): Add check on hard register before looping on eliminations. Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 178737) +++ lra-constraints.c (working copy) @@ -270,7 +270,8 @@ init_curr_insn_input_reloads (void) NEW_CLASS. Print info about it using TITLE. Output a new line if NL_P. */ static void -change_class (int regno, enum reg_class new_class, const char *title, bool nl_p) +change_class (int regno, enum reg_class new_class, + const char *title, bool nl_p) { int curr_regno; @@ -1143,6 +1144,10 @@ 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. */ +static int best_reload_nregs; /* Overall number reflecting distances of previous reloading the same value. It is used to improve inheritance chances. */ static int best_reload_sum; @@ -1415,7 +1420,9 @@ process_alt_operands (int only_alternati rtx no_subreg_operand[MAX_RECOG_OPERANDS], operand_reg[MAX_RECOG_OPERANDS]; int hard_regno[MAX_RECOG_OPERANDS]; enum machine_mode biggest_mode[MAX_RECOG_OPERANDS]; - int reload_sum; + int reload_nregs, reload_sum; + bool costly_p; + enum reg_class cl; /* Calculate some data common for all alternatives to speed up the function. */ @@ -1460,7 +1467,7 @@ process_alt_operands (int only_alternati (only_alternative >= 0 && nalt != only_alternative)) continue; - overall = losers = reject = reload_sum = 0; + overall = losers = reject = reload_nregs = reload_sum = 0; for (nop = 0; nop < n_operands; nop++) reject += (curr_static_id ->operand_alternative[nalt * n_operands + nop].reject); @@ -1481,8 +1488,8 @@ process_alt_operands (int only_alternati /* False if a constant forced into memory would be OK for this operand. */ bool constmemok; - enum reg_class this_alternative; - HARD_REG_SET this_alternative_set; + enum reg_class this_alternative, this_costly_alternative; + HARD_REG_SET this_alternative_set, this_costly_alternative_set; bool this_alternative_match_win, this_alternative_win; bool this_alternative_offmemok; int invalidate_m; @@ -1510,13 +1517,14 @@ process_alt_operands (int only_alternati early_clobber_p = false; p = curr_static_id->operand_alternative[opalt_num].constraint; - this_alternative = NO_REGS; + this_costly_alternative = this_alternative = NO_REGS; /* We update set of possible hard regs besides its class because reg class might be inaccurate. For example, union of LO_REGS (l), HI_REGS(h), and STACK_REG(k) in ARM is translated in HI_REGS because classes are merged by pairs and there is no accurate intermediate class. */ CLEAR_HARD_REG_SET (this_alternative_set); + CLEAR_HARD_REG_SET (this_costly_alternative_set); this_alternative_win = false; this_alternative_match_win = false; this_alternative_offmemok = false; @@ -1534,349 +1542,378 @@ process_alt_operands (int only_alternati letter after reloads, or set WINREG if this operand could fit after reloads provided the constraint allows some registers. */ - + costly_p = false; do - switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) - { - case '\0': - len = 0; - break; - case ',': - c = '\0'; - break; - - case '=': case '+': case '*': case '?': case '!': - break; - - case '%': - /* We only support one commutative marker, the first - one. We already set commutative above. */ - break; - - case '&': - early_clobber_p = true; - break; - - case '#': - /* Ignore rest of this alternative. */ - c = '\0'; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + { + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) { - int m_hregno, m_offset; - bool match_p; - - m = strtoul (p, &end, 10); - p = end; + case '\0': len = 0; - gcc_assert (nop > m); - - this_alternative_matches = m; - lra_get_hard_regno_and_offset (*curr_id->operand_loc[m], - &m_hregno, &m_offset); - m_hregno = get_final_hard_regno (m_hregno, m_offset); - /* We are supposed to match a previous operand. If - we do, we win if that one did. If we do not, - count both of the operands as losers. (This is - too conservative, since most of the time only a - single reload insn will be needed to make the two - operands win. As a result, this alternative may - be rejected when it is actually desirable.) */ - /* If it conflicts with others. */ - match_p = false; - if (operands_match_p (*curr_id->operand_loc[nop], - *curr_id->operand_loc[m], m_hregno)) - { - int i; - - for (i = 0; i < early_clobbered_regs_num; i++) - if (early_clobbered_nops[i] == m) - break; - /* We should reject matching of an early clobber - operand if the matching operand is not dying - in the insn. */ - if (i >= early_clobbered_regs_num - || operand_reg[nop] == NULL_RTX - || (find_regno_note (curr_insn, REG_DEAD, - REGNO (operand_reg[nop])) - != NULL_RTX)) - match_p = true; - } - if (match_p) - { - /* If we are matching a non-offsettable address - where an offsettable address was expected, - then we must reject this combination, because - we can't reload it. */ - if (curr_alt_offmemok[m] - && MEM_P (*curr_id->operand_loc[m]) - && curr_alt[m] == NO_REGS && ! curr_alt_win[m]) - continue; - - did_match = curr_alt_win[m]; - } - else - { - /* Operands don't match. */ - /* Retroactively mark the operand we had to - match as a loser, if it wasn't already and it - wasn't matched to a register constraint (e.g - it might be matched by memory). */ - if (curr_alt_win[m] - && (operand_reg[m] == NULL_RTX || hard_regno[m] < 0)) - losers++; - invalidate_m = m; - if (curr_alt[m] == NO_REGS) - continue; - - /* We prefer no matching alternatives because it - gives more freedom in RA. */ - if (operand_reg[nop] == NULL_RTX - || (find_regno_note (curr_insn, REG_DEAD, - REGNO (operand_reg[nop])) - == NULL_RTX)) - reject += 2; - } - /* This can be fixed with reloads if the operand we - are supposed to match can be fixed with - reloads. */ - badop = false; - this_alternative = curr_alt[m]; - COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]); - - /* If we have to reload this operand and some - previous operand also had to match the same thing - as this operand, we don't know how to do that. - So reject this alternative. */ - if (! did_match) - for (i = 0; i < nop; i++) - if (curr_alt_matches[i] == this_alternative_matches) - badop = true; - break; - } - - case 'p': - this_alternative - = (reg_class_subunion - [this_alternative] - [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]); - IOR_HARD_REG_SET (this_alternative_set, - reg_class_contents - [base_reg_class - (VOIDmode, ADDRESS, SCRATCH)]); - win = true; - badop = false; - break; - - case TARGET_MEM_CONSTRAINT: - if (MEM_P (op) - || (REG_P (op) - && REGNO (op) >= FIRST_PSEUDO_REGISTER - && in_mem_p (REGNO (op)))) - win = true; - if (CONST_POOL_OK_P (mode, op)) - badop = false; - constmemok = true; - break; - - case '<': - if (MEM_P (op) - && (GET_CODE (XEXP (op, 0)) == PRE_DEC - || GET_CODE (XEXP (op, 0)) == POST_DEC)) - win = true; - break; - - case '>': - if (MEM_P (op) - && (GET_CODE (XEXP (op, 0)) == PRE_INC - || GET_CODE (XEXP (op, 0)) == POST_INC)) - win = true; - break; - - /* Memory op whose address is not - offsettable. */ - case 'V': - if (MEM_P (op) - && ! offsettable_nonstrict_memref_p (op)) - win = true; - break; - - /* Memory operand whose address is offsettable. */ - case 'o': - if ((MEM_P (op) - && offsettable_nonstrict_memref_p (op)) - || (REG_P (op) - && REGNO (op) >= FIRST_PSEUDO_REGISTER - && in_mem_p (REGNO (op)))) - win = true; - if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) - badop = false; - constmemok = true; - offmemok = true; - break; - - case 'E': - case 'F': - if (GET_CODE (op) == CONST_DOUBLE - || (GET_CODE (op) == CONST_VECTOR - && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT))) - win = true; - break; - - case 'G': - case 'H': - if (GET_CODE (op) == CONST_DOUBLE - && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) - win = true; - break; - - case 's': - if (CONST_INT_P (op) - || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) - break; - case 'i': - if (CONSTANT_P (op) - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) - win = true; - break; - - case 'n': - if (CONST_INT_P (op) - || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) - win = true; - break; - - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - if (CONST_INT_P (op) - && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) - win = true; - break; - - case 'X': - /* This constraint should be excluded by the fast - track. */ - gcc_unreachable (); - break; - - case 'g': - if (/* A PLUS is never a valid operand, but LRA can - make it from a register when eliminating - registers. */ - GET_CODE (op) != PLUS - && (! CONSTANT_P (op) || ! flag_pic - || LEGITIMATE_PIC_OPERAND_P (op)) - && (! REG_P (op) - || (REGNO (op) >= FIRST_PSEUDO_REGISTER - && in_mem_p (REGNO (op))))) - win = true; - /* Drop through into 'r' case. */ - - case 'r': - this_alternative - = reg_class_subunion[this_alternative][GENERAL_REGS]; - IOR_HARD_REG_SET (this_alternative_set, - reg_class_contents[GENERAL_REGS]); - goto reg; + case ',': + c = '\0'; + break; - default: - if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + case '=': case '+': case '?': case '*': case '!': + case ' ': case '\t': + break; + + case '%': + /* We only support one commutative marker, the first + one. We already set commutative above. */ + break; + + case '&': + early_clobber_p = true; + break; + + case '#': + /* Ignore rest of this alternative. */ + c = '\0'; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { -#ifdef EXTRA_CONSTRAINT_STR - if (EXTRA_MEMORY_CONSTRAINT (c, p)) + int m_hregno, m_offset; + bool match_p; + + m = strtoul (p, &end, 10); + p = end; + len = 0; + gcc_assert (nop > m); + + this_alternative_matches = m; + lra_get_hard_regno_and_offset (*curr_id->operand_loc[m], + &m_hregno, &m_offset); + m_hregno = get_final_hard_regno (m_hregno, m_offset); + /* We are supposed to match a previous operand. + If we do, we win if that one did. If we do + not, count both of the operands as losers. + (This is too conservative, since most of the + time only a single reload insn will be needed + to make the two operands win. As a result, + this alternative may be rejected when it is + actually desirable.) */ + /* If it conflicts with others. */ + match_p = false; + if (operands_match_p (*curr_id->operand_loc[nop], + *curr_id->operand_loc[m], m_hregno)) { - if (EXTRA_CONSTRAINT_STR (op, c, p)) - win = true; - /* For regno_equiv_mem_loc we have to - check. */ - else if (REG_P (op) - && REGNO (op) >= FIRST_PSEUDO_REGISTER - && in_mem_p (REGNO (op))) - { - /* We could transform spilled memory - finally to indirect memory. */ - if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode), - c, p)) - win = true; - } - - /* If we didn't already win, we can reload - constants via force_const_mem, and other - MEMs by reloading the address like for - 'o'. */ - if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) - badop = false; - constmemok = true; - offmemok = true; - break; + int i; + + for (i = 0; i < early_clobbered_regs_num; i++) + if (early_clobbered_nops[i] == m) + break; + /* We should reject matching of an early + clobber operand if the matching operand is + not dying in the insn. */ + if (i >= early_clobbered_regs_num + || operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (operand_reg[nop])) + != NULL_RTX)) + match_p = true; } - if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + if (match_p) { - if (EXTRA_CONSTRAINT_STR (op, c, p)) - win = true; - - /* If we didn't already win, we can reload the - address into a base register. */ - this_alternative - = (reg_class_subunion - [this_alternative] - [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]); - IOR_HARD_REG_SET - (this_alternative_set, - reg_class_contents[base_reg_class - (VOIDmode, ADDRESS, SCRATCH)]); - badop = false; - break; + /* If we are matching a non-offsettable + address where an offsettable address was + expected, then we must reject this + combination, because we can't reload + it. */ + if (curr_alt_offmemok[m] + && MEM_P (*curr_id->operand_loc[m]) + && curr_alt[m] == NO_REGS && ! curr_alt_win[m]) + continue; + + did_match = curr_alt_win[m]; } - - if (EXTRA_CONSTRAINT_STR (op, c, p)) - win = true; - else if (REG_P (op) - && REGNO (op) >= FIRST_PSEUDO_REGISTER - && in_mem_p (REGNO (op))) + else { - /* We could transform spilled memory finally - to indirect memory. */ - if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode), - c, p)) - win = true; + /* Operands don't match. */ + /* Retroactively mark the operand we had to + match as a loser, if it wasn't already and + it wasn't matched to a register constraint + (e.g it might be matched by memory). */ + if (curr_alt_win[m] + && (operand_reg[m] == NULL_RTX || hard_regno[m] < 0)) + { + losers++; + if (curr_alt[m] != NO_REGS) + reload_nregs + += (ira_reg_class_max_nregs[curr_alt[m]] + [GET_MODE (*curr_id->operand_loc[m])]); + } + invalidate_m = m; + if (curr_alt[m] == NO_REGS) + continue; + + /* We prefer no matching alternatives because + it gives more freedom in RA. */ + if (operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (operand_reg[nop])) + == NULL_RTX)) + reject += 2; } -#endif + /* This can be fixed with reloads if the operand + we are supposed to match can be fixed with + reloads. */ + badop = false; + this_alternative = curr_alt[m]; + COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]); + + /* If we have to reload this operand and some + previous operand also had to match the same + thing as this operand, we don't know how to do + that. So reject this alternative. */ + if (! did_match) + for (i = 0; i < nop; i++) + if (curr_alt_matches[i] == this_alternative_matches) + badop = true; + break; } + + case 'p': + cl = base_reg_class (VOIDmode, ADDRESS, SCRATCH); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + win = true; + badop = false; + break; + + case TARGET_MEM_CONSTRAINT: + if (MEM_P (op) + || (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER + && in_mem_p (REGNO (op)))) + win = true; + if (CONST_POOL_OK_P (mode, op)) + badop = false; + constmemok = true; + break; + + case '<': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == POST_DEC)) + win = true; + break; + + case '>': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == POST_INC)) + win = true; + break; + + /* Memory op whose address is not offsettable. */ + case 'V': + if (MEM_P (op) + && ! offsettable_nonstrict_memref_p (op)) + win = true; + break; + + /* Memory operand whose address is offsettable. */ + case 'o': + if ((MEM_P (op) + && offsettable_nonstrict_memref_p (op)) + || (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER + && in_mem_p (REGNO (op)))) + win = true; + if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + + case 'E': + case 'F': + if (GET_CODE (op) == CONST_DOUBLE + || (GET_CODE (op) == CONST_VECTOR + && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT))) + win = true; + break; + + case 'G': + case 'H': + if (GET_CODE (op) == CONST_DOUBLE + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) + win = true; + break; + + case 's': + if (CONST_INT_P (op) + || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) + break; + case 'i': + if (CONSTANT_P (op) + && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) + win = true; + break; + + case 'n': + if (CONST_INT_P (op) + || (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)) + win = true; + break; - this_alternative - = (reg_class_subunion - [this_alternative][REG_CLASS_FROM_CONSTRAINT (c, p)]); - IOR_HARD_REG_SET - (this_alternative_set, - reg_class_contents[REG_CLASS_FROM_CONSTRAINT (c, p)]); - reg: - if (mode == BLKmode) + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (CONST_INT_P (op) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) + win = true; break; - winreg = true; - if (REG_P (op)) - { - if (hard_regno[nop] >= 0 - && in_hard_reg_set_p (this_alternative_set, - mode, hard_regno[nop])) - win = true; - else if (hard_regno[nop] < 0 - && in_class_p (REGNO (op), - this_alternative, NULL)) - win = true; - } - break; - } + + case 'X': + /* This constraint should be excluded by the fast + track. */ + gcc_unreachable (); + break; + + case 'g': + if (/* A PLUS is never a valid operand, but LRA can + make it from a register when eliminating + registers. */ + GET_CODE (op) != PLUS + && (! CONSTANT_P (op) || ! flag_pic + || LEGITIMATE_PIC_OPERAND_P (op)) + && (! REG_P (op) + || (REGNO (op) >= FIRST_PSEUDO_REGISTER + && in_mem_p (REGNO (op))))) + win = true; + /* Drop through into 'r' case. */ + + case 'r': + this_alternative + = reg_class_subunion[this_alternative][GENERAL_REGS]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[GENERAL_REGS]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][GENERAL_REGS]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[GENERAL_REGS]); + } + goto reg; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + { +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + /* For regno_equiv_mem_loc we have to + check. */ + else if (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER + && in_mem_p (REGNO (op))) + { + /* We could transform spilled memory + finally to indirect memory. */ + if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode), + c, p)) + win = true; + } + + /* If we didn't already win, we can reload + constants via force_const_mem, and other + MEMs by reloading the address like for + 'o'. */ + if (CONST_POOL_OK_P (mode, op) || MEM_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + } + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + + /* If we didn't already win, we can reload + the address into a base register. */ + cl = base_reg_class (VOIDmode, ADDRESS, SCRATCH); + this_alternative + = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + badop = false; + break; + } + + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + else if (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER + && in_mem_p (REGNO (op))) + { + /* We could transform spilled memory finally + to indirect memory. */ + if (EXTRA_CONSTRAINT_STR (get_indirect_mem (mode), + c, p)) + win = true; + } +#endif + break; + } + + cl = REG_CLASS_FROM_CONSTRAINT (c, p); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + reg: + if (mode == BLKmode) + break; + winreg = true; + if (REG_P (op)) + { + if (hard_regno[nop] >= 0 + && in_hard_reg_set_p (this_alternative_set, + mode, hard_regno[nop])) + win = true; + else if (hard_regno[nop] < 0 + && in_class_p (REGNO (op), + this_alternative, NULL)) + win = true; + } + break; + } + if (c != ' ' && c != '\t') + costly_p = c == '*'; + } while ((p += len), c); /* If this operand could be handled with a reg, and some reg @@ -1888,10 +1925,24 @@ process_alt_operands (int only_alternati if (win) { this_alternative_win = true; - if (operand_reg[nop] != NULL_RTX && hard_regno[nop] < 0) - /* Prefer won reg to spilled pseudo under other equal - conditions. */ - reject++; + if (operand_reg[nop] != NULL_RTX) + { + if (hard_regno[nop] >= 0) + { + if (in_hard_reg_set_p (this_costly_alternative_set, + mode, hard_regno[nop])) + reject++; + } + else + { + /* Prefer won reg to spilled pseudo under other equal + conditions. */ + reject++; + if (in_class_p (REGNO (operand_reg[nop]), + this_costly_alternative, NULL)) + reject++; + } + } } else if (did_match) this_alternative_match_win = true; @@ -1906,6 +1957,8 @@ process_alt_operands (int only_alternati (reg_class_contents[this_alternative], lra_no_alloc_regs))); this_alternative_offmemok = offmemok; + if (this_costly_alternative != NO_REGS) + reject++; /* If the operand is dying, has a matching constraint, and satisfies constraints of the matched operand which failed to satisfy the own constraints, we do @@ -2003,7 +2056,7 @@ process_alt_operands (int only_alternati /* Input reloads can be inherited more often than output reloads can be removed, so penalize output reloads. */ - if (curr_static_id->operand[nop].type != OP_IN) + if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN) reject++; /* SUBREGS ??? */ if (this_alternative_matches >= 0) @@ -2012,6 +2065,9 @@ process_alt_operands (int only_alternati } else if (no_regs_p && ! this_alternative_offmemok && ! constmemok) goto fail; + + if (! no_regs_p) + reload_nregs += ira_reg_class_max_nregs[this_alternative][mode]; } if (early_clobber_p) @@ -2128,7 +2184,9 @@ process_alt_operands (int only_alternati < best_small_class_operands_num || (small_class_operands_num == best_small_class_operands_num - && best_reload_sum < reload_sum)))))) + && (reload_nregs < best_reload_nregs + || (reload_nregs == best_reload_nregs + && best_reload_sum < reload_sum)))))))) { for (nop = 0; nop < n_operands; nop++) { @@ -2145,6 +2203,7 @@ process_alt_operands (int only_alternati 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; } @@ -3045,7 +3104,8 @@ curr_insn_transform (void) return false; } } - if (before != NULL_RTX || after != NULL_RTX || max_regno_before != max_reg_num ()) + if (before != NULL_RTX || after != NULL_RTX + || max_regno_before != max_reg_num ()) change_p = true; if (change_p) { @@ -3504,7 +3564,8 @@ lra_inheritance (void) * lra_constraint_new_regno_start); memset (reload_insn_check, 0, sizeof (int) * lra_constraint_new_regno_start); - reload_insn = (rtx *) xmalloc (sizeof (rtx) * lra_constraint_new_regno_start); + reload_insn + = (rtx *) xmalloc (sizeof (rtx) * lra_constraint_new_regno_start); FOR_EACH_BB (bb) { head = BB_HEAD (bb); Index: lra-eliminations.c =================================================================== --- lra-eliminations.c (revision 178734) +++ lra-eliminations.c (working copy) @@ -671,49 +671,46 @@ mark_not_eliminable (rtx x) case POST_DEC: case POST_MODIFY: case PRE_MODIFY: - /* If we modify the source of an elimination rule, disable it. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == XEXP (x, 0) - || (ep->to_rtx == XEXP (x, 0) - && ep->to_rtx != hard_frame_pointer_rtx)) - setup_can_eliminate (ep, false); - - /* These two aren't unary operators. */ - if (code == POST_MODIFY || code == PRE_MODIFY) - break; - - mark_not_eliminable (XEXP (x, 0)); - return; - - case SUBREG: - mark_not_eliminable (SUBREG_REG (x)); + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) + /* If we modify the source of an elimination rule, disable it. */ + for (ep = reg_eliminate; + ep < ®_eliminate[NUM_ELIMINABLE_REGS]; + ep++) + if (ep->from_rtx == XEXP (x, 0) + || (ep->to_rtx == XEXP (x, 0) + && ep->to_rtx != hard_frame_pointer_rtx)) + setup_can_eliminate (ep, false); return; case USE: - /* If using a register that is the source of an eliminate we still - think can be performed, note it cannot be performed since we don't - know how this register is used. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == XEXP (x, 0) && ep->to_rtx != hard_frame_pointer_rtx) - setup_can_eliminate (ep, false); - - mark_not_eliminable (XEXP (x, 0)); + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) + /* If using a register that is the source of an eliminate we + still think can be performed, note it cannot be performed + since we don't know how this register is used. */ + for (ep = reg_eliminate; + ep < ®_eliminate[NUM_ELIMINABLE_REGS]; + ep++) + if (ep->from_rtx == XEXP (x, 0) + && ep->to_rtx != hard_frame_pointer_rtx) + setup_can_eliminate (ep, false); return; case CLOBBER: - /* If clobbering a register that is the replacement register for an - elimination we still think can be performed, note that it cannot - be performed. Otherwise, we need not be concerned about it. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->to_rtx == XEXP (x, 0) && ep->to_rtx != hard_frame_pointer_rtx) - setup_can_eliminate (ep, false); - - mark_not_eliminable (XEXP (x, 0)); + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) + /* If clobbering a register that is the replacement register for an + elimination we still think can be performed, note that it cannot + be performed. Otherwise, we need not be concerned about it. */ + for (ep = reg_eliminate; + ep < ®_eliminate[NUM_ELIMINABLE_REGS]; + ep++) + if (ep->to_rtx == XEXP (x, 0) + && ep->to_rtx != hard_frame_pointer_rtx) + setup_can_eliminate (ep, false); return; case SET: /* Check for setting a register that we know about. */ - if (REG_P (SET_DEST (x))) + if (REG_P (SET_DEST (x)) && REGNO (SET_DEST (x)) < FIRST_PSEUDO_REGISTER) { /* See if this is setting the replacement register for an elimination.