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

📄 cris.c

📁 gcc-you can use this code to learn something about gcc, and inquire further into linux,
💻 C
📖 第 1 页 / 共 5 页
字号:
      putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file);      return;    case '#':      /* Output a 'nop' if there's nothing for the delay slot.	 This method stolen from the sparc files.  */      if (dbr_sequence_length () == 0)	fputs ("\n\tnop", file);      return;    case 'H':      /* Print high (most significant) part of something.  */      switch (GET_CODE (operand))	{	case CONST_INT:	  if (HOST_BITS_PER_WIDE_INT == 32)	    /* Sign-extension from a normal int to a long long.  */	    fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");	  else	    fprintf (file, "0x%x", (unsigned int)(INTVAL (x) >> 31 >> 1));	  return;	case CONST_DOUBLE:	  /* High part of a long long constant.  */	  if (GET_MODE (operand) == VOIDmode)	    {	      fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x));	      return;	    }	  else	    LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);	case REG:	  /* Print reg + 1.  Check that there's not an attempt to print	     high-parts of registers like stack-pointer or higher.  */	  if (REGNO (operand) > STACK_POINTER_REGNUM - 2)	    LOSE_AND_RETURN ("bad register", operand);	  fprintf (file, "$%s", reg_names[REGNO (operand) + 1]);	  return;	case MEM:	  /* Adjust memory address to high part.  */	  {	    rtx adj_mem = operand;	    int size	      = GET_MODE_BITSIZE (GET_MODE (operand)) / BITS_PER_UNIT;	    /* Adjust so we can use two SImode in DImode.	       Calling adj_offsettable_operand will make sure it is an	       offsettable address.  Don't do this for a postincrement	       though; it should remain as it was.  */	    if (GET_CODE (XEXP (adj_mem, 0)) != POST_INC)	      adj_mem		= adjust_address (adj_mem, GET_MODE (adj_mem), size / 2);	    output_address (XEXP (adj_mem, 0));	    return;	  }	default:	  LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);	}    case 'L':      /* Strip the MEM expression.  */      operand = XEXP (operand, 0);      break;    case 'e':      /* Print 's' if operand is SIGN_EXTEND or 'u' if ZERO_EXTEND unless	 cris_output_insn_is_bound is nonzero.  */      if (GET_CODE (operand) != SIGN_EXTEND	  && GET_CODE (operand) != ZERO_EXTEND	  && GET_CODE (operand) != CONST_INT)	LOSE_AND_RETURN ("invalid operand for 'e' modifier", x);      if (cris_output_insn_is_bound)	{	  cris_output_insn_is_bound = 0;	  return;	}      putc (GET_CODE (operand) == SIGN_EXTEND	    || (GET_CODE (operand) == CONST_INT && INTVAL (operand) < 0)	    ? 's' : 'u', file);      return;    case 'm':      /* Print the size letter of the inner element.  We can do it by	 calling ourselves with the 's' modifier.  */      if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND)	LOSE_AND_RETURN ("invalid operand for 'm' modifier", x);      cris_print_operand (file, XEXP (operand, 0), 's');      return;    case 'M':      /* Print the least significant part of operand.  */      if (GET_CODE (operand) == CONST_DOUBLE)	{	  fprintf (file, "0x%x", CONST_DOUBLE_LOW (x));	  return;	}      else if (HOST_BITS_PER_WIDE_INT > 32 && GET_CODE (operand) == CONST_INT)	{	  fprintf (file, "0x%x",		   INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1));	  return;	}      /* Otherwise the least significant part equals the normal part,	 so handle it normally.  */      break;    case 'A':      /* When emitting an add for the high part of a DImode constant, we	 want to use addq for 0 and adds.w for -1.  */      if (GET_CODE (operand) != CONST_INT)	LOSE_AND_RETURN ("invalid operand for 'A' modifier", x);      fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");      return;    case 'D':      /* When emitting an sub for the high part of a DImode constant, we	 want to use subq for 0 and subs.w for -1.  */      if (GET_CODE (operand) != CONST_INT)	LOSE_AND_RETURN ("invalid operand for 'D' modifier", x);      fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq");      return;    case 'S':      /* Print the operand as the index-part of an address.	 Easiest way out is to use cris_print_index.  */      cris_print_index (operand, file);      return;    case 'T':      /* Print the size letter for an operand to a MULT, which must be a	 const_int with a suitable value.  */      if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4)	LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);      fprintf (file, "%s", mults[INTVAL (operand)]);      return;    case 0:      /* No code, print as usual.  */      break;    default:      LOSE_AND_RETURN ("invalid operand modifier letter", x);    }  /* Print an operand as without a modifier letter.  */  switch (GET_CODE (operand))    {    case REG:      if (REGNO (operand) > 15)	internal_error ("internal error: bad register: %d", REGNO (operand));      fprintf (file, "$%s", reg_names[REGNO (operand)]);      return;    case MEM:      output_address (XEXP (operand, 0));      return;    case CONST_DOUBLE:      if (GET_MODE (operand) == VOIDmode)	/* A long long constant.  */	output_addr_const (file, operand);      else	{	  /* Only single precision is allowed as plain operands the	     moment.  FIXME:  REAL_VALUE_FROM_CONST_DOUBLE isn't	     documented.  */	  REAL_VALUE_TYPE r;	  long l;	  /* FIXME:  Perhaps check overflow of the "single".  */	  REAL_VALUE_FROM_CONST_DOUBLE (r, operand);	  REAL_VALUE_TO_TARGET_SINGLE (r, l);	  fprintf (file, "0x%lx", l);	}      return;    case UNSPEC:      ASSERT_PLT_UNSPEC (operand);      /* Fall through.  */    case CONST:      cris_output_addr_const (file, operand);      return;    case MULT:    case ASHIFT:      {	/* For a (MULT (reg X) const_int) we output "rX.S".  */	int i = GET_CODE (XEXP (operand, 1)) == CONST_INT	  ? INTVAL (XEXP (operand, 1)) : INTVAL (XEXP (operand, 0));	rtx reg = GET_CODE (XEXP (operand, 1)) == CONST_INT	  ? XEXP (operand, 0) : XEXP (operand, 1);	if (GET_CODE (reg) != REG	    || (GET_CODE (XEXP (operand, 0)) != CONST_INT		&& GET_CODE (XEXP (operand, 1)) != CONST_INT))	  LOSE_AND_RETURN ("unexpected multiplicative operand", x);	cris_print_base (reg, file);	fprintf (file, ".%c",		 i == 0 || (i == 1 && GET_CODE (operand) == MULT) ? 'b'		 : i == 4 ? 'd'		 : (i == 2 && GET_CODE (operand) == MULT) || i == 1 ? 'w'		 : 'd');	return;      }    default:      /* No need to handle all strange variants, let output_addr_const	 do it for us.  */      if (CONSTANT_P (operand))	{	  cris_output_addr_const (file, operand);	  return;	}      LOSE_AND_RETURN ("unexpected operand", x);    }}/* The PRINT_OPERAND_ADDRESS worker.  */voidcris_print_operand_address (file, x)     FILE *file;     rtx x;{  /* All these were inside MEM:s so output indirection characters.  */  putc ('[', file);  if (CONSTANT_ADDRESS_P (x))    cris_output_addr_const (file, x);  else if (BASE_OR_AUTOINCR_P (x))    cris_print_base (x, file);  else if (GET_CODE (x) == PLUS)    {      rtx x1, x2;      x1 = XEXP (x, 0);      x2 = XEXP (x, 1);      if (BASE_P (x1))	{	  cris_print_base (x1, file);	  cris_print_index (x2, file);	}      else if (BASE_P (x2))	{	  cris_print_base (x2, file);	  cris_print_index (x1, file);	}      else	LOSE_AND_RETURN ("unrecognized address", x);    }  else if (GET_CODE (x) == MEM)    {      /* A DIP.  Output more indirection characters.  */      putc ('[', file);      cris_print_base (XEXP (x, 0), file);      putc (']', file);    }  else    LOSE_AND_RETURN ("unrecognized address", x);  putc (']', file);}/* The RETURN_ADDR_RTX worker.   We mark that the return address is used, either by EH or   __builtin_return_address, for use by the function prologue and   epilogue.  FIXME: This isn't optimal; we just use the mark in the   prologue and epilogue to say that the return address is to be stored   in the stack frame.  We could return SRP for leaf-functions and use the   initial-value machinery.  */rtxcris_return_addr_rtx (count, frameaddr)     int count;     rtx frameaddr ATTRIBUTE_UNUSED;{  cfun->machine->needs_return_address_on_stack = 1;  /* The return-address is stored just above the saved frame-pointer (if     present).  Apparently we can't eliminate from the frame-pointer in     that direction, so use the incoming args (maybe pretended) pointer.  */  return count == 0    ? gen_rtx_MEM (Pmode, plus_constant (virtual_incoming_args_rtx, -4))    : NULL_RTX;}/* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only   handles FP -> SP elimination offset.  */static intcris_initial_frame_pointer_offset (){  int regno;  /* Initial offset is 0 if we don't have a frame pointer.  */  int offs = 0;  /* And 4 for each register pushed.  */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)    if ((((regs_ever_live[regno]	   && !call_used_regs[regno])	  || (regno == (int) PIC_OFFSET_TABLE_REGNUM	      && (current_function_uses_pic_offset_table		  /* It is saved anyway, if there would be a gap.  */		  || (flag_pic		      && regs_ever_live[regno + 1]		      && !call_used_regs[regno + 1]))))	 && (regno != FRAME_POINTER_REGNUM || !frame_pointer_needed)	 && regno != CRIS_SRP_REGNUM)	|| (current_function_calls_eh_return	    && (regno == EH_RETURN_DATA_REGNO (0)		|| regno == EH_RETURN_DATA_REGNO (1)		|| regno == EH_RETURN_DATA_REGNO (2)		|| regno == EH_RETURN_DATA_REGNO (3))))      offs += 4;  /* And then, last, we add the locals allocated.  */  offs += get_frame_size ();  /* And more; the accumulated args size.  */  offs += current_function_outgoing_args_size;  /* Then round it off, in case we use aligned stack.  */  if (TARGET_STACK_ALIGN)    offs = TARGET_ALIGN_BY_32 ? (offs + 3) & ~3 : (offs + 1) & ~1;  return offs;}/* The INITIAL_ELIMINATION_OFFSET worker.   Calculate the difference between imaginary registers such as frame   pointer and the stack pointer.  Used to eliminate the frame pointer   and imaginary arg pointer.  */intcris_initial_elimination_offset (fromreg, toreg)     int fromreg;     int toreg;{  int fp_sp_offset    = cris_initial_frame_pointer_offset ();  /* We should be able to use regs_ever_live and related prologue     information here, or alpha should not as well.  */  int return_address_on_stack    = regs_ever_live[CRIS_SRP_REGNUM]    || cfun->machine->needs_return_address_on_stack != 0;  /* Here we act as if the frame-pointer is needed.  */  int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0);  if (fromreg == ARG_POINTER_REGNUM      && toreg == FRAME_POINTER_REGNUM)    return ap_fp_offset;  /* Between the frame pointer and the stack are only "normal" stack     variables and saved registers.  */  if (fromreg == FRAME_POINTER_REGNUM      && toreg == STACK_POINTER_REGNUM)    return fp_sp_offset;  /* We need to balance out the frame pointer here.  */  if (fromreg == ARG_POINTER_REGNUM      && toreg == STACK_POINTER_REGNUM)    return ap_fp_offset + fp_sp_offset - 4;  abort ();}/*  This function looks into the pattern to see how this insn affects    condition codes.    Used when to eliminate test insns before a condition-code user,    such as a "scc" insn or a conditional branch.  This includes    checking if the entities that cc was updated by, are changed by the    operation.    Currently a jumble of the old peek-inside-the-insn and the newer    check-cc-attribute methods.  */voidcris_notice_update_cc (exp, insn)     rtx exp;     rtx insn;{  /* Check if user specified "-mcc-init" as a bug-workaround.  FIXME:     TARGET_CCINIT does not work; we must set CC_REVERSED as below.     Several test-cases will otherwise fail, for example     gcc.c-torture/execute/20000217-1.c -O0 and -O1.  */  if (TARGET_CCINIT)    {      CC_STATUS_INIT;      return;    }  /* Slowly, we're converting to using attributes to control the setting     of condition-code status.  */  switch (get_attr_cc (insn))    {    case CC_NONE:      /* Even if it is "none", a setting may clobber a previous	 cc-value, so check.  */      if (GET_CODE (exp) == SET)	{	  if (cc_status.value1	      && cris_reg_overlap_mentioned_p (SET_DEST (exp),					     cc_status.value1))	    cc_status.value1 = 0;	  if (cc_status.value2	      && cris_reg_overlap_mentioned_p (SET_DEST (exp),					     cc_status.value2))	    cc_status.value2 = 0;	}      return;    case CC_CLOBBER:      CC_STATUS_INIT;      break;    case CC_NORMAL:      /* Which means, for:	 (set (cc0) (...)):	 CC is (...).	 (set (reg) (...)):	 CC is (reg) and (...) - unless (...) is 0, then CC does not change.	 CC_NO_OVERFLOW unless (...) is reg or mem.	 (set (mem) (...)):	 CC does not change.	 (set (pc) (...)):	 CC does not change.	 (parallel	  (set (reg1) (mem (bdap/biap)))	  (set (reg2) (bdap/biap))):	 CC is (reg1) and (mem (reg2))	 (parallel	  (set (mem (bdap/biap)) (reg1)) [or 0]	  (set (reg2) (bdap/biap))):	 CC does not change.	 (where reg and mem includes strict_low_parts variants thereof)	 For all others, assume CC is clobbered.	 Note that we do not have to care about setting CC_NO_OVERFLOW,	 since the overflow flag is set to 0 (i.e. right) for

⌨️ 快捷键说明

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