📄 xtensa.c
字号:
return nonimmed_operand (op, mode); return mem_operand (op, mode);}intsext_fldsz_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return ((GET_CODE (op) == CONST_INT) && xtensa_tp7 (INTVAL (op) - 1));}intlsbitnum_operand (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 (int v){ if (v == 0) return TRUE; return xtensa_b4const (v);}intbranch_operand (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 (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 (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. */ if (flag_pic) { tree callee, callee_sec, caller_sec; if (GET_CODE (op) != SYMBOL_REF || !SYMBOL_REF_LOCAL_P (op) || SYMBOL_REF_EXTERNAL_P (op)) return FALSE; /* Don't attempt a direct call if the callee is known to be in a different section, since there's a good chance it will be out of range. */ if (flag_function_sections || DECL_ONE_ONLY (current_function_decl)) return FALSE; caller_sec = DECL_SECTION_NAME (current_function_decl); callee = SYMBOL_REF_DECL (op); if (callee) { if (DECL_ONE_ONLY (callee)) return FALSE; callee_sec = DECL_SECTION_NAME (callee); if (((caller_sec == NULL_TREE) ^ (callee_sec == NULL_TREE)) || (caller_sec != NULL_TREE && strcmp (TREE_STRING_POINTER (caller_sec), TREE_STRING_POINTER (callee_sec)) != 0)) return FALSE; } else if (caller_sec != NULL_TREE) return FALSE; } return TRUE; } return FALSE;}intmove_operand (rtx op, enum machine_mode mode){ if (register_operand (op, mode) || memory_operand (op, mode)) return TRUE; switch (mode) { case DFmode: case SFmode: return TARGET_CONST16 && CONSTANT_P (op); case DImode: case SImode: if (TARGET_CONST16) return CONSTANT_P (op); /* Fall through. */ case HImode: case QImode: if (GET_CODE (op) == CONST_INT && xtensa_simm12b (INTVAL (op))) return TRUE; break; default: break; } return FALSE;}intsmalloffset_mem_p (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;}intconstantpool_address_p (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 (rtx op){ if (GET_CODE (op) == MEM) return constantpool_address_p (XEXP (op, 0)); return FALSE;}/* Accept the floating point constant 1 in the appropriate mode. */intconst_float_1_operand (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 (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 (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));}intbranch_operator (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 (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 (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 (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 (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 (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 (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 test */){ struct cmp_info { enum rtx_code test_code; /* test code to use in insn */ int (*const_range_p) (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_fmt_ee (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 (enum rtx_code test_code, /* relational test (EQ, etc) */ rtx cmp0, /* first operand to compare */ rtx cmp1 /* second operand to compare */){ rtx (*gen_fn) (rtx, rtx, rtx); rtx brtmp; int reverse_regs, invert; switch (test_code) { case EQ: reverse_regs = 0; invert = 0; gen_fn = gen_seq_sf; break; case NE: reverse_regs = 0; invert = 1; gen_fn = gen_seq_sf; break; case LE: reverse_regs = 0; invert = 0; gen_fn = gen_sle_sf; break; case GT: reverse_regs = 1; invert = 0; gen_fn = gen_slt_sf; break; case LT: reverse_regs = 0; invert = 0; gen_fn = gen_slt_sf; break; case GE: reverse_regs = 1; invert = 0; gen_fn = gen_sle_sf; break; default: fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1)); reverse_regs = 0; invert = 0; gen_fn = 0; /* avoid compiler warnings */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -