This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

epilogue scheduling for ppc



I am just about to commit this to the branch.

At present, it won't work if you actually specify -msched-prolog on
ELF targets under -fpic, because of register liveness problems.  This
will go away when I do the other half of the work and we can schedule
the prologue.

The cute part is in output_epilog when !TARGET_SCHED_PROLOG.  It may
be too cute; we'll see.

-- 
- Geoffrey Keating <geoffk@cygnus.com>

===File ~/patches/cygnus/rs6000-esched-2.patch==============
Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/Attic/ChangeLog,v
retrieving revision 1.1.2.12
diff -p -u -c -p -r1.1.2.12 ChangeLog
*** ChangeLog	2000/01/13 00:42:25	1.1.2.12
--- ChangeLog	2000/01/13 01:39:05
***************
*** 1,5 ****
--- 1,26 ----
  2000-01-12  Geoff Keating  <geoffk@cygnus.com>
  
+ 	* rs6000.md: Document 'unspec' values used.
+ 	(epilogue): New expander.
+ 	(movesi_to_cr_one): New expander.
+ 	(movesi_to_cr and following): New pattern.
+ 	(lmw): New pattern.
+ 	(return_internal_si): New pattern.
+ 	(return_internal_di): New pattern.
+ 	(return_and_restore_fpregs_si): New pattern.
+ 	(return_and_restore_fpregs_di): New pattern.
+ 	* rs6000.h: Declare new functions.
+ 	* rs6000.c (rs6000_stack_info): Use current_function_is_leaf
+ 	rather than rs6000_calls_p.
+ 	(rs6000_makes_calls): Delete.
+ 	(lmw_operation): New function.
+ 	(mtcrf_operation): New function.
+ 	(rs6000_emit_epilogue): New function.
+ 	(output_epilog): Call rs6000_emit_epilogue and final if
+ 	!TARGET_SCHED_PROLOG, instead of writing text unconditionally.
+ 
+ 2000-01-12  Geoff Keating  <geoffk@cygnus.com>
+ 
  	* aix43.h (SUBSUBTARGET_SWITCHES): Document switches.
  	* aix41.h (SUBSUBTARGET_SWITCHES): Document switches.
  	* aix.h (SUBTARGET_SWITCHES): Document switches.
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.108.2.4
diff -p -u -c -p -r1.108.2.4 rs6000.c
*** rs6000.c	2000/01/12 22:01:43	1.108.2.4
--- rs6000.c	2000/01/13 01:39:05
*************** function_arg_pass_by_reference (cum, mod
*** 1659,1665 ****
  
    return 0;
  }
