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

📄 iq2000.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
      else (offset) = cfun->machine->gp_sp_offset 	     + ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)) 		* (BYTES_BIG_ENDIAN != 0));     }  return offset;}/* Common code to emit the insns (or to write the instructions to a file)   to save/restore registers.     Other parts of the code assume that IQ2000_TEMP1_REGNUM (aka large_reg)   is not modified within save_restore_insns.  */#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)/* Emit instructions to load the value (SP + OFFSET) into IQ2000_TEMP2_REGNUM   and return an rtl expression for the register.  Write the assembly   instructions directly to FILE if it is not null, otherwise emit them as   rtl.   This function is a subroutine of save_restore_insns.  It is used when   OFFSET is too large to add in a single instruction.  */static rtxiq2000_add_large_offset_to_sp (HOST_WIDE_INT offset){  rtx reg = gen_rtx_REG (Pmode, IQ2000_TEMP2_REGNUM);  rtx offset_rtx = GEN_INT (offset);  emit_move_insn (reg, offset_rtx);  emit_insn (gen_addsi3 (reg, reg, stack_pointer_rtx));  return reg;}/* Make INSN frame related and note that it performs the frame-related   operation DWARF_PATTERN.  */static voidiq2000_annotate_frame_insn (rtx insn, rtx dwarf_pattern){  RTX_FRAME_RELATED_P (insn) = 1;  REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,				      dwarf_pattern,				      REG_NOTES (insn));}/* Emit a move instruction that stores REG in MEM.  Make the instruction   frame related and note that it stores REG at (SP + OFFSET).  */static voidiq2000_emit_frame_related_store (rtx mem, rtx reg, HOST_WIDE_INT offset){  rtx dwarf_address = plus_constant (stack_pointer_rtx, offset);  rtx dwarf_mem = gen_rtx_MEM (GET_MODE (reg), dwarf_address);  iq2000_annotate_frame_insn (emit_move_insn (mem, reg),			    gen_rtx_SET (GET_MODE (reg), dwarf_mem, reg));}/* Emit instructions to save/restore registers, as determined by STORE_P.  */static voidsave_restore_insns (int store_p){  long mask = cfun->machine->mask;  int regno;  rtx base_reg_rtx;  HOST_WIDE_INT base_offset;  HOST_WIDE_INT gp_offset;  HOST_WIDE_INT end_offset;  if (frame_pointer_needed      && ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))    abort ();  if (mask == 0)    {      base_reg_rtx = 0, base_offset  = 0;      return;    }  /* Save registers starting from high to low.  The debuggers prefer at least     the return register be stored at func+4, and also it allows us not to     need a nop in the epilog if at least one register is reloaded in     addition to return address.  */  /* Save GP registers if needed.  */  /* Pick which pointer to use as a base register.  For small frames, just     use the stack pointer.  Otherwise, use a temporary register.  Save 2     cycles if the save area is near the end of a large frame, by reusing     the constant created in the prologue/epilogue to adjust the stack     frame.  */  gp_offset = cfun->machine->gp_sp_offset;  end_offset    = gp_offset - (cfun->machine->gp_reg_size		   - GET_MODE_SIZE (gpr_mode));  if (gp_offset < 0 || end_offset < 0)    internal_error      ("gp_offset (%ld) or end_offset (%ld) is less than zero.",       (long) gp_offset, (long) end_offset);  else if (gp_offset < 32768)    base_reg_rtx = stack_pointer_rtx, base_offset  = 0;  else    {      int regno;      int reg_save_count = 0;      for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)	if (BITSET_P (mask, regno - GP_REG_FIRST)) reg_save_count += 1;      base_offset = gp_offset - ((reg_save_count - 1) * 4);      base_reg_rtx = iq2000_add_large_offset_to_sp (base_offset);    }  for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)    {      if (BITSET_P (mask, regno - GP_REG_FIRST))	{	  rtx reg_rtx;	  rtx mem_rtx	    = gen_rtx_MEM (gpr_mode,		       gen_rtx_PLUS (Pmode, base_reg_rtx,				GEN_INT (gp_offset - base_offset)));	  reg_rtx = gen_rtx_REG (gpr_mode, regno);	  if (store_p)	    iq2000_emit_frame_related_store (mem_rtx, reg_rtx, gp_offset);	  else 	    {	      emit_move_insn (reg_rtx, mem_rtx);	    }	  gp_offset -= GET_MODE_SIZE (gpr_mode);	}    }}/* Expand the prologue into a bunch of separate insns.  */voidiq2000_expand_prologue (void){  int regno;  HOST_WIDE_INT tsize;  int last_arg_is_vararg_marker = 0;  tree fndecl = current_function_decl;  tree fntype = TREE_TYPE (fndecl);  tree fnargs = DECL_ARGUMENTS (fndecl);  rtx next_arg_reg;  int i;  tree next_arg;  tree cur_arg;  CUMULATIVE_ARGS args_so_far;  int store_args_on_stack = (iq2000_can_use_return_insn ());  /* If struct value address is treated as the first argument.  */  if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)      && ! current_function_returns_pcc_struct      && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)    {      tree type = build_pointer_type (fntype);      tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);      DECL_ARG_TYPE (function_result_decl) = type;      TREE_CHAIN (function_result_decl) = fnargs;      fnargs = function_result_decl;    }  /* For arguments passed in registers, find the register number     of the first argument in the variable part of the argument list,     otherwise GP_ARG_LAST+1.  Note also if the last argument is     the varargs special argument, and treat it as part of the     variable arguments.     This is only needed if store_args_on_stack is true.  */  INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0);  regno = GP_ARG_FIRST;  for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)    {      tree passed_type = DECL_ARG_TYPE (cur_arg);      enum machine_mode passed_mode = TYPE_MODE (passed_type);      rtx entry_parm;      if (TREE_ADDRESSABLE (passed_type))	{	  passed_type = build_pointer_type (passed_type);	  passed_mode = Pmode;	}      entry_parm = FUNCTION_ARG (args_so_far, passed_mode, passed_type, 1);      FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, passed_type, 1);      next_arg = TREE_CHAIN (cur_arg);      if (entry_parm && store_args_on_stack)	{	  if (next_arg == 0	      && DECL_NAME (cur_arg)	      && ((0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)),				"__builtin_va_alist"))		  || (0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)),				   "va_alist"))))	    {	      last_arg_is_vararg_marker = 1;	      break;	    }	  else	    {	      int words;	      if (GET_CODE (entry_parm) != REG)	        abort ();	      /* Passed in a register, so will get homed automatically.  */	      if (GET_MODE (entry_parm) == BLKmode)		words = (int_size_in_bytes (passed_type) + 3) / 4;	      else		words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;	      regno = REGNO (entry_parm) + words - 1;	    }	}      else	{	  regno = GP_ARG_LAST+1;	  break;	}    }  /* In order to pass small structures by value in registers we need to     shift the value into the high part of the register.     Function_arg has encoded a PARALLEL rtx, holding a vector of     adjustments to be made as the next_arg_reg variable, so we split up the     insns, and emit them separately.  */  next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);  if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)    {      rtvec adjust = XVEC (next_arg_reg, 0);      int num = GET_NUM_ELEM (adjust);      for (i = 0; i < num; i++)	{	  rtx insn, pattern;	  pattern = RTVEC_ELT (adjust, i);	  if (GET_CODE (pattern) != SET	      || GET_CODE (SET_SRC (pattern)) != ASHIFT)	    abort_with_insn (pattern, "Insn is not a shift");	  PUT_CODE (SET_SRC (pattern), ASHIFTRT);	  insn = emit_insn (pattern);	  /* Global life information isn't valid at this point, so we	     can't check whether these shifts are actually used.  Mark	     them MAYBE_DEAD so that flow2 will remove them, and not	     complain about dead code in the prologue.  */	  REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,					       REG_NOTES (insn));	}    }  tsize = compute_frame_size (get_frame_size ());  /* If this function is a varargs function, store any registers that     would normally hold arguments ($4 - $7) on the stack.  */  if (store_args_on_stack      && ((TYPE_ARG_TYPES (fntype) != 0	   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))	       != void_type_node))	  || last_arg_is_vararg_marker))    {      int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;      rtx ptr = stack_pointer_rtx;      for (; regno <= GP_ARG_LAST; regno++)	{	  if (offset != 0)	    ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));	  emit_move_insn (gen_rtx_MEM (gpr_mode, ptr),			  gen_rtx_REG (gpr_mode, regno));	  offset += GET_MODE_SIZE (gpr_mode);	}    }  if (tsize > 0)    {      rtx tsize_rtx = GEN_INT (tsize);      rtx adjustment_rtx, insn, dwarf_pattern;      if (tsize > 32767)	{	  adjustment_rtx = gen_rtx_REG (Pmode, IQ2000_TEMP1_REGNUM);	  emit_move_insn (adjustment_rtx, tsize_rtx);	}      else	adjustment_rtx = tsize_rtx;      insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,				    adjustment_rtx));      dwarf_pattern = gen_rtx_SET (Pmode, stack_pointer_rtx,				   plus_constant (stack_pointer_rtx, -tsize));      iq2000_annotate_frame_insn (insn, dwarf_pattern);      save_restore_insns (1);      if (frame_pointer_needed)	{	  rtx insn = 0;	  insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,				       stack_pointer_rtx));	  if (insn)	    RTX_FRAME_RELATED_P (insn) = 1;	}    }  emit_insn (gen_blockage ());}/* Expand the epilogue into a bunch of separate insns.  */voidiq2000_expand_epilogue (void){  HOST_WIDE_INT tsize = cfun->machine->total_size;  rtx tsize_rtx = GEN_INT (tsize);  rtx tmp_rtx = (rtx)0;  if (iq2000_can_use_return_insn ())    {      emit_jump_insn (gen_return ());      return;    }  if (tsize > 32767)    {      tmp_rtx = gen_rtx_REG (Pmode, IQ2000_TEMP1_REGNUM);      emit_move_insn (tmp_rtx, tsize_rtx);      tsize_rtx = tmp_rtx;    }  if (tsize > 0)    {      if (frame_pointer_needed)	{	  emit_insn (gen_blockage ());	  emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));	}      save_restore_insns (0);      if (current_function_calls_eh_return)	{	  rtx eh_ofs = EH_RETURN_STACKADJ_RTX;	  emit_insn (gen_addsi3 (eh_ofs, eh_ofs, tsize_rtx));	  tsize_rtx = eh_ofs;	}      emit_insn (gen_blockage ());      if (tsize != 0 || current_function_calls_eh_return)	{	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,				 tsize_rtx));	}    }  if (current_function_calls_eh_return)    {      /* Perform the additional bump for __throw.  */      emit_move_insn (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),		      stack_pointer_rtx);      emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode,						  HARD_FRAME_POINTER_REGNUM)));      emit_jump_insn (gen_eh_return_internal ());    }  else      emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,						  GP_REG_FIRST + 31)));}voidiq2000_expand_eh_return (rtx address){  HOST_WIDE_INT gp_offset = cfun->machine->gp_sp_offset;  rtx scratch;  scratch = plus_constant (stack_pointer_rtx, gp_offset);  emit_move_insn (gen_rtx_MEM (GET_MODE (address), scratch), address);}/* Return nonzero if this function is known to have a null epilogue.   This allows the optimizer to omit jumps to jumps if no stack   was created.  */intiq2000_can_use_return_insn (void){  if (! reload_completed)    return 0;  if (regs_ever_live[31] || profile_flag)    return 0;  if (cfun->machine->initialized)    return cfun->machine->total_size == 0;  return compute_frame_size (get_frame_size ()) == 0;}/* Returns nonzero if X contains a SYMBOL_REF.  */static intsymbolic_expression_p (rtx x){  if (GET_CODE (x) == SYMBOL_REF)    return 1;  if (GET_CODE (x) == CONST)    return symbolic_expression_p (XEXP (x, 0));  if (UNARY_P (x))    return symbolic_expression_p (XEXP (x, 0));  if (ARITHMETIC_P (x))    return (symbolic_expression_p (XEXP (x, 0))	    || symbolic_expression_p (XEXP (x, 1)));  return 0;}/* Choose the section to use for the constant rtx expression X that has   mode MODE.  */static voidiq2000_select_rtx_section (enum machine_mode mode, rtx x ATTRIBUTE_UNUSED,			   unsigned HOST_WIDE_INT align){  /* For embedded applications, always put constants in read-only data,     in order to reduce RAM usage.  */      /* For embedded applications, always put constants in read-only data,         in order to reduce RAM usage.  */  mergeable_constant_section (mode, align, 0);}/* Choose the section to use for DECL.  RELOC is true if its value contains   any relocatable expression.   Some of the logic used here needs to be replicated in   ENCODE_SECTION_INFO in iq2000.h so that references to these symbols   are done correctly.  */static voidiq2000_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,		       unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED){  if (TARGET_EMBEDDED_DATA)    {      /* For embedded applications, always put an object in read-only data	 if possible, in order to reduce RAM usage.  */      if ((TREE_CODE (decl) == VAR_DECL	   && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)	   && DECL_INITIAL (decl)	   && (DECL_INITIAL (decl) == error_mark_node	       || TREE_CONSTANT (DECL_INITIAL (decl))))	  /* Deal with calls from output_constant_def_contents.  */	  || TREE_CODE (decl) != VAR_DECL)	readonly_data_section ();      else	data_section ();    }  else    {      /* For hosted applications, always put an object in small data if	 possible, as this gives the best performance.  */      if ((TREE_CODE (decl) == VAR_DECL	   && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)	   && DECL_INITIAL (decl)	   && (DECL_INITIAL (decl) == error_mark_node	       || TREE_CONSTANT (DECL_INITIAL (decl))))	  /* Deal with calls from output_constant_def_contents.  */	  || TREE_CODE (decl) != VAR_DECL)	readonly_dat

⌨️ 快捷键说明

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