public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* MIPS patch: allow ints in FPRs, rework some float patterns
@ 2002-07-09  7:44 Richard Sandiford
  2002-07-11 21:40 ` Hans-Peter Nilsson
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Richard Sandiford @ 2002-07-09  7:44 UTC (permalink / raw)
  To: gcc-patches

This patch reworks some of the MIPS floating-point patterns.
The main change is to allow integer values to be stored in
floating-point registers.

At the moment, we don't allow that, so patterns like fix_truncMMNN2
and floatMMNN2 have to include a move:

    (define_insn "fix_truncdfdi2"
      [(set (match_operand:DI 0 "nonimmediate_operand" "=d,*f,R,To")
	    (fix:DI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
       (clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
      "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
      "*
    {
      rtx xoperands[10];

      if (which_alternative == 1)
	return \"trunc.l.d %0,%1\";

      output_asm_insn (\"trunc.l.d %2,%1\", operands);

      xoperands[0] = operands[0];
      xoperands[1] = operands[2];
      output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
      return \"\";
    }"
      [(set_attr "type"	"fcvt")
       (set_attr "mode"	"DF")
       (set_attr "length"	"8,4,8,12")])

    (I don't really understand how the second alternative could be chosen
     in the current setup.)

It would be nice to split the instruction up for better scheduling,
including more filling of delay slots.  There's already code to allow
integer modes in float registers, selected by TARGET_DEBUG_H_MODE,
but it only works for 32-bit integers.

The main problem with extending it to 64-bit integers is the lack
of automatic sign extension.  When 32-bit values are stored in 64-bit
float registers, the upper 32 bits are left undefined.  So the
definition of LOAD_EXTEND_OP doesn't hold:

    #define LOAD_EXTEND_OP(MODE) \
      (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode) \
       ? SIGN_EXTEND : ZERO_EXTEND)

I've tried to avoid the problem by including 64-bit FPRs in
CLASS_CANNOT_CHANGE_MODE.  Is that the right thing to do?
Is it going to be enough?

The lack of sign extension means there are only two sign_extend
alternatives involving FPRs.  A 32-bit float register can be
sign-extended by moving it into an integer register using a
32-bit move.  The destination of a sign extension can be a
float register if the source is in an integer register (the
move is then a 64-bit one).

At the moment, there are two extendsidi2 patterns: extendsidi2
itself, which handles register destinations, and movdi_internal2,
which handles memory destinations.  In the patch, I've split
movdi_internal2 into extending and non-extending patterns and
made extendsidi2 a define_expand.

Patch tested by bootstrapping on mips-sgi-irix6.5, and on a customised
mipsisa32-elf build, with -mhard-float the default, and with EABI
multlibs.  Test pattern was {-mabi=eabi}{-mips32,-mips64}{-EL,-EB}.
Also tested on mipsisa32-elf without the '*'s in the move constraints,
the idea being that it would give better test coverage.  (BTW, one reason
we need the '*'s is that regclass doesn't look inside sign-extended
operands.)

I also compared the assembly output for c-torture before and after
the patch.  Probably the biggest improvement is in compile/920428-2.c:

@@ -77633,22 +77640,17 @@ gs_update_matrix_fixed:
 	li.s	$f2,4.096e3
 	l.s	$f1,36($4)
 	l.s	$f0,44($4)
-	li.d	$f3,2.44140625e-4
+	li.d	$f4,2.44140625e-4
 	mul.s	$f1,$f1,$f2
 	mul.s	$f0,$f0,$f2
-	trunc.w.s $f2,$f1,$3
-	mfc1	$2,$f2
-	trunc.w.s $f1,$f0,$5
-	mfc1	$3,$f1
-	#nop
-	mtc1	$3,$f0
-	cvt.d.w	$f0,$f0
-	mtc1	$2,$f1
-	cvt.d.w	$f1,$f1
-	mul.d	$f0,$f0,$f3
-	mul.d	$f1,$f1,$f3
-	sw	$2,48($4)
-	sw	$3,52($4)
+	trunc.w.s $f3,$f1
+	trunc.w.s $f2,$f0
+	cvt.d.w	$f1,$f3
+	cvt.d.w	$f0,$f2
+	mul.d	$f0,$f0,$f4
+	mul.d	$f1,$f1,$f4
+	s.s	$f3,48($4)
+	s.s	$f2,52($4)
 	cvt.s.d	$f0,$f0
 	cvt.s.d	$f1,$f1
 	s.s	$f0,44($4)

There are similar improvements to other functions in this file.
There are plenty of other, smaller improvements elsewhere, such as filling
more delay slots, or avoiding some moves.  The only case I could find where
the code got worse was compile/920710-2.c:

    union u
    {
      struct {unsigned h, l;} i;
      double d;
    };

    foo (union u x)
    {
      while (x.i.h++)
	{
	  while (x.i.l-- > 0)
	    ;
	  while (x.d++ > 0)
	    ;
	}
    }

The union gets allocated to a float register instead of an integer one.
It makes the x.d++ loop better, but the overall code is worse.

A float register is chosen because the x.d++ loop is given a frequency
about five times greater than the x.i.l one, so its costs dominate.
On that basis, I guess choosing a float register is the sensible thing
to do.  It would probably work out OK if everything was nicely reloaded.
Unfortunately, registers that could potentialy be used for reload
inheritance are clobbered just before they'd be used.  It seems to
happen three times in the function above, leading to several avoidable
moves.

One example.  The union is stored in register 182, which is allocated
$f1.  Before the outermost loop, we have:

   [A]	(set (reg/v:DI 182)
	     (and:DI (reg/v:DI 182)
		     (reg:DI 219)))

   [B]	(set (reg:DI 218)
	     (ashift:DI (subreg:DI (reg:SI 215) 0)
			(const_int 32)))

   [C]	(set (reg/v:DI 182)
	     (ior:DI (reg/v:DI 182)
		     (reg:DI 218)))

[A] needs an in-out reload for 182, which [C] would potentially
inherit, but can't because 218 is allocated the reload register.
The reloaded code (before scheduling) looks like:

        dmfc1   $3,$f1
        and     $3,$3,$2
        dmtc1   $3,$f1
        dsll    $3,$4,32
        dmfc1   $7,$f1
        or      $7,$7,$3
        dmtc1   $7,$f1

Anyway, the function's full diff is below.

***************
*** 86859,86917 ****
  	.frame	$sp,0,$31		# vars= 0, regs= 0/0, args= 0, extra= 0
  	.mask	0x00000000,0
  	.fmask	0x00000000,0
! 	move	$5,$4
! 	dsra	$4,$4,32
  	dli	$2,0xffffffff		# 4294967295
  	addu	$4,$4,1
! 	and	$5,$5,$2
  	dsll	$3,$4,32
  	li	$2,1			# 0x1
! 	.set	noreorder
! 	.set	nomacro
  	beq	$4,$2,$L15
- 	or	$5,$5,$3
- 	.set	macro
- 	.set	reorder
- 
  	dli	$4,0xffffffff00000000		# -4294967296
! 	dli	$7,0xffffffff		# 4294967295
! 	li	$6,1			# 0x1
  	.align	3
  $L14:
! 	dsll	$3,$5,32
  	dsra	$3,$3,32
  	addu	$2,$3,-1
  	dsll	$2,$2,32
  	dsrl	$2,$2,32
! 	and	$5,$5,$4
! 	.set	noreorder
! 	.set	nomacro
  	bne	$3,$0,$L14
! 	or	$5,$5,$2
! 	.set	macro
! 	.set	reorder
! 
! 	li.d	$f2,1.0e0
! 	dmtc1	$0,$f1
  	.align	3
  $L8:
! 	dmtc1	$5,$f0
  	#nop
- 	c.lt.d	$f1,$f0
- 	add.d	$f0,$f0,$f2
- 	dmfc1	$5,$f0
- 	bc1t	$L8
- 	dsra	$2,$5,32
- 	addu	$2,$2,1
- 	dsll	$3,$2,32
- 	and	$5,$5,$7
  	.set	noreorder
  	.set	nomacro
! 	bne	$2,$6,$L14
! 	or	$5,$5,$3
  	.set	macro
  	.set	reorder
  
  $L15:
  	j	$31
  	.end	foo
--- 86842,86898 ----
  	.frame	$sp,0,$31		# vars= 0, regs= 0/0, args= 0, extra= 0
  	.mask	0x00000000,0
  	.fmask	0x00000000,0
! 	dmtc1	$4,$f1
  	dli	$2,0xffffffff		# 4294967295
+ 	dmfc1	$3,$f1
+ 	dsra	$4,$4,32
+ 	and	$3,$3,$2
+ 	dmtc1	$3,$f1
  	addu	$4,$4,1
! 	dmfc1	$7,$f1
  	dsll	$3,$4,32
+ 	or	$7,$7,$3
  	li	$2,1			# 0x1
! 	dmtc1	$7,$f1
  	beq	$4,$2,$L15
  	dli	$4,0xffffffff00000000		# -4294967296
! 	dli	$6,0xffffffff		# 4294967295
! 	li	$5,1			# 0x1
  	.align	3
  $L14:
! 	dmfc1	$2,$f1
! 	dmfc1	$7,$f1
! 	dsll	$3,$2,32
  	dsra	$3,$3,32
  	addu	$2,$3,-1
  	dsll	$2,$2,32
  	dsrl	$2,$2,32
! 	and	$7,$7,$4
! 	or	$7,$7,$2
! 	dmtc1	$7,$f1
  	bne	$3,$0,$L14
! 	li.d	$f3,1.0e0
! 	dmtc1	$0,$f2
  	.align	3
  $L8:
! 	c.lt.d	$f2,$f1
  	#nop
  	.set	noreorder
  	.set	nomacro
! 	bc1t	$L8
! 	add.d	$f1,$f1,$f3
  	.set	macro
  	.set	reorder
  
+ 	dmfc1	$3,$f1
+ 	dmfc1	$7,$f1
+ 	dsra	$2,$3,32
+ 	addu	$2,$2,1
+ 	dsll	$3,$2,32
+ 	and	$7,$7,$6
+ 	or	$7,$7,$3
+ 	dmtc1	$7,$f1
+ 	bne	$2,$5,$L14
  $L15:
  	j	$31
  	.end	foo

Richard

	* config/mips/mips-protos.h (mips_sign_extend): Declare.
	* config/mips/mips.h (MASK_DEBUG_H, TARGET_DEBUG_H_MODE): Remove.
	(TARGET_SWITCHES): Remove debugh.
	(ISA_HAS_TRUNC_W): New macro.
	(CLASS_CANNOT_CHANGE_MODE): Include FP_REGS if TARGET_FLOAT64.
	(PREDICATE_CODES): Remove se_nonimmediate_operand.
	* config/mips/mips.c (movdi_operand): Allow sign-extensions of
	any SImode move_operand.
	(se_nonimmediate_operand): Remove.
	(mips_sign_extend): New.
	(mips_move_2words): Use it for sign-extended source operands.
	(override_options): Allow integers to be put into single FPRs.
	(mips_secondary_reload_class): Handle integers in float registers.
	* config/mips/mips.md (extendsidi2): Turn into a define_expand.
	(fix_truncsfsi2, fix_truncdfsi2): Likewise.
	(fix_truncdfsi2_insn, fix_truncdfsi2_macro): New.
	(fix_truncsfsi2_insn, fix_truncsfsi2_macro): New.
	(fix_truncdfdi2): Provide only a single alternative, in which the
	integer is in a float register.  Depend on TARGET_FLOAT64 rather
	than TARGET_64BIT.
	(fix_truncsfdi2, floatdidf2, floatdisf2): Likewise.
	(floatsidf2, floatsisf2): Likewise, but no TARGET_FLOAT64 dependency.
	(movdi_internal2): Don't allow the source operand to be sign-extended.
	Add alternatives for float registers.  Don't test TARGET_DEBUG_H_MODE.
	(*movdi_internal2_extend): New.  Version of movdi_internal2 that
	allows sign-extension.
	(*movdi_internal2_mips16): Name the existing mips16 movdi pattern.
	(movsi_internal2): Rename to movsi_internal.  Add alternatives for
	float registers.  Remove TARGET_DEBUG_H_MODE test.
	(movhi_internal1): Rename to movhi_internal.  Don't check
	TARGET_DEBUG_H_MODE.  Fix transposed *d and *f source constraints.
	(movqi_internal1): Rename to movqi_internal and remove
	TARGET_DEBUG_H_MODE dependency.
	(movsi_internal1, movhi_internal2, movqi_internal2): Remove.

Index: config/mips/mips-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips-protos.h,v
retrieving revision 1.25
diff -c -d -p -r1.25 mips-protos.h
*** config/mips/mips-protos.h	27 Jun 2002 02:10:36 -0000	1.25
--- config/mips/mips-protos.h	5 Jul 2002 13:18:22 -0000
*************** extern const char      *mips_fill_delay_
*** 98,103 ****
--- 98,104 ----
  						      rtx));
  extern const char      *mips_move_1word PARAMS ((rtx *, rtx, int));
  extern const char      *mips_move_2words PARAMS ((rtx *, rtx));
+ extern const char      *mips_sign_extend PARAMS ((rtx, rtx, rtx));
  extern const char      *mips_emit_prefetch PARAMS ((rtx *));
  extern const char      *mips_restore_gp PARAMS ((rtx *, rtx));
  extern const char      *output_block_move PARAMS ((rtx, rtx *, int,
Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.195
diff -c -d -p -r1.195 mips.h
*** config/mips/mips.h	1 Jul 2002 12:13:03 -0000	1.195
--- config/mips/mips.h	5 Jul 2002 13:18:22 -0000
*************** extern void		sbss_section PARAMS ((void)
*** 225,231 ****
  #define MASK_DEBUG_E	0		/* function_arg debug */
  #define MASK_DEBUG_F	0		/* ??? */
  #define MASK_DEBUG_G	0		/* don't support 64 bit arithmetic */
- #define MASK_DEBUG_H	0               /* allow ints in FP registers */
  #define MASK_DEBUG_I	0		/* unused */
  
  					/* Dummy switches used only in specs */
--- 225,230 ----
*************** extern void		sbss_section PARAMS ((void)
*** 253,259 ****
  #define TARGET_DEBUG_E_MODE	(target_flags & MASK_DEBUG_E)
  #define TARGET_DEBUG_F_MODE	(target_flags & MASK_DEBUG_F)
  #define TARGET_DEBUG_G_MODE	(target_flags & MASK_DEBUG_G)
- #define TARGET_DEBUG_H_MODE	(target_flags & MASK_DEBUG_H)
  #define TARGET_DEBUG_I_MODE	(target_flags & MASK_DEBUG_I)
  
  					/* Reg. Naming in .s ($21 vs. $a0) */
--- 252,257 ----
*************** extern void		sbss_section PARAMS ((void)
*** 589,596 ****
       NULL},								\
    {"debugg",		  MASK_DEBUG_G,					\
       NULL},								\
-   {"debugh",		  MASK_DEBUG_H,					\
-      NULL},								\
    {"debugi",		  MASK_DEBUG_I,					\
       NULL},								\
    {"",			  (TARGET_DEFAULT				\
--- 587,592 ----
*************** extern void		sbss_section PARAMS ((void)
*** 787,792 ****
--- 783,793 ----
  				  || ISA_MIPS64)	       		\
  				 && !TARGET_MIPS16)
  
+ /* True if trunc.w.s and trunc.w.d are real (not synthetic)
+    instructions.  Both require TARGET_HARD_FLOAT, and trunc.w.d
+    also requires TARGET_DOUBLE_FLOAT.  */
+ #define ISA_HAS_TRUNC_W		(!ISA_MIPS1)
+ 
  /* CC1_SPEC causes -mips3 and -mips4 to set -mfp64 and -mgp64; -mips1 or
     -mips2 sets -mfp32 and -mgp32.  This can be overridden by an explicit
     -mfp32, -mfp64, -mgp32 or -mgp64.  -mfp64 sets MASK_FLOAT64 in
*************** extern enum reg_class mips_char_to_class
*** 2259,2275 ****
  
  /* If defined, gives a class of registers that cannot be used as the
     operand of a SUBREG that changes the mode of the object illegally.
-    When FP regs are larger than integer regs... Er, anyone remember what
-    goes wrong?
  
     In little-endian mode, the hi-lo registers are numbered backwards,
     so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
!    word as intended.  */
  
  #define CLASS_CANNOT_CHANGE_MODE					\
    (TARGET_BIG_ENDIAN							\
!    ? (TARGET_FLOAT64 && ! TARGET_64BIT ? FP_REGS : NO_REGS)		\
!    : (TARGET_FLOAT64 && ! TARGET_64BIT ? HI_AND_FP_REGS : HI_REG))
  
  /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */
  
--- 2260,2279 ----
  
  /* If defined, gives a class of registers that cannot be used as the
     operand of a SUBREG that changes the mode of the object illegally.
  
     In little-endian mode, the hi-lo registers are numbered backwards,
     so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
!    word as intended.
! 
!    Also, storing a 32-bit value in a 64-bit floating-point
!    register will leave the upper 32 bits undefined.  We can't
!    allow 64-bit float registers to change from a 32-bit mode
!    to a 64-bit mode.  */
  
  #define CLASS_CANNOT_CHANGE_MODE					\
    (TARGET_BIG_ENDIAN							\
!    ? (TARGET_FLOAT64 ? FP_REGS : NO_REGS)				\
!    : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
  
  /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */
  
*************** typedef struct mips_args {
*** 3692,3698 ****
    {"se_nonmemory_operand",	{ CONST_INT, CONST_DOUBLE, CONST,	\
  				  SYMBOL_REF, LABEL_REF, SUBREG,	\
  				  REG, SIGN_EXTEND }},			\
-   {"se_nonimmediate_operand",   { SUBREG, REG, MEM, SIGN_EXTEND }},	\
    {"consttable_operand",	{ LABEL_REF, SYMBOL_REF, CONST_INT,	\
  				  CONST_DOUBLE, CONST }},		\
    {"extend_operator",           { SIGN_EXTEND, ZERO_EXTEND }},          \
--- 3696,3701 ----
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.213
diff -c -d -p -r1.213 mips.c
*** config/mips/mips.c	27 Jun 2002 02:10:36 -0000	1.213
--- config/mips/mips.c	5 Jul 2002 13:18:23 -0000
*************** move_operand (op, mode)
*** 1198,1206 ****
  
  /* Return nonzero if OPERAND is valid as a source operand for movdi.
     This accepts not only general_operand, but also sign extended
!    constants and registers.  We need to accept sign extended constants
     in case a sign extended register which is used in an expression,
!    and is equivalent to a constant, is spilled.  */
  
  int
  movdi_operand (op, mode)
--- 1198,1208 ----
  
  /* Return nonzero if OPERAND is valid as a source operand for movdi.
     This accepts not only general_operand, but also sign extended
!    move_operands.  Note that we need to accept sign extended constants
     in case a sign extended register which is used in an expression,
!    and is equivalent to a constant, is spilled.  We need to accept
!    sign-extended memory for spilled pseudos, and so that we generate
!    efficient code for extendsidi2.  */
  
  int
  movdi_operand (op, mode)
*************** movdi_operand (op, mode)
*** 1211,1221 ****
        && mode == DImode
        && GET_CODE (op) == SIGN_EXTEND
        && GET_MODE (op) == DImode
!       && (GET_MODE (XEXP (op, 0)) == SImode
! 	  || (GET_CODE (XEXP (op, 0)) == CONST_INT
! 	      && GET_MODE (XEXP (op, 0)) == VOIDmode))
!       && (register_operand (XEXP (op, 0), SImode)
! 	  || immediate_operand (XEXP (op, 0), SImode)))
      return 1;
  
    return (general_operand (op, mode)
--- 1213,1219 ----
        && mode == DImode
        && GET_CODE (op) == SIGN_EXTEND
        && GET_MODE (op) == DImode
!       && move_operand (XEXP (op, 0), SImode))
      return 1;
  
    return (general_operand (op, mode)
*************** se_nonmemory_operand (op, mode)
*** 1324,1349 ****
    return nonmemory_operand (op, mode);
  }
  
- /* Like nonimmediate_operand, but when in 64 bit mode also accept a
-    sign extend of a 32 bit register, since the value is known to be
-    already sign extended.  */
- 
- int
- se_nonimmediate_operand (op, mode)
-      rtx op;
-      enum machine_mode mode;
- {
-   if (TARGET_64BIT
-       && mode == DImode
-       && GET_CODE (op) == SIGN_EXTEND
-       && GET_MODE (op) == DImode
-       && GET_MODE (XEXP (op, 0)) == SImode
-       && register_operand (XEXP (op, 0), SImode))
-     return 1;
- 
-   return nonimmediate_operand (op, mode);
- }
- 
  /* Accept any operand that can appear in a mips16 constant table
     instruction.  We can't use any of the standard operand functions
     because for these instructions we accept values that are not
--- 1322,1327 ----
*************** mips_restore_gp (operands, insn)
*** 2462,2467 ****
--- 2440,2472 ----
    return mips_move_1word (operands, insn, 0);
  }
  \f
+ /* Return an instruction to sign-extend SImode value SRC and store it
+    in DImode value DEST.  INSN is the original extendsidi2-type insn.  */
+ 
+ const char *
+ mips_sign_extend (insn, dest, src)
+      rtx insn, dest, src;
+ {
+   rtx operands[MAX_RECOG_OPERANDS];
+ 
+   if ((register_operand (src, SImode) && FP_REG_P (true_regnum (src)))
+       || memory_operand (src, SImode))
+     {
+       /* If the source is a floating-point register, we need to use a
+ 	 32-bit move, since the float register is not kept sign-extended.
+ 	 If the source is in memory, we need a 32-bit load.  */
+       operands[0] = gen_lowpart_SUBREG (SImode, dest);
+       operands[1] = src;
+       return mips_move_1word (operands, insn, false);
+     }
+   else
+     {
+       operands[0] = dest;
+       operands[1] = src;
+       return mips_move_2words (operands, insn);
+     }
+ }
+ \f
  /* Return the appropriate instructions to move 2 words */
  
  const char *
*************** mips_move_2words (operands, insn)
*** 2478,2483 ****
--- 2483,2491 ----
    int subreg_offset1 = 0;
    enum delay_type delay = DELAY_NONE;
  
+   if (code1 == SIGN_EXTEND)
+     return mips_sign_extend (insn, op0, XEXP (op1, 0));
+ 
    while (code0 == SUBREG)
      {
        subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
*************** mips_move_2words (operands, insn)
*** 2488,2499 ****
        code0 = GET_CODE (op0);
      }
  
-   if (code1 == SIGN_EXTEND)
-     {
-       op1 = XEXP (op1, 0);
-       code1 = GET_CODE (op1);
-     }
- 
    while (code1 == SUBREG)
      {
        subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
--- 2496,2501 ----
*************** mips_move_2words (operands, insn)
*** 2504,2520 ****
        code1 = GET_CODE (op1);
      }
  
-   /* Sanity check.  */
-   if (GET_CODE (operands[1]) == SIGN_EXTEND
-       && code1 != REG
-       && code1 != CONST_INT
-       /* The following three can happen as the result of a questionable
- 	 cast.  */
-       && code1 != LABEL_REF
-       && code1 != SYMBOL_REF
-       && code1 != CONST)
-     abort ();
- 
    if (code0 == REG)
      {
        int regno0 = REGNO (op0) + subreg_offset0;
--- 2506,2511 ----
*************** override_options ()
*** 5440,5449 ****
                          the value, not about whether math works on the
                          register.  */
                       || (mips_abi == ABI_MEABI && size <= 4))
! 		    && (class == MODE_FLOAT
! 			|| class == MODE_COMPLEX_FLOAT
! 			|| (TARGET_DEBUG_H_MODE && class == MODE_INT))
! 		    && size <= UNITS_PER_FPVALUE);
  
  	  else if (MD_REG_P (regno))
  	    temp = (class == MODE_INT
--- 5431,5442 ----
                          the value, not about whether math works on the
                          register.  */
                       || (mips_abi == ABI_MEABI && size <= 4))
! 		    && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
! 			 && size <= UNITS_PER_FPVALUE)
! 			/* Allow integer modes that fit into a single
! 			   register.  We need to put integers into FPRs
! 			   when using instructions like cvt and trunc.  */
! 			|| (class == MODE_INT && size <= UNITS_PER_FPREG)));
  
  	  else if (MD_REG_P (regno))
  	    temp = (class == MODE_INT
*************** mips_secondary_reload_class (class, mode
*** 8352,8357 ****
--- 8345,8362 ----
  	  if (GET_CODE (x) == REG)
  	    regno = REGNO (x) + off;
  	}
+ 
+       /* 64-bit floating-point registers don't store 32-bit values
+ 	 in sign-extended form.  The only way we can reload
+ 	 (sign_extend:DI (reg:SI $f0)) is by moving $f0 into
+ 	 an integer register using a 32-bit move.  */
+       if (FP_REG_P (regno))
+ 	return (class == GR_REGS ? NO_REGS : GR_REGS);
+ 
+       /* For the same reason, we can only reload (sign_extend:DI FOO) into
+ 	 a floating-point register when FOO is an integer register. */
+       if (class == FP_REGS)
+ 	return (GP_REG_P (regno) ? NO_REGS : GR_REGS);
      }
  
    else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
*************** mips_secondary_reload_class (class, mode
*** 8409,8414 ****
--- 8414,8450 ----
        if (! in_p)
  	return FP_REGS;
        return class == GR_REGS ? NO_REGS : GR_REGS;
+     }
+ 
+   if (class == FP_REGS)
+     {
+       if (GET_CODE (x) == MEM)
+ 	{
+ 	  /* In this case we can use lwc1, swc1, ldc1 or sdc1. */
+ 	  return NO_REGS;
+ 	}
+       else if (CONSTANT_P (x) && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ 	{
+ 	  /* We can use the l.s and l.d macros to load floating-point
+ 	     constants.  ??? For l.s, we could probably get better
+ 	     code by returning GR_REGS here.  */
+ 	  return NO_REGS;
+ 	}
+       else if (GP_REG_P (regno) || x == CONST0_RTX (mode))
+ 	{
+ 	  /* In this case we can use mtc1, mfc1, dmtc1 or dmfc1.  */
+ 	  return NO_REGS;
+ 	}
+       else if (FP_REG_P (regno))
+ 	{
+ 	  /* In this case we can use mov.s or mov.d.  */
+ 	  return NO_REGS;
+ 	}
+       else
+ 	{
+ 	  /* Otherwise, we need to reload through an integer register.  */
+ 	  return GR_REGS;
+ 	}
      }
  
    /* In mips16 mode, going between memory and anything but M16_REGS
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.133
diff -c -d -p -r1.133 mips.md
*** config/mips/mips.md	25 Jun 2002 01:52:37 -0000	1.133
--- config/mips/mips.md	5 Jul 2002 13:18:23 -0000
*************** move\\t%0,%z4\\n\\
*** 4121,4136 ****
  ;; In 64 bit mode, 32 bit values in general registers are always
  ;; correctly sign extended.  That means that if the target is a
  ;; general register, we can sign extend from SImode to DImode just by
! ;; doing a move.
  
! (define_insn "extendsidi2"
!   [(set (match_operand:DI 0 "register_operand" "=d,y,d,*d,d,d")
! 	(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,d,y,*x,R,m")))]
    "TARGET_64BIT"
!   "* return mips_move_1word (operands, insn, FALSE);"
!   [(set_attr "type"	"move,move,move,hilo,load,load")
!    (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,4,4,4,8")])
  
  ;; These patterns originally accepted general_operands, however, slightly
  ;; better code is generated by only accepting register_operands, and then
--- 4121,4134 ----
  ;; In 64 bit mode, 32 bit values in general registers are always
  ;; correctly sign extended.  That means that if the target is a
  ;; general register, we can sign extend from SImode to DImode just by
! ;; doing a move.  The matching define_insns are *movdi_internal2_extend
! ;; and *movdi_internal2_mips16.
  
! (define_expand "extendsidi2"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
    "TARGET_64BIT"
!   "")
  
  ;; These patterns originally accepted general_operands, however, slightly
  ;; better code is generated by only accepting register_operands, and then
*************** move\\t%0,%z4\\n\\
*** 4306,4370 ****
  ;;
  ;;  ....................
  
! ;; The SImode scratch register can not be shared with address regs used for
! ;; operand zero, because then the address in the move instruction will be
! ;; clobbered.  We mark the scratch register as early clobbered to prevent this.
! 
! ;; We need the ?X in alternative 1 so that it will be chosen only if the
! ;; destination is a floating point register.  Otherwise, alternative 1 can
! ;; have lower cost than alternative 0 (because there is one less loser), and
! ;; can be chosen when it won't work (because integral reloads into FP
! ;; registers are not supported).
! 
! (define_insn "fix_truncdfsi2"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,*f,R,To")
! 	(fix:SI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
!    (clobber (match_scratch:SI 2 "=d,*d,&d,&d"))
!    (clobber (match_scratch:DF 3 "=f,?*X,f,f"))]
    "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
-   "*
  {
!   rtx xoperands[10];
! 
!   if (which_alternative == 1)
!     return \"trunc.w.d %0,%1,%2\";
! 
!   output_asm_insn (\"trunc.w.d %3,%1,%2\", operands);
  
!   xoperands[0] = operands[0];
!   xoperands[1] = operands[3];
!   output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
!   return \"\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"44,36,40,44")])
  
  
! (define_insn "fix_truncsfsi2"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,*f,R,To")
! 	(fix:SI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
!    (clobber (match_scratch:SI 2 "=d,*d,&d,&d"))
!    (clobber (match_scratch:SF 3 "=f,?*X,f,f"))]
    "TARGET_HARD_FLOAT"
-   "*
  {
!   rtx xoperands[10];
! 
!   if (which_alternative == 1)
!     return \"trunc.w.s %0,%1,%2\";
! 
!   output_asm_insn (\"trunc.w.s %3,%1,%2\", operands);
  
!   xoperands[0] = operands[0];
!   xoperands[1] = operands[3];
!   output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
!   return \"\";
! }"
    [(set_attr "type"	"fcvt")
!    (set_attr "mode"	"SF")
!    (set_attr "length"	"44,36,40,44")])
  
  
  ;;; ??? trunc.l.d is mentioned in the appendix of the 1993 r4000/r4600 manuals
  ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
--- 4304,4370 ----
  ;;
  ;;  ....................
  
! (define_expand "fix_truncdfsi2"
!   [(set (match_operand:SI 0 "register_operand" "=f")
! 	(fix:SI (match_operand:DF 1 "register_operand" "f")))]
    "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
  {
!   if (!ISA_HAS_TRUNC_W)
!     {
!       emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1]));
!       DONE;
!     }
! })
  
! (define_insn "fix_truncdfsi2_insn"
!   [(set (match_operand:SI 0 "register_operand" "=f")
! 	(fix:SI (match_operand:DF 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W"
!   "trunc.w.d %0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4")])
  
+ (define_insn "fix_truncdfsi2_macro"
+   [(set (match_operand:SI 0 "register_operand" "=f")
+ 	(fix:SI (match_operand:DF 1 "register_operand" "f")))
+    (clobber (match_scratch:DF 2 "=d"))]
+   "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
+   "trunc.w.d %0,%1,%2"
+   [(set_attr "type"	"fcvt")
+    (set_attr "mode"	"DF")
+    (set_attr "length"	"36")])
  
! (define_expand "fix_truncsfsi2"
!   [(set (match_operand:SI 0 "register_operand" "=f")
! 	(fix:SI (match_operand:SF 1 "register_operand" "f")))]
    "TARGET_HARD_FLOAT"
  {
!   if (!ISA_HAS_TRUNC_W)
!     {
!       emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1]));
!       DONE;
!     }
! })
  
! (define_insn "fix_truncsfsi2_insn"
!   [(set (match_operand:SI 0 "register_operand" "=f")
! 	(fix:SI (match_operand:SF 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W"
!   "trunc.w.s %0,%1"
    [(set_attr "type"	"fcvt")
!    (set_attr "mode"	"DF")
!    (set_attr "length"	"4")])
  
+ (define_insn "fix_truncsfsi2_macro"
+   [(set (match_operand:SI 0 "register_operand" "=f")
+ 	(fix:SI (match_operand:SF 1 "register_operand" "f")))
+    (clobber (match_scratch:SF 2 "=d"))]
+   "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
+   "trunc.w.s %0,%1,%2"
+   [(set_attr "type"	"fcvt")
+    (set_attr "mode"	"DF")
+    (set_attr "length"	"36")])
  
  ;;; ??? trunc.l.d is mentioned in the appendix of the 1993 r4000/r4600 manuals
  ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
*************** move\\t%0,%z4\\n\\
*** 4376,4497 ****
  ;;; If this is disabled, then fixuns_truncdfdi2 must be disabled also.
  
  (define_insn "fix_truncdfdi2"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,*f,R,To")
! 	(fix:DI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
!    (clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
!   "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
!   "*
! {
!   rtx xoperands[10];
! 
!   if (which_alternative == 1)
!     return \"trunc.l.d %0,%1\";
! 
!   output_asm_insn (\"trunc.l.d %2,%1\", operands);
! 
!   xoperands[0] = operands[0];
!   xoperands[1] = operands[2];
!   output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
!   return \"\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"8,4,8,12")])
  
  
  ;;; ??? trunc.l.s is mentioned in the appendix of the 1993 r4000/r4600 manuals
  ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
  ;;; in the 1991 manuals.  The r4000 at Cygnus does not have this instruction.
  (define_insn "fix_truncsfdi2"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,*f,R,To")
! 	(fix:DI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
!    (clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
!   "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
!   "*
! {
!   rtx xoperands[10];
! 
!   if (which_alternative == 1)
!     return \"trunc.l.s %0,%1\";
! 
!   output_asm_insn (\"trunc.l.s %2,%1\", operands);
! 
!   xoperands[0] = operands[0];
!   xoperands[1] = operands[2];
!   output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
!   return \"\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"8,4,8,12")])
  
  
  (define_insn "floatsidf2"
!   [(set (match_operand:DF 0 "register_operand" "=f,f,f")
! 	(float:DF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
    "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
!   "*
! {
!   dslots_load_total++;
!   if (GET_CODE (operands[1]) == MEM)
!     return \"l.s\\t%0,%1%#\;cvt.d.w\\t%0,%0\";
! 
!   return \"mtc1\\t%1,%0%#\;cvt.d.w\\t%0,%0\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"12,16,12")])
  
  
  (define_insn "floatdidf2"
!   [(set (match_operand:DF 0 "register_operand" "=f,f,f")
! 	(float:DF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
!   "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
!   "*
! {
!   dslots_load_total++;
!   if (GET_CODE (operands[1]) == MEM)
!     return \"l.d\\t%0,%1%#\;cvt.d.l\\t%0,%0\";
! 
!   return \"dmtc1\\t%1,%0%#\;cvt.d.l\\t%0,%0\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"12,16,12")])
  
  
  (define_insn "floatsisf2"
!   [(set (match_operand:SF 0 "register_operand" "=f,f,f")
! 	(float:SF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
    "TARGET_HARD_FLOAT"
!   "*
! {
!   dslots_load_total++;
!   if (GET_CODE (operands[1]) == MEM)
!     return \"l.s\\t%0,%1%#\;cvt.s.w\\t%0,%0\";
! 
!   return \"mtc1\\t%1,%0%#\;cvt.s.w\\t%0,%0\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"12,16,12")])
  
  
  (define_insn "floatdisf2"
!   [(set (match_operand:SF 0 "register_operand" "=f,f,f")
! 	(float:SF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
!   "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
!   "*
! {
!   dslots_load_total++;
!   if (GET_CODE (operands[1]) == MEM)
!     return \"l.d\\t%0,%1%#\;cvt.s.l\\t%0,%0\";
! 
!   return \"dmtc1\\t%1,%0%#\;cvt.s.l\\t%0,%0\";
! }"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"12,16,12")])
  
  
  (define_expand "fixuns_truncdfsi2"
--- 4376,4441 ----
  ;;; If this is disabled, then fixuns_truncdfdi2 must be disabled also.
  
  (define_insn "fix_truncdfdi2"
!   [(set (match_operand:DI 0 "register_operand" "=f")
! 	(fix:DI (match_operand:DF 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
!   "trunc.l.d %0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4")])
  
  
  ;;; ??? trunc.l.s is mentioned in the appendix of the 1993 r4000/r4600 manuals
  ;;; but not in the chapter that describes the FPU.  It is not mentioned at all
  ;;; in the 1991 manuals.  The r4000 at Cygnus does not have this instruction.
  (define_insn "fix_truncsfdi2"
!   [(set (match_operand:DI 0 "register_operand" "=f")
! 	(fix:DI (match_operand:SF 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
!   "trunc.l.s %0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"4")])
  
  
  (define_insn "floatsidf2"
!   [(set (match_operand:DF 0 "register_operand" "=f")
! 	(float:DF (match_operand:SI 1 "register_operand" "f")))]
    "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
!   "cvt.d.w\\t%0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4")])
  
  
  (define_insn "floatdidf2"
!   [(set (match_operand:DF 0 "register_operand" "=f")
! 	(float:DF (match_operand:DI 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
!   "cvt.d.l\\t%0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"DF")
!    (set_attr "length"	"4")])
  
  
  (define_insn "floatsisf2"
!   [(set (match_operand:SF 0 "register_operand" "=f")
! 	(float:SF (match_operand:SI 1 "register_operand" "f")))]
    "TARGET_HARD_FLOAT"
!   "cvt.s.w\\t%0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"4")])
  
  
  (define_insn "floatdisf2"
!   [(set (match_operand:SF 0 "register_operand" "=f")
! 	(float:SF (match_operand:DI 1 "register_operand" "f")))]
!   "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT"
!   "cvt.s.l\\t%0,%1"
    [(set_attr "type"	"fcvt")
     (set_attr "mode"	"SF")
!    (set_attr "length"	"4")])
  
  
  (define_expand "fixuns_truncdfsi2"
*************** move\\t%0,%z4\\n\\
*** 5139,5155 ****
    "")
  
  (define_insn "movdi_internal2"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(match_operand:DI 1 "movdi_operand" "d,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
    "TARGET_64BIT && !TARGET_MIPS16
     && (register_operand (operands[0], DImode)
!        || se_register_operand (operands[1], DImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
         || operands[1] == CONST0_RTX (DImode))"
    "* return mips_move_2words (operands, insn); "
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
     (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,8,8,8,8,8,8,8")])
  
  (define_insn ""
    [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d")
--- 5083,5123 ----
    "")
  
  (define_insn "movdi_internal2"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,*f,*d,*R,*m,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(match_operand:DI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
    "TARGET_64BIT && !TARGET_MIPS16
     && (register_operand (operands[0], DImode)
!        || register_operand (operands[1], DImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
         || operands[1] == CONST0_RTX (DImode))"
    "* return mips_move_2words (operands, insn); "
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
     (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,8,8,8,8,8,8,8")])
! 
! ;; Sign-extended operands are reloaded using this instruction, so the
! ;; constraints must handle every combination for which:
! ;;
! ;;     mips_secondary_reload_class (CLASS_OF (operands[0]), DImode, true,
! ;;				    gen_rtx_SIGN_EXTEND (DImode, operands[1]))
! ;;
! ;; returns NO_REGS.  Also handle memory destinations, where allowed.
! ;;
! ;; This pattern is essentially a trimmed-down version of movdi_internal2.
! ;; The main difference is that dJ -> f and f -> d are the only constraints
! ;; involving float registers.  See mips_secondary_reload_class for details.
! (define_insn "*movdi_internal2_extend"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f,*x,*d,*x,*a,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(sign_extend:DI (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*J,*x,*d,*J,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D")))]
!   "TARGET_64BIT && !TARGET_MIPS16
!    && (register_operand (operands[0], DImode)
!        || register_operand (operands[1], DImode)
!        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
!        || operands[1] == CONST0_RTX (DImode))"
!   "* return mips_sign_extend (insn, operands[0], operands[1]);"
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
!    (set_attr "mode"	"DI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,4,4,8,8,8,8,8,8,8")])
  
  (define_insn ""
    [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d")
*************** move\\t%0,%z4\\n\\
*** 5534,5562 ****
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movsi_internal1"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
!   "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
!    && (register_operand (operands[0], SImode)
!        || register_operand (operands[1], SImode)
!        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
!   "* return mips_move_1word (operands, insn, FALSE);"
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
!    (set_attr "mode"	"SI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,4,8,4,8,4,4,4,4,4,4,8,4,4,8")])
! 
! (define_insn "movsi_internal2"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
!   "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16
     && (register_operand (operands[0], SImode)
         || register_operand (operands[1], SImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
    "* return mips_move_1word (operands, insn, FALSE);"
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
     (set_attr "mode"	"SI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])
  
  ;; This is the mips16 movsi instruction.  We accept a small integer as
  ;; the source if the destination is a GP memory reference.  This is
--- 5502,5518 ----
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movsi_internal"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,?*f,*d,*R,*m,*d,*z,*x,*d,*x,*d,*B*C*D,*B*C*D,*B*C*D,*d,*m,*R")
! 	(match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,*d*J,*R,*m,*f,*f,*f,*z,*d,J,*x,*d,*a,*d,*m,*R,*B*C*D,*B*C*D,*B*C*D"))]
!   "!TARGET_MIPS16
     && (register_operand (operands[0], SImode)
         || register_operand (operands[1], SImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
    "* return mips_move_1word (operands, insn, FALSE);"
!   [(set_attr "type"	"move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store")
     (set_attr "mode"	"SI")
!    (set_attr "length"	"4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])
  
  ;; This is the mips16 movsi instruction.  We accept a small integer as
  ;; the source if the destination is a GP memory reference.  This is
*************** move\\t%0,%z4\\n\\
*** 6040,6049 ****
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movhi_internal1"
!   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f,*f*z,*x,*d")
  	(match_operand:HI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
!   "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
     && (register_operand (operands[0], HImode)
         || register_operand (operands[1], HImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
--- 5996,6005 ----
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movhi_internal"
!   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
  	(match_operand:HI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
!   "!TARGET_MIPS16
     && (register_operand (operands[0], HImode)
         || register_operand (operands[1], HImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
*************** move\\t%0,%z4\\n\\
*** 6052,6069 ****
     (set_attr "mode"	"HI")
     (set_attr "length"	"4,4,4,8,4,8,4,4,4,4,4")])
  
- (define_insn "movhi_internal2"
-   [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
- 	(match_operand:HI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
-   "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16
-    && (register_operand (operands[0], HImode)
-        || register_operand (operands[1], HImode)
-        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
-   "* return mips_move_1word (operands, insn, TRUE);"
-   [(set_attr "type"	"move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
-    (set_attr "mode"	"HI")
-    (set_attr "length"	"4,4,4,8,4,8,4,4,4,4")])
- 
  (define_insn ""
    [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
  	(match_operand:HI 1 "general_operand"      "d,d,y,K,N,R,m,d,d,*x"))]
--- 6008,6013 ----
*************** move\\t%0,%z4\\n\\
*** 6162,6171 ****
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movqi_internal1"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
  	(match_operand:QI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
!   "TARGET_DEBUG_H_MODE && !TARGET_MIPS16
     && (register_operand (operands[0], QImode)
         || register_operand (operands[1], QImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
--- 6106,6115 ----
  ;; The difference between these two is whether or not ints are allowed
  ;; in FP registers (off by default, use -mdebugh to enable).
  
! (define_insn "movqi_internal"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
  	(match_operand:QI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
!   "!TARGET_MIPS16
     && (register_operand (operands[0], QImode)
         || register_operand (operands[1], QImode)
         || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
*************** move\\t%0,%z4\\n\\
*** 6173,6190 ****
    [(set_attr "type"	"move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo")
     (set_attr "mode"	"QI")
     (set_attr "length"	"4,4,4,8,4,8,4,4,4,4,4")])
- 
- (define_insn "movqi_internal2"
-   [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
- 	(match_operand:QI 1 "general_operand"       "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
-   "!TARGET_DEBUG_H_MODE && !TARGET_MIPS16
-    && (register_operand (operands[0], QImode)
-        || register_operand (operands[1], QImode)
-        || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
-   "* return mips_move_1word (operands, insn, TRUE);"
-   [(set_attr "type"	"move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
-    (set_attr "mode"	"QI")
-    (set_attr "length"	"4,4,4,8,4,8,4,4,4,4")])
  
  (define_insn ""
    [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d")
--- 6117,6122 ----

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-09  7:44 MIPS patch: allow ints in FPRs, rework some float patterns Richard Sandiford
@ 2002-07-11 21:40 ` Hans-Peter Nilsson
  2002-07-12  0:56   ` Richard Sandiford
  2002-07-15 15:05 ` Richard Henderson
  2002-07-22  3:01 ` Richard Sandiford
  2 siblings, 1 reply; 7+ messages in thread
From: Hans-Peter Nilsson @ 2002-07-11 21:40 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches

On 9 Jul 2002, Richard Sandiford wrote:
> The main problem with extending it to 64-bit integers is the lack
> of automatic sign extension.  When 32-bit values are stored in 64-bit
> float registers, the upper 32 bits are left undefined.  So the
> definition of LOAD_EXTEND_OP doesn't hold:
>
>     #define LOAD_EXTEND_OP(MODE) \
>       (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode) \
>        ? SIGN_EXTEND : ZERO_EXTEND)
>
> I've tried to avoid the problem by including 64-bit FPRs in
> CLASS_CANNOT_CHANGE_MODE.  Is that the right thing to do?
> Is it going to be enough?

Wouldn't it help to augment LOAD_EXTEND_OP to return NIL for
DFmode, SFmode (et. al.)?  Random though, beware of nonsense.

brgds, H-P

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-11 21:40 ` Hans-Peter Nilsson
@ 2002-07-12  0:56   ` Richard Sandiford
  0 siblings, 0 replies; 7+ messages in thread
From: Richard Sandiford @ 2002-07-12  0:56 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches

Hans-Peter Nilsson <hp@bitrange.com> writes:
> On 9 Jul 2002, Richard Sandiford wrote:
> > The main problem with extending it to 64-bit integers is the lack
> > of automatic sign extension.  When 32-bit values are stored in 64-bit
> > float registers, the upper 32 bits are left undefined.  So the
> > definition of LOAD_EXTEND_OP doesn't hold:
> >
> >     #define LOAD_EXTEND_OP(MODE) \
> >       (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode) \
> >        ? SIGN_EXTEND : ZERO_EXTEND)
> >
> > I've tried to avoid the problem by including 64-bit FPRs in
> > CLASS_CANNOT_CHANGE_MODE.  Is that the right thing to do?
> > Is it going to be enough?
> 
> Wouldn't it help to augment LOAD_EXTEND_OP to return NIL for
> DFmode, SFmode (et. al.)?  Random though, beware of nonsense.

I believe LOAD_EXTEND_OP only applies to integer modes.  The
problem (after the patch) is that you can load SImode values
into float regs too, and later access the float regs in DImode.
The upper 32 bits aren't defined if you do that.

Richard

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-09  7:44 MIPS patch: allow ints in FPRs, rework some float patterns Richard Sandiford
  2002-07-11 21:40 ` Hans-Peter Nilsson
@ 2002-07-15 15:05 ` Richard Henderson
  2002-07-16 14:26   ` Eric Christopher
  2002-07-22  3:01 ` Richard Sandiford
  2 siblings, 1 reply; 7+ messages in thread
From: Richard Henderson @ 2002-07-15 15:05 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches

On Tue, Jul 09, 2002 at 02:23:07PM +0100, Richard Sandiford wrote:
> The main problem with extending it to 64-bit integers is the lack
> of automatic sign extension.  When 32-bit values are stored in 64-bit
> float registers, the upper 32 bits are left undefined.  So the
> definition of LOAD_EXTEND_OP doesn't hold:
> 
>     #define LOAD_EXTEND_OP(MODE) \
>       (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode) \
>        ? SIGN_EXTEND : ZERO_EXTEND)
> 
> I've tried to avoid the problem by including 64-bit FPRs in
> CLASS_CANNOT_CHANGE_MODE.  Is that the right thing to do?
> Is it going to be enough?

I believe so.  Certainly Alpha has the same issue, but we've
been able to load integer data in fp registers for a long time.


r~

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-15 15:05 ` Richard Henderson
@ 2002-07-16 14:26   ` Eric Christopher
  0 siblings, 0 replies; 7+ messages in thread
From: Eric Christopher @ 2002-07-16 14:26 UTC (permalink / raw)
  To: gcc-patches

>> I've tried to avoid the problem by including 64-bit FPRs in
>> CLASS_CANNOT_CHANGE_MODE.  Is that the right thing to do? Is it going
>> to be enough?
> 
> I believe so.  Certainly Alpha has the same issue, but we've been able
> to load integer data in fp registers for a long time.
> 

Thanks for the response Richard, with the other thread going nuts I'd
been a bit busy to get back to this and that was the last issue I was
looking at. :)

Richard: Go ahead and check this in then.

Thanks.

-eric
 

-- 
I will not grease the monkey bars

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-09  7:44 MIPS patch: allow ints in FPRs, rework some float patterns Richard Sandiford
  2002-07-11 21:40 ` Hans-Peter Nilsson
  2002-07-15 15:05 ` Richard Henderson
@ 2002-07-22  3:01 ` Richard Sandiford
  2002-07-22 10:44   ` Eric Christopher
  2 siblings, 1 reply; 7+ messages in thread
From: Richard Sandiford @ 2002-07-22  3:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: echristo

Richard Sandiford <rsandifo@redhat.com> writes:
> Patch tested by bootstrapping on mips-sgi-irix6.5, and on a customised
> mipsisa32-elf build, with -mhard-float the default, and with EABI
> multlibs.  Test pattern was {-mabi=eabi}{-mips32,-mips64}{-EL,-EB}.

Unfortunately, I didn't customise the thing properly, so that test
pattern ended up testing the soft-float multilibs.  The patch was also
tested on mips64-elf, but 32-bit targets weren't tested like I thought.

The upshot being that the patch caused a miscompilation of libm in
32-bit mode.  The lowest-numbered register in a float pair always holds
the low word, so (subreg:SI (reg:DI $f0) 0) will get the wrong word on a
big endian target.  Kind of like the reverse of the HI_REGS situation on
little-endian targets.

Sorry for the screw-up.  Will just stick to stock targets from now on.

Patch tested on mips-elf and mips64-elf (in both cases using
{-EL,-EB}{-msoft-float,-mhard-float}).  OK to install?

Richard

	* config/mips/mips.h (CLASS_CANNOT_CHANGE_MODE): Include FP_REGS
	on big-endian targets.

Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.200
diff -c -p -d -r1.200 mips.h
*** config/mips/mips.h	17 Jul 2002 21:31:39 -0000	1.200
--- config/mips/mips.h	20 Jul 2002 10:48:24 -0000
*************** extern enum reg_class mips_char_to_class
*** 2249,2262 ****
     so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
     word as intended.
  
     Also, loading a 32-bit value into a 64-bit floating-point register
     will not sign-extend the value, despite what LOAD_EXTEND_OP says.
     We can't allow 64-bit float registers to change from a 32-bit
     mode to a 64-bit mode.  */
  
  #define CLASS_CANNOT_CHANGE_MODE					\
!   (TARGET_BIG_ENDIAN							\
!    ? (TARGET_FLOAT64 ? FP_REGS : NO_REGS)				\
     : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
  
  /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */
--- 2249,2266 ----
     so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
     word as intended.
  
+    Similarly, when using paired floating-point registers, the first
+    register holds the low word, regardless of endianness.  So in big
+    endian mode, (subreg:SI (reg:DF $f0) 0) does not get the high word
+    as intended.
+ 
     Also, loading a 32-bit value into a 64-bit floating-point register
     will not sign-extend the value, despite what LOAD_EXTEND_OP says.
     We can't allow 64-bit float registers to change from a 32-bit
     mode to a 64-bit mode.  */
  
  #define CLASS_CANNOT_CHANGE_MODE					\
!   (TARGET_BIG_ENDIAN ? FP_REGS						\
     : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
  
  /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: MIPS patch: allow ints in FPRs, rework some float patterns
  2002-07-22  3:01 ` Richard Sandiford
@ 2002-07-22 10:44   ` Eric Christopher
  0 siblings, 0 replies; 7+ messages in thread
From: Eric Christopher @ 2002-07-22 10:44 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches


> Sorry for the screw-up.  Will just stick to stock targets from now on.
> 

Heh. Don't worry about that, mipsisa32 is convenient in that it has both
32 and 64-bit :)

> Patch tested on mips-elf and mips64-elf (in both cases using
> {-EL,-EB}{-msoft-float,-mhard-float}).  OK to install?
> 
> Richard
> 
> 	* config/mips/mips.h (CLASS_CANNOT_CHANGE_MODE): Include FP_REGS
> 	on big-endian targets.
> 

OK.

-eric

-- 
I don't want a pony, I want a rocket
powered jetpack!

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2002-07-22 17:18 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-09  7:44 MIPS patch: allow ints in FPRs, rework some float patterns Richard Sandiford
2002-07-11 21:40 ` Hans-Peter Nilsson
2002-07-12  0:56   ` Richard Sandiford
2002-07-15 15:05 ` Richard Henderson
2002-07-16 14:26   ` Eric Christopher
2002-07-22  3:01 ` Richard Sandiford
2002-07-22 10:44   ` Eric Christopher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).