📄 reload.c
字号:
&& ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) / UNITS_PER_WORD) != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out))))))) { /* This relies on the fact that emit_reload_insns outputs the instructions for output reloads of type RELOAD_OTHER in reverse order of the reloads. Thus if the outer reload is also of type RELOAD_OTHER, we are guaranteed that this inner reload will be output after the outer reload. */ dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), &SUBREG_REG (out), find_valid_class (outmode, SUBREG_WORD (out)), VOIDmode, VOIDmode, 0, 0, opnum, RELOAD_OTHER); } /* If IN appears in OUT, we can't share any input-only reload for IN. */ if (in != 0 && out != 0 && GET_CODE (out) == MEM && (GET_CODE (in) == REG || GET_CODE (in) == MEM) && reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0))) dont_share = 1; /* If IN is a SUBREG of a hard register, make a new REG. This simplifies some of the cases below. */ if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) in = gen_rtx (REG, GET_MODE (in), REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); /* Similarly for OUT. */ if (out != 0 && GET_CODE (out) == SUBREG && GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) out = gen_rtx (REG, GET_MODE (out), REGNO (SUBREG_REG (out)) + SUBREG_WORD (out)); /* Narrow down the class of register wanted if that is desirable on this machine for efficiency. */ if (in != 0) class = PREFERRED_RELOAD_CLASS (in, class); /* Output reloads may need analogous treatment, different in detail. */#ifdef PREFERRED_OUTPUT_RELOAD_CLASS if (out != 0) class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class);#endif /* Make sure we use a class that can handle the actual pseudo inside any subreg. For example, on the 386, QImode regs can appear within SImode subregs. Although GENERAL_REGS can handle SImode, QImode needs a smaller class. */#ifdef LIMIT_RELOAD_CLASS if (in_subreg_loc) class = LIMIT_RELOAD_CLASS (inmode, class); else if (in != 0 && GET_CODE (in) == SUBREG) class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), class); if (out_subreg_loc) class = LIMIT_RELOAD_CLASS (outmode, class); if (out != 0 && GET_CODE (out) == SUBREG) class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class);#endif /* Verify that this class is at least possible for the mode that is specified. */ if (this_insn_is_asm) { enum machine_mode mode; if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode)) 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 || SMALL_REGISTER_CLASSES) && 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 || SMALL_REGISTER_CLASSES) && 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. */#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);#endif 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 (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. */ /* The modes can be different. If they are, we want to reload in the larger mode, so that the value is valid for both modes. */ if (inmode != VOIDmode && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (reload_inmode[i])) reload_inmode[i] = inmode; if (outmode != VOIDmode && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i])) 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, earlyclobber_operand_p (out)); /* 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -