📄 h8300.c
字号:
emit_insn (gen_rtx_RETURN (VOIDmode));}/* Return nonzero if the current function is an interrupt function. */inth8300_current_function_interrupt_function_p (void){ return (h8300_interrupt_function_p (current_function_decl) || h8300_monitor_function_p (current_function_decl));}/* Output assembly code for the start of the file. */static voidh8300_file_start (void){ default_file_start (); if (TARGET_H8300H) fputs (TARGET_NORMAL_MODE ? "\t.h8300hn\n" : "\t.h8300h\n", asm_out_file); else if (TARGET_H8300SX) fputs (TARGET_NORMAL_MODE ? "\t.h8300sxn\n" : "\t.h8300sx\n", asm_out_file); else if (TARGET_H8300S) fputs (TARGET_NORMAL_MODE ? "\t.h8300sn\n" : "\t.h8300s\n", asm_out_file);}/* Output assembly language code for the end of file. */static voidh8300_file_end (void){ fputs ("\t.end\n", asm_out_file);}/* Return true if OP is a valid source operand for an integer move instruction. */intgeneral_operand_src (rtx op, enum machine_mode mode){ if (GET_MODE (op) == mode && GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC) return 1; return general_operand (op, mode);}/* Return true if OP is a valid destination operand for an integer move instruction. */intgeneral_operand_dst (rtx op, enum machine_mode mode){ if (GET_MODE (op) == mode && GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC) return 1; return general_operand (op, mode);}/* Return true if OP is a suitable first operand for a general arithmetic insn such as "add". */inth8300_dst_operand (rtx op, enum machine_mode mode){ if (TARGET_H8300SX) return nonimmediate_operand (op, mode); return register_operand (op, mode);}/* Likewise the second operand. */inth8300_src_operand (rtx op, enum machine_mode mode){ if (TARGET_H8300SX) return general_operand (op, mode); return nonmemory_operand (op, mode);}/* Check that an operand is either a register or an unsigned 4-bit constant. */intnibble_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == CONST_INT && TARGET_H8300SX && INTVAL (op) >= 0 && INTVAL (op) <= 15);}/* Check that an operand is either a register or an unsigned 4-bit constant. */intreg_or_nibble_operand (rtx op, enum machine_mode mode){ return (nibble_operand (op, mode) || register_operand (op, mode));}/* Return true if OP is a constant that contains only one 1 in its binary representation. */intsingle_one_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (operand) == CONST_INT) { /* We really need to do this masking because 0x80 in QImode is represented as -128 for example. */ if (exact_log2 (INTVAL (operand) & GET_MODE_MASK (mode)) >= 0) return 1; } return 0;}/* Return true if OP is a constant that contains only one 0 in its binary representation. */intsingle_zero_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (operand) == CONST_INT) { /* We really need to do this masking because 0x80 in QImode is represented as -128 for example. */ if (exact_log2 (~INTVAL (operand) & GET_MODE_MASK (mode)) >= 0) return 1; } return 0;}/* Return true if OP is a valid call operand. */intcall_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); if (register_operand (inside, Pmode)) return 1; if (CONSTANT_ADDRESS_P (inside)) return 1; } return 0;}/* Return 1 if an addition/subtraction of a constant integer can be transformed into two consecutive adds/subs that are faster than the straightforward way. Otherwise, return 0. */inttwo_insn_adds_subs_operand (rtx op, enum machine_mode mode){ if (TARGET_H8300SX) return 0; if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT value = INTVAL (op); /* Force VALUE to be positive so that we do not have to consider the negative case. */ if (value < 0) value = -value; if (TARGET_H8300H || TARGET_H8300S) { /* A constant addition/subtraction takes 2 states in QImode, 4 states in HImode, and 6 states in SImode. Thus, the only case we can win is when SImode is used, in which case, two adds/subs are used, taking 4 states. */ if (mode == SImode && (value == 2 + 1 || value == 4 + 1 || value == 4 + 2 || value == 4 + 4)) return 1; } else { /* We do not profit directly by splitting addition or subtraction of 3 and 4. However, since these are implemented as a sequence of adds or subs, they do not clobber (cc0) unlike a sequence of add.b and add.x. */ if (mode == HImode && (value == 2 + 1 || value == 2 + 2)) return 1; } } return 0;}/* Split an add of a small constant into two adds/subs insns. If USE_INCDEC_P is nonzero, we generate the last insn using inc/dec instead of adds/subs. */voidsplit_adds_subs (enum machine_mode mode, rtx *operands){ 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: abort (); } /* 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;}/* Return true if OP is a valid call operand, and OP represents an operand for a small call (4 bytes instead of 6 bytes). */intsmall_call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); /* Register indirect is a small call. */ if (register_operand (inside, Pmode)) return 1; /* A call through the function vector is a small call too. */ if (GET_CODE (inside) == SYMBOL_REF && (SYMBOL_REF_FLAGS (inside) & SYMBOL_FLAG_FUNCVEC_FUNCTION)) return 1; } /* Otherwise it's a large call. */ return 0;}/* Return true if OP is a valid jump operand. */intjump_address_operand (rtx op, enum machine_mode mode){ if (GET_CODE (op) == REG) return mode == Pmode; if (GET_CODE (op) == MEM) { rtx inside = XEXP (op, 0); if (register_operand (inside, Pmode)) return 1; if (CONSTANT_ADDRESS_P (inside)) return 1; } return 0;}/* Recognize valid operands for bit-field instructions. */intbit_operand (rtx op, enum machine_mode mode){ /* We can accept any nonimmediate operand, except that MEM operands must be limited to those that use addresses valid for the 'U' constraint. */ if (!nonimmediate_operand (op, mode)) return 0; /* H8SX accepts pretty much anything here. */ if (TARGET_H8300SX) return 1; /* Accept any mem during RTL generation. Otherwise, the code that does insv and extzv will think that we cannot handle memory. However, to avoid reload problems, we only accept 'U' MEM operands after RTL generation. This means that any named pattern which uses this predicate must force its operands to match 'U' before emitting RTL. */ if (GET_CODE (op) == REG) return 1; if (GET_CODE (op) == SUBREG) return 1; return (GET_CODE (op) == MEM && OK_FOR_U (op));}/* Return nonzero if OP is a MEM suitable for bit manipulation insns. */intbit_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == MEM && OK_FOR_U (op));}/* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -