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] standard_80387_constant_p improvements


The following patch extends standard_80387_constant_p to match
the remaining x87 mathematical constants.  This patch supports
the instructions fldlg2, fldln2, fldl2e, fldl2t and fldpi in
addition to the fldz and fld1 that are currently supported.

This patch builds upon the reviews of the previous attempts to
support this functionality and the suggestions of Richard Henderson.
Most importantly, these instructions are only used to implement
XFmode loads of the appropriate constants.  Although these will
almost never occur in user-code, they appear in the expansions
of log?f2 and exp?f2 patterns, etc...  Using the standard movxf
mechanism allows these constants to be loaded traditionally on
those platforms where this is a performance advantage.

This patch also provides two additional functions to the i386
back-end.  The first is standard_80387_constant_opcode, suggested
in earlier reviews, that returns the "const char *" of the assembler
opcode used to load the specified constant.  This dramatically
simplifies several patterns in i386.md.  The second function, thats
currently unused, is standard_80387_constant_rtx that may be used
by patterns to request the appropriate CONSTANT_DOUBLE for an x87
mathematical constant.  Providing this API guarantees that the rtx
value will be matched by standard_80387_constant_p when required
(avoiding potential precision issues).

The following patch has been tested on i686-pc-linux-gnu, with a
full bootstrap, all languages except Ada and treelang, and a
complete "make -k check" with no new regressions.


Ok for mainline?


2003-02-14  Roger Sayle  <roger@eyesopen.com>

	* config/i386/i386.c (x86_ext_80387_constants): Use 80387 insns
	to load mathematical constants on K6, Athlon, Pentium 4 and PPro.
	(ext_80387_constants_table): Global table of 80387 special constants
	guarded by ext_80387_constants_init flag when not initialized.
	(init_ext_80387_constants): New function to initialize this table.
	(standard_80387_constant_p): Extend to recognize extra 80387
	constants, in XFmode, on processors where this is a win.
	(standard_80387_constant_opcode): New function to return the
	opcode associated with standard_80387_constant_p.
	(standard_80387_constant_rtx): New function to return the XFmode
	CONST_DOUBLE associated with standard_80387_constant_p.
	(ix86_rtx_costs): Give the new constants the same cost as 1.0.

	* config/i386/i386-protos.h (standard_80387_constant_opcode):
	Prototype here.
	(standard_80387_constant_rtx): Likewise.

	* config/i386/i386.md (*movsf1, *movsf1_nointerunit, *movdf_nointeger,
	*movdf_integer, *movxf_nointeger, *movtf_nointeger, *movxf_integer,
	*movtf_integer): Simplify using new standard_80387_constant_opcode.

	* gcc.dg/i386-387-3.c: New test case.


Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.535
diff -c -3 -p -r1.535 i386.c
*** config/i386/i386.c	11 Feb 2003 21:58:09 -0000	1.535
--- config/i386/i386.c	14 Feb 2003 14:04:20 -0000
*************** const int x86_sse_load0_by_pxor = m_PPRO
*** 522,527 ****
--- 522,528 ----
  const int x86_use_ffreep = m_ATHLON_K8;
  const int x86_rep_movl_optimal = m_386 | m_PENT | m_PPRO | m_K6;
  const int x86_inter_unit_moves = ~(m_ATHLON_K8);
+ const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_PPRO;

  /* In case the average insn count for single function invocation is
     lower than this constant, emit fast (but longer) prologue and
*************** static rtx construct_container PARAMS ((
*** 924,929 ****
--- 925,935 ----
  					const int *, int));
  static enum x86_64_reg_class merge_classes PARAMS ((enum x86_64_reg_class,
  						    enum x86_64_reg_class));
+
+ /* Table of constants used by fldpi, fldln2, etc...  */
+ static REAL_VALUE_TYPE ext_80387_constants_table [5];
+ static bool ext_80387_constants_init = 0;
+ static void init_ext_80387_constants PARAMS ((void));

  /* Initialize the GCC target structure.  */
  #undef TARGET_ATTRIBUTE_TABLE
*************** aligned_operand (op, mode)
*** 4204,4212 ****
    return 1;
  }

  /* Return true if the constant is something that can be loaded with
!    a special instruction.  Only handle 0.0 and 1.0; others are less
!    worthwhile.  */

  int
  standard_80387_constant_p (x)
--- 4210,4243 ----
    return 1;
  }

+ /* Initialize the table of extra 80387 mathematical constants.  */
+
+ static void
+ init_ext_80387_constants ()
+ {
+   static const char * cst[5] =
+   {
+     "0.3010299956639811952256464283594894482",  /* 0: fldlg2  */
+     "0.6931471805599453094286904741849753009",  /* 1: fldln2  */
+     "1.4426950408889634073876517827983434472",  /* 2: fldl2e  */
+     "3.3219280948873623478083405569094566090",  /* 3: fldl2t  */
+     "3.1415926535897932385128089594061862044",  /* 4: fldpi   */
+   };
+   int i;
+
+   for (i = 0; i < 5; i++)
+     {
+       real_from_string (&ext_80387_constants_table[i], cst[i]);
+       /* Ensure each constant is rounded to XFmode precision.  */
+       real_convert (&ext_80387_constants_table[i], XFmode,
+ 		    &ext_80387_constants_table[i]);
+     }
+
+   ext_80387_constants_init = 1;
+ }
+
  /* Return true if the constant is something that can be loaded with
!    a special instruction.  */

  int
  standard_80387_constant_p (x)
*************** standard_80387_constant_p (x)
*** 4214,4229 ****
  {
    if (GET_CODE (x) != CONST_DOUBLE || !FLOAT_MODE_P (GET_MODE (x)))
      return -1;
!   /* Note that on the 80387, other constants, such as pi, that we should support
!      too.  On some machines, these are much slower to load as standard constant,
!      than to load from doubles in memory.  */
    if (x == CONST0_RTX (GET_MODE (x)))
      return 1;
    if (x == CONST1_RTX (GET_MODE (x)))
      return 2;
    return 0;
  }

  /* Return 1 if X is FP constant we can load to SSE register w/o using memory.
   */
  int
--- 4245,4333 ----
  {
    if (GET_CODE (x) != CONST_DOUBLE || !FLOAT_MODE_P (GET_MODE (x)))
      return -1;
!
    if (x == CONST0_RTX (GET_MODE (x)))
      return 1;
    if (x == CONST1_RTX (GET_MODE (x)))
      return 2;
+
+   /* For XFmode constants, try to find a special 80387 instruction on
+      those CPUs that benefit from them.  */
+   if (GET_MODE (x) == XFmode
+       && x86_ext_80387_constants & CPUMASK)
+     {
+       REAL_VALUE_TYPE r;
+       int i;
+
+       if (! ext_80387_constants_init)
+ 	init_ext_80387_constants ();
+
+       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+       for (i = 0; i < 5; i++)
+         if (real_identical (&r, &ext_80387_constants_table[i]))
+ 	  return i + 3;
+     }
+
    return 0;
  }

+ /* Return the opcode of the special instruction to be used to load
+    the constant X.  */
+
+ const char *
+ standard_80387_constant_opcode (x)
+      rtx x;
+ {
+   switch (standard_80387_constant_p (x))
+     {
+     case 1:
+       return "fldz";
+     case 2:
+       return "fld1";
+     case 3:
+       return "fldlg2";
+     case 4:
+       return "fldln2";
+     case 5:
+       return "fldl2e";
+     case 6:
+       return "fldl2t";
+     case 7:
+       return "fldpi";
+     }
+   abort ();
+ }
+
+ /* Return the CONST_DOUBLE representing the 80387 constant that is
+    loaded by the specified special instruction.  The argument IDX
+    matches the return value from standard_80387_constant_p.  */
+
+ rtx
+ standard_80387_constant_rtx (idx)
+      int idx;
+ {
+   int i;
+
+   if (! ext_80387_constants_init)
+     init_ext_80387_constants ();
+
+   switch (idx)
+     {
+     case 3:
+     case 4:
+     case 5:
+     case 6:
+     case 7:
+       i = idx - 3;
+       break;
+
+     default:
+       abort ();
+     }
+
+   return CONST_DOUBLE_FROM_REAL_VALUE (ext_80387_constants_table[i], XFmode);
+ }
+
  /* Return 1 if X is FP constant we can load to SSE register w/o using memory.
   */
  int
*************** ix86_rtx_costs (x, code, outer_code, tot
*** 14717,14726 ****
  	  case 1: /* 0.0 */
  	    *total = 1;
  	    break;
! 	  case 2: /* 1.0 */
  	    *total = 2;
  	    break;
! 	  default:
  	    /* Start with (MEM (SYMBOL_REF)), since that's where
  	       it'll probably end up.  Add a penalty for size.  */
  	    *total = (COSTS_N_INSNS (1)
--- 14821,14831 ----
  	  case 1: /* 0.0 */
  	    *total = 1;
  	    break;
! 	  default: /* Other constants */
  	    *total = 2;
  	    break;
! 	  case 0:
! 	  case -1:
  	    /* Start with (MEM (SYMBOL_REF)), since that's where
  	       it'll probably end up.  Add a penalty for size.  */
  	    *total = (COSTS_N_INSNS (1)
Index: config/i386/i386-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386-protos.h,v
retrieving revision 1.93
diff -c -3 -p -r1.93 i386-protos.h
*** config/i386/i386-protos.h	6 Feb 2003 01:23:40 -0000	1.93
--- config/i386/i386-protos.h	14 Feb 2003 14:04:21 -0000
*************** extern void ix86_output_addr_diff_elt PA
*** 39,44 ****
--- 39,46 ----
  extern int ix86_aligned_p PARAMS ((rtx));

  extern int standard_80387_constant_p PARAMS ((rtx));
+ extern const char *standard_80387_constant_opcode PARAMS ((rtx));
+ extern rtx standard_80387_constant_rtx PARAMS ((int));
  extern int standard_sse_constant_p PARAMS ((rtx));
  extern int symbolic_reference_mentioned_p PARAMS ((rtx));
  extern bool extended_reg_mentioned_p PARAMS ((rtx));
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.434
diff -c -3 -p -r1.434 i386.md
*** config/i386/i386.md	13 Feb 2003 03:09:44 -0000	1.434
--- config/i386/i386.md	14 Feb 2003 14:04:26 -0000
***************
*** 2248,2261 ****
          return "fst%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       abort();

      case 3:
      case 4:
--- 2248,2254 ----
          return "fst%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3:
      case 4:
***************
*** 2354,2367 ****
          return "fst%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       abort();

      case 3:
      case 4:
--- 2347,2353 ----
          return "fst%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3:
      case 4:
***************
*** 2536,2549 ****
          return "fst%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       abort();

      case 3:
      case 4:
--- 2522,2528 ----
          return "fst%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3:
      case 4:
***************
*** 2655,2668 ****
          return "fst%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       abort();

      case 3:
      case 4:
--- 2634,2640 ----
          return "fst%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3:
      case 4:
***************
*** 2902,2915 ****
          return "fstp%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       break;

      case 3: case 4:
        return "#";
--- 2874,2880 ----
          return "fstp%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3: case 4:
        return "#";
***************
*** 2954,2967 ****
          return "fstp%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       break;

      case 3: case 4:
        return "#";
--- 2919,2925 ----
          return "fstp%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3: case 4:
        return "#";
***************
*** 3006,3019 ****
          return "fstp%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       break;

      case 3: case 4:
        return "#";
--- 2964,2970 ----
          return "fstp%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3: case 4:
        return "#";
***************
*** 3058,3071 ****
          return "fstp%z0\t%y0";

      case 2:
!       switch (standard_80387_constant_p (operands[1]))
!         {
!         case 1:
! 	  return "fldz";
! 	case 2:
! 	  return "fld1";
! 	}
!       break;

      case 3: case 4:
        return "#";
--- 3009,3015 ----
          return "fstp%z0\t%y0";

      case 2:
!       return standard_80387_constant_opcode (operands[1]);

      case 3: case 4:
        return "#";

/* Verify that 387 mathematical constants are recognized.  */
/* { dg-do compile { target "i?86-*-*" } } */
/* { dg-options "-O2 -march=i686" } */
/* { dg-final { scan-assembler "fldpi" } } */

long double add_pi(long double x)
{
  return x + 3.1415926535897932385128089594061862044L;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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