📄 reload.c
字号:
win = 1; break; case 'n': if (GET_CODE (operand) == CONST_INT) win = 1; break; case 'I': case 'J': case 'K': case 'L': case 'M': if (GET_CODE (operand) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (operand), c)) win = 1; break; case 'g': if (! force_reload && (GENERAL_REGS == ALL_REGS || GET_CODE (operand) != REG || (REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0))) win = 1; /* Drop through into 'r' case */ case 'r': this_alternative[i] = (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS]; goto reg; default: this_alternative[i] = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)]; reg: if (GET_MODE (operand) == BLKmode) break; winreg = 1; if (GET_CODE (operand) == REG && reg_fits_class_p (operand, this_alternative[i], offset, GET_MODE (recog_operand[i]))) win = 1; break; } constraints[i] = p; /* If this operand could be handled with a reg, and some reg is allowed, then this operand can be handled. */ if (winreg && this_alternative[i] != (int) NO_REGS) badop = 0; /* Record which operands fit this alternative. */ this_alternative_earlyclobber[i] = earlyclobber; if (win && ! force_reload) this_alternative_win[i] = 1; else { this_alternative_offmemok[i] = offmemok; losers++; if (badop) bad = 1; /* Alternative loses if it has no regs for a reg operand. */ if (GET_CODE (operand) == REG && this_alternative[i] == (int) NO_REGS && this_alternative_matches[i] < 0) bad = 1; } } /* Now see if any output operands that are marked "earlyclobber" in this alternative conflict with any input operands or any memory addresses. */ for (i = 0; i < noperands; i++) if (this_alternative_earlyclobber[i] && this_alternative_win[i]) { struct decomposition early_data; int j; early_data = decompose (recog_operand[i]); if (modified[i] == RELOAD_READ) { if (this_insn_is_asm) warning_for_asm (this_insn, "`&' constraint used with input operand"); else abort (); continue; } if (this_alternative[i] == NO_REGS) { this_alternative_earlyclobber[i] = 0; if (this_insn_is_asm) error_for_asm (this_insn, "`&' constraint used with no register class"); else abort (); } for (j = 0; j < noperands; j++) /* Is this an input operand or a memory ref? */ if ((GET_CODE (recog_operand[j]) == MEM || modified[j] != RELOAD_WRITE) && j != i /* Don't count an input operand that is constrained to match the early clobber operand. */ && ! (this_alternative_matches[j] == i && rtx_equal_p (recog_operand[i], recog_operand[j])) /* Is it altered by storing the earlyclobber operand? */ && !immune_p (recog_operand[j], recog_operand[i], early_data)) { /* If the output is in a single-reg class, it's costly to reload it, so reload the input instead. */ if (reg_class_size[this_alternative[i]] == 1 && (GET_CODE (recog_operand[j]) == REG || GET_CODE (recog_operand[j]) == SUBREG)) { losers++; this_alternative_win[j] = 0; } else break; } /* If an earlyclobber operand conflicts with something, it must be reloaded, so request this and count the cost. */ if (j != noperands) { losers++; this_alternative_win[i] = 0; for (j = 0; j < noperands; j++) if (this_alternative_matches[j] == i && this_alternative_win[j]) { this_alternative_win[j] = 0; losers++; } } } /* If one alternative accepts all the operands, no reload required, choose that alternative; don't consider the remaining ones. */ if (losers == 0) { /* Unswap these so that they are never swapped at `finish'. */ if (commutative >= 0) { recog_operand[commutative] = substed_operand[commutative]; recog_operand[commutative + 1] = substed_operand[commutative + 1]; } for (i = 0; i < noperands; i++) { goal_alternative_win[i] = 1; goal_alternative[i] = this_alternative[i]; goal_alternative_offmemok[i] = this_alternative_offmemok[i]; goal_alternative_matches[i] = this_alternative_matches[i]; goal_alternative_earlyclobber[i] = this_alternative_earlyclobber[i]; } goal_alternative_number = this_alternative_number; goal_alternative_swapped = swapped; goal_earlyclobber = this_earlyclobber; goto finish; } /* REJECT, set by the ! and ? constraint characters, discourages the use of this alternative for a reload goal. */ if (reject > 0) losers += reject; /* If this alternative can be made to work by reloading, and it needs less reloading than the others checked so far, record it as the chosen goal for reloading. */ if (! bad && best > losers) { for (i = 0; i < noperands; i++) { goal_alternative[i] = this_alternative[i]; goal_alternative_win[i] = this_alternative_win[i]; goal_alternative_offmemok[i] = this_alternative_offmemok[i]; goal_alternative_matches[i] = this_alternative_matches[i]; goal_alternative_earlyclobber[i] = this_alternative_earlyclobber[i]; } goal_alternative_swapped = swapped; best = losers; goal_alternative_number = this_alternative_number; goal_earlyclobber = this_earlyclobber; } } /* If insn is commutative (it's safe to exchange a certain pair of operands) then we need to try each alternative twice, the second time matching those two operands as if we had exchanged them. To do this, really exchange them in operands. If we have just tried the alternatives the second time, return operands to normal and drop through. */ if (commutative >= 0) { swapped = !swapped; if (swapped) { recog_operand[commutative] = substed_operand[commutative + 1]; recog_operand[commutative + 1] = substed_operand[commutative]; bcopy (constraints1, constraints, noperands * sizeof (char *)); goto try_swapped; } else { recog_operand[commutative] = substed_operand[commutative]; recog_operand[commutative + 1] = substed_operand[commutative + 1]; } } /* 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. */ if (best == MAX_RECOG_OPERANDS + 100) { /* No alternative works with reloads?? */ if (insn_code_number >= 0) abort (); error_for_asm (insn, "inconsistent operand constraints in an `asm'"); /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx); n_reloads = 0; return; } /* Jump to `finish' from above if all operands are valid already. In that case, goal_alternative_win is all 1. */ finish: /* 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. */ for (i = 0; i < noperands; i++) goal_alternative_matched[i] = -1; for (i = 0; i < noperands; i++) if (! goal_alternative_win[i] && goal_alternative_matches[i] >= 0) goal_alternative_matched[goal_alternative_matches[i]] = i; /* If the best alternative is with operands 1 and 2 swapped, consider them swapped before reporting the reloads. */ if (goal_alternative_swapped) { register rtx tem; tem = substed_operand[commutative]; substed_operand[commutative] = substed_operand[commutative + 1]; substed_operand[commutative + 1] = tem; tem = recog_operand[commutative]; recog_operand[commutative] = recog_operand[commutative + 1]; recog_operand[commutative + 1] = tem; } /* Perform whatever substitutions on the operands we are supposed to make due to commutativity or replacement of registers with equivalent constants or memory slots. */ for (i = 0; i < noperands; i++) { *recog_operand_loc[i] = substed_operand[i]; /* While we are looping on operands, initialize this. */ operand_reloadnum[i] = -1; } /* Any constants that aren't allowed and can't be reloaded into memory locations are here changed into memory references. */ for (i = 0; i < noperands; i++) if (! goal_alternative_win[i] && (GET_CODE (recog_operand[i]) == CONST_DOUBLE || CONSTANT_P (recog_operand[i])) && (PREFERRED_RELOAD_CLASS (recog_operand[i], (enum reg_class) goal_alternative[i]) == NO_REGS)) { enum machine_mode mode = operand_mode[i]; *recog_operand_loc[i] = recog_operand[i] = (GET_CODE (recog_operand[i]) == CONST_DOUBLE ? force_const_double_mem (recog_operand[i]) : force_const_mem (mode != VOIDmode ? mode : SImode, recog_operand[i])); find_reloads_toplev (recog_operand[i]); if (alternative_allows_memconst (constraints1[i], goal_alternative_number)) goal_alternative_win[i] = 1; } /* Now record reloads for all the operands that need them. */ for (i = 0; i < noperands; i++) if (! goal_alternative_win[i]) { /* Operands that match previous ones have already been handled. */ if (goal_alternative_matches[i] >= 0) ; /* Handle an operand with a nonoffsettable address appearing where an offsettable address will do by reloading the address into a base register. */ else if (goal_alternative_matched[i] == -1 && goal_alternative_offmemok[i] && GET_CODE (recog_operand[i]) == MEM) { operand_reloadnum[i] = push_reload (XEXP (recog_operand[i], 0), 0, &XEXP (recog_operand[i], 0), 0, BASE_REG_CLASS, GET_MODE (XEXP (recog_operand[i], 0)), 0, 0, 0, 0); reload_inc[operand_reloadnum[i]] = GET_MODE_SIZE (GET_MODE (recog_operand[i])); } else if (goal_alternative_matched[i] == -1) operand_reloadnum[i] = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0, modified[i] != RELOAD_READ ? recog_operand[i] : 0, recog_operand_loc[i], 0, (enum reg_class) goal_alternative[i], (modified[i] == RELOAD_WRITE ? VOIDmode : operand_mode[i]), (modified[i] == RELOAD_READ ? VOIDmode : operand_mode[i]), (insn_code_number < 0 ? 0 : insn_operand_strict_low[insn_code_number][i]), 0, 0); /* In a matching pair of operands, one must be input only and the other must be output only. Pass the input operand as IN and the other as OUT. */ else if (modified[i] == RELOAD_READ && modified[goal_alternative_matched[i]] == RELOAD_WRITE) { operand_reloadnum[i] = push_reload (recog_operand[i], recog_operand[goal_alternative_matched[i]], recog_operand_loc[i], recog_operand_loc[goal_alternative_matched[i]], (enum reg_class) goal_alternative[i], operand_mode[i], operand_mode[goal_alternative_matched[i]], VOIDmode, 0, 0); operand_reloadnum[goal_alternative_matched[i]] = output_reloadnum; } else if (modified[i] == RELOAD_WRITE && modified[goal_alternative_matched[i]] == RELOAD_READ) { operand_reloadnum[goal_alternative_matched[i]] = push_reload (recog_operand[goal_alternative_matched[i]], recog_operand[i], recog_operand_loc[goal_alternative_matched[i]], recog_operand_loc[i], (enum reg_class) goal_alternative[i], operand_mode[goal_alternative_matched[i]], operand_mode[i], VOIDmode, 0, 0); operand_reloadnum[i] = output_reloadnum; } else if (insn_code_number >= 0) abort (); else { error_for_asm (insn, "inconsistent operand constraints in an `asm'"); /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx); n_reloads = 0; return; } } else if (goal_alternative_matched[i] < 0 && goal_alternative_matches[i] < 0 && optimize) { rtx operand = recog_operand[i]; /* For each non-matching operand that's a pseudo-register that didn't get a hard register, make an optional reload. This may get done even if the insn needs no reloads otherwise. */ /* (It would be safe to make an optional reload for a matching pair of operands, but we don't bother yet.) */ while (GET_CODE (operand) == SUBREG) operand = XEXP (operand, 0); if (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0 && (enum reg_class) goal_alternative[i] != NO_REGS /* Don't make optional output reloads for jump insns (such as aobjeq on the vax). */ && (modified[i] == RELOAD_READ || GET_CODE (insn) != JUMP_INSN)) operand_reloadnum[i] = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0, modified[i] != RELOAD_READ ? recog_operand[i] : 0, r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -