📄 arc.c
字号:
{ if (GET_CODE (op) != CONST_INT) return 0; return SMALL_INT (INTVAL (op));}/* Return true if OP will require a long immediate (limm) value. This is currently only used when calculating length attributes. */intlong_immediate_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ switch (GET_CODE (op)) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1; case CONST_INT : return !SMALL_INT (INTVAL (op)); case CONST_DOUBLE : /* These can happen because large unsigned 32 bit constants are represented this way (the multiplication patterns can cause these to be generated). They also occur for SFmode values. */ return 1; default: break; } return 0;}/* Return true if OP is a MEM that when used as a load or store address will require an 8 byte insn. Load and store instructions don't allow the same possibilities but they're similar enough that this one function will do. This is currently only used when calculating length attributes. */intlong_immediate_loadstore_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); switch (GET_CODE (op)) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1; case CONST_INT : /* This must be handled as "st c,[limm]". Ditto for load. Technically, the assembler could translate some possibilities to "st c,[limm/2 + limm/2]" if limm/2 will fit in a shimm, but we don't assume that it does. */ return 1; case CONST_DOUBLE : /* These can happen because large unsigned 32 bit constants are represented this way (the multiplication patterns can cause these to be generated). They also occur for SFmode values. */ return 1; case REG : return 0; case PLUS : if (GET_CODE (XEXP (op, 1)) == CONST_INT && !SMALL_INT (INTVAL (XEXP (op, 1)))) return 1; return 0; default: break; } return 0;}/* Return true if OP is an acceptable argument for a single word move source. */intmove_src_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1; case CONST_INT : return (LARGE_INT (INTVAL (op))); case CONST_DOUBLE : /* We can handle DImode integer constants in SImode if the value (signed or unsigned) will fit in 32 bits. This is needed because large unsigned 32 bit constants are represented as CONST_DOUBLEs. */ if (mode == SImode) return arc_double_limm_p (op); /* We can handle 32 bit floating point constants. */ if (mode == SFmode) return GET_MODE (op) == SFmode; return 0; case REG : return register_operand (op, mode); case SUBREG : /* (subreg (mem ...) ...) can occur here if the inner part was once a pseudo-reg and is now a stack slot. */ if (GET_CODE (SUBREG_REG (op)) == MEM) return address_operand (XEXP (SUBREG_REG (op), 0), mode); else return register_operand (op, mode); case MEM : return address_operand (XEXP (op, 0), mode); default : return 0; }}/* Return true if OP is an acceptable argument for a double word move source. */intmove_double_src_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case REG : return register_operand (op, mode); case SUBREG : /* (subreg (mem ...) ...) can occur here if the inner part was once a pseudo-reg and is now a stack slot. */ if (GET_CODE (SUBREG_REG (op)) == MEM) return move_double_src_operand (SUBREG_REG (op), mode); else return register_operand (op, mode); case MEM : /* Disallow auto inc/dec for now. */ if (GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == PRE_INC) return 0; return address_operand (XEXP (op, 0), mode); case CONST_INT : case CONST_DOUBLE : return 1; default : return 0; }}/* Return true if OP is an acceptable argument for a move destination. */intmove_dest_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case REG : return register_operand (op, mode); case SUBREG : /* (subreg (mem ...) ...) can occur here if the inner part was once a pseudo-reg and is now a stack slot. */ if (GET_CODE (SUBREG_REG (op)) == MEM) return address_operand (XEXP (SUBREG_REG (op), 0), mode); else return register_operand (op, mode); case MEM : return address_operand (XEXP (op, 0), mode); default : return 0; }}/* Return true if OP is valid load with update operand. */intload_update_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM || GET_MODE (op) != mode) return 0; op = XEXP (op, 0); if (GET_CODE (op) != PLUS || GET_MODE (op) != Pmode || !register_operand (XEXP (op, 0), Pmode) || !nonmemory_operand (XEXP (op, 1), Pmode)) return 0; return 1;}/* Return true if OP is valid store with update operand. */intstore_update_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM || GET_MODE (op) != mode) return 0; op = XEXP (op, 0); if (GET_CODE (op) != PLUS || GET_MODE (op) != Pmode || !register_operand (XEXP (op, 0), Pmode) || !(GET_CODE (XEXP (op, 1)) == CONST_INT && SMALL_INT (INTVAL (XEXP (op, 1))))) return 0; return 1;}/* Return true if OP is a non-volatile non-immediate operand. Volatile memory refs require a special "cache-bypass" instruction and only the standard movXX patterns are set up to handle them. */intnonvol_nonimm_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op)) return 0; return nonimmediate_operand (op, mode);}/* Accept integer operands in the range -0x80000000..0x7fffffff. We have to check the range carefully since this predicate is used in DImode contexts. */intconst_sint32_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ /* All allowed constants will fit a CONST_INT. */ return (GET_CODE (op) == CONST_INT && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));}/* Accept integer operands in the range 0..0xffffffff. We have to check the range carefully since this predicate is used in DImode contexts. Also, we need some extra crud to make it work when hosted on 64-bit machines. */intconst_uint32_operand (op, mode) 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) <= 0xffffffffL));#else return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));#endif}/* Return 1 if OP is a comparison operator valid for the mode of CC. This allows the use of MATCH_OPERATOR to recognize all the branch insns. Some insns only set a few bits in the condition code. So only allow those comparisons that use the bits that are valid. */intproper_comparison_operator (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ enum rtx_code code = GET_CODE (op); if (GET_RTX_CLASS (code) != '<') return 0; if (GET_MODE (XEXP (op, 0)) == CCZNmode) return (code == EQ || code == NE); if (GET_MODE (XEXP (op, 0)) == CCZNCmode) return (code == EQ || code == NE || code == LTU || code == GEU || code == GTU || code == LEU); return 1;}/* Misc. utilities. *//* X and Y are two things to compare using CODE. Emit the compare insn and return the rtx for the cc reg in the proper mode. */rtxgen_compare_reg (code, x, y) enum rtx_code code; rtx x, y;{ enum machine_mode mode = SELECT_CC_MODE (code, x, y); rtx cc_reg; cc_reg = gen_rtx_REG (mode, 61); emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y))); return cc_reg;}/* Return 1 if VALUE, a const_double, will fit in a limm (4 byte number). We assume the value can be either signed or unsigned. */intarc_double_limm_p (value) rtx value;{ HOST_WIDE_INT low, high; if (GET_CODE (value) != CONST_DOUBLE) abort (); low = CONST_DOUBLE_LOW (value); high = CONST_DOUBLE_HIGH (value); if (low & 0x80000000) { return (((unsigned HOST_WIDE_INT) low <= 0xffffffff && high == 0) || (((low & - (unsigned HOST_WIDE_INT) 0x80000000) == - (unsigned HOST_WIDE_INT) 0x80000000) && high == -1)); } else { return (unsigned HOST_WIDE_INT) low <= 0x7fffffff && high == 0; }}/* Do any needed setup for a variadic function. For the ARC, we must create a register parameter block, and then copy any anonymous arguments in registers to memory. CUM has not been updated for the last named argument which has type TYPE and mode MODE, and we rely on this fact. We do things a little weird here. We're supposed to only allocate space for the anonymous arguments. However we need to keep the stack eight byte aligned. So we round the space up if necessary, and leave it to va_start to compensate. */voidarc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type ATTRIBUTE_UNUSED; int *pretend_size; int no_rtl;{ int first_anon_arg; /* All BLKmode values are passed by reference. */ if (mode == BLKmode) abort (); first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl) { /* Note that first_reg_offset < MAX_ARC_PARM_REGS. */ int first_reg_offset = first_anon_arg; /* Size in words to "pretend" allocate. */ int size = MAX_ARC_PARM_REGS - first_reg_offset; /* Extra slop to keep stack eight byte aligned. */ int align_slop = size & 1; rtx regblock; regblock = gen_rtx_MEM (BLKmode, plus_constant (arg_pointer_rtx, FIRST_PARM_OFFSET (0) + align_slop * UNITS_PER_WORD)); set_mem_alias_set (regblock, get_varargs_alias_set ()); set_mem_align (regblock, BITS_PER_WORD); move_block_from_reg (first_reg_offset, regblock, MAX_ARC_PARM_REGS - first_reg_offset, ((MAX_ARC_PARM_REGS - first_reg_offset) * UNITS_PER_WORD)); *pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop) * UNITS_PER_WORD); }}/* Cost functions. *//* Provide the costs of an addressing mode that contains ADDR. If ADDR is not a valid address, its cost is irrelevant. */intarc_address_cost (addr) rtx addr;{ switch (GET_CODE (addr)) { case REG : /* This is handled in the macro that calls us. It's here for documentation. */ return 1; case LABEL_REF : case SYMBOL_REF : case CONST : return 2; case PLUS : { register rtx plus0 = XEXP (addr, 0); register rtx plus1 = XEXP (addr, 1); if (GET_CODE (plus0) != REG) break; switch (GET_CODE (plus1)) { case CONST_INT : return SMALL_INT (plus1) ? 1 : 2; case CONST : case SYMBOL_REF : case LABEL_REF : return 2; default: break; } break; } default: break; } return 4;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -