diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index e41e5ad3ae7..f93259a8c70 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -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 (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 (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) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index cedaaac3a45..cfdd9f693a8 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -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. */ diff --git a/gcc/common.opt b/gcc/common.opt index d21db5d4a20..35971c501fc 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -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. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index bc9f4f70914..086be0f40d2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 6e9530c3d7f..998b7608d78 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -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) { diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index 7de2b788185..e77bc9c340b 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -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 +{ +public: + ipa_return_value_sum_t (symbol_table *table, bool ggc): + function_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_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::create_ggc (37); + ipa_return_value_sum = new (ggc_alloc_no_dtor ()) + 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" diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index fcd0e5c638f..5901c805c40 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -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 */ diff --git a/gcc/ipa-pure-const.cc b/gcc/ipa-pure-const.cc index 058a7dd3019..3060ffeefcd 100644 --- a/gcc/ipa-pure-const.cc +++ b/gcc/ipa-pure-const.cc @@ -292,6 +292,15 @@ warn_function_cold (tree decl) true, warned_about, "cold"); } +void +warn_function_returns_nonnull (tree decl) +{ + static hash_set *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. */ diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 0eefcf40d44..84728c589ea 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -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); diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h index 3ed61627382..5fd49a2552e 100644 --- a/gcc/symbol-summary.h +++ b/gcc/symbol-summary.h @@ -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) diff --git a/gcc/testsuite/g++.dg/ipa/devirt-2.C b/gcc/testsuite/g++.dg/ipa/devirt-2.C index 48a94e09828..1797db6c81c 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-2.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-2.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/ipa/devirt-7.C b/gcc/testsuite/g++.dg/ipa/devirt-7.C index f27a264fd1e..b24b2bca5f9 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-7.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-7.C @@ -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); diff --git a/gcc/testsuite/g++.dg/ipa/ipa-icf-2.C b/gcc/testsuite/g++.dg/ipa/ipa-icf-2.C index 7f56189eebb..ae121e8a762 100644 --- a/gcc/testsuite/g++.dg/ipa/ipa-icf-2.C +++ b/gcc/testsuite/g++.dg/ipa/ipa-icf-2.C @@ -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 { diff --git a/gcc/testsuite/g++.dg/ipa/ipa-icf-3.C b/gcc/testsuite/g++.dg/ipa/ipa-icf-3.C index 5a3cca24fa2..03c10f12db2 100644 --- a/gcc/testsuite/g++.dg/ipa/ipa-icf-3.C +++ b/gcc/testsuite/g++.dg/ipa/ipa-icf-3.C @@ -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() diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-1.C b/gcc/testsuite/g++.dg/ipa/ivinline-1.C index 2d988bc6d55..ccb1870ec69 100644 --- a/gcc/testsuite/g++.dg/ipa/ivinline-1.C +++ b/gcc/testsuite/g++.dg/ipa/ivinline-1.C @@ -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); diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-3.C b/gcc/testsuite/g++.dg/ipa/ivinline-3.C index f756a16bae9..02e7e443fa9 100644 --- a/gcc/testsuite/g++.dg/ipa/ivinline-3.C +++ b/gcc/testsuite/g++.dg/ipa/ivinline-3.C @@ -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); diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-5.C b/gcc/testsuite/g++.dg/ipa/ivinline-5.C index 6c19907686e..cb889d1e84f 100644 --- a/gcc/testsuite/g++.dg/ipa/ivinline-5.C +++ b/gcc/testsuite/g++.dg/ipa/ivinline-5.C @@ -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); diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-8.C b/gcc/testsuite/g++.dg/ipa/ivinline-8.C index bc81abfe347..f29e818e357 100644 --- a/gcc/testsuite/g++.dg/ipa/ivinline-8.C +++ b/gcc/testsuite/g++.dg/ipa/ivinline-8.C @@ -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); diff --git a/gcc/testsuite/g++.dg/ipa/nothrow-1.C b/gcc/testsuite/g++.dg/ipa/nothrow-1.C index b30b0215924..1f243109619 100644 --- a/gcc/testsuite/g++.dg/ipa/nothrow-1.C +++ b/gcc/testsuite/g++.dg/ipa/nothrow-1.C @@ -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; diff --git a/gcc/testsuite/g++.dg/ipa/pure-const-1.C b/gcc/testsuite/g++.dg/ipa/pure-const-1.C index 61940c670e7..c18278cae11 100644 --- a/gcc/testsuite/g++.dg/ipa/pure-const-1.C +++ b/gcc/testsuite/g++.dg/ipa/pure-const-1.C @@ -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; diff --git a/gcc/testsuite/g++.dg/ipa/pure-const-2.C b/gcc/testsuite/g++.dg/ipa/pure-const-2.C index 6e739de4ade..d5f18bfa9be 100644 --- a/gcc/testsuite/g++.dg/ipa/pure-const-2.C +++ b/gcc/testsuite/g++.dg/ipa/pure-const-2.C @@ -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 diff --git a/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C b/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C index 0294dcc4bfb..c56360ef66e 100644 --- a/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C +++ b/gcc/testsuite/g++.dg/lto/inline-crossmodule-1_0.C @@ -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 () { diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106433.c b/gcc/testsuite/gcc.c-torture/compile/pr106433.c index b840e5ecd93..e02ad5ffe15 100644 --- a/gcc/testsuite/gcc.c-torture/compile/pr106433.c +++ b/gcc/testsuite/gcc.c-torture/compile/pr106433.c @@ -2,7 +2,7 @@ int m, *p; -__attribute__ ((simd)) int +__attribute__ ((simd,noipa)) int bar (int x) { if (x) diff --git a/gcc/testsuite/gcc.c-torture/execute/frame-address.c b/gcc/testsuite/gcc.c-torture/execute/frame-address.c index 5afa691e409..5950581054d 100644 --- a/gcc/testsuite/gcc.c-torture/execute/frame-address.c +++ b/gcc/testsuite/gcc.c-torture/execute/frame-address.c @@ -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) { diff --git a/gcc/testsuite/gcc.dg/ipa/fopt-info-inline-1.c b/gcc/testsuite/gcc.dg/ipa/fopt-info-inline-1.c index 4032ad13e19..155a6829b88 100644 --- a/gcc/testsuite/gcc.dg/ipa/fopt-info-inline-1.c +++ b/gcc/testsuite/gcc.dg/ipa/fopt-info-inline-1.c @@ -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) { diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-25.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-25.c index fad0891283e..cbda6858890 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-icf-25.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-25.c @@ -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(); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c index 57c5262dd4a..a8824d040e5 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-38.c @@ -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" }*/ diff --git a/gcc/testsuite/gcc.dg/ipa/pure-const-1.c b/gcc/testsuite/gcc.dg/ipa/pure-const-1.c index dd58457b629..10b572781c7 100644 --- a/gcc/testsuite/gcc.dg/ipa/pure-const-1.c +++ b/gcc/testsuite/gcc.dg/ipa/pure-const-1.c @@ -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; diff --git a/gcc/testsuite/gcc.dg/ipa/remref-0.c b/gcc/testsuite/gcc.dg/ipa/remref-0.c index 6073c028a98..497136e3607 100644 --- a/gcc/testsuite/gcc.dg/ipa/remref-0.c +++ b/gcc/testsuite/gcc.dg/ipa/remref-0.c @@ -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 index 00000000000..d66a60985b0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/nonnull-7.c @@ -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; +} diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c index 455f923f3f4..3f1d1e04619 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-1.c @@ -1,4 +1,4 @@ -/* { dg-options "-O2 -fdump-ipa-profile" } */ +/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */ __attribute__ ((noinline)) int foo() diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c index e6eaeb99810..eed0b1dd08d 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c +++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-2.c @@ -1,4 +1,4 @@ -/* { dg-options "-O2 -fdump-ipa-profile" } */ +/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */ #include diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110269.c b/gcc/testsuite/gcc.dg/tree-ssa/pr110269.c index c68a6f91604..dd5022f3b0c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr110269.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110269.c @@ -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; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20701.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20701.c index f05076cafac..3a7c03b27ff 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr20701.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20701.c @@ -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 index 00000000000..4db52233c5d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c @@ -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"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp05.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp05.c index 7f38e8d3852..f7ba16c20bb 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp05.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp05.c @@ -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() diff --git a/gcc/testsuite/gcc.dg/vla-1.c b/gcc/testsuite/gcc.dg/vla-1.c index 902166cb18c..12aa314f385 100644 --- a/gcc/testsuite/gcc.dg/vla-1.c +++ b/gcc/testsuite/gcc.dg/vla-1.c @@ -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]; diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 917fa873714..82001eff20e 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -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 (*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 ();