i386.c (x86_ext_80387_constants): Use 80387 insns to load mathematical constants...
authorRoger Sayle <roger@eyesopen.com>
Sun, 16 Feb 2003 01:35:38 +0000 (01:35 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Sun, 16 Feb 2003 01:35:38 +0000 (01:35 +0000)
2003-02-15  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.

From-SVN: r62958

gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/i386-387-3.c [new file with mode: 0644]

index 152ba528bce826d99ddad8db49ed575092bb0741..bbd38c38325031714c10ba3ca992f10602001fe2 100644 (file)
@@ -1,3 +1,26 @@
+2003-02-15  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.
+
 2003-02-15  Geoffrey Keating  <geoffk@apple.com>
 
        * doc/invoke.texi (Optimize Options): Correct @option syntax.
index c920985b21ffab9e7579656e098696f3ed85a6d4..b83aae745c822353cfb520f7f95b4f7334801dcd 100644 (file)
@@ -39,6 +39,8 @@ extern void ix86_output_addr_diff_elt PARAMS ((FILE *, int, int));
 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 c627e3d4a17c0396e58ab13c9e9fb5b0f56182e0..fd7a9c7531197e609cbc6fe83c6d7ae43bba7fa0 100644 (file)
@@ -522,6 +522,7 @@ const int x86_sse_load0_by_pxor = m_PPRO | m_PENT4;
 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
@@ -934,6 +935,11 @@ static rtx construct_container PARAMS ((enum machine_mode, tree, int, int, int,
                                        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));
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -4214,9 +4220,34 @@ aligned_operand (op, mode)
   return 1;
 }
 \f
+/* 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.  Only handle 0.0 and 1.0; others are less
-   worthwhile.  */
+   a special instruction.  */
 
 int
 standard_80387_constant_p (x)
@@ -4224,16 +4255,89 @@ standard_80387_constant_p (x)
 {
   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;
+
+  /* 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
@@ -14737,10 +14841,11 @@ ix86_rtx_costs (x, code, outer_code, total)
          case 1: /* 0.0 */
            *total = 1;
            break;
-         case 2: /* 1.0 */
+         default: /* Other constants */
            *total = 2;
            break;
-         default:
+         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 34905f8ac61d1030cb3e979356b58b88a83097a0..94206fab766b95b0ad915f6b9e5a3a89265de08c 100644 (file)
         return "fst%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      abort();
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3:
     case 4:
         return "fst%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      abort();
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3:
     case 4:
         return "fst%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      abort();
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3:
     case 4:
         return "fst%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      abort();
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3:
     case 4:
         return "fstp%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      break;
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3: case 4:
       return "#";
         return "fstp%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      break;
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3: case 4:
       return "#";
         return "fstp%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      break;
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3: case 4:
       return "#";
         return "fstp%z0\t%y0";
 
     case 2:
-      switch (standard_80387_constant_p (operands[1]))
-        {
-        case 1:
-         return "fldz";
-       case 2:
-         return "fld1";
-       }
-      break;
+      return standard_80387_constant_opcode (operands[1]);
 
     case 3: case 4:
       return "#";
index dc0b5db3a41a3a78ebe1008079279c9433749ee8..18044bbf1b69ddbf48786d497a082ceaf158b482 100644 (file)
@@ -1,3 +1,7 @@
+2003-02-15  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/i386-387-3.c: New test case.
+
 2003-02-14  Josef Zlomek  <zlomekj@suse.cz>
 
        * gcc.dg/20030213-1.c: Expect warning for unsupported -fpic on
diff --git a/gcc/testsuite/gcc.dg/i386-387-3.c b/gcc/testsuite/gcc.dg/i386-387-3.c
new file mode 100644 (file)
index 0000000..f61cd61
--- /dev/null
@@ -0,0 +1,10 @@
+/* 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;
+}
+