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

📄 d30v.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
  int adjust = (bytes > UNITS_PER_WORD && (*cum & 1) != 0);  int arg_num = *cum + adjust;  int ret;  ret = ((arg_num <= GPR_ARG_LAST && arg_num + words > GPR_ARG_LAST+1)	 ? GPR_ARG_LAST - arg_num + 1	 : 0);  if (TARGET_DEBUG_ARG && ret)    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);  return ret;}/* A C expression that indicates when an argument must be passed by reference.   If nonzero for an argument, a copy of that argument is made in memory and a   pointer to the argument is passed instead of the argument itself.  The   pointer is passed in whatever way is appropriate for passing a pointer to   that type.   On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable   definition of this macro might be        #define FUNCTION_ARG_PASS_BY_REFERENCE\        (CUM, MODE, TYPE, NAMED)  \          MUST_PASS_IN_STACK (MODE, TYPE)  */intd30v_function_arg_pass_by_reference (cum, mode, type, named)     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;     enum machine_mode mode;     tree type;     int named ATTRIBUTE_UNUSED;{  int ret = MUST_PASS_IN_STACK (mode, type);  if (TARGET_DEBUG_ARG && ret)    fprintf (stderr, "function_arg_pass_by_reference: %d\n", ret);  return ret;}/* A C statement (sans semicolon) to update the summarizer variable CUM to   advance past an argument in the argument list.  The values MODE, TYPE and   NAMED describe that argument.  Once this is done, the variable CUM is   suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.   This macro need not do anything if the argument in question was passed on   the stack.  The compiler knows how to track the amount of stack space used   for arguments without any special help.  */voidd30v_function_arg_advance (cum, mode, type, named)     CUMULATIVE_ARGS *cum;     enum machine_mode mode;     tree type;     int named;{  int bytes = ((mode == BLKmode)	       ? int_size_in_bytes (type)	       : (int) GET_MODE_SIZE (mode));  int words = D30V_ALIGN (bytes, UNITS_PER_WORD) / UNITS_PER_WORD;  int adjust = (bytes > UNITS_PER_WORD && (*cum & 1) != 0);  *cum += words + adjust;  if (TARGET_DEBUG_ARG)    fprintf (stderr,	     "function_adv: words = %2d, mode = %4s, named = %d, size = %3d, adjust = %1d\n",	     *cum, GET_MODE_NAME (mode), named, words * UNITS_PER_WORD, adjust);}/* If defined, is a C expression that produces the machine-specific code for a   call to `__builtin_saveregs'.  This code will be moved to the very beginning   of the function, before any parameter access are made.  The return value of   this function should be an RTX that contains the value to use as the return   of `__builtin_saveregs'.   If this macro is not defined, the compiler will output an ordinary call to   the library function `__builtin_saveregs'.  */rtxd30v_expand_builtin_saveregs (){  int offset = UNITS_PER_WORD * (GPR_ARG_LAST + 1 - GPR_ARG_FIRST);  if (TARGET_DEBUG_ARG)    fprintf (stderr, "expand_builtin_saveregs: offset from ap = %d\n",	     offset);  return gen_rtx (PLUS, Pmode, virtual_incoming_args_rtx, GEN_INT (- offset));}/* This macro offers an alternative to using `__builtin_saveregs' and defining   the macro `EXPAND_BUILTIN_SAVEREGS'.  Use it to store the anonymous register   arguments into the stack so that all the arguments appear to have been   passed consecutively on the stack.  Once this is done, you can use the   standard implementation of varargs that works for machines that pass all   their arguments on the stack.   The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure, containing   the values that obtain after processing of the named arguments.  The   arguments MODE and TYPE describe the last named argument--its machine mode   and its data type as a tree node.   The macro implementation should do two things: first, push onto the stack   all the argument registers *not* used for the named arguments, and second,   store the size of the data thus pushed into the `int'-valued variable whose   name is supplied as the argument PRETEND_ARGS_SIZE.  The value that you   store here will serve as additional offset for setting up the stack frame.   Because you must generate code to push the anonymous arguments at compile   time without knowing their data types, `SETUP_INCOMING_VARARGS' is only   useful on machines that have just a single category of argument register and   use it uniformly for all data types.   If the argument SECOND_TIME is nonzero, it means that the arguments of the   function are being analyzed for the second time.  This happens for an inline   function, which is not actually compiled until the end of the source file.   The macro `SETUP_INCOMING_VARARGS' should not generate any instructions in   this case.  */voidd30v_setup_incoming_varargs (cum, mode, type, pretend_size, second_time)     CUMULATIVE_ARGS *cum;     enum machine_mode mode;     tree type ATTRIBUTE_UNUSED;     int *pretend_size ATTRIBUTE_UNUSED;     int second_time;{  if (TARGET_DEBUG_ARG)    fprintf (stderr,	     "setup_vararg: words = %2d, mode = %4s, second_time = %d\n",	     *cum, GET_MODE_NAME (mode), second_time);}/* Create the va_list data type.  */treed30v_build_va_list (){  tree f_arg_ptr, f_arg_num, record, type_decl;  tree int_type_node;  record = (*lang_hooks.types.make_type) (RECORD_TYPE);  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);  int_type_node = make_signed_type (INT_TYPE_SIZE);  f_arg_ptr = build_decl (FIELD_DECL, get_identifier ("__va_arg_ptr"), 			  ptr_type_node);  f_arg_num = build_decl (FIELD_DECL, get_identifier ("__va_arg_num"),			  int_type_node);  DECL_FIELD_CONTEXT (f_arg_ptr) = record;  DECL_FIELD_CONTEXT (f_arg_num) = record;  TREE_CHAIN (record) = type_decl;  TYPE_NAME (record) = type_decl;  TYPE_FIELDS (record) = f_arg_ptr;  TREE_CHAIN (f_arg_ptr) = f_arg_num;  layout_type (record);  /* The correct type is an array type of one element.  */  return build_array_type (record, build_index_type (size_zero_node));}/* Expand __builtin_va_start to do the va_start macro.  */void d30v_expand_builtin_va_start (valist, nextarg)     tree valist;     rtx nextarg ATTRIBUTE_UNUSED;{  HOST_WIDE_INT words;  tree f_arg_ptr, f_arg_num;  tree arg_ptr, arg_num, saveregs, t;  f_arg_ptr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));  f_arg_num = TREE_CHAIN (f_arg_ptr);  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);  arg_ptr = build (COMPONENT_REF, TREE_TYPE (f_arg_ptr), valist, f_arg_ptr);  arg_num = build (COMPONENT_REF, TREE_TYPE (f_arg_num), valist, f_arg_num);  words = current_function_args_info;	/* __builtin_args_info (0) */  /* (AP)->__va_arg_ptr = (int *) __builtin_saveregs (); */  saveregs = make_tree (TREE_TYPE (arg_ptr), d30v_expand_builtin_saveregs ());  t = build (MODIFY_EXPR, TREE_TYPE (arg_ptr), arg_ptr, saveregs);  TREE_SIDE_EFFECTS (t) = 1;  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);  /* (AP)->__va_arg_num = __builtin_args_info (0) - 2; */  t = build (PLUS_EXPR, TREE_TYPE (arg_num), build_int_2 (words, 0),	     build_int_2 (-GPR_ARG_FIRST, 0));  t = build (MODIFY_EXPR, TREE_TYPE (arg_num), arg_num, t);  TREE_SIDE_EFFECTS (t) = 1;  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);}/* Expand __builtin_va_arg to do the va_arg macro.  */rtxd30v_expand_builtin_va_arg(valist, type)     tree valist;     tree type;{  tree f_arg_ptr, f_arg_num;  tree arg_ptr, arg_num, t, ptr;  int num, size;  rtx lab_false, ptr_rtx, r;  f_arg_ptr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));  f_arg_num = TREE_CHAIN (f_arg_ptr);  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);  arg_ptr = build (COMPONENT_REF, TREE_TYPE (f_arg_ptr), valist, f_arg_ptr);  arg_num = build (COMPONENT_REF, TREE_TYPE (f_arg_num), valist, f_arg_num);  size = int_size_in_bytes (type);  lab_false = gen_label_rtx ();  ptr_rtx = gen_reg_rtx (Pmode);  /* if (sizeof (TYPE) > 4 && ((AP)->__va_arg_num & 1) != 0)       (AP)->__va_arg_num++; */  if (size > UNITS_PER_WORD)     {      t = build (BIT_AND_EXPR, TREE_TYPE (arg_num), arg_num, 		 build_int_2 (1, 0));      emit_cmp_and_jump_insns (expand_expr (t, NULL_RTX, QImode, EXPAND_NORMAL),			       GEN_INT (0), EQ, const1_rtx, QImode, 1,			       lab_false);      t = build (POSTINCREMENT_EXPR, TREE_TYPE (arg_num), arg_num,		 build_int_2 (1, 0));      TREE_SIDE_EFFECTS (t) = 1;      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);      emit_label (lab_false);    }  /* __ptr = (TYPE *)(((char *)(void *)((AP)->__va_arg_ptr 	     + (AP)->__va_arg_num))); */  t = build (MULT_EXPR, TREE_TYPE (arg_num), arg_num, build_int_2 (4, 0));  t = build (PLUS_EXPR, ptr_type_node, arg_ptr, t);  /* if (sizeof (TYPE) < 4)       __ptr = (void *)__ptr + 4 - sizeof (TYPE); */  if (size < UNITS_PER_WORD)    t = build (PLUS_EXPR, ptr_type_node, t,	       build_int_2 (UNITS_PER_WORD - size, 0));  TREE_SIDE_EFFECTS (t) = 1;  ptr = build1 (NOP_EXPR, build_pointer_type (type), t);  t = build (MODIFY_EXPR, type, ptr, t);  r = expand_expr (t, ptr_rtx, Pmode, EXPAND_NORMAL);  if (r != ptr_rtx)    emit_move_insn (ptr_rtx, r);  /* (AP)->__va_arg_num += (sizeof (TYPE) + 3) / 4; */  num = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;  t = build (POSTINCREMENT_EXPR, TREE_TYPE (arg_num), arg_num, 	     build_int_2 (num, 0));  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);  return ptr_rtx;}/* Generate the assembly code for function entry.  FILE is a stdio   stream to output the code to.  SIZE is an int: how many units of   temporary storage to allocate.   Refer to the array `regs_ever_live' to determine which registers to   save; `regs_ever_live[I]' is nonzero if register number I is ever   used in the function.  This function is responsible for knowing   which registers should not be saved even if used.  */static voidd30v_output_function_prologue (stream, size)     FILE *stream ATTRIBUTE_UNUSED;     HOST_WIDE_INT size ATTRIBUTE_UNUSED;{  /* For the d30v, move all of the prologue processing into separate     insns.  */}/* 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 output_function_prologue (), 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.  */voidd30v_expand_prologue (){  rtx sp = stack_pointer_rtx;  d30v_stack_t *info = d30v_stack_info ();  int i;  rtx mem_di = NULL_RTX;  rtx mem_si = NULL_RTX;  int num_memrefs = (info->memrefs_2words		     + info->memrefs_1word		     + info->memrefs_varargs);  if (TARGET_DEBUG_STACK)    debug_stack_info (info);  /* Grow the stack.  */  if (info->total_size)    emit_insn (gen_addsi3 (sp, sp, GEN_INT (- info->total_size)));  /* If there is more than one save, use post-increment addressing which will     result in smaller code, than would the normal references.  If there is     only one save, just do the store as normal.  */  if (num_memrefs > 1)    {      rtx save_tmp = gen_rtx (REG, Pmode, GPR_STACK_TMP);      rtx post_inc = gen_rtx (POST_INC, Pmode, save_tmp);      mem_di = gen_rtx (MEM, DImode, post_inc);      mem_si = gen_rtx (MEM, SImode, post_inc);      emit_insn (gen_addsi3 (save_tmp, sp, GEN_INT (info->save_offset)));    }  else if (num_memrefs == 1)    {      rtx addr = plus_constant (sp, info->save_offset);      mem_di = gen_rtx (MEM, DImode, addr);      mem_si = gen_rtx (MEM, SImode, addr);    }  /* Save the accumulators.  */  for (i = ACCUM_FIRST; i <= ACCUM_LAST; i++)    if (info->save_p[i])      {	rtx acc_tmp = gen_rtx (REG, DImode, GPR_ATMP_FIRST);	emit_insn (gen_movdi (acc_tmp, gen_rtx (REG, DImode, i)));	emit_insn (gen_movdi (mem_di, acc_tmp));      }  /* Save the GPR registers that are adjacent to each other with st2w.  */  for (i = GPR_FIRST; i <= GPR_LAST; i += 2)    if (info->save_p[i] == 2)      emit_insn (gen_movdi (mem_di, gen_rtx (REG, DImode, i)));  /* Save the GPR registers that need to be saved with a single word store.  */  for (i = GPR_FIRST; i <= GPR_LAST; i++)    if (info->save_p[i] == 1)      emit_insn (gen_movsi (mem_si, gen_rtx (REG, SImode, i)));  /* Save the argument registers if this function accepts variable args.  */  if (info->varargs_p)    {      /* Realign r22 if an odd # of GPRs were saved.  */      if ((info->memrefs_1word & 1) != 0)	{	  rtx save_tmp = XEXP (XEXP (mem_si, 0), 0);	  emit_insn (gen_addsi3 (save_tmp, save_tmp, GEN_INT (UNITS_PER_WORD)));	}      for (i = GPR_ARG_FIRST; i <= GPR_ARG_LAST; i += 2)	emit_insn (gen_movdi (mem_di, gen_rtx (REG, DImode, i)));    }  /* Update the frame pointer.  */  if (frame_pointer_needed)    emit_move_insn (frame_pointer_rtx, sp);  /* Hack for now, to prevent scheduler from being too cleaver */  emit_insn (gen_blockage ());}/* This function generates the assembly code for function exit.   Args are as for output_function_prologue ().   The function epilogue should not depend on the current stack   pointer!  It should use the frame pointer only.  This is mandatory   because of alloca; we also take advantage of it to omit stack   adjustments before returning.  */static voidd30v_output_function_epilogue (stream, size)     FILE *stream ATTRIBUTE_UNUSED;     HOST_WIDE_INT size ATTRIBUTE_UNUSED;{  /* For the d30v, move all processing to be as insns, but do any     cleanup here, since it is done after handling all of the insns.  */  d30v_stack_cache = (d30v_stack_t *)0;	/* reset stack cache */}/* 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 output_function_prologue(), 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.  */voidd30v_expand_epilogue (){  rtx sp = stack_pointer_rtx;  d30v_stack_t *info = d30v_stack_info ();  int i;  rtx mem_di = NULL_RTX;  rtx mem_si = NULL_RTX;  rtx post_inc;  int extra_stack;  /* Hack for now, to prevent scheduler from being too cleaver */  emit_insn (gen_blockage ());  /* Restore sp from fp.  */  if (frame_pointer_needed)    emit_move_insn (sp, frame_pointer_rtx);  /* For the epilogue, use post-increment addressing all of the time.  First     adjust the sp, to eliminate all of the stack, except for the save area.  */  if (info->save_offset)    emit_insn (gen_addsi3 (sp, sp, GEN_INT (info->save_offset)));  post_inc = gen_rtx (POST_INC, Pmode, sp);  mem_di = gen_rtx (MEM, DImode, post_inc);  mem_si = gen_rtx (MEM, SImode, post_inc);  /* Restore the accumulators.  */  for (i = ACCUM_FIRST; i <= ACCUM_LAST; i++)    if (info->save_p[i])      {	rtx acc_tmp = gen_rtx (REG, DImode, GPR_ATMP_FIRST);	emit_insn (gen_movdi (acc_tmp, mem_di));	emit_insn (gen_movdi (gen_rtx (REG, DImode, i), acc_tmp));      }  /* Restore the GPR registers that are adjacent to each other with ld2w.  */  for (i = GPR_FIRST; i <= GPR_LAST; i += 2)    if (info->save_p[i] == 2)      emit_insn (gen_movdi (gen_rtx (REG, DImode, i), mem_di));  /* Save the GPR registers that need to be saved with a single word store.  */  extra_stack = 0;  for (i = GPR_FIRST; i <= GPR_LAST; i++)    if (info->save_p[i] == 1)      {	if (cfun->machine->eh_epilogue_sp_ofs && i == GPR_LINK)	  extra_stack = 4;	else	  {	    if (extra_stack)	      {	        emit_insn (gen_addsi3 (sp, sp, GEN_INT (extra_stack)));		extra_stack = 0;	      }	    emit_insn (gen_movsi (gen_rtx (REG, SImode, i), mem_si));	  }      }  /* Release any remaining stack that was allocated for saving the     varargs registers or because an odd # of registers were stored.  */  if ((info->memrefs_1word & 1) != 0)    extra_stack += UNITS_PER_WORD;  extra_stack += current_function_pretend_args_size + info->varargs_size;  if (extra_stack)    {      if (cfun->machine->eh_epilogue_sp_ofs)	emit_insn (gen_addsi3 (cfun->machine->eh_epilogue_sp_ofs,			       cfun->machine->eh_epilogue_sp_ofs,			       GEN_INT (extra_stack)));      else        emit_insn (gen_addsi3 (sp, sp, GEN_INT (extra_stack)));    }  if (cfun->machine->eh_epilogue_sp_ofs)    emit_insn (gen_addsi3 (sp, sp, cfun->machine->eh_epilogue_sp_ofs));  /* Now emit the return instruction.  */  emit_jump_insn (gen_rtx_RETURN (VOIDmode));}/* A C statement or compound statement to output to FILE some assembler code to   call the profiling subroutine `mcount'.  Before calling, the assembler code   must load the address of a counter variable into a register where `mcount'   expects to find the address.  The name of this variable is `LP' followed by   the number LABELNO, so you would generate the name using `LP%d' in a   `fprintf'.   The details of how the address should be passed to `mcount' are determined   by your operating system environment, not by GNU CC.  To figure t

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -