📄 function.c
字号:
&& reg_mentioned_p (var, PATTERN (insn)) && reg_mentioned_p (call_dest, PATTERN (insn))) { rtx temp = gen_reg_rtx (GET_MODE (call_dest)); emit_insn_before (gen_move_insn (temp, call_dest), insn); PATTERN (insn) = replace_rtx (PATTERN (insn), call_dest, temp); } if (GET_CODE (insn) == CALL_INSN && GET_CODE (PATTERN (insn)) == SET) call_dest = SET_DEST (PATTERN (insn)); else if (GET_CODE (insn) == CALL_INSN && GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); else call_dest = 0; } /* See if we have to do anything to INSN now that VAR is in memory. If it needs to be loaded into a pseudo, use a single pseudo for the entire insn in case there is a MATCH_DUP between two operands. We pass a pointer to the head of a list of struct fixup_replacements. If fixup_var_refs_1 needs to allocate pseudos or replacement MEMs (for SUBREGs), it will record them in this list. If it allocated a pseudo for any replacement, we copy into it here. */ fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn, &replacements); /* If this is last_parm_insn, and any instructions were output after it to fix it up, then we must set last_parm_insn to the last such instruction emitted. */ if (insn == last_parm_insn) last_parm_insn = PREV_INSN (next_insn); while (replacements) { if (GET_CODE (replacements->new) == REG) { rtx insert_before; rtx seq; /* OLD might be a (subreg (mem)). */ if (GET_CODE (replacements->old) == SUBREG) replacements->old = fixup_memory_subreg (replacements->old, insn, 0); else replacements->old = fixup_stack_1 (replacements->old, insn); insert_before = insn; /* If we are changing the mode, do a conversion. This might be wasteful, but combine.c will eliminate much of the waste. */ if (GET_MODE (replacements->new) != GET_MODE (replacements->old)) { start_sequence (); convert_move (replacements->new, replacements->old, unsignedp); seq = gen_sequence (); end_sequence (); } else seq = gen_move_insn (replacements->new, replacements->old); emit_insn_before (seq, insert_before); } replacements = replacements->next; } } /* Also fix up any invalid exprs in the REG_NOTES of this insn. But don't touch other insns referred to by reg-notes; we will get them elsewhere. */ for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) if (GET_CODE (note) != INSN_LIST) XEXP (note, 0) = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1); } insn = next; }}/* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE. See if the rtx expression at *LOC in INSN needs to be changed. REPLACEMENTS is a pointer to a list head that starts out zero, but may contain a list of original rtx's and replacements. If we find that we need to modify this insn by replacing a memory reference with a pseudo or by making a new MEM to implement a SUBREG, we consult that list to see if we have already chosen a replacement. If none has already been allocated, we allocate it and update the list. fixup_var_refs_insns will copy VAR or the SUBREG, as appropriate, to the pseudo. */static voidfixup_var_refs_1 (var, promoted_mode, loc, insn, replacements) register rtx var; enum machine_mode promoted_mode; register rtx *loc; rtx insn; struct fixup_replacement **replacements;{ register int i; register rtx x = *loc; RTX_CODE code = GET_CODE (x); register char *fmt; register rtx tem, tem1; struct fixup_replacement *replacement; switch (code) { case ADDRESSOF: if (XEXP (x, 0) == var) { /* Prevent sharing of rtl that might lose. */ rtx sub = copy_rtx (XEXP (var, 0)); start_sequence (); if (! validate_change (insn, loc, sub, 0)) { rtx y = force_operand (sub, NULL_RTX); if (! validate_change (insn, loc, y, 0)) *loc = copy_to_reg (y); } emit_insn_before (gen_sequence (), insn); end_sequence (); } return; case MEM: if (var == x) { /* If we already have a replacement, use it. Otherwise, try to fix up this address in case it is invalid. */ replacement = find_fixup_replacement (replacements, var); if (replacement->new) { *loc = replacement->new; return; } *loc = replacement->new = x = fixup_stack_1 (x, insn); /* Unless we are forcing memory to register or we changed the mode, we can leave things the way they are if the insn is valid. */ INSN_CODE (insn) = -1; if (! flag_force_mem && GET_MODE (x) == promoted_mode && recog_memoized (insn) >= 0) return; *loc = replacement->new = gen_reg_rtx (promoted_mode); return; } /* If X contains VAR, we need to unshare it here so that we update each occurrence separately. But all identical MEMs in one insn must be replaced with the same rtx because of the possibility of MATCH_DUPs. */ if (reg_mentioned_p (var, x)) { replacement = find_fixup_replacement (replacements, x); if (replacement->new == 0) replacement->new = copy_most_rtx (x, var); *loc = x = replacement->new; } break; case REG: case CC0: case PC: case CONST_INT: case CONST: case SYMBOL_REF: case LABEL_REF: case CONST_DOUBLE: return; case SIGN_EXTRACT: case ZERO_EXTRACT: /* Note that in some cases those types of expressions are altered by optimize_bit_field, and do not survive to get here. */ if (XEXP (x, 0) == var || (GET_CODE (XEXP (x, 0)) == SUBREG && SUBREG_REG (XEXP (x, 0)) == var)) { /* Get TEM as a valid MEM in the mode presently in the insn. We don't worry about the possibility of MATCH_DUP here; it is highly unlikely and would be tricky to handle. */ tem = XEXP (x, 0); if (GET_CODE (tem) == SUBREG) { if (GET_MODE_BITSIZE (GET_MODE (tem)) > GET_MODE_BITSIZE (GET_MODE (var))) { replacement = find_fixup_replacement (replacements, var); if (replacement->new == 0) replacement->new = gen_reg_rtx (GET_MODE (var)); SUBREG_REG (tem) = replacement->new; } else tem = fixup_memory_subreg (tem, insn, 0); } else tem = fixup_stack_1 (tem, insn); /* Unless we want to load from memory, get TEM into the proper mode for an extract from memory. This can only be done if the extract is at a constant position and length. */ if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT && GET_CODE (XEXP (x, 2)) == CONST_INT && ! mode_dependent_address_p (XEXP (tem, 0)) && ! MEM_VOLATILE_P (tem)) { enum machine_mode wanted_mode = VOIDmode; enum machine_mode is_mode = GET_MODE (tem); int width = INTVAL (XEXP (x, 1)); int pos = INTVAL (XEXP (x, 2));#ifdef HAVE_extzv if (GET_CODE (x) == ZERO_EXTRACT) wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];#endif#ifdef HAVE_extv if (GET_CODE (x) == SIGN_EXTRACT) wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];#endif /* If we have a narrower mode, we can do something. */ if (wanted_mode != VOIDmode && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode)) { int offset = pos / BITS_PER_UNIT; rtx old_pos = XEXP (x, 2); rtx newmem; /* If the bytes and bits are counted differently, we must adjust the offset. */ if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN) offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode) - offset); pos %= GET_MODE_BITSIZE (wanted_mode); newmem = gen_rtx (MEM, wanted_mode, plus_constant (XEXP (tem, 0), offset)); RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem); MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem); MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem); /* Make the change and see if the insn remains valid. */ INSN_CODE (insn) = -1; XEXP (x, 0) = newmem; XEXP (x, 2) = GEN_INT (pos); if (recog_memoized (insn) >= 0) return; /* Otherwise, restore old position. XEXP (x, 0) will be restored later. */ XEXP (x, 2) = old_pos; } } /* If we get here, the bitfield extract insn can't accept a memory reference. Copy the input into a register. */ tem1 = gen_reg_rtx (GET_MODE (tem)); emit_insn_before (gen_move_insn (tem1, tem), insn); XEXP (x, 0) = tem1; return; } break; case SUBREG: if (SUBREG_REG (x) == var) { /* If this is a special SUBREG made because VAR was promoted from a wider mode, replace it with VAR and call ourself recursively, this time saying that the object previously had its current mode (by virtue of the SUBREG). */ if (SUBREG_PROMOTED_VAR_P (x)) { *loc = var; fixup_var_refs_1 (var, GET_MODE (var), loc, insn, replacements); return; } /* If this SUBREG makes VAR wider, it has become a paradoxical SUBREG with VAR in memory, but these aren't allowed at this stage of the compilation. So load VAR into a pseudo and take a SUBREG of that pseudo. */ if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (var))) { replacement = find_fixup_replacement (replacements, var); if (replacement->new == 0) replacement->new = gen_reg_rtx (GET_MODE (var)); SUBREG_REG (x) = replacement->new; return; } /* See if we have already found a replacement for this SUBREG. If so, use it. Otherwise, make a MEM and see if the insn is recognized. If not, or if we should force MEM into a register, make a pseudo for this SUBREG. */ replacement = find_fixup_replacement (replacements, x); if (replacement->new) { *loc = replacement->new; return; } replacement->new = *loc = fixup_memory_subreg (x, insn, 0); INSN_CODE (insn) = -1; if (! flag_force_mem && recog_memoized (insn) >= 0) return; *loc = replacement->new = gen_reg_rtx (GET_MODE (x)); return; } break; case SET: /* First do special simplification of bit-field references. */ if (GET_CODE (SET_DEST (x)) == SIGN_EXTRACT || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT) optimize_bit_field (x, insn, 0); if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT) optimize_bit_field (x, insn, NULL_PTR); /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object into a register and then store it back out. */ if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG && SUBREG_REG (XEXP (SET_DEST (x), 0)) == var && (GET_MODE_SIZE (GET_MODE (XEXP (SET_DEST (x), 0))) > GET_MODE_SIZE (GET_MODE (var)))) { replacement = find_fixup_replacement (replacements, var); if (replacement->new == 0) replacement->new = gen_reg_rtx (GET_MODE (var)); SUBREG_REG (XEXP (SET_DEST (x), 0)) = replacement->new; emit_insn_after (gen_move_insn (var, replacement->new), insn); } /* If SET_DEST is now a paradoxical SUBREG, put the result of this insn into a pseudo and store the low part of the pseudo into VAR. */ if (GET_CODE (SET_DEST (x)) == SUBREG && SUBREG_REG (SET_DEST (x)) == var && (GET_MODE_SIZE (GET_MODE (SET_DEST (x))) > GET_MODE_SIZE (GET_MODE (var)))) { SET_DEST (x) = tem = gen_reg_rtx (GET_MODE (SET_DEST (x))); emit_insn_after (gen_move_insn (var, gen_lowpart (GET_MODE (var), tem)), insn); break; } { rtx dest = SET_DEST (x); rtx src = SET_SRC (x); rtx outerdest = dest; while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == ZERO_EXTRACT) dest = XEXP (dest, 0); if (GET_CODE (src) == SUBREG) src = XEXP (src, 0); /* If VAR does not appear at the top level of the SET just scan the lower levels of the tree. */ if (src != var && dest != var) break; /* We will need to rerecognize this insn. */ INSN_CODE (insn) = -1;#ifdef HAVE_insv if (GET_CODE (outerdest) == ZERO_EXTRACT && dest == var) { /* Since this case will return, ensure we fixup
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -