reload.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,737 行 · 第 1/5 页
C
1,737 行
static intpush_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode, type, picode) int in_p; rtx x; int opnum; int optional; enum reg_class reload_class; enum machine_mode reload_mode; enum reload_type type; enum insn_code *picode;{ enum reg_class class = NO_REGS; enum machine_mode mode = reload_mode; enum insn_code icode = CODE_FOR_nothing; enum reg_class t_class = NO_REGS; enum machine_mode t_mode = VOIDmode; enum insn_code t_icode = CODE_FOR_nothing; enum reload_type secondary_type; int i; int s_reload, t_reload = -1; if (type == RELOAD_FOR_INPUT_ADDRESS || type == RELOAD_FOR_OUTPUT_ADDRESS || type == RELOAD_FOR_INPADDR_ADDRESS || type == RELOAD_FOR_OUTADDR_ADDRESS) 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 || SMALL_REGISTER_CLASSES) && 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 || SMALL_REGISTER_CLASSES) && 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) {#ifdef SECONDARY_MEMORY_NEEDED /* If we need a memory location to copy between the two reload regs, set it up now. Note that we do the input case before making the reload and the output case after. This is due to the way reloads are output. */ if (in_p && icode == CODE_FOR_nothing && SECONDARY_MEMORY_NEEDED (class, reload_class, mode)) get_secondary_mem (x, reload_mode, opnum, type);#endif /* 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 (! in_p && icode == CODE_FOR_nothing && SECONDARY_MEMORY_NEEDED (reload_class, class, mode)) get_secondary_mem (x, 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, 0); 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, 0); } secondary_memlocs_elim[(int) mode][opnum] = loc;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?