📄 expr.c
字号:
abort (); if (to_mode == from_mode || (from_mode == VOIDmode && CONSTANT_P (from))) { emit_move_insn (to, from); return; } if (to_real) {#ifdef HAVE_extendsfdf2 if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode) { emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_extendsfxf2 if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode) { emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_extendsftf2 if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode) { emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_extenddfxf2 if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode) { emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_extenddftf2 if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode) { emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_truncdfsf2 if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode) { emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_truncxfsf2 if (HAVE_truncxfsf2 && from_mode == XFmode && to_mode == SFmode) { emit_unop_insn (CODE_FOR_truncxfsf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_trunctfsf2 if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode) { emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_truncxfdf2 if (HAVE_truncxfdf2 && from_mode == XFmode && to_mode == DFmode) { emit_unop_insn (CODE_FOR_truncxfdf2, to, from, UNKNOWN); return; }#endif#ifdef HAVE_trunctfdf2 if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode) { emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN); return; }#endif libcall = (rtx) 0; switch (from_mode) { case SFmode: switch (to_mode) { case DFmode: libcall = extendsfdf2_libfunc; break; case XFmode: libcall = extendsfxf2_libfunc; break; case TFmode: libcall = extendsftf2_libfunc; break; } break; case DFmode: switch (to_mode) { case SFmode: libcall = truncdfsf2_libfunc; break; case XFmode: libcall = extenddfxf2_libfunc; break; case TFmode: libcall = extenddftf2_libfunc; break; } break; case XFmode: switch (to_mode) { case SFmode: libcall = truncxfsf2_libfunc; break; case DFmode: libcall = truncxfdf2_libfunc; break; } break; case TFmode: switch (to_mode) { case SFmode: libcall = trunctfsf2_libfunc; break; case DFmode: libcall = trunctfdf2_libfunc; break; } break; } if (libcall == (rtx) 0) /* This conversion is not implemented yet. */ abort (); emit_library_call (libcall, 1, to_mode, 1, from, from_mode); emit_move_insn (to, hard_libcall_value (to_mode)); return; } /* Now both modes are integers. */ /* Handle expanding beyond a word. */ if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode) && GET_MODE_BITSIZE (to_mode) > BITS_PER_WORD) { rtx insns; rtx lowpart; rtx fill_value; rtx lowfrom; int i; enum machine_mode lowpart_mode; int nwords = CEIL (GET_MODE_SIZE (to_mode), UNITS_PER_WORD); /* Try converting directly if the insn is supported. */ if ((code = can_extend_p (to_mode, from_mode, unsignedp)) != CODE_FOR_nothing) { /* If FROM is a SUBREG, put it into a register. Do this so that we always generate the same set of insns for better cse'ing; if an intermediate assignment occurred, we won't be doing the operation directly on the SUBREG. */ if (optimize > 0 && GET_CODE (from) == SUBREG) from = force_reg (from_mode, from); emit_unop_insn (code, to, from, equiv_code); return; } /* Next, try converting via full word. */ else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD && ((code = can_extend_p (to_mode, word_mode, unsignedp)) != CODE_FOR_nothing)) { convert_move (gen_lowpart (word_mode, to), from, unsignedp); emit_unop_insn (code, to, gen_lowpart (word_mode, to), equiv_code); return; } /* No special multiword conversion insn; do it by hand. */ start_sequence (); /* Get a copy of FROM widened to a word, if necessary. */ if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD) lowpart_mode = word_mode; else lowpart_mode = from_mode; lowfrom = convert_to_mode (lowpart_mode, from, unsignedp); lowpart = gen_lowpart (lowpart_mode, to); emit_move_insn (lowpart, lowfrom); /* Compute the value to put in each remaining word. */ if (unsignedp) fill_value = const0_rtx; else {#ifdef HAVE_slt if (HAVE_slt && insn_operand_mode[(int) CODE_FOR_slt][0] == word_mode && STORE_FLAG_VALUE == -1) { emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX, lowpart_mode, 0, 0); fill_value = gen_reg_rtx (word_mode); emit_insn (gen_slt (fill_value)); } else#endif { fill_value = expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom, 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, from)); return; } if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD) { 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_truncsipsi if (HAVE_truncsipsi) { emit_unop_insn (CODE_FOR_truncsipsi, to, from, UNKNOWN); return; }#endif /* HAVE_truncsipsi */ abort (); } if (from_mode == PSImode) { if (to_mode != SImode) { from = convert_to_mode (SImode, from, unsignedp); from_mode = SImode; } else {#ifdef HAVE_extendpsisi if (HAVE_extendpsisi) { emit_unop_insn (CODE_FOR_extendpsisi, to, from, UNKNOWN); return; }#endif /* HAVE_extendpsisi */ 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)) && ((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)) { emit_move_insn (to, gen_lowpart (to_mode, from)); return; } /* For truncation, usually we can just refer to FROM in a narrower mode. */ 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) { /* If FROM is a SUBREG, put it into a register. Do this so that we always generate the same set of insns for better cse'ing; if an intermediate assignment occurred, we won't be doing the operation directly on the SUBREG. */ if (optimize > 0 && GET_CODE (from) == SUBREG) from = force_reg (from_mode, from); 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) && (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; } /* 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -