📄 reload.c
字号:
/* Now get the operand values and constraints out of the insn. */ decode_asm_operands (body, recog_operand, recog_operand_loc, constraints, operand_mode); if (noperands > 0) { bcopy (constraints, constraints1, noperands * sizeof (char *)); n_alternatives = n_occurrences (',', constraints[0]) + 1; for (i = 1; i < noperands; i++) if (n_alternatives != n_occurrences (',', constraints[0]) + 1) { error_for_asm (insn, "operand constraints differ in number of alternatives"); /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx); n_reloads = 0; return; } } break; } default: /* Ordinary insn: recognize it, allocate space for operands and constraints, and get them out via insn_extract. */ insn_code_number = recog_memoized (insn); noperands = insn_n_operands[insn_code_number]; n_alternatives = insn_n_alternatives[insn_code_number]; /* Just return "no reloads" if insn has no operands with constraints. */ if (n_alternatives == 0) return; insn_extract (insn); for (i = 0; i < noperands; i++) { constraints[i] = constraints1[i] = insn_operand_constraint[insn_code_number][i]; operand_mode[i] = insn_operand_mode[insn_code_number][i]; } } if (noperands == 0) return; commutative = -1; /* If we will need to know, later, whether some pair of operands are the same, we must compare them now and save the result. Reloading the base and index registers will clobber them and afterward they will fail to match. */ for (i = 0; i < noperands; i++) { register char *p; register int c; substed_operand[i] = recog_operand[i]; p = constraints[i]; /* Scan this operand's constraint to see if it should match another. */ while (c = *p++) if (c == '%') commutative = i; else if (c >= '0' && c <= '9') { c -= '0'; operands_match[c][i] = operands_match_p (recog_operand[c], recog_operand[i]); /* If C can be commuted with C+1, and C might need to match I, then C+1 might also need to match I. */ if (commutative >= 0) { if (c == commutative || c == commutative + 1) { int other = c + (c == commutative ? 1 : -1); operands_match[other][i] = operands_match_p (recog_operand[other], recog_operand[i]); } if (i == commutative || i == commutative + 1) { int other = i + (i == commutative ? 1 : -1); operands_match[c][other] = operands_match_p (recog_operand[c], recog_operand[other]); } /* Note that C is supposed to be less than I. No need to consider altering both C and I because in that case we would alter one into the other. */ } } } /* Examine each operand that is a memory reference or memory address and reload parts of the addresses into index registers. While we are at it, initialize the array `modified'. Also here any references to pseudo regs that didn't get hard regs but are equivalent to constants get replaced in the insn itself with those constants. Nobody will ever see them again. */ for (i = 0; i < noperands; i++) { register RTX_CODE code = GET_CODE (recog_operand[i]); modified[i] = RELOAD_READ; address_reloaded[i] = 0; if (constraints[i][0] == 'p') { find_reloads_address (VOIDmode, 0, recog_operand[i], recog_operand_loc[i], recog_operand[i]); substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]; } else if (code == MEM) { if (find_reloads_address (GET_MODE (recog_operand[i]), recog_operand_loc[i], XEXP (recog_operand[i], 0), &XEXP (recog_operand[i], 0), recog_operand[i])) address_reloaded[i] = 1; substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]; } else if (code == SUBREG) substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = find_reloads_toplev (recog_operand[i]); else if (code == REG) { /* This is equivalent to calling find_reloads_toplev. The code is duplicated for speed. */ register int regno = REGNO (recog_operand[i]); if (reg_equiv_constant[regno] != 0) substed_operand[i] = recog_operand[i] = reg_equiv_constant[regno];#if 0 /* This might screw code in reload1.c to delete prior output-reload that feeds this insn. */ if (reg_equiv_mem[regno] != 0) substed_operand[i] = recog_operand[i] = reg_equiv_mem[regno];#endif if (reg_equiv_address[regno] != 0) { *recog_operand_loc[i] = recog_operand[i] = gen_rtx (MEM, GET_MODE (recog_operand[i]), reg_equiv_address[regno]); find_reloads_address (GET_MODE (recog_operand[i]), recog_operand_loc[i], XEXP (recog_operand[i], 0), &XEXP (recog_operand[i], 0), recog_operand[i]); substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]; } } } /* Now see what we need for pseudo-regs that didn't get hard regs or got the wrong kind of hard reg. For this, we must consider all the operands together against the register constraints. */ best = MAX_RECOG_OPERANDS + 100; swapped = 0; try_swapped: /* The constraints are made of several alternatives. Each operand's constraint looks like foo,bar,... with commas separating the alternatives. The first alternatives for all operands go together, the second alternatives go together, etc. First loop over alternatives. */ for (this_alternative_number = 0; this_alternative_number < n_alternatives; this_alternative_number++) { /* Loop over operands for one constraint alternative. */ /* LOSERS counts those that don't fit this alternative and would require loading. */ int losers = 0; /* BAD is set to 1 if it some operand can't fit this alternative even after reloading. */ int bad = 0; /* REJECT is a count of how undesirable this alternative says it is if any reloading is required. If the alternative matches exactly then REJECT is ignored, but otherwise it gets this much counted against it in addition to the reloading needed. */ int reject = 0; this_earlyclobber = 0; for (i = 0; i < noperands; i++) { register char *p = constraints[i]; register int win = 0; /* 0 => this operand can be reloaded somehow for this alternative */ int badop = 1; /* 0 => this operand can be reloaded if the alternative allows regs. */ int winreg = 0; int c; register rtx operand = recog_operand[i]; int offset = 0; /* Nonzero means this is a MEM that must be reloaded into a reg regardless of what the constraint says. */ int force_reload = 0; int offmemok = 0; int earlyclobber = 0; /* If the operand is a SUBREG, extract the REG or MEM (or maybe even a constant) within. (Constants can occur as a result of reg_equiv_constant.) */ while (GET_CODE (operand) == SUBREG) { offset += SUBREG_WORD (operand); operand = SUBREG_REG (operand); if (GET_CODE (operand) != REG) force_reload = 1; } this_alternative[i] = (int) NO_REGS; this_alternative_win[i] = 0; this_alternative_offmemok[i] = 0; this_alternative_earlyclobber[i] = 0; this_alternative_matches[i] = -1; /* An empty constraint or empty alternative allows anything which matched the pattern. */ if (*p == 0 || *p == ',') win = 1, badop = 0; /* Scan this alternative's specs for this operand; set WIN if the operand fits any letter in this alternative. Otherwise, clear BADOP if this operand could fit some letter after reloads, or set WINREG if this operand could fit after reloads provided the constraint allows some registers. */ while (*p && (c = *p++) != ',') switch (c) { case '=': modified[i] = RELOAD_WRITE; break; case '+': modified[i] = RELOAD_READ_WRITE; break; case '*': break; case '%': commutative = i; break; case '?': reject++; break; case '!': reject = 100; break; case '#': /* Ignore rest of this alternative as far as reloading is concerned. */ while (*p && *p != ',') p++; break; case '0': case '1': case '2': case '3': case '4': c -= '0'; this_alternative_matches[i] = c; /* 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 ((swapped && (c != commutative || i != commutative + 1)) /* If we are matching as if two operands were swapped, also pretend that operands_match had been computed with swapped. But if I is the second of those and C is the first, don't exchange them, because operands_match is valid only on one side of its diagonal. */ ? (operands_match [(c == commutative || c == commutative + 1) ? 2*commutative + 1 - c : c] [(i == commutative || i == commutative + 1) ? 2*commutative + 1 - i : i]) : operands_match[c][i]) win = this_alternative_win[c]; else { /* Operands don't match. */ rtx value; /* Retroactively mark the operand we had to match as a loser, if it wasn't already. */ if (this_alternative_win[c]) losers++; this_alternative_win[c] = 0; if (this_alternative[c] == (int) NO_REGS) bad = 1; /* But count the pair only once in the total badness of this alternative, if the pair can be a dummy reload. */ value = find_dummy_reload (recog_operand[i], recog_operand[c], recog_operand_loc[i], recog_operand_loc[c], this_alternative[c], -1); if (value != 0) losers--; } /* This can be fixed with reloads if the operand we are supposed to match can be fixed with reloads. */ badop = 0; this_alternative[i] = this_alternative[c]; break; case 'p': /* All necessary reloads for an address_operand were handled in find_reloads_address. */ this_alternative[i] = (int) ALL_REGS; win = 1; break; case 'm': if (force_reload) break; if (GET_CODE (operand) == MEM || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0)) win = 1; if (GET_CODE (operand) == CONST_DOUBLE || CONSTANT_P (operand)) badop = 0; break; case '<': if (GET_CODE (operand) == MEM && ! address_reloaded[i] && (GET_CODE (XEXP (operand, 0)) == PRE_DEC || GET_CODE (XEXP (operand, 0)) == POST_DEC)) win = 1; break; case '>': if (GET_CODE (operand) == MEM && ! address_reloaded[i] && (GET_CODE (XEXP (operand, 0)) == PRE_INC || GET_CODE (XEXP (operand, 0)) == POST_INC)) win = 1; break; /* Memory operand whose address is offsettable. */ case 'o': if (force_reload) break; if ((GET_CODE (operand) == MEM && offsettable_memref_p (operand)) /* Certain mem addresses will become offsettable after they themselves are reloaded. This is important; we don't want our own handling of unoffsettables to override the handling of reg_equiv_address. */ || (GET_CODE (operand) == MEM && GET_CODE (XEXP (operand, 0)) == REG && (! ind_ok || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0)) || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (operand)] < 0)) win = 1; if (GET_CODE (operand) == CONST_DOUBLE || CONSTANT_P (operand) || GET_CODE (operand) == MEM) badop = 0; offmemok = 1; break; case '&': /* Output operand that is stored before the need for the input operands (and their index registers) is over. */ if (GET_CODE (operand) == REG || GET_CODE (operand) == MEM) earlyclobber = 1, this_earlyclobber = 1; break; case 'F': if (GET_CODE (operand) == CONST_DOUBLE) win = 1; break; case 'G': case 'H': if (GET_CODE (operand) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c)) win = 1; break; case 's': if (GET_CODE (operand) == CONST_INT) break; case 'i': if (CONSTANT_P (operand))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -