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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Add workarounds for VR4122 errata


This patch adds a -mfix-vr4122-bugs option to gcc[*].  It's based on
something that DJ Delorie wrote two years ago, but with some minor
updates to make it work with current sources.

Note that I deliberately left %{mno-fix-vr4122-bugs} out of ASM_SPEC.
The negative of the gas option is -no-mfix-vr4122-bugs, and I'm not sure
whether to embrace or change that yet.

Tested on mips64vrel-elf, applied to trunk.

Richard

[*] -mfix-vr4122 would fit better with the new world order, but the
    equivalent option is already understood by gas, and is already
    out in the wild.


2004-03-24  DJ Delorie  <dj@redhat.com>
	    Richard Sandiford  <rsandifo@redhat.com>

	* config/mips/mips.h (MASK_FIX_VR4122, TARGET_FIX_VR4122): New macros.
	(TARGET_SWITCHES): Add -mfix-vr4122-bugs and -mno-fix-vr4122-bugs.
	(ASM_SPEC): Pass down -mfix-vr4122-bugs.
	* config/mips/mips.c (mips_avoid_hazards): Don't emit whole functions
	in .set noreorder and .set nomacro if TARGET_FIX_VR4122.
	(mips_init_libfuncs): Use special functions for divsi3 and modsi3
	if TARGET_FIX_VR4122.
	* config/mips/mips.md (define_attr length): Account for nops inserted
	after macc and dmult when using -mfix-vr4122-bugs.
	(umuldi3_highpart, divmodsi4, divmoddi4): Disable if TARGET_FIX_VR4122.
	* config/mips/t-vr (LIB2FUNCS_STATIC_EXTRA): Define instead of
	LIB2FUNCS_EXTRA.  Add config/mips/vr4122-div.S.
	* config/mips/vr4122-div.S: New file.
	* doc/invoke.texi: Document -mfix-vr4122-bugs.

Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.328
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.328 mips.h
--- config/mips/mips.h	24 Mar 2004 10:05:46 -0000	1.328
+++ config/mips/mips.h	24 Mar 2004 12:59:37 -0000
@@ -173,6 +173,7 @@ #define MASK_UNINIT_CONST_IN_RODATA \
 #define MASK_FIX_R4000	   0x01000000	/* Work around R4000 errata.  */
 #define MASK_FIX_R4400	   0x02000000	/* Work around R4400 errata.  */
 #define MASK_FIX_SB1	   0x04000000	/* Work around SB-1 errata.  */
+#define MASK_FIX_VR4122	   0x08000000   /* Work-around VR4122 errata.  */
 
 					/* Debug switches, not documented */
 #define MASK_DEBUG	0		/* unused */
@@ -256,6 +257,7 @@ #define TARGET_FIX_R4000	(target_flags &
 
 					/* Work around R4400 errata.  */
 #define TARGET_FIX_R4400		(target_flags & MASK_FIX_R4400)
+#define TARGET_FIX_VR4122	(target_flags & MASK_FIX_VR4122)
 
 /* True if we should use NewABI-style relocation operators for
    symbolic addresses.  This is never true for mips16 code,
@@ -606,6 +608,10 @@ #define TARGET_SWITCHES							\
      N_("Work around R4400 errata")},					\
   {"no-fix-r4400",	 -MASK_FIX_R4400,				\
      N_("Don't work around R4400 errata")},				\
+  {"fix-vr4122-bugs",     MASK_FIX_VR4122,				\
+     N_("Work around certain VR4122 errata")},				\
+  {"no-fix-vr4122-bugs", -MASK_FIX_VR4122,				\
+     N_("Don't work around certain VR4122 errata")},			\
   {"check-zero-division",-MASK_NO_CHECK_ZERO_DIV,			\
      N_("Trap on integer divide by zero")},				\
   {"no-check-zero-division", MASK_NO_CHECK_ZERO_DIV,			\
@@ -1109,6 +1115,7 @@ #define ASM_SPEC "\
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32} %{mips32r2} %{mips64} \
 %{mips16:%{!mno-mips16:-mips16}} %{mno-mips16:-no-mips16} \
+%{mfix-vr4122-bugs} \
 %(subtarget_asm_optimizing_spec) \
 %(subtarget_asm_debugging_spec) \
 %{membedded-pic} \
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.398
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.398 mips.c
--- config/mips/mips.c	24 Mar 2004 10:05:47 -0000	1.398
+++ config/mips/mips.c	24 Mar 2004 12:59:40 -0000
@@ -8721,8 +8721,10 @@ mips_avoid_hazards (void)
   cfun->machine->ignore_hazard_length_p = true;
   shorten_branches (get_insns ());
 
-  /* The profiler code uses assembler macros.  */
-  cfun->machine->all_noreorder_p = !current_function_profile;
+  /* The profiler code uses assembler macros.  -mfix-vr4122-bugs
+     relies on assembler nop insertion.  */
+  cfun->machine->all_noreorder_p = (!current_function_profile
+				    && !TARGET_FIX_VR4122);
 
   last_insn = 0;
   hilo_delay = 2;
@@ -8760,14 +8762,23 @@ mips_reorg (void)
     }
 }
 
-/* We need to use a special set of functions to handle hard floating
-   point code in mips16 mode.  Also, allow for --enable-gofast.  */
+/* This function does three things:
+
+   - Register the special divsi3 and modsi3 functions if -mfix-vr4122-bugs.
+   - Register the mips16 hardware floating point stubs.
+   - Register the gofast functions if selected using --enable-gofast.  */
 
 #include "config/gofast.h"
 
 static void
 mips_init_libfuncs (void)
 {
+  if (TARGET_FIX_VR4122)
+    {
+      set_optab_libfunc (sdiv_optab, SImode, "__vr4122_divsi3");
+      set_optab_libfunc (smod_optab, SImode, "__vr4122_modsi3");
+    }
+
   if (TARGET_MIPS16 && mips16_hard_float)
     {
       set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3");
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.228
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.228 mips.md
--- config/mips/mips.md	24 Mar 2004 10:05:49 -0000	1.228
+++ config/mips/mips.md	24 Mar 2004 12:59:41 -0000
@@ -212,6 +212,21 @@ (define_attr "length" ""
 	       (ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
 	  (const_int 8)
 
+	  ;; Various VR4122 errata require a nop to be inserted after a macc
+	  ;; instruction.  The assembler does this for us, so account for
+	  ;; the worst-case length here.
+	  (and (eq_attr "type" "imadd")
+	       (ne (symbol_ref "TARGET_FIX_VR4122") (const_int 0)))
+	  (const_int 8)
+
+	  ;; VR4122 errata MD(4): if there are consecutive dmult instructions,
+	  ;; the result of the second one is missed.  The assembler should work
+	  ;; around this by inserting a nop after the first dmult.
+	  (and (eq_attr "type" "imul")
+	       (and (eq_attr "mode" "DI")
+		    (ne (symbol_ref "TARGET_FIX_VR4122") (const_int 0))))
+	  (const_int 8)
+
 	  (eq_attr "type" "idiv")
 	  (symbol_ref "mips_idiv_insns () * 4")
 	  ] (const_int 4)))
@@ -2300,6 +2315,8 @@ (define_insn "smuldi3_highpart"
   [(set_attr "type"	"imul")
    (set_attr "mode"	"DI")])
 
+;; Disable this pattern for -mfix-vr4122-bugs.  This is for VR4122 errata
+;; MD(0), which says that dmultu does not always produce the correct result.
 (define_insn "umuldi3_highpart"
   [(set (match_operand:DI 0 "register_operand" "=h")
 	(truncate:DI
@@ -2309,7 +2326,7 @@ (define_insn "umuldi3_highpart"
 	   (zero_extend:TI (match_operand:DI 2 "register_operand" "d")))
 	  (const_int 64))))
    (clobber (match_scratch:DI 3 "=l"))]
-  "TARGET_64BIT && !TARGET_FIX_R4000"
+  "TARGET_64BIT && !TARGET_FIX_R4000 && !TARGET_FIX_VR4122"
   "dmultu\t%1,%2"
   [(set_attr "type"	"imul")
    (set_attr "mode"	"DI")])
@@ -2583,6 +2600,8 @@ (define_insn ""
                       (const_int 8)
                       (const_int 4)))])
 
+;; VR4122 errata MD(A1): signed division instructions do not work correctly
+;; with negative operands.  We use special libgcc functions instead.
 (define_insn "divmodsi4"
   [(set (match_operand:SI 0 "register_operand" "=l")
 	(div:SI (match_operand:SI 1 "register_operand" "d")
@@ -2590,7 +2609,7 @@ (define_insn "divmodsi4"
    (set (match_operand:SI 3 "register_operand" "=h")
 	(mod:SI (match_dup 1)
 		(match_dup 2)))]
-  ""
+  "!TARGET_FIX_VR4122"
   { return mips_output_division ("div\t$0,%1,%2", operands); }
   [(set_attr "type"	"idiv")
    (set_attr "mode"	"SI")])
@@ -2602,7 +2621,7 @@ (define_insn "divmoddi4"
    (set (match_operand:DI 3 "register_operand" "=h")
 	(mod:DI (match_dup 1)
 		(match_dup 2)))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && !TARGET_FIX_VR4122"
   { return mips_output_division ("ddiv\t$0,%1,%2", operands); }
   [(set_attr "type"	"idiv")
    (set_attr "mode"	"DI")])
Index: config/mips/t-vr
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/t-vr,v
retrieving revision 1.2
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.2 t-vr
--- config/mips/t-vr	14 Oct 2002 07:17:41 -0000	1.2
+++ config/mips/t-vr	24 Mar 2004 12:59:41 -0000
@@ -7,7 +7,8 @@ CRTSTUFF_T_CFLAGS = -G 0
 # without the $gp register.
 TARGET_LIBGCC2_CFLAGS = -G 0
 
-LIB2FUNCS_EXTRA = $(srcdir)/config/mips/mips16.S
+LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/mips/mips16.S \
+			 $(srcdir)/config/mips/vr4122-div.S
 EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
 
 # Assemble startup files.
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.433
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.433 invoke.texi
--- doc/invoke.texi	24 Mar 2004 10:05:50 -0000	1.433
+++ doc/invoke.texi	24 Mar 2004 12:59:45 -0000
@@ -479,7 +479,7 @@ in the following sections.
 -mmemcpy  -mno-memcpy  -mlong-calls  -mno-long-calls @gol
 -mmad  -mno-mad  -mfused-madd  -mno-fused-madd  -nocpp @gol
 -mfix-r4000  -mno-fix-r4000  -mfix-r4400  -mno-fix-r4400 @gol
--mfix-sb1  -mno-fix-sb1 @gol
+-mfix-vr4122-bugs  -mno-fix-vr4122-bugs  -mfix-sb1  -mno-fix-sb1 @gol
 -mflush-func=@var{func}  -mno-flush-func @gol
 -mbranch-likely  -mno-branch-likely}
 
@@ -8091,6 +8091,24 @@ Work around certain R4400 CPU errata:
 A double-word or a variable shift may give an incorrect result if executed
 immediately after starting an integer division.
 @end itemize
+
+@item -mfix-vr4122-bugs
+@itemx -mno-fix-vr4122-bugs
+@opindex mfix-vr4122-bugs
+Work around certain VR4122 errata:
+@itemize @minus
+@item
+@code{dmultu} does not always produce the correct result.
+@item
+@code{div} and @code{ddiv} do not always produce the correct result if one
+of the operands is negative.
+@end itemize
+The workarounds for the division errata rely on special functions in
+@file{libgcc.a}.  At present, these functions are only provided by
+the @code{mips64vr*-elf} configurations.
+
+Other VR4122 errata require a nop to be inserted between certain pairs of
+instructions.  These errata are handled by the assembler, not by GCC itself.
 
 @item -mfix-sb1
 @itemx -mno-fix-sb1
--- /dev/null	Tue Jun 17 23:06:41 2003
+++ config/mips/vr4122-div.S	Wed Mar 24 12:48:40 2004
@@ -0,0 +1,75 @@
+/* Support file for -mfix-vr4122-bugs.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This file contains functions which implement divsi3 and modsi3 for
+   -mfix-vr4122-bugs.  div and ddiv do not give the correct result
+   when one of the operands is negative.  */
+
+	.set	nomips16
+
+#define DIV								\
+	xor	$3,$4,$5	/* t = x ^ y */ ;			\
+	li	$2,0x80000000;						\
+	.set	noreorder;						\
+	bgez	$4,1f		/* x >= 0 */; 				\
+	and	$3,$3,$2	/* t = (x ^ y) & 0x80000000 in delay slot */ ;\
+	.set	reorder;						\
+	subu	$4,$0,$4	/* x = -x */ ;				\
+1:; 									\
+	.set	noreorder;						\
+	bgez	$5,2f		/* y >= 0 */ ;				\
+	nop;								\
+	subu	$5,$0,$5	/* y = -y */ ;				\
+	.set	reorder;						\
+2:;									\
+	divu	$0,$4,$5;	/* we use divu because of INT_MIN */	\
+	.set	noreorder;						\
+	bne	$5,$0,3f;						\
+	nop;								\
+	break	7		/* division on zero y */ ;		\
+3:;									\
+	.set	reorder;						\
+	mflo	$2		/* r = x / y */ ;			\
+	.set	noreorder;						\
+	beq	$3,$0,4f	/* t == 0 */ ;				\
+	nop;								\
+	subu	$2,$0,$2	/* r = -r */ ;				\
+	.set	reorder;						\
+4:
+
+	.globl	__vr4122_divsi3
+	.ent	__vr4122_divsi3
+__vr4122_divsi3:
+	DIV
+	j	$31
+	.end	__vr4122_divsi3
+
+	.globl	__vr4122_modsi3
+	.ent	__vr4122_modsi3
+__vr4122_modsi3:
+	move	$6,$4		# x1 = x
+	move	$7,$5		# y1 = y
+	DIV
+	mult	$2,$7		# r = r * y1
+	mflo	$2
+	.set	noreorder
+	j	$31
+	subu	$2,$6,$2	# r = x1 - r  in delay slot
+	.end	__vr4122_modsi3


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