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: IA64 inline integer division


When using the -minline-int-divide-max-throughput or
-minline-int-divide-min-latency options on IA64 the integer mod function
can return the wrong result.  In addition, the inlined versions of the
32 bit integer mod and div are slower than the library versions.

This patch fixes both problems by replacing a memory load of a floating
point constant with an immediate integer load and a setf_exp_xf
instruction.  This is faster and matches what the __divsi, etc.
functions already do in libgcc.

Tested on IA64 HP-UX and Linux with no regressions.  The new test shows
the failure you get without the patch.

Steve Ellcey
sje@cup.hp.com


2004-03-09  Steve Ellcey  <sje@cup.hp.com>

	* config/ia64/ia64.md (divsi3): Fix algorithm.
	  (udivsi3): Ditto.
	  (setf_exp_xf): Remove '*' from name.
	* testsuite/gcc.dg/20040309-1.c: New test.

*** gcc.orig/gcc/gcc/config/ia64/ia64.md	Tue Mar  9 10:14:07 2004
--- gcc/gcc/gcc/config/ia64/ia64.md	Tue Mar  9 10:15:11 2004
***************
*** 1840,1846 ****
  		(match_operand:SI 2 "general_operand" "")))]
    "TARGET_INLINE_INT_DIV"
  {
!   rtx op1_xf, op2_xf, op0_xf, op0_di, twon34;
    REAL_VALUE_TYPE twon34_r;
  
    op0_xf = gen_reg_rtx (XFmode);
--- 1840,1846 ----
  		(match_operand:SI 2 "general_operand" "")))]
    "TARGET_INLINE_INT_DIV"
  {
!   rtx op1_xf, op2_xf, op0_xf, op0_di, twon34, twon34_exp;
    REAL_VALUE_TYPE twon34_r;
  
    op0_xf = gen_reg_rtx (XFmode);
***************
*** 1857,1865 ****
    expand_float (op2_xf, operands[2], 0);
  
    /* 2^-34 */
!   real_2expN (&twon34_r, -34);
!   twon34 = CONST_DOUBLE_FROM_REAL_VALUE (twon34_r, XFmode);
!   twon34 = force_reg (XFmode, twon34);
  
    emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));
  
--- 1857,1866 ----
    expand_float (op2_xf, operands[2], 0);
  
    /* 2^-34 */
!   twon34_exp = gen_reg_rtx (DImode);
!   emit_move_insn (twon34_exp, GEN_INT (65501));
!   twon34 = gen_reg_rtx (XFmode);
!   emit_insn (gen_setf_exp_xf (twon34, twon34_exp));
  
    emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));
  
***************
*** 1897,1903 ****
  		 (match_operand:SI 2 "general_operand" "")))]
    "TARGET_INLINE_INT_DIV"
  {
!   rtx op1_xf, op2_xf, op0_xf, op0_di, twon34;
    REAL_VALUE_TYPE twon34_r;
  
    op0_xf = gen_reg_rtx (XFmode);
--- 1898,1904 ----
  		 (match_operand:SI 2 "general_operand" "")))]
    "TARGET_INLINE_INT_DIV"
  {
!   rtx op1_xf, op2_xf, op0_xf, op0_di, twon34, twon34_exp;
    REAL_VALUE_TYPE twon34_r;
  
    op0_xf = gen_reg_rtx (XFmode);
***************
*** 1914,1922 ****
    expand_float (op2_xf, operands[2], 1);
  
    /* 2^-34 */
!   real_2expN (&twon34_r, -34);
!   twon34 = CONST_DOUBLE_FROM_REAL_VALUE (twon34_r, XFmode);
!   twon34 = force_reg (XFmode, twon34);
  
    emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));
  
--- 1915,1924 ----
    expand_float (op2_xf, operands[2], 1);
  
    /* 2^-34 */
!   twon34_exp = gen_reg_rtx (DImode);
!   emit_move_insn (twon34_exp, GEN_INT (65501));
!   twon34 = gen_reg_rtx (XFmode);
!   emit_insn (gen_setf_exp_xf (twon34, twon34_exp));
  
    emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));
  
***************
*** 2712,2718 ****
    [(set_attr "itanium_class" "fmisc")
     (set_attr "predicable" "no")])
  
! (define_insn "*setf_exp_xf"
    [(set (match_operand:XF 0 "fr_register_operand" "=f")
          (unspec:XF [(match_operand:DI 1 "register_operand" "r")]
                    UNSPEC_SETF_EXP))]
--- 2714,2720 ----
    [(set_attr "itanium_class" "fmisc")
     (set_attr "predicable" "no")])
  
! (define_insn "setf_exp_xf"
    [(set (match_operand:XF 0 "fr_register_operand" "=f")
          (unspec:XF [(match_operand:DI 1 "register_operand" "r")]
                    UNSPEC_SETF_EXP))]
*** gcc.orig/gcc/gcc/testsuite/gcc.dg/20040309-1.c	Thu Mar  4 07:55:56 2004
--- gcc/gcc/gcc/testsuite/gcc.dg/20040309-1.c	Tue Mar  9 10:14:48 2004
***************
*** 0 ****
--- 1,17 ----
+ /* Test integer mod on ia64.  There was a bug in the inline integer
+    division code. */
+ 
+ /* { dg-do run } */
+ /* { dg-options "-minline-int-divide-max-throughput" { target ia64-*-* } } */
+ 
+ extern void abort (void);
+ 
+ volatile int i = 10;
+ volatile int j = 10;
+ 
+ int main()
+ {
+         int k = i % j;
+         if (k != 0) abort();
+ 	return 0;
+ }


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