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

📄 iq2000.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
      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;	      gcc_assert (GET_CODE (entry_parm) == REG);	      /* 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_data_section ();      else	data_section ();    }}/* Return register to use for a function return value with VALTYPE for function   FUNC.  */rtxiq2000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED){  int reg = GP_RETURN;  enum machine_mode mode = TYPE_MODE (valtype);  int unsignedp = TYPE_UNSIGNED (valtype);  /* Since we define TARGET_PROMOTE_FUNCTION_RETURN that returns true,     we must promote the mode just as PROMOTE_MODE does.  */  mode = promote_mode (valtype, mode, &unsignedp, 1);  return gen_rtx_REG (mode, reg);}/* Return true when an argument must be passed by reference.  */static booliq2000_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode,			  tree type, bool named ATTRIBUTE_UNUSED){  int size;  /* We must pass by reference if we would be both passing in registers     and the stack.  This is because any subsequent partial arg would be     handled incorrectly in this case.  */  if (cum && targetm.calls.must_pass_in_stack (mode, type))     {       /* Don't pass the actual CUM to FUNCTION_ARG, because we would	  get double copies of any offsets generated for small structs	  passed in registers.  */       CUMULATIVE_ARGS temp;       temp = *cum;       if (FUNCTION_ARG (temp, mode, type, named) != 0)	 return 1;     }  if (type == NULL_TREE || mode == DImode || mode == DFmode)    return 0;  size = int_size_in_bytes (type);  return size == -1 || size > UNITS_PER_WORD;}/* Return the length of INSN.  LENGTH is the initial length computed by   attributes in the machine-description file.  */intiq2000_adjust_insn_length (rtx insn, int length){  /* A unconditional jump has an unfilled delay slot if it is not part     of a sequence.  A conditional jump normally has a delay slot.  */  if (simplejump_p (insn)      || (   (GET_CODE (insn) == JUMP_INSN	   || GET_CODE (insn) == CALL_INSN)))    length += 4;  return length;}/* Output assembly instructions to perform a conditional branch.   INSN is the branch instruction.  OPERANDS[0] is the condition.   OPERANDS[1] is the target of the branch.  OPERANDS[2] is the target   of the first operand to the condition.  If TWO_OPERANDS_P is   nonzero the comparison takes two operands; OPERANDS[3] will be the   second operand.   If INVERTED_P is nonzero we are to branch if the condition does   not hold.  If FLOAT_P is nonzero this is a floating-point comparison.   LENGTH is the length (in bytes) of the sequence we are to generate.   That tells us whether to generate a simple conditional branch, or a   reversed conditional branch around a `jr' instruction.  */char *iq2000_output_conditional_branch (rtx insn, rtx * operands, int two_operands_p,				  int float_p, int inverted_p, int length){  static char buffer[200];  /* The kind of comparison we are doing.  */  enum rtx_code code = GET_CODE (operands[0]);  /* Nonzero if the opcode for the comparison needs a `z' indicating     that it is a comparison against zero.  */  int need_z_p;  /* A string to use in the assembly output to represent the first     operand.  */  const char *op1 = "%z2";  /* A string to use in the assembly output to represent the second     operand.  Use the hard-wired zero register if there's no second     operand.  */  const char *op2 = (two_operands_p ? ",%z3" : ",%.");  /* The operand-printing string for the comparison.  */  const char *comp = (float_p ? "%F0" : "%C0");  /* The operand-printing string for the inverted comparison.  */  const char *inverted_comp = (float_p ? "%W0" : "%N0");  /* Likely variants of each branch instruction annul the instruction     in the delay slot if the branch is not taken.  */  iq2000_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));  if (!two_operands_p)    {      /* To compute whether than A > B, for example, we normally	 subtract B from A and then look at the sign bit.  But, if we	 are doing an unsigned comparison, and B is zero, we don't	 have to do the subtraction.  Instead, we can just check to	 see if A is nonzero.  Thus, we change the CODE here to	 reflect the simpler comparison operation.  */      switch (code)	{	case GTU:	  code = NE;	  break;	case LEU:	  code = EQ;	  break;	case GEU:	  /* A condition which will always be true.  */	  code = EQ;	  op1 = "%.";	  break;	case LTU:	  /* A condition which will always be false.  */	  code = NE;	  op1 = "%.";	  break;	default:	  /* Not a special case.  */	  break;	}    }  /* Relative comparisons are always done against zero.  But     equality comparisons are done between two operands, and therefore     do not require a `z' in the assembly language output.  */  need_z_p = (!float_p && code != EQ && code != NE);  /* For comparisons against zero, the zero is not provided     explicitly.  */  if (need_z_p)    op2 = "";  /* Begin by terminating the buffer.  That way we can always use     strcat to add to it.  */  buffer[0] = '\0';  switch (length)    {    case 4:    case 8:      /* Just a simple conditional branch.  */      if (float_p)	sprintf (buffer, "b%s%%?\t%%Z2%%1",		 inverted_p ? inverted_comp : comp);      else	sprintf (buffer, "b%s%s%%?\t%s%s,%%1",		 inverted_p ? inverted_comp : comp,		 need_z_p ? "z" : "",		 op1,		 op2);      return buffer;    case 12:    case 16:      {	/* Generate a reversed conditional branch around ` j'	   instruction

⌨️ 快捷键说明

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