Hi! On Sun, 19 Nov 2023 at 16:05, Jan Hubicka <hubi...@ucw.cz> wrote: > > Hi, > this is updated version which also adds testuiste compensation > I lost earlier while maintaining the patch in my testing tree. > There are quite few testcases that use constant return values to hide > something from optimizer. > > Bootstrapped/regtested x86_64-linux. > 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/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. >
After this patch in addition to the problem already reported about vlda1.c and return-value-range-1.c, we have noticed these regressions on aarch64: Running gcc:gcc.target/aarch64/aarch64.exp ... FAIL: gcc.target/aarch64/movk.c scan-assembler movk\tx[0-9]+, 0x4667, lsl 16 FAIL: gcc.target/aarch64/movk.c scan-assembler movk\tx[0-9]+, 0x7a3d, lsl 32 Running gcc:gcc.target/aarch64/simd/simd.exp ... FAIL: gcc.target/aarch64/simd/vmulxd_f64_2.c scan-assembler-times fmul[ \t]+[dD][0-9]+, ?[dD][0-9]+, ?[dD][0-9]+\n 1 FAIL: gcc.target/aarch64/simd/vmulxd_f64_2.c scan-assembler-times fmulx[ \t]+[dD][0-9]+, ?[dD][0-9]+, ?[dD][0-9]+\n 4 FAIL: gcc.target/aarch64/simd/vmulxs_f32_2.c scan-assembler-times fmul[ \t]+[sS][0-9]+, ?[sS][0-9]+, ?[sS][0-9]+\n 1 FAIL: gcc.target/aarch64/simd/vmulxs_f32_2.c scan-assembler-times fmulx[ \t]+[sS][0-9]+, ?[sS][0-9]+, ?[sS][0-9]+\n 4 We have already sent you a notification for the regression on arm, but it includes on vla-1.c and return-value-range-1.c. The notification email contains a pointer to the page where we record all the configurations that regress because of this patch: https://linaro.atlassian.net/browse/GNU-1025 Can you have a look? Thanks, Christophe > diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc > index e41e5ad3ae7..71dacf23ce1 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<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); > +} > + > +/* Set DECL_IS_MALLOC on NODE's decl and on NODE's aliases if any. */ > + > +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) > 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..c6599c7147b 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 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 1f109679c70..3c33104df0a 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 > <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" > 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<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. */ > > 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/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 <unistd.h> > > 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/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 <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 ();