📄 h8300.c
字号:
} default: break; } }}/* Output assembly language output for the address ADDR to FILE. */voidprint_operand_address (FILE *file, rtx addr){ rtx index; int size; switch (GET_CODE (addr)) { case REG: fprintf (file, "%s", h8_reg_names[REGNO (addr)]); break; case PRE_DEC: fprintf (file, "-%s", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case POST_INC: fprintf (file, "%s+", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case PRE_INC: fprintf (file, "+%s", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case POST_DEC: fprintf (file, "%s-", h8_reg_names[REGNO (XEXP (addr, 0))]); break; case PLUS: fprintf (file, "("); index = h8300_get_index (XEXP (addr, 0), VOIDmode, &size); if (GET_CODE (index) == REG) { /* reg,foo */ print_operand_address (file, XEXP (addr, 1)); fprintf (file, ","); switch (size) { case 0: print_operand_address (file, index); break; case 1: print_operand (file, index, 'X'); fputs (".b", file); break; case 2: print_operand (file, index, 'T'); fputs (".w", file); break; case 4: print_operand (file, index, 'S'); fputs (".l", file); break; } /* print_operand_address (file, XEXP (addr, 0)); */ } else { /* foo+k */ print_operand_address (file, XEXP (addr, 0)); fprintf (file, "+"); print_operand_address (file, XEXP (addr, 1)); } fprintf (file, ")"); break; case CONST_INT: { /* Since the H8/300 only has 16 bit pointers, negative values are also those >= 32768. This happens for example with pointer minus a constant. We don't want to turn (char *p - 2) into (char *p + 65534) because loop unrolling can build upon this (IE: char *p + 131068). */ int n = INTVAL (addr); if (TARGET_H8300) n = (int) (short) n; fprintf (file, "%d", n); break; } default: output_addr_const (file, addr); break; }}/* Output all insn addresses and their sizes into the assembly language output file. This is helpful for debugging whether the length attributes in the md file are correct. This is not meant to be a user selectable option. */voidfinal_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED, int num_operands ATTRIBUTE_UNUSED){ /* This holds the last insn address. */ static int last_insn_address = 0; const int uid = INSN_UID (insn); if (TARGET_ADDRESSES) { fprintf (asm_out_file, "; 0x%x %d\n", INSN_ADDRESSES (uid), INSN_ADDRESSES (uid) - last_insn_address); last_insn_address = INSN_ADDRESSES (uid); }}/* Prepare for an SI sized move. */inth8300_expand_movsi (rtx operands[]){ rtx src = operands[1]; rtx dst = operands[0]; if (!reload_in_progress && !reload_completed) { if (!register_operand (dst, GET_MODE (dst))) { rtx tmp = gen_reg_rtx (GET_MODE (dst)); emit_move_insn (tmp, src); operands[1] = tmp; } } return 0;}/* Function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */inth8300_initial_elimination_offset (int from, int to){ /* The number of bytes that the return address takes on the stack. */ int pc_size = POINTER_SIZE / BITS_PER_UNIT; /* The number of bytes that the saved frame pointer takes on the stack. */ int fp_size = frame_pointer_needed * UNITS_PER_WORD; /* The number of bytes that the saved registers, excluding the frame pointer, take on the stack. */ int saved_regs_size = 0; /* The number of bytes that the locals takes on the stack. */ int frame_size = round_frame_size (get_frame_size ()); int regno; for (regno = 0; regno <= HARD_FRAME_POINTER_REGNUM; regno++) if (WORD_REG_USED (regno)) saved_regs_size += UNITS_PER_WORD; /* Adjust saved_regs_size because the above loop took the frame pointer int account. */ saved_regs_size -= fp_size; if (to == HARD_FRAME_POINTER_REGNUM) { switch (from) { case ARG_POINTER_REGNUM: return pc_size + fp_size; case RETURN_ADDRESS_POINTER_REGNUM: return fp_size; case FRAME_POINTER_REGNUM: return -saved_regs_size; default: abort (); } } else if (to == STACK_POINTER_REGNUM) { switch (from) { case ARG_POINTER_REGNUM: return pc_size + saved_regs_size + frame_size; case RETURN_ADDRESS_POINTER_REGNUM: return saved_regs_size + frame_size; case FRAME_POINTER_REGNUM: return frame_size; default: abort (); } } else abort ();}/* Worker function for RETURN_ADDR_RTX. */rtxh8300_return_addr_rtx (int count, rtx frame){ rtx ret; if (count == 0) ret = gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM)); else if (flag_omit_frame_pointer) return (rtx) 0; else ret = gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (frame, UNITS_PER_WORD))); set_mem_alias_set (ret, get_frame_alias_set ()); return ret;}/* Update the condition code from the insn. */voidnotice_update_cc (rtx body, rtx insn){ rtx set; switch (get_attr_cc (insn)) { case CC_NONE: /* Insn does not affect CC at all. */ break; case CC_NONE_0HIT: /* Insn does not change CC, but the 0'th operand has been changed. */ if (cc_status.value1 != 0 && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1)) cc_status.value1 = 0; if (cc_status.value2 != 0 && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value2)) cc_status.value2 = 0; break; case CC_SET_ZN: /* Insn sets the Z,N flags of CC to recog_data.operand[0]. The V flag is unusable. The C flag may or may not be known but that's ok because alter_cond will change tests to use EQ/NE. */ CC_STATUS_INIT; cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY; set = single_set (insn); cc_status.value1 = SET_SRC (set); if (SET_DEST (set) != cc0_rtx) cc_status.value2 = SET_DEST (set); break; case CC_SET_ZNV: /* Insn sets the Z,N,V flags of CC to recog_data.operand[0]. The C flag may or may not be known but that's ok because alter_cond will change tests to use EQ/NE. */ CC_STATUS_INIT; cc_status.flags |= CC_NO_CARRY; set = single_set (insn); cc_status.value1 = SET_SRC (set); if (SET_DEST (set) != cc0_rtx) { /* If the destination is STRICT_LOW_PART, strip off STRICT_LOW_PART. */ 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; }}/* Return nonzero if X is a stack pointer. */intstack_pointer_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return x == stack_pointer_rtx;}/* Return nonzero if X is a constant whose absolute value is greater than 2. */intconst_int_gt_2_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (x) == CONST_INT && abs (INTVAL (x)) > 2);}/* Return nonzero if X is a constant whose absolute value is no smaller than 8. */intconst_int_ge_8_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (x) == CONST_INT && abs (INTVAL (x)) >= 8);}/* Return nonzero if X is a constant expressible in QImode. */intconst_int_qi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (x) == CONST_INT && (INTVAL (x) & 0xff) == INTVAL (x));}/* Return nonzero if X is a constant expressible in HImode. */intconst_int_hi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (x) == CONST_INT && (INTVAL (x) & 0xffff) == INTVAL (x));}/* Return nonzero if X is a constant suitable for inc/dec. */intincdec_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (x) == CONST_INT && (CONST_OK_FOR_M (INTVAL (x)) || CONST_OK_FOR_O (INTVAL (x))));}/* Return nonzero if X is either EQ or NE. */inteqne_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ enum rtx_code code = GET_CODE (x); return (code == EQ || code == NE);}/* Return nonzero if X is either GT or LE. */intgtle_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ enum rtx_code code = GET_CODE (x); return (code == GT || code == LE);}/* Return nonzero if X is either GTU or LEU. */intgtuleu_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ enum rtx_code code = GET_CODE (x); return (code == GTU || code == LEU);}/* Return nonzero if X is either IOR or XOR. */intiorxor_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ enum rtx_code code = GET_CODE (x); return (code == IOR || code == XOR);}/* Recognize valid operators for bit instructions. */intbit_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ enum rtx_code code = GET_CODE (x); return (code == XOR || code == AND || code == IOR);}/* 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -