attribs.c (decl_attributes): Imply noinline, noclone and no_icf attributes for noipa...
authorJakub Jelinek <jakub@redhat.com>
Thu, 27 Jul 2017 07:53:33 +0000 (09:53 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 27 Jul 2017 07:53:33 +0000 (09:53 +0200)
* attribs.c (decl_attributes): Imply noinline, noclone and no_icf
attributes for noipa attribute.  For naked attribute use
lookup_attribute first before lookup_attribute_spec.
* final.c (rest_of_handle_final): Disable IPA RA for functions with
noipa attribute.
* ipa-visibility.c (non_local_p): Fix comment typos.  Return true
for functions with noipa attribute.
(cgraph_externally_visible_p): Return true for functions with noipa
attribute.
* cgraph.c (cgraph_node::get_availability): Return AVAIL_INTERPOSABLE
for functions with noipa attribute.
* doc/extend.texi: Document noipa function attribute.
* tree-ssa-structalias.c (refered_from_nonlocal_fn): Set *nonlocal_p
also for functions with noipa attribute.
(ipa_pta_execute): Set nonlocal_p also for nodes with noipa attribute.
c-family/
* c-attribs.c (c_common_attribute_table): Add noipa attribute.
(handle_noipa_attribute): New function.
testsuite/
* gcc.dg/attr-noipa.c: New test.
* gcc.dg/ipa/ipa-pta-18.c: New test.
* gcc.dg/ipa/ipa-sra-11.c: New test.

From-SVN: r250607

13 files changed:
gcc/ChangeLog
gcc/attribs.c
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/cgraph.c
gcc/doc/extend.texi
gcc/final.c
gcc/ipa-visibility.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/attr-noipa.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ipa/ipa-pta-18.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c [new file with mode: 0644]
gcc/tree-ssa-structalias.c

index 6866087dbea7d3e6fa7e775524d7ba2663f1bbd5..89180b7d9c22ba1e391aa521a65c2ff040eeceaf 100644 (file)
@@ -1,3 +1,21 @@
+2017-07-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * attribs.c (decl_attributes): Imply noinline, noclone and no_icf
+       attributes for noipa attribute.  For naked attribute use
+       lookup_attribute first before lookup_attribute_spec.
+       * final.c (rest_of_handle_final): Disable IPA RA for functions with
+       noipa attribute.
+       * ipa-visibility.c (non_local_p): Fix comment typos.  Return true
+       for functions with noipa attribute.
+       (cgraph_externally_visible_p): Return true for functions with noipa
+       attribute.
+       * cgraph.c (cgraph_node::get_availability): Return AVAIL_INTERPOSABLE
+       for functions with noipa attribute.
+       * doc/extend.texi: Document noipa function attribute.
+       * tree-ssa-structalias.c (refered_from_nonlocal_fn): Set *nonlocal_p
+       also for functions with noipa attribute.
+       (ipa_pta_execute): Set nonlocal_p also for nodes with noipa attribute.
+
 2017-07-26  Andrew Pinski  <apinski@cavium.com>
 
        * config/aarch64/aarch64.c (thunderx_vector_cost): Decrease cost of
index 5eb19e827952e7d46b0c85c349ee090de1dad740..05fa8ef8692867556300e63e5e239004373e4de2 100644 (file)
@@ -404,8 +404,8 @@ decl_attributes (tree *node, tree attributes, int flags)
      those targets that support it.  */
   if (TREE_CODE (*node) == FUNCTION_DECL
       && attributes
-      && lookup_attribute_spec (get_identifier ("naked"))
-      && lookup_attribute ("naked", attributes) != NULL)
+      && lookup_attribute ("naked", attributes) != NULL
+      && lookup_attribute_spec (get_identifier ("naked")))
     {
       if (lookup_attribute ("noinline", attributes) == NULL)
        attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
@@ -414,6 +414,23 @@ decl_attributes (tree *node, tree attributes, int flags)
        attributes = tree_cons (get_identifier ("noclone"),  NULL, attributes);
     }
 
+  /* A "noipa" function attribute implies "noinline", "noclone" and "no_icf"
+     for those targets that support it.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && attributes
+      && lookup_attribute ("noipa", attributes) != NULL
+      && lookup_attribute_spec (get_identifier ("noipa")))
+    {
+      if (lookup_attribute ("noinline", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
+
+      if (lookup_attribute ("noclone", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noclone"),  NULL, attributes);
+
+      if (lookup_attribute ("no_icf", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("no_icf"),  NULL, attributes);
+    }
+
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
index a457a6c78e4cd4d1bda1dba4342c554e4b675546..4a2b9ad430f331eae0643a42aa928e573309f165 100644 (file)
@@ -1,3 +1,8 @@
+2017-07-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-attribs.c (c_common_attribute_table): Add noipa attribute.
+       (handle_noipa_attribute): New function.
+
 2017-07-07  Torsten Duwe  <duwe@suse.de>
 
        * c-attribs.c (c_common_attribute_table): Add entry for
index ecb00c1d5b9ec56226ce351d0a4f39a879f0f936..0d9ab2d6ae037d36667ee2558e3aa91226f21095 100644 (file)
@@ -66,6 +66,7 @@ static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_always_inline_attribute (tree *, tree, tree, int,
                                            bool *);
@@ -178,6 +179,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_noclone_attribute, false },
   { "no_icf",                 0, 0, true,  false, false,
                              handle_noicf_attribute, false },
+  { "noipa",                 0, 0, true,  false, false,
+                             handle_noipa_attribute, false },
   { "leaf",                   0, 0, true,  false, false,
                              handle_leaf_attribute, false },
   { "always_inline",          0, 0, true,  false, false,
@@ -698,6 +701,21 @@ handle_asan_odr_indicator_attribute (tree *, tree, tree, int, bool *)
 static tree
 handle_stack_protect_attribute (tree *node, tree name, tree, int,
                                bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "noipa" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
index 2f820f1bb676164eb566bbd4188438c2aea58d90..d7c9ba617955122de611c43a8dbadc0280be580a 100644 (file)
@@ -2319,7 +2319,8 @@ cgraph_node::get_availability (symtab_node *ref)
     avail = AVAIL_AVAILABLE;
   else if (transparent_alias)
     ultimate_alias_target (&avail, ref);
-  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))
+          || lookup_attribute ("noipa", DECL_ATTRIBUTES (decl)))
     avail = AVAIL_INTERPOSABLE;
   else if (!externally_visible)
     avail = AVAIL_AVAILABLE;
index 156f7f2569ccd31dfeea08527c695b9384a50e52..6934b4cde3e53ce2f073f2fe9f478b5c0dfdad16 100644 (file)
@@ -2984,6 +2984,19 @@ asm ("");
 (@pxref{Extended Asm}) in the called function, to serve as a special
 side-effect.
 
+@item noipa
+@cindex @code{noipa} function attribute
+Disable interprocedural optimizations between the function with this
+attribute and its callers, as if the body of the function is not available
+when optimizing callers and the callers are unavailable when optimizing
+the body.  This attribute implies @code{noinline}, @code{noclone} and
+@code{no_icf} attributes.    However, this attribute is not equivalent
+to a combination of other attributes, because its purpose is to suppress
+existing and future optimizations employing interprocedural analysis,
+including those that do not have an attribute suitable for disabling
+them individually.  This attribute is supported mainly for the purpose
+of testing the compiler.
+
 @item nonnull (@var{arg-index}, @dots{})
 @cindex @code{nonnull} function attribute
 @cindex functions with non-null pointer arguments
index 356c923c4cd7294a2a2d7ec51b354d78105a6111..2a24f4fe10208306ab717cd1bad2774d7b6151ad 100644 (file)
@@ -4492,7 +4492,8 @@ rest_of_handle_final (void)
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
-  if (flag_ipa_ra)
+  if (flag_ipa_ra
+      && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
     collect_fn_hard_reg_usage ();
   final_end_function ();
 
index 13cf2a3a1cf0cb3fce97837ef6e7a2bfe7dadc31..3033f20e3f14e17956d56b1a5ded1b9d54216925 100644 (file)
@@ -92,10 +92,11 @@ non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
   return !(node->only_called_directly_or_aliased_p ()
           /* i386 would need update to output thunk with local calling
-             convetions.  */
+             conventions.  */
           && !node->thunk.thunk_p
           && node->definition
           && !DECL_EXTERNAL (node->decl)
+          && !lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl))
           && !node->externally_visible
           && !node->used_from_other_partition
           && !node->in_other_partition
@@ -211,6 +212,8 @@ cgraph_externally_visible_p (struct cgraph_node *node,
   if (lookup_attribute ("externally_visible",
                        DECL_ATTRIBUTES (node->decl)))
     return true;
+  if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+    return true;
   if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
       && lookup_attribute ("dllexport",
                           DECL_ATTRIBUTES (node->decl)))
index 228b885dba9aefc900ff1348119a04838c8cbdf5..532870c90a89e8c00a6e45c0986c8587c1e0d191 100644 (file)
@@ -1,3 +1,9 @@
+2017-07-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.dg/attr-noipa.c: New test.
+       * gcc.dg/ipa/ipa-pta-18.c: New test.
+       * gcc.dg/ipa/ipa-sra-11.c: New test.
+
 2017-07-25  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        * gcc.target/powerpc/vsx-himode.c: Delete -mvsx-small-integer
diff --git a/gcc/testsuite/gcc.dg/attr-noipa.c b/gcc/testsuite/gcc.dg/attr-noipa.c
new file mode 100644 (file)
index 0000000..1d2b868
--- /dev/null
@@ -0,0 +1,188 @@
+/* Test the noipa attribute.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+static inline int __attribute__((noipa))
+fn1 (void) /* { dg-warning "inline function \[^\n\]* given attribute noinline" "" } */
+{
+  return 1;
+}
+
+/* Verify the function is not inlined into its caller.  */
+
+static __attribute__((noipa)) int
+fn2 (int x, int y)
+{
+  return x + y;
+}
+
+int
+fn3 (int x)
+{
+  return fn2 (x, 0);
+}
+
+/* { dg-final { scan-tree-dump "= fn2 \\(" "optimized" } } */
+
+void fn4 (char *);
+
+/* Verify the function is not cloned.  */
+
+__attribute__((__noipa__)) static int
+fn5 (int x, int y)
+{
+  char *p = __builtin_alloca (x + y);
+  fn4 (p);
+  return x + y;
+}
+
+int
+fn6 (int x)
+{
+  return fn5 (x, 2);
+}
+
+/* { dg-final { scan-tree-dump "= fn5 \\(" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "fn5\\.constprop" "optimized" } } */
+
+/* Verify we still remove unused function calls, even if they have
+   noipa attribute.  */
+
+static void fn7 (void) __attribute__((noipa));
+static void
+fn7 (void)
+{
+}
+
+/* { dg-final { scan-tree-dump-not "fn7 \\(" "optimized" } } */
+
+/* Verify noipa functions are not ICF optimized.  */
+
+static __attribute__((noipa)) int
+fn8 (int x)
+{
+  return x + 12;
+}
+
+static __attribute__((noipa)) int
+fn9 (int x)
+{
+  return x + 12;
+}
+
+int
+fn10 (int x)
+{
+  return fn8 (x) + fn9 (x);
+}
+
+/* { dg-final { scan-tree-dump "fn8 \\(int" "optimized" } } */
+/* { dg-final { scan-tree-dump "fn9 \\(int" "optimized" } } */
+
+/* Verify IPA-VRP is not performed.  */
+
+void fn11 (void);
+
+static int __attribute__((noipa))
+fn12 (int x)
+{
+  if (x < 6 || x >= 29)
+    fn11 ();
+}
+
+void
+fn13 (int x)
+{
+  fn12 (6 + (x & 15));
+}
+
+/* { dg-final { scan-tree-dump "fn11 \\(\\)" "optimized" } } */
+
+void fn14 (void);
+
+__attribute__((noipa)) static int
+fn15 (int x)
+{
+  return x & 7;
+}
+
+int
+fn16 (int x)
+{
+  x = fn15 (x);
+  if (x < 0 || x >= 7)
+    fn14 ();
+}
+
+/* { dg-final { scan-tree-dump "fn14 \\(\\)" "optimized" } } */
+
+/* Verify IPA BIT CP is not performed.  */
+
+void fn17 (void);
+
+__attribute__((noipa)) static int
+fn18 (int x)
+{
+  if (x & 8)
+    fn17 ();
+}
+
+void
+fn19 (void)
+{
+  fn18 (1);
+  fn18 (2);
+  fn18 (4);
+  fn18 (16);
+  fn18 (32);
+  fn18 (64);
+}
+
+/* { dg-final { scan-tree-dump "fn17 \\(\\)" "optimized" } } */
+
+/* Ensure pure/const discovery is not performed.  */
+
+int var1;
+void fn20 (void);
+
+__attribute__((noipa)) static int
+fn21 (int x, int y)
+{
+  return x * y;
+}
+
+int
+fn22 (void)
+{
+  var1 = 7;
+  asm volatile ("" : "+g" (var1) : : "memory");
+  int a = var1;
+  int b = fn21 (a, a);
+  if (a != var1)
+    fn20 ();
+  return b;
+}
+
+/* { dg-final { scan-tree-dump "fn20 \\(\\)" "optimized" } } */
+
+/* Verify IPA alignment propagation is not performed.  */
+
+static __attribute__ ((aligned(16))) char var2[32];
+void fn23 (void);
+
+__attribute__((noipa)) static void
+fn24 (char *p)
+{
+  if ((((__UINTPTR_TYPE__) p) & 15) != 0)
+    fn23 ();
+  asm ("");
+}
+
+void
+fn25 (void)
+{
+  fn24 (var2);
+  fn24 (var2 + 16);
+}
+
+/* { dg-final { scan-tree-dump "fn20 \\(\\)" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-pta-18.c b/gcc/testsuite/gcc.dg/ipa/ipa-pta-18.c
new file mode 100644 (file)
index 0000000..01b0976
--- /dev/null
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta2-details -fdump-tree-fre3-details" } */
+
+static int __attribute__((noipa))
+foo (int *p, int *q)
+{
+  *p = 1;
+  *q = 0;
+  return *p;
+}
+
+extern void abort (void);
+
+int main()
+{
+  int a, b;
+  if (foo (&a, &b) != 1)
+    abort ();
+  return 0;
+}
+
+/* Verify we can disambiguate *p and *q in foo.  */
+
+/* { dg-final { scan-ipa-dump "foo.arg0 = &a" "pta2" } } */
+/* { dg-final { scan-ipa-dump "foo.arg1 = &b" "pta2" } } */
+/* { dg-final { scan-tree-dump-not "Replaced \\\*p_2\\\(D\\\) with 1" "fre3" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-11.c
new file mode 100644 (file)
index 0000000..e91423a
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details"  } */
+
+struct bovid
+{
+  float red;
+  int green;
+  void *blue;
+};
+
+extern int printf (const char *, ...);
+extern void abort (void);
+
+static int
+__attribute__((noipa))
+ox (struct bovid cow)
+{
+  if (cow.green != 6)
+    abort ();
+
+  printf ("green: %f\nblue: %p\nblue again: %p\n", cow.green,
+         cow.blue, cow.blue);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  struct bovid cow;
+
+  cow.red = 7.4;
+  cow.green = 6;
+  cow.blue = &cow;
+
+  ox (cow);
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "About to replace expr" "eipa_sra" } } */
index 16746e3da9280f5b56fd35672b40d9291974da9d..e743e35033eadcf9461ff322c6690bfcf21034a6 100644 (file)
@@ -7764,7 +7764,8 @@ refered_from_nonlocal_fn (struct cgraph_node *node, void *data)
   bool *nonlocal_p = (bool *)data;
   *nonlocal_p |= (node->used_from_other_partition
                  || node->externally_visible
-                 || node->force_output);
+                 || node->force_output
+                 || lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)));
   return false;
 }
 
@@ -7824,7 +7825,9 @@ ipa_pta_execute (void)
         constraints for parameters.  */
       bool nonlocal_p = (node->used_from_other_partition
                         || node->externally_visible
-                        || node->force_output);
+                        || node->force_output
+                        || lookup_attribute ("noipa",
+                                             DECL_ATTRIBUTES (node->decl)));
       node->call_for_symbol_thunks_and_aliases (refered_from_nonlocal_fn,
                                                &nonlocal_p, true);