📄 h8300.c
字号:
{ HOST_WIDE_INT val = INTVAL (operands[1]); rtx reg = operands[0]; HOST_WIDE_INT sign = 1; HOST_WIDE_INT amount; rtx (*gen_add) (rtx, rtx, rtx); /* Force VAL to be positive so that we do not have to consider the sign. */ if (val < 0) { val = -val; sign = -1; } switch (mode) { case HImode: gen_add = gen_addhi3; break; case SImode: gen_add = gen_addsi3; break; default: gcc_unreachable (); } /* Try different amounts in descending order. */ for (amount = (TARGET_H8300H || TARGET_H8300S) ? 4 : 2; amount > 0; amount /= 2) { for (; val >= amount; val -= amount) emit_insn (gen_add (reg, reg, GEN_INT (sign * amount))); } return;}/* Handle machine specific pragmas for compatibility with existing compilers for the H8/300. pragma saveall generates prologue/epilogue code which saves and restores all the registers on function entry. pragma interrupt saves and restores all registers, and exits with an rte instruction rather than an rts. A pointer to a function with this attribute may be safely used in an interrupt vector. */voidh8300_pr_interrupt (struct cpp_reader *pfile ATTRIBUTE_UNUSED){ pragma_interrupt = 1;}voidh8300_pr_saveall (struct cpp_reader *pfile ATTRIBUTE_UNUSED){ pragma_saveall = 1;}/* If the next function argument with MODE and TYPE is to be passed in a register, return a reg RTX for the hard register in which to pass the argument. CUM represents the state after the last argument. If the argument is to be pushed, NULL_RTX is returned. */rtxfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named){ static const char *const hand_list[] = { "__main", "__cmpsi2", "__divhi3", "__modhi3", "__udivhi3", "__umodhi3", "__divsi3", "__modsi3", "__udivsi3", "__umodsi3", "__mulhi3", "__mulsi3", "__reg_memcpy", "__reg_memset", "__ucmpsi2", 0, }; rtx result = NULL_RTX; const char *fname; int regpass = 0; /* Never pass unnamed arguments in registers. */ if (!named) return NULL_RTX; /* Pass 3 regs worth of data in regs when user asked on the command line. */ if (TARGET_QUICKCALL) regpass = 3; /* If calling hand written assembler, use 4 regs of args. */ if (cum->libcall) { const char * const *p; fname = XSTR (cum->libcall, 0); /* See if this libcall is one of the hand coded ones. */ for (p = hand_list; *p && strcmp (*p, fname) != 0; p++) ; if (*p) regpass = 4; } if (regpass) { int size; if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); if (size + cum->nbytes <= regpass * UNITS_PER_WORD && cum->nbytes / UNITS_PER_WORD <= 3) result = gen_rtx_REG (mode, cum->nbytes / UNITS_PER_WORD); } return result;}/* Compute the cost of an and insn. */static inth8300_and_costs (rtx x){ rtx operands[4]; if (GET_MODE (x) == QImode) return 1; if (GET_MODE (x) != HImode && GET_MODE (x) != SImode) return 100; operands[0] = NULL; operands[1] = XEXP (x, 0); operands[2] = XEXP (x, 1); operands[3] = x; return compute_logical_op_length (GET_MODE (x), operands) / 2;}/* Compute the cost of a shift insn. */static inth8300_shift_costs (rtx x){ rtx operands[4]; if (GET_MODE (x) != QImode && GET_MODE (x) != HImode && GET_MODE (x) != SImode) return 100; operands[0] = NULL; operands[1] = NULL; operands[2] = XEXP (x, 1); operands[3] = x; return compute_a_shift_length (NULL, operands) / 2;}/* Worker function for TARGET_RTX_COSTS. */static boolh8300_rtx_costs (rtx x, int code, int outer_code, int *total){ if (TARGET_H8300SX && outer_code == MEM) { /* Estimate the number of execution states needed to calculate the address. */ if (register_operand (x, VOIDmode) || GET_CODE (x) == POST_INC || GET_CODE (x) == POST_DEC || CONSTANT_P (x)) *total = 0; else *total = COSTS_N_INSNS (1); return true; } switch (code) { case CONST_INT: { HOST_WIDE_INT n = INTVAL (x); if (TARGET_H8300SX) { /* Constant operands need the same number of processor states as register operands. Although we could try to use a size-based cost for optimize_size, the lack of of a mode makes the results very unpredictable. */ *total = 0; return true; } if (-4 <= n || n <= 4) { switch ((int) n) { case 0: *total = 0; return true; case 1: case 2: case -1: case -2: *total = 0 + (outer_code == SET); return true; case 4: case -4: if (TARGET_H8300H || TARGET_H8300S) *total = 0 + (outer_code == SET); else *total = 1; return true; } } *total = 1; return true; } case CONST: case LABEL_REF: case SYMBOL_REF: if (TARGET_H8300SX) { /* See comment for CONST_INT. */ *total = 0; return true; } *total = 3; return true; case CONST_DOUBLE: *total = 20; return true; case AND: if (!h8300_dst_operand (XEXP (x, 0), VOIDmode) || !h8300_src_operand (XEXP (x, 1), VOIDmode)) return false; *total = COSTS_N_INSNS (h8300_and_costs (x)); return true; /* We say that MOD and DIV are so expensive because otherwise we'll generate some really horrible code for division of a power of two. */ case MOD: case DIV: case UMOD: case UDIV: if (TARGET_H8300SX) switch (GET_MODE (x)) { case QImode: case HImode: *total = COSTS_N_INSNS (optimize_size ? 4 : 10); return false; case SImode: *total = COSTS_N_INSNS (optimize_size ? 4 : 18); return false; default: break; } *total = COSTS_N_INSNS (12); return true; case MULT: if (TARGET_H8300SX) switch (GET_MODE (x)) { case QImode: case HImode: *total = COSTS_N_INSNS (2); return false; case SImode: *total = COSTS_N_INSNS (5); return false; default: break; } *total = COSTS_N_INSNS (4); return true; case ASHIFT: case ASHIFTRT: case LSHIFTRT: if (h8sx_binary_shift_operator (x, VOIDmode)) { *total = COSTS_N_INSNS (2); return false; } else if (h8sx_unary_shift_operator (x, VOIDmode)) { *total = COSTS_N_INSNS (1); return false; } *total = COSTS_N_INSNS (h8300_shift_costs (x)); return true; case ROTATE: case ROTATERT: if (GET_MODE (x) == HImode) *total = 2; else *total = 8; return true; default: *total = COSTS_N_INSNS (1); return false; }}/* Documentation for the machine specific operand escapes: 'E' like s but negative. 'F' like t but negative. 'G' constant just the negative 'R' print operand as a byte:8 address if appropriate, else fall back to 'X' handling. 'S' print operand as a long word 'T' print operand as a word 'V' find the set bit, and print its number. 'W' find the clear bit, and print its number. 'X' print operand as a byte 'Y' print either l or h depending on whether last 'Z' operand < 8 or >= 8. If this operand isn't a register, fall back to 'R' handling. 'Z' print int & 7. 'c' print the opcode corresponding to rtl 'e' first word of 32 bit value - if reg, then least reg. if mem then least. if const then most sig word 'f' second word of 32 bit value - if reg, then biggest reg. if mem then +2. if const then least sig word 'j' print operand as condition code. 'k' print operand as reverse condition code. 'm' convert an integer operand to a size suffix (.b, .w or .l) 'o' print an integer without a leading '#' 's' print as low byte of 16 bit value 't' print as high byte of 16 bit value 'w' print as low byte of 32 bit value 'x' print as 2nd byte of 32 bit value 'y' print as 3rd byte of 32 bit value 'z' print as msb of 32 bit value*//* Return assembly language string which identifies a comparison type. */static const char *cond_string (enum rtx_code code){ switch (code) { case NE: return "ne"; case EQ: return "eq"; case GE: return "ge"; case GT: return "gt"; case LE: return "le"; case LT: return "lt"; case GEU: return "hs"; case GTU: return "hi"; case LEU: return "ls"; case LTU: return "lo"; default: gcc_unreachable (); }}/* Print operand X using operand code CODE to assembly language output file FILE. */voidprint_operand (FILE *file, rtx x, int code){ /* This is used for communication between codes V,W,Z and Y. */ static int bitint; switch (code) { case 'E': switch (GET_CODE (x)) { case REG: fprintf (file, "%sl", names_big[REGNO (x)]); break; case CONST_INT: fprintf (file, "#%ld", (-INTVAL (x)) & 0xff); break; default: gcc_unreachable (); } break; case 'F': switch (GET_CODE (x)) { case REG: fprintf (file, "%sh", names_big[REGNO (x)]); break; case CONST_INT: fprintf (file, "#%ld", ((-INTVAL (x)) & 0xff00) >> 8); break; default: gcc_unreachable (); } break; case 'G': gcc_assert (GET_CODE (x) == CONST_INT); fprintf (file, "#%ld", 0xff & (-INTVAL (x))); break; case 'S': if (GET_CODE (x) == REG) fprintf (file, "%s", names_extended[REGNO (x)]); else goto def; break; case 'T': if (GET_CODE (x) == REG) fprintf (file, "%s", names_big[REGNO (x)]); else goto def; break; case 'V': bitint = exact_log2 (INTVAL (x) & 0xff); gcc_assert (bitint >= 0); fprintf (file, "#%d", bitint); break; case 'W': bitint = exact_log2 ((~INTVAL (x)) & 0xff); gcc_assert (bitint >= 0); fprintf (file, "#%d", bitint); break; case 'R': case 'X': if (GET_CODE (x) == REG) fprintf (file, "%s", byte_reg (x, 0)); else goto def; break; case 'Y': gcc_assert (bitint >= 0); if (GET_CODE (x) == REG) fprintf (file, "%s%c", names_big[REGNO (x)], bitint > 7 ? 'h' : 'l'); else print_operand (file, x, 'R'); bitint = -1; break; case 'Z': bitint = INTVAL (x); fprintf (file, "#%d", bitint & 7); break; case 'c': switch (GET_CODE (x)) { case IOR: fprintf (file, "or"); break; case XOR: fprintf (file, "xor"); break; case AND: fprintf (file, "and");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -