mips.h (MASK_FIX_VR4122, [...]): New macros.
authorDJ Delorie <dj@redhat.com>
Wed, 24 Mar 2004 13:05:40 +0000 (08:05 -0500)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 24 Mar 2004 13:05:40 +0000 (13:05 +0000)
* 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.

Co-Authored-By: Richard Sandiford <rsandifo@redhat.com>
From-SVN: r79912

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/t-vr
gcc/config/mips/vr4122-div.S [new file with mode: 0644]
gcc/doc/invoke.texi

index 985a742..80a7cd1 100644 (file)
@@ -1,3 +1,21 @@
+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.
+
 2004-03-24  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.h (PROCESSOR_R4130): New processor_type.
index 5c1ce71..cbd248e 100644 (file)
@@ -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 7b079d8..c47637c 100644 (file)
@@ -173,6 +173,7 @@ extern const struct mips_cpu_info *mips_tune_info;
 #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 @@ extern const struct mips_cpu_info *mips_tune_info;
 
                                        /* 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 @@ extern const struct mips_cpu_info *mips_tune_info;
      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 @@ extern const struct mips_cpu_info *mips_tune_info;
 %{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 45a106a..21b8277 100644 (file)
               (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)))
   [(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
           (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")])
                       (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")
    (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")])
    (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 68daad8..2f0aef4 100644 (file)
@@ -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.
diff --git a/gcc/config/mips/vr4122-div.S b/gcc/config/mips/vr4122-div.S
new file mode 100644 (file)
index 0000000..8936af1
--- /dev/null
@@ -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 59e02a0..8c6e440 100644 (file)
@@ -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}
 
@@ -8092,6 +8092,24 @@ 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
 @opindex mfix-sb1