⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frv.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
      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 + -