📄 h8300.c
字号:
if (GET_CODE (SET_DEST (set)) == STRICT_LOW_PART) cc_status.value2 = XEXP (SET_DEST (set), 0); else cc_status.value2 = SET_DEST (set); } break; case CC_COMPARE: /* The insn is a compare instruction. */ CC_STATUS_INIT; cc_status.value1 = SET_SRC (body); break; case CC_CLOBBER: /* Insn doesn't leave CC in a usable state. */ CC_STATUS_INIT; break; }}/* Given that X occurs in an address of the form (plus X constant), return the part of X that is expected to be a register. There are four kinds of addressing mode to recognize: @(dd,Rn) @(dd,RnL.b) @(dd,Rn.w) @(dd,ERn.l) If SIZE is nonnull, and the address is one of the last three forms, set *SIZE to the index multiplication factor. Set it to 0 for plain @(dd,Rn) addresses. MODE is the mode of the value being accessed. It can be VOIDmode if the address is known to be valid, but its mode is unknown. */rtxh8300_get_index (rtx x, enum machine_mode mode, int *size){ int dummy, factor; if (size == 0) size = &dummy; factor = (mode == VOIDmode ? 0 : GET_MODE_SIZE (mode)); if (TARGET_H8300SX && factor <= 4 && (mode == VOIDmode || GET_MODE_CLASS (mode) == MODE_INT || GET_MODE_CLASS (mode) == MODE_FLOAT)) { if (factor <= 1 && GET_CODE (x) == ZERO_EXTEND) { /* When accessing byte-sized values, the index can be a zero-extended QImode or HImode register. */ *size = GET_MODE_SIZE (GET_MODE (XEXP (x, 0))); return XEXP (x, 0); } else { /* We're looking for addresses of the form: (mult X I) or (mult (zero_extend X) I) where I is the size of the operand being accessed. The canonical form of the second expression is: (and (mult (subreg X) I) J) where J == GET_MODE_MASK (GET_MODE (X)) * I. */ rtx index; if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT && (factor == 0 || INTVAL (XEXP (x, 1)) == 0xff * factor || INTVAL (XEXP (x, 1)) == 0xffff * factor)) { index = XEXP (x, 0); *size = (INTVAL (XEXP (x, 1)) >= 0xffff ? 2 : 1); } else { index = x; *size = 4; } if (GET_CODE (index) == MULT && GET_CODE (XEXP (index, 1)) == CONST_INT && (factor == 0 || factor == INTVAL (XEXP (index, 1)))) return XEXP (index, 0); } } *size = 0; return x;}static const h8300_length_table addb_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 2, 4, 4, 4 }, /* add.b xx,Rd */ { 4, 4, 4, 4, 6 }, /* add.b xx,@aa */ { 4, 4, 4, 4, 6 }, /* add.b xx,@Rd */ { 6, 4, 4, 4, 6 } /* add.b xx,@xx */};static const h8300_length_table addw_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 2, 4, 4, 4 }, /* add.w xx,Rd */ { 4, 4, 4, 4, 6 }, /* add.w xx,@aa */ { 4, 4, 4, 4, 6 }, /* add.w xx,@Rd */ { 4, 4, 4, 4, 6 } /* add.w xx,@xx */};static const h8300_length_table addl_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 2, 4, 4, 4 }, /* add.l xx,Rd */ { 4, 4, 6, 6, 6 }, /* add.l xx,@aa */ { 4, 4, 6, 6, 6 }, /* add.l xx,@Rd */ { 4, 4, 6, 6, 6 } /* add.l xx,@xx */};#define logicb_length_table addb_length_table#define logicw_length_table addw_length_tablestatic const h8300_length_table logicl_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 4, 4, 4, 4 }, /* and.l xx,Rd */ { 4, 4, 6, 6, 6 }, /* and.l xx,@aa */ { 4, 4, 6, 6, 6 }, /* and.l xx,@Rd */ { 4, 4, 6, 6, 6 } /* and.l xx,@xx */};static const h8300_length_table movb_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 2, 2, 2, 4 }, /* mov.b xx,Rd */ { 4, 2, 4, 4, 4 }, /* mov.b xx,@aa */ { 4, 2, 4, 4, 4 }, /* mov.b xx,@Rd */ { 4, 4, 4, 4, 4 } /* mov.b xx,@xx */};#define movw_length_table movb_length_tablestatic const h8300_length_table movl_length_table ={ /* #xx Rs @aa @Rs @xx */ { 2, 2, 4, 4, 4 }, /* mov.l xx,Rd */ { 4, 4, 4, 4, 4 }, /* mov.l xx,@aa */ { 4, 4, 4, 4, 4 }, /* mov.l xx,@Rd */ { 4, 4, 4, 4, 4 } /* mov.l xx,@xx */};/* Return the size of the given address or displacement constant. */static unsigned inth8300_constant_length (rtx constant){ /* Check for (@d:16,Reg). */ if (GET_CODE (constant) == CONST_INT && IN_RANGE (INTVAL (constant), -0x8000, 0x7fff)) return 2; /* Check for (@d:16,Reg) in cases where the displacement is an absolute address. */ if (Pmode == HImode || h8300_tiny_constant_address_p (constant)) return 2; return 4;}/* Return the size of a displacement field in address ADDR, which should have the form (plus X constant). SIZE is the number of bytes being accessed. */static unsigned inth8300_displacement_length (rtx addr, int size){ rtx offset; offset = XEXP (addr, 1); /* Check for @(d:2,Reg). */ if (register_operand (XEXP (addr, 0), VOIDmode) && GET_CODE (offset) == CONST_INT && (INTVAL (offset) == size || INTVAL (offset) == size * 2 || INTVAL (offset) == size * 3)) return 0; return h8300_constant_length (offset);}/* Store the class of operand OP in *CLASS and return the length of any extra operand fields. SIZE is the number of bytes in OP. CLASS can be null if only the length is needed. */static unsigned inth8300_classify_operand (rtx op, int size, enum h8300_operand_class *class){ enum h8300_operand_class dummy; if (class == 0) class = &dummy; if (CONSTANT_P (op)) { *class = H8OP_IMMEDIATE; /* Byte-sized immediates are stored in the opcode fields. */ if (size == 1) return 0; /* If this is a 32-bit instruction, see whether the constant will fit into a 16-bit immediate field. */ if (TARGET_H8300SX && size == 4 && GET_CODE (op) == CONST_INT && IN_RANGE (INTVAL (op), 0, 0xffff)) return 2; return size; } else if (GET_CODE (op) == MEM) { op = XEXP (op, 0); if (CONSTANT_P (op)) { *class = H8OP_MEM_ABSOLUTE; return h8300_constant_length (op); } else if (GET_CODE (op) == PLUS && CONSTANT_P (XEXP (op, 1))) { *class = H8OP_MEM_COMPLEX; return h8300_displacement_length (op, size); } else if (GET_RTX_CLASS (GET_CODE (op)) == RTX_AUTOINC) { *class = H8OP_MEM_COMPLEX; return 0; } else if (register_operand (op, VOIDmode)) { *class = H8OP_MEM_BASE; return 0; } } gcc_assert (register_operand (op, VOIDmode)); *class = H8OP_REGISTER; return 0;}/* Return the length of the instruction described by TABLE given that its operands are OP1 and OP2. OP1 must be an h8300_dst_operand and OP2 must be an h8300_src_operand. */static unsigned inth8300_length_from_table (rtx op1, rtx op2, const h8300_length_table *table){ enum h8300_operand_class op1_class, op2_class; unsigned int size, immediate_length; size = GET_MODE_SIZE (GET_MODE (op1)); immediate_length = (h8300_classify_operand (op1, size, &op1_class) + h8300_classify_operand (op2, size, &op2_class)); return immediate_length + (*table)[op1_class - 1][op2_class];}/* Return the length of a unary instruction such as neg or not given that its operand is OP. */unsigned inth8300_unary_length (rtx op){ enum h8300_operand_class class; unsigned int size, operand_length; size = GET_MODE_SIZE (GET_MODE (op)); operand_length = h8300_classify_operand (op, size, &class); switch (class) { case H8OP_REGISTER: return 2; case H8OP_MEM_BASE: return (size == 4 ? 6 : 4); case H8OP_MEM_ABSOLUTE: return operand_length + (size == 4 ? 6 : 4); case H8OP_MEM_COMPLEX: return operand_length + 6; default: gcc_unreachable (); }}/* Likewise short immediate instructions such as add.w #xx:3,OP. */static unsigned inth8300_short_immediate_length (rtx op){ enum h8300_operand_class class; unsigned int size, operand_length; size = GET_MODE_SIZE (GET_MODE (op)); operand_length = h8300_classify_operand (op, size, &class); switch (class) { case H8OP_REGISTER: return 2; case H8OP_MEM_BASE: case H8OP_MEM_ABSOLUTE: case H8OP_MEM_COMPLEX: return 4 + operand_length; default: gcc_unreachable (); }}/* Likewise bitfield load and store instructions. */static unsigned inth8300_bitfield_length (rtx op, rtx op2){ enum h8300_operand_class class; unsigned int size, operand_length; if (GET_CODE (op) == REG) op = op2; gcc_assert (GET_CODE (op) != REG); size = GET_MODE_SIZE (GET_MODE (op)); operand_length = h8300_classify_operand (op, size, &class); switch (class) { case H8OP_MEM_BASE: case H8OP_MEM_ABSOLUTE: case H8OP_MEM_COMPLEX: return 4 + operand_length; default: gcc_unreachable (); }}/* Calculate the length of general binary instruction INSN using TABLE. */static unsigned inth8300_binary_length (rtx insn, const h8300_length_table *table){ rtx set; set = single_set (insn); gcc_assert (set); if (BINARY_P (SET_SRC (set))) return h8300_length_from_table (XEXP (SET_SRC (set), 0), XEXP (SET_SRC (set), 1), table); else { gcc_assert (GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == RTX_TERNARY); return h8300_length_from_table (XEXP (XEXP (SET_SRC (set), 1), 0), XEXP (XEXP (SET_SRC (set), 1), 1), table); }}/* Subroutine of h8300_move_length. Return true if OP is 1- or 2-byte memory reference and either (1) it has the form @(d:16,Rn) or (2) its address has the code given by INC_CODE. */static boolh8300_short_move_mem_p (rtx op, enum rtx_code inc_code){ rtx addr; unsigned int size; if (GET_CODE (op) != MEM) return false; addr = XEXP (op, 0); size = GET_MODE_SIZE (GET_MODE (op)); if (size != 1 && size != 2) return false; return (GET_CODE (addr) == inc_code || (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == REG && h8300_displacement_length (addr, size) == 2));}/* Calculate the length of move instruction INSN using the given length table. Although the tables are correct for most cases, there is some irregularity in the length of mov.b and mov.w. The following forms: mov @ERs+, Rd mov @(d:16,ERs), Rd mov Rs, @-ERd mov Rs, @(d:16,ERd) are two bytes shorter than most other "mov Rs, @complex" or "mov @complex,Rd" combinations. */static unsigned inth8300_move_length (rtx *operands, const h8300_length_table *table){ unsigned int size; size = h8300_length_from_table (operands[0], operands[1], table); if (REG_P (operands[0]) && h8300_short_move_mem_p (operands[1], POST_INC)) size -= 2; if (REG_P (operands[1]) && h8300_short_move_mem_p (operands[0], PRE_DEC)) size -= 2; return size;}/* Return the length of a mova instruction with the given operands. DEST is the register destination, SRC is the source address and OFFSET is the 16-bit or 32-bit displacement. */static unsigned inth8300_mova_length (rtx dest, rtx src, rtx offset){ unsigned int size; size = (2 + h8300_constant_length (offset) + h8300_classify_operand (src, GET_MODE_SIZE (GET_MODE (src)), 0)); if (!REG_P (dest) || !REG_P (src) || REGNO (src) != REGNO (dest)) size += 2; return size;}/* Compute the length of INSN based on its length_table attribute. OPERANDS is the array of its operands. */unsigned inth8300_insn_length_from_table (rtx insn, rtx * operands){ switch (get_attr_length_table (insn)) { case LENGTH_TABLE_NONE: gcc_unreachable (); case LENGTH_TABLE_ADDB: return h8300_binary_length (insn, &addb_length_table); case LENGTH_TABLE_ADDW: return h8300_binary_length (insn, &addw_length_table); case LENGTH_TABLE_ADDL: return h8300_binary_length (insn, &addl_length_table); case LENGTH_TABLE_LOGICB: return h8300_binary_length (insn, &logicb_length_table); case LENGTH_TABLE_MOVB: return h8300_move_length (operands, &movb_length_table); case LENGTH_TABLE_MOVW: return h8300_move_length (operands, &movw_length_table); case LENGTH_TABLE_MOVL: return h8300_move_length (operands, &movl_length_table); case LENGTH_TABLE_MOVA: return h8300_mova_length (operands[0], operands[1], operands[2]); case LENGTH_TABLE_MOVA_ZERO: return h8300_mova_length (operands[0], operands[1], const0_rtx); case LENGTH_TABLE_UNARY: return h8300_unary_length (operands[0]); case LENGTH_TABLE_MOV_IMM4: return 2 + h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -