From patchwork Tue Jul 26 18:55:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Makarov X-Patchwork-Id: 106911 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 851DBB6F83 for ; Wed, 27 Jul 2011 04:55:56 +1000 (EST) Received: (qmail 14956 invoked by alias); 26 Jul 2011 18:55:54 -0000 Received: (qmail 14945 invoked by uid 22791); 26 Jul 2011 18:55:50 -0000 X-SWARE-Spam-Status: No, hits=-6.9 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; Tue, 26 Jul 2011 18:55: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 p6QItMit011641 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 26 Jul 2011 14:55:22 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p6QItLtJ008597 for ; Tue, 26 Jul 2011 14:55:22 -0400 Received: from localhost.localdomain (ovpn-113-167.phx2.redhat.com [10.3.113.167]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p6QItJ3k028805 for ; Tue, 26 Jul 2011 14:55:20 -0400 Message-ID: <4E2F0DA2.2080404@redhat.com> Date: Tue, 26 Jul 2011 14:55:30 -0400 From: Vladimir Makarov User-Agent: Mozilla/5.0 (X11; U; Linux i686; 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@gcc.gnu.org Subject: [lra] patch to decrease code size degradation for ARM 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 decreases existing code size degradation on ARM by permitting a special case of early clobber without reloads, for example, for pattern ;; Use `&' and then `0' to prevent the operands 0 and 1 being the same (define_insn "*arm_mulsi3" [(set (match_operand:SI 0 "s_register_operand" "=&r,&r") (mult:SI (match_operand:SI 2 "s_register_operand" "r,r") (match_operand:SI 1 "s_register_operand" "%0,r")))] "TARGET_32BIT && !arm_arch6" "mul%?\\t%0, %2, %1" [(set_attr "insn" "mul") (set_attr "predicable" "yes")] ) It required complete rewriting code dealing with early clobbers in LRA. The patch was successfully bootstrapped on x86-64, ia64, and ppc. 2011-07-26 Vladimir Makarov * lra-assign.c (setup_live_pseudos_and_spill_after_equiv_moves): Remove the dead code. * lra-constraints.c (goal_alternative*): Rename to goal_alt... (goal_early_clobbered_nops_num, goal_early_clobbered_nops): Remove. (goal_alt_dont_inherit_ops_num, goal_alt_dont_inherit_ops): New static variables. (uses_hard_regs_p): New function. (process_alt_operands): Rename curr_alternative to curr_alt... Rename curr_early_clobbered_regs[_num] to early_clobbered_regs[_num]. Add code for matching with early clobber. Add code to process and evaluate conflicts with early clobbers. Set up goal_alt_dont_inherit_ops_num, goal_alt_dont_inherit_ops. (early_clobber_reload_regs_num, early_clobber_reload_regs): Remove. (make_early_clobber_input_reload_reg, search_and_replace_reg): Ditto. s(create_early_clobber_reloads): Ditto. (curr_insn_transform): Rename goal_alternative_matched to goal_alt_matched. Setup dont_inherit flag for early clobber reload pseudo. Don't call create_early_clobber_reloads. Index: lra-assigns.c =================================================================== --- lra-assigns.c (revision 175931) +++ lra-assigns.c (working copy) @@ -869,8 +869,6 @@ curr_regno >= 0; curr_regno = lra_reg_info[curr_regno].next) { - IOR_HARD_REG_SET (conflict_set, - lra_reg_info[curr_regno].conflict_hard_regs); if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (lra_reg_info[curr_regno].biggest_mode)) mode = lra_reg_info[curr_regno].biggest_mode; Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 176001) +++ lra-constraints.c (working copy) @@ -802,7 +802,7 @@ outmode = lra_get_mode (curr_static_id->operand[out].mode, out_rtx); if (inmode != outmode) { - /* Don't reuse the pseudos for inheritance -- they will bound. */ + /* Don't reuse the pseudos for inheritance -- they will be bound. */ get_reload_reg (OP_IN, inmode, in_rtx, goal_class, "", &new_in_reg); new_out_reg = lra_create_new_reg (outmode, out_rtx, goal_class, ""); } @@ -1060,26 +1060,24 @@ /* The chosen reg class which should be used for the corresponding operands. */ -static enum reg_class goal_alternative[MAX_RECOG_OPERANDS]; +static enum reg_class goal_alt[MAX_RECOG_OPERANDS]; /* True if the operand should be the same as another operand and the another operand does not need a reload. */ -static bool goal_alternative_match_win[MAX_RECOG_OPERANDS]; +static bool goal_alt_match_win[MAX_RECOG_OPERANDS]; /* True if the operand does not need a reload. */ -static bool goal_alternative_win[MAX_RECOG_OPERANDS]; +static bool goal_alt_win[MAX_RECOG_OPERANDS]; /* True if the operand can be offsetable memory. */ -static bool goal_alternative_offmemok[MAX_RECOG_OPERANDS]; +static bool goal_alt_offmemok[MAX_RECOG_OPERANDS]; /* The number of operand to which given operand can be matched to. */ -static int goal_alternative_matches[MAX_RECOG_OPERANDS]; +static int goal_alt_matches[MAX_RECOG_OPERANDS]; +/* The number of elements in the following array. */ +static int goal_alt_dont_inherit_ops_num; +/* Numbers of operands whose reload pseudos should not be inherited. */ +static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; /* True if the insn commutative operands should be swapped. */ -static bool goal_alternative_swapped; -/* The number of elements in the following two arrays. */ -static int goal_early_clobbered_nops_num; -/* Numbers of operands which are early clobbered registers. */ -static int goal_early_clobbered_nops[MAX_RECOG_OPERANDS]; -/* Biggest of mode of the early clobbered registers. */ -static enum machine_mode goal_early_clobbered_modes[MAX_RECOG_OPERANDS]; +static bool goal_alt_swapped; /* The chosen insn alternative. */ -static int goal_alternative_number; +static int goal_alt_number; /* The following four variables are used to choose the best insn alternative. They reflect finally characteristics of the best @@ -1247,6 +1245,74 @@ return lra_get_elimation_hard_regno (hard_regno); } +/* Return TRUE if *LOC refers for a hard register from SET. */ +static bool +uses_hard_regs_p (rtx *loc, HARD_REG_SET set) +{ + int i, j, x_hard_regno; + enum machine_mode mode; + rtx x; + const char *fmt; + enum rtx_code code; + + if (*loc == NULL_RTX) + return false; + x = *loc; + code = GET_CODE (x); + mode = GET_MODE (x); + if (code == SUBREG) + { + loc = &SUBREG_REG (x); + x = SUBREG_REG (x); + code = GET_CODE (x); + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) + mode = GET_MODE (x); + } + + if (REG_P (x)) + { + x_hard_regno = REGNO (x); + if (x_hard_regno >= FIRST_PSEUDO_REGISTER) + x_hard_regno = reg_renumber[x_hard_regno]; + return (x_hard_regno >= 0 + && lra_hard_reg_set_intersection_p (x_hard_regno, mode, set)); + } + if (MEM_P (x)) + { + struct address ad; + enum machine_mode mode = GET_MODE (x); + rtx *addr_loc = &XEXP (x, 0); + + extract_address_regs (mode, addr_loc, MEM, &ad); + if (ad.base_reg_loc != NULL) + { + if (uses_hard_regs_p (ad.base_reg_loc, set)) + return true; + } + if (ad.index_reg_loc != NULL) + { + if (uses_hard_regs_p (ad.index_reg_loc, set)) + return true; + } + } + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (uses_hard_regs_p (&XEXP (x, i), set)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (*loc, i) - 1; j >= 0; j--) + if (uses_hard_regs_p (&XVECEXP (*loc, i, j), set)) + return true; + } + } + return false; +} + /* Major function to choose the current insn alternative and what operands should be reload and how. If ONLY_ALTERNATIVE is not negative we should consider only this alternative. Return false if @@ -1269,18 +1335,20 @@ three times here since we want the disparaging caused by a bad register class to only count 1/3 as much. */ int reject; - /* The number of elements in the following two arrays. */ - int curr_early_clobbered_regs_num; + /* The number of elements in the following array. */ + int early_clobbered_regs_num; /* Numbers of operands which are early clobber registers. */ - int curr_early_clobbered_nops[MAX_RECOG_OPERANDS]; - /* Biggest of mode of the early clobbered registers. */ - enum machine_mode curr_early_clobbered_modes[MAX_RECOG_OPERANDS]; - enum reg_class curr_alternative[MAX_RECOG_OPERANDS]; - HARD_REG_SET curr_alternative_set[MAX_RECOG_OPERANDS]; - bool curr_alternative_match_win[MAX_RECOG_OPERANDS]; - bool curr_alternative_win[MAX_RECOG_OPERANDS]; - bool curr_alternative_offmemok[MAX_RECOG_OPERANDS]; - int curr_alternative_matches[MAX_RECOG_OPERANDS]; + int early_clobbered_nops[MAX_RECOG_OPERANDS]; + enum reg_class curr_alt[MAX_RECOG_OPERANDS]; + HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS]; + bool curr_alt_match_win[MAX_RECOG_OPERANDS]; + bool curr_alt_win[MAX_RECOG_OPERANDS]; + bool curr_alt_offmemok[MAX_RECOG_OPERANDS]; + int curr_alt_matches[MAX_RECOG_OPERANDS]; + /* The number of elements in the following array. */ + int curr_alt_dont_inherit_ops_num; + /* Numbers of operands whose reload pseudos should not be inherited. */ + int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; rtx op; rtx no_subreg_operand[MAX_RECOG_OPERANDS], operand_reg[MAX_RECOG_OPERANDS]; int hard_regno[MAX_RECOG_OPERANDS]; @@ -1334,7 +1402,7 @@ for (nop = 0; nop < n_operands; nop++) reject += (curr_static_id ->operand_alternative[nalt * n_operands + nop].reject); - curr_early_clobbered_regs_num = 0; + early_clobbered_regs_num = 0; for (nop = 0; nop < n_operands; nop++) { @@ -1362,12 +1430,12 @@ if (curr_static_id->operand_alternative[opalt_num].anything_ok) { /* Fast track for no constraints at all. */ - curr_alternative[nop] = NO_REGS; - CLEAR_HARD_REG_SET (curr_alternative_set[nop]); - curr_alternative_win[nop] = true; - curr_alternative_match_win[nop] = false; - curr_alternative_offmemok[nop] = false; - curr_alternative_matches[nop] = -1; + curr_alt[nop] = NO_REGS; + CLEAR_HARD_REG_SET (curr_alt_set[nop]); + curr_alt_win[nop] = true; + curr_alt_match_win[nop] = false; + curr_alt_offmemok[nop] = false; + curr_alt_matches[nop] = -1; continue; } @@ -1436,6 +1504,7 @@ case '5': case '6': case '7': case '8': case '9': { int m_hregno, m_offset; + bool match_p; m = strtoul (p, &end, 10); p = end; @@ -1454,20 +1523,37 @@ 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_alternative_offmemok[m] + if (curr_alt_offmemok[m] && MEM_P (*curr_id->operand_loc[m]) - && curr_alternative[m] == NO_REGS - && ! curr_alternative_win[m]) + && curr_alt[m] == NO_REGS && ! curr_alt_win[m]) continue; - did_match = curr_alternative_win[m]; + did_match = curr_alt_win[m]; } else { @@ -1476,11 +1562,11 @@ 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_alternative_win[m] + if (curr_alt_win[m] && (operand_reg[m] == NULL_RTX || hard_regno[m] < 0)) losers++; invalidate_m = m; - if (curr_alternative[m] == NO_REGS) + if (curr_alt[m] == NO_REGS) continue; /* We prefer no matching alternatives because it @@ -1495,9 +1581,8 @@ are supposed to match can be fixed with reloads. */ badop = false; - this_alternative = curr_alternative[m]; - COPY_HARD_REG_SET (this_alternative_set, - curr_alternative_set[m]); + 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 @@ -1505,8 +1590,7 @@ So reject this alternative. */ if (! did_match) for (i = 0; i < nop; i++) - if (curr_alternative_matches[i] - == this_alternative_matches) + if (curr_alt_matches[i] == this_alternative_matches) badop = true; break; @@ -1766,7 +1850,7 @@ not need to generate a reload insn for this operand. */ if (this_alternative_matches < 0 - || curr_alternative_win[this_alternative_matches] + || curr_alt_win[this_alternative_matches] || ! REG_P (op) || find_regno_note (curr_insn, REG_DEAD, REGNO (op)) == NULL_RTX @@ -1878,22 +1962,83 @@ if ((best_losers == 0 || losers != 0) && best_overall < overall) goto fail; - curr_alternative[nop] = this_alternative; - COPY_HARD_REG_SET (curr_alternative_set[nop], this_alternative_set); - curr_alternative_win[nop] = this_alternative_win; - curr_alternative_match_win[nop] = this_alternative_match_win; - curr_alternative_offmemok[nop] = this_alternative_offmemok; - curr_alternative_matches[nop] = this_alternative_matches; + curr_alt[nop] = this_alternative; + COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_set); + curr_alt_win[nop] = this_alternative_win; + curr_alt_match_win[nop] = this_alternative_match_win; + curr_alt_offmemok[nop] = this_alternative_offmemok; + curr_alt_matches[nop] = this_alternative_matches; if (invalidate_m >= 0 && ! this_alternative_win) - curr_alternative_win[invalidate_m] = false; + curr_alt_win[invalidate_m] = false; if (early_clobber_p && operand_reg[nop] != NULL_RTX) + early_clobbered_nops[early_clobbered_regs_num++] = nop; + } + ok_p = true; + curr_alt_dont_inherit_ops_num = 0; + for (nop = 0; nop < early_clobbered_regs_num; nop++) + { + int i, j, clobbered_hard_regno; + HARD_REG_SET temp_set; + + i = early_clobbered_nops[nop]; + if ((! curr_alt_win[i] && ! curr_alt_match_win[i]) + || hard_regno[i] < 0) + continue; + clobbered_hard_regno = hard_regno[i]; + CLEAR_HARD_REG_SET (temp_set); + for (j = hard_regno_nregs[clobbered_hard_regno][biggest_mode[i]] - 1; + j >= 0; + j--) + SET_HARD_REG_BIT (temp_set, clobbered_hard_regno + j); + for (j = 0; j < n_operands; j++) + if (j == i + /* We don't want process insides of match_operator and + match_parallel because otherwise we would process + their operands once again generating a wrong + code. */ + || curr_static_id->operand[j].is_operator) + continue; + else if (curr_alt_matches[j] == i && curr_alt_match_win[j]) + { + /* This is a trick. Such operands don't conflict and + don't need a reload. But it is hard to transfer + this information to the assignment pass which + spills one operand without this info. We avoid the + conflict by forcing to use the same pseudo for the + operands hoping that the pseudo gets the same hard + regno as the operands and the reloads are gone. */ + curr_alt_win[i] = false; + curr_alt_match_win[j] = false; + continue; + } + else if (curr_alt_matches[i] == j && curr_alt_match_win[i]) + { + /* See the comment for the previous case. */ + curr_alt_win[j] = false; + curr_alt_match_win[i] = false; + continue; + } + else if (uses_hard_regs_p (curr_id->operand_loc[j], temp_set)) + break; + if (j >= n_operands) + continue; + /* We need to reload early clobbered register. */ + for (j = 0; j < n_operands; j++) + if (curr_alt_matches[j] == i) + curr_alt_match_win[j] = false; + if (! curr_alt_match_win[i]) + curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i; + else { - curr_early_clobbered_nops[curr_early_clobbered_regs_num] = nop; - curr_early_clobbered_modes[curr_early_clobbered_regs_num++] - = biggest_mode[nop]; + /* Remember pseudos used for match reloads are never inherited. */ + gcc_assert (curr_alt_matches[i] >= 0); + curr_alt_win[curr_alt_matches[i]] = false; } + curr_alt_win[i] = curr_alt_match_win[i] = false; + losers++; + overall += 6; } small_class_operands_num = 0; for (nop = 0; nop < n_operands; nop++) @@ -1901,7 +2046,7 @@ it needs less reloading than the others checked so far, record it as the chosen goal for reloading. */ small_class_operands_num - += SMALL_REGISTER_CLASS_P (curr_alternative[nop]) ? 1 : 0; + += SMALL_REGISTER_CLASS_P (curr_alt[nop]) ? 1 : 0; if ((best_losers != 0 && losers == 0) || (((best_losers == 0 && losers == 0) @@ -1922,24 +2067,22 @@ { for (nop = 0; nop < n_operands; nop++) { - goal_alternative_win[nop] = curr_alternative_win[nop]; - goal_alternative_match_win[nop] - = curr_alternative_match_win[nop]; - goal_alternative_matches[nop] = curr_alternative_matches[nop]; - goal_alternative[nop] = curr_alternative[nop]; - goal_alternative_offmemok[nop] = curr_alternative_offmemok[nop]; - goal_early_clobbered_nops[nop] = curr_early_clobbered_nops[nop]; - goal_early_clobbered_modes[nop] = curr_early_clobbered_modes[nop]; + goal_alt_win[nop] = curr_alt_win[nop]; + goal_alt_match_win[nop] = curr_alt_match_win[nop]; + goal_alt_matches[nop] = curr_alt_matches[nop]; + goal_alt[nop] = curr_alt[nop]; + goal_alt_offmemok[nop] = curr_alt_offmemok[nop]; } - goal_early_clobbered_nops_num = curr_early_clobbered_regs_num; - goal_alternative_swapped = curr_swapped; + goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num; + for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++) + goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop]; + goal_alt_swapped = curr_swapped; best_overall = overall; best_losers = losers; best_small_class_operands_num = small_class_operands_num; best_reload_sum = reload_sum; - goal_alternative_number = nalt; + goal_alt_number = nalt; } - ok_p = true; if (losers == 0) /* Everything is satisfied. Do not process alternatives anymore. */ @@ -2375,216 +2518,6 @@ return result; } -/* Number of elements in the following array. */ -static int early_clobber_reload_regs_num; - -/* Info about registers which we already reloaded because of conflict - with early clobber. */ -static struct -{ - /* Regno of already reloaded register because of conflict with early - clobber. */ - int regno; - /* New register used for the reload. */ - rtx new_reg; -} early_clobber_reload_regs[MAX_RECOG_OPERANDS]; - -/* The function returns a new register of class RCLASS which should be - used for reload input register X because of conflict with an early - clobbered register. If such new register are being created, emit - the reload insns and put them to INSERT sequence. */ -static rtx -make_early_clobber_input_reload_reg (rtx x, enum reg_class rclass, - rtx *insert) -{ - int i, regno; - rtx new_reg; - - gcc_assert (REG_P (x)); - regno = REGNO (x); - for (i = 0; i < early_clobber_reload_regs_num; i++) - if (early_clobber_reload_regs[i].regno == regno - /* It is not worth to check class subsets or to use class - intersects because such cases are extremely rare. */ - && (rclass - == lra_get_allocno_class (REGNO (early_clobber_reload_regs[i].new_reg)))) - return early_clobber_reload_regs[i].new_reg; - if (get_reload_reg (OP_IN, VOIDmode, x, rclass, "early clobbered", &new_reg)) - { - push_to_sequence (*insert); - lra_emit_move (new_reg, x); - *insert = get_insns (); - end_sequence (); - } - gcc_assert (early_clobber_reload_regs_num < MAX_RECOG_OPERANDS); - early_clobber_reload_regs[early_clobber_reload_regs_num].regno = regno; - early_clobber_reload_regs[early_clobber_reload_regs_num++].new_reg - = new_reg; - return new_reg; -} - -/* Replace registers conflicting with early clobbered registers in - *LOC which is inside the operand with number NOP. The substitution - register should have class RCLASS and the reload insns (if it is - not created yet) should be put into sequence *BEFORE. *LOC is an - insn input if IN_P. If the clobbered register is a hard register, - replace it by a new pseudo whose class should be RCLASS and the - reload insns should be put into sequence *BEFORE. If a replacement - is done, return TRUE. */ -static bool -search_and_replace_reg (int nop, rtx *loc, enum reg_class rclass, - rtx *before, rtx *after, bool in_p) -{ - int i, j, clobber_nop, x_hard_regno, clobbered_hard_regno; - bool res; - enum machine_mode mode; - rtx x, *clobbered_reg_loc, new_reg; - const char *fmt; - enum rtx_code code; - HARD_REG_SET temp_set; - - if (*loc == NULL_RTX) - return false; - x = *loc; - code = GET_CODE (x); - mode = GET_MODE (x); - if (code == SUBREG) - { - loc = &SUBREG_REG (x); - x = SUBREG_REG (x); - code = GET_CODE (x); - if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) - mode = GET_MODE (x); - } - - res = false; - if (REG_P (x)) - { - if (! in_p) - return false; - for (i = 0; i < goal_early_clobbered_nops_num; i++) - { - clobber_nop = goal_early_clobbered_nops[i]; - if (goal_alternative_matches[nop] == clobber_nop - || goal_alternative_matches[clobber_nop] == nop) - continue; - clobbered_reg_loc = curr_id->operand_loc[clobber_nop]; - if (GET_CODE (*clobbered_reg_loc) == SUBREG) - clobbered_reg_loc = &SUBREG_REG (*clobbered_reg_loc); - x_hard_regno = REGNO (x); - if (x_hard_regno >= FIRST_PSEUDO_REGISTER) - x_hard_regno = reg_renumber[x_hard_regno]; - clobbered_hard_regno = REGNO (*clobbered_reg_loc); - if (clobbered_hard_regno >= FIRST_PSEUDO_REGISTER) - clobbered_hard_regno = reg_renumber[clobbered_hard_regno]; - CLEAR_HARD_REG_SET (temp_set); - if (clobbered_hard_regno >= 0) - { - for (j = (hard_regno_nregs[clobbered_hard_regno] - [goal_early_clobbered_modes[i]]) - 1; - j >= 0; - j--) - SET_HARD_REG_BIT (temp_set, clobbered_hard_regno + j); - } - /* Examples of conflicts: 1) early clobbered pseudo which is - also an address register in a memory; 2) early clobbered - pseudo which got the same hard register as an input - operand (it might be a hard register itself). ??? Should - we fix it in IRA. */ - if (x != *clobbered_reg_loc - && (x_hard_regno == -1 - || clobbered_hard_regno == -1 - || ! lra_hard_reg_set_intersection_p (x_hard_regno, mode, - temp_set))) - continue; - if (REGNO (*clobbered_reg_loc) >= FIRST_PSEUDO_REGISTER) - { - new_reg - = make_early_clobber_input_reload_reg (x, rclass, before); - *loc = new_reg; - } - else - { - /* In case of conflict with another input, the following - code is not executed again because a new register has - no hard register yet. */ - gcc_assert (goal_alternative[clobber_nop] != NO_REGS); - new_reg = lra_create_new_reg (VOIDmode, *clobbered_reg_loc, - goal_alternative[clobber_nop], - "early clobbered"); - push_to_sequence (*after); - lra_emit_move (*clobbered_reg_loc, new_reg); - *after = get_insns (); - end_sequence (); - *clobbered_reg_loc = new_reg; - } - bitmap_set_bit (&lra_dont_inherit_pseudos, REGNO (new_reg)); - res = true; - } - return res; - } - if (MEM_P (x)) - { - struct address ad; - enum machine_mode mode = GET_MODE (x); - rtx *addr_loc = &XEXP (x, 0); - - extract_address_regs (mode, addr_loc, MEM, &ad); - if (ad.base_reg_loc != NULL) - res = search_and_replace_reg (nop, ad.base_reg_loc, - base_reg_class (mode, - ad.base_outer_code, - ad.index_code), - before, after, true); - if (ad.index_reg_loc != NULL) - res = (search_and_replace_reg (nop, ad.index_reg_loc, - INDEX_REG_CLASS, before, after, true) - || res); - } - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - res = search_and_replace_reg (nop, &XEXP (x, i), - rclass, before, after, in_p) || res; - else if (fmt[i] == 'E') - { - for (j = XVECLEN (*loc, i) - 1; j >= 0; j--) - res = search_and_replace_reg (nop, &XVECEXP (*loc, i, j), - rclass, before, after, in_p) || res; - } - } - return res; -} - -/* Make reload insn and put them into sequence *BEFORE or *AFTER to - resolve conflicts of inputs with early clobbered registers. - Unfortunately IRA does not avoid such conflict creation, e.g. when - early clobbered pseudo also present in a memory as an address - register. - - ??? Should we fix such conflicts in IRA (pro: we can remove this - code here, contra: we can not do it effectively in IRA because we - don't know yet there what insn alternative will be used). */ -static void -create_early_clobber_reloads (rtx *before, rtx *after) -{ - int i; - - if (goal_early_clobbered_nops_num == 0) - return; - early_clobber_reload_regs_num = 0; - for (i = 0; i < curr_static_id->n_operands; i++) - /* We don't want process insides of match_operator and - match_parallel because otherwise we would process their - operands once again generating a wrong code. */ - if (! curr_static_id->operand[i].is_operator - && search_and_replace_reg (i, curr_id->operand_loc[i], - goal_alternative[i], before, after, - curr_static_id->operand[i].type == OP_IN)) - lra_update_dups (curr_id, i, -1); -} - /* Main entry point of this file: search the body of the current insn to choose the best alternative. It is mimicking insn alternative cost calculation model of former reload pass. That is because @@ -2601,7 +2534,7 @@ int n_alternatives; int n_dups; int commutative; - int goal_alternative_matched[MAX_RECOG_OPERANDS]; + int goal_alt_matched[MAX_RECOG_OPERANDS]; rtx before, after; bool alt_p = false; /* Flag that the insn has been changed through a transformation. */ @@ -2610,7 +2543,7 @@ int reused_alternative_num; no_input_reloads_p = no_output_reloads_p = false; - goal_alternative_number = 0; + goal_alt_number = 0; if (check_and_process_move (&change_p)) return change_p; @@ -2641,8 +2574,8 @@ for (i = 0; i < n_operands; i++) { - goal_alternative_matched[i] = -1; - goal_alternative_matches[i] = -1; + goal_alt_matched[i] = -1; + goal_alt_matches[i] = -1; } commutative = curr_static_id->commutative; @@ -2655,7 +2588,7 @@ best_small_class_operands_num = best_reload_sum = 0; curr_swapped = false; - goal_alternative_swapped = false; + goal_alt_swapped = false; /* Make equivalence substitution and memory subreg elimination before address processing because an address legitimacy can @@ -2747,9 +2680,9 @@ } } - /* The operands don't meet the constraints. goal_alternative - describes the alternative that we could reach by reloading the - fewest operands. Reload so as to fit it. */ + /* The operands don't meet the constraints. goal_alt describes the + alternative that we could reach by reloading the fewest operands. + Reload so as to fit it. */ if (! alt_p) { @@ -2768,7 +2701,7 @@ them. Update the operand numbers of any reloads already pushed. */ - if (goal_alternative_swapped) + if (goal_alt_swapped) { rtx tem; rtx x; @@ -2800,19 +2733,18 @@ change_p = true; } - lra_set_used_insn_alternative (curr_insn, - goal_alternative_number); + lra_set_used_insn_alternative (curr_insn, goal_alt_number); if (lra_dump_file != NULL) { const char *p; fprintf (lra_dump_file, " Choosing alt %d in insn %u:", - goal_alternative_number, INSN_UID (curr_insn)); + goal_alt_number, INSN_UID (curr_insn)); for (i = 0; i < n_operands; i++) { p = (curr_static_id->operand_alternative - [goal_alternative_number * n_operands + i].constraint); + [goal_alt_number * n_operands + i].constraint); if (*p == '\0') continue; fprintf (lra_dump_file, " (%d) ", i); @@ -2823,21 +2755,21 @@ } /* Right now, for any pair of operands I and J that are required to - match, with I < J, goal_alternative_matches[J] is I. Set up - goal_alternative_matched as the inverse function: - goal_alternative_matched[I] = J. */ + match, with I < J, goal_alt_matches[J] is I. Set up + goal_alt_matched as the inverse function: goal_alt_matched[I] = + J. */ for (i = 0; i < n_operands; i++) - if (goal_alternative_matches[i] >= 0) - goal_alternative_matched[goal_alternative_matches[i]] = i; + if (goal_alt_matches[i] >= 0) + goal_alt_matched[goal_alt_matches[i]] = i; for (i = 0; i < n_operands; i++) - goal_alternative_win[i] |= goal_alternative_match_win[i]; + goal_alt_win[i] |= goal_alt_match_win[i]; /* Any constants that aren't allowed and can't be reloaded into registers are here changed into memory references. */ for (i = 0; i < n_operands; i++) - if (goal_alternative_win[i]) + if (goal_alt_win[i]) { int regno; enum reg_class new_class; @@ -2848,7 +2780,7 @@ if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) { - bool ok_p = in_class_p (regno, goal_alternative[i], &new_class); + bool ok_p = in_class_p (regno, goal_alt[i], &new_class); if (new_class != NO_REGS && get_reg_class (regno) != new_class) { @@ -2882,7 +2814,7 @@ if (CONST_POOL_OK_P (mode, op) && ((targetm.preferred_reload_class - (op, (enum reg_class) goal_alternative[i]) == NO_REGS) + (op, (enum reg_class) goal_alt[i]) == NO_REGS) || no_input_reloads_p) && mode != VOIDmode) { @@ -2905,9 +2837,8 @@ if (plus != NULL_RTX || subreg != NULL_RTX) continue; /* Skip alternatives before the one requested. */ - constraint - = (curr_static_id->operand_alternative - [goal_alternative_number * n_operands + i].constraint); + constraint = (curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].constraint); for (; (c = *constraint) && c != ',' && c != '#'; constraint += CONSTRAINT_LEN (c, constraint)) @@ -2923,7 +2854,7 @@ if (c == '\0' || c == ',' || c == '#') continue; - goal_alternative_win[i] = true; + goal_alt_win[i] = true; } } @@ -2932,9 +2863,9 @@ rtx old, new_reg; rtx op = *curr_id->operand_loc[i]; - if (goal_alternative_win[i]) + if (goal_alt_win[i]) { - if (goal_alternative[i] == NO_REGS + if (goal_alt[i] == NO_REGS && REG_P (op) && lra_former_scratch_operand_p (curr_insn, i)) change_class (REGNO (op), NO_REGS, " Change", true); @@ -2942,16 +2873,14 @@ } /* Operands that match previous ones have already been handled. */ - if (goal_alternative_matches[i] >= 0) + if (goal_alt_matches[i] >= 0) continue; /* We should not have an operand with a nonoffsettable address appearing where an offsettable address will do. It also may be a case when the address should be special in other words not a general one (e.g. it needs no index reg). */ - if (goal_alternative_matched[i] == -1 - && goal_alternative_offmemok[i] - && MEM_P (op)) + if (goal_alt_matched[i] == -1 && goal_alt_offmemok[i] && MEM_P (op)) { enum reg_class rclass; rtx *loc = &XEXP (op, 0); @@ -2973,11 +2902,11 @@ *loc = new_reg; lra_update_dups (curr_id, i, -1); } - else if (goal_alternative_matched[i] == -1) + else if (goal_alt_matched[i] == -1) { enum machine_mode mode; rtx reg, *loc; - int hard_regno, byte; + int j, hard_regno, byte; enum op_type type = curr_static_id->operand[i].type; loc = curr_id->operand_loc[i]; @@ -2997,9 +2926,9 @@ && (simplify_subreg_regno (hard_regno, GET_MODE (reg), byte, mode) < 0) - && (goal_alternative[i] == NO_REGS + && (goal_alt[i] == NO_REGS || (simplify_subreg_regno - (ira_class_hard_regs[goal_alternative[i]][0], + (ira_class_hard_regs[goal_alt[i]][0], GET_MODE (reg), byte, mode) >= 0))))) { loc = &SUBREG_REG (*loc); @@ -3007,7 +2936,7 @@ } } old = *loc; - if (get_reload_reg (type, mode, old, goal_alternative[i], "", &new_reg) + if (get_reload_reg (type, mode, old, goal_alt[i], "", &new_reg) && type != OP_OUT) { push_to_sequence (before); @@ -3027,18 +2956,21 @@ } *loc = new_reg; } + for (j = 0; j < goal_alt_dont_inherit_ops_num; j++) + if (goal_alt_dont_inherit_ops[j] == i) + { + bitmap_set_bit (&lra_dont_inherit_pseudos, REGNO (new_reg)); + break; + } lra_update_dups (curr_id, i, -1); } else if (curr_static_id->operand[i].type == OP_IN - && (curr_static_id - ->operand[goal_alternative_matched[i]].type == OP_OUT)) - match_reload (goal_alternative_matched[i], i, - goal_alternative[i], &before, &after); + && curr_static_id->operand[goal_alt_matched[i]].type == OP_OUT) + match_reload (goal_alt_matched[i], i, + goal_alt[i], &before, &after); else if (curr_static_id->operand[i].type == OP_OUT - && (curr_static_id - ->operand[goal_alternative_matched[i]].type == OP_IN)) - match_reload (i, goal_alternative_matched[i], - goal_alternative[i], &before, &after); + && curr_static_id->operand[goal_alt_matched[i]].type == OP_IN) + match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after); else { gcc_assert (INSN_CODE (curr_insn) < 0); @@ -3049,7 +2981,6 @@ return false; } } - create_early_clobber_reloads (&before, &after); if (before != NULL_RTX || after != NULL_RTX || max_regno_before != max_reg_num ()) change_p = true; if (change_p)