📄 xtensa.c
字号:
enum machine_mode mode ATTRIBUTE_UNUSED;{ return ((GET_CODE (op) == CONST_INT) && xtensa_tp7 (INTVAL (op) - 1));}intlsbitnum_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == CONST_INT) { return (BITS_BIG_ENDIAN ? (INTVAL (op) == BITS_PER_WORD-1) : (INTVAL (op) == 0)); } return FALSE;}static intb4const_or_zero (v) int v;{ if (v == 0) return TRUE; return xtensa_b4const (v);}intbranch_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return b4const_or_zero (INTVAL (op)); return register_operand (op, mode);}intubranch_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return xtensa_b4constu (INTVAL (op)); return register_operand (op, mode);}intcall_insn_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if ((GET_CODE (op) == REG) && (op != arg_pointer_rtx) && ((REGNO (op) < FRAME_POINTER_REGNUM) || (REGNO (op) > LAST_VIRTUAL_REGISTER))) return TRUE; if (CONSTANT_ADDRESS_P (op)) { /* Direct calls only allowed to static functions with PIC. */ return (!flag_pic || (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op))); } return FALSE;}intmove_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return TRUE; /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1. */ if (GET_CODE (op) == CONSTANT_P_RTX) return TRUE; if (GET_CODE (op) == CONST_INT) return xtensa_simm12b (INTVAL (op)); if (GET_CODE (op) == MEM) return memory_address_p (mode, XEXP (op, 0)); return FALSE;}intsmalloffset_mem_p (op) rtx op;{ if (GET_CODE (op) == MEM) { rtx addr = XEXP (op, 0); if (GET_CODE (addr) == REG) return REG_OK_FOR_BASE_P (addr); if (GET_CODE (addr) == PLUS) { rtx offset = XEXP (addr, 0); if (GET_CODE (offset) != CONST_INT) offset = XEXP (addr, 1); if (GET_CODE (offset) != CONST_INT) return FALSE; return xtensa_lsi4x4 (INTVAL (offset)); } } return FALSE;}intsmalloffset_double_mem_p (op) rtx op;{ if (!smalloffset_mem_p (op)) return FALSE; return smalloffset_mem_p (adjust_address (op, GET_MODE (op), 4));}intconstantpool_address_p (addr) rtx addr;{ rtx sym = addr; if (GET_CODE (addr) == CONST) { rtx offset; /* only handle (PLUS (SYM, OFFSET)) form */ addr = XEXP (addr, 0); if (GET_CODE (addr) != PLUS) return FALSE; /* make sure the address is word aligned */ offset = XEXP (addr, 1); if ((GET_CODE (offset) != CONST_INT) || ((INTVAL (offset) & 3) != 0)) return FALSE; sym = XEXP (addr, 0); } if ((GET_CODE (sym) == SYMBOL_REF) && CONSTANT_POOL_ADDRESS_P (sym)) return TRUE; return FALSE;}intconstantpool_mem_p (op) rtx op;{ if (GET_CODE (op) == MEM) return constantpool_address_p (XEXP (op, 0)); return FALSE;}intnon_const_move_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) == MEM) return memory_address_p (mode, XEXP (op, 0)); return FALSE;}/* Accept the floating point constant 1 in the appropriate mode. */intconst_float_1_operand (op, mode) rtx op; enum machine_mode mode;{ REAL_VALUE_TYPE d; static REAL_VALUE_TYPE onedf; static REAL_VALUE_TYPE onesf; static int one_initialized; if ((GET_CODE (op) != CONST_DOUBLE) || (mode != GET_MODE (op)) || (mode != DFmode && mode != SFmode)) return FALSE; REAL_VALUE_FROM_CONST_DOUBLE (d, op); if (! one_initialized) { onedf = REAL_VALUE_ATOF ("1.0", DFmode); onesf = REAL_VALUE_ATOF ("1.0", SFmode); one_initialized = TRUE; } if (mode == DFmode) return REAL_VALUES_EQUAL (d, onedf); else return REAL_VALUES_EQUAL (d, onesf);}intfpmem_offset_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == CONST_INT) return xtensa_mem_offset (INTVAL (op), SFmode); return 0;}voidxtensa_extend_reg (dst, src) rtx dst; rtx src;{ rtx temp = gen_reg_rtx (SImode); rtx shift = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (GET_MODE (src))); /* generate paradoxical subregs as needed so that the modes match */ src = simplify_gen_subreg (SImode, src, GET_MODE (src), 0); dst = simplify_gen_subreg (SImode, dst, GET_MODE (dst), 0); emit_insn (gen_ashlsi3 (temp, src, shift)); emit_insn (gen_ashrsi3 (dst, temp, shift));}voidxtensa_load_constant (dst, src) rtx dst; rtx src;{ enum machine_mode mode = GET_MODE (dst); src = force_const_mem (SImode, src); /* PC-relative loads are always SImode so we have to add a SUBREG if that is not the desired mode */ if (mode != SImode) { if (register_operand (dst, mode)) dst = simplify_gen_subreg (SImode, dst, mode, 0); else { src = force_reg (SImode, src); src = gen_lowpart_SUBREG (mode, src); } } emit_move_insn (dst, src);}intbranch_operator (x, mode) rtx x; enum machine_mode mode;{ if (GET_MODE (x) != mode) return FALSE; switch (GET_CODE (x)) { case EQ: case NE: case LT: case GE: return TRUE; default: break; } return FALSE;}intubranch_operator (x, mode) rtx x; enum machine_mode mode;{ if (GET_MODE (x) != mode) return FALSE; switch (GET_CODE (x)) { case LTU: case GEU: return TRUE; default: break; } return FALSE;}intboolean_operator (x, mode) rtx x; enum machine_mode mode;{ if (GET_MODE (x) != mode) return FALSE; switch (GET_CODE (x)) { case EQ: case NE: return TRUE; default: break; } return FALSE;}intxtensa_mask_immediate (v) int v;{#define MAX_MASK_SIZE 16 int mask_size; for (mask_size = 1; mask_size <= MAX_MASK_SIZE; mask_size++) { if ((v & 1) == 0) return FALSE; v = v >> 1; if (v == 0) return TRUE; } return FALSE;}intxtensa_mem_offset (v, mode) unsigned v; enum machine_mode mode;{ switch (mode) { case BLKmode: /* Handle the worst case for block moves. See xtensa_expand_block_move where we emit an optimized block move operation if the block can be moved in < "move_ratio" pieces. The worst case is when the block is aligned but has a size of (3 mod 4) (does this happen?) so that the last piece requires a byte load/store. */ return (xtensa_uimm8 (v) && xtensa_uimm8 (v + MOVE_MAX * LARGEST_MOVE_RATIO)); case QImode: return xtensa_uimm8 (v); case HImode: return xtensa_uimm8x2 (v); case DFmode: return (xtensa_uimm8x4 (v) && xtensa_uimm8x4 (v + 4)); default: break; } return xtensa_uimm8x4 (v);}/* Make normal rtx_code into something we can index from an array */static enum internal_testmap_test_to_internal_test (test_code) enum rtx_code test_code;{ enum internal_test test = ITEST_MAX; switch (test_code) { default: break; case EQ: test = ITEST_EQ; break; case NE: test = ITEST_NE; break; case GT: test = ITEST_GT; break; case GE: test = ITEST_GE; break; case LT: test = ITEST_LT; break; case LE: test = ITEST_LE; break; case GTU: test = ITEST_GTU; break; case GEU: test = ITEST_GEU; break; case LTU: test = ITEST_LTU; break; case LEU: test = ITEST_LEU; break; } return test;}/* Generate the code to compare two integer values. The return value is the comparison expression. */static rtxgen_int_relational (test_code, cmp0, cmp1, p_invert) enum rtx_code test_code; /* relational test (EQ, etc) */ rtx cmp0; /* first operand to compare */ rtx cmp1; /* second operand to compare */ int *p_invert; /* whether branch needs to reverse its test */{ struct cmp_info { enum rtx_code test_code; /* test code to use in insn */ int (*const_range_p) PARAMS ((int)); /* predicate function to check range */ int const_add; /* constant to add (convert LE -> LT) */ int reverse_regs; /* reverse registers in test */ int invert_const; /* != 0 if invert value if cmp1 is constant */ int invert_reg; /* != 0 if invert value if cmp1 is register */ int unsignedp; /* != 0 for unsigned comparisons. */ }; static struct cmp_info info[ (int)ITEST_MAX ] = { { EQ, b4const_or_zero, 0, 0, 0, 0, 0 }, /* EQ */ { NE, b4const_or_zero, 0, 0, 0, 0, 0 }, /* NE */ { LT, b4const_or_zero, 1, 1, 1, 0, 0 }, /* GT */ { GE, b4const_or_zero, 0, 0, 0, 0, 0 }, /* GE */ { LT, b4const_or_zero, 0, 0, 0, 0, 0 }, /* LT */ { GE, b4const_or_zero, 1, 1, 1, 0, 0 }, /* LE */ { LTU, xtensa_b4constu, 1, 1, 1, 0, 1 }, /* GTU */ { GEU, xtensa_b4constu, 0, 0, 0, 0, 1 }, /* GEU */ { LTU, xtensa_b4constu, 0, 0, 0, 0, 1 }, /* LTU */ { GEU, xtensa_b4constu, 1, 1, 1, 0, 1 }, /* LEU */ }; enum internal_test test; enum machine_mode mode; struct cmp_info *p_info; test = map_test_to_internal_test (test_code); if (test == ITEST_MAX) abort (); p_info = &info[ (int)test ]; mode = GET_MODE (cmp0); if (mode == VOIDmode) mode = GET_MODE (cmp1); /* Make sure we can handle any constants given to us. */ if (GET_CODE (cmp1) == CONST_INT) { HOST_WIDE_INT value = INTVAL (cmp1); unsigned HOST_WIDE_INT uvalue = (unsigned HOST_WIDE_INT)value; /* if the immediate overflows or does not fit in the immediate field, spill it to a register */ if ((p_info->unsignedp ? (uvalue + p_info->const_add > uvalue) : (value + p_info->const_add > value)) != (p_info->const_add > 0)) { cmp1 = force_reg (mode, cmp1); } else if (!(p_info->const_range_p) (value + p_info->const_add)) { cmp1 = force_reg (mode, cmp1); } } else if ((GET_CODE (cmp1) != REG) && (GET_CODE (cmp1) != SUBREG)) { cmp1 = force_reg (mode, cmp1); } /* See if we need to invert the result. */ *p_invert = ((GET_CODE (cmp1) == CONST_INT) ? p_info->invert_const : p_info->invert_reg); /* Comparison to constants, may involve adding 1 to change a LT into LE. Comparison between two registers, may involve switching operands. */ if (GET_CODE (cmp1) == CONST_INT) { if (p_info->const_add != 0) cmp1 = GEN_INT (INTVAL (cmp1) + p_info->const_add); } else if (p_info->reverse_regs) { rtx temp = cmp0; cmp0 = cmp1; cmp1 = temp; } return gen_rtx (p_info->test_code, VOIDmode, cmp0, cmp1);}/* Generate the code to compare two float values. The return value is the comparison expression. */static rtxgen_float_relational (test_code, cmp0, cmp1) enum rtx_code test_code; /* relational test (EQ, etc) */ rtx cmp0; /* first operand to compare */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -