📄 expr.c
字号:
size_int (GET_MODE_BITSIZE (lowpart_mode) - 1), NULL_RTX, 0); fill_value = convert_to_mode (word_mode, fill_value, 1); } } /* Fill the remaining words. */ for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++) { int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); rtx subword = operand_subword (to, index, 1, to_mode); if (subword == 0) abort (); if (fill_value != subword) emit_move_insn (subword, fill_value); } insns = get_insns (); end_sequence (); emit_no_conflict_block (insns, to, from, NULL_RTX, gen_rtx (equiv_code, to_mode, copy_rtx (from))); return; } /* Truncating multi-word to a word or less. */ if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD && GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD) { if (!((GET_CODE (from) == MEM && ! MEM_VOLATILE_P (from) && direct_load[(int) to_mode] && ! mode_dependent_address_p (XEXP (from, 0))) || GET_CODE (from) == REG || GET_CODE (from) == SUBREG)) from = force_reg (from_mode, from); convert_move (to, gen_lowpart (word_mode, from), 0); return; } /* Handle pointer conversion */ /* SPEE 900220 */ if (to_mode == PSImode) { if (from_mode != SImode) from = convert_to_mode (SImode, from, unsignedp);#ifdef HAVE_truncsipsi2 if (HAVE_truncsipsi2) { emit_unop_insn (CODE_FOR_truncsipsi2, to, from, UNKNOWN); return; }#endif /* HAVE_truncsipsi2 */ abort (); } if (from_mode == PSImode) { if (to_mode != SImode) { from = convert_to_mode (SImode, from, unsignedp); from_mode = SImode; } else {#ifdef HAVE_extendpsisi2 if (HAVE_extendpsisi2) { emit_unop_insn (CODE_FOR_extendpsisi2, to, from, UNKNOWN); return; }#endif /* HAVE_extendpsisi2 */ abort (); } } if (to_mode == PDImode) { if (from_mode != DImode) from = convert_to_mode (DImode, from, unsignedp);#ifdef HAVE_truncdipdi2 if (HAVE_truncdipdi2) { emit_unop_insn (CODE_FOR_truncdipdi2, to, from, UNKNOWN); return; }#endif /* HAVE_truncdipdi2 */ abort (); } if (from_mode == PDImode) { if (to_mode != DImode) { from = convert_to_mode (DImode, from, unsignedp); from_mode = DImode; } else {#ifdef HAVE_extendpdidi2 if (HAVE_extendpdidi2) { emit_unop_insn (CODE_FOR_extendpdidi2, to, from, UNKNOWN); return; }#endif /* HAVE_extendpdidi2 */ abort (); } } /* Now follow all the conversions between integers no more than a word long. */ /* For truncation, usually we can just refer to FROM in a narrower mode. */ if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode) && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode), GET_MODE_BITSIZE (from_mode))) { if (!((GET_CODE (from) == MEM && ! MEM_VOLATILE_P (from) && direct_load[(int) to_mode] && ! mode_dependent_address_p (XEXP (from, 0))) || GET_CODE (from) == REG || GET_CODE (from) == SUBREG)) from = force_reg (from_mode, from); if (GET_CODE (from) == REG && REGNO (from) < FIRST_PSEUDO_REGISTER && ! HARD_REGNO_MODE_OK (REGNO (from), to_mode)) from = copy_to_reg (from); emit_move_insn (to, gen_lowpart (to_mode, from)); return; } /* Handle extension. */ if (GET_MODE_BITSIZE (to_mode) > GET_MODE_BITSIZE (from_mode)) { /* Convert directly if that works. */ if ((code = can_extend_p (to_mode, from_mode, unsignedp)) != CODE_FOR_nothing) { emit_unop_insn (code, to, from, equiv_code); return; } else { enum machine_mode intermediate; /* Search for a mode to convert via. */ for (intermediate = from_mode; intermediate != VOIDmode; intermediate = GET_MODE_WIDER_MODE (intermediate)) if (((can_extend_p (to_mode, intermediate, unsignedp) != CODE_FOR_nothing) || (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (intermediate) && TRULY_NOOP_TRUNCATION (to_mode, intermediate))) && (can_extend_p (intermediate, from_mode, unsignedp) != CODE_FOR_nothing)) { convert_move (to, convert_to_mode (intermediate, from, unsignedp), unsignedp); return; } /* No suitable intermediate mode. */ abort (); } } /* Support special truncate insns for certain modes. */ if (from_mode == DImode && to_mode == SImode) {#ifdef HAVE_truncdisi2 if (HAVE_truncdisi2) { emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == DImode && to_mode == HImode) {#ifdef HAVE_truncdihi2 if (HAVE_truncdihi2) { emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == DImode && to_mode == QImode) {#ifdef HAVE_truncdiqi2 if (HAVE_truncdiqi2) { emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == SImode && to_mode == HImode) {#ifdef HAVE_truncsihi2 if (HAVE_truncsihi2) { emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == SImode && to_mode == QImode) {#ifdef HAVE_truncsiqi2 if (HAVE_truncsiqi2) { emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == HImode && to_mode == QImode) {#ifdef HAVE_trunchiqi2 if (HAVE_trunchiqi2) { emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == TImode && to_mode == DImode) {#ifdef HAVE_trunctidi2 if (HAVE_trunctidi2) { emit_unop_insn (CODE_FOR_trunctidi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == TImode && to_mode == SImode) {#ifdef HAVE_trunctisi2 if (HAVE_trunctisi2) { emit_unop_insn (CODE_FOR_trunctisi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == TImode && to_mode == HImode) {#ifdef HAVE_trunctihi2 if (HAVE_trunctihi2) { emit_unop_insn (CODE_FOR_trunctihi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } if (from_mode == TImode && to_mode == QImode) {#ifdef HAVE_trunctiqi2 if (HAVE_trunctiqi2) { emit_unop_insn (CODE_FOR_trunctiqi2, to, from, UNKNOWN); return; }#endif convert_move (to, force_reg (from_mode, from), unsignedp); return; } /* Handle truncation of volatile memrefs, and so on; the things that couldn't be truncated directly, and for which there was no special instruction. */ if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)) { rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from)); emit_move_insn (to, temp); return; } /* Mode combination is not recognized. */ abort ();}/* Return an rtx for a value that would result from converting X to mode MODE. Both X and MODE may be floating, or both integer. UNSIGNEDP is nonzero if X is an unsigned value. This can be done by referring to a part of X in place or by copying to a new temporary with conversion. This function *must not* call protect_from_queue except when putting X into an insn (in which case convert_move does it). */rtxconvert_to_mode (mode, x, unsignedp) enum machine_mode mode; rtx x; int unsignedp;{ return convert_modes (mode, VOIDmode, x, unsignedp);}/* Return an rtx for a value that would result from converting X from mode OLDMODE to mode MODE. Both modes may be floating, or both integer. UNSIGNEDP is nonzero if X is an unsigned value. This can be done by referring to a part of X in place or by copying to a new temporary with conversion. You can give VOIDmode for OLDMODE, if you are sure X has a nonvoid mode. This function *must not* call protect_from_queue except when putting X into an insn (in which case convert_move does it). */rtxconvert_modes (mode, oldmode, x, unsignedp) enum machine_mode mode, oldmode; rtx x; int unsignedp;{ register rtx temp; /* If FROM is a SUBREG that indicates that we have already done at least the required extension, strip it. */ if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x) && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) >= GET_MODE_SIZE (mode) && SUBREG_PROMOTED_UNSIGNED_P (x) == unsignedp) x = gen_lowpart (mode, x); if (GET_MODE (x) != VOIDmode) oldmode = GET_MODE (x); if (mode == oldmode) return x; /* There is one case that we must handle specially: If we are converting a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and we are to interpret the constant as unsigned, gen_lowpart will do the wrong if the constant appears negative. What we want to do is make the high-order word of the constant zero, not all ones. */ if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT && GET_CODE (x) == CONST_INT && INTVAL (x) < 0) { HOST_WIDE_INT val = INTVAL (x); if (oldmode != VOIDmode && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode)) { int width = GET_MODE_BITSIZE (oldmode); /* We need to zero extend VAL. */ val &= ((HOST_WIDE_INT) 1 << width) - 1; } return immed_double_const (val, (HOST_WIDE_INT) 0, mode); } /* We can do this with a gen_lowpart if both desired and current modes are integer, and this is either a constant integer, a register, or a non-volatile MEM. Except for the constant case where MODE is no wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand. */ if ((GET_CODE (x) == CONST_INT && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) || (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_CLASS (oldmode) == MODE_INT && (GET_CODE (x) == CONST_DOUBLE || (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode) && ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x) && direct_load[(int) mode]) || (GET_CODE (x) == REG && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), GET_MODE_BITSIZE (GET_MODE (x))))))))) { /* ?? If we don't know OLDMODE, we have to assume here that X does not need sign- or zero-extension. This may not be the case, but it's the best we can do. */ if (GET_CODE (x) == CONST_INT && oldmode != VOIDmode && GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode)) { HOST_WIDE_INT val = INTVAL (x); int width = GET_MODE_BITSIZE (oldmode); /* We must sign or zero-extend in this case. Start by zero-extending, then sign extend if we need to. */ val &= ((HOST_WIDE_INT) 1 << width) - 1; if (! unsignedp && (val & ((HOST_WIDE_INT) 1 << (width - 1)))) val |= (HOST_WIDE_INT) (-1) << width; return GEN_INT (val); } return gen_lowpart (mode, x); } temp = gen_reg_rtx (mode); convert_move (temp, x, unsignedp); return temp;}/* Generate several move instructions to copy LEN bytes from block FROM to block TO. (These are MEM rtx's with BLKmode). The caller must pass FROM and TO through protect_from_queue before calling. ALIGN (in bytes) is maximum alignment we can assume. */static voidmove_by_pieces (to, from, len, align) rtx to, from; int len, align;{ struct move_by_pieces data; rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0); int max_size = MOVE_MAX + 1; data.offset = 0; data.to_addr = to_addr; data.from_addr = from_addr; data.to = to; data.from = from; data.autinc_to = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC); data.autinc_from = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC || GET_CODE (from_addr) == POST_INC || GET_CODE (from_addr) == POST_DEC); data.explicit_inc_from = 0; data.explicit_inc_to = 0; data.reverse
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -