📄 frv.c
字号:
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 (accessor, info, reg_set) 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 (op, info) 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 FUNCTION_PROLOGUE macro, 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 (){ 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 (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 convient place to do cleanup. */static voidfrv_function_epilogue (file, size) 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 ((PTR) &frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg)); /* release the bitmap of created insns. */ BITMAP_XFREE (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 FUNCTION_PROLOGUE macro, 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. If SIBCALL_P is true, the final branch back to the calling function is omitted, and is used for sibling call (aka tail call) sites. For sibcalls, we must not clobber any arguments used for parameter passing or any stack slots for arguments passed to the current function. */voidfrv_expand_epilogue (sibcall_p) int sibcall_p;{ 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 (sibcall_p) return_addr = 0; else if (info->save_p[LR_REGNO]) { int lr_offset; rtx mem; /* Use the same method to access the link register's slot as we did in the prologue. In other words, use the frame pointer if available, otherwise use the stack pointer. LR_OFFSET is the offset of the link register's slot from the start of the frame and MEM is a memory rtx for it. */ lr_offset = info->reg_offset[LR_REGNO]; if (frame_pointer_needed) mem = frv_frame_mem (Pmode, fp, lr_offset - fp_offset); else mem = frv_frame_mem (Pmode, sp, lr_offset); /* Load the old link register into a GPR. */ return_addr = gen_rtx_REG (Pmode, TEMP_REGNO); emit_insn (gen_rtx_SET (VOIDmode, return_addr, mem)); } else return_addr = gen_rtx_REG (Pmode, LR_REGNO); /* Restore the old frame pointer. Emit a USE afterwards to make sure the load is preserved. */ if (frame_pointer_needed) { emit_insn (gen_rtx_SET (VOIDmode, fp, gen_rtx_MEM (Pmode, fp))); emit_insn (gen_rtx_USE (VOIDmode, fp)); } /* Deallocate the stack frame. */ if (info->total_size != 0) { rtx offset = frv_frame_offset_rtx (info->total_size); emit_insn (gen_stack_adjust (sp, sp, offset)); } /* If this function uses eh_return, add the final stack adjustment now. */ if (current_function_calls_eh_return) emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX)); if (return_addr) emit_jump_insn (gen_epilogue_return (return_addr));}/* A C compound statement that outputs the assembler code for a thunk function, used to implement C++ virtual function calls with multiple inheritance. The thunk acts as a wrapper around a virtual function, adjusting the implicit object parameter before handing control off to the real function. First, emit code to add the integer DELTA to the location that contains the incoming first argument. Assume that this argument contains a pointer, and is the one used to pass the `this' pointer in C++. This is the incoming argument *before* the function prologue, e.g. `%o0' on a sparc. The addition must preserve the values of all other incoming arguments. After the addition, emit code to jump to FUNCTION, which is a `FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch the return address. Hence returning from FUNCTION will return to whoever called the current `thunk'. The effect must be as if FUNCTION had been called directly with the adjusted first argument. This macro is responsible for emitting all of the code for a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not invoked. The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been extracted from it.) It might possibly be useful on some targets, but probably not. If you do not define this macro, the target-independent code in the C++ frontend will generate a less efficient heavyweight thunk that calls FUNCTION instead of jumping to it. The generic approach does not support varargs. */static voidfrv_asm_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) FILE *file; tree thunk_fndecl ATTRIBUTE_UNUSED; HOST_WIDE_INT delta; HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED; tree function;{ const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0); const char *name_arg0 = reg_names[FIRST_ARG_REGNUM]; const char *name_jmp = reg_names[JUMP_REGNO]; const char *parallel = ((PACKING_FLAG_USED_P ()) ? ".p" : ""); /* Do the add using an addi if possible */ if (IN_RANGE_P (delta, -2048, 2047)) fprintf (file, "\taddi %s,#%d,%s\n", name_arg0, (int) delta, name_arg0); else { const char *name_add = reg_names[TEMP_REGNO]; fprintf (file, "\tsethi%s #hi(", parallel); fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta); fprintf (file, "),%s\n", name_add); fprintf (file, "\tsetlo #lo("); fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta); fprintf (file, "),%s\n", name_add); fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0); } if (!flag_pic) { fprintf (file, "\tsethi%s #hi(", parallel); assemble_name (file, name_func); fprintf (file, "),%s\n", name_jmp); fprintf (file, "\tsetlo #lo("); assemble_name (file, name_func); fprintf (file, "),%s\n", name_jmp); } else { /* Use JUMP_REGNO as a temporary PIC register. */ const char *name_lr = reg_names[LR_REGNO]; const char *name_gppic = name_jmp; const char *name_tmp = reg_names[TEMP_REGNO]; fprintf (file, "\tmovsg %s,%s\n", name_lr, name_tmp); fprintf (file, "\tcall 1f\n"); fprintf (file, "1:\tmovsg %s,%s\n", name_lr, name_gppic); fprintf (file, "\tmovgs %s,%s\n", name_tmp, name_lr); fprintf (file, "\tsethi%s #gprelhi(1b),%s\n", parallel, name_tmp); fprintf (file, "\tsetlo #gprello(1b),%s\n", name_tmp); fprintf (file, "\tsub %s,%s,%s\n", name_gppic, name_tmp, name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -