This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[i386] __builtin_ia32_stmxcsr could be pure
- From: Marc Glisse <marc dot glisse at inria dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 26 May 2017 10:55:49 +0200 (CEST)
- Subject: [i386] __builtin_ia32_stmxcsr could be pure
- Authentication-results: sourceware.org; auth=none
Hello,
glibc marks fegetround as a pure function. On x86, people tend to use
_MM_GET_ROUNDING_MODE instead, which could benefit from the same. I think
it is safe, but a second opinion would be welcome.
I could have handled just this builtin, but it seemed better to provide
def_builtin_pure (like "const" already has) since there should be other
builtins that can be marked this way (maybe the gathers?).
Bootstrap+testsuite on x86_64-pc-linux-gnu with default languages.
2017-05-29 Marc Glisse <marc.glisse@inria.fr>
gcc/
* config/i386/i386.c (struct builtin_isa): New field pure_p.
Reorder for compactness.
(def_builtin, def_builtin2, ix86_add_new_builtins): Handle pure_p.
(def_builtin_pure, def_builtin_pure2): New functions.
(ix86_init_mmx_sse_builtins) [__builtin_ia32_stmxcsr]: Mark as pure.
gcc/testsuite/
* gcc.target/i386/getround.c: New file.
--
Marc Glisse
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c (revision 248449)
+++ gcc/config/i386/i386.c (working copy)
@@ -31952,25 +31952,26 @@ enum ix86_builtins
IX86_BUILTIN__BDESC_MAX_LAST = IX86_BUILTIN__BDESC_MAX_FIRST
};
/* Table for the ix86 builtin decls. */
static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
/* Table of all of the builtin functions that are possible with different ISA's
but are waiting to be built until a function is declared to use that
ISA. */
struct builtin_isa {
- const char *name; /* function name */
- enum ix86_builtin_func_type tcode; /* type to use in the declaration */
HOST_WIDE_INT isa; /* isa_flags this builtin is defined for */
HOST_WIDE_INT isa2; /* additional isa_flags this builtin is defined for */
- bool const_p; /* true if the declaration is constant */
+ const char *name; /* function name */
+ enum ix86_builtin_func_type tcode; /* type to use in the declaration */
+ unsigned char const_p:1; /* true if the declaration is constant */
+ unsigned char pure_p:1; /* true if the declaration has pure attribute */
bool leaf_p; /* true if the declaration has leaf attribute */
bool nothrow_p; /* true if the declaration has nothrow attribute */
bool set_and_not_built_p;
};
static struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
/* Bits that can still enable any inclusion of a builtin. */
static HOST_WIDE_INT deferred_isa_values = 0;
static HOST_WIDE_INT deferred_isa_values2 = 0;
@@ -32027,20 +32028,21 @@ def_builtin (HOST_WIDE_INT mask, const c
{
/* Just a MASK where set_and_not_built_p == true can potentially
include a builtin. */
deferred_isa_values |= mask;
ix86_builtins[(int) code] = NULL_TREE;
ix86_builtins_isa[(int) code].tcode = tcode;
ix86_builtins_isa[(int) code].name = name;
ix86_builtins_isa[(int) code].leaf_p = false;
ix86_builtins_isa[(int) code].nothrow_p = false;
ix86_builtins_isa[(int) code].const_p = false;
+ ix86_builtins_isa[(int) code].pure_p = false;
ix86_builtins_isa[(int) code].set_and_not_built_p = true;
}
}
return decl;
}
/* Like def_builtin, but also marks the function decl "const". */
static inline tree
@@ -32049,20 +32051,35 @@ def_builtin_const (HOST_WIDE_INT mask, c
{
tree decl = def_builtin (mask, name, tcode, code);
if (decl)
TREE_READONLY (decl) = 1;
else
ix86_builtins_isa[(int) code].const_p = true;
return decl;
}
+/* Like def_builtin, but also marks the function decl "pure". */
+
+static inline tree
+def_builtin_pure (HOST_WIDE_INT mask, const char *name,
+ enum ix86_builtin_func_type tcode, enum ix86_builtins code)
+{
+ tree decl = def_builtin (mask, name, tcode, code);
+ if (decl)
+ DECL_PURE_P (decl) = 1;
+ else
+ ix86_builtins_isa[(int) code].pure_p = true;
+
+ return decl;
+}
+
/* Like def_builtin, but for additional isa2 flags. */
static inline tree
def_builtin2 (HOST_WIDE_INT mask, const char *name,
enum ix86_builtin_func_type tcode,
enum ix86_builtins code)
{
tree decl = NULL_TREE;
ix86_builtins_isa[(int) code].isa2 = mask;
@@ -32083,20 +32100,21 @@ def_builtin2 (HOST_WIDE_INT mask, const
{
/* Just a MASK where set_and_not_built_p == true can potentially
include a builtin. */
deferred_isa_values2 |= mask;
ix86_builtins[(int) code] = NULL_TREE;
ix86_builtins_isa[(int) code].tcode = tcode;
ix86_builtins_isa[(int) code].name = name;
ix86_builtins_isa[(int) code].leaf_p = false;
ix86_builtins_isa[(int) code].nothrow_p = false;
ix86_builtins_isa[(int) code].const_p = false;
+ ix86_builtins_isa[(int) code].pure_p = false;
ix86_builtins_isa[(int) code].set_and_not_built_p = true;
}
return decl;
}
/* Like def_builtin, but also marks the function decl "const". */
static inline tree
def_builtin_const2 (HOST_WIDE_INT mask, const char *name,
@@ -32104,20 +32122,35 @@ def_builtin_const2 (HOST_WIDE_INT mask,
{
tree decl = def_builtin2 (mask, name, tcode, code);
if (decl)
TREE_READONLY (decl) = 1;
else
ix86_builtins_isa[(int) code].const_p = true;
return decl;
}
+/* Like def_builtin, but also marks the function decl "pure". */
+
+static inline tree
+def_builtin_pure2 (HOST_WIDE_INT mask, const char *name,
+ enum ix86_builtin_func_type tcode, enum ix86_builtins code)
+{
+ tree decl = def_builtin2 (mask, name, tcode, code);
+ if (decl)
+ DECL_PURE_P (decl) = 1;
+ else
+ ix86_builtins_isa[(int) code].pure_p = true;
+
+ return decl;
+}
+
/* Add any new builtin functions for a given ISA that may not have been
declared. This saves a bit of space compared to adding all of the
declarations to the tree, even if we didn't use them. */
static void
ix86_add_new_builtins (HOST_WIDE_INT isa, HOST_WIDE_INT isa2)
{
if ((isa & deferred_isa_values) == 0
&& (isa2 & deferred_isa_values2) == 0)
return;
@@ -32142,20 +32175,22 @@ ix86_add_new_builtins (HOST_WIDE_INT isa
ix86_builtins_isa[i].set_and_not_built_p = false;
type = ix86_get_builtin_func_type (ix86_builtins_isa[i].tcode);
decl = add_builtin_function_ext_scope (ix86_builtins_isa[i].name,
type, i, BUILT_IN_MD, NULL,
NULL_TREE);
ix86_builtins[i] = decl;
if (ix86_builtins_isa[i].const_p)
TREE_READONLY (decl) = 1;
+ if (ix86_builtins_isa[i].pure_p)
+ DECL_PURE_P (decl) = 1;
if (ix86_builtins_isa[i].leaf_p)
DECL_ATTRIBUTES (decl) = build_tree_list (get_identifier ("leaf"),
NULL_TREE);
if (ix86_builtins_isa[i].nothrow_p)
TREE_NOTHROW (decl) = 1;
}
}
current_target_pragma = saved_current_target_pragma;
}
@@ -32495,22 +32530,22 @@ ix86_init_mmx_sse_builtins (void)
ftype = INT_FTYPE_V4SF_V4SF;
def_builtin_const (d->mask, d->name, ftype, d->code);
}
BDESC_VERIFYS (IX86_BUILTIN__BDESC_COMI_LAST,
IX86_BUILTIN__BDESC_COMI_FIRST,
ARRAY_SIZE (bdesc_comi) - 1);
/* SSE */
def_builtin (OPTION_MASK_ISA_SSE, "__builtin_ia32_ldmxcsr",
VOID_FTYPE_UNSIGNED, IX86_BUILTIN_LDMXCSR);
- def_builtin (OPTION_MASK_ISA_SSE, "__builtin_ia32_stmxcsr",
- UNSIGNED_FTYPE_VOID, IX86_BUILTIN_STMXCSR);
+ def_builtin_pure (OPTION_MASK_ISA_SSE, "__builtin_ia32_stmxcsr",
+ UNSIGNED_FTYPE_VOID, IX86_BUILTIN_STMXCSR);
/* SSE or 3DNow!A */
def_builtin (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A,
"__builtin_ia32_maskmovq", VOID_FTYPE_V8QI_V8QI_PCHAR,
IX86_BUILTIN_MASKMOVQ);
/* SSE2 */
def_builtin (OPTION_MASK_ISA_SSE2, "__builtin_ia32_maskmovdqu",
VOID_FTYPE_V16QI_V16QI_PCHAR, IX86_BUILTIN_MASKMOVDQU);
Index: gcc/testsuite/gcc.target/i386/getround.c
===================================================================
--- gcc/testsuite/gcc.target/i386/getround.c (nonexistent)
+++ gcc/testsuite/gcc.target/i386/getround.c (working copy)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -msse" } */
+
+#include <xmmintrin.h>
+
+unsigned save;
+
+void f(unsigned mode){
+ unsigned tmp = _MM_GET_ROUNDING_MODE();
+ _MM_SET_ROUNDING_MODE(mode);
+ save = tmp;
+}
+
+/* { dg-final { scan-assembler-times "stmxcsr" 1 } } */