Committed, CRIS: function prologue as RTL.

Hans-Peter Nilsson hans-peter.nilsson@axis.com
Wed Apr 13 19:39:00 GMT 2005


Also known as the fix for PR target/14619.  Tested cross to
cris-axis-elf and cris-axis-linux-gnu.  Mostly
performance-neutral (net 1 cycle saved), but causes a strange
difference in __pack_d; delay-slots previously filled are now
empty.  (PR target/21002).  Apparently a basic-block-reordering
issue.  Good effect: I noticed the return-address-saving move to
fill a first delay-slot.  Bad effect: (synchronous) EH info gets
bloated.  I recently posted a patch to fix that, though.  Since
libgcc is compiled with -fnon-call-exceptions, it gets a little
uselessly bloated, as there's no (other) target support for
non-call-exceptions.  I'm not going to do anything to that,
except Some Time Later Maybe add support for asynchronous
excetions.

	CRIS prologue as RTL.
	* config/cris/cris-protos.h (cris_emit_movem_store)
	(cris_expand_prologue): Prototype.
	* config/cris/cris.c (struct machine_function): New member
	stdarg_regs.
	(cfa_label_num, cris_target_asm_function_prologue): Remove.
	(TARGET_ASM_FUNCTION_PROLOGUE): Don't override.
	(cris_general_operand_or_gotless_symbol): Accept CRIS_UNSPEC_GOT.
	(cris_load_multiple_op, cris_return_address_on_stack)
	(cris_return_address_on_stack_for_return): ISO-Cify.
	(cris_store_multiple_op): New predicate function.
	(cris_expand_prologue, cris_emit_movem_store): New functions.
	(cris_print_operand) <case 'O'>: Handle modifications other than
	post-increment.
	(cris_symbol, cris_got_symbol): Return 0 for CRIS_UNSPEC_GOT.
	(cris_gotless_symbol): Return 1 for CRIS_UNSPEC_GOT.
	(cris_gen_movem_load): Rearrange slightly to make local variable
	src a parameter, removing osrc.
	(cris_setup_incoming_varargs): Set machine_function member
	stdarg_regs to correspond to the number of registers that need to
	be saved.
	* config/cris/cris.h (EXTRA_CONSTRAINT_S): Accept
	CRIS_UNSPEC_GOT.
	(PREDICATE_CODES): Add cris_store_multiple_op.  Make
	cris_general_operand_or_gotless_symbol accept UNSPEC.
	* config/cris/cris.md (CRIS_UNSPEC_GOT): New constant.
	("*movsi_internal") <alternative 8>: Handle CRIS_UNSPEC_GOT.
	("*cris_store_multiple"): New pattern.  Tweak common comment above
	this and "*cris_load_multiple".
	("prologue"): New define_expand.

Index: cris-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris-protos.h,v
retrieving revision 1.17
diff -c -p -r1.17 cris-protos.h
*** cris-protos.h	4 Apr 2005 22:43:34 -0000	1.17
--- cris-protos.h	13 Apr 2005 15:48:12 -0000
*************** extern void cris_asm_output_symbol_ref (
*** 45,53 ****
--- 45,55 ----
  extern bool cris_output_addr_const_extra (FILE *, rtx);
  extern int cris_cfun_uses_pic_table (void);
  extern rtx cris_gen_movem_load (rtx, rtx, int);
+ extern rtx cris_emit_movem_store (rtx, rtx, int, bool);
  #endif /* RTX_CODE */
  extern void cris_asm_output_label_ref (FILE *, char *);
  extern void cris_target_asm_named_section (const char *, unsigned int, tree);
+ extern void cris_expand_prologue (void);
  extern void cris_expand_epilogue (void);
  extern void cris_expand_return (bool);
  extern bool cris_return_address_on_stack_for_return (void);
Index: cris.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.c,v
retrieving revision 1.70
diff -c -p -r1.70 cris.c
*** cris.c	4 Apr 2005 22:43:34 -0000	1.70
--- cris.c	13 Apr 2005 15:48:12 -0000
*************** enum cris_retinsn_type
*** 74,79 ****
--- 74,84 ----
  struct machine_function GTY(())
   {
     int needs_return_address_on_stack;
+ 
+    /* This is the number of registers we save in the prologue due to
+       stdarg.  */
+    int stdarg_regs;
+ 
     enum cris_retinsn_type return_type;
   };
  
*************** static int cris_initial_frame_pointer_of
*** 111,118 ****
  
  static int saved_regs_mentioned (rtx);
  
- static void cris_target_asm_function_prologue (FILE *, HOST_WIDE_INT);
- 
  static void cris_operand_lossage (const char *, rtx);
  
  static int cris_reg_saved_in_regsave_area  (unsigned int, bool);
--- 116,121 ----
*************** int cris_cpu_version = CRIS_DEFAULT_CPU_
*** 171,179 ****
  #undef TARGET_ASM_UNALIGNED_DI_OP
  #define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
  
- #undef TARGET_ASM_FUNCTION_PROLOGUE
- #define TARGET_ASM_FUNCTION_PROLOGUE cris_target_asm_function_prologue
- 
  #undef TARGET_ASM_OUTPUT_MI_THUNK
  #define TARGET_ASM_OUTPUT_MI_THUNK cris_asm_output_mi_thunk
  #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
--- 174,179 ----
*************** cris_general_operand_or_symbol (rtx op, 
*** 431,442 ****
  
  /* Since a PIC symbol without a GOT entry is not a general_operand, we
     have to have a predicate that matches it.  We use this in the expanded
!    "movsi" anonymous pattern for PIC symbols.  */
  
  int
  cris_general_operand_or_gotless_symbol (rtx op, enum machine_mode mode)
  {
    return general_operand (op, mode)
      || (CONSTANT_P (op) && cris_gotless_symbol (op));
  }
  
--- 431,443 ----
  
  /* Since a PIC symbol without a GOT entry is not a general_operand, we
     have to have a predicate that matches it.  We use this in the expanded
!    "movsi" anonymous pattern.  */
  
  int
  cris_general_operand_or_gotless_symbol (rtx op, enum machine_mode mode)
  {
    return general_operand (op, mode)
+     || (GET_CODE (op) == UNSPEC && XINT (op, 1) == CRIS_UNSPEC_GOT)
      || (CONSTANT_P (op) && cris_gotless_symbol (op));
  }
  
*************** cris_movem_load_rest_p (rtx op, int offs
*** 556,568 ****
  /* Predicate for the parallel contents in a movem from-memory.  */
  
  int
! cris_load_multiple_op (op, mode)
!      rtx op;
!      enum machine_mode mode ATTRIBUTE_UNUSED;
  {
    return cris_movem_load_rest_p (op, 0);
  }
  
  /* The CONDITIONAL_REGISTER_USAGE worker.  */
  
  void
--- 557,680 ----
  /* Predicate for the parallel contents in a movem from-memory.  */
  
  int
! cris_load_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
  {
    return cris_movem_load_rest_p (op, 0);
  }
  
+ /* Predicate for the parallel contents in a movem to-memory.  */
+ 
+ int
+ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+ {
+   int reg_count = XVECLEN (op, 0);
+   rtx dest;
+   rtx dest_addr;
+   rtx dest_base;
+   int i;
+   rtx elt;
+   int setno;
+   int regno_dir = 1;
+   int regno = 0;
+   int offset = 0;
+ 
+   /* Perform a quick check so we don't blow up below.  FIXME: Adjust for
+      other than (MEM reg) and (MEM (PLUS reg const)).  */
+   if (reg_count <= 1)
+     return 0;
+ 
+   elt = XVECEXP (op, 0, 0);
+ 
+   if (GET_CODE (elt) != SET)
+     return  0;
+ 
+   dest = SET_DEST (elt);
+ 
+   if (GET_CODE (SET_SRC (elt)) != REG
+       || GET_CODE (dest) != MEM)
+     return 0;
+ 
+   dest_addr = XEXP (dest, 0);
+ 
+   /* Check a possible post-inc indicator.  */
+   if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS)
+     {
+       rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 0);
+       rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1);
+ 
+       reg_count--;
+ 
+       if (reg_count == 1
+ 	  || !REG_P (reg)
+ 	  || !REG_P (SET_DEST (XVECEXP (op, 0, 1)))
+ 	  || REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, 1)))
+ 	  || GET_CODE (inc) != CONST_INT
+ 	  /* Support increment by number of registers, and by the offset
+ 	     of the destination, if it has the form (MEM (PLUS reg
+ 	     offset)).  */
+ 	  || !((REG_P (dest_addr)
+ 		&& REGNO (dest_addr) == REGNO (reg)
+ 		&& INTVAL (inc) == (HOST_WIDE_INT) reg_count * 4)
+ 	       || (GET_CODE (dest_addr) == PLUS
+ 		   && REG_P (XEXP (dest_addr, 0))
+ 		   && REGNO (XEXP (dest_addr, 0)) == REGNO (reg)
+ 		   && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT
+ 		   && INTVAL (XEXP (dest_addr, 1)) == INTVAL (inc))))
+ 	return 0;
+ 
+       i = 2;
+     }
+   else
+     i = 1;
+ 
+   /* FIXME: These two only for pre-v32.  */
+   regno_dir = -1;
+   regno = reg_count - 1;
+ 
+   if (GET_CODE (elt) != SET
+       || GET_CODE (SET_SRC (elt)) != REG
+       || GET_MODE (SET_SRC (elt)) != SImode
+       || REGNO (SET_SRC (elt)) != (unsigned int) regno
+       || GET_CODE (SET_DEST (elt)) != MEM
+       || GET_MODE (SET_DEST (elt)) != SImode)
+     return 0;
+ 
+   if (REG_P (dest_addr))
+     {
+       dest_base = dest_addr;
+       offset = 0;
+     }
+   else if (GET_CODE (dest_addr) == PLUS
+ 	   && REG_P (XEXP (dest_addr, 0))
+ 	   && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
+     {
+       dest_base = XEXP (dest_addr, 0);
+       offset = INTVAL (XEXP (dest_addr, 1));
+     }
+   else
+     return 0;
+ 
+   for (setno = 1; i < XVECLEN (op, 0); setno++, i++)
+     {
+       rtx elt = XVECEXP (op, 0, i);
+       regno += regno_dir;
+ 
+       if (GET_CODE (elt) != SET
+ 	  || GET_CODE (SET_SRC (elt)) != REG
+ 	  || GET_MODE (SET_SRC (elt)) != SImode
+ 	  || REGNO (SET_SRC (elt)) != (unsigned int) regno
+ 	  || GET_CODE (SET_DEST (elt)) != MEM
+ 	  || GET_MODE (SET_DEST (elt)) != SImode
+ 	  || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+ 	  || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_base)
+ 	  || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+ 	  || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != setno * 4 + offset)
+ 	return 0;
+     }
+ 
+   return 1;
+ }
+ 
  /* The CONDITIONAL_REGISTER_USAGE worker.  */
  
  void
*************** cris_reg_saved_in_regsave_area (unsigned
*** 775,1054 ****
  	    || regno == EH_RETURN_DATA_REGNO (3)));
  }
  
- /* This variable belongs to cris_target_asm_function_prologue but must
-    be located outside it for GTY reasons.  */
- static GTY(()) unsigned long cfa_label_num = 0;
- 
- /* Textual function prologue.  */
- 
- static void
- cris_target_asm_function_prologue (FILE *file, HOST_WIDE_INT size)
- {
-   int regno;
- 
-   /* Shorten the used name for readability.  */
-   int cfoa_size = current_function_outgoing_args_size;
-   int last_movem_reg = -1;
-   int doing_dwarf = dwarf2out_do_frame ();
-   int framesize;
-   int faked_args_size = 0;
-   int cfa_write_offset = 0;
-   static char cfa_label[30];
-   bool return_address_on_stack = cris_return_address_on_stack ();
-   bool got_really_used = current_function_uses_pic_offset_table;
- 
-   /* Don't do anything if no prologues or epilogues are wanted.  */
-   if (!TARGET_PROLOGUE_EPILOGUE)
-     return;
- 
-   if (size < 0)
-     abort ();
- 
-   /* Align the size to what's best for the CPU model.  */
-   if (TARGET_STACK_ALIGN)
-     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
- 
-   if (current_function_pretend_args_size)
-     {
-       int pretend = current_function_pretend_args_size;
-       for (regno = CRIS_FIRST_ARG_REG + CRIS_MAX_ARGS_IN_REGS - 1;
- 	   pretend > 0;
- 	   regno--, pretend -= 4)
- 	{
- 	  fprintf (file, "\tpush $%s\n", reg_names[regno]);
- 	  faked_args_size += 4;
- 	}
-     }
- 
-   framesize = faked_args_size;
- 
-   if (doing_dwarf)
-     {
-       /* FIXME: Slightly redundant calculation, as we do the same in
- 	 pieces below.  This offset must be the total adjustment of the
- 	 stack-pointer.  We can then def_cfa call at the end of this
- 	 function with the current implementation of execute_cfa_insn, but
- 	 that wouldn't really be clean.  */
- 
-       int cfa_offset
- 	= faked_args_size
- 	+ (return_address_on_stack ? 4 : 0)
- 	+ (frame_pointer_needed ? 4 : 0);
- 
-       int cfa_reg;
- 
-       if (frame_pointer_needed)
- 	cfa_reg = FRAME_POINTER_REGNUM;
-       else
- 	{
- 	  cfa_reg = STACK_POINTER_REGNUM;
- 	  cfa_offset += cris_initial_frame_pointer_offset ();
- 	}
- 
-       ASM_GENERATE_INTERNAL_LABEL (cfa_label, "LCFIT",
- 				   cfa_label_num++);
-       dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);
- 
-       cfa_write_offset = - faked_args_size - 4;
-     }
- 
-   /* Save SRP if not a leaf function.  */
-   if (return_address_on_stack)
-     {
-       fprintf (file, "\tPush $srp\n");
-       framesize += 4;
- 
-       if (doing_dwarf)
- 	{
- 	  dwarf2out_return_save (cfa_label, cfa_write_offset);
- 	  cfa_write_offset -= 4;
- 	}
-     }
- 
-   /* Set up frame pointer if needed.  */
-   if (frame_pointer_needed)
-     {
-       fprintf (file, "\tpush $%s\n\tmove.d $sp,$%s\n",
- 	       reg_names[FRAME_POINTER_REGNUM],
- 	       reg_names[FRAME_POINTER_REGNUM]);
-       framesize += 4;
- 
-       if (doing_dwarf)
- 	{
- 	  dwarf2out_reg_save (cfa_label, FRAME_POINTER_REGNUM,
- 			      cfa_write_offset);
- 	  cfa_write_offset -= 4;
- 	}
-     }
- 
-   /* Local vars are located above saved regs.  */
-   cfa_write_offset -= size;
- 
-   /* Get a contiguous sequence of registers, starting with r0, that need
-      to be saved.  */
-   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-     {
-       if (cris_reg_saved_in_regsave_area (regno, got_really_used))
- 	{
- 	  /* Check if movem may be used for registers so far.  */
- 	  if (regno == last_movem_reg + 1)
- 	    /* Yes, update next expected register.  */
- 	    last_movem_reg++;
- 	  else
- 	    {
- 	      /* We cannot use movem for all registers.  We have to flush
- 		 any movem:ed registers we got so far.  */
- 	      if (last_movem_reg != -1)
- 		{
- 		  /* It is a win to use a side-effect assignment for
- 		     64 <= size <= 128.  But side-effect on movem was
- 		     not usable for CRIS v0..3.  Also only do it if
- 		     side-effects insns are allowed.  */
- 		  if ((last_movem_reg + 1) * 4 + size >= 64
- 		      && (last_movem_reg + 1) * 4 + size <= 128
- 		      && cris_cpu_version >= CRIS_CPU_SVINTO
- 		      && TARGET_SIDE_EFFECT_PREFIXES)
- 		    fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
- 			     reg_names[last_movem_reg],
- 			     (last_movem_reg + 1) * 4 + size);
- 		  else
- 		    {
- 		      /* Avoid printing multiple subsequent sub:s for sp.  */
- 		      fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
- 			       ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1)
- 						       * 4 + size),
- 			       (last_movem_reg + 1) * 4 + size);
- 
- 		      fprintf (file, "\tmovem $%s,[$sp]\n",
- 			       reg_names[last_movem_reg]);
- 		    }
- 
- 		  framesize += (last_movem_reg + 1) * 4 + size;
- 
- 		  if (TARGET_PDEBUG)
- 		    fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
- 			     ", #regs %d, bytes %d args %d\n",
- 			     size,
- 			     last_movem_reg + 1,
- 			     (last_movem_reg + 1) * 4,
- 			     current_function_args_size);
- 
- 		  last_movem_reg = -1;
- 		  size = 0;
- 		}
- 	      else if (size > 0)
- 		{
- 		  /* Local vars on stack, but there are no movem:s.
- 		     Just allocate space.  */
- 		  fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
- 			   ADDITIVE_SIZE_MODIFIER (size),
- 			   size);
- 		  framesize += size;
- 		  size = 0;
- 		}
- 
- 	      fprintf (file, "\tPush $%s\n", reg_names[regno]);
- 	      framesize += 4;
- 	    }
- 
- 	  if (doing_dwarf)
- 	    {
- 	      /* Registers are stored lowest numbered at highest address,
- 		 which matches the loop order; we just need to update the
- 		 write-offset.  */
- 	      dwarf2out_reg_save (cfa_label, regno, cfa_write_offset);
- 	      cfa_write_offset -= 4;
- 	    }
- 	}
-     }
- 
-   /* Check after, if we can movem all registers.  This is the normal
-      case.  */
-   if (last_movem_reg != -1)
-     {
-       /* Side-effect assignment on movem was not supported for CRIS v0..3,
- 	 and don't do it if we're asked not to.
- 
- 	 The movem is already accounted for, for unwind.  */
- 
-       if ((last_movem_reg + 1) * 4 + size >= 64
- 	  && (last_movem_reg + 1) * 4 + size <= 128
- 	  && cris_cpu_version >= CRIS_CPU_SVINTO
- 	  && TARGET_SIDE_EFFECT_PREFIXES)
- 	fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
- 		 reg_names[last_movem_reg],
- 		 (last_movem_reg+1) * 4 + size);
-       else
- 	{
- 	  /* Avoid printing multiple subsequent sub:s for sp.  FIXME:
- 	     Clean up the conditional expression.  */
- 	  fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
- 		   ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1) * 4 + size),
- 		   (last_movem_reg + 1) * 4 + size);
- 	  /* To be compatible with v0..v3 means we do not use an assignment
- 	     addressing mode with movem.  We normally don't need that
- 	     anyway.  It would only be slightly more efficient for 64..128
- 	     bytes frame size.  */
- 	  fprintf (file, "\tmovem $%s,[$sp]\n", reg_names[last_movem_reg]);
- 	}
- 
-       framesize += (last_movem_reg + 1) * 4 + size;
- 
-       if (TARGET_PDEBUG)
- 	fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
- 		 ", #regs %d, bytes %d args %d\n",
- 		 size,
- 		 last_movem_reg + 1,
- 		 (last_movem_reg + 1) * 4,
- 		 current_function_args_size);
- 
-       /* We have to put outgoing argument space after regs.  */
-       if (cfoa_size)
- 	{
- 	  /* This does not need to be accounted for, for unwind.  */
- 
- 	  fprintf (file, "\tSub%s %d,$sp\n",
- 		   ADDITIVE_SIZE_MODIFIER (cfoa_size),
- 		   cfoa_size);
- 	  framesize += cfoa_size;
- 	}
-     }
-   else if ((size + cfoa_size) > 0)
-     {
-       /* This does not need to be accounted for, for unwind.  */
- 
-       /* Local vars on stack, and we could not use movem.  Add a sub here.  */
-       fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
- 	       ADDITIVE_SIZE_MODIFIER (size + cfoa_size),
- 	       cfoa_size + size);
-       framesize += size + cfoa_size;
-     }
- 
-   /* Set up the PIC register.  */
-   if (current_function_uses_pic_offset_table)
-     fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
- 	     reg_names[PIC_OFFSET_TABLE_REGNUM],
- 	     reg_names[PIC_OFFSET_TABLE_REGNUM]);
- 
-   if (doing_dwarf)
-     ASM_OUTPUT_LABEL (file, cfa_label);
- 
-   if (TARGET_PDEBUG)
-     fprintf (file,
- 	     "; parm #%d @ %d; frame " HOST_WIDE_INT_PRINT_DEC
- 	     ", FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
- 	     CRIS_MAX_ARGS_IN_REGS + 1, FIRST_PARM_OFFSET (0),
- 	     get_frame_size (),
- 	     cris_initial_frame_pointer_offset (),
- 	     leaf_function_p () ? "yes" : "no",
- 	     return_address_on_stack ? "no" :"yes",
- 	     frame_pointer_needed ? "yes" : "no",
- 	     cfoa_size, current_function_args_size);
- 
-   if (cris_max_stackframe && framesize > cris_max_stackframe)
-     warning ("stackframe too big: %d bytes", framesize);
- }
- 
  /* Return nonzero if there are regs mentioned in the insn that are not all
     in the call_used regs.  This is part of the decision whether an insn
     can be put in the epilogue.  */
--- 887,892 ----
*************** cris_print_operand (FILE *file, rtx x, i
*** 1176,1186 ****
  	  ? XEXP (SET_SRC (XVECEXP (x, 0, 0)), 0)
  	  : XEXP (SET_DEST (XVECEXP (x, 0, 0)), 0);
  
! 	/* The second item can be a (set reg (plus reg const)) to denote a
! 	   post-increment.  */
  	if (GET_CODE (SET_SRC (XVECEXP (x, 0, 1))) == PLUS)
! 	  addr = gen_rtx_POST_INC (SImode, addr);
! 
  	output_address (addr);
        }
        return;
--- 1014,1037 ----
  	  ? XEXP (SET_SRC (XVECEXP (x, 0, 0)), 0)
  	  : XEXP (SET_DEST (XVECEXP (x, 0, 0)), 0);
  
! 	/* The second item can be a (set reg (plus reg const)) to denote
! 	   a modification.  */
  	if (GET_CODE (SET_SRC (XVECEXP (x, 0, 1))) == PLUS)
! 	  {
! 	    /* It's a post-increment, if the address is a naked (reg).  */
! 	    if (REG_P (addr))
! 	      addr = gen_rtx_POST_INC (SImode, addr);
! 	    else
! 	      {
! 		/* Otherwise, it's a side-effect; RN=RN+M.  */
! 		fprintf (file, "[$%s=$%s%s%d]",
! 			 reg_names [REGNO (SET_DEST (XVECEXP (x, 0, 1)))],
! 			 reg_names [REGNO (XEXP (addr, 0))],
! 			 INTVAL (XEXP (addr, 1)) < 0 ? "" : "+",
! 			 (int) INTVAL (XEXP (addr, 1)));
! 		return;
! 	      }
! 	  }
  	output_address (addr);
        }
        return;
*************** cris_return_addr_rtx (int count, rtx fra
*** 1561,1567 ****
     there.  */
  
  bool
! cris_return_address_on_stack ()
  {
    return regs_ever_live[CRIS_SRP_REGNUM]
      || cfun->machine->needs_return_address_on_stack;
--- 1412,1418 ----
     there.  */
  
  bool
! cris_return_address_on_stack (void)
  {
    return regs_ever_live[CRIS_SRP_REGNUM]
      || cfun->machine->needs_return_address_on_stack;
*************** cris_return_address_on_stack ()
*** 1571,1577 ****
     there.  */
  
  bool
! cris_return_address_on_stack_for_return ()
  {
    return cfun->machine->return_type == CRIS_RETINSN_RET ? false
      : cris_return_address_on_stack ();
--- 1422,1428 ----
     there.  */
  
  bool
! cris_return_address_on_stack_for_return (void)
  {
    return cfun->machine->return_type == CRIS_RETINSN_RET ? false
      : cris_return_address_on_stack ();
*************** cris_symbol (rtx x)
*** 2325,2330 ****
--- 2176,2183 ----
        return 1;
  
      case UNSPEC:
+       if (XINT (x, 1) == CRIS_UNSPEC_GOT)
+ 	return 0;
        /* A PLT reference.  */
        ASSERT_PLT_UNSPEC (x);
        return 1;
*************** cris_gotless_symbol (rtx x)
*** 2363,2368 ****
--- 2216,2223 ----
    switch (GET_CODE (x))
      {
      case UNSPEC:
+       if (XINT (x, 1) == CRIS_UNSPEC_GOT)
+ 	return 1;
        ASSERT_PLT_UNSPEC (x);
        return 1;
  
*************** cris_got_symbol (rtx x)
*** 2422,2427 ****
--- 2277,2284 ----
    switch (GET_CODE (x))
      {
      case UNSPEC:
+       if (XINT (x, 1) == CRIS_UNSPEC_GOT)
+ 	return 0;
        ASSERT_PLT_UNSPEC (x);
        return 0;
  
*************** cris_split_movdx (rtx *operands)
*** 2806,2811 ****
--- 2663,2939 ----
    return val;
  }
  
+ /* The expander for the prologue pattern name.  */
+ 
+ void
+ cris_expand_prologue (void)
+ {
+   int regno;
+   int size = get_frame_size ();
+   /* Shorten the used name for readability.  */
+   int cfoa_size = current_function_outgoing_args_size;
+   int last_movem_reg = -1;
+   int framesize = 0;
+   rtx mem, insn;
+   int return_address_on_stack = cris_return_address_on_stack ();
+   int got_really_used = current_function_uses_pic_offset_table;
+   int n_movem_regs = 0;
+   int pretend = current_function_pretend_args_size;
+ 
+   /* Don't do anything if no prologues or epilogues are wanted.  */
+   if (!TARGET_PROLOGUE_EPILOGUE)
+     return;
+ 
+   if (size < 0)
+     abort ();
+ 
+   /* Align the size to what's best for the CPU model.  */
+   if (TARGET_STACK_ALIGN)
+     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
+ 
+   if (pretend)
+     {
+       /* See also cris_setup_incoming_varargs where
+ 	 cfun->machine->stdarg_regs is set.  There are other setters of
+ 	 current_function_pretend_args_size than stdarg handling, like
+ 	 for an argument passed with parts in R13 and stack.  We must
+ 	 not store R13 into the pretend-area for that case, as GCC does
+ 	 that itself.  "Our" store would be marked as redundant and GCC
+ 	 will attempt to remove it, which will then be flagged as an
+ 	 internal error; trying to remove a frame-related insn.  */
+       int stdarg_regs = cfun->machine->stdarg_regs;
+ 
+       framesize += pretend;
+ 
+       for (regno = CRIS_FIRST_ARG_REG + CRIS_MAX_ARGS_IN_REGS - 1;
+ 	   stdarg_regs > 0;
+ 	   regno--, pretend -= 4, stdarg_regs--)
+ 	{
+ 	  insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 					 stack_pointer_rtx,
+ 					 plus_constant (stack_pointer_rtx,
+ 							-4)));
+ 	  /* FIXME: When dwarf2 frame output and unless asynchronous
+ 	     exceptions, make dwarf2 bundle together all stack
+ 	     adjustments like it does for registers between stack
+ 	     adjustments.  */
+ 	  RTX_FRAME_RELATED_P (insn) = 1;
+ 
+ 	  mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+ 	  set_mem_alias_set (mem, get_varargs_alias_set ());
+ 	  insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, regno));
+ 
+ 	  /* Note the absence of RTX_FRAME_RELATED_P on the above insn:
+ 	     the value isn't restored, so we don't want to tell dwarf2
+ 	     that it's been stored to stack, else EH handling info would
+ 	     get confused.  */
+ 	}
+ 
+       /* For other setters of current_function_pretend_args_size, we
+ 	 just adjust the stack by leaving the remaining size in
+ 	 "pretend", handled below.  */
+     }
+ 
+   /* Save SRP if not a leaf function.  */
+   if (return_address_on_stack)
+     {
+       insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 				     stack_pointer_rtx,
+ 				     plus_constant (stack_pointer_rtx,
+ 						    -4 - pretend)));
+       pretend = 0;
+       RTX_FRAME_RELATED_P (insn) = 1;
+ 
+       mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+       set_mem_alias_set (mem, get_frame_alias_set ());
+       insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, CRIS_SRP_REGNUM));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       framesize += 4;
+     }
+ 
+   /* Set up the frame pointer, if needed.  */
+   if (frame_pointer_needed)
+     {
+       insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 				     stack_pointer_rtx,
+ 				     plus_constant (stack_pointer_rtx,
+ 						    -4 - pretend)));
+       pretend = 0;
+       RTX_FRAME_RELATED_P (insn) = 1;
+ 
+       mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+       set_mem_alias_set (mem, get_frame_alias_set ());
+       insn = emit_move_insn (mem, frame_pointer_rtx);
+       RTX_FRAME_RELATED_P (insn) = 1;
+ 
+       insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+       RTX_FRAME_RELATED_P (insn) = 1;
+ 
+       framesize += 4;
+     }
+ 
+   /* Between frame-pointer and saved registers lie the area for local
+      variables.  If we get here with "pretended" size remaining, count
+      it into the general stack size.  */
+   size += pretend;
+ 
+   /* Get a contiguous sequence of registers, starting with R0, that need
+      to be saved.  */
+   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+     {
+       if (cris_reg_saved_in_regsave_area (regno, got_really_used))
+ 	{
+ 	  n_movem_regs++;
+ 
+ 	  /* Check if movem may be used for registers so far.  */
+ 	  if (regno == last_movem_reg + 1)
+ 	    /* Yes, update next expected register.  */
+ 	    last_movem_reg = regno;
+ 	  else
+ 	    {
+ 	      /* We cannot use movem for all registers.  We have to flush
+ 		 any movem:ed registers we got so far.  */
+ 	      if (last_movem_reg != -1)
+ 		{
+ 		  int n_saved
+ 		    = (n_movem_regs == 1) ? 1 : last_movem_reg + 1;
+ 
+ 		  /* It is a win to use a side-effect assignment for
+ 		     64 <= size <= 128.  But side-effect on movem was
+ 		     not usable for CRIS v0..3.  Also only do it if
+ 		     side-effects insns are allowed.  */
+ 		  if ((last_movem_reg + 1) * 4 + size >= 64
+ 		      && (last_movem_reg + 1) * 4 + size <= 128
+ 		      && (cris_cpu_version >= CRIS_CPU_SVINTO || n_saved == 1)
+ 		      && TARGET_SIDE_EFFECT_PREFIXES)
+ 		    {
+ 		      mem
+ 			= gen_rtx_MEM (SImode,
+ 				       plus_constant (stack_pointer_rtx,
+ 						      -(n_saved * 4 + size)));
+ 		      set_mem_alias_set (mem, get_frame_alias_set ());
+ 		      insn
+ 			= cris_emit_movem_store (mem, GEN_INT (n_saved),
+ 						 -(n_saved * 4 + size),
+ 						 true);
+ 		    }
+ 		  else
+ 		    {
+ 		      insn
+ 			= gen_rtx_SET (VOIDmode,
+ 				       stack_pointer_rtx,
+ 				       plus_constant (stack_pointer_rtx,
+ 						      -(n_saved * 4 + size)));
+ 		      insn = emit_insn (insn);
+ 		      RTX_FRAME_RELATED_P (insn) = 1;
+ 
+ 		      mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+ 		      set_mem_alias_set (mem, get_frame_alias_set ());
+ 		      insn = cris_emit_movem_store (mem, GEN_INT (n_saved),
+ 						    0, true);
+ 		    }
+ 
+ 		  framesize += n_saved * 4 + size;
+ 		  last_movem_reg = -1;
+ 		  size = 0;
+ 		}
+ 
+ 	      insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 					     stack_pointer_rtx,
+ 					     plus_constant (stack_pointer_rtx,
+ 							    -4 - size)));
+ 	      RTX_FRAME_RELATED_P (insn) = 1;
+ 
+ 	      mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+ 	      set_mem_alias_set (mem, get_frame_alias_set ());
+ 	      insn = emit_move_insn (mem, gen_rtx_raw_REG (SImode, regno));
+ 	      RTX_FRAME_RELATED_P (insn) = 1;
+ 
+ 	      framesize += 4 + size;
+ 	      size = 0;
+ 	    }
+ 	}
+     }
+ 
+   /* Check after, if we could movem all registers.  This is the normal case.  */
+   if (last_movem_reg != -1)
+     {
+       int n_saved
+ 	= (n_movem_regs == 1) ? 1 : last_movem_reg + 1;
+ 
+       /* Side-effect on movem was not usable for CRIS v0..3.  Also only
+ 	 do it if side-effects insns are allowed.  */
+       if ((last_movem_reg + 1) * 4 + size >= 64
+ 	  && (last_movem_reg + 1) * 4 + size <= 128
+ 	  && (cris_cpu_version >= CRIS_CPU_SVINTO || n_saved == 1)
+ 	  && TARGET_SIDE_EFFECT_PREFIXES)
+ 	{
+ 	  mem
+ 	    = gen_rtx_MEM (SImode,
+ 			   plus_constant (stack_pointer_rtx,
+ 					  -(n_saved * 4 + size)));
+ 	  set_mem_alias_set (mem, get_frame_alias_set ());
+ 	  insn = cris_emit_movem_store (mem, GEN_INT (n_saved),
+ 					-(n_saved * 4 + size), true);
+ 	}
+       else
+ 	{
+ 	  insn
+ 	    = gen_rtx_SET (VOIDmode,
+ 			   stack_pointer_rtx,
+ 			   plus_constant (stack_pointer_rtx,
+ 					  -(n_saved * 4 + size)));
+ 	  insn = emit_insn (insn);
+ 	  RTX_FRAME_RELATED_P (insn) = 1;
+ 
+ 	  mem = gen_rtx_MEM (SImode, stack_pointer_rtx);
+ 	  set_mem_alias_set (mem, get_frame_alias_set ());
+ 	  insn = cris_emit_movem_store (mem, GEN_INT (n_saved), 0, true);
+ 	}
+ 
+       framesize += n_saved * 4 + size;
+       /* We have to put outgoing argument space after regs.  */
+       if (cfoa_size)
+ 	{
+ 	  insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 					 stack_pointer_rtx,
+ 					 plus_constant (stack_pointer_rtx,
+ 							-cfoa_size)));
+ 	  RTX_FRAME_RELATED_P (insn) = 1;
+ 	  framesize += cfoa_size;
+ 	}
+     }
+   else if ((size + cfoa_size) > 0)
+     {
+       insn = emit_insn (gen_rtx_SET (VOIDmode,
+ 				     stack_pointer_rtx,
+ 				     plus_constant (stack_pointer_rtx,
+ 						    -(cfoa_size + size))));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       framesize += size + cfoa_size;
+     }
+ 
+   /* Set up the PIC register, if it is used.  */
+   if (got_really_used)
+     {
+       rtx got
+ 	= gen_rtx_UNSPEC (SImode, gen_rtvec (1, const0_rtx), CRIS_UNSPEC_GOT);
+       emit_move_insn (pic_offset_table_rtx, got);
+ 
+       /* FIXME: This is a cover-up for flow2 messing up; it doesn't
+ 	 follow exceptional paths and tries to delete the GOT load as
+ 	 unused, if it isn't used on the non-exceptional paths.  Other
+ 	 ports have similar or other cover-ups, or plain bugs marking
+ 	 the GOT register load as maybe-dead.  To see this, remove the
+ 	 line below and try libsupc++/vec.cc or a trivial
+ 	 "static void y (); void x () {try {y ();} catch (...) {}}".  */
+       emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+     }
+ 
+   if (cris_max_stackframe && framesize > cris_max_stackframe)
+     warning ("stackframe too big: %d bytes", framesize);
+ }
+ 
  /* The expander for the epilogue pattern.  */
  
  void
*************** cris_expand_epilogue (void)
*** 2991,3004 ****
  /* Worker function for generating movem from mem for load_multiple.  */
  
  rtx
! cris_gen_movem_load (rtx osrc, rtx nregs_rtx, int nprefix)
  {
    int nregs = INTVAL (nregs_rtx);
    rtvec vec;
    int eltno = 1;
    int i;
!   rtx srcreg = XEXP (osrc, 0);
!   rtx src = osrc;
    unsigned int regno = nregs - 1;
    int regno_inc = -1;
  
--- 3119,3131 ----
  /* Worker function for generating movem from mem for load_multiple.  */
  
  rtx
! cris_gen_movem_load (rtx src, rtx nregs_rtx, int nprefix)
  {
    int nregs = INTVAL (nregs_rtx);
    rtvec vec;
    int eltno = 1;
    int i;
!   rtx srcreg = XEXP (src, 0);
    unsigned int regno = nregs - 1;
    int regno_inc = -1;
  
*************** cris_gen_movem_load (rtx osrc, rtx nregs
*** 3009,3033 ****
      abort ();
  
    /* Don't use movem for just one insn.  The insns are equivalent except
!      for the pipeline hazard; movem does not forward the loaded
!      registers so there's a three cycles penalty for use.  */
    if (nregs == 1)
!     return gen_movsi (gen_rtx_REG (SImode, regno), osrc);
  
    vec = rtvec_alloc (nprefix + nregs
! 		     + (GET_CODE (XEXP (osrc, 0)) == POST_INC));
!   src = replace_equiv_address (osrc, srcreg);
!   RTVEC_ELT (vec, nprefix)
!     = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno), src);
!   regno += regno_inc;
  
!   if (GET_CODE (XEXP (osrc, 0)) == POST_INC)
      {
        RTVEC_ELT (vec, nprefix + 1)
  	= gen_rtx_SET (VOIDmode, srcreg, plus_constant (srcreg, nregs * 4));
        eltno++;
      }
  
    for (i = 1; i < nregs; i++, eltno++)
      {
        RTVEC_ELT (vec, nprefix + eltno)
--- 3136,3161 ----
      abort ();
  
    /* Don't use movem for just one insn.  The insns are equivalent except
!      for the pipeline hazard (on v32); movem does not forward the loaded
!      registers so there's a three cycles penalty for their use.  */
    if (nregs == 1)
!     return gen_movsi (gen_rtx_REG (SImode, 0), src);
  
    vec = rtvec_alloc (nprefix + nregs
! 		     + (GET_CODE (XEXP (src, 0)) == POST_INC));
  
!   if (GET_CODE (XEXP (src, 0)) == POST_INC)
      {
        RTVEC_ELT (vec, nprefix + 1)
  	= gen_rtx_SET (VOIDmode, srcreg, plus_constant (srcreg, nregs * 4));
        eltno++;
      }
  
+   src = replace_equiv_address (src, srcreg);
+   RTVEC_ELT (vec, nprefix)
+     = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno), src);
+   regno += regno_inc;
+ 
    for (i = 1; i < nregs; i++, eltno++)
      {
        RTVEC_ELT (vec, nprefix + eltno)
*************** cris_gen_movem_load (rtx osrc, rtx nregs
*** 3039,3044 ****
--- 3167,3302 ----
    return gen_rtx_PARALLEL (VOIDmode, vec);
  }
  
+ /* Worker function for generating movem to mem.  If FRAME_RELATED, notes
+    are added that the dwarf2 machinery understands.  */
+ 
+ rtx
+ cris_emit_movem_store (rtx dest, rtx nregs_rtx, int increment,
+ 		       bool frame_related)
+ {
+   int nregs = INTVAL (nregs_rtx);
+   rtvec vec;
+   int eltno = 1;
+   int i;
+   rtx insn;
+   rtx destreg = XEXP (dest, 0);
+   unsigned int regno = nregs - 1;
+   int regno_inc = -1;
+ 
+   if (GET_CODE (destreg) == POST_INC)
+     increment += nregs * 4;
+ 
+   if (GET_CODE (destreg) == POST_INC || GET_CODE (destreg) == PLUS)
+     destreg = XEXP (destreg, 0);
+ 
+   if (!REG_P (destreg))
+     abort ();
+ 
+   /* Don't use movem for just one insn.  The insns are equivalent except
+      for the pipeline hazard (on v32); movem does not forward the loaded
+      registers so there's a three cycles penalty for use.  */
+   if (nregs == 1)
+     {
+       rtx mov = gen_rtx_SET (VOIDmode, dest, gen_rtx_REG (SImode, 0));
+ 
+       if (increment == 0)
+ 	{
+ 	  insn = emit_insn (mov);
+ 	  if (frame_related)
+ 	    RTX_FRAME_RELATED_P (insn) = 1;
+ 	  return insn;
+ 	}
+ 
+       /* If there was a request for a side-effect, create the ordinary
+          parallel.  */
+       vec = rtvec_alloc (2);
+ 
+       RTVEC_ELT (vec, 0) = mov;
+       RTVEC_ELT (vec, 1) = gen_rtx_SET (VOIDmode, destreg,
+ 					plus_constant (destreg, increment));
+       if (frame_related)
+ 	{
+ 	  RTX_FRAME_RELATED_P (mov) = 1;
+ 	  RTX_FRAME_RELATED_P (RTVEC_ELT (vec, 1)) = 1;
+ 	}
+     }
+   else
+     {
+       vec = rtvec_alloc (nregs + (increment != 0 ? 1 : 0));
+       RTVEC_ELT (vec, 0)
+ 	= gen_rtx_SET (VOIDmode,
+ 		       replace_equiv_address (dest,
+ 					      plus_constant (destreg,
+ 							     increment)),
+ 		       gen_rtx_REG (SImode, regno));
+       regno += regno_inc;
+ 
+       /* The dwarf2 info wants this mark on each component in a parallel
+ 	 that's part of the prologue (though it's optional on the first
+ 	 component).  */
+       if (frame_related)
+ 	RTX_FRAME_RELATED_P (RTVEC_ELT (vec, 0)) = 1;
+ 
+       if (increment != 0)
+ 	{
+ 	  RTVEC_ELT (vec, 1)
+ 	    = gen_rtx_SET (VOIDmode, destreg,
+ 			   plus_constant (destreg,
+ 					  increment != 0
+ 					  ? increment : nregs * 4));
+ 	  eltno++;
+ 
+ 	  if (frame_related)
+ 	    RTX_FRAME_RELATED_P (RTVEC_ELT (vec, 1)) = 1;
+ 
+ 	  /* Don't call adjust_address_nv on a post-incremented address if
+ 	     we can help it.  */
+ 	  if (GET_CODE (XEXP (dest, 0)) == POST_INC)
+ 	    dest = replace_equiv_address (dest, destreg);
+ 	}
+ 
+       for (i = 1; i < nregs; i++, eltno++)
+ 	{
+ 	  RTVEC_ELT (vec, eltno)
+ 	    = gen_rtx_SET (VOIDmode, adjust_address_nv (dest, SImode, i * 4),
+ 			   gen_rtx_REG (SImode, regno));
+ 	  if (frame_related)
+ 	    RTX_FRAME_RELATED_P (RTVEC_ELT (vec, eltno)) = 1;
+ 	  regno += regno_inc;
+ 	}
+     }
+ 
+   insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+ 
+   /* Because dwarf2out.c handles the insns in a parallel as a sequence,
+      we need to keep the stack adjustment separate, after the
+      MEM-setters.  Else the stack-adjustment in the second component of
+      the parallel would be mishandled; the offsets for the SETs that
+      follow it would be wrong.  We prepare for this by adding a
+      REG_FRAME_RELATED_EXPR with the MEM-setting parts in a SEQUENCE
+      followed by the increment.  Note that we have FRAME_RELATED_P on
+      all the SETs, including the original stack adjustment SET in the
+      parallel.  */
+   if (frame_related)
+     {
+       if (increment != 0)
+ 	{
+ 	  rtx seq = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (nregs + 1));
+ 	  XVECEXP (seq, 0, 0) = XVECEXP (PATTERN (insn), 0, 0);
+ 	  for (i = 1; i < nregs; i++)
+ 	    XVECEXP (seq, 0, i) = XVECEXP (PATTERN (insn), 0, i + 1);
+ 	  XVECEXP (seq, 0, nregs) = XVECEXP (PATTERN (insn), 0, 1);
+ 	  REG_NOTES (insn)
+ 	    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, seq,
+ 				 REG_NOTES (insn));
+ 	}
+ 
+       RTX_FRAME_RELATED_P (insn) = 1;
+     }
+ 
+   return insn;
+ }
+ 
  /* Use from within code, from e.g. PRINT_OPERAND and
     PRINT_OPERAND_ADDRESS.  Macros used in output_addr_const need to emit
     different things depending on whether code operand or constant is
*************** cris_setup_incoming_varargs (CUMULATIVE_
*** 3175,3187 ****
  			     int second_time)
  {
    if (ca->regs < CRIS_MAX_ARGS_IN_REGS)
-     *pretend_arg_size = (CRIS_MAX_ARGS_IN_REGS - ca->regs) * 4;
-   if (TARGET_PDEBUG)
      {
!       fprintf (asm_out_file,
! 	       "\n; VA:: ANSI: %d args before, anon @ #%d, %dtime\n",
! 	       ca->regs, *pretend_arg_size, second_time);
      }
  }
  
  /* Return true if TYPE must be passed by invisible reference.
--- 3433,3448 ----
  			     int second_time)
  {
    if (ca->regs < CRIS_MAX_ARGS_IN_REGS)
      {
!       int stdarg_regs = CRIS_MAX_ARGS_IN_REGS - ca->regs;
!       cfun->machine->stdarg_regs = stdarg_regs;
!       *pretend_arg_size = stdarg_regs * 4;
      }
+ 
+   if (TARGET_PDEBUG)
+     fprintf (asm_out_file,
+ 	     "\n; VA:: ANSI: %d args before, anon @ #%d, %dtime\n",
+ 	     ca->regs, *pretend_arg_size, second_time);
  }
  
  /* Return true if TYPE must be passed by invisible reference.
Index: cris.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.h,v
retrieving revision 1.88
diff -c -p -r1.88 cris.h
*** cris.h	4 Apr 2005 22:43:34 -0000	1.88
--- cris.h	13 Apr 2005 15:48:12 -0000
*************** enum reg_class 
*** 854,861 ****
  		  && BIAP_INDEX_P (XEXP (XEXP (X, 0), 0))))))		\
   )
  
! #define EXTRA_CONSTRAINT_S(X) \
!  (flag_pic && CONSTANT_P (X) && cris_gotless_symbol (X))
  
  #define EXTRA_CONSTRAINT_U(X) \
   (flag_pic && CONSTANT_P (X) && cris_got_symbol (X))
--- 854,866 ----
  		  && BIAP_INDEX_P (XEXP (XEXP (X, 0), 0))))))		\
   )
  
! /* We're kind of out of constraints, so we use "S" for both gotless
!    symbols and the GOT-address load.  Both must go in a general register
!    only: for pre-V32, arithmetic is done on the destination.  */
! #define EXTRA_CONSTRAINT_S(X)						\
!  (flag_pic								\
!   && ((CONSTANT_P (X) && cris_gotless_symbol (X))			\
!       || (GET_CODE (X) == UNSPEC && XINT ((X), 1) == CRIS_UNSPEC_GOT)))
  
  #define EXTRA_CONSTRAINT_U(X) \
   (flag_pic && CONSTANT_P (X) && cris_got_symbol (X))
