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]

Re: head: MIPS: Workaround an R4000SC/MC branch/divide erratum


"Maciej W. Rozycki" <macro@ds2.pg.gda.pl> writes:
> On Mon, 1 Mar 2004, Richard Sandiford wrote:
>> Anyhow, after the change to force division into the delay slot,
>> I think all we need to do is swap the clauses around, like so:
> [...]
>> If you agree, I'll test your patch with that change.
>
>  It looks promising.

Bootstrap & regression tests went OK, so for the record, here's what
I installed.  (Maciej, this is the patch you sent me off-list.)
The only difference from the previous on-list version is in the
change to the comment above mips_output_division.

Richard


	* config/mips/mips.h (MASK_FIX_SB1): Bump.
	(MASK_FIX_R4400, TARGET_FIX_R4400): New macros.
	(TARGET_SWITCHES): Add -mfix-r4400 and -mno-fix-r4400.
	* config/mips/mips.c (mips_output_division): Fill the branch delay
	slot with a nop if TARGET_FIX_R4000.  Extend R4000 workarounds to
	TARGET_FIX_R4400.
	(mips_output_division): Adjust accordingly.
	(override_options): Make -march=r4400 imply -mfix-r4400 by default.
	* doc/invoke.texi: Document -mfix-r4400 and new errata workarounds.

Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.419
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.419 invoke.texi
*** doc/invoke.texi	1 Mar 2004 19:40:08 -0000	1.419
--- doc/invoke.texi	3 Mar 2004 08:47:00 -0000
*************** in the following sections.
*** 478,484 ****
  -mcheck-zero-division  -mno-check-zero-division @gol
  -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-sb1  -mno-fix-sb1 @gol
  -mflush-func=@var{func}  -mno-flush-func @gol
  -mbranch-likely  -mno-branch-likely}
  
--- 478,485 ----
  -mcheck-zero-division  -mno-check-zero-division @gol
  -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
  -mflush-func=@var{func}  -mno-flush-func @gol
  -mbranch-likely  -mno-branch-likely}
  
*************** immediately after starting an integer di
*** 8048,8053 ****
--- 8049,8068 ----
  @item
  A double-word or a variable shift may give an incorrect result if executed
  while an integer multiplication is in progress.
+ @item
+ An integer division may give an incorrect result if started in a delay slot
+ of a taken branch or a jump.
+ @end itemize
+ 
+ @item -mfix-r4400
+ @itemx -mno-fix-r4400
+ @opindex mfix-r4400
+ @opindex mno-fix-r4400
+ Work around certain R4400 CPU errata:
+ @itemize @minus
+ @item
+ A double-word or a variable shift may give an incorrect result if executed
+ immediately after starting an integer division.
  @end itemize
  
  @item -mfix-sb1
Index: config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.324
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.324 mips.h
*** config/mips/mips.h	1 Mar 2004 19:40:10 -0000	1.324
--- config/mips/mips.h	3 Mar 2004 08:47:02 -0000
*************** #define MASK_UNINIT_CONST_IN_RODATA \
*** 170,176 ****
  			   0x00800000	/* Store uninitialized
  					   consts in rodata */
  #define MASK_FIX_R4000	   0x01000000	/* Work around R4000 errata.  */
! #define MASK_FIX_SB1       0x02000000   /* Work around SB-1 errata.  */
  
  					/* Debug switches, not documented */
  #define MASK_DEBUG	0		/* unused */
--- 170,177 ----
  			   0x00800000	/* Store uninitialized
  					   consts 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.  */
  
  					/* Debug switches, not documented */
  #define MASK_DEBUG	0		/* unused */
*************** #define TARGET_FIX_SB1		(target_flags & 
*** 252,257 ****
--- 253,261 ----
  					/* Work around R4000 errata.  */
  #define TARGET_FIX_R4000	(target_flags & MASK_FIX_R4000)
  
+ 					/* Work around R4400 errata.  */
+ #define TARGET_FIX_R4400		(target_flags & MASK_FIX_R4400)
+ 
  /* True if we should use NewABI-style relocation operators for
     symbolic addresses.  This is never true for mips16 code,
     which has its own conventions.  */
*************** #define TARGET_SWITCHES							\
*** 596,601 ****
--- 600,609 ----
       N_("Work around R4000 errata")},					\
    {"no-fix-r4000",	 -MASK_FIX_R4000,				\
       N_("Don't work around R4000 errata")},				\
+   {"fix-r4400",		  MASK_FIX_R4400,				\
+      N_("Work around R4400 errata")},					\
+   {"no-fix-r4400",	 -MASK_FIX_R4400,				\
+      N_("Don't work around R4400 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,			\
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.392
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.392 mips.c
*** config/mips/mips.c	3 Mar 2004 08:35:02 -0000	1.392
--- config/mips/mips.c	3 Mar 2004 08:47:04 -0000
*************** mips_idiv_insns (void)
*** 1321,1327 ****
    count = 1;
    if (TARGET_CHECK_ZERO_DIV)
      count += 2;
!   if (TARGET_FIX_R4000)
      count++;
    return count;
  }
--- 1321,1327 ----
    count = 1;
    if (TARGET_CHECK_ZERO_DIV)
      count += 2;
!   if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
      count++;
    return count;
  }
*************** override_options (void)
*** 5101,5106 ****
--- 5101,5112 ----
    if ((target_flags_explicit & MASK_FIX_R4000) == 0
        && mips_matching_cpu_name_p (mips_arch_info->name, "r4000"))
      target_flags |= MASK_FIX_R4000;
+ 
+   /* Default to working around R4400 errata only if the processor
+      was selected explicitly.  */
+   if ((target_flags_explicit & MASK_FIX_R4400) == 0
+       && mips_matching_cpu_name_p (mips_arch_info->name, "r4400"))
+     target_flags |= MASK_FIX_R4400;
  }
  
  /* Implement CONDITIONAL_REGISTER_USAGE.  */
*************** mips_output_conditional_branch (rtx insn
*** 9171,9189 ****
    return 0;
  }
  
! /* Used to output div or ddiv instruction DIVISION, which has the
!    operands given by OPERANDS.  If we need a divide-by-zero check,
!    output the instruction and return an asm string that traps if
!    operand 2 is zero.
! 
!    The original R4000 has a cpu bug.  If a double-word or a variable
!    shift executes immediately after starting an integer division, the
!    shift may give an incorrect result.  Avoid this by adding a nop on
!    the R4000.  See quotations of errata #16 and #28 from "MIPS
!    R4000PC/SC Errata, Processor Revision 2.2 and 3.0" in mips.md for
!    details.
  
!    Otherwise just return DIVISION itself.  */
  
  const char *
  mips_output_division (const char *division, rtx *operands)
--- 9177,9270 ----
    return 0;
  }
  
! /* Used to output div or ddiv instruction DIVISION, which has the operands
!    given by OPERANDS.  Add in a divide-by-zero check if needed.
! 
!    When working around R4000 and R4400 errata, we need to make sure that
!    the division is not immediately followed by a shift[1][2].  We also
!    need to stop the division from being put into a branch delay slot[3].
!    The easiest way to avoid both problems is to add a nop after the
!    division.  When a divide-by-zero check is neeeded, this nop can be
!    used to fill the branch delay slot.
! 
!    [1] If a double-word or a variable shift executes immediately
!        after starting an integer division, the shift may give an
!        incorrect result.  See quotations of errata #16 and #28 from
!        "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
!        in mips.md for details.
! 
!    [2] A similar bug to [1] exists for all revisions of the
!        R4000 and the R4400 when run in an MC configuration.
!        From "MIPS R4000MC Errata, Processor Revision 2.2 and 3.0":
! 
!        "19. In this following sequence:
! 
! 		    ddiv		(or ddivu or div or divu)
! 		    dsll32		(or dsrl32, dsra32)
! 
! 	    if an MPT stall occurs, while the divide is slipping the cpu
! 	    pipeline, then the following double shift would end up with an
! 	    incorrect result.
! 
! 	    Workaround: The compiler needs to avoid generating any
! 	    sequence with divide followed by extended double shift."
! 
!        This erratum is also present in "MIPS R4400MC Errata, Processor
!        Revision 1.0" and "MIPS R4400MC Errata, Processor Revision 2.0
!        & 3.0" as errata #10 and #4, respectively.
! 
!    [3] From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
!        (also valid for MIPS R4000MC processors):
! 
!        "52. R4000SC: This bug does not apply for the R4000PC.
! 
! 	    There are two flavors of this bug:
! 
! 	    1) If the instruction just after divide takes an RF exception
! 	       (tlb-refill, tlb-invalid) and gets an instruction cache
! 	       miss (both primary and secondary) and the line which is
! 	       currently in secondary cache at this index had the first
! 	       data word, where the bits 5..2 are set, then R4000 would
! 	       get a wrong result for the div.
! 
! 	    ##1
! 		    nop
! 		    div	r8, r9
! 		    -------------------		# end-of page. -tlb-refill
! 		    nop
! 	    ##2
! 		    nop
! 		    div	r8, r9
! 		    -------------------		# end-of page. -tlb-invalid
! 		    nop
! 
! 	    2) If the divide is in the taken branch delay slot, where the
! 	       target takes RF exception and gets an I-cache miss for the
! 	       exception vector or where I-cache miss occurs for the
! 	       target address, under the above mentioned scenarios, the
! 	       div would get wrong results.
! 
! 	    ##1
! 		    j	r2		# to next page mapped or unmapped
! 		    div	r8,r9		# this bug would be there as long
! 					# as there is an ICache miss and
! 		    nop			# the "data pattern" is present
! 
! 	    ##2
! 		    beq	r0, r0, NextPage	# to Next page
! 		    div	r8,r9
! 		    nop
! 
! 	    This bug is present for div, divu, ddiv, and ddivu
! 	    instructions.
! 
! 	    Workaround: For item 1), OS could make sure that the next page
! 	    after the divide instruction is also mapped.  For item 2), the
! 	    compiler could make sure that the divide instruction is not in
! 	    the branch delay slot."
  
!        These processors have PRId values of 0x00004220 and 0x00004300 for
!        the R4000 and 0x00004400, 0x00004500 and 0x00004600 for the R4400.  */
  
  const char *
  mips_output_division (const char *division, rtx *operands)
*************** mips_output_division (const char *divisi
*** 9191,9196 ****
--- 9272,9282 ----
    const char *s;
  
    s = division;
+   if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
+     {
+       output_asm_insn (s, operands);
+       s = "nop";
+     }
    if (TARGET_CHECK_ZERO_DIV)
      {
        if (TARGET_MIPS16)
*************** mips_output_division (const char *divisi
*** 9204,9214 ****
  	  output_asm_insn (s, operands);
  	  s = "break\t7%)\n1:";
  	}
-     }
-   if (TARGET_FIX_R4000)
-     {
-       output_asm_insn (s, operands);
-       s = "nop";
      }
    return s;
  }
--- 9290,9295 ----


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