mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 19:03:59 +08:00
inter-procedural value range propagation
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.
This commit is contained in:
parent
57c028acbe
commit
53ba8d6695
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ()
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
int m, *p;
|
||||
|
||||
__attribute__ ((simd)) int
|
||||
__attribute__ ((simd,noipa)) int
|
||||
bar (int x)
|
||||
{
|
||||
if (x)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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" }*/
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
10
gcc/testsuite/gcc.dg/nonnull-7.c
Normal file
10
gcc/testsuite/gcc.dg/nonnull-7.c
Normal file
@ -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;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* { dg-options "-O2 -fdump-ipa-profile" } */
|
||||
/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */
|
||||
|
||||
__attribute__ ((noinline))
|
||||
int foo()
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* { dg-options "-O2 -fdump-ipa-profile" } */
|
||||
/* { dg-options "-O2 -fdump-ipa-profile -fno-ipa-vrp" } */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
22
gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c
Normal file
22
gcc/testsuite/gcc.dg/tree-ssa/return-value-range-1.c
Normal file
@ -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"} } */
|
@ -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()
|
||||
|
@ -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];
|
||||
|
@ -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 ();
|
||||
|
Loading…
Reference in New Issue
Block a user