📄 reload.c
字号:
secondary_type = type; else secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS; *picode = CODE_FOR_nothing; /* If X is a paradoxical SUBREG, use the inner value to determine both the mode and object being reloaded. */ if (GET_CODE (x) == SUBREG && (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) { x = SUBREG_REG (x); reload_mode = GET_MODE (x); } /* If X is a pseudo-register that has an equivalent MEM (actually, if it is still a pseudo-register by now, it *must* have an equivalent MEM but we don't want to assume that), use that equivalent when seeing if a secondary reload is needed since whether or not a reload is needed might be sensitive to the form of the MEM. */ if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_equiv_mem[REGNO (x)] != 0) x = reg_equiv_mem[REGNO (x)];#ifdef SECONDARY_INPUT_RELOAD_CLASS if (in_p) class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS if (! in_p) class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif /* If we don't need any secondary registers, done. */ if (class == NO_REGS) return -1; /* Get a possible insn to use. If the predicate doesn't accept X, don't use the insn. */ icode = (in_p ? reload_in_optab[(int) reload_mode] : reload_out_optab[(int) reload_mode]); if (icode != CODE_FOR_nothing && insn_operand_predicate[(int) icode][in_p] && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode))) icode = CODE_FOR_nothing; /* If we will be using an insn, see if it can directly handle the reload register we will be using. If it can, the secondary reload is for a scratch register. If it can't, we will use the secondary reload for an intermediate register and require a tertiary reload for the scratch register. */ if (icode != CODE_FOR_nothing) { /* If IN_P is non-zero, the reload register will be the output in operand 0. If IN_P is zero, the reload register will be the input in operand 1. Outputs should have an initial "=", which we must skip. */ char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p]; enum reg_class insn_class = (insn_letter == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (insn_letter)); if (insn_class == NO_REGS || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=') /* The scratch register's constraint must start with "=&". */ || insn_operand_constraint[(int) icode][2][0] != '=' || insn_operand_constraint[(int) icode][2][1] != '&') abort (); if (reg_class_subset_p (reload_class, insn_class)) mode = insn_operand_mode[(int) icode][2]; else { char t_letter = insn_operand_constraint[(int) icode][2][2]; class = insn_class; t_mode = insn_operand_mode[(int) icode][2]; t_class = (t_letter == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (t_letter)); t_icode = icode; icode = CODE_FOR_nothing; } } /* This case isn't valid, so fail. Reload is allowed to use the same register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads, but in the case of a secondary register, we actually need two different registers for correct code. We fail here to prevent the possibility of silently generating incorrect code later. The convention is that secondary input reloads are valid only if the secondary_class is different from class. If you have such a case, you can not use secondary reloads, you must work around the problem some other way. Allow this when MODE is not reload_mode and assume that the generated code handles this case (it does on the Alpha, which is the only place this currently happens). */ if (in_p && class == reload_class && mode == reload_mode) abort (); /* If we need a tertiary reload, see if we have one we can reuse or else make a new one. */ if (t_class != NO_REGS) { for (t_reload = 0; t_reload < n_reloads; t_reload++) if (reload_secondary_p[t_reload] && (reg_class_subset_p (t_class, reload_reg_class[t_reload]) || reg_class_subset_p (reload_reg_class[t_reload], t_class)) && ((in_p && reload_inmode[t_reload] == t_mode) || (! in_p && reload_outmode[t_reload] == t_mode)) && ((in_p && (reload_secondary_in_icode[t_reload] == CODE_FOR_nothing)) || (! in_p &&(reload_secondary_out_icode[t_reload] == CODE_FOR_nothing))) && (reg_class_size[(int) t_class] == 1#ifdef SMALL_REGISTER_CLASSES || 1#endif ) && MERGABLE_RELOADS (secondary_type, reload_when_needed[t_reload], opnum, reload_opnum[t_reload])) { if (in_p) reload_inmode[t_reload] = t_mode; if (! in_p) reload_outmode[t_reload] = t_mode; if (reg_class_subset_p (t_class, reload_reg_class[t_reload])) reload_reg_class[t_reload] = t_class; reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum); reload_optional[t_reload] &= optional; reload_secondary_p[t_reload] = 1; if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload], opnum, reload_opnum[t_reload])) reload_when_needed[t_reload] = RELOAD_OTHER; } if (t_reload == n_reloads) { /* We need to make a new tertiary reload for this register class. */ reload_in[t_reload] = reload_out[t_reload] = 0; reload_reg_class[t_reload] = t_class; reload_inmode[t_reload] = in_p ? t_mode : VOIDmode; reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode; reload_reg_rtx[t_reload] = 0; reload_optional[t_reload] = optional; reload_inc[t_reload] = 0; /* Maybe we could combine these, but it seems too tricky. */ reload_nocombine[t_reload] = 1; reload_in_reg[t_reload] = 0; reload_opnum[t_reload] = opnum; reload_when_needed[t_reload] = secondary_type; reload_secondary_in_reload[t_reload] = -1; reload_secondary_out_reload[t_reload] = -1; reload_secondary_in_icode[t_reload] = CODE_FOR_nothing; reload_secondary_out_icode[t_reload] = CODE_FOR_nothing; reload_secondary_p[t_reload] = 1; n_reloads++; } } /* See if we can reuse an existing secondary reload. */ for (s_reload = 0; s_reload < n_reloads; s_reload++) if (reload_secondary_p[s_reload] && (reg_class_subset_p (class, reload_reg_class[s_reload]) || reg_class_subset_p (reload_reg_class[s_reload], class)) && ((in_p && reload_inmode[s_reload] == mode) || (! in_p && reload_outmode[s_reload] == mode)) && ((in_p && reload_secondary_in_reload[s_reload] == t_reload) || (! in_p && reload_secondary_out_reload[s_reload] == t_reload)) && ((in_p && reload_secondary_in_icode[s_reload] == t_icode) || (! in_p && reload_secondary_out_icode[s_reload] == t_icode)) && (reg_class_size[(int) class] == 1#ifdef SMALL_REGISTER_CLASSES || 1#endif ) && MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload], opnum, reload_opnum[s_reload])) { if (in_p) reload_inmode[s_reload] = mode; if (! in_p) reload_outmode[s_reload] = mode; if (reg_class_subset_p (class, reload_reg_class[s_reload])) reload_reg_class[s_reload] = class; reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum); reload_optional[s_reload] &= optional; reload_secondary_p[s_reload] = 1; if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload], opnum, reload_opnum[s_reload])) reload_when_needed[s_reload] = RELOAD_OTHER; } if (s_reload == n_reloads) { /* We need to make a new secondary reload for this register class. */ reload_in[s_reload] = reload_out[s_reload] = 0; reload_reg_class[s_reload] = class; reload_inmode[s_reload] = in_p ? mode : VOIDmode; reload_outmode[s_reload] = ! in_p ? mode : VOIDmode; reload_reg_rtx[s_reload] = 0; reload_optional[s_reload] = optional; reload_inc[s_reload] = 0; /* Maybe we could combine these, but it seems too tricky. */ reload_nocombine[s_reload] = 1; reload_in_reg[s_reload] = 0; reload_opnum[s_reload] = opnum; reload_when_needed[s_reload] = secondary_type; reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1; reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1; reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing; reload_secondary_out_icode[s_reload] = ! in_p ? t_icode : CODE_FOR_nothing; reload_secondary_p[s_reload] = 1; n_reloads++;#ifdef SECONDARY_MEMORY_NEEDED /* If we need a memory location to copy between the two reload regs, set it up now. */ if (in_p && icode == CODE_FOR_nothing && SECONDARY_MEMORY_NEEDED (class, reload_class, reload_mode)) get_secondary_mem (x, reload_mode, opnum, type); if (! in_p && icode == CODE_FOR_nothing && SECONDARY_MEMORY_NEEDED (reload_class, class, reload_mode)) get_secondary_mem (x, reload_mode, opnum, type);#endif } *picode = icode; return s_reload;}#endif /* HAVE_SECONDARY_RELOADS */#ifdef SECONDARY_MEMORY_NEEDED/* Return a memory location that will be used to copy X in mode MODE. If we haven't already made a location for this mode in this insn, call find_reloads_address on the location being returned. */rtxget_secondary_mem (x, mode, opnum, type) rtx x; enum machine_mode mode; int opnum; enum reload_type type;{ rtx loc; int mem_valid; /* By default, if MODE is narrower than a word, widen it to a word. This is required because most machines that require these memory locations do not support short load and stores from all registers (e.g., FP registers). */#ifdef SECONDARY_MEMORY_NEEDED_MODE mode = SECONDARY_MEMORY_NEEDED_MODE (mode);#else if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD) mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);#endif /* If we already have made a MEM for this operand in MODE, return it. */ if (secondary_memlocs_elim[(int) mode][opnum] != 0) return secondary_memlocs_elim[(int) mode][opnum]; /* If this is the first time we've tried to get a MEM for this mode, allocate a new one. `something_changed' in reload will get set by noticing that the frame size has changed. */ if (secondary_memlocs[(int) mode] == 0) {#ifdef SECONDARY_MEMORY_NEEDED_RTX secondary_memlocs[(int) mode] = SECONDARY_MEMORY_NEEDED_RTX (mode);#else secondary_memlocs[(int) mode] = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);#endif } /* Get a version of the address doing any eliminations needed. If that didn't give us a new MEM, make a new one if it isn't valid. */ loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX); mem_valid = strict_memory_address_p (mode, XEXP (loc, 0)); if (! mem_valid && loc == secondary_memlocs[(int) mode]) loc = copy_rtx (loc); /* The only time the call below will do anything is if the stack offset is too large. In that case IND_LEVELS doesn't matter, so we can just pass a zero. Adjust the type to be the address of the corresponding object. If the address was valid, save the eliminated address. If it wasn't valid, we need to make a reload each time, so don't save it. */ if (! mem_valid) { type = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS : RELOAD_OTHER); find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0), opnum, type, 0); } secondary_memlocs_elim[(int) mode][opnum] = loc; return loc;}/* Clear any secondary memory locations we've made. */voidclear_secondary_mem (){ bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);}#endif /* SECONDARY_MEMORY_NEEDED *//* Record one reload that needs to be performed. IN is an rtx saying where the data are to be found before this instruction. OUT says where they must be stored after the instruction. (IN is zero for data not read, and OUT is zero for data not written.) INLOC and OUTLOC point to the places in the instructions where IN and OUT were found. If IN and OUT are both non-zero, it means the same register must be used to reload both IN and OUT. CLASS is a register class required for the reloaded data. INMODE is the machine mode that the instruction requires for the reg that replaces IN and OUTMODE is likewise for OUT. If IN is zero, then OUT's location and mode should be passed as INLOC and INMODE.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -