📄 m32r.c
字号:
voidm32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int *pretend_size; int no_rtl;{ int first_anon_arg; if (no_rtl) return; /* All BLKmode values are passed by reference. */ if (mode == BLKmode) abort (); first_anon_arg = (ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type)); if (first_anon_arg < M32R_MAX_PARM_REGS) { /* Note that first_reg_offset < M32R_MAX_PARM_REGS. */ int first_reg_offset = first_anon_arg; /* Size in words to "pretend" allocate. */ int size = M32R_MAX_PARM_REGS - first_reg_offset; rtx regblock; regblock = gen_rtx_MEM (BLKmode, plus_constant (arg_pointer_rtx, FIRST_PARM_OFFSET (0))); set_mem_alias_set (regblock, get_varargs_alias_set ()); move_block_from_reg (first_reg_offset, regblock, size, size * UNITS_PER_WORD); *pretend_size = (size * UNITS_PER_WORD); }}/* Implement `va_arg'. */rtxm32r_va_arg (valist, type) tree valist, type;{ HOST_WIDE_INT size, rsize; tree t; rtx addr_rtx; size = int_size_in_bytes (type); rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; if (size > 8) { tree type_ptr, type_ptr_ptr; /* Pass by reference. */ type_ptr = build_pointer_type (type); type_ptr_ptr = build_pointer_type (type_ptr); t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, build_int_2 (UNITS_PER_WORD, 0)); TREE_SIDE_EFFECTS (t) = 1; t = build1 (NOP_EXPR, type_ptr_ptr, t); TREE_SIDE_EFFECTS (t) = 1; t = build1 (INDIRECT_REF, type_ptr, t); addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); } else { /* Pass by value. */ if (size < UNITS_PER_WORD) { /* Care for bigendian correction on the aligned address. */ t = build (PLUS_EXPR, ptr_type_node, valist, build_int_2 (rsize - size, 0)); addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); addr_rtx = copy_to_reg (addr_rtx); /* Increment AP. */ t = build (PLUS_EXPR, va_list_type_node, valist, build_int_2 (rsize, 0)); t = build (MODIFY_EXPR, va_list_type_node, valist, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } else { t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, build_int_2 (rsize, 0)); TREE_SIDE_EFFECTS (t) = 1; addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); } } return addr_rtx;}static intm32r_adjust_cost (insn, link, dep_insn, cost) rtx insn ATTRIBUTE_UNUSED; rtx link ATTRIBUTE_UNUSED; rtx dep_insn ATTRIBUTE_UNUSED; int cost;{ return cost;}/* Return true if INSN is real instruction bearing insn. */static intm32r_is_insn (insn) rtx insn;{ return (INSN_P (insn) && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER && GET_CODE (PATTERN (insn)) != ADDR_VEC);}/* Increase the priority of long instructions so that the short instructions are scheduled ahead of the long ones. */static intm32r_adjust_priority (insn, priority) rtx insn; int priority;{ if (m32r_is_insn (insn) && get_attr_insn_size (insn) != INSN_SIZE_SHORT) priority <<= 3; return priority;}/* Initialize for scheduling a group of instructions. */static voidm32r_sched_init (stream, verbose, max_ready) FILE * stream ATTRIBUTE_UNUSED; int verbose ATTRIBUTE_UNUSED; int max_ready ATTRIBUTE_UNUSED;{ m32r_sched_odd_word_p = FALSE;}/* Reorder the schedulers priority list if needed */static intm32r_sched_reorder (stream, verbose, ready, n_readyp, clock) FILE * stream; int verbose; rtx * ready; int *n_readyp; int clock ATTRIBUTE_UNUSED;{ int n_ready = *n_readyp; if (TARGET_DEBUG) return m32r_issue_rate (); if (verbose <= 7) stream = (FILE *)0; if (stream) fprintf (stream, ";;\t\t::: Looking at %d insn(s) on ready list, boundary is %s word\n", n_ready, (m32r_sched_odd_word_p) ? "odd" : "even"); if (n_ready > 1) { rtx * long_head = (rtx *) alloca (sizeof (rtx) * n_ready); rtx * long_tail = long_head; rtx * short_head = (rtx *) alloca (sizeof (rtx) * n_ready); rtx * short_tail = short_head; rtx * new_head = (rtx *) alloca (sizeof (rtx) * n_ready); rtx * new_tail = new_head + (n_ready - 1); int i; /* Loop through the instructions, classifing them as short/long. Try to keep 2 short together and/or 1 long. Note, the ready list is actually ordered backwards, so keep it in that manner. */ for (i = n_ready-1; i >= 0; i--) { rtx insn = ready[i]; if (! m32r_is_insn (insn)) { /* Dump all current short/long insns just in case. */ while (long_head != long_tail) *new_tail-- = *long_head++; while (short_head != short_tail) *new_tail-- = *short_head++; *new_tail-- = insn; if (stream) fprintf (stream, ";;\t\t::: Skipping non instruction %d\n", INSN_UID (insn)); } else { if (get_attr_insn_size (insn) != INSN_SIZE_SHORT) *long_tail++ = insn; else *short_tail++ = insn; } } /* If we are on an odd word, emit a single short instruction if we can */ if (m32r_sched_odd_word_p && short_head != short_tail) *new_tail-- = *short_head++; /* Now dump out all of the long instructions */ while (long_head != long_tail) *new_tail-- = *long_head++; /* Now dump out all of the short instructions */ while (short_head != short_tail) *new_tail-- = *short_head++; if (new_tail+1 != new_head) abort (); memcpy (ready, new_head, sizeof (rtx) * n_ready); if (stream) { int i; fprintf (stream, ";;\t\t::: New ready list: "); for (i = 0; i < n_ready; i++) { rtx insn = ready[i]; fprintf (stream, " %d", INSN_UID (ready[i])); if (! m32r_is_insn (insn)) fputs ("(?)", stream); else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT) fputs ("(l)", stream); else fputs ("(s)", stream); } fprintf (stream, "\n"); } } return m32r_issue_rate ();}/* Indicate how many instructions can be issued at the same time. This is sort of a lie. The m32r can issue only 1 long insn at once, but it can issue 2 short insns. The default therefore is set at 2, but this can be overridden by the command line option -missue-rate=1 */static intm32r_issue_rate (){ return ((TARGET_LOW_ISSUE_RATE) ? 1 : 2);}/* If we have a machine that can issue a variable # of instructions per cycle, indicate how many more instructions can be issued after the current one. */static intm32r_variable_issue (stream, verbose, insn, how_many) FILE * stream; int verbose; rtx insn; int how_many;{ int orig_odd_word_p = m32r_sched_odd_word_p; int short_p = FALSE; how_many--; if (how_many > 0 && !TARGET_DEBUG) { if (! m32r_is_insn (insn)) how_many++; else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT) { how_many = 0; m32r_sched_odd_word_p = 0; } else { m32r_sched_odd_word_p = !m32r_sched_odd_word_p; short_p = TRUE; } } if (verbose > 7 && stream) fprintf (stream, ";;\t\t::: %s insn %d starts on an %s word, can emit %d more instruction(s)\n", short_p ? "short" : "long", INSN_UID (insn), orig_odd_word_p ? "odd" : "even", how_many); return how_many;}/* Cost functions. *//* Provide the costs of an addressing mode that contains ADDR. If ADDR is not a valid address, its cost is irrelevant. This function is trivial at the moment. This code doesn't live in m32r.h so it's easy to experiment. */intm32r_address_cost (addr) rtx addr ATTRIBUTE_UNUSED;{ return 1;}/* Type of function DECL. The result is cached. To reset the cache at the end of a function, call with DECL = NULL_TREE. */enum m32r_function_typem32r_compute_function_type (decl) tree decl;{ /* Cached value. */ static enum m32r_function_type fn_type = M32R_FUNCTION_UNKNOWN; /* Last function we were called for. */ static tree last_fn = NULL_TREE; /* Resetting the cached value? */ if (decl == NULL_TREE) { fn_type = M32R_FUNCTION_UNKNOWN; last_fn = NULL_TREE; return fn_type; } if (decl == last_fn && fn_type != M32R_FUNCTION_UNKNOWN) return fn_type; /* Compute function type. */ fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE ? M32R_FUNCTION_INTERRUPT : M32R_FUNCTION_NORMAL); last_fn = decl; return fn_type;}/* Function prologue/epilogue handlers. *//* M32R stack frames look like: Before call After call +-----------------------+ +-----------------------+ | | | | high | local variables, | | local variables, | mem | reg save area, etc. | | reg save area, etc. | | | | | +-----------------------+ +-----------------------+ | | | | | arguments on stack. | | arguments on stack. | | | | | SP+0->+-----------------------+ +-----------------------+ | reg parm save area, | | only created for | | variable argument | | functions | +-----------------------+ | previous frame ptr | +-----------------------+ | | | register save area | | | +-----------------------+ | return address | +-----------------------+ | | | local variables | | | +-----------------------+ | | | alloca allocations | | | +-----------------------+ | | low | arguments on stack | memory | | SP+0->+-----------------------+ Notes:1) The "reg parm save area" does not exist for non variable argument fns.2) The "reg parm save area" can be eliminated completely if we saved regs containing anonymous args separately but that complicates things too much (so it's not done).3) The return address is saved after the register save area so as to have as many insns as possible between the restoration of `lr' and the `jmp lr'.*//* Structure to be filled in by m32r_compute_frame_size with register save masks, and offsets for the current function. */struct m32r_frame_info{ unsigned int total_size; /* # bytes that the entire frame takes up */ unsigned int extra_size; /* # bytes of extra stuff */ unsigned int pretend_size; /* # bytes we push and pretend caller did */ unsigned int args_size; /* # bytes that outgoing arguments take up */ unsigned int reg_size; /* # bytes needed to store regs */ unsigned int var_size; /* # bytes that variables take up */ unsigned int gmask; /* mask of saved gp registers */ unsigned int save_fp; /* nonzero if fp must be saved */ unsigned int save_lr; /* nonzero if lr (return addr) must be saved */ int initialized; /* nonzero if frame size already calculated */};/* Current frame information calculated by m32r_compute_frame_size. */static struct m32r_frame_info current_frame_info;/* Zero structure to initialize current_frame_info. */static struct m32r_frame_info zero_frame_info;#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))/* Tell prologue and epilogue if register REGNO should be saved / restored. The return address and frame pointer are treated separately. Don't consider them here. */#define MUST_SAVE_REGISTER(regno, interrupt_p) \((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \ && (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p)))#define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM] || current_function_profile)#define SHORT_INSN_SIZE 2 /* size of small instructions */#define LONG_INSN_SIZE 4 /* size of long instructions *//* Return the bytes needed to compute the frame pointer from the current stack pointer. SIZE is the size needed for local variables. */unsigned intm32r_compute_frame_size (size) int size; /* # of var. bytes allocated. */{ int regno; unsigned int total_size, var_size, args_size, pretend_size, extra_size; unsigned int reg_size, frame_size; unsigned int gmask; enum m32r_function_type fn_type; int interrupt_p; var_size = M32R_STACK_ALIGN (size); args_size = M32R_STACK_ALIGN (current_function_outgoing_args_size); pretend_size = current_function_pretend_args_size; extra_size = FIRST_PARM_OFFSET (0); total_size = extra_size + pretend_size + args_size + var_size; reg_size = 0; gmask = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -