[PATCH/RFC] m68k: add pc as register

Roman Zippel zippel@linux-m68k.org
Mon Aug 9 22:48:00 GMT 2004


Hi,

This is an experimental patch I'd like to get some comments on. The main 
purpose is to add the pc as another register, so it can be used in address 
operations. The goal is for pc relative addressing not to be a special 
case anymore and letting it work more like pic addressing. As a result 
this will simplify the move patterns again, which currently have separate 
constraints for the pcrel and normal addressing.

I didn't modify the -mpcrel option yet and modified the tablejump pattern 
instead, which requires now a lot less magic to use pc relative 
addressing. One remaining issue is the use of PIC_CASE_VECTOR_ADDRESS (of 
which is m68k is the only user), currently I use it to wrap the label 
within an unspec and later turn this into a (plus (pc) (label)) (I cannot 
do this immediately to get this past break_out_memory_refs(), which would 
separate the label from the pc).  I'm open to ideas on how to remove 
PIC_CASE_VECTOR_ADDRESS completely, maybe by adding a flag to the label?

Another issue is that on m68k a pc relative address must not appear as the 
destination of an operation. A rather simple solution would be to modify 
nonimmediate_operand to reject pc relative operands. Is it acceptable to 
add a hook to nonimmediate_operand() or is it better to replace nearly all 
of them within m68k.md?

The rest of the patch splits a few more patterns. It splits long moves and 
truncxfdf2 very similiar to i386. This needs a bit more fine tuning and 
retesting.

bye, Roman

Index: expr.c
===================================================================
RCS file: /home/roman/src/gcc-cvs/gcc/gcc/expr.c,v
retrieving revision 1.696
diff -u -p -c -r1.696 expr.c
*** expr.c	6 Aug 2004 10:40:29 -0000	1.696
--- expr.c	9 Aug 2004 09:56:37 -0000
*************** do_tablejump (rtx index, enum machine_mo
*** 9102,9115 ****
    if (mode != Pmode)
      index = convert_to_mode (Pmode, index, 1);
  
-   /* Don't let a MEM slip through, because then INDEX that comes
-      out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
-      and break_out_memory_refs will go to work on it and mess it up.  */
- #ifdef PIC_CASE_VECTOR_ADDRESS
-   if (flag_pic && !REG_P (index))
-     index = copy_to_mode_reg (Pmode, index);
- #endif
- 
    /* If flag_force_addr were to affect this address
       it could interfere with the tricky assumptions made
       about addresses that contain label-refs,
--- 9102,9107 ----
*************** do_tablejump (rtx index, enum machine_mo
*** 9123,9133 ****
  				      GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
  			gen_rtx_LABEL_REF (Pmode, table_label));
  #ifdef PIC_CASE_VECTOR_ADDRESS
!   if (flag_pic)
!     index = PIC_CASE_VECTOR_ADDRESS (index);
!   else
  #endif
!     index = memory_address_noforce (CASE_VECTOR_MODE, index);
    temp = gen_reg_rtx (CASE_VECTOR_MODE);
    vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
    RTX_UNCHANGING_P (vector) = 1;
--- 9115,9123 ----
  				      GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
  			gen_rtx_LABEL_REF (Pmode, table_label));
  #ifdef PIC_CASE_VECTOR_ADDRESS
!   PIC_CASE_VECTOR_ADDRESS (index);
  #endif
!   index = memory_address_noforce (CASE_VECTOR_MODE, index);
    temp = gen_reg_rtx (CASE_VECTOR_MODE);
    vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
    RTX_UNCHANGING_P (vector) = 1;
Index: recog.c
===================================================================
RCS file: /home/roman/src/gcc-cvs/gcc/gcc/recog.c,v
retrieving revision 1.208
diff -u -p -c -r1.208 recog.c
*** recog.c	3 Aug 2004 23:37:32 -0000	1.208
--- recog.c	9 Aug 2004 09:56:37 -0000
*************** const_double_operand (rtx op, enum machi
*** 1142,1148 ****
  int
  nonimmediate_operand (rtx op, enum machine_mode mode)
  {
!   return (general_operand (op, mode) && ! CONSTANT_P (op));
  }
  
  /* Return 1 if OP is a register reference or immediate value of mode MODE.  */
--- 1142,1148 ----
  int
  nonimmediate_operand (rtx op, enum machine_mode mode)
  {
!   return (general_operand (op, mode) && ! CONSTANT_P (op) && !reg_mentioned_p (pc_pointer_rtx, op));
  }
  
  /* Return 1 if OP is a register reference or immediate value of mode MODE.  */
diff -crp config/m68k/linux.h config/m68k/linux.h
*** config/m68k/linux.h	2004-08-08 17:58:00.000000000 +0200
--- config/m68k/linux.h	2004-08-07 13:33:05.000000000 +0200
*************** Boston, MA 02111-1307, USA.  */
*** 146,163 ****
  
  /* Use the default action for outputting the case label.  */
  #undef ASM_OUTPUT_CASE_LABEL
- #define ASM_RETURN_CASE_JUMP				\
-   do {							\
-     if (TARGET_COLDFIRE)				\
-       {							\
- 	if (ADDRESS_REG_P (operands[0]))		\
- 	  return "jmp %%pc@(2,%0:l)";			\
- 	else						\
- 	  return "ext%.l %0\n\tjmp %%pc@(2,%0:l)";	\
-       }							\
-     else						\
-       return "jmp %%pc@(2,%0:w)";			\
-   } while (0)
  
  /* This is how to output an assembler line that says to advance the
     location counter to a multiple of 2**LOG bytes.  */
--- 146,151 ----
diff -crp config/m68k/m68k.c config/m68k/m68k.c
*** config/m68k/m68k.c	2004-08-08 19:11:48.000000000 +0200
--- config/m68k/m68k.c	2004-08-09 11:50:52.000000000 +0200
*************** Boston, MA 02111-1307, USA.  */
*** 38,43 ****
--- 38,44 ----
  #include "toplev.h"
  #include "expr.h"
  #include "reload.h"
+ #include "ggc.h"
  #include "tm_p.h"
  #include "target.h"
  #include "target-def.h"
*************** enum reg_class regno_reg_class[] =
*** 52,60 ****
    ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
    FP_REGS, FP_REGS, FP_REGS, FP_REGS,
    FP_REGS, FP_REGS, FP_REGS, FP_REGS,
!   ADDR_REGS
  };
  
  
  /* The ASM_DOT macro allows easy string pasting to handle the differences
     between MOTOROLA and MIT syntaxes in asm_fprintf(), which doesn't
--- 53,62 ----
    ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS,
    FP_REGS, FP_REGS, FP_REGS, FP_REGS,
    FP_REGS, FP_REGS, FP_REGS, FP_REGS,
!   ADDR_REGS, PC_REGS
  };
  
+ rtx pc_pointer_rtx;
  
  /* The ASM_DOT macro allows easy string pasting to handle the differences
     between MOTOROLA and MIT syntaxes in asm_fprintf(), which doesn't
*************** struct m68k_frame
*** 100,105 ****
--- 102,120 ----
    int funcdef_no;
  };
  
+ struct m68k_address
+ {
+   rtx base, index, disp;
+   int mult;
+   unsigned absolute : 1;
+   unsigned index16 : 1;
+   unsigned disp8 : 1;
+   unsigned disp16 : 1;
+   unsigned pre_dec : 1;
+   unsigned post_inc : 1;
+   unsigned tablejump : 1;
+ };
+ 
  /* Current frame information calculated by m68k_compute_frame_layout().  */
  static struct m68k_frame current_frame;
  
*************** static void m68k_compute_frame_layout (v
*** 118,123 ****
--- 133,141 ----
  static bool m68k_save_reg (unsigned int regno, bool interrupt_handler);
  static int const_int_cost (rtx);
  static bool m68k_rtx_costs (rtx, int, int, int *);
+ static int m68k_address_cost (rtx);
+ static struct machine_function * m68k_init_machine_status (void);
+ static int m68k_decompose_address(rtx, struct m68k_address *);
  
  
  /* Specify the identification number of the library being built */
*************** int m68k_last_compare_had_fp_operands;
*** 168,173 ****
--- 186,193 ----
  
  #undef TARGET_RTX_COSTS
  #define TARGET_RTX_COSTS m68k_rtx_costs
+ #undef TARGET_ADDRESS_COST
+ #define TARGET_ADDRESS_COST m68k_address_cost
  
  #undef TARGET_ATTRIBUTE_TABLE
  #define TARGET_ATTRIBUTE_TABLE m68k_attribute_table
*************** override_options (void)
*** 250,255 ****
--- 270,279 ----
    if (flag_pic)
      flag_no_function_cse = 1;
  
+   init_machine_status = m68k_init_machine_status;
+ 
+   pc_pointer_rtx = gen_raw_REG (Pmode, 25);
+ 
    SUBTARGET_OVERRIDE_OPTIONS;
  }
  
*************** legitimize_pic_address (rtx orig, enum m
*** 1385,1390 ****
--- 1409,1418 ----
        pic_ref = gen_rtx_PLUS (Pmode, base, orig);
        /* Likewise, should we set special REG_NOTEs here?  */
      }
+   else if (GET_CODE (orig) == UNSPEC && XINT (orig, 1) == UNSPEC_PCREL)
+     {
+       pic_ref = gen_rtx_PLUS (Pmode, XVECEXP (orig, 0, 0), pc_pointer_rtx);
+     }
    return pic_ref;
  }
  
*************** m68k_rtx_costs (rtx x, int code, int out
*** 1502,1524 ****
  			(TARGET_COLDFIRE && !TARGET_5200) ? 2 : 5)
  #define DIVW_COST (TARGET_68020 ? 27 : TARGET_CF_HWDIV ? 11 : 12)
  
-     case PLUS:
-       /* An lea costs about three times as much as a simple add.  */
-       if (GET_MODE (x) == SImode
- 	  && GET_CODE (XEXP (x, 1)) == REG
- 	  && GET_CODE (XEXP (x, 0)) == MULT
- 	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
- 	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- 	  && (INTVAL (XEXP (XEXP (x, 0), 1)) == 2
- 	      || INTVAL (XEXP (XEXP (x, 0), 1)) == 4
- 	      || INTVAL (XEXP (XEXP (x, 0), 1)) == 8))
- 	{
- 	    /* lea an@(dx:l:i),am */
- 	    *total = COSTS_N_INSNS (TARGET_COLDFIRE ? 2 : 3);
- 	    return true;
- 	}
-       return false;
- 
      case ASHIFT:
      case ASHIFTRT:
      case LSHIFTRT:
--- 1530,1535 ----
*************** m68k_rtx_costs (rtx x, int code, int out
*** 1585,1590 ****
--- 1596,1621 ----
      }
  }
  
+ static int
+ m68k_address_cost (rtx x)
+ {
+   struct m68k_address addr;
+ 
+   if (!m68k_decompose_address(x, &addr))
+     abort ();
+ 
+   if (!addr.disp && !addr.index)
+     return COSTS_N_INSNS (1) / 2;
+ 
+   if (addr.absolute || addr.disp16)
+     return COSTS_N_INSNS (1);
+ 
+   if (addr.disp8)
+     return COSTS_N_INSNS (2);
+ 
+   return COSTS_N_INSNS (4);
+ }
+ 
  const char *
  output_move_const_into_data_reg (rtx *operands)
  {
*************** print_operand (FILE *file, rtx op, int l
*** 2688,2962 ****
     offset is output in word mode (eg movel a5@(_foo:w), a0).  When generating
     -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
  
! #if MOTOROLA
! #  define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
! 	asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname)
! #else /* !MOTOROLA */
! # define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
! 	asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname)
! #endif /* !MOTOROLA */
  
  void
! print_operand_address (FILE *file, rtx addr)
  {
!   register rtx reg1, reg2, breg, ireg;
!   rtx offset;
  
!   switch (GET_CODE (addr))
      {
!       case REG:
! 	fprintf (file, MOTOROLA ? "(%s)" : "%s@", M68K_REGNAME(REGNO (addr)));
! 	break;
!       case PRE_DEC:
! 	fprintf (file, MOTOROLA ? "-(%s)" : "%s@-",
! 	         M68K_REGNAME(REGNO (XEXP (addr, 0))));
! 	break;
!       case POST_INC:
! 	fprintf (file, MOTOROLA ? "(%s)+" : "%s@+",
! 		 M68K_REGNAME(REGNO (XEXP (addr, 0))));
! 	break;
!       case PLUS:
! 	reg1 = reg2 = ireg = breg = offset = 0;
! 	if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
! 	  {
! 	    offset = XEXP (addr, 0);
! 	    addr = XEXP (addr, 1);
! 	  }
! 	else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
! 	  {
! 	    offset = XEXP (addr, 1);
! 	    addr = XEXP (addr, 0);
! 	  }
! 	if (GET_CODE (addr) != PLUS)
! 	  {
! 	    ;
! 	  }
! 	else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND)
! 	  {
! 	    reg1 = XEXP (addr, 0);
! 	    addr = XEXP (addr, 1);
! 	  }
! 	else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND)
! 	  {
! 	    reg1 = XEXP (addr, 1);
! 	    addr = XEXP (addr, 0);
! 	  }
! 	else if (GET_CODE (XEXP (addr, 0)) == MULT)
! 	  {
! 	    reg1 = XEXP (addr, 0);
! 	    addr = XEXP (addr, 1);
! 	  }
! 	else if (GET_CODE (XEXP (addr, 1)) == MULT)
! 	  {
! 	    reg1 = XEXP (addr, 1);
! 	    addr = XEXP (addr, 0);
! 	  }
! 	else if (GET_CODE (XEXP (addr, 0)) == REG)
! 	  {
! 	    reg1 = XEXP (addr, 0);
! 	    addr = XEXP (addr, 1);
! 	  }
! 	else if (GET_CODE (XEXP (addr, 1)) == REG)
! 	  {
! 	    reg1 = XEXP (addr, 1);
! 	    addr = XEXP (addr, 0);
! 	  }
! 	if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT
! 	    || GET_CODE (addr) == SIGN_EXTEND)
! 	  {
! 	    if (reg1 == 0)
! 	      {
! 		reg1 = addr;
! 	      }
! 	    else
! 	      {
! 		reg2 = addr;
! 	      }
! 	    addr = 0;
! 	  }
! #if 0	/* for OLD_INDEXING */
! 	else if (GET_CODE (addr) == PLUS)
! 	  {
! 	    if (GET_CODE (XEXP (addr, 0)) == REG)
! 	      {
! 		reg2 = XEXP (addr, 0);
! 		addr = XEXP (addr, 1);
! 	      }
! 	    else if (GET_CODE (XEXP (addr, 1)) == REG)
! 	      {
! 		reg2 = XEXP (addr, 1);
! 		addr = XEXP (addr, 0);
! 	      }
! 	  }
  #endif
! 	if (offset != 0)
! 	  {
! 	    if (addr != 0)
! 	      {
! 		abort ();
! 	      }
! 	    addr = offset;
! 	  }
! 	if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND
! 		      || GET_CODE (reg1) == MULT))
! 	    || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
! 	  {
! 	    breg = reg2;
! 	    ireg = reg1;
! 	  }
! 	else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
! 	  {
! 	    breg = reg1;
! 	    ireg = reg2;
! 	  }
! 	if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF
! 	    && ! (flag_pic && ireg == pic_offset_table_rtx))
! 	  {
! 	    int scale = 1;
! 	    if (GET_CODE (ireg) == MULT)
! 	      {
! 		scale = INTVAL (XEXP (ireg, 1));
! 		ireg = XEXP (ireg, 0);
! 	      }
! 	    if (GET_CODE (ireg) == SIGN_EXTEND)
! 	      {
! 		ASM_OUTPUT_CASE_FETCH (file,
! 			     CODE_LABEL_NUMBER (XEXP (addr, 0)),
! 			     M68K_REGNAME(REGNO (XEXP (ireg, 0))));
! 		fprintf (file, "w");
! 	      }
! 	    else
  	      {
! 		ASM_OUTPUT_CASE_FETCH (file,
! 			     CODE_LABEL_NUMBER (XEXP (addr, 0)),
! 			     M68K_REGNAME(REGNO (ireg)));
! 		fprintf (file, "l");
  	      }
- 	    if (scale != 1)
- 	      fprintf (file, MOTOROLA ? "*%d" : ":%d", scale);
- 	    putc (')', file);
- 	    break;
- 	  }
- 	if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
- 	    && ! (flag_pic && breg == pic_offset_table_rtx))
- 	  {
- 	    ASM_OUTPUT_CASE_FETCH (file,
- 			 CODE_LABEL_NUMBER (XEXP (addr, 0)),
- 			 M68K_REGNAME(REGNO (breg)));
- 	    fprintf (file, "l)");
  	    break;
! 	  }
! 	if (ireg != 0 || breg != 0)
! 	  {
! 	    int scale = 1;
! 	    if (breg == 0)
  	      {
! 		abort ();
  	      }
! 	    if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF)
  	      {
! 		abort ();
  	      }
- 	    if (MOTOROLA)
- 	      {
- 		if (addr != 0)
- 		  {
- 		    output_addr_const (file, addr);
- 	            if (flag_pic && (breg == pic_offset_table_rtx))
- 		      {
- 			fprintf (file, "@GOT");
- 			if (flag_pic == 1)
- 			  fprintf (file, ".w");
- 		      }
- 		  }
- 		fprintf (file, "(%s", M68K_REGNAME(REGNO (breg)));
- 		if (ireg != 0)
- 		  putc (',', file);
- 	      }
- 	    else /* !MOTOROLA */
- 	      {
- 		fprintf (file, "%s@(", M68K_REGNAME(REGNO (breg)));
- 		if (addr != 0)
- 		  {
- 		    output_addr_const (file, addr);
- 		    if (breg == pic_offset_table_rtx)
- 		      switch (flag_pic)
- 		        {
- 		        case 1:
- 		          fprintf (file, ":w"); break;
- 		        case 2:
- 		          fprintf (file, ":l"); break;
- 		        default:
- 		          break;
- 		        }
- 		    if (ireg != 0)
- 		      putc (',', file);
- 		  }
- 	      } /* !MOTOROLA */
- 	    if (ireg != 0 && GET_CODE (ireg) == MULT)
- 	      {
- 		scale = INTVAL (XEXP (ireg, 1));
- 		ireg = XEXP (ireg, 0);
- 	      }
- 	    if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND)
- 	      fprintf (file, MOTOROLA ? "%s.w" : "%s:w",
- 		       M68K_REGNAME(REGNO (XEXP (ireg, 0))));
- 	    else if (ireg != 0)
- 	      fprintf (file, MOTOROLA ? "%s.l" : "%s:l",
- 		       M68K_REGNAME(REGNO (ireg)));
- 	    if (scale != 1)
- 	      fprintf (file, MOTOROLA ? "*%d" : ":%d", scale);
- 	    putc (')', file);
- 	    break;
- 	  }
- 	else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
- 		 && ! (flag_pic && reg1 == pic_offset_table_rtx))
- 	  {
- 	    ASM_OUTPUT_CASE_FETCH (file,
- 			 CODE_LABEL_NUMBER (XEXP (addr, 0)),
- 			 M68K_REGNAME(REGNO (reg1)));
- 	    fprintf (file, "l)");
  	    break;
! 	  }
! 	/* FALL-THROUGH (is this really what we want?)  */
!       default:
!         if (GET_CODE (addr) == CONST_INT
! 	    && INTVAL (addr) < 0x8000
! 	    && INTVAL (addr) >= -0x8000)
! 	  {
! 	    fprintf (file, MOTOROLA ? "%d.w" : "%d:w", (int) INTVAL (addr));
! 	  }
! 	else if (GET_CODE (addr) == CONST_INT)
! 	  {
! 	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
! 	  }
! 	else if (TARGET_PCREL)
! 	  {
! 	    fputc ('(', file);
! 	    output_addr_const (file, addr);
! 	    if (flag_pic == 1)
! 	      asm_fprintf (file, ":w,%Rpc)");
! 	    else
! 	      asm_fprintf (file, ":l,%Rpc)");
! 	  }
! 	else
! 	  {
! 	    /* Special case for SYMBOL_REF if the symbol name ends in
! 	       `.<letter>', this can be mistaken as a size suffix.  Put
! 	       the name in parentheses.  */
! 	    if (GET_CODE (addr) == SYMBOL_REF
! 		&& strlen (XSTR (addr, 0)) > 2
! 		&& XSTR (addr, 0)[strlen (XSTR (addr, 0)) - 2] == '.')
! 	      {
! 		putc ('(', file);
! 		output_addr_const (file, addr);
! 		putc (')', file);
! 	      }
! 	    else
! 	      output_addr_const (file, addr);
! 	  }
! 	break;
      }
  }
  
  /* Check for cases where a clr insns can be omitted from code using
--- 2719,3061 ----
     offset is output in word mode (eg movel a5@(_foo:w), a0).  When generating
     -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
  
! void
! print_operand_address (FILE *file, rtx x)
! {
!   struct m68k_address addr;
! 
!   if (!m68k_decompose_address (x, &addr))
!     abort ();
! 
!   if (addr.absolute)
!     {
!       if (GET_CODE (addr.disp) == CONST_INT
! 	  && INTVAL (addr.disp) < 0x8000
! 	  && INTVAL (addr.disp) >= -0x8000)
! 	{
! 	  fprintf (file, MOTOROLA ? "%d.w" : "%d:w", (int) INTVAL (addr.disp));
! 	}
!       else if (GET_CODE (addr.disp) == CONST_INT)
! 	{
! 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr.disp));
! 	}
!       else if (TARGET_PCREL)
! 	{
! 	  fputc ('(', file);
! 	  output_addr_const (file, addr.disp);
! 	  if (flag_pic == 1)
! 	    asm_fprintf (file, ":w,%Rpc)");
! 	  else
! 	    asm_fprintf (file, ":l,%Rpc)");
! 	}
!       else
! 	{
! 	  /* Special case for SYMBOL_REF if the symbol name ends in
! 	     `.<letter>', this can be mistaken as a size suffix.  Put
! 	     the name in parentheses.  */
! 	  if (GET_CODE (addr.disp) == SYMBOL_REF
! 	      && strlen (XSTR (addr.disp, 0)) > 2
! 	      && XSTR (addr.disp, 0)[strlen (XSTR (addr.disp, 0)) - 2] == '.')
! 	    {
! 	      putc ('(', file);
! 	      output_addr_const (file, addr.disp);
! 	      putc (')', file);
! 	    }
! 	  else
! 	    output_addr_const (file, addr.disp);
! 	}
!       return;
!     }
! 
!   if (addr.pre_dec)
!     {
!       fprintf (file, MOTOROLA ? "-(%s)" : "%s@-",
! 	       M68K_REGNAME (REGNO (addr.base)));
!       return;
!     }
!   if (addr.post_inc)
!     {
!       fprintf (file, MOTOROLA ? "(%s)+" : "%s@+",
! 	       M68K_REGNAME (REGNO (addr.base)));
!       return;
!     }
!   if (!MOTOROLA)
!     {
!       if (addr.base)
! 	fprintf (file, "%s", M68K_REGNAME (REGNO (addr.base)));
!       fprintf (file, "@");
!       if (!addr.disp && !addr.index)
! 	return;
!       fprintf (file, "(");
!     }
!   if (addr.disp)
!     {
!       output_addr_const (file, addr.disp);
!       if (flag_pic && addr.base == pic_offset_table_rtx)
! 	{
! 	  fprintf (file, "@GOT");
! 	  fprintf (file, MOTOROLA ? ".%c" : ":%c", flag_pic == 1 ? 'w' : 'l');
! 	}
!       if (!MOTOROLA && addr.index)
! 	fprintf (file, ",");
!     }
!   if (MOTOROLA)
!     {
!       fprintf (file, "(");
!       if (addr.base)
! 	{
! 	  fprintf (file, "%s", M68K_REGNAME (REGNO (addr.base)));
! 	  if (addr.index)
! 	    fprintf (file, ",");
! 	}
!     }
!   if (addr.index)
!     {
!       if (!REG_P (addr.index))
! 	addr.index = SUBREG_REG (addr.index);
!       fprintf (file, "%s", M68K_REGNAME (REGNO (addr.index)));
!       fprintf (file, MOTOROLA ? ".%c" : ":%c", addr.index16 ? 'w' : 'l');
!       if (addr.mult)
! 	fprintf (file, MOTOROLA ? "*%d" : ":%d", addr.mult);
!     }
!   fprintf (file, ")");
! }
  
+ #if 0
  void
! split_di (rtx operands[], unsigned int num, rtx lo_half[], rtx hi_half[])
  {
!   int lo_adj = 0, hi_adj = 0;
  
!   if (num > 1)
      {
!       if (pre_dec_operand (operands[0], VOIDmode) ||
! 	  pre_dec_operand (operands[1], VOIDmode))
! 	{
! 	  rtx *tmp = lo_half;
! 	  lo_half = hi_half;
! 	  hi_half = tmp;
! 	}
!       if (pre_dec_operand (operands[0], VOIDmode)
! 	  && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1]))
! 	lo_adj = 4;
!       else if (pre_dec_operand (operands[1], VOIDmode)
! 	  && reg_mentioned_p (XEXP (XEXP (operands[1], 0), 0), operands[0]))
! 	lo_adj = 4;
!       else if (post_inc_operand (operands[0], VOIDmode)
! 	  && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1]))
! 	hi_adj = -4;
!       else if (post_inc_operand (operands[1], VOIDmode)
! 	  && reg_mentioned_p (XEXP (XEXP (operands[1], 0), 0), operands[0]))
! 	hi_adj = -4;
!     }
!   while (num--)
!     {
!       rtx op = operands[num];
! 
!       if (!MEM_P (op))
! 	{
! 	  lo_half[num] = simplify_gen_subreg (SImode, op,
! 					      GET_MODE (op) == VOIDmode
! 					      ? DImode : GET_MODE (op), 0);
! 	  hi_half[num] = simplify_gen_subreg (SImode, op,
! 					      GET_MODE (op) == VOIDmode
! 					      ? DImode : GET_MODE (op), 4);
! 	}
!       else if (GET_CODE (XEXP (op, 0)) == PRE_DEC ||
! 	       GET_CODE (XEXP (op, 0)) == POST_INC)
! 	{
! 	  lo_half[num] = hi_half[num] = adjust_address (op, SImode, 0);
! 	}
!       else
! 	{
! 	  lo_half[num] = adjust_address (op, SImode, 0 + lo_adj);
! 	  hi_half[num] = adjust_address (op, SImode, 4 + hi_adj);
! 	}
!     }
! }
  #endif
! 
! static void
! m68k_split (int nr, rtx op, rtx *part)
! {
!   enum machine_mode mode;
! 
!   if (!MEM_P (op))
!     {
!       mode = GET_MODE (op) == VOIDmode ?  DImode : GET_MODE (op);
!       part[0] = simplify_gen_subreg (SImode, op, mode, 0);
!       part[1] = simplify_gen_subreg (SImode, op, mode, 4);
!       if (nr > 2)
! 	part[2] = simplify_gen_subreg (SImode, op, mode, 8);
!     }
!   else if (GET_CODE (XEXP (op, 0)) == PRE_DEC ||
! 	   GET_CODE (XEXP (op, 0)) == POST_INC)
!     {
!       part[0] = part[1] = part[2] = copy_rtx (op);
!       PUT_MODE (part[0], SImode);
!     }
!   else
!     {
!       part[0] = adjust_address (op, SImode, 0);
!       part[1] = adjust_address (op, SImode, 4);
!       if (nr > 2)
! 	part[2] = adjust_address (op, SImode, 8);
!     }
! }
! 
! 
! void
! m68k_split_long_move (int nr, rtx op0, rtx op1)
! {
!   rtx reg, tmp, *p, part0[3], part1[3];
!   int adj = 0, off = 0;
!   enum rtx_code code;
!   struct m68k_address addr;
! 
!   m68k_split (nr, op0, part0);
!   m68k_split (nr, op1, part1);
! 
! #define SWAP(op0, op1) (tmp = op0, op0 = op1, op1 = tmp)
! 
!   if (MEM_P (op0) && GET_RTX_CLASS (GET_CODE (XEXP (op0, 0))) == RTX_AUTOINC)
!     {
!       if (GET_CODE (XEXP (op0, 0)) != GET_CODE (XEXP (op0, 1)))
! 	{
! 	  code = GET_CODE (XEXP (op0, 0));
! 	  reg = XEXP (XEXP (op0, 0), 0);
! 	  p = part1;
! 	  goto adjust_autoinc;
! 	}
!     }
!   else if (MEM_P (op1) && GET_RTX_CLASS (GET_CODE (XEXP (op1, 0))) == RTX_AUTOINC)
!     {
!       code = GET_CODE (XEXP (op1, 0));
!       reg = XEXP (XEXP (op1, 0), 0);
!       p = part0;
! adjust_autoinc:
!       if (code == PRE_DEC)
! 	SWAP (p[0], p[nr - 1]);
!       if (reg_overlap_mentioned_p (reg, p[0]))
! 	{
! 	  if (REG_P (p[0]))
! 	    abort ();
! 	  m68k_decompose_address (XEXP (p[0], 0), &addr);
! 	  if (rtx_equal_p (addr.base, reg))
! 	    adj = 4;
! 	  if (rtx_equal_p (addr.index, reg))
! 	    adj += addr.mult ? 4 * addr.mult : 4;
! 	  if (code == POST_INC)
! 	    adj = -adj;
! 	  p[0] = adjust_address (p[0], SImode, off);
! 	  off += adj;
! 	  p[1] = adjust_address (p[1], SImode, off);
! 	  if (nr > 2)
! 	    p[2] = adjust_address (p[2], SImode, off + adj);
! 	}
!     }
!   else if (REG_P (op0) && REG_P (op1))
!     {
!       if (REGNO (op0) > REGNO (op1))
! 	{
! 	  SWAP (part0[0], part0[nr - 1]);
! 	  SWAP (part1[0], part1[nr - 1]);
! 	}
!     }
!   else if (REG_P (op0) && MEM_P (op1))
!     {
!       int c, collisions;
!       collisions = 0;
! 
!       if (reg_mentioned_p (part0[0], op1))
! 	{
! 	  c = 0;
! 	  collisions++;
! 	}
!       if (reg_mentioned_p (part0[1], op1))
! 	{
! 	  c = 1;
! 	  collisions++;
! 	}
!       if (nr > 2 && reg_mentioned_p (part0[2], op1))
! 	{
! 	  c = 2;
! 	  collisions++;
! 	}
!       switch (collisions)
! 	{
! 	  case 1:
! 	    if (c < nr - 1)
  	      {
! 		SWAP (part0[c], part0[nr - 1]);
! 		SWAP (part1[c], part1[nr - 1]);
  	      }
  	    break;
! 	  case 2:
! 	    m68k_decompose_address (XEXP (op1, 0), &addr);
! 	    emit_move_insn (addr.base, XEXP (op1, 0));
! 	    part1[0] = replace_equiv_address (part1[0], addr.base);
! 	    part1[1] = replace_equiv_address (part1[1],
! 					     plus_constant (addr.base, 4));
! 	    if (nr > 2)
! 	      part1[2] = replace_equiv_address (part1[2], plus_constant (addr.base, 8));
! 	    if (rtx_equal_p (addr.base, part0[0]))
  	      {
! 		SWAP (part0[0], part0[nr - 1]);
! 		SWAP (part1[0], part1[nr - 1]);
  	      }
! 	    else if (nr > 2 && rtx_equal_p (addr.base, part0[1]))
  	      {
! 		SWAP (part0[1], part0[nr - 1]);
! 		SWAP (part1[1], part1[nr - 1]);
  	      }
  	    break;
! 	}
      }
+ 
+ #undef SWAP
+ 
+   emit_move_insn (part0[0], part1[0]);
+   emit_move_insn (part0[1], part1[1]);
+   if (nr > 2)
+     emit_move_insn (part0[2], part1[2]);
+ }
+ 
+ static struct machine_function *
+ m68k_init_machine_status (void)
+ {
+   struct machine_function *f;
+ 
+   f = ggc_alloc_cleared (sizeof (struct machine_function));
+   return f;
+ }
+ 
+ struct stack_local_entry GTY(())
+ {
+   unsigned short mode;
+   unsigned short n;
+   rtx rtl;
+   struct stack_local_entry *next;
+ };
+ 
+ rtx
+ m68k_assign_stack_local (enum machine_mode mode, int n)
+ {
+   struct stack_local_entry *s;
+ 
+   for (s = m68k_stack_locals; s; s = s->next)
+     if (s->mode == mode && s->n == n)
+       return s->rtl;
+ 
+   s = (struct stack_local_entry *)
+     ggc_alloc (sizeof (struct stack_local_entry));
+   s->n = n;
+   s->mode = mode;
+   s->rtl = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+ 
+   s->next = m68k_stack_locals;
+   m68k_stack_locals = s;
+   return s->rtl;
  }
  
  /* Check for cases where a clr insns can be omitted from code using
*************** m68k_struct_value_rtx (tree fntype ATTRI
*** 3399,3401 ****
--- 3498,3840 ----
  {
    return gen_rtx_REG (Pmode, M68K_STRUCT_VALUE_REGNUM);
  }
+ 
+ #define VALID_SUBREG_P(X) (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG)
+ #define FIRST_REGNO(X)	  REGNO (REG_P (X) ? (X) : SUBREG_REG (X))
+ #define DEBUG_ADDR 0
+ 
+ static int
+ m68k_decompose_address(rtx x, struct m68k_address *addr)
+ {
+   memset(addr, 0, sizeof(*addr));
+   if (CONSTANT_ADDRESS_P (x))
+     {
+       addr->disp = x;
+       addr->absolute = 1;
+       return 1;
+     }
+   switch (GET_CODE (x))
+     {
+       case REG:
+ 	addr->base = x;
+ 	return 1;
+       case SUBREG:
+ 	addr->base = x;
+ 	return VALID_SUBREG_P (x);
+       case PRE_DEC:
+ 	addr->pre_dec = 1;
+ 	addr->base = XEXP (x, 0);
+ 	return REG_P (addr->base) || VALID_SUBREG_P (addr->base);
+       case POST_INC:
+ 	addr->post_inc = 1;
+ 	addr->base = XEXP (x, 0);
+ 	return REG_P (addr->base) || VALID_SUBREG_P (addr->base);
+       case UNSPEC:
+ 	if (XINT (x, 1) == UNSPEC_PCREL)
+ 	  {
+ 	    addr->base = pc_pointer_rtx;
+ 	    addr->disp = XVECEXP (x, 0, 0);
+ 	    addr->disp16 = 1;
+ 	    return 1;
+ 	  }
+ 	break;
+       default:
+ 	break;
+     }
+   if (GET_CODE (x) == PLUS)
+     {
+       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
+ 	{
+ 	  addr->disp = XEXP (x, 0);
+ 	  x = XEXP (x, 1);
+ 	}
+       else if (CONSTANT_ADDRESS_P (XEXP (x, 1)))
+ 	{
+ 	  addr->disp = XEXP (x, 1);
+ 	  x = XEXP (x, 0);
+ 	}
+       if (addr->disp && GET_CODE (addr->disp) == LABEL_REF)
+ 	{
+ 	  rtx temp = next_nonnote_insn (XEXP (addr->disp, 0));
+ 	  if ((temp && GET_CODE (temp) == JUMP_INSN
+ 	       && (GET_CODE (PATTERN (temp)) == ADDR_VEC
+ 		   || GET_CODE (PATTERN (temp)) == ADDR_DIFF_VEC))
+ 	      || flag_pic)
+ 	    {
+ 	      addr->tablejump = 1;
+ 	    }
+ 	}
+       if (REG_P (x) || VALID_SUBREG_P (x))
+ 	{
+ 	  addr->base = x;
+ 	  if ((GET_CODE (addr->disp) == CONST_INT
+ 	       && (unsigned) INTVAL (addr->disp) + 0x8000 < 0x10000)
+ 	      || addr->base == pc_pointer_rtx)
+ 	    addr->disp16 = 1;
+ 	  return 1;
+ 	}
+     }
+   if (GET_CODE (x) == PLUS)
+     {
+       if (XEXP (x, 0) == pc_pointer_rtx)
+ 	{
+ 	  addr->base = XEXP (x, 0);
+ 	  x = XEXP (x, 1);
+ 	}
+       else if (XEXP (x, 1) == pc_pointer_rtx)
+ 	{
+ 	  addr->base = XEXP (x, 1);
+ 	  x = XEXP (x, 0);
+ 	}
+       else if ((REG_P (XEXP (x, 0)) || VALID_SUBREG_P (XEXP (x, 0)))
+ 	       && (REG_P (XEXP (x, 1)) || VALID_SUBREG_P (XEXP (x, 1))))
+ 	{
+ 	  if (ADDR_REGNO_P (FIRST_REGNO (XEXP (x, 0))))
+ 	    {
+ 	      addr->base = XEXP (x, 0);
+ 	      addr->index = XEXP (x, 1);
+ 	    }
+ 	  else
+ 	    {
+ 	      addr->base = XEXP (x, 1);
+ 	      addr->index = XEXP (x, 0);
+ 	    }
+ 	  return 1;
+ 	}
+       else if ((REG_P (XEXP (x, 0)) || VALID_SUBREG_P (XEXP (x, 0))))
+ 	{
+ 	  addr->base = XEXP (x, 0);
+ 	  x = XEXP (x, 1);
+ 	}
+       else if ((REG_P (XEXP (x, 1)) || VALID_SUBREG_P (XEXP (x, 1))))
+ 	{
+ 	  addr->base = XEXP (x, 1);
+ 	  x = XEXP (x, 0);
+ 	}
+     }
+   if (GET_CODE (x) == SIGN_EXTRACT && GET_CODE (XEXP (x, 0)) == MULT
+       && GET_CODE (XEXP (x, 1)) == CONST_INT && GET_CODE (XEXP (x, 2)) == CONST_INT
+       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+     {
+       switch (INTVAL (XEXP (XEXP (x, 0), 1)))
+ 	{
+ 	  case 2:
+ 	    if (INTVAL (XEXP (x, 1)) == 17 && INTVAL (XEXP (x, 2)) == 15)
+ 	      {
+ 		addr->mult = 2;
+ 		addr->index16 = 1;
+ 		x = XEXP (XEXP (x, 0), 0);
+ 	      }
+ 	    break;
+ 	  case 4:
+ 	    if (INTVAL (XEXP (x, 1)) == 18 && INTVAL (XEXP (x, 2)) == 14)
+ 	      {
+ 		addr->mult = 4;
+ 		addr->index16 = 1;
+ 		x = XEXP (XEXP (x, 0), 0);
+ 	      }
+ 	    break;
+ 	  case 8:
+ 	    if (INTVAL (XEXP (x, 1)) == 19 && INTVAL (XEXP (x, 2)) == 13)
+ 	      {
+ 		addr->mult = 8;
+ 		addr->index16 = 1;
+ 		x = XEXP (XEXP (x, 0), 0);
+ 	      }
+ 	    break;
+ 	}
+     }
+   else if (GET_CODE (x) == MULT && GET_CODE (XEXP (x, 1)) == CONST_INT)
+     {
+       switch (INTVAL (XEXP (x, 1)))
+ 	{
+ 	  case 2: case 4: case 8:
+ 	    addr->mult = INTVAL (XEXP (x, 1));
+ 	    x = XEXP (x, 0);
+ 	    break;
+ 	}
+     }
+ #if 0
+   else if (GET_CODE (x) == ASHIFT && GET_CODE (XEXP (x, 1)) == CONST_INT)
+     {
+       switch (INTVAL (XEXP (x, 1)))
+ 	{
+ 	  case 1: case 2: case 3:
+ 	    addr->mult = 1 << INTVAL (XEXP (x, 1));
+ 	    x = XEXP (x, 0);
+ 	    break;
+ 	}
+     }
+ #endif
+   else if (GET_CODE (x) == SIGN_EXTEND && GET_MODE (XEXP (x, 0)) == HImode)
+     {
+       addr->index16 = 1;
+       x = XEXP (x, 0);
+     }
+   if (!REG_P (x) && !VALID_SUBREG_P (x))
+     return 0;
+ 
+   addr->index = x;
+   if (!addr->disp || (GET_CODE (addr->disp) == CONST_INT
+ 		      && (unsigned) INTVAL (addr->disp) + 0x80 < 0x100)
+       || (addr->base == pc_pointer_rtx && addr->tablejump))
+     addr->disp8 = 1;
+ 
+   return 1;
+ }
+ 
+ int
+ m68k_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
+ {
+   struct m68k_address addr;
+   const char *reason;
+   int regno;
+ 
+   if (DEBUG_ADDR)
+     {
+       fprintf (stderr, "legitimate_address_p: %s, %d\n", GET_MODE_NAME (mode), strict);
+       debug_rtx (x);
+     }
+   if (!m68k_decompose_address(x, &addr))
+     {
+       reason = "decomposition failed";
+       goto fail;
+     }
+ 
+   if (flag_pic && addr.disp)
+     {
+       if (addr.base != pic_offset_table_rtx
+ 	  && addr.base != pc_pointer_rtx 
+ 	  && !LEGITIMATE_PIC_OPERAND_P (addr.disp))
+ 	{
+ 	  reason = "invalid pic disp";
+ 	  goto fail;
+ 	}
+     }
+   if (!addr.base && !addr.index)
+     goto ok;
+   if (!addr.base && !TARGET_68020)
+     {
+       reason = "missing base reg";
+       goto fail;
+     }
+   if (strict)
+     {
+       if (addr.base)
+ 	{
+ 	  if (!REG_P (addr.base) || !REGNO_OK_FOR_BASE_P (REGNO (addr.base)))
+ 	    {
+ 	      reason = "invalid base reg";
+ 	      goto fail;
+ 	    }
+ 	}
+       if (addr.index)
+ 	{
+ 	  regno = REGNO (REG_P (addr.index) ? addr.index
+ 					    : SUBREG_REG (addr.index));
+ 	  if (!REGNO_OK_FOR_INDEX_P (regno))
+ 	    {
+ 	      reason = "invalid index reg";
+ 	      goto fail;
+ 	    }
+ 	}
+     }
+   else
+     {
+       if (addr.base)
+ 	{
+ 	  regno = REGNO (REG_P (addr.base) ? addr.base
+ 					   : SUBREG_REG (addr.base));
+ 	  if (FP_REGNO_P (regno))
+ 	    {
+ 	      reason = "invalid base reg";
+ 	      goto fail;
+ 	    }
+ 	}
+       if (addr.index)
+ 	{
+ 	  regno = REGNO (REG_P (addr.index) ? addr.index
+ 					    : SUBREG_REG (addr.index));
+ 	  if (FP_REGNO_P (regno) || PC_REGNO_P (regno))
+ 	    {
+ 	      reason = "invalid index reg";
+ 	      goto fail;
+ 	    }
+ 	}
+     }
+   if (addr.index)
+     {
+       if (addr.index16 && TARGET_COLDFIRE)
+ 	{
+ 	  reason = "no short index on coldfire";
+ 	  goto fail;
+ 	}
+       if ((addr.mult && !TARGET_68020 && !TARGET_COLDFIRE)
+ 	  || (addr.mult == 8 && TARGET_COLDFIRE))
+ 	{
+ 	  reason = "invalid index multiplier";
+ 	  goto fail;
+ 	}
+     }
+   if (addr.disp)
+     {
+       if (TARGET_68020)
+ 	goto ok;
+       if (addr.base == pc_pointer_rtx && (addr.tablejump
+ 					  || (symbolic_operand(addr.disp, mode)
+ 					      && !addr.index)))
+ 	goto ok;
+       if (GET_CODE (addr.disp) == CONST_INT)
+ 	{
+ 	  unsigned int val = INTVAL (addr.disp);
+ 
+ 	  if (addr.index ? (val + 0x80 < 0x100) : (val + 0x8000 < 0x10000))
+ 	    goto ok;
+ 	}
+       reason = "invalid disp";
+       goto fail;
+     }
+ ok:
+   if (DEBUG_ADDR)
+     fprintf (stderr, "ok\n");
+   return 1;
+ fail:
+   if (DEBUG_ADDR)
+     fprintf (stderr, "failed (%s)\n", reason);
+   return 0;
+ }
+ 
+ rtx m68k_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
+ {
+   if (DEBUG_ADDR)
+     {
+       fprintf (stderr, "legitimize_address: %s\n", GET_MODE_NAME (mode));
+       debug_rtx (x);
+     }
+   if (GET_CODE (x) != PLUS)
+     return NULL_RTX;
+   if (GET_CODE (XEXP (x, 0)) == MULT)
+     {
+       x = gen_rtx_PLUS (Pmode, XEXP (x, 1), force_reg (Pmode, XEXP (x, 0)));
+     }
+   if (GET_CODE (XEXP (x, 1)) == MULT)
+     {
+       x = gen_rtx_PLUS (Pmode, XEXP (x, 0), force_reg (Pmode, XEXP (x, 1)));
+     }
+   if (x != oldx)
+     {
+       if (m68k_legitimate_address_p (mode, x, 0))
+ 	return x;
+     }
+   if (GET_CODE (XEXP (x, 0)) == REG)
+     {
+       return gen_rtx_PLUS (Pmode, XEXP (x, 0), force_reg (Pmode, XEXP (x, 1)));
+     }
+   else if (GET_CODE (XEXP (x, 1)) == REG)
+     {
+       return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)), XEXP (x, 1));
+     }
+   return NULL_RTX;
+ }
+ 
+ #include "gt-m68k.h"
diff -crp config/m68k/m68k.h config/m68k/m68k.h
*** config/m68k/m68k.h	2004-08-08 18:04:58.000000000 +0200
--- config/m68k/m68k.h	2004-08-07 17:22:27.000000000 +0200
*************** extern int target_flags;
*** 398,404 ****
     and the 68881 floating point registers numbers 020-027 (16-24).
     We also have a fake `arg-pointer' register 030 (25) used for
     register elimination.  */
! #define FIRST_PSEUDO_REGISTER 25
  
  /* All m68k targets (except AmigaOS) use %a5 as the PIC register  */
  #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 13 : INVALID_REGNUM)
--- 398,404 ----
     and the 68881 floating point registers numbers 020-027 (16-24).
     We also have a fake `arg-pointer' register 030 (25) used for
     register elimination.  */
! #define FIRST_PSEUDO_REGISTER 26
  
  /* All m68k targets (except AmigaOS) use %a5 as the PIC register  */
  #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 13 : INVALID_REGNUM)
*************** extern int target_flags;
*** 418,425 ****
       (if available).  */       \
    0, 0, 0, 0, 0, 0, 0, 0,      \
                                 \
!   /* Arg pointer.  */          \
!   1 }
  
  /* 1 for registers not available across function calls.
     These must include the FIXED_REGISTERS and also any
--- 418,425 ----
       (if available).  */       \
    0, 0, 0, 0, 0, 0, 0, 0,      \
                                 \
!   /* Arg pointer, PC.  */      \
!   1, 1 }
  
  /* 1 for registers not available across function calls.
     These must include the FIXED_REGISTERS and also any
*************** extern int target_flags;
*** 438,455 ****
       (if available).  */        \
    1, 1, 0, 0, 0, 0, 0, 0,       \
                                  \
!   /* Arg pointer.  */           \
!   1 }
  
  #define REG_ALLOC_ORDER		\
  { /* d0/d1/a0/a1 */		\
    0, 1, 8, 9,			\
    /* d2-d7 */			\
    2, 3, 4, 5, 6, 7,		\
!   /* a2-a7/arg */		\
!   10, 11, 12, 13, 14, 15, 24,	\
    /* fp0-fp7 */			\
!   16, 17, 18, 19, 20, 21, 22, 23\
  }
  
  
--- 438,458 ----
       (if available).  */        \
    1, 1, 0, 0, 0, 0, 0, 0,       \
                                  \
!   /* Arg pointer, PC.  */       \
!   1, 1 }
  
  #define REG_ALLOC_ORDER		\
  { /* d0/d1/a0/a1 */		\
    0, 1, 8, 9,			\
    /* d2-d7 */			\
    2, 3, 4, 5, 6, 7,		\
!   /* a2-a7 */			\
!   10, 11, 12, 13, 14, 15,	\
    /* fp0-fp7 */			\
!   16, 17, 18, 19,		\
!   20, 21, 22, 23,		\
!   /* arg/pc */			\
!   24, 25			\
  }
  
  
*************** extern int target_flags;
*** 527,544 ****
     a complete set.  One of them is not needed.  */
  enum reg_class {
    NO_REGS, DATA_REGS,
!   ADDR_REGS, FP_REGS,
    GENERAL_REGS, DATA_OR_FP_REGS,
!   ADDR_OR_FP_REGS, ALL_REGS,
    LIM_REG_CLASSES };
  
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
  #define REG_CLASS_NAMES \
   { "NO_REGS", "DATA_REGS",              \
!    "ADDR_REGS", "FP_REGS",              \
     "GENERAL_REGS", "DATA_OR_FP_REGS",   \
!    "ADDR_OR_FP_REGS", "ALL_REGS" }
  
  #define REG_CLASS_CONTENTS \
  {					\
--- 530,547 ----
     a complete set.  One of them is not needed.  */
  enum reg_class {
    NO_REGS, DATA_REGS,
!   ADDR_REGS, FP_REGS, PC_REGS,
    GENERAL_REGS, DATA_OR_FP_REGS,
!   ADDR_OR_PC_REGS, ALL_REGS,
    LIM_REG_CLASSES };
  
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
  #define REG_CLASS_NAMES \
   { "NO_REGS", "DATA_REGS",              \
!    "ADDR_REGS", "FP_REGS", "PC_REGS",   \
     "GENERAL_REGS", "DATA_OR_FP_REGS",   \
!    "ADDR_OR_PC_REGS", "ALL_REGS" }
  
  #define REG_CLASS_CONTENTS \
  {					\
*************** enum reg_class {
*** 546,561 ****
    {0x000000ff},  /* DATA_REGS */	\
    {0x0100ff00},  /* ADDR_REGS */	\
    {0x00ff0000},  /* FP_REGS */		\
    {0x0100ffff},  /* GENERAL_REGS */	\
    {0x00ff00ff},  /* DATA_OR_FP_REGS */	\
!   {0x01ffff00},  /* ADDR_OR_FP_REGS */	\
!   {0x01ffffff},  /* ALL_REGS */		\
  }
  
  extern enum reg_class regno_reg_class[];
  #define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)])
  #define INDEX_REG_CLASS GENERAL_REGS
! #define BASE_REG_CLASS ADDR_REGS
  
  /* We do a trick here to modify the effective constraints on the
     machine description; we zorch the constraint letters that aren't
--- 549,565 ----
    {0x000000ff},  /* DATA_REGS */	\
    {0x0100ff00},  /* ADDR_REGS */	\
    {0x00ff0000},  /* FP_REGS */		\
+   {0x02000000},  /* PC_REGS */		\
    {0x0100ffff},  /* GENERAL_REGS */	\
    {0x00ff00ff},  /* DATA_OR_FP_REGS */	\
!   {0x0300ff00},  /* ADDR_OR_PC_REGS */	\
!   {0x03ffffff},  /* ALL_REGS */		\
  }
  
  extern enum reg_class regno_reg_class[];
  #define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)])
  #define INDEX_REG_CLASS GENERAL_REGS
! #define BASE_REG_CLASS ADDR_OR_PC_REGS
  
  /* We do a trick here to modify the effective constraints on the
     machine description; we zorch the constraint letters that aren't
*************** extern enum reg_class regno_reg_class[];
*** 644,649 ****
--- 648,659 ----
     ? ADDR_REGS					\
     : (CLASS))
  
+ 
+ #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+   (reg_class_subset_p (CLASS1, FP_REGS) != reg_class_subset_p (CLASS2, FP_REGS) && \
+    GET_MODE_SIZE (MODE) > 4)
+ 
+ 
  /* Force QImode output reloads from subregs to be allocated to data regs,
     since QImode stores from address regs are not supported.  We make the
     assumption that if the class is not ADDR_REGS, then it must be a superset
*************** __transfer_from_trampoline ()					\
*** 827,840 ****
  
  /* Macros to check register numbers against specific register classes.  */
  
! #define REGNO_OK_FOR_INDEX_P(REGNO) \
! ((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16)
! #define REGNO_OK_FOR_BASE_P(REGNO) \
! (((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8)
! #define REGNO_OK_FOR_DATA_P(REGNO) \
! ((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8)
! #define REGNO_OK_FOR_FP_P(REGNO) \
! (((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8)
  
  /* Now macros that check whether X is a register and also,
     strictly, whether it is in a specified class.
--- 842,863 ----
  
  /* Macros to check register numbers against specific register classes.  */
  
! #define DATA_REGNO_P(X)		((unsigned)(X) < 8)
! #define ADDR_REGNO_P(X)		((unsigned)((X) ^ 010) < 8)
! #define ADDR_OR_DATA_REGNO_P(X)	((unsigned)(X) < 16)
! #define FP_REGNO_P(X)		((unsigned)((X) ^ 020) < 8)
! #define FP_OR_DATA_REGNO_P(X)	(((X) & ~027) == 0)
! #define ARG_REGNO_P(X)		((X) == 24)
! #define PC_REGNO_P(X)		((X) == 25)
! 
! #define REGNO_OK_FOR_INDEX_P(REGNO)		\
!   (ADDR_OR_DATA_REGNO_P (REGNO)			\
!    || ADDR_OR_DATA_REGNO_P (reg_renumber[(REGNO)]))
! #define REGNO_OK_FOR_BASE_P(REGNO)		\
!   (ADDR_REGNO_P (REGNO)				\
!    || ADDR_REGNO_P (reg_renumber[(REGNO)])	\
!    || ARG_REGNO_P (REGNO)			\
!    || PC_REGNO_P (REGNO))
  
  /* Now macros that check whether X is a register and also,
     strictly, whether it is in a specified class.
*************** __transfer_from_trampoline ()					\
*** 844,856 ****
     define_optimization.  */
  
  /* 1 if X is a data register.  */
! #define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X)))
  
  /* 1 if X is an fp register.  */
! #define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
  
  /* 1 if X is an address register  */
! #define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
  
  
  #define MAX_REGS_PER_ADDRESS 2
--- 867,879 ----
     define_optimization.  */
  
  /* 1 if X is a data register.  */
! #define DATA_REG_P(X)	(REG_P (X) && DATA_REGNO_P (REGNO (X)))
  
  /* 1 if X is an fp register.  */
! #define FP_REG_P(X)	(REG_P (X) && FP_REGNO_P (REGNO (X)))
  
  /* 1 if X is an address register  */
! #define ADDRESS_REG_P(X) (REG_P (X) && ADDR_REGNO_P (REGNO (X)))
  
  
  #define MAX_REGS_PER_ADDRESS 2
*************** __transfer_from_trampoline ()					\
*** 879,888 ****
  
  /* Nonzero if X is a hard reg that can be used as an index
     or if it is a pseudo reg.  */
! #define REG_OK_FOR_INDEX_P(X) ((REGNO (X) ^ 020) >= 8)
  /* Nonzero if X is a hard reg that can be used as a base reg
     or if it is a pseudo reg.  */
! #define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~027) != 0)
  
  #else
  
--- 902,917 ----
  
  /* Nonzero if X is a hard reg that can be used as an index
     or if it is a pseudo reg.  */
! #define REG_OK_FOR_INDEX_P(X)	(!FP_REGNO_P (REGNO (X)) && !PC_REGNO_P (REGNO (X)))
  /* Nonzero if X is a hard reg that can be used as a base reg
     or if it is a pseudo reg.  */
! #define REG_OK_FOR_BASE_P(X)	(!FP_OR_DATA_REGNO_P (REGNO (X)))
! 
! #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)		\
! do {							\
!   if (m68k_legitimate_address_p((MODE), (X), 0))	\
!     goto ADDR;						\
! } while (0)
  
  #else
  
*************** __transfer_from_trampoline ()					\
*** 891,896 ****
--- 920,931 ----
  /* Nonzero if X is a hard reg that can be used as a base reg.  */
  #define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
  
+ #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)		\
+ do {							\
+   if (m68k_legitimate_address_p((MODE), (X), 1))	\
+     goto ADDR;						\
+ } while (0)
+ 
  #endif
  
  /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
*************** __transfer_from_trampoline ()					\
*** 907,1008 ****
  
     The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS.  */
  
- /* Allow SUBREG everywhere we allow REG.  This results in better code.  It
-    also makes function inlining work when inline functions are called with
-    arguments that are SUBREGs.  */
- 
- #define LEGITIMATE_BASE_REG_P(X)   \
-   ((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))	\
-    || (GET_CODE (X) == SUBREG				\
-        && GET_CODE (SUBREG_REG (X)) == REG		\
-        && REG_OK_FOR_BASE_P (SUBREG_REG (X))))
- 
- #define INDIRECTABLE_1_ADDRESS_P(X)  \
-   ((CONSTANT_ADDRESS_P (X) && (!flag_pic || LEGITIMATE_PIC_OPERAND_P (X))) \
-    || LEGITIMATE_BASE_REG_P (X)						\
-    || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC)		\
-        && LEGITIMATE_BASE_REG_P (XEXP (X, 0)))				\
-    || (GET_CODE (X) == PLUS						\
-        && LEGITIMATE_BASE_REG_P (XEXP (X, 0))				\
-        && GET_CODE (XEXP (X, 1)) == CONST_INT				\
-        && (TARGET_68020							\
- 	   || ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000))	\
-    || (GET_CODE (X) == PLUS && XEXP (X, 0) == pic_offset_table_rtx 	\
-        && flag_pic && GET_CODE (XEXP (X, 1)) == SYMBOL_REF)		\
-    || (GET_CODE (X) == PLUS && XEXP (X, 0) == pic_offset_table_rtx 	\
-        && flag_pic && GET_CODE (XEXP (X, 1)) == LABEL_REF))
- 
- #define GO_IF_NONINDEXED_ADDRESS(X, ADDR)  \
- { if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; }
- 
- /* Only labels on dispatch tables are valid for indexing from.  */
- #define GO_IF_INDEXABLE_BASE(X, ADDR)				\
- { rtx temp;							\
-   if (GET_CODE (X) == LABEL_REF					\
-       && (temp = next_nonnote_insn (XEXP (X, 0))) != 0		\
-       && GET_CODE (temp) == JUMP_INSN				\
-       && (GET_CODE (PATTERN (temp)) == ADDR_VEC			\
- 	  || GET_CODE (PATTERN (temp)) == ADDR_DIFF_VEC))	\
-     goto ADDR;							\
-   if (LEGITIMATE_BASE_REG_P (X)) goto ADDR; }
- 
- #define GO_IF_INDEXING(X, ADDR)	\
- { if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0)))		\
-     { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); }			\
-   if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1)))		\
-     { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } }
- 
- #define GO_IF_INDEXED_ADDRESS(X, ADDR)	 \
- { GO_IF_INDEXING (X, ADDR);						\
-   if (GET_CODE (X) == PLUS)						\
-     { if (GET_CODE (XEXP (X, 1)) == CONST_INT				\
- 	  && (TARGET_68020 || (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100))		\
- 	{ rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); }	\
-       if (GET_CODE (XEXP (X, 0)) == CONST_INT				\
- 	  && (TARGET_68020 || (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100))		\
- 	{ rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } }
- 
- /* ColdFire/5200 does not allow HImode index registers.  */
- #define LEGITIMATE_INDEX_REG_P(X)   \
-   ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X))	\
-    || (! TARGET_COLDFIRE					\
-        && GET_CODE (X) == SIGN_EXTEND			\
-        && GET_CODE (XEXP (X, 0)) == REG			\
-        && GET_MODE (XEXP (X, 0)) == HImode		\
-        && REG_OK_FOR_INDEX_P (XEXP (X, 0)))		\
-    || (GET_CODE (X) == SUBREG				\
-        && GET_CODE (SUBREG_REG (X)) == REG		\
-        && REG_OK_FOR_INDEX_P (SUBREG_REG (X))))
- 
- #define LEGITIMATE_INDEX_P(X)   \
-    (LEGITIMATE_INDEX_REG_P (X)				\
-     || ((TARGET_68020 || TARGET_COLDFIRE) && GET_CODE (X) == MULT \
- 	&& LEGITIMATE_INDEX_REG_P (XEXP (X, 0))		\
- 	&& GET_CODE (XEXP (X, 1)) == CONST_INT		\
- 	&& (INTVAL (XEXP (X, 1)) == 2			\
- 	    || INTVAL (XEXP (X, 1)) == 4		\
- 	    || (INTVAL (XEXP (X, 1)) == 8 && !TARGET_COLDFIRE))))
- 
- /* If pic, we accept INDEX+LABEL, which is what do_tablejump makes.  */
- #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)				\
- { GO_IF_NONINDEXED_ADDRESS (X, ADDR);					\
-   GO_IF_INDEXED_ADDRESS (X, ADDR);					\
-   if (flag_pic && MODE == CASE_VECTOR_MODE && GET_CODE (X) == PLUS	\
-       && LEGITIMATE_INDEX_P (XEXP (X, 0))				\
-       && GET_CODE (XEXP (X, 1)) == LABEL_REF)				\
-     goto ADDR; }
- 
  /* Don't call memory_address_noforce for the address to fetch
     the switch offset.  This address is ok as it stands (see above),
     but memory_address_noforce would alter it.  */
! #define PIC_CASE_VECTOR_ADDRESS(index) index
  
  /* For the 68000, we handle X+REG by loading X into a register R and
     using R+REG.  R will go in an address reg and indexing will be used.
     However, if REG is a broken-out memory address or multiplication,
     nothing needs to be done because REG can certainly go in an address reg.  */
  #define COPY_ONCE(Y) if (!copied) { Y = copy_rtx (Y); copied = ch = 1; }
! #define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)   \
  { register int ch = (X) != (OLDX);					\
    if (GET_CODE (X) == PLUS)						\
      { int copied = 0;							\
--- 942,976 ----
  
     The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS.  */
  
  /* Don't call memory_address_noforce for the address to fetch
     the switch offset.  This address is ok as it stands (see above),
     but memory_address_noforce would alter it.  */
! #define PIC_CASE_VECTOR_ADDRESS(X)					\
! do									\
!   {									\
!     rtx tmp_ = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP ((X), 1)),	\
! 			       UNSPEC_PCREL);				\
!     (X) = gen_rtx_PLUS (Pmode, force_reg (Pmode, tmp_), XEXP ((X), 0));	\
!   }									\
! while (0)
  
  /* For the 68000, we handle X+REG by loading X into a register R and
     using R+REG.  R will go in an address reg and indexing will be used.
     However, if REG is a broken-out memory address or multiplication,
     nothing needs to be done because REG can certainly go in an address reg.  */
+ #define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)			\
+ do								\
+   {								\
+     rtx new_ = m68k_legitimize_address ((X), (OLDX), (MODE));	\
+     if (new_)							\
+       {								\
+ 	(X) = new_;						\
+ 	goto WIN;						\
+       }								\
+   }								\
+ while (0)
  #define COPY_ONCE(Y) if (!copied) { Y = copy_rtx (Y); copied = ch = 1; }
! #define __LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)   \
  { register int ch = (X) != (OLDX);					\
    if (GET_CODE (X) == PLUS)						\
      { int copied = 0;							\
*************** do { if (cc_prev_status.flags & CC_IN_68
*** 1098,1104 ****
   REGISTER_PREFIX"a6", REGISTER_PREFIX"sp",			\
   REGISTER_PREFIX"fp0", REGISTER_PREFIX"fp1", REGISTER_PREFIX"fp2", \
   REGISTER_PREFIX"fp3", REGISTER_PREFIX"fp4", REGISTER_PREFIX"fp5", \
!  REGISTER_PREFIX"fp6", REGISTER_PREFIX"fp7", REGISTER_PREFIX"argptr" }
  
  #define M68K_FP_REG_NAME REGISTER_PREFIX"fp"
  
--- 1066,1073 ----
   REGISTER_PREFIX"a6", REGISTER_PREFIX"sp",			\
   REGISTER_PREFIX"fp0", REGISTER_PREFIX"fp1", REGISTER_PREFIX"fp2", \
   REGISTER_PREFIX"fp3", REGISTER_PREFIX"fp4", REGISTER_PREFIX"fp5", \
!  REGISTER_PREFIX"fp6", REGISTER_PREFIX"fp7",			   \
!  REGISTER_PREFIX"argptr", REGISTER_PREFIX"pc" }
  
  #define M68K_FP_REG_NAME REGISTER_PREFIX"fp"
  
*************** do { if (cc_prev_status.flags & CC_IN_68
*** 1247,1256 ****
--- 1216,1233 ----
  #define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
  
  #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+ 
+ struct machine_function GTY(())
+ {
+   struct stack_local_entry *stack_locals;
+ };
+ 
+ #define m68k_stack_locals (cfun->machine->stack_locals)
  
  /* Variables in m68k.c */
  extern const char *m68k_library_id_string;
  extern int m68k_last_compare_had_fp_operands;
+ extern GTY(()) rtx pc_pointer_rtx;
  
  
  /* Define the codes that are matched by predicates in m68k.c.  */
diff -crp config/m68k/m68k.md config/m68k/m68k.md
*** config/m68k/m68k.md	2004-08-08 18:51:51.000000000 +0200
--- config/m68k/m68k.md	2004-08-09 11:52:49.000000000 +0200
***************
*** 118,123 ****
--- 118,124 ----
     (UNSPEC_MOVEM	3)
     (UNSPEC_FMOVEM	4)
     (UNSPEC_EH_RETURN	5)
+    (UNSPEC_PCREL	6)
    ])
  
  ;; UNSPEC_VOLATILE usage:
***************
*** 644,650 ****
  	(match_operand:SI 1 "general_operand" ""))]
    ""
  {
!   if (flag_pic && !TARGET_PCREL && symbolic_operand (operands[1], SImode))
      {
        /* The source is an address which requires PIC relocation.
           Call legitimize_pic_address with the source, mode, and a relocation
--- 635,645 ----
  	(match_operand:SI 1 "general_operand" ""))]
    ""
  {
!   if (GET_CODE (operands[1]) == UNSPEC && XINT (operands[1], 1) == UNSPEC_PCREL)
!     {
!       operands [1] = gen_rtx_PLUS (Pmode, XVECEXP (operands[1], 0, 0), pc_pointer_rtx);
!     }
!   else if (flag_pic && !TARGET_PCREL && symbolic_operand (operands[1], SImode))
      {
        /* The source is an address which requires PIC relocation.
           Call legitimize_pic_address with the source, mode, and a relocation
***************
*** 666,675 ****
      }
  })
  
  ;; General case of fullword move.  The register constraints
  ;; force integer constants in range for a moveq to be reloaded
  ;; if they are headed for memory.
! (define_insn ""
    ;; Notes: make sure no alternative allows g vs g.
    ;; We don't allow f-regs since fixed point cannot go in them.
    [(set (match_operand:SI 0 "nonimmediate_operand" "=g,d,a<")
--- 661,676 ----
      }
  })
  
+ (define_insn "*movsi_split"
+   [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ 	(match_operand:SI 1 "const_int_operand" "i"))]
+   "reload_completed"
+   "* return output_move_simode (operands);")
+ 
  ;; General case of fullword move.  The register constraints
  ;; force integer constants in range for a moveq to be reloaded
  ;; if they are headed for memory.
! (define_insn "*movsi"
    ;; Notes: make sure no alternative allows g vs g.
    ;; We don't allow f-regs since fixed point cannot go in them.
    [(set (match_operand:SI 0 "nonimmediate_operand" "=g,d,a<")
***************
*** 848,897 ****
    ""
    "")
  
! (define_insn ""
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=rm,rf,rf,&rof<>")
! 	(match_operand:DF 1 "general_operand" "*rf,m,0,*rofE<>"))]
! ;  [(set (match_operand:DF 0 "nonimmediate_operand" "=rm,&rf,&rof<>")
! ;	(match_operand:DF 1 "general_operand" "rf,m,rofF<>"))]
!   "!TARGET_COLDFIRE"
! {
!   if (FP_REG_P (operands[0]))
!     {
!       if (FP_REG_P (operands[1]))
! 	return "f%&move%.x %1,%0";
!       if (REG_P (operands[1]))
! 	{
! 	  rtx xoperands[2];
! 	  xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
! 	  output_asm_insn ("move%.l %1,%-", xoperands);
! 	  output_asm_insn ("move%.l %1,%-", operands);
! 	  return "f%&move%.d %+,%0";
! 	}
!       if (GET_CODE (operands[1]) == CONST_DOUBLE)
! 	return output_move_const_double (operands);
!       return "f%&move%.d %f1,%0";
!     }
!   else if (FP_REG_P (operands[1]))
!     {
!       if (REG_P (operands[0]))
! 	{
! 	  output_asm_insn ("fmove%.d %f1,%-\;move%.l %+,%0", operands);
! 	  operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
! 	  return "move%.l %+,%0";
! 	}
!       else
!         return "fmove%.d %f1,%0";
!     }
!   return output_move_double (operands);
! })
! 
! (define_insn ""
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,g")
! 	(match_operand:DF 1 "general_operand" "g,r"))]
    "TARGET_COLDFIRE"
  {
!   return output_move_double (operands);
  })
  
  ;; ??? The XFmode patterns are schizophrenic about whether constants are
  ;; allowed.  Most but not all have predicates and constraint that disallow
--- 849,883 ----
    ""
    "")
  
! (define_insn "*movdf"
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,ro<,ro>")
! 	(match_operand:DF 1 "general_operand" "f,mF,f,rFo<,rFo>"))]
!   "!TARGET_COLDFIRE"
!   "@
!    f%&move%.x %1,%0
!    fmove%.d %f1,%0
!    fmove%.d %1,%0
!    #
!    #")
! 
! (define_insn "*movdf_cf"
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=&rQ<,&rQ>,&rFo<,&rFo>")
! 	(match_operand:DF 1 "general_src_operand" "rFo<,rFo>,rQU<,rQU>"))]
    "TARGET_COLDFIRE"
+   "#")
+ 
+ (define_split
+   [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ 	(match_operand:DF 1 "general_src_operand" ""))]
+   "reload_completed && !FP_REG_P (operands[0]) && !FP_REG_P (operands[1])"
+   [(const_int 1)]
  {
!   m68k_split_long_move(2, operands[0], operands[1]);
!   DONE;
  })
+ ;;  [(set (match_dup 2) (match_dup 3))
+ ;;   (set (match_dup 4) (match_dup 5))]
+ ;;  "split_di(operands, 2, operands + 2, operands + 4);")
  
  ;; ??? The XFmode patterns are schizophrenic about whether constants are
  ;; allowed.  Most but not all have predicates and constraint that disallow
***************
*** 924,1013 ****
      }
  })
  
! (define_insn ""
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,!r,!f,!r")
! 	(match_operand:XF 1 "nonimmediate_operand" "m,f,f,f,r,!r"))]
!   "TARGET_68881"
! {
!   if (FP_REG_P (operands[0]))
!     {
!       if (FP_REG_P (operands[1]))
! 	return "fmove%.x %1,%0";
!       if (REG_P (operands[1]))
! 	{
! 	  rtx xoperands[2];
! 	  xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
! 	  output_asm_insn ("move%.l %1,%-", xoperands);
! 	  xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
! 	  output_asm_insn ("move%.l %1,%-", xoperands);
! 	  output_asm_insn ("move%.l %1,%-", operands);
! 	  return "fmove%.x %+,%0";
! 	}
!       if (GET_CODE (operands[1]) == CONST_DOUBLE)
!         return "fmove%.x %1,%0";
!       return "fmove%.x %f1,%0";
!     }
!   if (FP_REG_P (operands[1]))
!     {
!       if (REG_P (operands[0]))
! 	{
! 	  output_asm_insn ("fmove%.x %f1,%-\;move%.l %+,%0", operands);
! 	  operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
! 	  output_asm_insn ("move%.l %+,%0", operands);
! 	  operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
! 	  return "move%.l %+,%0";
! 	}
!       /* Must be memory destination.  */
!       return "fmove%.x %f1,%0";
!     }
!   return output_move_double (operands);
! })
  
! (define_insn ""
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=rm,rf,&rof<>")
! 	(match_operand:XF 1 "nonimmediate_operand" "rf,m,rof<>"))]
!   "! TARGET_68881 && ! TARGET_COLDFIRE"
  {
!   if (FP_REG_P (operands[0]))
!     {
!       if (FP_REG_P (operands[1]))
! 	return "fmove%.x %1,%0";
!       if (REG_P (operands[1]))
! 	{
! 	  rtx xoperands[2];
! 	  xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
! 	  output_asm_insn ("move%.l %1,%-", xoperands);
! 	  xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
! 	  output_asm_insn ("move%.l %1,%-", xoperands);
! 	  output_asm_insn ("move%.l %1,%-", operands);
! 	  return "fmove%.x %+,%0";
! 	}
!       if (GET_CODE (operands[1]) == CONST_DOUBLE)
!         return "fmove%.x %1,%0";
!       return "fmove%.x %f1,%0";
!     }
!   if (FP_REG_P (operands[1]))
!     {
!       if (REG_P (operands[0]))
!         {
!           output_asm_insn ("fmove%.x %f1,%-\;move%.l %+,%0", operands);
!           operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
!           output_asm_insn ("move%.l %+,%0", operands);
!           operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
!           return "move%.l %+,%0";
!         }
!       else
!         return "fmove%.x %f1,%0";
!     }
!   return output_move_double (operands);
  })
  
- (define_insn ""
-   [(set (match_operand:XF 0 "nonimmediate_operand" "=r,g")
- 	(match_operand:XF 1 "nonimmediate_operand" "g,r"))]
-   "! TARGET_68881 && TARGET_COLDFIRE"
-   "* return output_move_double (operands);")
- 
  (define_expand "movdi"
    ;; Let's see if it really still needs to handle fp regs, and, if so, why.
    [(set (match_operand:DI 0 "nonimmediate_operand" "")
--- 910,942 ----
      }
  })
  
! (define_insn "*movxf"
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,m,ro<,ro>")
! 	(match_operand:XF 1 "general_operand" "f,mF,f,rFo<,rFo>"))]
!   "!TARGET_COLDFIRE"
!   "@
!    fmove%.x %1,%0
!    fmove%.x %f1,%0
!    fmove%.x %1,%0
!    #
!    #")
! 
! (define_insn "*movxf_cf"
!   [(set (match_operand:XF 0 "nonimmediate_operand" "=&rQ<,&rQ>,&rFo<,&rFo>")
! 	(match_operand:XF 1 "general_src_operand" "rFo<,rFo>,rQU<,rQU>"))]
!   "TARGET_COLDFIRE"
!   "#")
  
! (define_split
!   [(set (match_operand:XF 0 "nonimmediate_operand" "")
! 	(match_operand:XF 1 "general_src_operand" ""))]
!   "reload_completed && !FP_REG_P (operands[0]) && !FP_REG_P (operands[1])"
!   [(const_int 1)]
  {
!   m68k_split_long_move(3, operands[0], operands[1]);
!   DONE;
  })
  
  (define_expand "movdi"
    ;; Let's see if it really still needs to handle fp regs, and, if so, why.
    [(set (match_operand:DI 0 "nonimmediate_operand" "")
***************
*** 1843,1853 ****
  ;; so commutativity won't apply to them.
  (define_insn "*addsi3_internal"
    [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?a,?a,d,a")
!         (plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJK,0,0")
!                  (match_operand:SI 2 "general_src_operand" "dIKLT,rJK,a,mSrIKLT,mSrIKLs")))]
  
  
!   "! TARGET_COLDFIRE"
    "* return output_addsi3 (operands);")
  
  (define_insn "*addsi3_5200"
--- 1783,1794 ----
  ;; so commutativity won't apply to them.
  (define_insn "*addsi3_internal"
    [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?a,?a,d,a")
!         (plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJKs,0,0")
!                  (match_operand:SI 2 "general_src_operand" "dIKLT,rJKs,a,mSrIKLT,mSrIKLs")))]
  
  
!   "!TARGET_COLDFIRE && !reg_mentioned_p(pc_pointer_rtx, operands[1])
!    && !reg_mentioned_p(pc_pointer_rtx, operands[2])"
    "* return output_addsi3 (operands);")
  
  (define_insn "*addsi3_5200"
***************
*** 1865,1870 ****
--- 1806,1821 ----
    "!TARGET_COLDFIRE"
    "add%.w %2,%0")
  
+ ;; Special case of fullword move, where we need to get a non-GOT PIC
+ ;; reference into an address register.
+ (define_insn ""
+   [(set (match_operand:SI 0 "nonimmediate_operand" "=a,<")
+         (match_operand:SI 1 "address_operand" "p,p"))]
+   ""
+   "@
+    lea %a1,%0
+    pea %a1")
+ 
  (define_insn "addhi3"
    [(set (match_operand:HI 0 "nonimmediate_operand" "=m,r")
  	(plus:HI (match_operand:HI 1 "general_operand" "%0,0")
***************
*** 6007,6051 ****
  	      (use (label_ref (match_operand 1 "" "")))])]
    ""
  {
! #ifdef CASE_VECTOR_PC_RELATIVE
!     operands[0] = gen_rtx_PLUS (SImode, pc_rtx,
! 				gen_rtx_SIGN_EXTEND (SImode, operands[0]));
! #endif
! })
! 
! ;; Jump to variable address from dispatch table of absolute addresses.
! (define_insn ""
!   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
!    (use (label_ref (match_operand 1 "" "")))]
!   ""
! {
!   return MOTOROLA ? "jmp (%0)" : "jmp %0@";
  })
  
  ;; Jump to variable address from dispatch table of relative addresses.
  (define_insn ""
!   [(set (pc)
! 	(plus:SI (pc)
! 		 (sign_extend:SI (match_operand:HI 0 "register_operand" "r"))))
     (use (label_ref (match_operand 1 "" "")))]
    ""
! {
! #ifdef ASM_RETURN_CASE_JUMP
!   ASM_RETURN_CASE_JUMP;
! #else
!   if (TARGET_COLDFIRE)
!     {
!       if (ADDRESS_REG_P (operands[0]))
! 	return MOTOROLA ? "jmp (2,pc,%0.l)" : "jmp pc@(2,%0:l)";
!       else if (MOTOROLA)
! 	return "ext%.l %0\;jmp (2,pc,%0.l)";
!       else
! 	return "extl %0\;jmp pc@(2,%0:l)";
!     }
!   else
!     return MOTOROLA ? "jmp (2,pc,%0.w)" : "jmp pc@(2,%0:w)";
! #endif
! })
  
  ;; Decrement-and-branch insns.
  (define_insn ""
--- 5950,5971 ----
  	      (use (label_ref (match_operand 1 "" "")))])]
    ""
  {
!   if (CASE_VECTOR_PC_RELATIVE)
!     {
!       rtx op1 = force_reg (Pmode, gen_rtx_SIGN_EXTEND (Pmode, operands[0]));
!       rtx op2 = force_reg (Pmode, gen_rtx_UNSPEC (Pmode,
! 			   gen_rtvec (1, gen_rtx_LABEL_REF (Pmode, operands[1])),
! 			   UNSPEC_PCREL));
!       operands[0] = gen_rtx_PLUS (Pmode, op1, op2);
!     }
  })
  
  ;; Jump to variable address from dispatch table of relative addresses.
  (define_insn ""
!   [(set (pc) (match_operand:SI 0 "address_operand" "p"))
     (use (label_ref (match_operand 1 "" "")))]
    ""
!   "jmp %a0")
  
  ;; Decrement-and-branch insns.
  (define_insn ""
***************
*** 6450,6478 ****
  ;; This should not be used unless the add/sub insns can't be.
  
  (define_insn ""
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=a")
! 	(match_operand:QI 1 "address_operand" "p"))]
    ""
! {
!   /* Recognize an insn that refers to a table of offsets.  Such an insn will
!      need to refer to a label on the insn.  So output one.  Use the
!      label-number of the table of offsets to generate this label.  This code,
!      and similar code above, assumes that there will be at most one reference
!      to each table.  */
!   if (GET_CODE (operands[1]) == PLUS
!       && GET_CODE (XEXP (operands[1], 1)) == LABEL_REF
!       && GET_CODE (XEXP (operands[1], 0)) != PLUS)
!     {
!       rtx labelref = XEXP (operands[1], 1);
!       if (MOTOROLA)
!         asm_fprintf (asm_out_file, "\\t.set %LLI%d,.+2\\n",
! 		     CODE_LABEL_NUMBER (XEXP (labelref, 0)));
!       else
!         (*targetm.asm_out.internal_label) (asm_out_file, "LI",
! 		     CODE_LABEL_NUMBER (XEXP (labelref, 0)));
!     }
!   return "lea %a1,%0";
! })
  
  ;; This is the first machine-dependent peephole optimization.
  ;; It is useful when a floating value is returned from a function call
--- 6370,6381 ----
  ;; This should not be used unless the add/sub insns can't be.
  
  (define_insn ""
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=a,<")
! 	(match_operand:QI 1 "address_operand" "p,p"))]
    ""
!   "@
!    lea %a1,%0
!    pea %a1")
  
  ;; This is the first machine-dependent peephole optimization.
  ;; It is useful when a floating value is returned from a function call
***************
*** 6842,6866 ****
    return "fmove%.x %f1,%0";
  })
  
! (define_insn "truncxfdf2"
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=m,!r")
  	(float_truncate:DF
!           (match_operand:XF 1 "general_operand" "f,f")))]
    "TARGET_68881"
! {
!   if (REG_P (operands[0]))
!     {
!       output_asm_insn ("fmove%.d %f1,%-\;move%.l %+,%0", operands);
!       operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
!       return "move%.l %+,%0";
!     }
!   return "fmove%.d %f1,%0";
! })
  
  (define_insn "truncxfsf2"
    [(set (match_operand:SF 0 "nonimmediate_operand" "=dm")
  	(float_truncate:SF
! 	  (match_operand:XF 1 "general_operand" "f")))]
    "TARGET_68881"
    "fmove%.s %f1,%0")
  
--- 6745,6797 ----
    return "fmove%.x %f1,%0";
  })
  
! (define_expand "truncxfdf2"
!   [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
! 		   (float_truncate:DF
! 		    (match_operand:XF 1 "register_operand" "")))
! 	      (clobber (match_dup 2))])]
!   "TARGET_68881"
!   "operands[2] = m68k_assign_stack_local(DFmode, 0);")
! 
! (define_insn "*truncxfdf2"
!   [(set (match_operand:DF 0 "memory_operand" "=m")
  	(float_truncate:DF
! 	 (match_operand:XF 1 "register_operand" "f")))]
    "TARGET_68881"
!   "fmove%.d %1,%0")
! 
! (define_insn "*truncxfdf2_2"
!   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m")
! 	(float_truncate:DF
! 	 (match_operand:XF 1 "register_operand" "f,f")))
!    (clobber (match_operand:DF 2 "memory_operand" "=m,X"))]
!   "TARGET_68881"
!   "#")
! 
! (define_split
!   [(set (match_operand:DF 0 "memory_operand" "")
! 	(float_truncate:DF
! 	 (match_operand:XF 1 "register_operand" "")))
!    (clobber (match_operand:DF 2 "memory_operand" ""))]
!   ""
!   [(set (match_dup 0) (float_truncate:DF (match_dup 1)))]
!   "")
! 
! (define_split
!   [(set (match_operand:DF 0 "register_operand" "")
! 	(float_truncate:DF
! 	 (match_operand:XF 1 "register_operand" "")))
!    (clobber (match_operand:DF 2 "memory_operand" ""))]
!   ""
!   [(set (match_dup 2) (float_truncate:DF (match_dup 1)))
!    (set (match_dup 0) (match_dup 2))]
!   "")
! 
  
  (define_insn "truncxfsf2"
    [(set (match_operand:SF 0 "nonimmediate_operand" "=dm")
  	(float_truncate:SF
! 	 (match_operand:XF 1 "register_operand" "f")))]
    "TARGET_68881"
    "fmove%.s %f1,%0")
  
diff -crp config/m68k/m68k-protos.h config/m68k/m68k-protos.h
*** config/m68k/m68k-protos.h	2004-08-08 18:04:58.000000000 +0200
--- config/m68k/m68k-protos.h	2004-08-07 13:33:45.000000000 +0200
*************** extern void output_dbcc_and_branch (rtx 
*** 46,51 ****
--- 46,58 ----
  extern int floating_exact_log2 (rtx);
  extern bool strict_low_part_peephole_ok (enum machine_mode mode, rtx first_insn, rtx target);
  
+ extern int m68k_legitimate_address_p (enum machine_mode mode, rtx x, int strict);
+ extern rtx m68k_legitimize_address (rtx, rtx, enum machine_mode);
+ 
+ extern void split_di (rtx[], unsigned int, rtx[], rtx[]);
+ extern void m68k_split_long_move(int, rtx, rtx);
+ extern rtx m68k_assign_stack_local (enum machine_mode, int);
+ 
  /* Functions from m68k.c used in macros.  */
  extern int standard_68881_constant_p (rtx);
  extern void print_operand_address (FILE *, rtx);
diff -crp config/m68k/netbsd-elf.h config/m68k/netbsd-elf.h
*** config/m68k/netbsd-elf.h	2004-08-08 17:42:38.000000000 +0200
--- config/m68k/netbsd-elf.h	2004-08-02 20:57:29.000000000 +0200
*************** while (0)
*** 184,202 ****
  
  /* Use the default action for outputting the case label.  */
  #undef ASM_OUTPUT_CASE_LABEL
- #define ASM_RETURN_CASE_JUMP				\
-   do {							\
-     if (TARGET_COLDFIRE)				\
-       {							\
- 	if (ADDRESS_REG_P (operands[0]))		\
- 	  return "jmp %%pc@(2,%0:l)";			\
- 	else						\
- 	  return "ext%.l %0\n\tjmp %%pc@(2,%0:l)";	\
-       }							\
-     else						\
-       return "jmp %%pc@(2,%0:w)";			\
-   } while (0)
- 
  
  /* This is how to output an assembler line that says to advance the
     location counter to a multiple of 2**LOG bytes.  */
--- 184,189 ----



More information about the Gcc-patches mailing list