📄 h8300.c
字号:
break; default: break; } break; case 'e': switch (GET_CODE (x)) { case REG: if (TARGET_H8300) fprintf (file, "%s", names_big[REGNO (x)]); else fprintf (file, "%s", names_upper_extended[REGNO (x)]); break; case MEM: print_operand (file, x, 0); break; case CONST_INT: fprintf (file, "#%ld", ((INTVAL (x) >> 16) & 0xffff)); break; case CONST_DOUBLE: { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); fprintf (file, "#%ld", ((val >> 16) & 0xffff)); break; } default: gcc_unreachable (); break; } break; case 'f': switch (GET_CODE (x)) { case REG: if (TARGET_H8300) fprintf (file, "%s", names_big[REGNO (x) + 1]); else fprintf (file, "%s", names_big[REGNO (x)]); break; case MEM: x = adjust_address (x, HImode, 2); print_operand (file, x, 0); break; case CONST_INT: fprintf (file, "#%ld", INTVAL (x) & 0xffff); break; case CONST_DOUBLE: { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); fprintf (file, "#%ld", (val & 0xffff)); break; } default: gcc_unreachable (); } break; case 'j': fputs (cond_string (GET_CODE (x)), file); break; case 'k': fputs (cond_string (reverse_condition (GET_CODE (x))), file); break; case 'm': gcc_assert (GET_CODE (x) == CONST_INT); switch (INTVAL (x)) { case 1: fputs (".b", file); break; case 2: fputs (".w", file); break; case 4: fputs (".l", file); break; default: gcc_unreachable (); } break; case 'o': print_operand_address (file, x); break; case 's': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", (INTVAL (x)) & 0xff); else fprintf (file, "%s", byte_reg (x, 0)); break; case 't': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", (INTVAL (x) >> 8) & 0xff); else fprintf (file, "%s", byte_reg (x, 1)); break; case 'w': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", INTVAL (x) & 0xff); else fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 2 : 0)); break; case 'x': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", (INTVAL (x) >> 8) & 0xff); else fprintf (file, "%s", byte_reg (x, TARGET_H8300 ? 3 : 1)); break; case 'y': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", (INTVAL (x) >> 16) & 0xff); else fprintf (file, "%s", byte_reg (x, 0)); break; case 'z': if (GET_CODE (x) == CONST_INT) fprintf (file, "#%ld", (INTVAL (x) >> 24) & 0xff); else fprintf (file, "%s", byte_reg (x, 1)); break; default: def: switch (GET_CODE (x)) { case REG: switch (GET_MODE (x)) { case QImode:#if 0 /* Is it asm ("mov.b %0,r2l", ...) */ fprintf (file, "%s", byte_reg (x, 0));#else /* ... or is it asm ("mov.b %0l,r2l", ...) */ fprintf (file, "%s", names_big[REGNO (x)]);#endif break; case HImode: fprintf (file, "%s", names_big[REGNO (x)]); break; case SImode: case SFmode: fprintf (file, "%s", names_extended[REGNO (x)]); break; default: gcc_unreachable (); } break; case MEM: { rtx addr = XEXP (x, 0); fprintf (file, "@"); output_address (addr); /* Add a length suffix to constant addresses. Although this is often unnecessary, it helps to avoid ambiguity in the syntax of mova. If we wrote an insn like: mova/w.l @(1,@foo.b),er0 then .b would be considered part of the symbol name. Adding a length after foo will avoid this. */ if (CONSTANT_P (addr)) switch (code) { case 'R': /* Used for mov.b and bit operations. */ if (h8300_eightbit_constant_address_p (addr)) { fprintf (file, ":8"); break; } /* Fall through. We should not get here if we are processing bit operations on H8/300 or H8/300H because 'U' constraint does not allow bit operations on the tiny area on these machines. */ case 'X': case 'T': case 'S': if (h8300_constant_length (addr) == 2) fprintf (file, ":16"); else fprintf (file, ":32"); break; default: break; } } break; case CONST_INT: case SYMBOL_REF: case CONST: case LABEL_REF: fprintf (file, "#"); print_operand_address (file, x); break; case CONST_DOUBLE: { long val; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, val); fprintf (file, "#%ld", val); break; } 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; switch (to) { case 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: gcc_unreachable (); } break; case 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: gcc_unreachable (); } break; default: gcc_unreachable (); } gcc_unreachable ();}/* 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -