📄 frv.c
字号:
int first = reg_ptr->first; int last = reg_ptr->last; int regno; for (regno = first; regno <= last; regno++) if (info_ptr->save_p[regno] == REG_SAVE_2WORDS && regno != FRAME_POINTER_REGNUM && (regno < FIRST_ARG_REGNUM || regno > LAST_ARG_REGNUM)) { info_ptr->reg_offset[regno] = offset; offset += 2 * UNITS_PER_WORD; } } } /* Calculate the offsets to save normal single registers */ for (range = 0; range < STACK_REGS_MAX; range++) { frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]); if (! reg_ptr->special_p) { int first = reg_ptr->first; int last = reg_ptr->last; int regno; for (regno = first; regno <= last; regno++) if (info_ptr->save_p[regno] == REG_SAVE_1WORD && regno != FRAME_POINTER_REGNUM && (regno < FIRST_ARG_REGNUM || regno > LAST_ARG_REGNUM)) { info_ptr->reg_offset[regno] = offset; offset += UNITS_PER_WORD; } } } /* Calculate the offset to save the local variables at. */ offset = ADDR_ALIGN (offset, alignment); if (info_ptr->vars_size) { info_ptr->vars_offset = offset; offset += info_ptr->vars_size; } /* Align header to a dword-boundary. */ offset = ADDR_ALIGN (offset, 2 * UNITS_PER_WORD); /* Calculate the offsets in the fixed frame. */ info_ptr->save_p[FRAME_POINTER_REGNUM] = REG_SAVE_1WORD; info_ptr->reg_offset[FRAME_POINTER_REGNUM] = offset; info_ptr->regs[STACK_REGS_FP].size_1word = UNITS_PER_WORD; info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD; info_ptr->reg_offset[LR_REGNO] = offset + 2*UNITS_PER_WORD; info_ptr->regs[STACK_REGS_LR].size_1word = UNITS_PER_WORD; if (cfun->returns_struct) { info_ptr->save_p[STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD; info_ptr->reg_offset[STRUCT_VALUE_REGNUM] = offset + UNITS_PER_WORD; info_ptr->regs[STACK_REGS_STRUCT].size_1word = UNITS_PER_WORD; } /* Calculate the offsets to store the arguments passed in registers for stdarg functions. The register pairs are first and the single register if any is last. The register save area starts on a dword-boundary. */ if (info_ptr->stdarg_size) { int first = info_ptr->regs[STACK_REGS_STDARG].first; int last = info_ptr->regs[STACK_REGS_STDARG].last; int regno; /* Skip the header. */ offset += 4 * UNITS_PER_WORD; for (regno = first; regno <= last; regno++) { if (info_ptr->save_p[regno] == REG_SAVE_2WORDS) { info_ptr->reg_offset[regno] = offset; offset += 2 * UNITS_PER_WORD; } else if (info_ptr->save_p[regno] == REG_SAVE_1WORD) { info_ptr->reg_offset[regno] = offset; offset += UNITS_PER_WORD; } } } } if (reload_completed) frv_stack_cache = info_ptr; return info_ptr;}/* Print the information about the frv stack offsets, etc. when debugging. */voidfrv_debug_stack (info) frv_stack_t *info;{ int range; if (!info) info = frv_stack_info (); fprintf (stderr, "\nStack information for function %s:\n", ((current_function_decl && DECL_NAME (current_function_decl)) ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl)) : "<unknown>")); fprintf (stderr, "\ttotal_size\t= %6d\n", info->total_size); fprintf (stderr, "\tvars_size\t= %6d\n", info->vars_size); fprintf (stderr, "\tparam_size\t= %6d\n", info->parameter_size); fprintf (stderr, "\tregs_size\t= %6d, 1w = %3d, 2w = %3d\n", info->regs_size, info->regs_size_1word, info->regs_size_2words); fprintf (stderr, "\theader_size\t= %6d\n", info->header_size); fprintf (stderr, "\tpretend_size\t= %6d\n", info->pretend_size); fprintf (stderr, "\tvars_offset\t= %6d\n", info->vars_offset); fprintf (stderr, "\tregs_offset\t= %6d\n", info->regs_offset); for (range = 0; range < STACK_REGS_MAX; range++) { frv_stack_regs_t *regs = &(info->regs[range]); if ((regs->size_1word + regs->size_2words) > 0) { int first = regs->first; int last = regs->last; int regno; fprintf (stderr, "\t%s\tsize\t= %6d, 1w = %3d, 2w = %3d, save =", regs->name, regs->size_1word + regs->size_2words, regs->size_1word, regs->size_2words); for (regno = first; regno <= last; regno++) { if (info->save_p[regno] == REG_SAVE_1WORD) fprintf (stderr, " %s (%d)", reg_names[regno], info->reg_offset[regno]); else if (info->save_p[regno] == REG_SAVE_2WORDS) fprintf (stderr, " %s-%s (%d)", reg_names[regno], reg_names[regno+1], info->reg_offset[regno]); } fputc ('\n', stderr); } } fflush (stderr);}/* The following variable value is TRUE if the next output insn should finish cpu cycle. In order words the insn will have packing bit (which means absence of asm code suffix `.p' on assembler. */static int frv_insn_packing_flag;/* True if the current function contains a far jump. */static intfrv_function_contains_far_jump (){ rtx insn = get_insns (); while (insn != NULL && !(GET_CODE (insn) == JUMP_INSN /* Ignore tablejump patterns. */ && GET_CODE (PATTERN (insn)) != ADDR_VEC && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC && get_attr_far_jump (insn) == FAR_JUMP_YES)) insn = NEXT_INSN (insn); return (insn != NULL);}/* For the FRV, this function makes sure that a function with far jumps will return correctly. It also does the VLIW packing. */static voidfrv_function_prologue (file, size) FILE *file; HOST_WIDE_INT size ATTRIBUTE_UNUSED;{ /* If no frame was created, check whether the function uses a call instruction to implement a far jump. If so, save the link in gr3 and replace all returns to LR with returns to GR3. GR3 is used because it is call-clobbered, because is not available to the register allocator, and because all functions that take a hidden argument pointer will have a stack frame. */ if (frv_stack_info ()->total_size == 0 && frv_function_contains_far_jump ()) { rtx insn; /* Just to check that the above comment is true. */ if (regs_ever_live[GPR_FIRST + 3]) abort (); /* Generate the instruction that saves the link register. */ fprintf (file, "\tmovsg lr,gr3\n"); /* Replace the LR with GR3 in *return_internal patterns. The insn will now return using jmpl @(gr3,0) rather than bralr. We cannot simply emit a different assembly directive because bralr and jmpl execute in different units. */ for (insn = get_insns(); insn != NULL; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == JUMP_INSN) { rtx pattern = PATTERN (insn); if (GET_CODE (pattern) == PARALLEL && XVECLEN (pattern, 0) >= 2 && GET_CODE (XVECEXP (pattern, 0, 0)) == RETURN && GET_CODE (XVECEXP (pattern, 0, 1)) == USE) { rtx address = XEXP (XVECEXP (pattern, 0, 1), 0); if (GET_CODE (address) == REG && REGNO (address) == LR_REGNO) REGNO (address) = GPR_FIRST + 3; } } } frv_pack_insns (); frv_insn_packing_flag = TRUE;}/* Return the next available temporary register in a given class. */static rtxfrv_alloc_temp_reg (info, class, mode, mark_as_used, no_abort) frv_tmp_reg_t *info; /* which registers are available */ enum reg_class class; /* register class desired */ enum machine_mode mode; /* mode to allocate register with */ int mark_as_used; /* register not available after allocation */ int no_abort; /* return NULL instead of aborting */{ int regno = info->next_reg[ (int)class ]; int orig_regno = regno; HARD_REG_SET *reg_in_class = ®_class_contents[ (int)class ]; int i, nr; for (;;) { if (TEST_HARD_REG_BIT (*reg_in_class, regno) && TEST_HARD_REG_BIT (info->regs, regno)) break; if (++regno >= FIRST_PSEUDO_REGISTER) regno = 0; if (regno == orig_regno) { if (no_abort) return NULL_RTX; else abort (); } } nr = HARD_REGNO_NREGS (regno, mode); info->next_reg[ (int)class ] = regno + nr; if (mark_as_used) for (i = 0; i < nr; i++) CLEAR_HARD_REG_BIT (info->regs, regno+i); return gen_rtx_REG (mode, regno);}/* Return an rtx with the value OFFSET, which will either be a register or a signed 12-bit integer. It can be used as the second operand in an "add" instruction, or as the index in a load or store. The function returns a constant rtx if OFFSET is small enough, otherwise it loads the constant into register OFFSET_REGNO and returns that. */static rtxfrv_frame_offset_rtx (offset) int offset;{ rtx offset_rtx = GEN_INT (offset); if (IN_RANGE_P (offset, -2048, 2047)) return offset_rtx; else { rtx reg_rtx = gen_rtx_REG (SImode, OFFSET_REGNO); if (IN_RANGE_P (offset, -32768, 32767)) emit_insn (gen_movsi (reg_rtx, offset_rtx)); else { emit_insn (gen_movsi_high (reg_rtx, offset_rtx)); emit_insn (gen_movsi_lo_sum (reg_rtx, offset_rtx)); } return reg_rtx; }}/* Generate (mem:MODE (plus:Pmode BASE (frv_frame_offset OFFSET)))). The prologue and epilogue uses such expressions to access the stack. */static rtxfrv_frame_mem (mode, base, offset) enum machine_mode mode; rtx base; int offset;{ return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, base, frv_frame_offset_rtx (offset)));}/* Generate a frame-related expression: (set REG (mem (plus (sp) (const_int OFFSET)))). Such expressions are used in FRAME_RELATED_EXPR notes for more complex instructions. Marking the expressions as frame-related is superfluous if the note contains just a single set. But if the note contains a PARALLEL or SEQUENCE that has several sets, each set must be individually marked as frame-related. */static rtxfrv_dwarf_store (reg, offset) rtx reg; int offset;{ rtx set = gen_rtx_SET (VOIDmode, gen_rtx_MEM (GET_MODE (reg), plus_constant (stack_pointer_rtx, offset)), reg); RTX_FRAME_RELATED_P (set) = 1; return set;}/* Emit a frame-related instruction whose pattern is PATTERN. The instruction is the last in a sequence that cumulatively performs the operation described by DWARF_PATTERN. The instruction is marked as frame-related and has a REG_FRAME_RELATED_EXPR note containing DWARF_PATTERN. */static voidfrv_frame_insn (pattern, dwarf_pattern) rtx pattern; rtx dwarf_pattern;{ rtx insn = emit_insn (pattern); RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf_pattern, REG_NOTES (insn));}/* Emit instructions that transfer REG to or from the memory location (sp + STACK_OFFSET). The register is stored in memory if ACCESSOR->OP is FRV_STORE and loaded if it is FRV_LOAD. Only the prologue uses this function to store registers and only the epilogue uses it to load them. The caller sets up ACCESSOR so that BASE is equal to (sp + BASE_OFFSET). The generated instruction will use BASE as its base register. BASE may simply be the stack pointer, but if several accesses are being made to a region far away from the stack pointer, it may be more efficient to set up a temporary instead. Store instructions will be frame-related and will be annotated with the overall effect of the store. Load instructions will be followed by a (use) to prevent later optimizations from zapping them. The function takes care of the moves to and from SPRs, using TEMP_REGNO as a temporary in such cases. */static voidfrv_frame_access (accessor, reg, stack_offset) frv_frame_accessor_t *accessor; rtx reg; int stack_offset;{ enum machine_mode mode = GET_MODE (reg); rtx mem = frv_frame_mem (mode, accessor->base, stack_offset - accessor->base_offset); if (accessor->op == FRV_LOAD) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -