]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
inter-procedural value range propagation
authorJan Hubicka <jh@suse.cz>
Mon, 20 Nov 2023 18:35:53 +0000 (19:35 +0100)
committerJan Hubicka <jh@suse.cz>
Mon, 20 Nov 2023 18:37:45 +0000 (19:37 +0100)
implement very basic propapgation of return value ranges from VRP
pass.  This helps std::vector's push_back since we work out value range of
allocated block.  This propagates only within single translation unit.  I hoped
we will also do the propagation at WPA stage, but that needs more work on
ipa-cp side.

I also added code auto-detecting return_nonnull and corresponding -Wsuggest-attribute.

gcc/ChangeLog:

* cgraph.cc (add_detected_attribute_1): New function.
(cgraph_node::add_detected_attribute): Likewise.
* cgraph.h (cgraph_node::add_detected_attribute): Declare.
* common.opt: Add -Wsuggest-attribute=returns_nonnull.
* doc/invoke.texi: Document new flag.
* gimple-range-fold.cc (fold_using_range::range_of_call):
Use known reutrn value ranges.
* ipa-prop.cc (struct ipa_return_value_summary): New type.
(class ipa_return_value_sum_t): New type.
(ipa_return_value_sum): New summary.
(ipa_record_return_value_range): New function.
(ipa_return_value_range): New function.
* ipa-prop.h (ipa_return_value_range): Declare.
(ipa_record_return_value_range): Declare.
* ipa-pure-const.cc (warn_function_returns_nonnull): New funcion.
* ipa-utils.h (warn_function_returns_nonnull): Declare.
* symbol-summary.h: Fix comment.
* tree-vrp.cc (execute_ranger_vrp): Record return values.

gcc/testsuite/ChangeLog:

* g++.dg/ipa/devirt-2.C: Add noipa attribute to prevent ipa-vrp.
* g++.dg/ipa/devirt-7.C: Disable ipa-vrp.
* g++.dg/ipa/ipa-icf-2.C: Disable ipa-vrp.
* g++.dg/ipa/ipa-icf-3.C: Disable ipa-vrp.
* g++.dg/ipa/ivinline-1.C: Disable ipa-vrp.
* g++.dg/ipa/ivinline-3.C: Disable ipa-vrp.
* g++.dg/ipa/ivinline-5.C: Disable ipa-vrp.
* g++.dg/ipa/ivinline-8.C: Disable ipa-vrp.
* g++.dg/ipa/nothrow-1.C: Disable ipa-vrp.
* g++.dg/ipa/pure-const-1.C: Disable ipa-vrp.
* g++.dg/ipa/pure-const-2.C: Disable ipa-vrp.
* g++.dg/lto/inline-crossmodule-1_0.C: Disable ipa-vrp.
* gcc.c-torture/compile/pr106433.c: Add noipa attribute to prevent ipa-vrp.
* gcc.c-torture/execute/frame-address.c: Likewise.
* gcc.dg/vla-1.c: Add noipa attribute to prevent ipa-vrp.
* gcc.dg/ipa/fopt-info-inline-1.c: Disable ipa-vrp.
* gcc.dg/ipa/ipa-icf-25.c: Disable ipa-vrp.
* gcc.dg/ipa/ipa-icf-38.c: Disable ipa-vrp.
* gcc.dg/ipa/pure-const-1.c: Disable ipa-vrp.
* gcc.dg/ipa/remref-0.c: Add noipa attribute to prevent ipa-vrp.
* gcc.dg/tree-prof/time-profiler-1.c: Disable ipa-vrp.
* gcc.dg/tree-prof/time-profiler-2.c: Disable ipa-vrp.
* gcc.dg/tree-ssa/pr110269.c: Disable ipa-vrp.
* gcc.dg/tree-ssa/pr20701.c: Disable ipa-vrp.
* gcc.dg/tree-ssa/vrp05.c: Disable ipa-vrp.
* gcc.dg/tree-ssa/return-value-range-1.c: New test.

38 files changed:
gcc/cgraph.cc
gcc/cgraph.h
gcc/common.opt
gcc/doc/invoke.texi
gcc/gimple-range-fold.cc
gcc/ipa-prop.cc
gcc/ipa-prop.h
gcc/ipa-pure-const.cc
gcc/ipa-utils.h
gcc/symbol-summary.h
gcc/testsuite/g++.dg/ipa/devirt-2.C
gcc/testsuite/g++.dg/ipa/devirt-7.C
gcc/testsuite/g++.dg/ipa/ipa-icf-2.C
gcc/testsuite/g++.dg/ipa/ipa-icf-3.C
gcc/testsuite/g++.dg/ipa/ivinline-1.C
gcc/testsuite/g++.dg/ipa/ivinline-3.C
gcc/testsuite/g++.dg/ipa/ivinline-5.C
gcc/testsuite/g++.dg/ipa/ivinline-8.C
gcc/testsuite/g++.dg/ipa/nothrow-1.C
gcc/testsuite/g++.dg/ipa/pure-const-1.C
gcc/testsuite/g++.dg/ipa/pure-const-2.C
gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C
gcc/testsuite/gcc.c-torture/compile/pr106433.c
gcc/testsuite/gcc.c-torture/execute/frame-address.c
gcc/testsuite/gcc.dg/ipa/fopt-info-inline-1.c
gcc/testsuite/gcc.dg/ipa/ipa-icf-25.c
gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c
gcc/testsuite/gcc.dg/ipa/pure-const-1.c
gcc/testsuite/gcc.dg/ipa/remref-0.c
gcc/testsuite/gcc.dg/nonnull-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c
gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c
gcc/testsuite/gcc.dg/tree-ssa/pr110269.c
gcc/testsuite/gcc.dg/tree-ssa/pr20701.c
gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/vrp05.c
gcc/testsuite/gcc.dg/vla-1.c
gcc/tree-vrp.cc

index e41e5ad3ae74d1fd73aef79f7cf96dac0dffa015..f93259a8c70c441e4fdb2ccbd1ef2bba62b5e477 100644 (file)
@@ -2629,6 +2629,54 @@ cgraph_node::set_malloc_flag (bool malloc_p)
   return changed;
 }
 
+/* Worker to set malloc flag.  */
+static void
+add_detected_attribute_1 (cgraph_node *node, const char *attr, bool *changed)
+{
+  if (!lookup_attribute (attr, DECL_ATTRIBUTES (node->decl)))
+    {
+      DECL_ATTRIBUTES (node->decl) = tree_cons (get_identifier (attr),
+                                        NULL_TREE, DECL_ATTRIBUTES (node->decl));
+      *changed = true;
+    }
+
+  ipa_ref *ref;
+  FOR_EACH_ALIAS (node, ref)
+    {
+      cgraph_node *alias = dyn_cast<cgraph_node *> (ref->referring);
+      if (alias->get_availability () > AVAIL_INTERPOSABLE)
+       add_detected_attribute_1 (alias, attr, changed);
+    }
+
+  for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+    if (e->caller->thunk
+       && (e->caller->get_availability () > AVAIL_INTERPOSABLE))
+      add_detected_attribute_1 (e->caller, attr, changed);
+}
+
+/* Add attribyte ATTR to function and its aliases.  */
+
+bool
+cgraph_node::add_detected_attribute (const char *attr)
+{
+  bool changed = false;
+
+  if (get_availability () > AVAIL_INTERPOSABLE)
+    add_detected_attribute_1 (this, attr, &changed);
+  else
+    {
+      ipa_ref *ref;
+
+      FOR_EACH_ALIAS (this, ref)
+       {
+         cgraph_node *alias = dyn_cast<cgraph_node *> (ref->referring);
+         if (alias->get_availability () > AVAIL_INTERPOSABLE)
+           add_detected_attribute_1 (alias, attr, &changed);
+       }
+    }
+  return changed;
+}
+
 /* Worker to set noreturng flag.  */
 static void
 set_noreturn_flag_1 (cgraph_node *node, bool noreturn_p, bool *changed)
index cedaaac3a45b774f87ae176e9b961df8c0e61466..cfdd9f693a8892ae2ef39fd3586935407a09b658 100644 (file)
@@ -1190,6 +1190,10 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
 
   bool set_pure_flag (bool pure, bool looping);
 
+  /* Add attribute ATTR to cgraph_node's decl and on aliases of the node
+     if any.  */
+  bool add_detected_attribute (const char *attr);
+
   /* Call callback on function and aliases associated to the function.
      When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
      skipped. */
index d21db5d4a208d06eacef6488af285762cfefadc8..35971c501fc31de01776ff3230fd59093dc47506 100644 (file)
@@ -781,6 +781,10 @@ Wsuggest-attribute=malloc
 Common Var(warn_suggest_attribute_malloc) Warning
 Warn about functions which might be candidates for __attribute__((malloc)).
 
+Wsuggest-attribute=returns_nonnull
+Common Var(warn_suggest_attribute_returns_nonnull) Warning
+Warn about functions which might be candidates for __attribute__((returns_nonnull)).
+
 Wsuggest-final-types
 Common Var(warn_suggest_final_types) Warning
 Warn about C++ polymorphic types where adding final keyword would improve code quality.
index bc9f4f70914383fae110c30d6575c41f8305fac8..086be0f40d235b49e746bff2977ac1f9f0901d99 100644 (file)
@@ -8093,7 +8093,7 @@ if the array is referenced as a flexible array member.
 
 @opindex Wsuggest-attribute=
 @opindex Wno-suggest-attribute=
-@item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
+@item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}returns_nonnull@r{|}
 Warn for cases where adding an attribute may be beneficial. The
 attributes currently supported are listed below.
 
@@ -8113,9 +8113,11 @@ attributes currently supported are listed below.
 @itemx -Wsuggest-attribute=noreturn
 @itemx -Wmissing-noreturn
 @itemx -Wsuggest-attribute=malloc
+@itemx -Wsuggest-attribute=returns_nonnull
+@itemx -Wno-suggest-attribute=returns_nonnull
 
 Warn about functions that might be candidates for attributes
-@code{pure}, @code{const} or @code{noreturn} or @code{malloc}. The compiler
+@code{pure}, @code{const}, @code{noreturn}, @code{malloc} or @code{returns_nonnull}. The compiler
 only warns for functions visible in other compilation units or (in the case of
 @code{pure} and @code{const}) if it cannot prove that the function returns
 normally. A function returns normally if it doesn't contain an infinite loop or
index 6e9530c3d7f07fddf3ddda6bd83fe82cdd815008..998b7608d78906b74a17240c158dca6159c0a5af 100644 (file)
@@ -44,6 +44,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-query.h"
 #include "gimple-range-op.h"
 #include "gimple-range.h"
+#include "cgraph.h"
+#include "alloc-pool.h"
+#include "symbol-summary.h"
+#include "ipa-utils.h"
+#include "ipa-prop.h"
 // Construct a fur_source, and set the m_query field.
 
 fur_source::fur_source (range_query *q)
@@ -1013,6 +1018,25 @@ fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &)
   else
     r.set_varying (type);
 
+  tree callee = gimple_call_fndecl (call);
+  if (callee
+      && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)), type))
+    {
+      Value_Range val;
+      if (ipa_return_value_range (val, callee))
+       {
+         r.intersect (val);
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Using return value range of ");
+             print_generic_expr (dump_file, callee, TDF_SLIM);
+             fprintf (dump_file, ": ");
+             val.dump (dump_file);
+             fprintf (dump_file, "\n");
+           }
+       }
+    }
+
   // If there is an LHS, intersect that with what is known.
   if (lhs)
     {
index 7de2b788185b6720b9cc4e8f994a2107c6f7d8c8..e77bc9c340b70a8db1ffc5a3c344cbe62dcc7be6 100644 (file)
@@ -237,6 +237,35 @@ gt_ggc_mx (ipa_vr *&x)
   return gt_ggc_mx ((ipa_vr *) x);
 }
 
+/* Analysis summery of function call return value.  */
+struct GTY(()) ipa_return_value_summary
+{
+  /* Known value range.
+     This needs to be wrapped in struccture due to specific way
+     we allocate ipa_vr. */
+  ipa_vr *vr;
+};
+
+/* Function summary for return values.  */
+class ipa_return_value_sum_t : public function_summary <ipa_return_value_summary *>
+{
+public:
+  ipa_return_value_sum_t (symbol_table *table, bool ggc):
+    function_summary <ipa_return_value_summary *> (table, ggc) { }
+
+  /* Hook that is called by summary when a node is duplicated.  */
+  void duplicate (cgraph_node *,
+                 cgraph_node *,
+                 ipa_return_value_summary *data,
+                 ipa_return_value_summary *data2) final override
+  {
+    *data2=*data;
+  }
+};
+
+/* Variable hoding the return value summary.  */
+static GTY(()) function_summary <ipa_return_value_summary *> *ipa_return_value_sum;
+
 
 /* Return true if DECL_FUNCTION_SPECIFIC_OPTIMIZATION of the decl associated
    with NODE should prevent us from analyzing it for the purposes of IPA-CP.  */
@@ -5915,5 +5944,49 @@ ipcp_transform_function (struct cgraph_node *node)
   return modified_mem_access ? TODO_update_ssa_only_virtuals : 0;
 }
 
+/* Record that current function return value range is VAL.  */
+
+void
+ipa_record_return_value_range (Value_Range val)
+{
+  cgraph_node *n = cgraph_node::get (current_function_decl);
+  if (!ipa_return_value_sum)
+    {
+      if (!ipa_vr_hash_table)
+       ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37);
+      ipa_return_value_sum = new (ggc_alloc_no_dtor <ipa_return_value_sum_t> ())
+             ipa_return_value_sum_t (symtab, true);
+      ipa_return_value_sum->disable_insertion_hook ();
+    }
+  ipa_return_value_sum->get_create (n)->vr = ipa_get_value_range (val);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Recording return range ");
+      val.dump (dump_file);
+      fprintf (dump_file, "\n");
+    }
+}
+
+/* Return true if value range of DECL is known and if so initialize RANGE.  */
+
+bool
+ipa_return_value_range (Value_Range &range, tree decl)
+{
+  cgraph_node *n = cgraph_node::get (decl);
+  if (!n || !ipa_return_value_sum)
+    return false;
+  enum availability avail;
+  n = n->ultimate_alias_target (&avail);
+  if (avail < AVAIL_AVAILABLE)
+    return false;
+  if (n->decl != decl && !useless_type_conversion_p (TREE_TYPE (decl), TREE_TYPE (n->decl)))
+    return false;
+  ipa_return_value_summary *v = ipa_return_value_sum->get (n);
+  if (!v)
+    return false;
+  v->vr->get_vrange (range);
+  return true;
+}
+
 
 #include "gt-ipa-prop.h"
index fcd0e5c638f54bb6f33ac421c817d43b8ec9bca6..5901c805c4071a3bd04152cfc5779472c9474a38 100644 (file)
@@ -309,7 +309,7 @@ public:
   void get_vrange (Value_Range &) const;
   bool equal_p (const vrange &) const;
   const vrange_storage *storage () const { return m_storage; }
-  void streamer_read (lto_input_block *, data_in *);
+  void streamer_read (lto_input_block *, class data_in *);
   void streamer_write (output_block *) const;
   void dump (FILE *) const;
 
@@ -1274,4 +1274,7 @@ ipa_range_set_and_normalize (vrange &r, tree val)
     r.set (val, val);
 }
 
+bool ipa_return_value_range (Value_Range &range, tree decl);
+void ipa_record_return_value_range (Value_Range val);
+
 #endif /* IPA_PROP_H */
index 058a7dd3019108a840a706fff146bdbc439b21f3..3060ffeefcd97f79509ec0c3963e59c910982af6 100644 (file)
@@ -292,6 +292,15 @@ warn_function_cold (tree decl)
                         true, warned_about, "cold");
 }
 
+void
+warn_function_returns_nonnull (tree decl)
+{
+  static hash_set<tree> *warned_about;
+  warned_about
+    = suggest_attribute (OPT_Wsuggest_attribute_returns_nonnull, decl,
+                        true, warned_about, "returns_nonnull");
+}
+
 /* Check to see if the use (or definition when CHECKING_WRITE is true)
    variable T is legal in a function that is either pure or const.  */
 
index 0eefcf40d4401a18d88325212aa1e1a7f23f376b..84728c589ea1e5a377a0f909dc6b01388f70aff9 100644 (file)
@@ -105,6 +105,7 @@ tree prevailing_odr_type (tree type);
 void enable_odr_based_tbaa (tree type);
 bool odr_based_tbaa_p (const_tree type);
 void set_type_canonical_for_odr_type (tree type, tree canonical);
+void warn_function_returns_nonnull (tree);
 
 void register_odr_enum (tree type);
 
index 3ed6162738245f537f603ea3094d089018553d05..5fd49a2552eb11ef86b9e9f08f42e4c9072c84df 100644 (file)
@@ -71,7 +71,7 @@ public:
        = m_symtab->add_cgraph_insertion_hook (m_symtab_insertion, this);
   }
 
-  /* Enable insertion hook invocation.  */
+  /* Disable insertion hook invocation.  */
   void disable_insertion_hook ()
   {
     if (m_symtab_insertion_hook != NULL)
index 48a94e09828d2319ddd3d527b641775d643257b3..1797db6c81c7e570ef364275319c91e5332666e0 100644 (file)
@@ -43,7 +43,7 @@ int C::foo (int i)
   return i + 3;
 }
 
-int __attribute__ ((noinline,noclone)) get_input(void)
+int __attribute__ ((noinline,noclone,noipa)) get_input(void)
 {
   return 1;
 }
index f27a264fd1e1fd76a810cfe9a484d913e338eb3b..b24b2bca5f91382bccc9b466553f3122e85d3546 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that IPA-CP can do devirtualization even if the virtual call
    comes from a method that has been early-inlined into a descendant.  */
 /* { dg-do run } */
-/* { dg-options "-O3 -fdump-ipa-cp"  } */
+/* { dg-options "-O3 -fdump-ipa-cp -fno-ipa-vrp"  } */
 /* { dg-add-options bind_pic_locally } */
 
 extern "C" void abort (void);
index 7f56189eebbc31df9bcc861b8b27bbcd5b615c71..ae121e8a76264182fc4e8658d4b76a745259c659 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-ipa-icf-optimized"  } */
+/* { dg-options "-O2 -fdump-ipa-icf-optimized -fno-ipa-vrp"  } */
 
 class A
 {
index 5a3cca24fa27ca3505f0ee993ce8465a684f6315..03c10f12db2c628210b91332a1194d8239d90e90 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-ipa-icf-optimized"  } */
+/* { dg-options "-O2 -fdump-ipa-icf-optimized -fno-ipa-vrp"  } */
 
 __attribute__ ((noinline))
 int zero()
index 2d988bc6d55ea374f9f8ee8007eb4be79a073fc8..ccb1870ec69265adafbeca23bfb9295d9e527c3e 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that simple virtual calls are inlined even without early
    inlining.  */
 /* { dg-do run { target { nonpic || pie_enabled } } } */
-/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp -fno-ipa-vrp"  } */
 
 extern "C" void abort (void);
 
index f756a16bae99eb0845f77dba43f096f0a63e904e..02e7e443fa912a0e4a6964071248579c822e071c 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that simple virtual calls on an object refrence are inlined
    even without early inlining.  */
 /* { dg-do run { target { nonpic || pie_enabled } } } */
-/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp -fno-ipa-vrp"  } */
 
 extern "C" void abort (void);
 
index 6c19907686e644c24bedf24018fe775edc34af62..cb889d1e84f0f81c62c17dc77cc0689b8ebf2b5e 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that virtual call inlining does not pick a wrong method when
    there is a user defined ancestor in an object.  */
 /* { dg-do run { target { nonpic || pie_enabled } } } */
-/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp -fno-ipa-vrp"  } */
 
 extern "C" void abort (void);
 
index bc81abfe3474744efe46a1c05f61825e61d7a2f4..f29e818e357f17c85050299736fd14de67be74c6 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that virtual calls are inlined (ithout early inlining) even
    when their caller is itself indirectly inlined.  */
 /* { dg-do run { target { nonpic || pie_enabled } } } */
-/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp -fno-ipa-vrp"  } */
 
 extern "C" void abort (void);
 
index b30b021592431e1584be59b981ac3861eee51626..1f24310961963eefb018aeda4ad7586e27b27b3f 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fnon-call-exceptions -fdump-tree-optimized"  } */
+/* { dg-options "-O2 -fnon-call-exceptions -fdump-tree-optimized -fno-ipa-vrp"  } */
 int *ptr;
 static int barvar;
 
index 61940c670e75b3a37e932ef398ff4f6943f7c7f6..c18278cae116c7b273c97d45849cd74b5193ae1e 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized"  } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-ipa-vrp"  } */
 int *ptr;
 static int barvar;
 
index 6e739de4ade7631b081fe2b623baa805e072ad7b..d5f18bfa9be8a4553e32476c066c6d870b1c859a 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized"  } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-ipa-vrp"  } */
 int *ptr;
 static int barvar;
 /* We can not detect A to be const because it may be interposed by unoptimized
index 0294dcc4bfb7000c6a3338f855f541d0760be27d..c56360ef66e7e61bed27fefcdbfa41a97f64e0ec 100644 (file)
@@ -1,5 +1,5 @@
 // { dg-lto-do link }
-/* { dg-lto-options { "-O2 -fno-early-inlining -fno-implicit-constexpr -flto -fdump-ipa-inline-details" } } */
+/* { dg-lto-options { "-O2 -fno-early-inlining -fno-implicit-constexpr -flto -fdump-ipa-inline-details -fno-ipa-vrp" } } */
 #include "inline-crossmodule-1.h"
 int a::key ()
 {
index b840e5ecd931607a903b802a1f9f6868061ae70c..e02ad5ffe15916cf07c52cb5ad88f42891306de7 100644 (file)
@@ -2,7 +2,7 @@
 
 int m, *p;
 
-__attribute__ ((simd)) int
+__attribute__ ((simd,noipa)) int
 bar (int x)
 {
   if (x)
index 5afa691e4093b8b20144ba121ca4d34b4bc66009..5950581054d2d271a839f6d2e810703afaebd688 100644 (file)
@@ -1,10 +1,10 @@
 /* { dg-require-effective-target return_address } */
 void abort (void);
 
-int check_fa_work (const char *, const char *) __attribute__((noinline));
-int check_fa_mid (const char *) __attribute__((noinline));
-int check_fa (char *) __attribute__((noinline));
-int how_much (void) __attribute__((noinline));
+int check_fa_work (const char *, const char *) __attribute__((noinline,noipa));
+int check_fa_mid (const char *) __attribute__((noinline,noipa));
+int check_fa (char *) __attribute__((noinline,noipa));
+int how_much (void) __attribute__((noinline,noipa));
 
 int check_fa_work (const char *c, const char *f)
 {
index 4032ad13e19669aec6a03d3f41ca36d9956bf191..155a6829b883f412bfadf106dc1cbbdfe070f534 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "-O3 -fopt-info-inline-optimized-missed" } */
+/* { dg-options "-O3 -fopt-info-inline-optimized-missed -fno-ipa-vrp" } */
 
 static int foo (int a)
 {
index fad0891283e5b91c1bad98d9245eeae643e79fda..cbda6858890aac7b05a30e89eb12b4d9f2a0e54f 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-ipa-icf-optimized-all"  } */
+/* { dg-options "-O2 -fdump-ipa-icf-optimized-all -fno-ipa-vrp"  } */
 
 static int zip();
 static int zap();
index 57c5262dd4a831170f34558c9886afa80a812c0b..a8824d040e52a2c6bc15ffbf5509c003b65b3282 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do link } */
 /* { dg-require-alias "" } */
-/* { dg-options "-O2 -fdump-ipa-icf-optimized -flto -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-ipa-icf-optimized -flto -fdump-tree-optimized -fno-ipa-vrp" } */
 /* { dg-require-effective-target lto } */
 /* { dg-additional-sources "ipa-icf-38a.c" }*/
 
index dd58457b6292aa73604e3c231da8bd05ba9a3490..10b572781c7d6d46d1a1637c843358ec497e25a3 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { nonpic || pie_enabled } } } */
-/* { dg-options "-O3 -fdump-tree-local-pure-const1 -fdump-ipa-pure-const -fdump-tree-optimized -fno-early-inlining -fgnu89-inline" } */
+/* { dg-options "-O3 -fno-ipa-vrp -fdump-tree-local-pure-const1 -fdump-ipa-pure-const -fdump-tree-optimized -fno-early-inlining -fgnu89-inline" } */
 void abort (void);
 int error_code;
 static int val;
index 6073c028a98619340e9f3ac24001b5320234d0b8..497136e36078dbbfbf3b2de8b75faa6b75575b43 100644 (file)
@@ -3,7 +3,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fno-ipa-cp -fdump-ipa-inline -fdump-tree-optimized"  } */
 
-extern int __attribute__ ((noinline, noclone, used))
+extern int __attribute__ ((noinline, noclone, used, noipa))
 stuff (int i)
 {
   return 0;
diff --git a/gcc/testsuite/gcc.dg/nonnull-7.c b/gcc/testsuite/gcc.dg/nonnull-7.c
new file mode 100644 (file)
index 0000000..d66a609
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile { target nonpic } }
+   { dg-options "-O2 -Wsuggest-attribute=returns_nonnull" } */
+
+int *q;
+int *test()    /* { dg-warning "candidate for attribute .returns_nonnull." } */
+{
+       if (!q)
+               __builtin_unreachable ();
+       return q;
+}
index 455f923f3f40533fb37b9d11d03b1966f2d50782..3f1d1e0461933de44030bc85724dce5981c5e403 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 -fdump-ipa-profile" } */
+/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */
 
 __attribute__ ((noinline))
 int foo()
index e6eaeb9981016f0a417d317e5a956b7cd6df396c..eed0b1dd08d4dd683fc7c39820dd5cde01c2a2c1 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 -fdump-ipa-profile" } */
+/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */
 
 #include <unistd.h>
 
index c68a6f91604285a9536a57c1011d27ce294b0b21..dd5022f3b0cdb794640c83704a16d12d99e7cf80 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ccp2 -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-tree-ccp2 -fdump-tree-optimized -fno-ipa-vrp" } */
 
 void foo(void);
 static int a = 1, c;
index f05076cafac0cae8ff1237f97531aef80946a83a..3a7c03b27ffe7a73fe84651f25f8d614134404d4 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining -fdelete-null-pointer-checks -fno-thread-jumps" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining -fdelete-null-pointer-checks -fno-thread-jumps -fno-ipa-vrp" } */
 
 typedef struct {
   int code;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c b/gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c
new file mode 100644 (file)
index 0000000..4db5223
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do ling } */
+/* { dg-options "-O1 -dump-tree-evrp-details" } */
+__attribute__ ((__noinline__))
+int a(char c)
+{
+       return c;
+}
+void link_error ();
+
+void
+test(int d)
+{
+       if (a(d) > 200)
+               link_error ();
+}
+int
+main(int argc, char **argv)
+{
+       test(argc);
+       return 0;
+}
+/* { dg-final { scan-tree-dump-times "Recording return range" 2 "evrp"} } */
index 7f38e8d3852ba939829875668d061f0b1fbe195f..f7ba16c20bbc2216076ff70c0022f39b2350d8a5 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining -fno-thread-jumps" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fno-early-inlining -fno-thread-jumps -fno-ipa-vrp" } */
 
 
 inline int ten()
index 902166cb18c964ad9d52e95aa68e2447b3deb668..12aa314f385620c1d10b1c224e4d4766a84cabb8 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-g -O3 -fdump-tree-optimized -fvar-tracking-assignments -fno-selective-scheduling -fno-selective-scheduling2" } */
 
-int __attribute__((noinline))
+int __attribute__((noinline,noipa))
 f1 (int i)
 {
   char a[i + 1];
index 917fa873714f8dfdc9b8e1dbd007875cda7fdb1a..82001eff20e5668f980bc98a342ad2522e9b17fc 100644 (file)
@@ -52,6 +52,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "tree-dfa.h"
 #include "tree-ssa-dce.h"
+#include "alloc-pool.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
+#include "ipa-utils.h"
+#include "ipa-prop.h"
+#include "attribs.h"
 
 // This class is utilized by VRP and ranger to remove __builtin_unreachable
 // calls, and reflect any resulting global ranges.
@@ -1081,6 +1087,51 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p,
       array_checker.check ();
     }
 
+
+  if (Value_Range::supports_type_p (TREE_TYPE
+                                    (TREE_TYPE (current_function_decl)))
+      && flag_ipa_vrp
+      && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
+    {
+      edge e;
+      edge_iterator ei;
+      bool found = false;
+      Value_Range return_range (TREE_TYPE (TREE_TYPE (current_function_decl)));
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+       if (greturn *ret = dyn_cast <greturn *> (*gsi_last_bb (e->src)))
+         {
+           tree retval = gimple_return_retval (ret);
+           if (!retval)
+             {
+               return_range.set_varying (TREE_TYPE (TREE_TYPE (current_function_decl)));
+               found = true;
+               continue;
+             }
+           Value_Range r (TREE_TYPE (retval));
+           if (ranger->range_of_expr (r, retval, ret)
+               && !r.undefined_p ()
+               && !r.varying_p ())
+             {
+               if (!found)
+                 return_range = r;
+               else
+                 return_range.union_ (r);
+             }
+           else
+             return_range.set_varying (TREE_TYPE (retval));
+           found = true;
+         }
+      if (found && !return_range.varying_p ())
+       {
+         ipa_record_return_value_range (return_range);
+         if (POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+             && return_range.nonzero_p ()
+             && cgraph_node::get (current_function_decl)
+                       ->add_detected_attribute ("returns_nonnull"))
+           warn_function_returns_nonnull (current_function_decl);
+       }
+    }
+
   phi_analysis_finalize ();
   disable_ranger (fun);
   scev_finalize ();