- 
  
  /* Perform any needed actions needed for a function that is receiving a
     variable number of arguments. 
--- 1659,1664 ----
*************** store_multiple_operation (op, mode)
*** 2431,2436 ****
--- 2430,2565 ----
  
    return 1;
  }
+ 
+ /* Return 1 for an PARALLEL suitable for mtcrf. */
+ 
+ int
+ mtcrf_operation (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+ {
+   int count = XVECLEN (op, 0);
+   int i;
+   int bitmap = 0;
+   rtx src_reg;
+ 
+   /* Perform a quick check so we don't blow up below.  */
+   if (count < 2
+       || GET_CODE (XVECEXP (op, 0, 0)) != USE
+       || GET_CODE (XEXP (XVECEXP (op, 0, 0), 0)) != CONST_INT
+       || GET_CODE (XVECEXP (op, 0, 1)) != SET
+       || GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != UNSPEC
+       || XVECLEN (SET_SRC (XVECEXP (op, 0, 1)), 0) != 2)
+     return 0;
+   src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 1)), 0, 0);
+   
+   if (GET_CODE (src_reg) != REG
+       || GET_MODE (src_reg) != SImode
+       || ! INT_REGNO_P (REGNO (src_reg)))
+     return 0;
+ 
+   for (i = 1; i < count; i++)
+     {
+       rtx exp = XVECEXP (op, 0, i);
+       rtx unspec;
+       int maskval;
+       
+       if (GET_CODE (exp) != SET
+ 	  || GET_CODE (SET_DEST (exp)) != REG
+ 	  || GET_MODE (SET_DEST (exp)) != CCmode
+ 	  || ! CR_REGNO_P (REGNO (SET_DEST (exp))))
+ 	return 0;
+       unspec = SET_SRC (exp);
+       maskval = 1 << (75 - REGNO (SET_DEST (exp)));
+       bitmap |= maskval;
+       
+       if (GET_CODE (unspec) != UNSPEC
+ 	  || XINT (unspec, 1) != 20
+ 	  || XVECLEN (unspec, 0) != 2
+ 	  || XVECEXP (unspec, 0, 0) != src_reg
+ 	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
+ 	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
+ 	return 0;
+     }
+   return INTVAL (XEXP (XVECEXP (op, 0, 0), 0)) == bitmap;
+ }
+ 
+ 
+ /* Return 1 for an PARALLEL suitable for lmw. */
+ 
+ int
+ lmw_operation (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+ {
+   int count = XVECLEN (op, 0);
+   int dest_regno;
+   rtx src_addr;
+   int base_regno;
+   HOST_WIDE_INT offset;
+   int i;
+ 
+   /* Perform a quick check so we don't blow up below.  */
+   if (count <= 1
+       || GET_CODE (XVECEXP (op, 0, 0)) != SET
+       || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+       || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+     return 0;
+ 
+   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+   src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+ 
+   if (dest_regno > 31
+       || count != 32 - dest_regno)
+     return 0;
+ 
+   if (LEGITIMATE_INDIRECT_ADDRESS_P (src_addr))
+     {
+       offset = 0;
+       base_regno = REGNO (src_addr);
+     }
+   else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, src_addr))
+     {
+       offset = INTVAL (XEXP (src_addr, 1));
+       base_regno = REGNO (XEXP (src_addr, 0));
+     }
+   else
+     return 0;
+ 
+   for (i = 0; i < count; i++)
+     {
+       rtx elt = XVECEXP (op, 0, i);
+       rtx newaddr;
+       rtx addr_reg;
+       HOST_WIDE_INT newoffset;
+ 
+       if (GET_CODE (elt) != SET
+ 	  || GET_CODE (SET_DEST (elt)) != REG
+ 	  || GET_MODE (SET_DEST (elt)) != SImode
+ 	  || REGNO (SET_DEST (elt)) != dest_regno + i
+ 	  || GET_CODE (SET_SRC (elt)) != MEM
+ 	  || GET_MODE (SET_SRC (elt)) != SImode)
+ 	return 0;
+       newaddr = XEXP (SET_SRC (elt), 0);
+       if (LEGITIMATE_INDIRECT_ADDRESS_P (newaddr))
+ 	{
+ 	  newoffset = 0;
+ 	  addr_reg = newaddr;
+ 	}
+       else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, newaddr))
+ 	{
+ 	  addr_reg = XEXP (newaddr, 0);
+ 	  newoffset = INTVAL (XEXP (newaddr, 1));
+ 	}
+       else
+ 	return 0;
+       if (REGNO (addr_reg) != base_regno
+ 	  || newoffset != offset + 4 * i)
+ 	return 0;
+     }
+ 
+   return 1;
+ }
  
  /* Return 1 if OP is a comparison operation that is valid for a branch insn.
     We only check the opcode against the mode of the CC value here.  */
*************** first_fp_reg_to_save ()
*** 3577,3603 ****
  
    return first_reg;
  }
- 
- /* Return non-zero if this function makes calls.  */
- 
- int
- rs6000_makes_calls ()
- {
-   rtx insn;
- 
-   /* If we are profiling, we will be making a call to __mcount.
-      Under the System V ABI's, we store the LR directly, so
-      we don't need to do it here.  */
-   if (DEFAULT_ABI == ABI_AIX && profile_flag)
-     return 1;
- 
-   for (insn = get_insns (); insn; insn = next_insn (insn))
-     if (GET_CODE (insn) == CALL_INSN)
-       return 1;
- 
-   return 0;
- }
- 
  
  /* Calculate the stack information for the current function.  This is
     complicated by having two separate calling sequences, the AIX calling
--- 3706,3711 ----
*************** rs6000_stack_info ()
*** 3759,3765 ****
    info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
  
    /* Does this function call anything? */
!   info_ptr->calls_p = rs6000_makes_calls ();
  
    /* Allocate space to save the toc. */
    if (abi == ABI_NT && info_ptr->calls_p)
--- 3867,3873 ----
    info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
  
    /* Does this function call anything? */
!   info_ptr->calls_p = ! current_function_is_leaf;
  
    /* Allocate space to save the toc. */
    if (abi == ABI_NT && info_ptr->calls_p)
*************** output_prolog (file, size)
*** 4541,4649 ****
      }
  }
  
! /* Write function epilogue.  */
  
  void
! output_epilog (file, size)
!      FILE *file;
!      int size ATTRIBUTE_UNUSED;
  {
!   rs6000_stack_t *info = rs6000_stack_info ();
!   const char *load_reg = (TARGET_32BIT) ? "\t{l|lwz} %s,%d(%s)\n" : "\tld %s,%d(%s)\n";
!   rtx insn = get_last_insn ();
!   int sp_reg = 1;
    int sp_offset = 0;
  
!   /* If the last insn was a BARRIER, we don't have to write anything except
!      the trace table.  */
!   if (GET_CODE (insn) == NOTE)
!     insn = prev_nonnote_insn (insn);
!   if (insn == 0 ||  GET_CODE (insn) != BARRIER)
!     {
!       /* If we have a frame pointer, a call to alloca,  or a large stack
! 	 frame, restore the old stack pointer using the backchain.  Otherwise,
! 	 we know what size to update it with.  */
!       if (frame_pointer_needed || current_function_calls_alloca
! 	  || info->total_size > 32767)
! 	{
! 	  /* Under V.4, don't reset the stack pointer until after we're done
! 	     loading the saved registers.  */
! 	  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
! 	    sp_reg = 11;
  
! 	  asm_fprintf (file, load_reg, reg_names[sp_reg], 0, reg_names[1]);
! 	}
!       else if (info->push_p)
  	{
! 	  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
! 	    sp_offset = info->total_size;
! 	  else
! 	    asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
! 			 reg_names[1], info->total_size, reg_names[1]);
  	}
! 
!       /* Get the old lr if we saved it.  */
!       if (info->lr_save_p)
! 	asm_fprintf (file, load_reg, reg_names[0], info->lr_save_offset + sp_offset, reg_names[sp_reg]);
  
!       /* Get the old cr if we saved it.  */
!       if (info->cr_save_p)
! 	asm_fprintf (file, load_reg, reg_names[12], info->cr_save_offset + sp_offset, reg_names[sp_reg]);
  
!       /* Set LR here to try to overlap restores below.  */
!       if (info->lr_save_p)
! 	asm_fprintf (file, "\tmtlr %s\n", reg_names[0]);
  
!       /* Restore gpr's.  */
!       if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
  	{
! 	  int regno    = info->first_gp_reg_save;
! 	  int loc      = info->gp_save_offset + sp_offset;
! 	  int reg_size = (TARGET_32BIT) ? 4 : 8;
! 
! 	  for ( ; regno < 32; regno++, loc += reg_size)
! 	    asm_fprintf (file, load_reg, reg_names[regno], loc, reg_names[sp_reg]);
  	}
  
!       else if (info->first_gp_reg_save != 32)
! 	asm_fprintf (file, "\t{lm|lmw} %s,%d(%s)\n",
! 		     reg_names[info->first_gp_reg_save],
! 		     info->gp_save_offset + sp_offset,
! 		     reg_names[sp_reg]);
  
!       /* Restore fpr's if we can do it without calling a function.  */
!       if (FP_SAVE_INLINE (info->first_fp_reg_save))
  	{
! 	  int regno = info->first_fp_reg_save;
! 	  int loc   = info->fp_save_offset + sp_offset;
  
! 	  for ( ; regno < 64; regno++, loc += 8)
! 	    asm_fprintf (file, "\tlfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[sp_reg]);
  	}
  
!       /* If we saved cr, restore it here.  Just those of cr2, cr3, and cr4
! 	 that were used.  */
!       if (info->cr_save_p)
! 	asm_fprintf (file, "\tmtcrf %d,%s\n",
! 		     (regs_ever_live[70] != 0) * 0x20
! 		     + (regs_ever_live[71] != 0) * 0x10
! 		     + (regs_ever_live[72] != 0) * 0x8, reg_names[12]);
! 
!       /* If this is V.4, unwind the stack pointer after all of the loads
! 	 have been done */
!       if (sp_offset != 0)
! 	asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
! 		     reg_names[1], sp_offset, reg_names[1]);
!       else if (sp_reg != 1)
! 	asm_fprintf (file, "\tmr %s,%s\n", reg_names[1], reg_names[sp_reg]);
  
!       /* If we have to restore more than two FP registers, branch to the
! 	 restore function.  It will return to our caller.  */
!       if (info->first_fp_reg_save != 64 && !FP_SAVE_INLINE (info->first_fp_reg_save))
! 	asm_fprintf (file, "\tb %s%d%s\n", RESTORE_FP_PREFIX,
! 		     info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
!       else
! 	asm_fprintf (file, "\t{br|blr}\n");
      }
  
    /* Output a traceback table here.  See /usr/include/sys/debug.h for info
--- 4649,4944 ----
      }
  }
  
! /* Emit function epilogue as insns.  */
  
  void
! rs6000_emit_epilogue(sibcall)
!      int sibcall;
  {
!   rs6000_stack_t *info;
!   int saving_FPRs_inline;
!   int using_load_multiple;
!   int using_mfcr_multiple;
!   int use_backchain_to_restore_sp;
    int sp_offset = 0;
+   rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
+   rtx frame_reg_rtx = sp_reg_rtx;
+   enum machine_mode reg_mode = (TARGET_32BIT) ? SImode : DImode;
+   int reg_size = (TARGET_32BIT) ? 4 : 8;
+   rtx insn;
+   int i;
  
!   info = rs6000_stack_info ();
!   using_load_multiple = (TARGET_MULTIPLE && !TARGET_64BIT
! 			 && info->first_gp_reg_save < 31);
!   saving_FPRs_inline = (sibcall
! 			|| info->first_fp_reg_save == 64
! 			|| FP_SAVE_INLINE (info->first_fp_reg_save));
!   use_backchain_to_restore_sp = (frame_pointer_needed 
! 				 || current_function_calls_alloca
! 				 || info->total_size > 32767);
!   using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
! 			 || rs6000_cpu == PROCESSOR_PPC603
! 			 || rs6000_cpu == PROCESSOR_PPC750
! 			 || optimize_size);
! 
!   /* If we have a frame pointer, a call to alloca,  or a large stack
!      frame, restore the old stack pointer using the backchain.  Otherwise,
!      we know what size to update it with.  */
!   if (use_backchain_to_restore_sp)
!     {
!       /* Under V.4, don't reset the stack pointer until after we're done
! 	 loading the saved registers.  */
!       if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
! 	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
! 
!       insn = emit_move_insn (frame_reg_rtx,
! 			     gen_rtx_MEM (reg_mode, sp_reg_rtx));
!       RTX_FRAME_RELATED_P (insn) = 1;
  
!     }
!   else if (info->push_p)
!     {
!       if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
! 	sp_offset = info->total_size;
!       else
  	{
! 	  insn
! 	    = emit_insn (TARGET_32BIT
! 			 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
! 				       GEN_INT (info->total_size))
! 			 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
! 				       GEN_INT (info->total_size)));
! 	  RTX_FRAME_RELATED_P (insn) = 1;
  	}
