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

📄 i860.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
   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 i860/sysv4.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 (FILE *asm_file, 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 specifies using `adds' for	 this, but the native C compiler on SVR4 uses `addu'.  */      fprintf (asm_file, "\taddu -" HOST_WIDE_INT_PRINT_DEC ",%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",	i860_reg_prefix, i860_reg_prefix);      /* Setup the new frame pointer.  The ABI specifies that this is to	 be done after preserving registers (using `adds'), but that's not	 what the native C compiler on SVR4 does.  */      fprintf (asm_file, "\taddu 0,%ssp,%sfp\n",	i860_reg_prefix, i860_reg_prefix);      /* Get the value of frame_lower_bytes into r31.  */      fprintf (asm_file, "\torh " HOST_WIDE_INT_PRINT_DEC ",%sr0,%sr31\n",	frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix);      fprintf (asm_file, "\tor " HOST_WIDE_INT_PRINT_DEC ",%sr31,%sr31\n",	frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix);      /* Now re-adjust the stack pointer using the value in r31.	 The ABI specifies that this is done with `subs' but SDB may	 prefer `subu'.  */      fprintf (asm_file, "\tsubu %ssp,%sr31,%ssp\n",	i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);      /* Preserve registers.  The ABI specifies that this is to be done	 before setting up the new frame pointer, but that's not what the	 native C compiler on SVR4 does.  */      for (i = 1; i < 32; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes  + (4 * preserved_so_far++),	    i860_reg_prefix);      for (i = 32; i < 64; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      /* Save the return address.  */      if (must_preserve_r1)        fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n",	  i860_reg_prefix, i860_reg_prefix);    }  else    {      /* Adjust the stack pointer.  The ABI specifies using `adds' for this,	 but the native C compiler on SVR4 uses `addu'.  */      fprintf (asm_file, "\taddu -" HOST_WIDE_INT_PRINT_DEC ",%ssp,%ssp\n",	total_fsize, i860_reg_prefix, i860_reg_prefix);      /* Save the old frame pointer.  */      fprintf (asm_file, "\tst.l %sfp," HOST_WIDE_INT_PRINT_DEC "(%ssp)\n",	i860_reg_prefix, frame_lower_bytes, i860_reg_prefix);      /* Setup the new frame pointer.  The ABI specifies that this is to be	 done after preserving registers and after saving the return address,	 (and to do it using `adds'), but that's not what the native C	 compiler on SVR4 does.  */      fprintf (asm_file, "\taddu " HOST_WIDE_INT_PRINT_DEC ",%ssp,%sfp\n",	frame_lower_bytes, i860_reg_prefix, i860_reg_prefix);      /* Preserve registers.  The ABI specifies that this is to be done	 before setting up the new frame pointer, but that's not what the	 native compiler on SVR4 does.  */      for (i = 1; i < 32; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tst.l %s%s,%d(%sfp)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      for (i = 32; i < 64; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tfst.l %s%s,%d(%sfp)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      /* Save the return address.  The ABI specifies that this is to be	 done earlier, and also via an offset from %sp, but the native C	 compiler on SVR4 does it later (i.e. now) and uses an offset from	 %fp.  */      if (must_preserve_r1)        fprintf (asm_file, "\tst.l %sr1,4(%sfp)\n",	  i860_reg_prefix, i860_reg_prefix);    }#else /* defined(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 (thereby allocating a new frame).  */      fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n",	frame_upper_bytes, i860_reg_prefix, i860_reg_prefix);      /* Save the caller's frame pointer.  */      fprintf (asm_file, "\tst.l %sfp,0(%ssp)\n",	i860_reg_prefix, i860_reg_prefix);      /* Save return address.  */      if (must_preserve_r1)        fprintf (asm_file, "\tst.l %sr1,4(%ssp)\n",	  i860_reg_prefix, i860_reg_prefix);      /* Get the value of frame_lower_bytes into r31 for later use.  */      fprintf (asm_file, "\torh %d,%sr0,%sr31\n",	frame_lower_bytes >> 16, i860_reg_prefix, i860_reg_prefix);      fprintf (asm_file, "\tor %d,%sr31,%sr31\n",	frame_lower_bytes & 0xffff, i860_reg_prefix, i860_reg_prefix);      /* Now re-adjust the stack pointer using the value in r31.  */      fprintf (asm_file, "\tsubs %ssp,%sr31,%ssp\n",	i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);      /* Pre-compute value to be used as the new frame pointer.  */      fprintf (asm_file, "\tadds %ssp,%sr31,%sr31\n",	i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);      /* Preserve registers.  */      for (i = 1; i < 32; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tst.l %s%s,%d(%sr31)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      for (i = 32; i < 64; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tfst.l %s%s,%d(%sr31)\n",	    i860_reg_prefix, reg_names[i],	    must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      /* Actually set the new value of the frame pointer.  */      fprintf (asm_file, "\tmov %sr31,%sfp\n",	i860_reg_prefix, i860_reg_prefix);    }  else    {      /* Adjust the stack pointer.  */      fprintf (asm_file, "\tadds -%d,%ssp,%ssp\n",	total_fsize, i860_reg_prefix, i860_reg_prefix);      /* Save the caller's frame pointer.  */      fprintf (asm_file, "\tst.l %sfp,%d(%ssp)\n",	i860_reg_prefix, frame_lower_bytes, i860_reg_prefix);      /* Save the return address.  */      if (must_preserve_r1)        fprintf (asm_file, "\tst.l %sr1,%d(%ssp)\n",	  i860_reg_prefix, frame_lower_bytes + 4, i860_reg_prefix);      /* Preserve registers.  */      for (i = 1; i < 32; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tst.l %s%s,%d(%ssp)\n",	    i860_reg_prefix, reg_names[i],	    frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      for (i = 32; i < 64; i++)        if (regs_ever_live[i] && ! call_used_regs[i])          fprintf (asm_file, "\tfst.l %s%s,%d(%ssp)\n",	    i860_reg_prefix, reg_names[i],	    frame_lower_bytes + must_preserve_bytes + (4 * preserved_so_far++),	    i860_reg_prefix);      /* Setup the new frame pointer.  */      fprintf (asm_file, "\tadds %d,%ssp,%sfp\n",	frame_lower_bytes, i860_reg_prefix, i860_reg_prefix);    }#endif /* defined(I860_STRICT_ABI_PROLOGUES) */#ifdef ASM_OUTPUT_PROLOGUE_SUFFIX  ASM_OUTPUT_PROLOGUE_SUFFIX (asm_file);#endif /* defined(ASM_OUTPUT_PROLOGUE_SUFFIX) */}/* This function generates the assembly code for function exit.   ASM_FILE is a stdio stream to output the code to.   SIZE is an int: how many units of temporary storage to allocate.   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.   Note that when we go to restore the preserved register values we must   not try to address their slots by using offsets from the stack pointer.   That's because the stack pointer may have been moved during the function   execution due to a call to alloca().  Rather, we must restore all   preserved registers via offsets from the frame pointer value.   Note also that when the current frame is being "popped" (by adjusting   the value of the stack pointer) on function exit, we must (for the   sake of alloca) set the new value of the stack pointer based upon   the current value of the frame pointer.  We can't just add what we   believe to be the (static) frame size to the stack pointer because   if we did that, and alloca() had been called during this function,   we would end up returning *without* having fully deallocated all of   the space grabbed by alloca.  If that happened, and a function   containing one or more alloca() calls was called over and over again,   then the stack would grow without limit!   Finally note that the epilogues generated here are completely ABI   compliant.  They go out of their way to insure that the value in   the frame pointer register is never less than the value in the stack   pointer register.  It's not clear why this relationship needs to be   maintained at all times, but maintaining it only costs one extra   instruction, so what the hell.  *//* This corresponds to a version 4 TDESC structure. Lower numbered   versions successively omit the last word of the structure. We   don't try to handle version 5 here.  */typedef struct TDESC_flags {	int version:4;	int reg_packing:1;	int callable_block:1;	int reserved:4;	int fregs:6;	/* fp regs 2-7 */	int iregs:16;	/* regs 0-15 */} TDESC_flags;typedef struct TDESC {	TDESC_flags flags;	int integer_reg_offset;		/* same as must_preserve_bytes */	int floating_point_reg_offset;	unsigned int positive_frame_size;	/* same as frame_upper_bytes */	unsigned int negative_frame_size;	/* same as frame_lower_bytes */} TDESC;static voidi860_output_function_epilogue (FILE *asm_file, HOST_WIDE_INT local_bytes){  register HOST_WIDE_INT frame_upper_bytes;  register HOST_WIDE_INT frame_lower_bytes;  register HOST_WIDE_INT preserved_reg_bytes = 0;  register unsigned i;  register unsigned restored_so_far = 0;  register unsigned int_restored;  register unsigned mask;  unsigned intflags=0;  register TDESC_flags *flags = (TDESC_flags *) &intflags;#ifdef	OUTPUT_TDESC	/* Output an ABI-compliant TDESC entry */  const char *long_op = integer_asm_op (4, TRUE);#endif  flags->version = 4;  flags->reg_packing = 1;  flags->iregs = 8;	/* old fp always gets saved */  /* Round-up the frame_lower_bytes so that it's a multiple of 16.  */  frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT;  /* Count the number of registers that were preserved in the prologue.     Ignore r0.  It is never preserved.  */  for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)    {      if (regs_ever_live[i] && ! call_used_regs[i])        preserved_reg_bytes += 4;    }  /* The upper part of each frame will contain only saved fp,     the saved r1, and stack slots for all of the other "preserved"     registers that we find we will need to save & restore.  */

⌨️ 快捷键说明

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