*************** struct cum_args {int regs;};
*** 1629,1634 ****
--- 1634,1641 ----
    {MEM}},						\
   {"cris_load_multiple_op",				\
    {PARALLEL}},						\
+  {"cris_store_multiple_op",				\
+   {PARALLEL}},						\
   {"cris_bdap_operand",					\
    {SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT,	\
     CONST_DOUBLE, CONST, SIGN_EXTEND}},			\
*************** struct cum_args {int regs;};
*** 1637,1643 ****
     CONST_DOUBLE, CONST, SIGN_EXTEND, MULT}},		\
   {"cris_general_operand_or_gotless_symbol",		\
    {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
!    LABEL_REF, SUBREG, REG, MEM}},			\
   {"cris_general_operand_or_symbol",			\
    {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
     LABEL_REF, SUBREG, REG, MEM}},			\
--- 1644,1650 ----
     CONST_DOUBLE, CONST, SIGN_EXTEND, MULT}},		\
   {"cris_general_operand_or_gotless_symbol",		\
    {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
!    LABEL_REF, SUBREG, REG, MEM, UNSPEC}},		\
   {"cris_general_operand_or_symbol",			\
    {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,		\
     LABEL_REF, SUBREG, REG, MEM}},			\
Index: cris.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.md,v
retrieving revision 1.27
diff -c -p -r1.27 cris.md
*** cris.md	4 Apr 2005 22:43:34 -0000	1.27
--- cris.md	13 Apr 2005 15:48:12 -0000
***************
*** 59,69 ****
  ;; 0 PLT reference from call expansion: operand 0 is the address,
  ;;   the mode is VOIDmode.  Always wrapped in CONST.
  ;; 1 Stack frame deallocation barrier.
  
  (define_constants
    [(CRIS_UNSPEC_PLT 0)
!    (CRIS_UNSPEC_FRAME_DEALLOC 1)])
! 
  
  ;; Register numbers.
  (define_constants
--- 59,70 ----
  ;; 0 PLT reference from call expansion: operand 0 is the address,
  ;;   the mode is VOIDmode.  Always wrapped in CONST.
  ;; 1 Stack frame deallocation barrier.
+ ;; 2 The address of the global offset table as a source operand.
  
  (define_constants
    [(CRIS_UNSPEC_PLT 0)
!    (CRIS_UNSPEC_FRAME_DEALLOC 1)
!    (CRIS_UNSPEC_GOT 2)])
  
  ;; Register numbers.
  (define_constants
***************
*** 1067,1087 ****
  	}
        return \"move.d %1,%0\";
  
!       case 8:
! 	/* FIXME: Try and split this into pieces GCC makes better code of,
! 	   than this multi-insn pattern.  Synopsis: wrap the GOT-relative
! 	   symbol into an unspec, and when PIC, recognize the unspec
! 	   everywhere a symbol is normally recognized.  (The PIC register
! 	   should be recognized by GCC as pic_offset_table_rtx when needed
! 	   and similar for PC.)  Each component can then be optimized with
! 	   the rest of the code; it should be possible to have a constant
! 	   term added on an unspec.  Don't forget to add a REG_EQUAL (or
! 	   is it REG_EQUIV) note to the destination.  It might not be
! 	   worth it.  Measure.
! 
! 	   Note that the 'v' modifier makes PLT references be output as
! 	   sym:PLT rather than [rPIC+sym:GOTPLT].  */
! 	return \"move.d %v1,%0\;add.d %P1,%0\";
  
      default:
        return \"BOGUS: %1 to %0\";
--- 1068,1100 ----
  	}
        return \"move.d %1,%0\";
  
!     case 8:
!       /* FIXME: Try and split this into pieces GCC makes better code of,
! 	 than this multi-insn pattern.  Synopsis: wrap the GOT-relative
! 	 symbol into an unspec, and when PIC, recognize the unspec
! 	 everywhere a symbol is normally recognized.  (The PIC register
! 	 should be recognized by GCC as pic_offset_table_rtx when needed
! 	 and similar for PC.)  Each component can then be optimized with
! 	 the rest of the code; it should be possible to have a constant
! 	 term added on an unspec.  Don't forget to add a REG_EQUAL (or
! 	 is it REG_EQUIV) note to the destination.  It might not be
! 	 worth it.  Measure.
! 
! 	 Note that the 'v' modifier makes PLT references be output as
! 	 sym:PLT rather than [rPIC+sym:GOTPLT].  */
!       if (GET_CODE (operands[1]) == UNSPEC
! 	  && XINT (operands[1], 1) == CRIS_UNSPEC_GOT)
! 	{
! 	  /* We clobber cc0 rather than set it to GOT.  Should not
!              matter, though.  */
! 	  CC_STATUS_INIT;
! 	  if (REGNO (operands[0]) != PIC_OFFSET_TABLE_REGNUM)
! 	    abort ();
! 
! 	  return \"move.d $pc,%0\;sub.d .:GOTOFF,%0\";
! 	}
! 
!       return \"move.d %v1,%0\;add.d %P1,%0\";
  
      default:
        return \"BOGUS: %1 to %0\";
***************
*** 1387,1394 ****
     move %1,%0"
    [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
  
! ;; Note that the order of the registers is the reverse of that of the
! ;; standard pattern "load_multiple".
  (define_insn "*cris_load_multiple"
    [(match_parallel 0 "cris_load_multiple_op"
  		   [(set (match_operand:SI 1 "register_operand" "=r,r")
--- 1400,1407 ----
     move %1,%0"
    [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
  
! ;; Note that the memory layout of the registers is the reverse of that
! ;; of the standard patterns "load_multiple" and "store_multiple".
  (define_insn "*cris_load_multiple"
    [(match_parallel 0 "cris_load_multiple_op"
  		   [(set (match_operand:SI 1 "register_operand" "=r,r")
***************
*** 1404,1409 ****
--- 1417,1431 ----
     ;; FIXME: temporary change until all insn lengths are correctly
     ;; described.  FIXME: have better target control over bb-reorder.
     (set_attr "length" "0")])
+ 
+ (define_insn "*cris_store_multiple"
+   [(match_parallel 0 "cris_store_multiple_op"
+ 		   [(set (match_operand:SI 2 "memory_operand" "=Q,m")
+ 			 (match_operand:SI 1 "register_operand" "r,r"))])]
+   ""
+   "movem %o0,%O0"
+   [(set_attr "cc" "none")
+    (set_attr "slottable" "yes,no")])
  
  
  ;; Sign- and zero-extend insns with standard names.
***************
*** 3515,3520 ****
--- 3537,3547 ----
   	 (const_string "no")
  	 (const_string "has_slot")))])
  
+ (define_expand "prologue"
+   [(const_int 0)]
+   "TARGET_PROLOGUE_EPILOGUE"
+   "cris_expand_prologue (); DONE;")
+ 
  ;; Note that the (return) from the expander itself is always the last
  ;; insn in the epilogue.
  (define_expand "epilogue"

brgds, H-P



More information about the Gcc-patches mailing list