📄 expr.c
字号:
if (to_mode == SImode && from_mode == HImode) { if (unsignedp) {#ifdef HAVE_zero_extendhisi2 if (HAVE_zero_extendhisi2) emit_unop_insn (CODE_FOR_zero_extendhisi2, to, from, ZERO_EXTEND); else#endif abort (); } else {#ifdef HAVE_extendhisi2 if (HAVE_extendhisi2) emit_unop_insn (CODE_FOR_extendhisi2, to, from, SIGN_EXTEND); else#endif abort (); } return; } if (to_mode == SImode && from_mode == QImode) { if (unsignedp) {#ifdef HAVE_zero_extendqisi2 if (HAVE_zero_extendqisi2) { emit_unop_insn (CODE_FOR_zero_extendqisi2, to, from, ZERO_EXTEND); return; }#endif#if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2) if (HAVE_zero_extendqihi2 && HAVE_extendhisi2) { register rtx temp = gen_reg_rtx (HImode); emit_unop_insn (CODE_FOR_zero_extendqihi2, temp, from, ZERO_EXTEND); emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); return; }#endif } else {#ifdef HAVE_extendqisi2 if (HAVE_extendqisi2) { emit_unop_insn (CODE_FOR_extendqisi2, to, from, SIGN_EXTEND); return; }#endif#if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2) if (HAVE_extendqihi2 && HAVE_extendhisi2) { register rtx temp = gen_reg_rtx (HImode); emit_unop_insn (CODE_FOR_extendqihi2, temp, from, SIGN_EXTEND); emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); return; }#endif } abort (); } if (to_mode == HImode && from_mode == QImode) { if (unsignedp) {#ifdef HAVE_zero_extendqihi2 if (HAVE_zero_extendqihi2) { emit_unop_insn (CODE_FOR_zero_extendqihi2, to, from, ZERO_EXTEND); return; }#endif } else {#ifdef HAVE_extendqihi2 if (HAVE_extendqihi2) { emit_unop_insn (CODE_FOR_extendqihi2, to, from, SIGN_EXTEND); return; }#endif } abort (); }#if 0 /* This seems to be redundant with code 100 lines up. */ /* Now we are truncating an integer to a smaller one. If the result is a temporary, we might as well just copy it, since only the low-order part of the result needs to be valid and it is valid with no change. */ if (GET_CODE (to) == REG) { if (GET_CODE (from) == REG) { emit_move_insn (to, gen_lowpart (GET_MODE (to), from)); return; } else if (GET_CODE (from) == SUBREG) { from = copy_rtx (from); /* This is safe since FROM is not more than one word. */ PUT_MODE (from, GET_MODE (to)); emit_move_insn (to, from); return; }#ifndef BYTES_BIG_ENDIAN else if (GET_CODE (from) == MEM) { register rtx addr = XEXP (from, 0); if (memory_address_p (GET_MODE (to), addr)) { emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr)); return; } }#endif /* not BYTES_BIG_ENDIAN */ }#endif /* 0 */ if (from_mode == SImode && to_mode == HImode) {#ifdef HAVE_truncsihi2 if (HAVE_truncsihi2) { emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN); return; }#endif abort (); } if (from_mode == SImode && to_mode == QImode) {#ifdef HAVE_truncsiqi2 if (HAVE_truncsiqi2) { emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN); return; }#endif abort (); } if (from_mode == HImode && to_mode == QImode) {#ifdef HAVE_trunchiqi2 if (HAVE_trunchiqi2) { emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN); return; }#endif abort (); } /* 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. */rtxconvert_to_mode (mode, x, unsignedp) enum machine_mode mode; rtx x; int unsignedp;{ register rtx temp; if (mode == GET_MODE (x)) return x; if (integer_mode_p (mode) && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x)) && (GET_CODE (x) == REG || GET_CODE (x) == CONST_DOUBLE || (GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)))) return gen_lowpart (mode, x); temp = gen_reg_rtx (mode); convert_move (temp, x, unsignedp); return temp;}intinteger_mode_p (mode) enum machine_mode mode;{ return (int) mode > (int) VOIDmode && (int) mode <= (int) TImode;}/* 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. */struct move_by_pieces{ rtx to; rtx to_addr; int autinc_to; int explicit_inc_to; rtx from; rtx from_addr; int autinc_from; int explicit_inc_from; int len; int offset; int reverse;};static void move_by_pieces_1 ();static int move_by_pieces_ninsns ();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); 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 = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC); if (data.reverse) data.offset = len; data.len = len; /* If copying requires more than two move insns, copy addresses to registers (to make displacements shorter) and use post-increment if available. */ if (!(data.autinc_from && data.autinc_to) && move_by_pieces_ninsns (len, align) > 2) {#ifdef HAVE_PRE_DECREMENT if (data.reverse && ! data.autinc_from) { data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); data.autinc_from = 1; data.explicit_inc_from = -1; }#endif#ifdef HAVE_POST_INCREMENT if (! data.autinc_from) { data.from_addr = copy_addr_to_reg (from_addr); data.autinc_from = 1; data.explicit_inc_from = 1; }#endif if (!data.autinc_from && CONSTANT_P (from_addr)) data.from_addr = copy_addr_to_reg (from_addr);#ifdef HAVE_PRE_DECREMENT if (data.reverse && ! data.autinc_to) { data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); data.autinc_to = 1; data.explicit_inc_to = -1; }#endif#ifdef HAVE_POST_INCREMENT if (! data.reverse && ! data.autinc_to) { data.to_addr = copy_addr_to_reg (to_addr); data.autinc_to = 1; data.explicit_inc_to = 1; }#endif if (!data.autinc_to && CONSTANT_P (to_addr)) data.to_addr = copy_addr_to_reg (to_addr); }#ifdef STRICT_ALIGNMENT if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) align = MOVE_MAX;#else align = MOVE_MAX;#endif#ifdef HAVE_movti if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) move_by_pieces_1 (gen_movti, TImode, &data);#endif#ifdef HAVE_movdi if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) move_by_pieces_1 (gen_movdi, DImode, &data);#endif#ifdef HAVE_movsi if (align >= GET_MODE_SIZE (SImode)) move_by_pieces_1 (gen_movsi, SImode, &data);#endif#ifdef HAVE_movhi if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) move_by_pieces_1 (gen_movhi, HImode, &data);#endif#ifdef HAVE_movqi move_by_pieces_1 (gen_movqi, QImode, &data);#else movqi instruction required in machine description#endif}/* Return number of insns required to move L bytes by pieces. ALIGN (in bytes) is maximum alignment we can assume. */static intmove_by_pieces_ninsns (l, align) unsigned int l; int align;{ register int n_insns = 0;#ifdef STRICT_ALIGNMENT if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) align = MOVE_MAX;#else align = MOVE_MAX;#endif#ifdef HAVE_movti if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode);#endif#ifdef HAVE_movdi if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode);#endif#ifdef HAVE_movsi if (HAVE_movsi && align >= GET_MODE_SIZE (SImode)) n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode);#endif#ifdef HAVE_movhi if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode);#endif n_insns += l; return n_insns;}/* Subroutine of move_by_pieces. Move as many bytes as appropriate with move instructions for mode MODE. GENFUN is the gen_... function to make a move insn for that mode. DATA has all the other info. */static voidmove_by_pieces_1 (genfun, mode, data) rtx (*genfun) (); enum machine_mode mode; struct move_by_pieces *data;{ register int size = GET_MODE_SIZE (mode); register rtx to1, from1; while (data->len >= size) { if (data->reverse) data->offset -= size; to1 = (data->autinc_to ? gen_rtx (MEM, mode, data->to_addr) : change_address (data->to, mode, plus_constant (data->to_addr, data->offset))); from1 = (data->autinc_from ? gen_rtx (MEM, mode, data->from_addr) : change_address (data->from, mode, plus_constant (data->from_addr, data->offset)));#ifdef HAVE_PRE_DECREMENT if (data->explicit_inc_to < 0) emit_insn (gen_sub2_insn (data->to_addr, gen_rtx (CONST_INT, VOIDmode, size))); if (data->explicit_inc_from < 0) emit_insn (gen_sub2_insn (data->from_addr, gen_rtx (CONST_INT, VOIDmode, size)));#endif emit_insn ((*genfun) (to1, from1));#ifdef HAVE_POST_INCREMENT if (data->explicit_inc_to > 0) emit_insn (gen_add2_insn (data->to_addr, gen_rtx (CONST_INT, VOIDmode, size))); if (data->explicit_inc_from > 0) emit_insn (gen_add2_insn (data->from_addr, gen_rtx (CONST_INT, VOIDmode, size)));#endif if (! data->reverse) data->offset += size; data->len -= size; }}/* Emit code to move a block Y to a block X. This may be done with string-move instructions, with multiple scalar move instructions, or with a library call. Both X and Y must be MEM rtx's (perhaps inside VOLATILE) with mode BLKmode. SIZE is an rtx that says how long they are. ALIGN is the maximum alignment we can assume they have, measured in bytes. */static voidemit_block_move (x, y, size, align) rtx x, y; rtx size; int align;{ if (GET_MODE (x) != BLKmode) abort (); if (GET_MODE (y) != BLKmode) abort (); x = protect_from_queue (x, 1); y = protect_from_queue (y, 0); if (GET_CODE (x) != MEM) abort (); if (GET_CODE (y) != MEM) abort (); if (size == 0) abort (); if (GET_CODE (size) == CONST_INT && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) < MOVE_RATIO)) move_by_pieces (x, y, INTVAL (size), align); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -