📄 frv.c
字号:
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 (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 (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 (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 (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 (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) { if (SPR_P (REGNO (reg))) { rtx temp = gen_rtx_REG (mode, TEMP_REGNO); emit_insn (gen_rtx_SET (VOIDmode, temp, mem)); emit_insn (gen_rtx_SET (VOIDmode, reg, temp)); } else emit_insn (gen_rtx_SET (VOIDmode, reg, mem)); emit_insn (gen_rtx_USE (VOIDmode, reg)); } else { if (SPR_P (REGNO (reg))) { rtx temp = gen_rtx_REG (mode, TEMP_REGNO); emit_insn (gen_rtx_SET (VOIDmode, temp, reg)); frv_frame_insn (gen_rtx_SET (Pmode, mem, temp), frv_dwarf_store (reg, stack_offset)); } else if (GET_MODE (reg) == DImode) { /* For DImode saves, the dwarf2 version needs to be a SEQUENCE with a separate save for each register. */ rtx reg1 = gen_rtx_REG (SImode, REGNO (reg)); rtx reg2 = gen_rtx_REG (SImode, REGNO (reg) + 1); rtx set1 = frv_dwarf_store (reg1, stack_offset); rtx set2 = frv_dwarf_store (reg2, stack_offset + 4); frv_frame_insn (gen_rtx_SET (Pmode, mem, reg), gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set1, set2))); } else frv_frame_insn (gen_rtx_SET (Pmode, mem, reg), frv_dwarf_store (reg, stack_offset)); }}/* A function that uses frv_frame_access to transfer a group of registers to or from the stack. ACCESSOR is passed directly to frv_frame_access, INFO is the stack information generated by frv_stack_info, and REG_SET is the number of the register set to transfer. */static voidfrv_frame_access_multi (frv_frame_accessor_t *accessor, frv_stack_t *info, int reg_set){ frv_stack_regs_t *regs_info; int regno; regs_info = &info->regs[reg_set]; for (regno = regs_info->first; regno <= regs_info->last; regno++) if (info->save_p[regno]) frv_frame_access (accessor, info->save_p[regno] == REG_SAVE_2WORDS ? gen_rtx_REG (DImode, regno) : gen_rtx_REG (SImode, regno), info->reg_offset[regno]);}/* Save or restore callee-saved registers that are kept outside the frame header. The function saves the registers if OP is FRV_STORE and restores them if OP is FRV_LOAD. INFO is the stack information generated by frv_stack_info. */static voidfrv_frame_access_standard_regs (enum frv_stack_op op, frv_stack_t *info){ frv_frame_accessor_t accessor; accessor.op = op; accessor.base = stack_pointer_rtx; accessor.base_offset = 0; frv_frame_access_multi (&accessor, info, STACK_REGS_GPR); frv_frame_access_multi (&accessor, info, STACK_REGS_FPR); frv_frame_access_multi (&accessor, info, STACK_REGS_LCR);}/* Called after register allocation to add any instructions needed for the prologue. Using a prologue insn is favored compared to putting all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE target hook, since it allows the scheduler to intermix instructions with the saves of the caller saved registers. In some cases, it might be necessary to emit a barrier instruction as the last insn to prevent such scheduling. Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1 so that the debug info generation code can handle them properly. */voidfrv_expand_prologue (void){ frv_stack_t *info = frv_stack_info (); rtx sp = stack_pointer_rtx; rtx fp = frame_pointer_rtx; frv_frame_accessor_t accessor; if (TARGET_DEBUG_STACK) frv_debug_stack (info); if (info->total_size == 0) return; /* We're interested in three areas of the frame here: A: the register save area B: the old FP C: the header after B If the frame pointer isn't used, we'll have to set up A, B and C using the stack pointer. If the frame pointer is used, we'll access them as follows: A: set up using sp B: set up using sp or a temporary (see below) C: set up using fp We set up B using the stack pointer if the frame is small enough. Otherwise, it's more efficient to copy the old stack pointer into a temporary and use that. Note that it's important to make sure the prologue and epilogue use the same registers to access A and C, since doing otherwise will confuse the aliasing code. */ /* Set up ACCESSOR for accessing region B above. If the frame pointer isn't used, the same method will serve for C. */ accessor.op = FRV_STORE; if (frame_pointer_needed && info->total_size > 2048) { rtx insn; accessor.base = gen_rtx_REG (Pmode, OLD_SP_REGNO); accessor.base_offset = info->total_size; insn = emit_insn (gen_movsi (accessor.base, sp)); } else { accessor.base = stack_pointer_rtx; accessor.base_offset = 0; } /* Allocate the stack space. */ { rtx asm_offset = frv_frame_offset_rtx (-info->total_size); rtx dwarf_offset = GEN_INT (-info->total_size); frv_frame_insn (gen_stack_adjust (sp, sp, asm_offset), gen_rtx_SET (Pmode, sp, gen_rtx_PLUS (Pmode, sp, dwarf_offset))); } /* If the frame pointer is needed, store the old one at (sp + FP_OFFSET) and point the new one to that location. */ if (frame_pointer_needed) { int fp_offset = info->reg_offset[FRAME_POINTER_REGNUM]; /* ASM_SRC and DWARF_SRC both point to the frame header. ASM_SRC is based on ACCESSOR.BASE but DWARF_SRC is always based on the stack pointer. */ rtx asm_src = plus_constant (accessor.base, fp_offset - accessor.base_offset); rtx dwarf_src = plus_constant (sp, fp_offset); /* Store the old frame pointer at (sp + FP_OFFSET). */ frv_frame_access (&accessor, fp, fp_offset); /* Set up the new frame pointer. */ frv_frame_insn (gen_rtx_SET (VOIDmode, fp, asm_src), gen_rtx_SET (VOIDmode, fp, dwarf_src)); /* Access region C from the frame pointer. */ accessor.base = fp; accessor.base_offset = fp_offset; } /* Set up region C. */ frv_frame_access_multi (&accessor, info, STACK_REGS_STRUCT); frv_frame_access_multi (&accessor, info, STACK_REGS_LR); frv_frame_access_multi (&accessor, info, STACK_REGS_STDARG); /* Set up region A. */ frv_frame_access_standard_regs (FRV_STORE, info); /* If this is a varargs/stdarg function, issue a blockage to prevent the scheduler from moving loads before the stores saving the registers. */ if (info->stdarg_size > 0) emit_insn (gen_blockage ()); /* Set up pic register/small data register for this function. */ if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table) emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO), gen_rtx_REG (Pmode, LR_REGNO), gen_rtx_REG (SImode, OFFSET_REGNO)));}/* Under frv, all of the work is done via frv_expand_epilogue, but this function provides a convenient place to do cleanup. */static voidfrv_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT size ATTRIBUTE_UNUSED){ frv_stack_cache = (frv_stack_t *)0; /* Zap last used registers for conditional execution. */ memset (&frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg)); /* Release the bitmap of created insns. */ BITMAP_FREE (frv_ifcvt.scratch_insns_bitmap);}/* Called after register allocation to add any instructions needed for the epilogue. Using an epilogue insn is favored compared to putting all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE target hook, since it allows the scheduler to intermix instructions with the saves of the caller saved registers. In some cases, it might be necessary to emit a barrier instruction as the last insn to prevent such scheduling. */voidfrv_expand_epilogue (bool emit_return){ frv_stack_t *info = frv_stack_info (); rtx fp = frame_pointer_rtx; rtx sp = stack_pointer_rtx; rtx return_addr; int fp_offset; fp_offset = info->reg_offset[FRAME_POINTER_REGNUM]; /* Restore the stack pointer to its original value if alloca or the like is used. */ if (! current_function_sp_is_unchanging) emit_insn (gen_addsi3 (sp, fp, frv_frame_offset_rtx (-fp_offset))); /* Restore the callee-saved registers that were used in this function. */ frv_frame_access_standard_regs (FRV_LOAD, info); /* Set RETURN_ADDR to the address we should return to. Set it to NULL if no return instruction should be emitted. */ if (info->sav
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -