From: Jan Hubicka <hubicka@ucw.cz>
To: gcc-patches@gcc.gnu.org
Subject: Propagate value ranges of return values
Date: Sun, 19 Nov 2023 02:21:21 +0100 [thread overview]
Message-ID: <ZVljEevbGcssSuh8@kam.mff.cuni.cz> (raw)
Hi,
this patch implements very basic propaation 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
Variant of this patch bootstrapped/regtested x86_64-linux, testing with
this version is running. I plan to commit the patch at Monday provided
there are no issues.
gcc/ChangeLog:
* cgraph.cc (add_detected_attribute_1): New function.
(cgraph_node::add_detected_attribute): New member function.
* cgraph.h (struct cgraph_node): Declare it.
* common.opt: Add Wsuggest-attribute=returns_nonnull.
* doc/invoke.texi: Document +Wsuggest-attribute=returns_nonnull.
* gimple-range-fold.cc: Include ipa-prop and dependencies.
(fold_using_range::range_of_call): Look for return value range.
* ipa-prop.cc (struct ipa_return_value_summary): New structure.
(class ipa_return_value_sum_t): 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 function.
* ipa-utils.h (warn_function_returns_nonnull): Declare.
* symbol-summary.h: Fix comment typo.
* tree-vrp.cc (execute_ranger_vrp): Record return values.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/return-value-range-1.c: New test.
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..0be4f02677c 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_malloc) Warning
+Warn about functions which might be candidates for __attribute__((malloc)).
+
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 557d613a1e6..b9e98843613 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8092,7 +8092,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.
@@ -8112,9 +8112,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..0af3fa1b008 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,24 @@ 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)
+ {
+ 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/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/tree-vrp.cc b/gcc/tree-vrp.cc
index 917fa873714..11a382170d8 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -52,6 +52,11 @@ 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"
// This class is utilized by VRP and ranger to remove __builtin_unreachable
// calls, and reflect any resulting global ranges.
@@ -1081,6 +1086,47 @@ 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))))
+ {
+ 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 ();
next reply other threads:[~2023-11-19 1:21 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-19 1:21 Jan Hubicka [this message]
2023-11-19 11:30 ` Sam James
2023-11-19 14:31 ` Jan Hubicka
2023-11-19 15:05 ` Jan Hubicka
2023-11-20 16:28 ` Martin Jambor
2023-11-21 11:09 ` Fix 'gcc.dg/tree-ssa/return-value-range-1.c' (was: Propagate value ranges of return values) Thomas Schwinge
2023-11-21 12:18 ` Jan Hubicka
2023-11-21 13:58 ` Propagate value ranges of return values Christophe Lyon
2023-11-21 14:06 ` Jan Hubicka
2023-11-21 21:35 ` Thomas Schwinge
2023-11-23 7:24 ` Andrew Pinski
2023-11-21 21:24 ` Fix 'gcc.dg/tree-ssa/return-value-range-1.c' for 'char' defaulting to 'unsigned' (was: Propagate value ranges of return values) Thomas Schwinge
2023-11-22 10:51 ` Christophe Lyon
2023-11-22 11:05 ` Thomas Schwinge
2023-11-22 17:16 ` Adjust 'libgomp.c/declare-variant-{3,4}-[...]' for inter-procedural value range propagation " Thomas Schwinge
2023-11-20 14:50 ` Propagate value ranges of return values Andrew MacLeod
2023-11-20 15:34 ` Jan Hubicka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZVljEevbGcssSuh8@kam.mff.cuni.cz \
--to=hubicka@ucw.cz \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).