[PATCH] Fixes for the SUBREG_BYTE patch, SPARC fixes

Jakub Jelinek jj@sunsite.ms.mff.cuni.cz
Fri Jun 18 08:32:00 GMT 1999


Hi!

With this patch on top of the June, 15th SUBREG patch I was able to
bootstrap
sparc-redhat-linux-gnu
mips-sgi-irix6.5
i586-redhat-linux-gnu
sparc64-redhat-linux-gnu (bootstraps for the first time, but still has
			  some issues)

alpha-dec-osf4.0d bootstrap failed, but I guess it was not caused by the
SUBREG patch, because without it it crashed on the same file equally.

This patch also fixes sparc64 long double support, internal _Qp_* functions
take arguments as reference.

Now I have two questions: is there some way how to get for a REG_USERVAR_P
rtx during rtl generating phase a tree of the related variable? Without
that, I have no idea how to make gcc generate decent code for sparc64 long
double. Things like addtf3 if emulated in software are handled by functions
like void _Qp_add(long double *result, const long double *a, const long double *b);
My code below calls assign_stack_temp, but that has the bad property of
copying TFmode variables from memory to registers and back and forth. The
best would be if I could call something like put_var_into_stack. Any ideas
where this would be done best? Somewhere in expr.c layer and let backend set
some flags for the libfunc functions, or make some hook which could be
called from within md's define_expands? I don't mind if the routine tells
me it just cannot put it onto the stack (e.g. it did not find the user
variable decl for it), in such case I can still call assign_stack_temp, but
I'd like to optimize the common case.
Ugly example:
long double a, b, c; void foo(void) { c = a + b; }
foo:	save    %sp, -240, %sp
        sethi   %hi(a), %o4
        sethi   %hi(b), %o5
        ldx     [%o4+%lo(a)], %o0
        ldx     [%o5+%lo(b)], %o2
        ldx     [%o4+%lo(a+8)], %o1
        ldx     [%o5+%lo(b+8)], %o3
        stx     %o0, [%fp+1999]
        stx     %o1, [%fp+2007]
        stx     %o2, [%fp+1983]
        stx     %o3, [%fp+1991]
        add     %fp, 2015, %o0
        add     %fp, 1999, %o1
        add     %fp, 1983, %o2
        call    _Qp_add, 0
        sethi   %hi(c), %l0
        ldx     [%fp+2015], %o0
        ldx     [%fp+2023], %o1
        stx     %o0, [%l0+%lo(c)]
        stx     %o1, [%l0+%lo(c+8)]
        return  %i7+8
        nop
while
foo:	save    %sp, -240, %sp
        sethi   %hi(c), %o0
        sethi   %hi(a), %o1
	sethi	%hi(b), %o2
	or	%o0, %lo(c), %o0
	or	%o1, %lo(a), %o1
        call    _Qp_add, 0
	or	%o2, %lo(b), %o2
        return  %i7+8
        nop
is sufficient. And just think how it looks like when you do things like:
a*b+c*d*e.

The other question is about caller-saved/fixed/used registers. Wouldn't it
be useful to specify using some attributes that a certain function uses some
non-standard saved/fixed/used register sets? E.g. for the internal _Qp_*
functions it would not be a bad idea to specify they must not clobber any
FPU regs but one or two specific ones (in fact that's the case already, they
clobber %f60 and %f62), for sparc v7 .mul/.div etc. internal functions one
could specify they don't clobber any floating point registers, etc. For the
_Qp_* routines it would have the advantage of avoiding storage of all
floating point registers accross these internal calls, when the routine is
expected to have many floating point regs live around.

1999-06-18  Jakub Jelinek  <jj@ultra.linux.cz>

	* config/alpha/alpha.c (print_operand_address): Fix typo.
	* config/mips/mips.c (mips_move_1word, mips_move_2words,
	mips_secondary_reload_class): SUBREG_REGNO_OFFSET macro
	requires four arguments.
	* config/pyr/pyr.c (consecutive_operands): Likewise.
	* config/sh/sh.c (regs_used, machine_dependent_reorg): Likewise.
	* config/sparc/sparc.h: Define PROMOTE_FOR_CALLS_ONLY.
	(LEGITIMATE_CONSTANT_P): Allow TFmode constant zero.
	(*_LIBCALL): Only use for _Q_* routines, _Qp_* cannot be handled
	like that now.
	(INIT_TARGET_OPTABS): Likewise.
	* config/sparc/sparc.c (hard_??bit_mode_classes): Allow some TFmode
	capable registers to hold TCmode.
	(sparc_emit_lib_float_cmp): New function.
	* config/sparc/sparc.md: Use it instead of emit_lib_float_cmp.
	(clear_sfp, clear_dfp, clear_tf, clear_tfp): New patterns.
	(movtf): Special case TFmode constant zero set.
	(extendsftf2, extenddftf2, trunctfsf2, trunctfdf2, floatsitf2,
	floatditf2, fix_trunctfsi2, fix_trunctfdi2, addtf3, subtf3, multf3,
	divtf3, sqrttf3): New expands.
	(extendsftf2_hq, extenddftf2_hq, trunctfsf2_hq, trunctfdf2_hq,
	floatsitf2_hq, floatditf2_hq, fix_trunctfsi2_hq, fix_trunctfdi2_hq,
	addtf3_hq, subtf3_hq, multf3_hq, divtf3_hq, sqrttf3_hq): Rename from
	non-_hq patterns.
	* function.c (assign_params): Mark arguments SUBREG_PROMOTED_VAR_P
	if they are actually promoted by the caller and
	PROMOTE_FOR_CALLS_ONLY is true. Otherwise combiner will not know
	that their bits are already guaranteed to be zero or sign copies.
	* real.c (PUT_REAL): Clear unused bytes if long double is IEEE quad,
	otherwise cse won't be able to CSE together identical float
	constants.

--- ./config/alpha/alpha.c.jj2	Mon Jun 14 18:11:51 1999
+++ ./config/alpha/alpha.c	Fri Jun 18 08:44:11 1999
@@ -3009,7 +3009,8 @@ print_operand_address (file, addr)
     basereg = REGNO (addr);
   else if (GET_CODE (addr) == SUBREG
 	   && GET_CODE (SUBREG_REG (addr)) == REG)
-    basereg = REGNO (SUBREG_REG (addr)) + SUBREG_BYTE (addr) / GET_MODE_SIZE (addr);
+    basereg = REGNO (SUBREG_REG (addr))
+	      + SUBREG_BYTE (addr) / GET_MODE_SIZE (GET_MODE (addr));
   else if (GET_CODE (addr) == CONST_INT)
     offset = INTVAL (addr);
   else
--- ./config/mips/mips.c.jj2	Fri Jun 18 09:11:15 1999
+++ ./config/mips/mips.c	Wed Jun 16 14:13:19 1999
@@ -1674,8 +1674,9 @@ mips_move_1word (operands, insn, unsigne
 
   while (code0 == SUBREG)
     {
-      subreg_offset0 += SUBREG_REGNO_OFFSET (SUBREG_REG (op0),
+      subreg_offset0 += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op0)),
 					     GET_MODE (SUBREG_REG (op0)),
+					     SUBREG_BYTE (op0),
 					     GET_MODE (op0));
       op0 = SUBREG_REG (op0);
       code0 = GET_CODE (op0);
@@ -1683,8 +1684,9 @@ mips_move_1word (operands, insn, unsigne
 
   while (code1 == SUBREG)
     {
-      subreg_offset1 += SUBREG_REGNO_OFFSET (SUBREG_REG (op1),
+      subreg_offset1 += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op1)),
 					     GET_MODE (SUBREG_REG (op1)),
+					     SUBREG_BYTE (op1),
 					     GET_MODE (op1));
       op1 = SUBREG_REG (op1);
       code1 = GET_CODE (op1);
@@ -2070,8 +2072,9 @@ mips_move_2words (operands, insn)
 
   while (code0 == SUBREG)
     {
-      subreg_offset0 += SUBREG_REGNO_OFFSET (SUBREG_REG (op0),
+      subreg_offset0 += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op0)),
 					     GET_MODE (SUBREG_REG (op0)),
+					     SUBREG_BYTE (op0),
 					     GET_MODE (op0));
       op0 = SUBREG_REG (op0);
       code0 = GET_CODE (op0);
@@ -2085,8 +2088,9 @@ mips_move_2words (operands, insn)
 
   while (code1 == SUBREG)
     {
-      subreg_offset1 += SUBREG_REGNO_OFFSET (SUBREG_REG (op1),
+      subreg_offset1 += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op1)),
 					     GET_MODE (SUBREG_REG (op1)),
+					     SUBREG_BYTE (op1),
 					     GET_MODE (op1));
       op1 = SUBREG_REG (op1);
       code1 = GET_CODE (op1);
@@ -7164,8 +7168,9 @@ mips_secondary_reload_class (class, mode
 	{
 	  while (GET_CODE (x) == SUBREG)
 	    {
-	      off += SUBREG_REGNO_OFFSET (SUBREG_REG (x),
+	      off += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (x)),
 					  GET_MODE (SUBREG_REG (x)),
+					  SUBREG_BYTE (x),
 					  GET_MODE (x));
 	      x = SUBREG_REG (x);
 	    }
--- ./config/pyr/pyr.c.jj2	Fri Jun 11 12:59:49 1999
+++ ./config/pyr/pyr.c	Wed Jun 16 17:46:39 1999
@@ -429,8 +429,9 @@ consecutive_operands (op0, op1)
     {
       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD)
 	return 0;
-      regno_off0 = SUBREG_REGNO_OFFSET (SUBREG_REG (op0),
+      regno_off0 = SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op0)),
 					GET_MODE (SUBREG_REG (op0)),
+					SUBREG_BYTE (op0),
 					GET_MODE (op0));
       op0 = SUBREG_REG (op0);
       code0 = REG;
@@ -441,8 +442,9 @@ consecutive_operands (op0, op1)
     {
       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD)
 	return 0;
-      regno_off1 = SUBREG_REGNO_OFFSET (SUBREG_REG (op1),
+      regno_off1 = SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (op1)),
 					GET_MODE (SUBREG_REG (op1)),
+					SUBREG_BYTE (op1),
 					GET_MODE (op1));
       op1 = SUBREG_REG (op1);
       code1 = REG;
--- ./config/sh/sh.c.jj2	Fri Jun 11 12:59:49 1999
+++ ./config/sh/sh.c	Wed Jun 16 17:48:18 1999
@@ -2406,10 +2406,10 @@ regs_used (x, is_dest)
 	if (REGNO (y) < 16)
 	  return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
 		  << (REGNO (y) +
-		      SUBREG_REGNO_OFFSET (SUBREG_REG (x),
-					   GET_MODE (SUBREG_REG (x)),
-					   GET_MOD (x)) +
-		      is_dest));
+		      SUBREG_REGNO_OFFSET (REGNO (y),
+					   GET_MODE (y),
+					   SUBREG_BYTE (x),
+					   GET_MOD (x)) + is_dest));
 	return 0;
       }
     case SET:
@@ -3091,8 +3091,9 @@ machine_dependent_reorg (first)
 		      mode = HImode;
 		      while (GET_CODE (dst) == SUBREG)
 			{
-			  offset += SUBREG_REGNO_OFFSET (SUBREG_REG (dst),
+			  offset += SUBREG_REGNO_OFFSET (REGNO (SUBREG_REG (dst)),
 							 GET_MODE (SUBREG_REG (dst)),
+							 SUBREG_BYTE (dst),
 							 GET_MODE (dst));
 			  dst = SUBREG_REG (dst);
 			}
--- ./config/sparc/sparc.h.jj2	Tue Jun 15 13:55:31 1999
+++ ./config/sparc/sparc.h	Thu Jun 17 17:30:42 1999
@@ -787,6 +787,18 @@ if (TARGET_ARCH64				\
    for this value.  */
 #define PROMOTE_FUNCTION_RETURN
 
+/* Define this macro if the promotion described by PROMOTE_MODE
+   should _only_ be performed for outgoing function arguments or
+   function return values, as specified by PROMOTE_FUNCTION_ARGS
+   and PROMOTE_FUNCTION_RETURN, respectively.  */
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
+   for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime test
+   for this value.  For TARGET_ARCH64 we need it, as we don't have instructions
+   for arithmetic operations which do zero/sign extension at the same time,
+   so without this we end up with a srl/sra after every assignment to an
+   user variable,  which means very very bad code.  */
+#define PROMOTE_FOR_CALL_ONLY
+
 /* Allocation boundary (in *bits*) for storing arguments in argument list.  */
 #define PARM_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
 
@@ -2389,7 +2401,9 @@ extern struct rtx_def *sparc_builtin_sav
 
 #define LEGITIMATE_CONSTANT_P(X) 					\
   (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode || 		\
-   (TARGET_VIS && (GET_MODE (X) == SFmode || GET_MODE (X) == DFmode) &&	\
+   (TARGET_VIS &&							\
+    (GET_MODE (X) == SFmode || GET_MODE (X) == DFmode ||		\
+     GET_MODE (X) == TFmode) &&						\
     fp_zero_operand (X)))
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
@@ -2776,61 +2790,63 @@ do {                                    
 #define MULSI3_LIBCALL "*.umul"
 
 /* Define library calls for quad FP operations.  These are all part of the
-   SPARC ABI.
-   ??? ARCH64 still does not work as the _Qp_* routines take pointers.  */
-#define ADDTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_add" : "_Q_add")
-#define SUBTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_sub" : "_Q_sub")
-#define NEGTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_neg" : "_Q_neg")
-#define MULTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_mul" : "_Q_mul")
-#define DIVTF3_LIBCALL (TARGET_ARCH64 ? "_Qp_div" : "_Q_div")
-#define FLOATSITF2_LIBCALL (TARGET_ARCH64 ? "_Qp_itoq" : "_Q_itoq")
-#define FIX_TRUNCTFSI2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtoi" : "_Q_qtoi")
-#define FIXUNS_TRUNCTFSI2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtoui" : "_Q_qtou")
-#define EXTENDSFTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_stoq" : "_Q_stoq")
-#define TRUNCTFSF2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtos" :  "_Q_qtos")
-#define EXTENDDFTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_dtoq" : "_Q_dtoq")
-#define TRUNCTFDF2_LIBCALL (TARGET_ARCH64 ? "_Qp_qtod" : "_Q_qtod")
-#define EQTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq")
-#define NETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne")
-#define GTTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt")
-#define GETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge")
-#define LTTF2_LIBCALL (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt")
-#define LETF2_LIBCALL (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle")
+   SPARC 32bit ABI.  */
+#define ADDTF3_LIBCALL "_Q_add"
+#define SUBTF3_LIBCALL "_Q_sub"
+#define NEGTF2_LIBCALL "_Q_neg"
+#define MULTF3_LIBCALL "_Q_mul"
+#define DIVTF3_LIBCALL "_Q_div"
+#define FLOATSITF2_LIBCALL "_Q_itoq"
+#define FIX_TRUNCTFSI2_LIBCALL "_Q_qtoi"
+#define FIXUNS_TRUNCTFSI2_LIBCALL "_Q_qtou"
+#define EXTENDSFTF2_LIBCALL "_Q_stoq"
+#define TRUNCTFSF2_LIBCALL "_Q_qtos"
+#define EXTENDDFTF2_LIBCALL "_Q_dtoq"
+#define TRUNCTFDF2_LIBCALL "_Q_qtod"
+#define EQTF2_LIBCALL "_Q_feq"
+#define NETF2_LIBCALL "_Q_fne"
+#define GTTF2_LIBCALL "_Q_fgt"
+#define GETF2_LIBCALL "_Q_fge"
+#define LTTF2_LIBCALL "_Q_flt"
+#define LETF2_LIBCALL "_Q_fle"
 
 /* We can define the TFmode sqrt optab only if TARGET_FPU.  This is because
    with soft-float, the SFmode and DFmode sqrt instructions will be absent,
    and the compiler will notice and try to use the TFmode sqrt instruction
    for calls to the builtin function sqrt, but this fails.  */
-#define INIT_TARGET_OPTABS						\
-  do {									\
-    add_optab->handlers[(int) TFmode].libfunc				\
-      = gen_rtx_SYMBOL_REF (Pmode, ADDTF3_LIBCALL);			\
-    sub_optab->handlers[(int) TFmode].libfunc				\
-      = gen_rtx_SYMBOL_REF (Pmode, SUBTF3_LIBCALL);			\
-    neg_optab->handlers[(int) TFmode].libfunc				\
-      = gen_rtx_SYMBOL_REF (Pmode, NEGTF2_LIBCALL);			\
-    smul_optab->handlers[(int) TFmode].libfunc				\
-      = gen_rtx_SYMBOL_REF (Pmode, MULTF3_LIBCALL);			\
-    flodiv_optab->handlers[(int) TFmode].libfunc			\
-      = gen_rtx_SYMBOL_REF (Pmode, DIVTF3_LIBCALL);			\
-    eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EQTF2_LIBCALL);		\
-    netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, NETF2_LIBCALL);		\
-    gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GTTF2_LIBCALL);		\
-    getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GETF2_LIBCALL);		\
-    lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LTTF2_LIBCALL);		\
-    letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LETF2_LIBCALL);		\
-    trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFSF2_LIBCALL);   \
-    trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFDF2_LIBCALL);   \
-    extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDSFTF2_LIBCALL); \
-    extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDDFTF2_LIBCALL); \
-    floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, FLOATSITF2_LIBCALL);    \
-    fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, FIX_TRUNCTFSI2_LIBCALL);  \
-    fixunstfsi_libfunc							\
-      = gen_rtx_SYMBOL_REF (Pmode, FIXUNS_TRUNCTFSI2_LIBCALL);		\
-    if (TARGET_FPU)							\
-      sqrt_optab->handlers[(int) TFmode].libfunc			\
-	= gen_rtx_SYMBOL_REF (Pmode, "_Q_sqrt");			\
-    INIT_SUBTARGET_OPTABS;						\
+#define INIT_TARGET_OPTABS							\
+  do {										\
+    if (TARGET_ARCH32)								\
+      {										\
+	add_optab->handlers[(int) TFmode].libfunc				\
+	  = gen_rtx_SYMBOL_REF (Pmode, ADDTF3_LIBCALL);				\
+	sub_optab->handlers[(int) TFmode].libfunc				\
+	  = gen_rtx_SYMBOL_REF (Pmode, SUBTF3_LIBCALL);				\
+	neg_optab->handlers[(int) TFmode].libfunc				\
+	  = gen_rtx_SYMBOL_REF (Pmode, NEGTF2_LIBCALL);				\
+	smul_optab->handlers[(int) TFmode].libfunc				\
+	  = gen_rtx_SYMBOL_REF (Pmode, MULTF3_LIBCALL);				\
+	flodiv_optab->handlers[(int) TFmode].libfunc				\
+	  = gen_rtx_SYMBOL_REF (Pmode, DIVTF3_LIBCALL);				\
+	eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EQTF2_LIBCALL);		\
+	netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, NETF2_LIBCALL);		\
+	gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GTTF2_LIBCALL);		\
+	getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GETF2_LIBCALL);		\
+	lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LTTF2_LIBCALL);		\
+	letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LETF2_LIBCALL);		\
+	trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFSF2_LIBCALL);	\
+	trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFDF2_LIBCALL);	\
+	extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDSFTF2_LIBCALL);	\
+	extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDDFTF2_LIBCALL);	\
+	floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, FLOATSITF2_LIBCALL);	\
+	fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, FIX_TRUNCTFSI2_LIBCALL);	\
+	fixunstfsi_libfunc							\
+	  = gen_rtx_SYMBOL_REF (Pmode, FIXUNS_TRUNCTFSI2_LIBCALL);		\
+	if (TARGET_FPU)								\
+	  sqrt_optab->handlers[(int) TFmode].libfunc				\
+	    = gen_rtx_SYMBOL_REF (Pmode, "_Q_sqrt");				\
+      }										\
+    INIT_SUBTARGET_OPTABS;							\
   } while (0)
 
 /* This is meant to be redefined in the host dependent files */
@@ -3496,6 +3512,7 @@ extern int text_segment_operand ();
 extern int uns_small_int ();
 extern int v9_regcmp_op ();
 extern int v9_regcmp_p ();
+extern void sparc_emit_float_lib_cmp ();
 
 extern unsigned long sparc_flat_compute_frame_size ();
 extern unsigned long sparc_type_code ();
--- ./config/sparc/sparc.md.jj2	Thu Jun 17 11:48:30 1999
+++ ./config/sparc/sparc.md	Fri Jun 18 11:20:28 1999
@@ -836,7 +836,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
       emit_insn (gen_sne (operands[0]));
       DONE;
     }      
@@ -889,7 +889,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
       emit_insn (gen_sne (operands[0]));
       DONE;
     }      
@@ -931,7 +931,7 @@
 {
   if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
       emit_insn (gen_sne (operands[0]));
       DONE;
     }
@@ -952,7 +952,7 @@
 {
   if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
       emit_insn (gen_sne (operands[0]));
       DONE;
     }
@@ -973,7 +973,7 @@
 {
   if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
       emit_insn (gen_sne (operands[0]));
       DONE;
     }
@@ -1607,7 +1607,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -1631,7 +1631,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -1655,7 +1655,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -1689,7 +1689,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -1723,7 +1723,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -1757,7 +1757,7 @@
     }
   else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
     {
-      emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+      sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
       emit_jump_insn (gen_bne (operands[0]));
       DONE;
     }      
@@ -2808,6 +2808,16 @@
   [(set_attr "type" "fpmove")
    (set_attr "length" "1")])
 
+(define_insn "*clear_sfp"
+  [(set (match_operand:SF 0 "general_operand" "=m")
+        (match_operand:SF 1 "" ""))]
+  "! TARGET_LIVE_G0
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && fp_zero_operand (operands[1])"
+  "st\\t%%g0, %0"
+  [(set_attr "type" "store")
+   (set_attr "length" "1")])
+
 (define_insn "*movsf_const_intreg"
   [(set (match_operand:SF 0 "general_operand" "=f,r")
         (match_operand:SF 1 ""                 "m,F"))]
@@ -2974,12 +2984,25 @@
         (match_operand:DF 1 "" ""))]
   "TARGET_VIS
    && GET_CODE (operands[1]) == CONST_DOUBLE
-   && GET_CODE (operands[0]) == REG
+   && (GET_CODE (operands[0]) == REG
+       || (GET_CODE (operands[0]) == SUBREG
+	   && GET_CODE (SUBREG_REG (operands[0])) == REG))
    && fp_zero_operand (operands[1])"
   "fzero\\t%0"
   [(set_attr "type" "fpmove")
    (set_attr "length" "1")])
 
+(define_insn "*clear_dfp"
+  [(set (match_operand:DF 0 "general_operand" "=m")
+        (match_operand:DF 1 "" ""))]
+  "! TARGET_LIVE_G0
+   && TARGET_V9
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && fp_zero_operand (operands[1])"
+  "stx\\t%%g0, %0"
+  [(set_attr "type" "store")
+   (set_attr "length" "1")])
+
 (define_insn "*movdf_const_intreg_sp32"
   [(set (match_operand:DF 0 "general_operand" "=e,e,r")
         (match_operand:DF 1 ""                 "T,o,F"))]
@@ -3344,6 +3367,59 @@
   DONE;
 }")
 
+(define_insn "*clear_tf"
+  [(set (match_operand:TF 0 "general_operand" "=e")
+        (match_operand:TF 1 "" ""))]
+  "TARGET_VIS
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && GET_CODE (operands[0]) == REG
+   && fp_zero_operand (operands[1])"
+  "#"
+  [(set_attr "type" "fpmove")
+   (set_attr "length" "2")])
+
+(define_split
+  [(set (match_operand:TF 0 "general_operand" "")
+        (match_operand:TF 1 "" ""))]
+  "TARGET_VIS && reload_completed
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && GET_CODE (operands[0]) == REG
+   && fp_zero_operand (operands[1])"
+  [(set (subreg:DF (match_dup 0) 0) (match_dup 1))
+   (set (subreg:DF (match_dup 0) 8) (match_dup 1))]
+  "
+{
+  operands[1] = CONST0_RTX (DFmode);
+}
+")
+
+(define_insn "*clear_tfp"
+  [(set (match_operand:TF 0 "general_operand" "=e")
+        (match_operand:TF 1 "" ""))]
+  "! TARGET_LIVE_G0
+   && TARGET_V9
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && GET_CODE (operands[0]) == REG
+   && fp_zero_operand (operands[1])"
+  "#"
+  [(set_attr "type" "fpmove")
+   (set_attr "length" "2")])
+
+(define_split
+  [(set (match_operand:TF 0 "general_operand" "=m")
+        (match_operand:TF 1 "" ""))]
+  "! TARGET_LIVE_G0
+   && TARGET_V9 && reload_completed
+   && GET_CODE (operands[1]) == CONST_DOUBLE
+   && fp_zero_operand (operands[1])"
+  [(set (subreg:DF (match_dup 0) 0) (match_dup 1))
+   (set (subreg:DF (match_dup 0) 8) (match_dup 1))]
+  "
+{
+  operands[1] = CONST0_RTX (DFmode);
+}
+")
+
 (define_expand "movtf"
   [(set (match_operand:TF 0 "general_operand" "")
 	(match_operand:TF 1 "general_operand" ""))]
@@ -3354,6 +3430,11 @@
   if (GET_CODE (operands[0]) == REG
       && CONSTANT_P (operands[1]))
     {
+      if (TARGET_VIS
+          && GET_CODE (operands[1]) == CONST_DOUBLE
+	  && fp_zero_operand (operands[1]))
+	goto movtf_is_ok;
+
       /* emit_group_store will send such bogosity to us when it is
          not storing directly into memory.  So fix this up to avoid
          crashes in output_constant_pool.  */
@@ -4544,7 +4625,29 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "extendsftf2"
+(define_expand "extendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+	(float_extend:TF
+	 (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_stoq\"), 0,
+			 VOIDmode, 2,
+			 XEXP (slot0, 0), Pmode,
+			 operands[1], SFmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*extendsftf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(float_extend:TF
 	 (match_operand:SF 1 "register_operand" "f")))]
@@ -4553,7 +4656,29 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "extenddftf2"
+(define_expand "extenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+	(float_extend:TF
+	 (match_operand:DF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_dtoq\"), 0,
+			 VOIDmode, 2,
+			 XEXP (slot0, 0), Pmode,
+			 operands[1], DFmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*extenddftf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(float_extend:TF
 	 (match_operand:DF 1 "register_operand" "e")))]
@@ -4571,7 +4696,28 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "trunctfsf2"
+(define_expand "trunctfsf2"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+	(float_truncate:SF
+	 (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtos\"),
+			       operands[0], 0, SFmode, 1,
+			       XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*trunctfsf2_hq"
   [(set (match_operand:SF 0 "register_operand" "=f")
 	(float_truncate:SF
 	 (match_operand:TF 1 "register_operand" "e")))]
@@ -4580,7 +4726,28 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "trunctfdf2"
+(define_expand "trunctfdf2"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+	(float_truncate:DF
+	 (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtod\"),
+			       operands[0], 0, DFmode, 1,
+			       XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*trunctfdf2_hq"
   [(set (match_operand:DF 0 "register_operand" "=e")
 	(float_truncate:DF
 	 (match_operand:TF 1 "register_operand" "e")))]
@@ -4607,7 +4774,28 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "floatsitf2"
+(define_expand "floatsitf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+	(float:TF (match_operand:SI 1 "register_operand" "f")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_itoq\"), 0,
+			 VOIDmode, 2,
+			 XEXP (slot0, 0), Pmode,
+			 operands[1], SImode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*floatsitf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(float:TF (match_operand:SI 1 "register_operand" "f")))]
   "TARGET_FPU && TARGET_HARD_QUAD"
@@ -4633,7 +4821,28 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "floatditf2"
+(define_expand "floatditf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+	(float:TF (match_operand:DI 1 "register_operand" "e")))]
+  "TARGET_FPU && TARGET_V9 && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_xtoq\"), 0,
+			 VOIDmode, 2,
+			 XEXP (slot0, 0), Pmode,
+			 operands[1], DImode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*floatditf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(float:TF (match_operand:DI 1 "register_operand" "e")))]
   "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
@@ -4660,7 +4869,27 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "fix_trunctfsi2"
+(define_expand "fix_trunctfsi2"
+  [(set (match_operand:SI 0 "register_operand" "=f")
+	(fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtoi\"),
+			       operands[0], 0, SImode, 1,
+			       XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*fix_trunctfsi2_hq"
   [(set (match_operand:SI 0 "register_operand" "=f")
 	(fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
   "TARGET_FPU && TARGET_HARD_QUAD"
@@ -4686,7 +4915,27 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "fix_trunctfdi2"
+(define_expand "fix_trunctfdi2"
+  [(set (match_operand:DI 0 "register_operand" "=e")
+	(fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+  "TARGET_V9 && TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot0, operands[1]));
+      emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_qtox\"),
+			       operands[0], 0, DImode, 1,
+			       XEXP (slot0, 0), Pmode);
+      DONE;
+    }
+}")
+
+(define_insn "*fix_trunctfdi2_hq"
   [(set (match_operand:DI 0 "register_operand" "=e")
 	(fix:DI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
   "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
@@ -6568,7 +6817,34 @@
 
 ;; Floating point arithmetic instructions.
 
-(define_insn "addtf3"
+(define_expand "addtf3"
+  [(set (match_operand:TF 0 "general_operand" "")
+	(plus:TF (match_operand:TF 1 "general_operand" "")
+		 (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+      emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_add\"), 0,
+			 VOIDmode, 3,
+			 XEXP (slot0, 0), Pmode,
+			 XEXP (slot1, 0), Pmode,
+			 XEXP (slot2, 0), Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*addtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(plus:TF (match_operand:TF 1 "register_operand" "e")
 		 (match_operand:TF 2 "register_operand" "e")))]
@@ -6595,7 +6871,34 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "subtf3"
+(define_expand "subtf3"
+  [(set (match_operand:TF 0 "general_operand" "")
+	(minus:TF (match_operand:TF 1 "general_operand" "")
+		  (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+      emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_sub\"), 0,
+			 VOIDmode, 3,
+			 XEXP (slot0, 0), Pmode,
+			 XEXP (slot1, 0), Pmode,
+			 XEXP (slot2, 0), Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*subtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(minus:TF (match_operand:TF 1 "register_operand" "e")
 		  (match_operand:TF 2 "register_operand" "e")))]
@@ -6622,7 +6925,34 @@
   [(set_attr "type" "fp")
    (set_attr "length" "1")])
 
-(define_insn "multf3"
+(define_expand "multf3"
+  [(set (match_operand:TF 0 "general_operand" "")
+	(mult:TF (match_operand:TF 1 "general_operand" "")
+		 (match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+      emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_mul\"), 0,
+			 VOIDmode, 3,
+			 XEXP (slot0, 0), Pmode,
+			 XEXP (slot1, 0), Pmode,
+			 XEXP (slot2, 0), Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*multf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(mult:TF (match_operand:TF 1 "register_operand" "e")
 		 (match_operand:TF 2 "register_operand" "e")))]
@@ -6667,8 +6997,35 @@
   [(set_attr "type" "fpmul")
    (set_attr "length" "1")])
 
+(define_expand "divtf3"
+  [(set (match_operand:TF 0 "general_operand" "")
+	(div:TF (match_operand:TF 1 "general_operand" "")
+		(match_operand:TF 2 "general_operand" "")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1, slot2;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot2 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+      emit_insn (gen_rtx_SET (VOIDmode, slot2, operands[2]));
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_div\"), 0,
+			 VOIDmode, 3,
+			 XEXP (slot0, 0), Pmode,
+			 XEXP (slot1, 0), Pmode,
+			 XEXP (slot2, 0), Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
 ;; don't have timing for quad-prec. divide.
-(define_insn "divtf3"
+(define_insn "*divtf3_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(div:TF (match_operand:TF 1 "register_operand" "e")
 		(match_operand:TF 2 "register_operand" "e")))]
@@ -6939,7 +7296,30 @@
   [(set_attr "type" "fpmove")
    (set_attr "length" "1")])
 
-(define_insn "sqrttf2"
+(define_expand "sqrttf2"
+  [(set (match_operand:TF 0 "register_operand" "=e")
+	(sqrt:TF (match_operand:TF 1 "register_operand" "e")))]
+  "TARGET_FPU && (TARGET_HARD_QUAD || TARGET_ARCH64)"
+  "
+{
+  if (! TARGET_HARD_QUAD)
+    {
+      rtx slot0, slot1;
+
+      slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+
+      emit_insn (gen_rtx_SET (VOIDmode, slot1, operands[1]));
+      emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \"_Qp_sqrt\"), 0,
+			 VOIDmode, 2,
+			 XEXP (slot0, 0), Pmode,
+			 XEXP (slot1, 0), Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0], slot0));
+      DONE;
+    }
+}")
+
+(define_insn "*sqrttf2_hq"
   [(set (match_operand:TF 0 "register_operand" "=e")
 	(sqrt:TF (match_operand:TF 1 "register_operand" "e")))]
   "TARGET_FPU && TARGET_HARD_QUAD"
--- ./config/sparc/sparc.c.jj2	Tue Jun 15 16:34:01 1999
+++ ./config/sparc/sparc.c	Fri Jun 18 15:28:45 1999
@@ -2724,13 +2724,8 @@ enum sparc_mode_class {
 /* Modes for double-float and smaller quantities.  */
 #define DF_MODES (S_MODES | D_MODES)
 
-#define DF_MODES64 DF_MODES
-
 /* Modes for double-float only quantities.  */
-#define DF_ONLY_MODES ((1 << (int) DF_MODE) | (1 << (int) D_MODE))
-
-/* Modes for double-float and larger quantities.  */
-#define DF_UP_MODES (DF_ONLY_MODES | TF_ONLY_MODES)
+#define DF_MODES_NO_S (D_MODES)
 
 /* Modes for quad-float only quantities.  */
 #define TF_ONLY_MODES (1 << (int) TF_MODE)
@@ -2738,7 +2733,16 @@ enum sparc_mode_class {
 /* Modes for quad-float and smaller quantities.  */
 #define TF_MODES (DF_MODES | TF_ONLY_MODES)
 
-#define TF_MODES64 (DF_MODES64 | TF_ONLY_MODES)
+/* Modes for quad-float and double-float quantities.  */
+#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES)
+
+/* Modes for quad-float pair only quantities.  */
+#define OF_ONLY_MODES (1 << (int) OF_MODE)
+
+/* Modes for quad-float pairs and smaller quantities.  */
+#define OF_MODES (TF_MODES | OF_ONLY_MODES)
+
+#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES)
 
 /* Modes for condition codes.  */
 #define CC_MODES (1 << (int) CC_MODE)
@@ -2759,17 +2763,17 @@ static int hard_32bit_mode_classes[] = {
   T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
 
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
 
   /* FP regs f32 to f63.  Only the even numbered registers actually exist,
      and none can hold SFmode/SImode values.  */
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
 
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
@@ -2784,17 +2788,17 @@ static int hard_64bit_mode_classes[] = {
   T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
   O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
 
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
 
   /* FP regs f32 to f63.  Only the even numbered registers actually exist,
      and none can hold SFmode/SImode values.  */
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
 
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
@@ -4525,6 +4529,78 @@ output_cbranch (op, label, reversed, ann
   return string;
 }
 
+/* Emit a library call comparison between floating point X and Y.
+   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
+   values as arguments instead of the TFmode registers themselves,
+   that's why we cannot call emit_float_lib_cmp.  */
+
+void
+sparc_emit_float_lib_cmp (x, y, comparison)
+     rtx x, y;
+     enum rtx_code comparison;
+{
+  const char *qpfunc;
+  rtx slot0, slot1, result;
+
+  if (!TARGET_ARCH64 || GET_MODE (x) != TFmode)
+    {
+      emit_float_lib_cmp (x, y, comparison);
+      return;
+    }
+
+  switch (comparison)
+    {
+    case EQ:
+      qpfunc = "_Qp_feq";
+      break;
+
+    case NE:
+      qpfunc = "_Qp_fne";
+      break;
+
+    case GT:
+      qpfunc = "_Qp_fgt";
+      break;
+
+    case GE:
+      qpfunc = "_Qp_fge";
+      break;
+
+    case LT:
+      qpfunc = "_Qp_flt";
+      break;
+
+    case LE:
+      qpfunc = "_Qp_fle";
+      break;
+
+    default:
+      abort();
+      break;
+    }
+
+  slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+  slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+      
+  emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+  emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+
+  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, qpfunc), 1,
+                     DImode, 2,
+                     XEXP (slot0, 0), Pmode,
+                     XEXP (slot1, 0), Pmode);
+
+  /* Immediately move the result of the libcall into a pseudo
+     register so reload doesn't clobber the value if it needs
+     the return register for a spill reg.  */
+  result = gen_reg_rtx (DImode);
+  emit_move_insn (result, hard_libcall_value (DImode));
+
+  emit_cmp_insn (result, const0_rtx, comparison,
+                 NULL_RTX, DImode, 0, 0);
+}
+          
 /* Return the string to output a conditional branch to LABEL, testing
    register REG.  LABEL is the operand number of the label; REG is the
    operand number of the reg.  OP is the conditional expression.  The mode
--- ./function.c.jj2	Mon Jun 14 17:58:16 1999
+++ ./function.c	Wed Jun 16 16:35:24 1999
@@ -4791,6 +4791,22 @@ assign_parms (fndecl, second_time)
 	      push_to_sequence (conversion_insns);
 	      tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
+#ifdef PROMOTE_FOR_CALL_ONLY
+	      if (GET_CODE (tempreg) == SUBREG
+		  && GET_MODE (tempreg) == nominal_mode
+		  && GET_CODE (SUBREG_REG (tempreg)) == REG
+		  && nominal_mode == passed_mode
+		  && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
+		  && GET_MODE_SIZE (GET_MODE (tempreg))
+		     < GET_MODE_SIZE (GET_MODE (entry_parm)))
+		{
+		  /* The argument is already sign/zero extended, so note it
+		     into the subreg.  */
+		  SUBREG_PROMOTED_VAR_P (tempreg) = 1;
+		  SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp;
+		}
+#endif
+
 	      /* TREE_USED gets set erroneously during expand_assignment.  */
 	      save_tree_used = TREE_USED (parm);
 	      expand_assignment (parm,
--- ./real.c.jj2	Sat Mar  6 06:34:25 1999
+++ ./real.c	Thu Jun 17 11:22:48 1999
@@ -260,7 +260,12 @@ do {						\
 #define MAXDECEXP 4932
 #define MINDECEXP -4977
 #define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
-#define PUT_REAL(e,r) bcopy ((char *) e, (char *) r, 2*NE)
+#define PUT_REAL(e,r)				\
+do {						\
+  if (2*NE < sizeof(*r))			\
+    bzero((char *)r, sizeof(*r));		\
+  bcopy ((char *) e, (char *) r, 2*NE);		\
+} while (0)
 #else
 #define NE 6
 #define MAXDECEXP 4932

	

Cheers,
    Jakub
___________________________________________________________________
Jakub Jelinek | jj@sunsite.mff.cuni.cz | http://sunsite.mff.cuni.cz
Administrator of SunSITE Czech Republic, MFF, Charles University
___________________________________________________________________
UltraLinux  |  http://ultra.linux.cz/  |  http://ultra.penguin.cz/
Linux version 2.3.6 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________


More information about the Gcc-patches mailing list