!     }
!   
!   /* Get the old lr if we saved it.  */
!   if (info->lr_save_p)
!     {
!       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
! 			       GEN_INT (info->lr_save_offset + sp_offset));
!       insn = emit_move_insn (gen_rtx_REG (Pmode, 0), 
! 			     gen_rtx_MEM (Pmode, addr));
!       RTX_FRAME_RELATED_P (insn) = 1;
!     }
!   
!   /* Get the old cr if we saved it.  */
!   if (info->cr_save_p)
!     {
!       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
! 			       GEN_INT (info->cr_save_offset + sp_offset));
!       insn = emit_move_insn (gen_rtx_REG (reg_mode, 12), 
! 			     gen_rtx_MEM (reg_mode, addr));
!       RTX_FRAME_RELATED_P (insn) = 1;
!     }
!   
!   /* Set LR here to try to overlap restores below.  */
!   if (info->lr_save_p)
!     RTX_FRAME_RELATED_P (emit_move_insn (gen_rtx_REG (Pmode, 
! 						      LINK_REGISTER_REGNUM),
! 					 gen_rtx_REG (Pmode, 0))) = 1;
!   
!   /* Restore GPRs.  This is done as a PARALLEL if we are using
!      the load-multiple instructions.  */
!   if (using_load_multiple)
!     {
!       rtvec p;
!       p = rtvec_alloc (32 - info->first_gp_reg_save);
!       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
! 	{
! 	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, 
! 				   GEN_INT (info->gp_save_offset 
! 					    + sp_offset 
! 					    + reg_size * i));
! 	  RTVEC_ELT (p, i) = 
! 	    gen_rtx_SET (VOIDmode,
! 			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
! 			 gen_rtx_MEM (reg_mode, addr));
! 	}
!       insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
!       RTX_FRAME_RELATED_P (insn) = 1;
!     }
!   else
!     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
!       if ((regs_ever_live[info->first_gp_reg_save+i] 
! 	   && ! call_used_regs[info->first_gp_reg_save+i])
! 	  || (i+info->first_gp_reg_save == PIC_OFFSET_TABLE_REGNUM
! 	      && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
! 	      && flag_pic == 1))
! 	{
! 	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, 
! 				   GEN_INT (info->gp_save_offset 
! 					    + sp_offset 
! 					    + reg_size * i));
! 	  insn = emit_move_insn (gen_rtx_REG (reg_mode, 
! 					      info->first_gp_reg_save + i),
! 				 gen_rtx_MEM (reg_mode, addr));
! 	  RTX_FRAME_RELATED_P (insn) = 1;
! 	}
! 
!   /* Restore fpr's if we need to do it without calling a function.  */
!   if (saving_FPRs_inline)
!     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
!       {
! 	rtx addr;
! 	addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
! 			     GEN_INT (info->fp_save_offset 
! 				      + sp_offset 
! 				      + 8*i));
! 	insn = emit_move_insn (gen_rtx_REG (DFmode, 
! 					    info->first_fp_reg_save + i),
! 			       gen_rtx_MEM (DFmode, addr));
! 	RTX_FRAME_RELATED_P (insn) = 1;
!       }
  
!   /* If we saved cr, restore it here.  Just those that were used.  */
!   if (info->cr_save_p)
!     {
!       rtx r12_rtx = gen_rtx_REG (SImode, 12);
!       
!       if (using_mfcr_multiple)
! 	{
! 	  rtvec p;
! 	  int mask = 0;
! 	  int count = 0;
! 
! 	  for (i = 0; i < 8; i++)
! 	    if (regs_ever_live[68+i] && ! call_used_regs[68+i])
! 	      {
! 		mask |= 1 << (7-i);
! 		count++;
! 	      }
! 	  if (count == 0)
! 	    abort();
! 	  
! 	  p = rtvec_alloc (count + 1);
  
! 	  RTVEC_ELT (p, 0) = gen_rtx_USE (VOIDmode, GEN_INT (mask));
! 	  count = 1;
! 	  for (i = 0; i < 8; i++)
! 	    if (regs_ever_live[68+i] && ! call_used_regs[68+i])
! 	      {
! 		rtvec r = rtvec_alloc (2);
! 		RTVEC_ELT (r, 0) = r12_rtx;
! 		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
! 		RTVEC_ELT (p, count) =
! 		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, 68+i), 
! 			       gen_rtx_UNSPEC (CCmode, r, 20));
! 		count++;
! 	      }
! 	  insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
! 	  RTX_FRAME_RELATED_P (insn) = 1;
! 	}
!       else
! 	for (i = 0; i < 8; i++)
! 	  if (regs_ever_live[68+i] && ! call_used_regs[68+i])
! 	    {
! 	      insn = emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode, 
! 								  68+i),
! 						     r12_rtx));
! 	      RTX_FRAME_RELATED_P (insn) = 1;
! 	    }
!     }
  
!   /* If this is V.4, unwind the stack pointer after all of the loads
!      have been done. */
!   if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
!     {
!       if (use_backchain_to_restore_sp)
  	{
! 	  insn = emit_move_insn (sp_reg_rtx, frame_reg_rtx);
! 	  RTX_FRAME_RELATED_P (insn) = 1;
  	}
+       else if (sp_offset != 0)
+ 	{
+ 	  insn = emit_insn (Pmode == SImode
+ 			    ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
+ 					  GEN_INT (sp_offset))
+ 			    : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
+ 					  GEN_INT (sp_offset)));
+ 	  RTX_FRAME_RELATED_P (insn) = 1;
+ 	}
+     }
  
!   if (!sibcall)
!     {
!       rtvec p;
!       if (! saving_FPRs_inline)
! 	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
!       else
! 	p = rtvec_alloc (2);
! 
!       RTVEC_ELT (p, 0) = gen_rtx_USE (VOIDmode, 
! 				      gen_rtx_REG (Pmode, 
! 						   LINK_REGISTER_REGNUM));
!       RTVEC_ELT (p, 1) = gen_rtx_RETURN (VOIDmode);
  
!       /* If we have to restore more than two FP registers, branch to the
! 	 restore function.  It will return to our caller.  */
!       if (! saving_FPRs_inline)
  	{
! 	  int i;
! 	  char rname[30];
! 	  char *alloc_rname;
! 
! 	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX, 
! 		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
! 	  alloc_rname = ggc_alloc_string (rname, -1);
! 	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
! 					  gen_rtx_SYMBOL_REF (Pmode,
! 							      alloc_rname));
  
! 	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
! 	    {
! 	      rtx addr;
! 	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
! 				   GEN_INT (info->fp_save_offset + 8*i));
! 	      RTVEC_ELT (p, i+3) = 
! 		gen_rtx_SET (VOIDmode,
! 			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
! 			     gen_rtx_MEM (DFmode, addr));
! 	    }
  	}
+       
+       insn = emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+       RTX_FRAME_RELATED_P (insn) = 1;
+     }
+ }
  
! /* Write function epilogue.  */
  
! void
! output_epilog (file, size)
!      FILE *file;
!      int size ATTRIBUTE_UNUSED;
! {
!   rs6000_stack_t *info = rs6000_stack_info ();
! 
!   if (! HAVE_epilogue)
!     {
!       rtx insn = get_last_insn ();
!       /* If the last insn was a BARRIER, we don't have to write anything except
! 	 the trace table.  */
!       if (GET_CODE (insn) == NOTE)
! 	insn = prev_nonnote_insn (insn);
!       if (insn == 0 ||  GET_CODE (insn) != BARRIER)
! 	{
! 	  /* This is slightly ugly, but at least we don't have two
! 	     copies of the epilogue-emitting code.  */
! 	  start_sequence ();
! 
! 	  /* A NOTE_INSN_DELETED is supposed to be at the start
! 	     and end of the "toplevel" insn chain.  */
! 	  emit_note (0, NOTE_INSN_DELETED);
! 	  rs6000_emit_epilogue (FALSE);
! 	  emit_note (0, NOTE_INSN_DELETED);
! 
! 	  if (TARGET_DEBUG_ARG)
! 	    debug_rtx_list (get_insns(), 100);
! 	  final (get_insns(), file, FALSE, FALSE);
! 	  end_sequence ();
! 	}
      }
  
    /* Output a traceback table here.  See /usr/include/sys/debug.h for info
Index: rs6000.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.64.2.6
diff -p -u -c -p -r1.64.2.6 rs6000.h
*** rs6000.h	2000/01/13 00:42:25	1.64.2.6
--- rs6000.h	2000/01/13 01:39:06
*************** extern int function_arg_padding ();
*** 3079,3084 ****
--- 3079,3087 ----
  extern void toc_section ();
  extern void private_data_section ();
  extern void rs6000_fatal_bad_address ();
+ extern void rs6000_emit_epilogue ();
+ extern int mtcrf_operation ();
+ extern int lmw_operation ();
  
  /* See nonlocal_goto_receiver for when this must be set.  */
  
Index: rs6000.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.79.2.4
diff -p -u -c -p -r1.79.2.4 rs6000.md
*** rs6000.md	2000/01/12 22:01:44	1.79.2.4
--- rs6000.md	2000/01/13 01:39:06
***************
*** 20,25 ****
--- 20,41 ----
  ;; Boston, MA 02111-1307, USA.
  
  ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+ 
+ ;; `unspec' values used in rs6000.md:
+ ;; Number	Use
+ ;; 0		frsp for POWER machines
+ ;; 0/v		blockage
+ ;; 1/v		nonlocal_goto_receiver for MINIMAL_TOC
+ ;; 7		clobber SP for NT
+ ;; 7		address of the GOT under SVR4 -fpic
+ ;; 8		movsi_got
+ ;; 11		floatsidf2_loadaddr
+ ;; 12		floatsidf2_store1
+ ;; 13		floatsidf2_store2
+ ;; 14		floatsidf2_load
+ ;; 15		fix_truncdfsi2_store
+ ;; 16		fix_truncdfsi2_load
+ ;; 20		movesi_to_cr
  
  ;; Define an insn type attribute.  This is used in function unit delay
  ;; computations.
***************
*** 11199,11201 ****
--- 11215,11307 ----
  	    (const_int 0))]
    "TARGET_POWERPC64"
    "td%V0%I2 %1,%2")
+ 
+ ;; Insns related to generating the function prologue and epilogue.
+ 
+ (define_expand "epilogue"
+   [(use (const_int 0))]
+   "TARGET_SCHED_PROLOG"
+   "
+ {
+       rs6000_emit_epilogue (FALSE);
+       DONE;
+ }")
+ 
+ ; On some processors, doing the mtcrf one CC register at a time is
+ ; faster (like on the 604e).  On others, doing them all at once is
+ ; faster; for instance, on the 601 and 750.
+ 
+ (define_expand "movsi_to_cr_one"
+  [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+        (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
+ 		   (match_dup 2)] 20))]
+  ""
+  "operands[2] = GEN_INT (1 << (75 - REGNO (operands[0])));")
+ 
+ (define_insn "*movsi_to_cr"
+  [(match_parallel 0 "mtcrf_operation"
+                   [(use (match_operand 1 "immediate_operand" "n"))
+ 		   (set (match_operand:CC 2 "cc_reg_operand" "=y")
+        			(unspec:CC [(match_operand:SI 3 "gpc_reg_operand" "r")
+ 		   		    (match_operand 4 "immediate_operand" "n")]
+ 			 20))])]
+  ""
+  "mtcrf %4,%3")
+ 
+ (define_insn ""
+  [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+        (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
+ 		   (match_operand 2 "immediate_operand" "n")] 20))]
+  "GET_CODE (operands[0]) == REG 
+   && CR_REGNO_P (REGNO (operands[0]))
+   && GET_CODE (operands[2]) == CONST_INT
+   && INTVAL (operands[2]) == 1 << (75 - REGNO (operands[0]))"
+  "mtcrf %R0,%1")
+ 
+ ; The load-multiple instructions have similar properties.
+ ; Note that "load_multiple" is a name known to the machine-independent
+ ; code that actually corresponds to the powerpc load-string.
+ 
+ (define_insn "*lmw"
+  [(match_parallel 0 "lmw_operation"
+ 		  [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
+        			(match_operand:SI 2 "memory_operand" "m"))])]
+  "TARGET_MULTIPLE"
+  "lmw %1,%2")
+  
+ (define_insn "*return_internal_si"
+   [(use (match_operand:SI 0 "register_operand" "l"))
+    (return)]
+   "TARGET_32BIT"
+   "{br|blr}"
+   [(set_attr "type" "jmpreg")])
+ 
+ (define_insn "*return_internal_di"
+   [(use (match_operand:DI 0 "register_operand" "l"))
+    (return)]
+   "TARGET_64BIT"
+   "{br|blr}"
+   [(set_attr "type" "jmpreg")])
+ 
+ ; FIXME: This would probably be somewhat simpler if the Cygnus sibcall
+ ; stuff was in GCC.  Oh, and "any_operand" is a bit flexible...
+ 
+ (define_insn "*return_and_restore_fpregs_si"
+  [(match_parallel 0 "any_operand"
+                   [(use (match_operand:SI 1 "register_operand" "l"))
+ 		   (return)
+ 		   (use (match_operand:SI 2 "call_operand" "s"))
+ 		   (set (match_operand:DF 3 "gpc_reg_operand" "=f")
+ 			(match_operand:DF 4 "memory_operand" "m"))])]
+  "TARGET_32BIT"
+  "b %z2")
+ 
+ (define_insn "*return_and_restore_fpregs_di"
+  [(match_parallel 0 "any_operand"
+                   [(use (match_operand:DI 1 "register_operand" "l"))
+ 		   (return)
+ 		   (use (match_operand:DI 2 "call_operand" "s"))
+ 		   (set (match_operand:DF 3 "gpc_reg_operand" "=f")
+ 			(match_operand:DF 4 "memory_operand" "m"))])]
+  "TARGET_64BIT"
+  "b %z2")
============================================================

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]