📄 sparc.c
字号:
return ((GET_CODE (op) == CONST_INT && SPARC_SIMM13_P (INTVAL (op)))#if HOST_BITS_PER_WIDE_INT != 64 || (GET_CODE (op) == CONST_DOUBLE && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)) && (CONST_DOUBLE_HIGH (op) == ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ? (HOST_WIDE_INT)-1 : 0)))#endif );}/* The same, but only for sethi instructions. */intconst64_high_operand (rtx op, enum machine_mode mode){ return ((GET_CODE (op) == CONST_INT && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0 && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) ) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0 && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));}/* Return true if OP is a register, or is a CONST_INT that can fit in a signed 11 bit immediate field. This is an acceptable SImode operand for the movcc instructions. */intarith11_operand (rtx op, enum machine_mode mode){ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));}/* Return true if OP is a register, or is a CONST_INT that can fit in a signed 10 bit immediate field. This is an acceptable SImode operand for the movrcc instructions. */intarith10_operand (rtx op, enum machine_mode mode){ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));}/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit immediate field. ARCH64: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that can fit in a 13 bit immediate field. This is an acceptable DImode operand for most 3 address instructions. */intarith_double_operand (rtx op, enum machine_mode mode){ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op)) || (! TARGET_ARCH64 && GET_CODE (op) == CONST_DOUBLE && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000) || (TARGET_ARCH64 && GET_CODE (op) == CONST_DOUBLE && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 && ((CONST_DOUBLE_HIGH (op) == -1 && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000) || (CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));}/* Return true if OP is a constant 4096 for DImode on ARCH64 */intarith_double_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (TARGET_ARCH64 && ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 4096 && CONST_DOUBLE_HIGH (op) == 0)));}/* Return true if OP is suitable as second operand for add/sub in DImode */intarith_double_add_operand (rtx op, enum machine_mode mode){ return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);}/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that can fit in an 11 bit immediate field. This is an acceptable DImode operand for the movcc instructions. *//* ??? Replace with arith11_operand? */intarith11_double_operand (rtx op, enum machine_mode mode){ return (register_operand (op, mode) || (GET_CODE (op) == CONST_DOUBLE && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800 && ((CONST_DOUBLE_HIGH (op) == -1 && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400) || (CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & 0x400) == 0))) || (GET_CODE (op) == CONST_INT && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));}/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that can fit in an 10 bit immediate field. This is an acceptable DImode operand for the movrcc instructions. *//* ??? Replace with arith10_operand? */intarith10_double_operand (rtx op, enum machine_mode mode){ return (register_operand (op, mode) || (GET_CODE (op) == CONST_DOUBLE && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400 && ((CONST_DOUBLE_HIGH (op) == -1 && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200) || (CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & 0x200) == 0))) || (GET_CODE (op) == CONST_INT && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));}/* Return truth value of whether OP is an integer which fits the range constraining immediate operands in most three-address insns, which have a 13 bit immediate field. */intsmall_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}intsmall_int_or_double (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return ((GET_CODE (op) == CONST_INT && SMALL_INT (op)) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));}/* Recognize operand values for the umul instruction. That instruction sign extends immediate values just like all other sparc instructions, but interprets the extended result as an unsigned number. */intuns_small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){#if HOST_BITS_PER_WIDE_INT > 32 /* All allowed constants will fit a CONST_INT. */ return (GET_CODE (op) == CONST_INT && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000) || (INTVAL (op) >= 0xFFFFF000 && INTVAL (op) <= 0xFFFFFFFF)));#else return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));#endif}intuns_arith_operand (rtx op, enum machine_mode mode){ return register_operand (op, mode) || uns_small_int (op, mode);}/* Return truth value of statement that OP is a call-clobbered register. */intclobbered_register (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);}/* Return 1 if OP is a valid operand for the source of a move insn. */intinput_operand (rtx op, enum machine_mode mode){ enum mode_class mclass; /* If both modes are non-void they must be the same. */ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) return 0; /* Allow any one instruction integer constant, and all CONST_INT variants when we are working in DImode and !arch64. */ if (GET_MODE_CLASS (mode) == MODE_INT && ((GET_CODE (op) == CONST_INT && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) || SPARC_SIMM13_P (INTVAL (op)) || (mode == DImode && ! TARGET_ARCH64))) || (TARGET_ARCH64 && GET_CODE (op) == CONST_DOUBLE && ((CONST_DOUBLE_HIGH (op) == 0 && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))) ||#if HOST_BITS_PER_WIDE_INT == 64 (CONST_DOUBLE_HIGH (op) == 0 && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))#else (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)) && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0 && CONST_DOUBLE_HIGH (op) == 0) || (CONST_DOUBLE_HIGH (op) == -1 && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))#endif )))) return 1; /* If !arch64 and this is a DImode const, allow it so that the splits can be generated. */ if (! TARGET_ARCH64 && mode == DImode && GET_CODE (op) == CONST_DOUBLE) return 1; if (register_operand (op, mode)) return 1; mclass = GET_MODE_CLASS (mode); if ((mclass == MODE_FLOAT && GET_CODE (op) == CONST_DOUBLE) || (mclass == MODE_VECTOR_INT && GET_CODE (op) == CONST_VECTOR)) return 1; /* If this is a SUBREG, look inside so that we handle paradoxical ones. */ if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); /* Check for valid MEM forms. */ if (GET_CODE (op) == MEM) return memory_address_p (mode, XEXP (op, 0)); return 0;}/* Return 1 if OP is valid for the lhs of a compare insn. */intcompare_operand (rtx op, enum machine_mode mode){ if (GET_CODE (op) == ZERO_EXTRACT) return (register_operand (XEXP (op, 0), mode) && small_int_or_double (XEXP (op, 1), mode) && small_int_or_double (XEXP (op, 2), mode) /* This matches cmp_zero_extract. */ && ((mode == SImode && ((GET_CODE (XEXP (op, 2)) == CONST_INT && INTVAL (XEXP (op, 2)) > 19) || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE && CONST_DOUBLE_LOW (XEXP (op, 2)) > 19))) /* This matches cmp_zero_extract_sp64. */ || (mode == DImode && TARGET_ARCH64 && ((GET_CODE (XEXP (op, 2)) == CONST_INT && INTVAL (XEXP (op, 2)) > 51) || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE && CONST_DOUBLE_LOW (XEXP (op, 2)) > 51))))); else return register_operand (op, mode);}/* We know it can't be done in one insn when we get here, the movsi expander guarantees this. */voidsparc_emit_set_const32 (rtx op0, rtx op1){ enum machine_mode mode = GET_MODE (op0); rtx temp; if (GET_CODE (op1) == CONST_INT) { HOST_WIDE_INT value = INTVAL (op1); if (SPARC_SETHI_P (value & GET_MODE_MASK (mode)) || SPARC_SIMM13_P (value)) abort (); } /* Full 2-insn decomposition is needed. */ if (reload_in_progress || reload_completed) temp = op0; else temp = gen_reg_rtx (mode); if (GET_CODE (op1) == CONST_INT) { /* Emit them as real moves instead of a HIGH/LO_SUM, this way CSE can see everything and reuse intermediate values if it wants. */ if (TARGET_ARCH64 && HOST_BITS_PER_WIDE_INT != 64 && (INTVAL (op1) & 0x80000000) != 0) emit_insn (gen_rtx_SET (VOIDmode, temp, immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff, 0, DImode))); else emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff))); emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_IOR (mode, temp, GEN_INT (INTVAL (op1) & 0x3ff)))); } else { /* A symbol, emit in the traditional way. */ emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, op1))); emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (mode, temp, op1))); }}/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register. If TEMP is nonzero, we are forbidden to use any other scratch registers. Otherwise, we are allowed to generate them as needed. Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns). */voidsparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp){ rtx temp1, temp2, temp3, temp4, temp5; rtx ti_temp = 0; if (temp && GET_MODE (temp) == TImode) { ti_temp = temp; temp = gen_rtx_REG (DImode, REGNO (temp)); } /* SPARC-V9 code-model support. */ switch (sparc_cmodel) { case CM_MEDLOW: /* The range spanned by all instructions in the object is less than 2^31 bytes (2GB) and the distance from any instruction to the location of the label _GLOBAL_OFFSET_TABLE_ is less than 2^31 bytes (2GB). The executable must be in the low 4TB of the virtual address space. sethi %hi(symbol), %temp1 or %temp1, %lo(symbol), %reg */ if (temp) temp1 = temp; /* op0 is allowed. */ else temp1 = gen_reg_rtx (DImode); emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1))); emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1))); break; case CM_MEDMID: /* The range spanned by all instructions in the object is less than 2^31 bytes (2GB) and the distance from any instruction to the location of the label _GLOBAL_OFFSET_TABLE_ is less than 2^31 bytes (2GB). The executable must be in the low 16TB of the virtual address space. sethi %h44(symbol), %temp1 or %temp1, %m44(symbol), %temp2 sllx %temp2, 12, %temp3 or %temp3, %l44(symbol), %reg */ if (temp) { temp1 = op0; temp2 = op0; temp3 = temp; /* op0 is allowed. */ } else { temp1 = gen_reg_rtx (DImode); temp2 = gen_reg_rtx (DImode); temp3 = gen_reg_rtx (DImode); } emit_insn (gen_seth44 (temp1, op1)); emit_insn (gen_setm44 (temp2, temp1, op1)); emit_insn (gen_rtx_SET (VOIDmode, temp3, gen_rtx_ASHIFT (DImode, temp2, GEN_INT (12)))); emit_insn (gen_setl44 (op0, temp3, op1)); break; case CM_MEDANY: /* The range spanned by all instructions in the object is less than 2^31 bytes (2GB) and the distance from any instruction to the location of the label _GLOBAL_OFFSET_TABLE_ is less than 2^31 bytes (2GB). The executable can be placed anywhere in the virtual address space. sethi %hh(symbol), %temp1 sethi %lm(symbol), %temp2 or %temp1, %hm(symbol), %temp3 sllx %temp3, 32, %temp4 or %temp4, %temp2, %temp5 or %temp5, %lo(symbol), %reg */ if (temp) { /* It is possible that one of the registers we got for operands[2] might coincide with that of operands[0] (which is why we made it TImode). Pick the other one to use as our scratch. */ if (rtx_equal_p (temp, op0)) { if (ti_temp) temp = gen_rtx_REG (DImode, REGNO (temp) + 1); else abort(); } temp1 = op0; temp2 = temp; /* op0 is _not_ allowed, see above. */ temp3 = op0; temp4 = op0; temp5 = op0; } else { temp1 = gen_reg_rtx (DImode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -