📄 emit-rtl.c
字号:
return SUBREG_WORD (x) == 0;}/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value, return an rtx (MEM, SUBREG, or CONST_INT) that refers to the least-significant part of X. MODE specifies how big a part of X to return; it usually should not be larger than a word. If X is a MEM whose address is a QUEUED, the value may be so also. */rtxgen_lowpart (mode, x) enum machine_mode mode; register rtx x;{ rtx result = gen_lowpart_common (mode, x); if (result) return result; else if (GET_CODE (x) == REG) { /* Must be a hard reg that's not valid in MODE. */ result = gen_lowpart_common (mode, copy_to_reg (x)); if (result == 0) abort (); return result; } else if (GET_CODE (x) == MEM) { /* The only additional case we can do is MEM. */ register int offset = 0; if (WORDS_BIG_ENDIAN) offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); if (BYTES_BIG_ENDIAN) /* Adjust the address so that the address-after-the-data is unchanged. */ offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); } else if (GET_CODE (x) == ADDRESSOF) return gen_lowpart (mode, force_reg (GET_MODE (x), x)); else abort ();}/* Like `gen_lowpart', but refer to the most significant part. This is used to access the imaginary part of a complex number. */rtxgen_highpart (mode, x) enum machine_mode mode; register rtx x;{ /* This case loses if X is a subreg. To catch bugs early, complain if an invalid MODE is used even in other cases. */ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD && GET_MODE_SIZE (mode) != GET_MODE_UNIT_SIZE (GET_MODE (x))) abort (); if (GET_CODE (x) == CONST_DOUBLE#if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE)) && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT#endif ) return gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode)); else if (GET_CODE (x) == CONST_INT) return const0_rtx; else if (GET_CODE (x) == MEM) { register int offset = 0; if (! WORDS_BIG_ENDIAN) offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); if (! BYTES_BIG_ENDIAN && GET_MODE_SIZE (mode) < UNITS_PER_WORD) offset -= (GET_MODE_SIZE (mode) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); } else if (GET_CODE (x) == SUBREG) { /* The only time this should occur is when we are looking at a multi-word item with a SUBREG whose mode is the same as that of the item. It isn't clear what we would do if it wasn't. */ if (SUBREG_WORD (x) != 0) abort (); return gen_highpart (mode, SUBREG_REG (x)); } else if (GET_CODE (x) == REG) { int word = 0; if (! WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) word = ((GET_MODE_SIZE (GET_MODE (x)) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) / UNITS_PER_WORD); /* * ??? This fails miserably for complex values being passed in registers * where the sizeof the real and imaginary part are not equal to the * sizeof SImode. FIXME */ if (REGNO (x) < FIRST_PSEUDO_REGISTER /* integrate.c can't handle parts of a return value register. */ && (! REG_FUNCTION_VALUE_P (x) || ! rtx_equal_function_value_matters) /* We want to keep the stack, frame, and arg pointers special. */ && x != frame_pointer_rtx#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && x != arg_pointer_rtx#endif && x != stack_pointer_rtx) return gen_rtx (REG, mode, REGNO (x) + word); else return gen_rtx (SUBREG, mode, x, word); } else abort ();}/* Return 1 iff X, assumed to be a SUBREG, refers to the least significant part of its containing reg. If X is not a SUBREG, always return 1 (it is its own low part!). */intsubreg_lowpart_p (x) rtx x;{ if (GET_CODE (x) != SUBREG) return 1; else if (GET_MODE (SUBREG_REG (x)) == VOIDmode) return 0; if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD) return (SUBREG_WORD (x) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) - MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)) / UNITS_PER_WORD)); return SUBREG_WORD (x) == 0;}/* Return subword I of operand OP. The word number, I, is interpreted as the word number starting at the low-order address. Word 0 is the low-order word if not WORDS_BIG_ENDIAN, otherwise it is the high-order word. If we cannot extract the required word, we return zero. Otherwise, an rtx corresponding to the requested word will be returned. VALIDATE_ADDRESS is nonzero if the address should be validated. Before reload has completed, a valid address will always be returned. After reload, if a valid address cannot be returned, we return zero. If VALIDATE_ADDRESS is zero, we simply form the required address; validating it is the responsibility of the caller. MODE is the mode of OP in case it is a CONST_INT. */rtxoperand_subword (op, i, validate_address, mode) rtx op; int i; int validate_address; enum machine_mode mode;{ HOST_WIDE_INT val; int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; if (mode == VOIDmode) mode = GET_MODE (op); if (mode == VOIDmode) abort (); /* If OP is narrower than a word or if we want a word outside OP, fail. */ if (mode != BLKmode && (GET_MODE_SIZE (mode) < UNITS_PER_WORD || (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))) return 0; /* If OP is already an integer word, return it. */ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == UNITS_PER_WORD) return op; /* If OP is a REG or SUBREG, we can handle it very simply. */ if (GET_CODE (op) == REG) { /* If the register is not valid for MODE, return 0. If we don't do this, there is no way to fix up the resulting REG later. */ if (REGNO (op) < FIRST_PSEUDO_REGISTER && ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)) return 0; else if (REGNO (op) >= FIRST_PSEUDO_REGISTER || (REG_FUNCTION_VALUE_P (op) && rtx_equal_function_value_matters) /* We want to keep the stack, frame, and arg pointers special. */ || op == frame_pointer_rtx#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM || op == arg_pointer_rtx#endif || op == stack_pointer_rtx) return gen_rtx (SUBREG, word_mode, op, i); else return gen_rtx (REG, word_mode, REGNO (op) + i); } else if (GET_CODE (op) == SUBREG) return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); else if (GET_CODE (op) == CONCAT) { int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; if (i < partwords) return operand_subword (XEXP (op, 0), i, validate_address, mode); return operand_subword (XEXP (op, 1), i - partwords, validate_address, mode); } /* Form a new MEM at the requested address. */ if (GET_CODE (op) == MEM) { rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD); rtx new; if (validate_address) { if (reload_completed) { if (! strict_memory_address_p (word_mode, addr)) return 0; } else addr = memory_address (word_mode, addr); } new = gen_rtx (MEM, word_mode, addr); MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op); MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op); RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op); return new; } /* The only remaining cases are when OP is a constant. If the host and target floating formats are the same, handling two-word floating constants are easy. Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE} are defined as returning one or two 32 bit values, respectively, and not values of BITS_PER_WORD bits. */#ifdef REAL_ARITHMETIC/* The output is some bits, the width of the target machine's word. A wider-word host can surely hold them in a CONST_INT. A narrower-word host can't. */ if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == 64 && GET_CODE (op) == CONST_DOUBLE) { long k[2]; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_DOUBLE (rv, k); /* We handle 32-bit and >= 64-bit words here. Note that the order in which the words are written depends on the word endianness. ??? This is a potential portability problem and should be fixed at some point. */ if (BITS_PER_WORD == 32) return GEN_INT ((HOST_WIDE_INT) k[i]);#if HOST_BITS_PER_WIDE_INT > 32 else if (BITS_PER_WORD >= 64 && i == 0) return GEN_INT ((((HOST_WIDE_INT) k[! WORDS_BIG_ENDIAN]) << 32) | (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN]);#endif else if (BITS_PER_WORD == 16) { long value; value = k[i >> 1]; if ((i & 0x1) == 0) value >>= 16; value &= 0xffff; return GEN_INT ((HOST_WIDE_INT) value); } else abort (); } else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_BITSIZE (mode) > 64 && GET_CODE (op) == CONST_DOUBLE) { long k[4]; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); if (BITS_PER_WORD == 32) return GEN_INT ((HOST_WIDE_INT) k[i]); }#else /* no REAL_ARITHMETIC */ if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) || flag_pretend_float) && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD && GET_CODE (op) == CONST_DOUBLE) { /* The constant is stored in the host's word-ordering, but we want to access it in the target's word-ordering. Some compilers don't like a conditional inside macro args, so we have two copies of the return. */#ifdef HOST_WORDS_BIG_ENDIAN return GEN_INT (i == WORDS_BIG_ENDIAN ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));#else return GEN_INT (i != WORDS_BIG_ENDIAN ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));#endif }#endif /* no REAL_ARITHMETIC */ /* Single word float is a little harder, since single- and double-word values often do not have the same high-order bits. We have already verified that we want the only defined word of the single-word value. */#ifdef REAL_ARITHMETIC if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == 32 && GET_CODE (op) == CONST_DOUBLE) { long l; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_SINGLE (rv, l); return GEN_INT ((HOST_WIDE_INT) l); }#else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) || flag_pretend_float) && sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_SIZE (mode) == UNITS_PER_WORD && GET_CODE (op) == CONST_DOUBLE) { double d; union {float f; HOST_WIDE_INT i; } u; REAL_VALUE_FROM_CONST_DOUBLE (d, op); u.f = d; return GEN_INT (u.i); } if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) || flag_pretend_float) && sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_SIZE (mode) == UNITS_PER_WORD && GET_CODE (op) == CONST_DOUBLE) { double d; union {double d; HOST_WIDE_INT i; } u; REAL_VALUE_FROM_CONST_DOUBLE (d, op); u.d = d; return GEN_INT (u.i); }#endif /* no REAL_ARITHMETIC */ /* The only remaining cases that we can handle are integers. Convert to proper endianness now since these cases need it. At this point, i == 0 means the low-order word. We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT in general. However, if OP is (const_int 0), we can just return it for any word. */ if (op == const0_rtx) return op; if (GET_MODE_CLASS (mode) != MODE_INT || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE) || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT) return 0; if (WORDS_BIG_ENDIAN) i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i; /* Find out which word on the host machine this value is in and get it from the constant. */ val = (i / size_ratio == 0 ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op)) : (GET_CODE (op) == CONST_INT ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op))); /* If BITS_PER_WORD is smaller than an int, get the appropriate bits. */ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT) val = ((val >> ((i % size_ratio) * BITS_PER_WORD)) & (((HOST_WIDE_INT) 1 << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1)); return GEN_INT (val);}/* Similar to `operand_subword', but never return 0. If we can't extract the required subword, put OP into a register and try again. If that fails, abort. We always validate the address in this case. It is not valid to call this function after reload; it is mostly meant for RTL generation. MODE is the mode of OP, in case it is CONST_INT. */rtxoperand_subword_force (op, i, mode) rtx op; int i; enum machine_mode mode;{ rtx result = operand_subword (op, i, 1, mode); if (result) return result; if (mode != BLKmode && mode != VOIDmode) op = force_reg (mode, op); result = operand_subword (op, i, 1, mode); if (result == 0) abort (); return result;}/* Given a compare instruction, swap the operands. A test instruction is changed into a compare of 0 against the operand. */voidreverse_comparison (insn) rtx insn;{ rtx body = PATTERN (insn); rtx comp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -