📄 function.c
字号:
{ /* 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) tem = fixup_memory_subreg (tem, insn, 1); 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); /* 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 all the operands here. */ fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 1), insn, replacements); fixup_var_refs_1 (var, promoted_mode, &XEXP (outerdest, 2), insn, replacements); fixup_var_refs_1 (var, promoted_mode, &SET_SRC (x), insn, replacements); tem = XEXP (outerdest, 0); /* Clean up (SUBREG:SI (MEM:mode ...) 0) that may appear inside a ZERO_EXTRACT. This was legitimate when the MEM was a REG. */ if (GET_CODE (tem) == SUBREG && SUBREG_REG (tem) == var) tem = fixup_memory_subreg (tem, insn, 1); else tem = fixup_stack_1 (tem, insn); if (GET_CODE (XEXP (outerdest, 1)) == CONST_INT && GET_CODE (XEXP (outerdest, 2)) == CONST_INT && ! mode_dependent_address_p (XEXP (tem, 0)) && ! MEM_VOLATILE_P (tem)) { enum machine_mode wanted_mode = insn_operand_mode[(int) CODE_FOR_insv][0]; enum machine_mode is_mode = GET_MODE (tem); int width = INTVAL (XEXP (outerdest, 1)); int pos = INTVAL (XEXP (outerdest, 2)); /* If we have a narrower mode, we can do something. */ if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode)) { int offset = pos / BITS_PER_UNIT; rtx old_pos = XEXP (outerdest, 2); rtx newmem; 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 (outerdest, 0) = newmem; XEXP (outerdest, 2) = GEN_INT (pos); if (recog_memoized (insn) >= 0) return; /* Otherwise, restore old position. XEXP (x, 0) will be restored later. */ XEXP (outerdest, 2) = old_pos; } } /* If we get here, the bit-field store doesn't allow memory or isn't located at a constant position. Load the value into a register, do the store, and put it back into memory. */ tem1 = gen_reg_rtx (GET_MODE (tem)); emit_insn_before (gen_move_insn (tem1, tem), insn); emit_insn_after (gen_move_insn (tem, tem1), insn); XEXP (outerdest, 0) = tem1; return; }#endif /* STRICT_LOW_PART is a no-op on memory references and it can cause combinations to be unrecognizable, so eliminate it. */ if (dest == var && GET_CODE (SET_DEST (x)) == STRICT_LOW_PART) SET_DEST (x) = XEXP (SET_DEST (x), 0); /* A valid insn to copy VAR into or out of a register must be left alone, to avoid an infinite loop here. If the reference to VAR is by a subreg, fix that up, since SUBREG is not valid for a memref. Also fix up the address of the stack slot. Note that we must not try to recognize the insn until after we know that we have valid addresses and no (subreg (mem ...) ...) constructs, since these interfere with determining the validity of the insn. */ if ((SET_SRC (x) == var || (GET_CODE (SET_SRC (x)) == SUBREG && SUBREG_REG (SET_SRC (x)) == var)) && (GET_CODE (SET_DEST (x)) == REG || (GET_CODE (SET_DEST (x)) == SUBREG && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG)) && x == single_set (PATTERN (insn))) { rtx pat; replacement = find_fixup_replacement (replacements, SET_SRC (x)); if (replacement->new) SET_SRC (x) = replacement->new; else if (GET_CODE (SET_SRC (x)) == SUBREG) SET_SRC (x) = replacement->new = fixup_memory_subreg (SET_SRC (x), insn, 0); else SET_SRC (x) = replacement->new = fixup_stack_1 (SET_SRC (x), insn); if (recog_memoized (insn) >= 0) return; /* INSN is not valid, but we know that we want to copy SET_SRC (x) to SET_DEST (x) in some way. So we generate the move and see whether it requires more than one insn. If it does, we emit those insns and delete INSN. Otherwise, we an just replace the pattern of INSN; we have already verified above that INSN has no other function that to do X. */ pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); if (GET_CODE (pat) == SEQUENCE) { emit_insn_after (pat, insn); PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; } else PATTERN (insn) = pat; return; } if ((SET_DEST (x) == var || (GET_CODE (SET_DEST (x)) == SUBREG && SUBREG_REG (SET_DEST (x)) == var)) && (GET_CODE (SET_SRC (x)) == REG || (GET_CODE (SET_SRC (x)) == SUBREG && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG)) && x == single_set (PATTERN (insn))) { rtx pat; if (GET_CODE (SET_DEST (x)) == SUBREG) SET_DEST (x) = fixup_memory_subreg (SET_DEST (x), insn, 0); else SET_DEST (x) = fixup_stack_1 (SET_DEST (x), insn); if (recog_memoized (insn) >= 0) return; pat = gen_move_insn (SET_DEST (x), SET_SRC (x)); if (GET_CODE (pat) == SEQUENCE) { emit_insn_after (pat, insn); PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; } else PATTERN (insn) = pat; return; } /* Otherwise, storing into VAR must be hand
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -