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

📄 i860.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
     nobody is going to try to do a memcpy() of more than half of the     entire address space (i.e. 2 gigabytes) anyway.  */  output_asm_insn ("bc .Le%3", xoperands);  /* Make available a register which is a temporary.  */  xoperands[6] = operands[6];  /* Now the actual loop.     In xoperands, elements 1 and 0 are the input and output vectors.     Element 2 is the loop index.  Element 5 is the increment.  */  output_asm_insn ("subs %1,%5,%1", xoperands);  output_asm_insn ("bla %5,%2,.Lm%3", xoperands);  output_asm_insn ("adds %0,%2,%6", xoperands);  output_asm_insn ("\n.Lm%3:", xoperands);	    /* Label for bla above.  */  output_asm_insn ("\n.Ls%3:",  xoperands);	    /* Loop start label. */  output_asm_insn ("adds %5,%6,%6", xoperands);  /* NOTE:  The code here which is supposed to handle the cases where the     sources and destinations are known to start on a 4 or 2 byte boundary     are currently broken.  They fail to do anything about the overflow     bytes which might still need to be copied even after we have copied     some number of words or halfwords.  Thus, for now we use the lowest     common denominator, i.e. the code which just copies some number of     totally unaligned individual bytes.  (See the calculation of     chunk_size above.  */  if (chunk_size == 4)    {      output_asm_insn ("ld.l %2(%1),%?r31", xoperands);      output_asm_insn ("bla %5,%2,.Ls%3", xoperands);      output_asm_insn ("st.l %?r31,8(%6)", xoperands);    }  else if (chunk_size == 2)    {      output_asm_insn ("ld.s %2(%1),%?r31", xoperands);      output_asm_insn ("bla %5,%2,.Ls%3", xoperands);      output_asm_insn ("st.s %?r31,4(%6)", xoperands);    }  else /* chunk_size == 1 */    {      output_asm_insn ("ld.b %2(%1),%?r31", xoperands);      output_asm_insn ("bla %5,%2,.Ls%3", xoperands);      output_asm_insn ("st.b %?r31,2(%6)", xoperands);    }  output_asm_insn ("\n.Le%3:", xoperands);	    /* Here if count <= 0.  */  return "";}#if 0/* Output a delayed branch insn with the delay insn in its   branch slot.  The delayed branch insn template is in TEMPLATE,   with operands OPERANDS.  The insn in its delay slot is INSN.   As a special case, since we know that all memory transfers are via   ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory   reference around the branch as	orh ha%x,%?r0,%?r31	b ...	ld/st l%x(%?r31),...   As another special case, we handle loading (SYMBOL_REF ...) and   other large constants around branches as well:	orh h%x,%?r0,%0	b ...	or l%x,%0,%1   *//* ??? Disabled because this re-recognition is incomplete and causes   constrain_operands to segfault.  Anyone who cares should fix up   the code to use the DBR pass.  */const char *output_delayed_branch (template, operands, insn)     const char *template;     rtx *operands;     rtx insn;{  rtx src = XVECEXP (PATTERN (insn), 0, 1);  rtx dest = XVECEXP (PATTERN (insn), 0, 0);  /* See if we are doing some branch together with setting some register     to some 32-bit value which does (or may) have some of the high-order     16 bits set.  If so, we need to set the register in two stages.  One     stage must be done before the branch, and the other one can be done     in the delay slot.  */  if ( (GET_CODE (src) == CONST_INT	&& ((unsigned) INTVAL (src) & (unsigned) 0xffff0000) != (unsigned) 0)      || (GET_CODE (src) == SYMBOL_REF)      || (GET_CODE (src) == LABEL_REF)      || (GET_CODE (src) == CONST))    {      rtx xoperands[2];      xoperands[0] = dest;      xoperands[1] = src;      CC_STATUS_PARTIAL_INIT;      /* Output the `orh' insn.  */      output_asm_insn ("orh %H1,%?r0,%0", xoperands);      /* Output the branch instruction next.  */      output_asm_insn (template, operands);      /* Now output the `or' insn.  */      output_asm_insn ("or %L1,%0,%0", xoperands);    }  else if ((GET_CODE (src) == MEM	    && CONSTANT_ADDRESS_P (XEXP (src, 0)))	   || (GET_CODE (dest) == MEM	       && CONSTANT_ADDRESS_P (XEXP (dest, 0))))    {      rtx xoperands[2];      const char *split_template;      xoperands[0] = dest;      xoperands[1] = src;      /* Output the `orh' insn.  */      if (GET_CODE (src) == MEM)	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		 && (cc_prev_status.flags & CC_HI_R31_ADJ)		 && cc_prev_status.mdep == XEXP (operands[1], 0)))	    {	      CC_STATUS_INIT;	      output_asm_insn ("orh %h1,%?r0,%?r31", xoperands);	    }	  split_template = load_opcode (GET_MODE (dest),					"%L1(%?r31),%0", dest);	}      else	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		 && (cc_prev_status.flags & CC_HI_R31_ADJ)		 && cc_prev_status.mdep == XEXP (operands[0], 0)))	    {	      CC_STATUS_INIT;	      output_asm_insn ("orh %h0,%?r0,%?r31", xoperands);	    }	  split_template = store_opcode (GET_MODE (dest),					 "%r1,%L0(%?r31)", src);	}      /* Output the branch instruction next.  */      output_asm_insn (template, operands);      /* Now output the load or store.	 No need to do a CC_STATUS_INIT, because we are branching anyway.  */      output_asm_insn (split_template, xoperands);    }  else    {      int insn_code_number;      rtx pat = gen_rtx_SET (VOIDmode, dest, src);      rtx delay_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, pat, -1, 0, 0);      int i;      /* Output the branch instruction first.  */      output_asm_insn (template, operands);      /* Now recognize the insn which we put in its delay slot.	 We must do this after outputting the branch insn,	 since operands may just be a pointer to `recog_data.operand'.  */      INSN_CODE (delay_insn) = insn_code_number	= recog (pat, delay_insn, NULL);      if (insn_code_number == -1)	abort ();      for (i = 0; i < insn_data[insn_code_number].n_operands; i++)	{	  if (GET_CODE (recog_data.operand[i]) == SUBREG)	    alter_subreg (&recog_data.operand[i]);	}      insn_extract (delay_insn);      if (! constrain_operands (1))	fatal_insn_not_found (delay_insn);      template = get_insn_template (insn_code_number, delay_insn);      output_asm_insn (template, recog_data.operand);    }  CC_STATUS_INIT;  return "";}/* Output a newly constructed insn DELAY_INSN.  */const char *output_delay_insn (delay_insn)     rtx delay_insn;{  const char *template;  int insn_code_number;  int i;  /* Now recognize the insn which we put in its delay slot.     We must do this after outputting the branch insn,     since operands may just be a pointer to `recog_data.operand'.  */  insn_code_number = recog_memoized (delay_insn);  if (insn_code_number == -1)    abort ();  /* Extract the operands of this delay insn.  */  INSN_CODE (delay_insn) = insn_code_number;  insn_extract (delay_insn);  /* It is possible that this insn has not been properly scanned by final     yet.  If this insn's operands don't appear in the peephole's     actual operands, then they won't be fixed up by final, so we     make sure they get fixed up here.  -- This is a kludge.  */  for (i = 0; i < insn_data[insn_code_number].n_operands; i++)    {      if (GET_CODE (recog_data.operand[i]) == SUBREG)	alter_subreg (&recog_data.operand[i]);    }  if (! constrain_operands (1))    abort ();  cc_prev_status = cc_status;  /* Update `cc_status' for this instruction.     The instruction's output routine may change it further.     If the output routine for a jump insn needs to depend     on the cc status, it should look at cc_prev_status.  */  NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);  /* Now get the template for what this insn would     have been, without the branch.  */  template = get_insn_template (insn_code_number, delay_insn);  output_asm_insn (template, recog_data.operand);  return "";}#endif/* Special routine to convert an SFmode value represented as a   CONST_DOUBLE into its equivalent unsigned long bit pattern.   We convert the value from a double precision floating-point   value to single precision first, and thence to a bit-wise   equivalent unsigned long value.  This routine is used when   generating an immediate move of an SFmode value directly   into a general register because the svr4 assembler doesn't   grok floating literals in instruction operand contexts.  */unsigned longsfmode_constant_to_ulong (x)     rtx x;{  REAL_VALUE_TYPE d;  union { float f; unsigned long i; } u2;  if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != SFmode)    abort ();#if TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT error IEEE emulation needed#endif  REAL_VALUE_FROM_CONST_DOUBLE (d, x);  u2.f = d;  return u2.i;}/* This function generates the assembly code for function entry.   ASM_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 macro is responsible for   knowing which registers should not be saved even if used.   NOTE: `frame_lower_bytes' is the count of bytes which will lie   between the new `fp' value and the new `sp' value after the   prologue is done.  `frame_upper_bytes' is the count of bytes   that will lie between the new `fp' and the *old* `sp' value   after the new `fp' is setup (in the prologue).  The upper   part of each frame always includes at least 2 words (8 bytes)   to hold the saved frame pointer and the saved return address.   The svr4 ABI for the i860 now requires that the values of the   stack pointer and frame pointer registers be kept aligned to   16-byte boundaries at all times.  We obey that restriction here.   The svr4 ABI for the i860 is entirely vague when it comes to specifying   exactly where the "preserved" registers should be saved.  The native   svr4 C compiler I now have doesn't help to clarify the requirements   very much because it is plainly out-of-date and non-ABI-compliant   (in at least one important way, i.e. how it generates function   epilogues).   The native svr4 C compiler saves the "preserved" registers (i.e.   r4-r15 and f2-f7) in the lower part of a frame (i.e. at negative   offsets from the frame pointer).   Previous versions of GCC also saved the "preserved" registers in the   "negative" part of the frame, but they saved them using positive   offsets from the (adjusted) stack pointer (after it had been adjusted   to allocate space for the new frame).  That's just plain wrong   because if the current function calls alloca(), the stack pointer   will get moved, and it will be impossible to restore the registers   properly again after that.   Both compilers handled parameter registers (i.e. r16-r27 and f8-f15)   by copying their values either into various "preserved" registers or   into stack slots in the lower part of the current frame (as seemed   appropriate, depending upon subsequent usage of these values).   Here we want to save the preserved registers at some offset from the   frame pointer register so as to avoid any possible problems arising   from calls to alloca().  We can either save them at small positive   offsets from the frame pointer, or at small negative offsets from   the frame pointer.  If we save them at small negative offsets from   the frame pointer (i.e. in the lower part of the frame) then we   must tell the rest of GCC (via STARTING_FRAME_OFFSET) exactly how   many bytes of space we plan to use in the lower part of the frame   for this purpose.  Since other parts of the compiler reference the   value of STARTING_FRAME_OFFSET long before final() calls this function,   we would have to go ahead and assume the worst-case storage requirements   for saving all of the "preserved" registers (and use that number, i.e.   `80', to define STARTING_FRAME_OFFSET) if we wanted to save them in   the lower part of the frame.  That could potentially be very wasteful,   and that wastefulness could really hamper people compiling for embedded   i860 targets with very tight limits on stack space.  Thus, we choose   here to save the preserved registers in the upper part of the   frame, so that we can decide at the very last minute how much (or how   little) space we must allocate for this purpose.   To satisfy the needs of the svr4 ABI "tdesc" scheme, preserved   registers must always be saved so that the saved values of registers   with higher numbers are at higher addresses.  We obey that restriction   here.   There are two somewhat different ways that you can generate prologues   here... i.e. pedantically ABI-compliant, and the "other" way.  The   "other" way is more consistent with what is currently generated by the   "native" svr4 C compiler for the i860.  That's important if you want   to use the current (as of 8/91) incarnation of svr4 SDB for the i860.   The SVR4 SDB for the i860 insists on having function prologues be   non-ABI-compliant!   To get fully ABI-compliant prologues, define I860_STRICT_ABI_PROLOGUES   in the i860svr4.h file.  (By default this is *not* defined).   The differences between the ABI-compliant and non-ABI-compliant prologues   are that (a) the ABI version seems to require the use of *signed*   (rather than unsigned) adds and subtracts, and (b) the ordering of   the various steps (e.g. saving preserved registers, saving the   return address, setting up the new frame pointer value) is different.   For strict ABI compliance, it seems to be the case that the very last   thing that is supposed to happen in the prologue is getting the frame   pointer set to its new value (but only after everything else has   already been properly setup).  We do that here, but only if the symbol   I860_STRICT_ABI_PROLOGUES is defined.*/#ifndef STACK_ALIGNMENT#define STACK_ALIGNMENT	16#endifconst char *current_function_original_name;static int must_preserve_r1;static unsigned must_preserve_bytes;static voidi860_output_function_prologue (asm_file, local_bytes)     register FILE *asm_file;     register HOST_WIDE_INT local_bytes;{  register HOST_WIDE_INT frame_lower_bytes;  register HOST_WIDE_INT frame_upper_bytes;  register HOST_WIDE_INT total_fsize;  register unsigned preserved_reg_bytes = 0;  register unsigned i;  register unsigned preserved_so_far = 0;  must_preserve_r1 = (optimize < 2 || ! leaf_function_p ());  must_preserve_bytes = 4 + (must_preserve_r1 ? 4 : 0);  /* Count registers that need preserving.  Ignore r0.  It never needs     preserving.  */  for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)    {      if (regs_ever_live[i] && ! call_used_regs[i])        preserved_reg_bytes += 4;    }  /* Round-up the frame_lower_bytes so that it's a multiple of 16. */  frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;  /* The upper part of each frame will contain the saved fp,     the saved r1, and stack slots for all of the other "preserved"     registers that we find we will need to save & restore. */  frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes;  /* Round-up the frame_upper_bytes so that it's a multiple of 16. */  frame_upper_bytes    = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;  total_fsize = frame_upper_bytes + frame_lower_bytes;#ifndef I860_STRICT_ABI_PROLOGUES  /* There are two kinds of function prologues.     You use the "small" version if the total frame size is     small enough so that it can fit into an immediate 16-bit     value in one instruction.  Otherwise, you use the "large"     version of the function prologue.  */  if (total_fsize > 0x7fff)    {      /* Adjust the stack pointer.  The ABI sez to do this using `adds',	 but the native C compiler on svr4 uses `addu'.  */      fprintf (asm_file, "\taddu -%d,%ssp,%ssp\n",	frame_upper_bytes, i860_reg_prefix, i860_reg_prefix);      /* Save the old frame pointer.  */      fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n",

⌨️ 快捷键说明

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