📄 function.c
字号:
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);#endif 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); 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);#endif 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. */ 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)) && recog_memoized (insn) >= 0) { replacement = find_fixup_replacement (replacements, SET_SRC (x)); if (replacement->new) { SET_SRC (x) = replacement->new; return; } 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); 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)) && recog_memoized (insn) >= 0) { 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); return; } /* Otherwise, storing into VAR must be handled specially by storing into a temporary and copying that into VAR with a new insn after this one. Note that this case will be used when storing into a promoted scalar since the insn will now have different modes on the input and output and hence will be invalid (except for the case of setting it to a constant, which does not need any change if it is valid). We generate extra code in that case, but combine.c will eliminate it. */ if (dest == var) { rtx temp; rtx fixeddest = SET_DEST (x); /* STRICT_LOW_PART can be discarded, around a MEM. */ if (GET_CODE (fixeddest) == STRICT_LOW_PART) fixeddest = XEXP (fixeddest, 0); /* Convert (SUBREG (MEM)) to a MEM in a changed mode. */ if (GET_CODE (fixeddest) == SUBREG) fixeddest = fixup_memory_subreg (fixeddest, insn, 0); else fixeddest = fixup_stack_1 (fixeddest, insn); temp = gen_reg_rtx (GET_MODE (SET_SRC (x)) == VOIDmode ? GET_MODE (fixeddest) : GET_MODE (SET_SRC (x))); emit_insn_after (gen_move_insn (fixeddest, gen_lowpart (GET_MODE (fixeddest), temp)), insn); SET_DEST (x) = temp; } } } /* Nothing special about this RTX; fix its operands. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') fixup_var_refs_1 (var, promoted_mode, &XEXP (x, i), insn, replacements); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) fixup_var_refs_1 (var, promoted_mode, &XVECEXP (x, i, j), insn, replacements); } }}/* Given X, an rtx of the form (SUBREG:m1 (MEM:m2 addr)), return an rtx (MEM:m1 newaddr) which is equivalent. If any insns must be emitted to compute NEWADDR, put them before INSN. UNCRITICAL nonzero means accept paradoxical subregs. This is used for subregs found inside of ZERO_EXTRACTs. */static rtxfixup_memory_subreg (x, insn, uncritical) rtx x; rtx insn; int uncritical;{ int offset = SUBREG_WORD (x) * UNITS_PER_WORD; rtx addr = XEXP (SUBREG_REG (x), 0); enum machine_mode mode = GET_MODE (x); rtx saved, result; /* Paradoxical SUBREGs are usually invalid during RTL generation. */ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) && ! uncritical) abort ();#if BYTES_BIG_ENDIAN offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));#endif addr = plus_constant (addr, offset); if (!flag_force_addr && memory_address_p (mode, addr)) /* Shortcut if no insns need be emitted. */ return change_address (SUBREG_REG (x), mode, addr); start_sequence (); result = change_address (SUBREG_REG (x), mode, addr); emit_insn_before (gen_sequence (), insn); end_sequence (); return result;}/* Do fixup_memory_subreg on all (SUBREG (MEM ...) ...) contained in X. Replace subexpressions of X in place. If X itself is a (SUBREG (MEM ...) ...), return the replacement expression. Otherwise return X, with its contents possibly altered. If any insns must be emitted to compute NEWADDR, put them before INSN. */static rtxwalk_fixup_memory_subreg (x, insn) register rtx x; rtx insn;{ register enum rtx_code code; register char *fmt; register int i; if (x == 0) return 0; code = GET_CODE (x); if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM) return fixup_memory_subreg (x, insn, 0); /* Nothing special about this RTX; fix its operands. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') XEXP (x, i) = walk_fixup_memory_subreg (XEXP (x, i), insn); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) = walk_fixup_memory_subreg (XVECEXP (x, i, j), insn); } } return x;}#if 0/* Fix up any references to stack slots that are invalid memory addresses because they exceed the maximum range of a displacement. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -