📄 reload.c
字号:
mode = inmode; else mode = outmode; if (mode == VOIDmode) { error_for_asm (this_insn, "cannot reload integer constant operand in `asm'"); mode = word_mode; if (in != 0) inmode = word_mode; if (out != 0) outmode = word_mode; } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (HARD_REGNO_MODE_OK (i, mode) && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i)) { int nregs = HARD_REGNO_NREGS (i, mode); int j; for (j = 1; j < nregs; j++) if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j)) break; if (j == nregs) break; } if (i == FIRST_PSEUDO_REGISTER) { error_for_asm (this_insn, "impossible register constraint in `asm'"); class = ALL_REGS; } } if (class == NO_REGS) abort (); /* We can use an existing reload if the class is right and at least one of IN and OUT is a match and the other is at worst neutral. (A zero compared against anything is neutral.) If SMALL_REGISTER_CLASSES, don't use existing reloads unless they are for the same thing since that can cause us to need more reload registers than we otherwise would. */ for (i = 0; i < n_reloads; i++) if ((reg_class_subset_p (class, reload_reg_class[i]) || reg_class_subset_p (reload_reg_class[i], class)) /* If the existing reload has a register, it must fit our class. */ && (reload_reg_rtx[i] == 0 || TEST_HARD_REG_BIT (reg_class_contents[(int) class], true_regnum (reload_reg_rtx[i]))) && ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share && (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out))) || (out != 0 && MATCHES (reload_out[i], out) && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in)))) && (reg_class_size[(int) class] == 1#ifdef SMALL_REGISTER_CLASSES || 1#endif ) && MERGABLE_RELOADS (type, reload_when_needed[i], opnum, reload_opnum[i])) break; /* Reloading a plain reg for input can match a reload to postincrement that reg, since the postincrement's value is the right value. Likewise, it can match a preincrement reload, since we regard the preincrementation as happening before any ref in this insn to that register. */ if (i == n_reloads) for (i = 0; i < n_reloads; i++) if ((reg_class_subset_p (class, reload_reg_class[i]) || reg_class_subset_p (reload_reg_class[i], class)) /* If the existing reload has a register, it must fit our class. */ && (reload_reg_rtx[i] == 0 || TEST_HARD_REG_BIT (reg_class_contents[(int) class], true_regnum (reload_reg_rtx[i]))) && out == 0 && reload_out[i] == 0 && reload_in[i] != 0 && ((GET_CODE (in) == REG && (GET_CODE (reload_in[i]) == POST_INC || GET_CODE (reload_in[i]) == POST_DEC || GET_CODE (reload_in[i]) == PRE_INC || GET_CODE (reload_in[i]) == PRE_DEC) && MATCHES (XEXP (reload_in[i], 0), in)) || (GET_CODE (reload_in[i]) == REG && (GET_CODE (in) == POST_INC || GET_CODE (in) == POST_DEC || GET_CODE (in) == PRE_INC || GET_CODE (in) == PRE_DEC) && MATCHES (XEXP (in, 0), reload_in[i]))) && (reg_class_size[(int) class] == 1#ifdef SMALL_REGISTER_CLASSES || 1#endif ) && MERGABLE_RELOADS (type, reload_when_needed[i], opnum, reload_opnum[i])) { /* Make sure reload_in ultimately has the increment, not the plain register. */ if (GET_CODE (in) == REG) in = reload_in[i]; break; } if (i == n_reloads) { /* See if we need a secondary reload register to move between CLASS and IN or CLASS and OUT. Get the icode and push any required reloads needed for each of them if so. */#ifdef SECONDARY_INPUT_RELOAD_CLASS if (in != 0) secondary_in_reload = push_secondary_reload (1, in, opnum, optional, class, inmode, type, &secondary_in_icode);#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS if (out != 0 && GET_CODE (out) != SCRATCH) secondary_out_reload = push_secondary_reload (0, out, opnum, optional, class, outmode, type, &secondary_out_icode);#endif /* We found no existing reload suitable for re-use. So add an additional reload. */ i = n_reloads; reload_in[i] = in; reload_out[i] = out; reload_reg_class[i] = class; reload_inmode[i] = inmode; reload_outmode[i] = outmode; reload_reg_rtx[i] = 0; reload_optional[i] = optional; reload_inc[i] = 0; reload_nocombine[i] = 0; reload_in_reg[i] = inloc ? *inloc : 0; reload_opnum[i] = opnum; reload_when_needed[i] = type; reload_secondary_in_reload[i] = secondary_in_reload; reload_secondary_out_reload[i] = secondary_out_reload; reload_secondary_in_icode[i] = secondary_in_icode; reload_secondary_out_icode[i] = secondary_out_icode; reload_secondary_p[i] = 0; n_reloads++;#ifdef SECONDARY_MEMORY_NEEDED /* If a memory location is needed for the copy, make one. */ if (in != 0 && GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)), class, inmode)) get_secondary_mem (in, inmode, opnum, type); if (out != 0 && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)), outmode)) get_secondary_mem (out, outmode, opnum, type);#endif } else { /* We are reusing an existing reload, but we may have additional information for it. For example, we may now have both IN and OUT while the old one may have just one of them. */ if (inmode != VOIDmode) reload_inmode[i] = inmode; if (outmode != VOIDmode) reload_outmode[i] = outmode; if (in != 0) reload_in[i] = in; if (out != 0) reload_out[i] = out; if (reg_class_subset_p (class, reload_reg_class[i])) reload_reg_class[i] = class; reload_optional[i] &= optional; if (MERGE_TO_OTHER (type, reload_when_needed[i], opnum, reload_opnum[i])) reload_when_needed[i] = RELOAD_OTHER; reload_opnum[i] = MIN (reload_opnum[i], opnum); } /* If the ostensible rtx being reload differs from the rtx found in the location to substitute, this reload is not safe to combine because we cannot reliably tell whether it appears in the insn. */ if (in != 0 && in != *inloc) reload_nocombine[i] = 1;#if 0 /* This was replaced by changes in find_reloads_address_1 and the new function inc_for_reload, which go with a new meaning of reload_inc. */ /* If this is an IN/OUT reload in an insn that sets the CC, it must be for an autoincrement. It doesn't work to store the incremented value after the insn because that would clobber the CC. So we must do the increment of the value reloaded from, increment it, store it back, then decrement again. */ if (out != 0 && sets_cc0_p (PATTERN (this_insn))) { out = 0; reload_out[i] = 0; reload_inc[i] = find_inc_amount (PATTERN (this_insn), in); /* If we did not find a nonzero amount-to-increment-by, that contradicts the belief that IN is being incremented in an address in this insn. */ if (reload_inc[i] == 0) abort (); }#endif /* If we will replace IN and OUT with the reload-reg, record where they are located so that substitution need not do a tree walk. */ if (replace_reloads) { if (inloc != 0) { register struct replacement *r = &replacements[n_replacements++]; r->what = i; r->subreg_loc = in_subreg_loc; r->where = inloc; r->mode = inmode; } if (outloc != 0 && outloc != inloc) { register struct replacement *r = &replacements[n_replacements++]; r->what = i; r->where = outloc; r->subreg_loc = out_subreg_loc; r->mode = outmode; } } /* If this reload is just being introduced and it has both an incoming quantity and an outgoing quantity that are supposed to be made to match, see if either one of the two can serve as the place to reload into. If one of them is acceptable, set reload_reg_rtx[i] to that one. */ if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0) { reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc, inmode, outmode, reload_reg_class[i], i); /* If the outgoing register already contains the same value as the incoming one, we can dispense with loading it. The easiest way to tell the caller that is to give a phony value for the incoming operand (same as outgoing one). */ if (reload_reg_rtx[i] == out && (GET_CODE (in) == REG || CONSTANT_P (in)) && 0 != find_equiv_reg (in, this_insn, 0, REGNO (out), static_reload_reg_p, i, inmode)) reload_in[i] = out; } /* If this is an input reload and the operand contains a register that dies in this insn and is used nowhere else, see if it is the right class to be used for this reload. Use it if so. (This occurs most commonly in the case of paradoxical SUBREGs and in-out reloads). We cannot do this if it is also an output reload that mentions the register unless the output is a SUBREG that clobbers an entire register. Note that the operand might be one of the spill regs, if it is a pseudo reg and we are in a block where spilling has not taken place. But if there is no spilling in this block, that is OK. An explicitly used hard reg cannot be a spill reg. */ if (reload_reg_rtx[i] == 0 && in != 0) { rtx note; int regno; for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note) == REG_DEAD && GET_CODE (XEXP (note, 0)) == REG && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER && reg_mentioned_p (XEXP (note, 0), in) && ! refers_to_regno_for_reload_p (regno, (regno + HARD_REGNO_NREGS (regno, inmode)), PATTERN (this_insn), inloc) /* If this is also an output reload, IN cannot be used as the reload register if it is set in this insn unless IN is also OUT. */ && (out == 0 || in == out || ! hard_reg_set_here_p (regno, (regno + HARD_REGNO_NREGS (regno, inmode)), PATTERN (this_insn))) /* ??? Why is this code so different from the previous? Is there any simple coherent way to describe the two together? What's going on here. */ && (in != out || (GET_CODE (in) == SUBREG && (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))) /* Make sure the operand fits in the reg that dies. */ && GET_MODE_SIZE (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) && HARD_REGNO_MODE_OK (regno, inmode) && GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) && HARD_REGNO_MODE_OK (regno, outmode) && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno) && !fixed_regs[regno]) { reload_reg_rtx[i] = gen_rtx (REG, inmode, regno); break; } } if (out) output_reloadnum = i; return i;}/* Record an additional place we must replace a value for which we have already recorded a reload. RELOADNUM is the value returned by push_reload when the reload was recorded. This is used in insn patterns that use match_dup. */static voidpush_replacement (loc, reloadnum, mode) rtx *loc; int reloadnum; enum machine_mode mode;{ if (replace_reloads) { register struct replacement *r = &replacements[n_replacements++]; r->what = reloadnum; r->where = loc; r->subreg_loc = 0; r->mode = mode; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -