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]

Patch to rework mips divide patterns


The original motivation for this patch was to get rid of the div_trap insns.
They have a fixed length of 12 but don't always emit code:

    (define_insn "div_trap_normal"
      [(trap_if (eq (match_operand 0 "register_operand" "d,d")
                    (match_operand 1 "true_reg_or_0_operand" "d,J"))
                (match_operand 2 "immediate_operand" ""))]
      "!TARGET_MIPS16"
      "*
    {
      rtx link;
      int have_dep_anti = 0;

      /* For divmod if one division is not needed then we don't need an extra
         divide by zero trap, which is anti dependent on previous trap */
      for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))

        if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link)
            && GET_CODE (XEXP (link, 0)) == INSN
            && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF
            && which_alternative == 1)
          have_dep_anti = 1;
      if (! have_dep_anti)
        {
          ...
        }
      return \"\";
    }"
      [(set_attr "type" "unknown")
       (set_attr "length" "12")])

This makes it difficult to get nop insertion right.

The comment above the dependence check is a bit unclear: it sounds
like it's trying optimise the case where a divmod has two traps.
But the divmod patterns only emit a single trap, and the port
disallows individual divs & mods if optimize > 0.

The dependence check can trigger in other cases though.  Suppose we have:

    x1 = y1 / z1;
    x2 = y2 / z2;

and the divisions get constant-folded after initial rtl generation.
The rtl stream will still contain the traps for z1 and z2, but since
the trap for z2 depends on the trap for z1, we only emit the latter.

This all suggests we're creating the trap too early.  In fact, there
doesn't seem to be much reason to split off the trap in the first place.
If we keep it as part of the main pattern, it will be emitted inbetween
the division and the following mflo or mfhi.  On most targets there's
around a 30-cycle delay before the mflo or mfhi can complete, so we're
unlikely to gain anything by moving the trap elsewhere.

In theory, separate traps could be eliminated when their conditions are
known to be false.  But we don't do that optimisation yet.  And besides,
if we end up keeping a division insn (rather than replacing division by
a constant with multiplication by a constant), the extra check costs very
little, for the reasons given above.

I was hoping to keep this message short, but there's something else...
We have this undocumented -mcheck-range-division option.  I'm not quite
sure what's it's supposed to do, but I think what it actually does is:

   trap for SImode division by -1 or -0x8000_0000

   trap for DImode division by -1 or 0x8000_0000

I don't really see why this is useful since all four cases can give
valid results for some dividends.  And the DImode handling looks
suspiciously like a bug.  If there's no objections, I'd like to remove
this feature.

At the moment we use divmod when optimisation is enabled and separate
div & mod otherwise.  This seems like an unnecessary complication:
it shouldn't be needed for correctness.

Patch tested on mips-sgi-irix6.5, mips-sgi-irix6.5o32, mips64vrel-elf,
mipsisa64-elf and mipsel-linux-gnu.  Also benchmarked on a vr5400 board,
where each program showed either no change or a slight improvement.
OK to install?

Richard


	* config/mips/mips-protos.h (mips_output_division): Declare.
	* config/mips/mips.h (MASK_CHECK_RANGE_DIV): Remove.
	(MASK_BRANCHLIKELY): Use MASK_CHECK_RANGE_DIV's old number.
	(TARGET_NO_CHECK_ZERO_DIV, TARGET_CHECK_RANGE_DIV): Remove.
	(TARGET_CHECK_ZERO_DIV): New macro.
	(TARGET_SWITCHES): Remove -mcheck-range-div & -mno-check-range-div.
	* config/mips/mips.md (length): Take TARGET_CHECK_ZERO_DIV into
	account when calculating the default length of a division.
	(divmodsi4, divmoddi4, udivmodsi4, udivmoddi4): Turn into define_insns.
	Enable regardless of optimization level.  Use mips_output_division.
	(divmodsi4_internal, divmoddi4_internal, udivmodsi4_internal,
	udivmoddi4_internal, div_trap, div_trap_normal, div_trap_mips16,
	divsi3, divsi3_internal, divdi3, divdi3_internal, modsi3,
	modsi3_internal, moddi3, moddi3_internal, udivsi3, udivsi3_internal,
	udivdi3, udivdi3_internal, umodsi3, umodsi3_internal, umoddi3,
	umoddi3_internal): Remove.

diff -cpdr config/mips.pending/mips-protos.h config/mips/mips-protos.h
*** config/mips.pending/mips-protos.h	Tue Jun  3 17:41:48 2003
--- config/mips/mips-protos.h	Sat Jun  7 13:40:51 2003
*************** extern const char	*mips_output_load_labe
*** 112,117 ****
--- 112,118 ----
  extern const char       *mips_output_conditional_branch PARAMS ((rtx, rtx *,
  								 int, int, int,
  								 int));
+ extern const char	*mips_output_division PARAMS ((const char *, rtx *));
  extern int              mips_adjust_insn_length PARAMS ((rtx, int));
  extern enum reg_class	mips_secondary_reload_class PARAMS ((enum reg_class,
  							     enum machine_mode,
diff -cpdr config/mips.pending/mips.c config/mips/mips.c
*** config/mips.pending/mips.c	Sat Jun  7 13:17:03 2003
--- config/mips/mips.c	Sun Jun  8 15:58:55 2003
*************** mips_output_conditional_branch (insn,
*** 10210,10215 ****
--- 10210,10236 ----
    return 0;
  }
  
+ /* If appropriate, add divide-by-zero checks to div or ddiv instruction
+    DIVISION, which has the given operands.  Return an asm string for the
+    final instruction.  */
+ 
+ const char *
+ mips_output_division (division, operands)
+      const char *division;
+      rtx *operands;
+ {
+   if (TARGET_CHECK_ZERO_DIV)
+     {
+       output_asm_insn (division, operands);
+ 
+       if (TARGET_MIPS16)
+ 	return "bnez\t%2,1f\n\tbreak\t7\n1:";
+       else
+ 	return "bne\t%2,%.,1f\n\t%#break\t7\n1:";
+     }
+   return division;
+ }
+ 
  /* Return true if GIVEN is the same as CANONICAL, or if it is CANONICAL
     with a final "000" replaced by "k".  Ignore case.
  
diff -cpdr config/mips.pending/mips.h config/mips/mips.h
*** config/mips.pending/mips.h	Sat Jun  7 13:17:03 2003
--- config/mips/mips.h	Sat Jun  7 18:52:07 2003
*************** extern void		sbss_section PARAMS ((void)
*** 201,215 ****
  #define MASK_MIPS16	   0x00100000	/* Generate mips16 code */
  #define MASK_NO_CHECK_ZERO_DIV \
  			   0x00200000	/* divide by zero checking */
! #define MASK_CHECK_RANGE_DIV \
! 			   0x00400000	/* divide result range checking */
  #define MASK_UNINIT_CONST_IN_RODATA \
  			   0x00800000	/* Store uninitialized
  					   consts in rodata */
  #define MASK_NO_FUSED_MADD 0x01000000   /* Don't generate floating point
  					   multiply-add operations.  */
- #define MASK_BRANCHLIKELY  0x02000000   /* Generate Branch Likely
- 					   instructions.  */
  
  					/* Debug switches, not documented */
  #define MASK_DEBUG	0		/* unused */
--- 201,213 ----
  #define MASK_MIPS16	   0x00100000	/* Generate mips16 code */
  #define MASK_NO_CHECK_ZERO_DIV \
  			   0x00200000	/* divide by zero checking */
! #define MASK_BRANCHLIKELY  0x00400000   /* Generate Branch Likely
! 					   instructions.  */
  #define MASK_UNINIT_CONST_IN_RODATA \
  			   0x00800000	/* Store uninitialized
  					   consts in rodata */
  #define MASK_NO_FUSED_MADD 0x01000000   /* Don't generate floating point
  					   multiply-add operations.  */
  
  					/* Debug switches, not documented */
  #define MASK_DEBUG	0		/* unused */
*************** extern void		sbss_section PARAMS ((void)
*** 294,301 ****
  
  #define TARGET_4300_MUL_FIX     (target_flags & MASK_4300_MUL_FIX)
  
! #define TARGET_NO_CHECK_ZERO_DIV (target_flags & MASK_NO_CHECK_ZERO_DIV)
! #define TARGET_CHECK_RANGE_DIV  (target_flags & MASK_CHECK_RANGE_DIV)
  
  #define TARGET_BRANCHLIKELY	(target_flags & MASK_BRANCHLIKELY)
  
--- 292,298 ----
  
  #define TARGET_4300_MUL_FIX     (target_flags & MASK_4300_MUL_FIX)
  
! #define TARGET_CHECK_ZERO_DIV   (!(target_flags & MASK_NO_CHECK_ZERO_DIV))
  
  #define TARGET_BRANCHLIKELY	(target_flags & MASK_BRANCHLIKELY)
  
*************** extern void		sbss_section PARAMS ((void)
*** 624,633 ****
       N_("Trap on integer divide by zero")},				\
    {"no-check-zero-division", MASK_NO_CHECK_ZERO_DIV,			\
       N_("Don't trap on integer divide by zero")},			\
-   {"check-range-division",MASK_CHECK_RANGE_DIV,				\
-      N_("Trap on integer divide overflow")},				\
-   {"no-check-range-division",-MASK_CHECK_RANGE_DIV,			\
-      N_("Don't trap on integer divide overflow")},			\
    { "branch-likely",      MASK_BRANCHLIKELY,				\
        N_("Use Branch Likely instructions, overriding default for arch")}, \
    { "no-branch-likely",  -MASK_BRANCHLIKELY,				\
--- 621,626 ----
diff -cpdr config/mips.pending/mips.md config/mips/mips.md
*** config/mips.pending/mips.md	Sat Jun  7 13:17:03 2003
--- config/mips/mips.md	Sat Jun  7 18:52:07 2003
***************
*** 174,179 ****
--- 174,184 ----
  	  (and (eq_attr "extended_mips16" "yes")
  	       (ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
  	  (const_int 8)
+ 	  (and (eq_attr "type" "idiv")
+ 	       (ne (symbol_ref "TARGET_CHECK_ZERO_DIV") (const_int 0)))
+ 	  (cond [(ne (symbol_ref "TARGET_MIPS16") (const_int 0))
+ 		 (const_int 12)]
+ 		(const_int 16))
  	  ] (const_int 4)))
  
  ;; Attribute describing the processor.  This attribute must match exactly
***************
*** 2833,3371 ****
    [(set_attr "type"	"fdiv")
     (set_attr "mode"	"SF")])
  
! ;; If optimizing, prefer the divmod functions over separate div and
! ;; mod functions, since this will allow using one instruction for both
! ;; the quotient and remainder.  At present, the divmod is not moved out
! ;; of loops if it is constant within the loop, so allow -mdebugc to
! ;; use the old method of doing things.
! 
! ;; 64 is the multiply/divide hi register
! ;; 65 is the multiply/divide lo register
! 
! ;; ??? We can't accept constants here, because the MIPS assembler will replace
! ;; a divide by power of 2 with a shift, and then the remainder is no longer
! ;; available.
! 
! (define_expand "divmodsi4"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(div:SI (match_operand:SI 1 "register_operand" "")
! 		(match_operand:SI 2 "register_operand" "")))
!    (set (match_operand:SI 3 "register_operand" "")
! 	(mod:SI (match_dup 1)
! 		(match_dup 2)))]
!   "optimize"
!   "
! {
!   emit_insn (gen_divmodsi4_internal (operands[0], operands[1], operands[2],
! 	     operands[3]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode,
! 						 GEN_INT
! 						 (trunc_int_for_mode
! 						  (BITMASK_HIGH, SImode))),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "divmodsi4_internal"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(div:SI (match_operand:SI 1 "register_operand" "d")
  		(match_operand:SI 2 "register_operand" "d")))
     (set (match_operand:SI 3 "register_operand" "=h")
  	(mod:SI (match_dup 1)
  		(match_dup 2)))]
!   "optimize"
!   "div\\t$0,%1,%2"
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"SI")])
  
! (define_expand "divmoddi4"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(div:DI (match_operand:DI 1 "register_operand" "")
! 		(match_operand:DI 2 "register_operand" "")))
!    (set (match_operand:DI 3 "register_operand" "")
! 	(mod:DI (match_dup 1)
! 		(match_dup 2)))]
!   "TARGET_64BIT && optimize"
!   "
! {
!   emit_insn (gen_divmoddi4_internal (operands[0], operands[1], operands[2],
!              operands[3]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode,
! 						 GEN_INT (BITMASK_HIGH)),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "divmoddi4_internal"
    [(set (match_operand:DI 0 "register_operand" "=l")
  	(div:DI (match_operand:DI 1 "register_operand" "d")
  		(match_operand:DI 2 "register_operand" "d")))
     (set (match_operand:DI 3 "register_operand" "=h")
  	(mod:DI (match_dup 1)
  		(match_dup 2)))]
!   "TARGET_64BIT && optimize"
!   "ddiv\\t$0,%1,%2"
    [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! (define_expand "udivmodsi4"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(udiv:SI (match_operand:SI 1 "register_operand" "")
! 		 (match_operand:SI 2 "register_operand" "")))
!    (set (match_operand:SI 3 "register_operand" "")
! 	(umod:SI (match_dup 1)
! 		 (match_dup 2)))]
!   "optimize"
!   "
! {
!   emit_insn (gen_udivmodsi4_internal (operands[0], operands[1], operands[2],
!                                       operands[3]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
  
! (define_insn "udivmodsi4_internal"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(udiv:SI (match_operand:SI 1 "register_operand" "d")
  		 (match_operand:SI 2 "register_operand" "d")))
     (set (match_operand:SI 3 "register_operand" "=h")
  	(umod:SI (match_dup 1)
  		 (match_dup 2)))]
!   "optimize"
!   "divu\\t$0,%1,%2"
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"SI")])
  
! (define_expand "udivmoddi4"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(udiv:DI (match_operand:DI 1 "register_operand" "")
! 		 (match_operand:DI 2 "register_operand" "")))
!    (set (match_operand:DI 3 "register_operand" "")
! 	(umod:DI (match_dup 1)
! 		 (match_dup 2)))]
!   "TARGET_64BIT && optimize"
!   "
! {
!   emit_insn (gen_udivmoddi4_internal (operands[0], operands[1], operands[2],
!                                       operands[3]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "udivmoddi4_internal"
    [(set (match_operand:DI 0 "register_operand" "=l")
  	(udiv:DI (match_operand:DI 1 "register_operand" "d")
  		 (match_operand:DI 2 "register_operand" "d")))
     (set (match_operand:DI 3 "register_operand" "=h")
  	(umod:DI (match_dup 1)
  		 (match_dup 2)))]
!   "TARGET_64BIT && optimize"
!   "ddivu\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! ;; Division trap
! 
! (define_expand "div_trap"
!   [(trap_if (eq (match_operand 0 "register_operand" "d")
! 		(match_operand 1 "true_reg_or_0_operand" "dJ"))
!             (match_operand 2 "immediate_operand" ""))]
!   ""
!   "
! {
!   if (TARGET_MIPS16)
!     emit_insn (gen_div_trap_mips16 (operands[0],operands[1],operands[2]));
!   else
!     emit_insn (gen_div_trap_normal (operands[0],operands[1],operands[2]));
!   DONE;
! }")
! 
! (define_insn "div_trap_normal"
!   [(trap_if (eq (match_operand 0 "register_operand" "d,d")
! 		(match_operand 1 "true_reg_or_0_operand" "d,J"))
!             (match_operand 2 "immediate_operand" ""))]
!   "!TARGET_MIPS16"
!   "*
! {
!   rtx link;
!   int have_dep_anti = 0;
! 
!   /* For divmod if one division is not needed then we don't need an extra
!      divide by zero trap, which is anti dependent on previous trap */
!   for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
! 
!     if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link)
!         && GET_CODE (XEXP (link, 0)) == INSN
!         && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF
! 	&& which_alternative == 1)
!       have_dep_anti = 1;
!   if (! have_dep_anti)
!     {
!       if (GENERATE_BRANCHLIKELY)
! 	{
!           if (which_alternative == 1)
! 	    return \"%(beql\\t%0,$0,1f\\n\\tbreak\\t%2\\n%~1:%)\";
! 	  else
! 	    return \"%(beql\\t%0,%1,1f\\n\\tbreak\\t%2\\n%~1:%)\";
! 	}
!       else
! 	{
!           if (which_alternative == 1)
! 	    return \"%(bne\\t%0,$0,1f\\n\\tnop\\n\\tbreak\\t%2\\n%~1:%)\";
! 	  else
! 	    return \"%(bne\\t%0,%1,1f\\n\\tnop\\n\\tbreak\\t%2\\n%~1:%)\";
! 	}
!     }
!   return \"\";
! }"
!   [(set_attr "type" "unknown")
!    (set_attr "length" "12")])
! 
! 
! ;; The mips16 bne insns is a macro which uses reg 24 as an intermediate.
! 
! (define_insn "div_trap_mips16"
!   [(trap_if (eq (match_operand 0 "register_operand" "d,d")
! 		(match_operand 1 "true_reg_or_0_operand" "d,J"))
!             (match_operand 2 "immediate_operand" ""))
!    (clobber (reg:SI 24))]
!   "TARGET_MIPS16"
!   "*
! {
!   rtx link;
!   int have_dep_anti = 0;
! 
!   /* For divmod if one division is not needed then we don't need an extra
!      divide by zero trap, which is anti dependent on previous trap */
!   for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
! 
!     if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link)
!         && GET_CODE (XEXP (link, 0)) == INSN
!         && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF
! 	&& which_alternative == 1)
!       have_dep_anti = 1;
!   if (! have_dep_anti)
!     {
!       /* No branch delay slots on mips16.  */
!       if (which_alternative == 1)
!         return \"%(bnez\\t%0,1f\\n\\tbreak\\t%2\\n%~1:%)\";
!       else
!         return \"%(bne\\t%0,%1,1f\\n\\tbreak\\t%2\\n%~1:%)\";
!     }
!   return \"\";
! }"
!   [(set_attr "type" "unknown")
!    (set_attr "length" "12")])
! 
! (define_expand "divsi3"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(div:SI (match_operand:SI 1 "register_operand" "")
! 		(match_operand:SI 2 "register_operand" "")))]
!   "!optimize"
!   "
! {
!   emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2]));
! 
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode,
! 						 GEN_INT
! 						 (trunc_int_for_mode
! 						  (BITMASK_HIGH, SImode))),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "divsi3_internal"
!   [(set (match_operand:SI 0 "register_operand" "=l")
! 	(div:SI (match_operand:SI 1 "register_operand" "d")
! 		(match_operand:SI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=h"))]
!   "!optimize"
!   "div\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! (define_expand "divdi3"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(div:DI (match_operand:DI 1 "register_operand" "")
! 		(match_operand:DI 2 "register_operand" "")))]
!   "TARGET_64BIT && !optimize"
!   "
! {
!   emit_insn (gen_divdi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode,
! 						 GEN_INT (BITMASK_HIGH)),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "divdi3_internal"
!   [(set (match_operand:DI 0 "register_operand" "=l")
! 	(div:DI (match_operand:DI 1 "register_operand" "d")
! 		(match_operand:DI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=h"))]
!   "TARGET_64BIT && !optimize"
!   "ddiv\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"DI")])
! 
! (define_expand "modsi3"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(mod:SI (match_operand:SI 1 "register_operand" "")
! 		(match_operand:SI 2 "register_operand" "")))]
!   "!optimize"
!   "
! {
!   emit_insn (gen_modsi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (SImode,
! 						 GEN_INT
! 						 (trunc_int_for_mode
! 						  (BITMASK_HIGH, SImode))),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "modsi3_internal"
!   [(set (match_operand:SI 0 "register_operand" "=h")
! 	(mod:SI (match_operand:SI 1 "register_operand" "d")
! 		(match_operand:SI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=l"))]
!   "!optimize"
!   "div\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! (define_expand "moddi3"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(mod:DI (match_operand:DI 1 "register_operand" "")
! 		(match_operand:DI 2 "register_operand" "")))]
!   "TARGET_64BIT && !optimize"
!   "
! {
!   emit_insn (gen_moddi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
!   if (TARGET_CHECK_RANGE_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode, GEN_INT (-1)),
! 			       GEN_INT (0x6)));
!       emit_insn (gen_div_trap (operands[2],
! 			       copy_to_mode_reg (DImode,
! 						 GEN_INT (BITMASK_HIGH)),
! 			       GEN_INT (0x6)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "moddi3_internal"
!   [(set (match_operand:DI 0 "register_operand" "=h")
! 	(mod:DI (match_operand:DI 1 "register_operand" "d")
! 		(match_operand:DI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=l"))]
!   "TARGET_64BIT && !optimize"
!   "ddiv\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"DI")])
! 
! (define_expand "udivsi3"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(udiv:SI (match_operand:SI 1 "register_operand" "")
! 		 (match_operand:SI 2 "register_operand" "")))]
!   "!optimize"
!   "
! {
!   emit_insn (gen_udivsi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "udivsi3_internal"
!   [(set (match_operand:SI 0 "register_operand" "=l")
! 	(udiv:SI (match_operand:SI 1 "register_operand" "d")
! 		 (match_operand:SI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=h"))]
!   "!optimize"
!   "divu\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! (define_expand "udivdi3"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(udiv:DI (match_operand:DI 1 "register_operand" "")
! 		 (match_operand:DI 2 "register_operand" "")))]
!   "TARGET_64BIT && !optimize"
!   "
! {
!   emit_insn (gen_udivdi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "udivdi3_internal"
!   [(set (match_operand:DI 0 "register_operand" "=l")
! 	(udiv:DI (match_operand:DI 1 "register_operand" "d")
! 		 (match_operand:DI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=h"))]
!   "TARGET_64BIT && !optimize"
!   "ddivu\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"DI")])
! 
! (define_expand "umodsi3"
!   [(set (match_operand:SI 0 "register_operand" "")
! 	(umod:SI (match_operand:SI 1 "register_operand" "")
! 		 (match_operand:SI 2 "register_operand" "")))]
!   "!optimize"
!   "
! {
!   emit_insn (gen_umodsi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "umodsi3_internal"
!   [(set (match_operand:SI 0 "register_operand" "=h")
! 	(umod:SI (match_operand:SI 1 "register_operand" "d")
! 		 (match_operand:SI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=l"))]
!   "!optimize"
!   "divu\\t$0,%1,%2"
!   [(set_attr "type"	"idiv")
!    (set_attr "mode"	"SI")])
! 
! (define_expand "umoddi3"
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(umod:DI (match_operand:DI 1 "register_operand" "")
! 		 (match_operand:DI 2 "register_operand" "")))]
!   "TARGET_64BIT && !optimize"
!   "
! {
!   emit_insn (gen_umoddi3_internal (operands[0], operands[1], operands[2]));
!   if (!TARGET_NO_CHECK_ZERO_DIV)
!     {
!       emit_insn (gen_div_trap (operands[2],
! 			       GEN_INT (0),
! 			       GEN_INT (0x7)));
!     }
! 
!   DONE;
! }")
! 
! (define_insn "umoddi3_internal"
!   [(set (match_operand:DI 0 "register_operand" "=h")
! 	(umod:DI (match_operand:DI 1 "register_operand" "d")
! 		 (match_operand:DI 2 "register_operand" "d")))
!    (clobber (match_scratch:SI 3 "=l"))]
!   "TARGET_64BIT && !optimize"
!   "ddivu\\t$0,%1,%2"
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"DI")])
- 
  ;;
  ;;  ....................
  ;;
--- 2838,2890 ----
    [(set_attr "type"	"fdiv")
     (set_attr "mode"	"SF")])
  
! (define_insn "divmodsi4"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(div:SI (match_operand:SI 1 "register_operand" "d")
  		(match_operand:SI 2 "register_operand" "d")))
     (set (match_operand:SI 3 "register_operand" "=h")
  	(mod:SI (match_dup 1)
  		(match_dup 2)))]
!   ""
!   { return mips_output_division ("div\\t$0,%1,%2", operands); }
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"SI")])
  
! (define_insn "divmoddi4"
    [(set (match_operand:DI 0 "register_operand" "=l")
  	(div:DI (match_operand:DI 1 "register_operand" "d")
  		(match_operand:DI 2 "register_operand" "d")))
     (set (match_operand:DI 3 "register_operand" "=h")
  	(mod:DI (match_dup 1)
  		(match_dup 2)))]
!   "TARGET_64BIT"
!   { return mips_output_division ("ddiv\\t$0,%1,%2", operands); }
    [(set_attr "type"	"idiv")
!    (set_attr "mode"	"DI")])
  
! (define_insn "udivmodsi4"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(udiv:SI (match_operand:SI 1 "register_operand" "d")
  		 (match_operand:SI 2 "register_operand" "d")))
     (set (match_operand:SI 3 "register_operand" "=h")
  	(umod:SI (match_dup 1)
  		 (match_dup 2)))]
!   ""
!   { return mips_output_division ("divu\\t$0,%1,%2", operands); }
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"SI")])
  
! (define_insn "udivmoddi4"
    [(set (match_operand:DI 0 "register_operand" "=l")
  	(udiv:DI (match_operand:DI 1 "register_operand" "d")
  		 (match_operand:DI 2 "register_operand" "d")))
     (set (match_operand:DI 3 "register_operand" "=h")
  	(umod:DI (match_dup 1)
  		 (match_dup 2)))]
!   "TARGET_64BIT"
!   { return mips_output_division ("ddivu\\t$0,%1,%2", operands); }
    [(set_attr "type"	"idiv")
     (set_attr "mode"	"DI")])
  ;;
  ;;  ....................
  ;;


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