aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-08-18 21:21:45 +0200
committerMartin Liska <mliska@suse.cz>2022-08-18 21:21:45 +0200
commit9dfe1f671aee1e41ded1563ffd974f510800572b (patch)
tree5e692541dd0a8059c19e76a4d543b32701d33789 /gcc
parentc4cf402822be5b52516a727e6b2abc923d1a9d52 (diff)
parent7f5ec900e53f6c7f7c06c641b4fb303ebdc83785 (diff)
downloadgcc-9dfe1f671aee1e41ded1563ffd974f510800572b.zip
gcc-9dfe1f671aee1e41ded1563ffd974f510800572b.tar.gz
gcc-9dfe1f671aee1e41ded1563ffd974f510800572b.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
-rw-r--r--gcc/analyzer/analyzer.opt4
-rw-r--r--gcc/analyzer/region-model.cc179
-rw-r--r--gcc/analyzer/region-model.h2
-rw-r--r--gcc/config/riscv/riscv.md4
-rw-r--r--gcc/doc/invoke.texi14
-rw-r--r--gcc/gimple-range-path.cc114
-rw-r--r--gcc/gimple-range-path.h22
-rw-r--r--gcc/match.pd4
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c10
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c74
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/pr106181.c11
-rw-r--r--gcc/testsuite/gcc.dg/pr106617.c36
-rw-r--r--gcc/tree-ssa-dom.cc2
-rw-r--r--gcc/tree-ssa-loop-ch.cc12
-rw-r--r--gcc/tree-ssa-threadbackward.cc20
-rw-r--r--gcc/tree-ssa-threadedge.cc30
-rw-r--r--gcc/tree-ssa-threadedge.h5
17 files changed, 418 insertions, 125 deletions
diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt
index 61b58c5..437ea92 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -98,6 +98,10 @@ Wanalyzer-free-of-non-heap
Common Var(warn_analyzer_free_of_non_heap) Init(1) Warning
Warn about code paths in which a non-heap pointer is freed.
+Wanalyzer-imprecise-fp-arithmetic
+Common Var(warn_analyzer_imprecise_fp_arithmetic) Init(1) Warning
+Warn about code paths in which floating-point arithmetic is used in locations where precise computation is needed.
+
Wanalyzer-jump-through-null
Common Var(warn_analyzer_jump_through_null) Init(1) Warning
Warn about code paths in which a NULL function pointer is called.
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index b5bc3efd..ec29be2 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -3301,7 +3301,8 @@ public:
m.add_cwe (131);
return warning_meta (rich_loc, m, get_controlling_option (),
- "allocated buffer size is not a multiple of the pointee's size");
+ "allocated buffer size is not a multiple"
+ " of the pointee's size");
}
label_text
@@ -3396,21 +3397,20 @@ capacity_compatible_with_type (tree cst, tree pointee_size_tree)
class size_visitor : public visitor
{
public:
- size_visitor (tree size_cst, const svalue *sval, constraint_manager *cm)
- : m_size_cst (size_cst), m_sval (sval), m_cm (cm)
+ size_visitor (tree size_cst, const svalue *root_sval, constraint_manager *cm)
+ : m_size_cst (size_cst), m_root_sval (root_sval), m_cm (cm)
{
- sval->accept (this);
+ m_root_sval->accept (this);
}
bool get_result ()
{
- return result_set.contains (m_sval);
+ return result_set.contains (m_root_sval);
}
void visit_constant_svalue (const constant_svalue *sval) final override
{
- if (capacity_compatible_with_type (sval->get_constant (), m_size_cst))
- result_set.add (sval);
+ check_constant (sval->get_constant (), sval);
}
void visit_unknown_svalue (const unknown_svalue *sval ATTRIBUTE_UNUSED)
@@ -3478,15 +3478,10 @@ public:
equiv_class_id id (-1);
if (m_cm->get_equiv_class_by_svalue (sval, &id))
{
- if (tree cst_val = id.get_obj (*m_cm).get_any_constant ())
- {
- if (capacity_compatible_with_type (cst_val, m_size_cst))
- result_set.add (sval);
- }
+ if (tree cst = id.get_obj (*m_cm).get_any_constant ())
+ check_constant (cst, sval);
else
- {
- result_set.add (sval);
- }
+ result_set.add (sval);
}
}
@@ -3503,8 +3498,23 @@ public:
}
private:
+ void check_constant (tree cst, const svalue *sval)
+ {
+ switch (TREE_CODE (cst))
+ {
+ default:
+ /* Assume all unhandled operands are compatible. */
+ result_set.add (sval);
+ break;
+ case INTEGER_CST:
+ if (capacity_compatible_with_type (cst, m_size_cst))
+ result_set.add (sval);
+ break;
+ }
+ }
+
tree m_size_cst;
- const svalue *m_sval;
+ const svalue *m_root_sval;
constraint_manager *m_cm;
svalue_set result_set; /* Used as a mapping of svalue*->bool. */
};
@@ -3541,12 +3551,12 @@ struct_or_union_with_inheritance_p (tree struc)
static bool
is_any_cast_p (const gimple *stmt)
{
- if (const gassign *assign = dyn_cast<const gassign *>(stmt))
+ if (const gassign *assign = dyn_cast <const gassign *> (stmt))
return gimple_assign_cast_p (assign)
|| !pending_diagnostic::same_tree_p (
TREE_TYPE (gimple_assign_lhs (assign)),
TREE_TYPE (gimple_assign_rhs1 (assign)));
- else if (const gcall *call = dyn_cast<const gcall *>(stmt))
+ else if (const gcall *call = dyn_cast <const gcall *> (stmt))
{
tree lhs = gimple_call_lhs (call);
return lhs != NULL_TREE && !pending_diagnostic::same_tree_p (
@@ -3606,10 +3616,11 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
case svalue_kind::SK_CONSTANT:
{
const constant_svalue *cst_cap_sval
- = as_a <const constant_svalue *> (capacity);
+ = as_a <const constant_svalue *> (capacity);
tree cst_cap = cst_cap_sval->get_constant ();
- if (!capacity_compatible_with_type (cst_cap, pointee_size_tree,
- is_struct))
+ if (TREE_CODE (cst_cap) == INTEGER_CST
+ && !capacity_compatible_with_type (cst_cap, pointee_size_tree,
+ is_struct))
ctxt->warn (new dubious_allocation_size (lhs_reg, rhs_reg,
cst_cap));
}
@@ -5055,6 +5066,125 @@ region_model::append_regions_cb (const region *base_reg,
cb_data->out->safe_push (decl_reg);
}
+
+/* Abstract class for diagnostics related to the use of
+ floating-point arithmetic where precision is needed. */
+
+class imprecise_floating_point_arithmetic : public pending_diagnostic
+{
+public:
+ int get_controlling_option () const final override
+ {
+ return OPT_Wanalyzer_imprecise_fp_arithmetic;
+ }
+};
+
+/* Concrete diagnostic to complain about uses of floating-point arithmetic
+ in the size argument of malloc etc. */
+
+class float_as_size_arg : public imprecise_floating_point_arithmetic
+{
+public:
+ float_as_size_arg (tree arg) : m_arg (arg)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "float_as_size_arg_diagnostic";
+ }
+
+ bool subclass_equal_p (const pending_diagnostic &other) const
+ {
+ return same_tree_p (m_arg, ((const float_as_size_arg &) other).m_arg);
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ bool warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "use of floating-point arithmetic here might"
+ " yield unexpected results");
+ if (warned)
+ inform (rich_loc->get_loc (), "only use operands of an integer type"
+ " inside the size argument");
+ return warned;
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev) final
+ override
+ {
+ if (m_arg)
+ return ev.formatted_print ("operand %qE is of type %qT",
+ m_arg, TREE_TYPE (m_arg));
+ return ev.formatted_print ("at least one operand of the size argument is"
+ " of a floating-point type");
+ }
+
+private:
+ tree m_arg;
+};
+
+/* Visitor to find uses of floating-point variables/constants in an svalue. */
+
+class contains_floating_point_visitor : public visitor
+{
+public:
+ contains_floating_point_visitor (const svalue *root_sval) : m_result (NULL)
+ {
+ root_sval->accept (this);
+ }
+
+ const svalue *get_svalue_to_report ()
+ {
+ return m_result;
+ }
+
+ void visit_constant_svalue (const constant_svalue *sval) final override
+ {
+ /* At the point the analyzer runs, constant integer operands in a floating
+ point expression are already implictly converted to floating-points.
+ Thus, we do prefer to report non-constants such that the diagnostic
+ always reports a floating-point operand. */
+ tree type = sval->get_type ();
+ if (type && FLOAT_TYPE_P (type) && !m_result)
+ m_result = sval;
+ }
+
+ void visit_conjured_svalue (const conjured_svalue *sval) final override
+ {
+ tree type = sval->get_type ();
+ if (type && FLOAT_TYPE_P (type))
+ m_result = sval;
+ }
+
+ void visit_initial_svalue (const initial_svalue *sval) final override
+ {
+ tree type = sval->get_type ();
+ if (type && FLOAT_TYPE_P (type))
+ m_result = sval;
+ }
+
+private:
+ /* Non-null if at least one floating-point operand was found. */
+ const svalue *m_result;
+};
+
+/* May complain about uses of floating-point operands in SIZE_IN_BYTES. */
+
+void
+region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes,
+ region_model_context *ctxt) const
+{
+ gcc_assert (ctxt);
+
+ contains_floating_point_visitor v (size_in_bytes);
+ if (const svalue *float_sval = v.get_svalue_to_report ())
+ {
+ tree diag_arg = get_representative_tree (float_sval);
+ ctxt->warn (new float_as_size_arg (diag_arg));
+ }
+}
+
/* Return a new region describing a heap-allocated block of memory.
Use CTXT to complain about tainted sizes. */
@@ -5092,8 +5222,11 @@ region_model::set_dynamic_extents (const region *reg,
{
assert_compat_types (size_in_bytes->get_type (), size_type_node);
if (ctxt)
- check_dynamic_size_for_taint (reg->get_memory_space (), size_in_bytes,
- ctxt);
+ {
+ check_dynamic_size_for_taint (reg->get_memory_space (), size_in_bytes,
+ ctxt);
+ check_dynamic_size_for_floats (size_in_bytes, ctxt);
+ }
m_dynamic_extents.put (reg, size_in_bytes);
}
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index cdf1087..7ce832f 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -853,6 +853,8 @@ class region_model
void check_dynamic_size_for_taint (enum memory_space mem_space,
const svalue *size_in_bytes,
region_model_context *ctxt) const;
+ void check_dynamic_size_for_floats (const svalue *size_in_bytes,
+ region_model_context *ctxt) const;
void check_region_for_taint (const region *reg,
enum access_direction dir,
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index c517ae0..f4a5ff0 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2254,8 +2254,8 @@
(match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
"TARGET_SFB_ALU"
"@
- b%C5 %1,%z2,1f; mv %0,%z4; 1: # movcc
- b%C5 %1,%z2,1f; li %0,%4; 1: # movcc"
+ b%C5\t%1,%z2,1f\t# movcc\;mv\t%0,%z4\n1:
+ b%C5\t%1,%z2,1f\t# movcc\;li\t%0,%4\n1:"
[(set_attr "length" "8")
(set_attr "type" "sfb_alu")
(set_attr "mode" "<GPR:MODE>")])
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 685d74c..375ccbc 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -416,6 +416,7 @@ Objective-C and Objective-C++ Dialects}.
-Wno-analyzer-fd-use-without-check @gol
-Wno-analyzer-file-leak @gol
-Wno-analyzer-free-of-non-heap @gol
+-Wno-analyzer-imprecise-fp-arithmetic @gol
-Wno-analyzer-jump-through-null @gol
-Wno-analyzer-malloc-leak @gol
-Wno-analyzer-mismatching-deallocation @gol
@@ -9721,6 +9722,7 @@ Enabling this option effectively enables the following warnings:
-Wanalyzer-fd-use-without-check @gol
-Wanalyzer-file-leak @gol
-Wanalyzer-free-of-non-heap @gol
+-Wanalyzer-imprecise-fp-arithmetic @gol
-Wanalyzer-jump-through-null @gol
-Wanalyzer-malloc-leak @gol
-Wanalyzer-mismatching-deallocation @gol
@@ -9909,6 +9911,18 @@ is called on a non-heap pointer (e.g. an on-stack buffer, or a global).
See @uref{https://cwe.mitre.org/data/definitions/590.html, CWE-590: Free of Memory not on the Heap}.
+@item -Wno-analyzer-imprecise-fp-arithmetic
+@opindex Wanalyzer-imprecise-fp-arithmetic
+@opindex Wno-analyzer-imprecise-fp-arithmetic
+This warning requires @option{-fanalyzer}, which enables it; use
+@option{-Wno-analyzer-imprecise-fp-arithmetic}
+to disable it.
+
+This diagnostic warns for paths through the code in which floating-point
+arithmetic is used in locations where precise computation is needed. This
+diagnostic only warns on use of floating-point operands inside the
+calculation of an allocation size at the moment.
+
@item -Wno-analyzer-jump-through-null
@opindex Wanalyzer-jump-through-null
@opindex Wno-analyzer-jump-through-null
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index ff991b7..ba7c2ed 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -36,33 +36,52 @@ along with GCC; see the file COPYING3. If not see
// Internal construct to help facilitate debugging of solver.
#define DEBUG_SOLVER (dump_file && (param_threader_debug == THREADER_DEBUG_ALL))
-path_range_query::path_range_query (bool resolve, gimple_ranger *ranger)
+path_range_query::path_range_query (gimple_ranger &ranger,
+ const vec<basic_block> &path,
+ const bitmap_head *dependencies,
+ bool resolve)
: m_cache (new ssa_global_cache),
m_has_cache_entry (BITMAP_ALLOC (NULL)),
- m_resolve (resolve),
- m_alloced_ranger (!ranger)
+ m_ranger (ranger),
+ m_resolve (resolve)
{
- if (m_alloced_ranger)
- m_ranger = new gimple_ranger;
- else
- m_ranger = ranger;
+ m_oracle = new path_oracle (m_ranger.oracle ());
+
+ reset_path (path, dependencies);
+}
- m_oracle = new path_oracle (m_ranger->oracle ());
+path_range_query::path_range_query (gimple_ranger &ranger, bool resolve)
+ : m_cache (new ssa_global_cache),
+ m_has_cache_entry (BITMAP_ALLOC (NULL)),
+ m_ranger (ranger),
+ m_resolve (resolve)
+{
+ m_oracle = new path_oracle (m_ranger.oracle ());
+}
- if (m_resolve && flag_checking)
- verify_marked_backedges (cfun);
+path_range_query::path_range_query (gimple_ranger &ranger,
+ edge e,
+ bool resolve)
+ : m_cache (new ssa_global_cache),
+ m_has_cache_entry (BITMAP_ALLOC (NULL)),
+ m_ranger (ranger),
+ m_resolve (resolve)
+{
+ m_oracle = new path_oracle (m_ranger.oracle ());
+ auto_vec<basic_block> bbs (2);
+ bbs.quick_push (e->dest);
+ bbs.quick_push (e->src);
+ reset_path (bbs, NULL);
}
path_range_query::~path_range_query ()
{
delete m_oracle;
- if (m_alloced_ranger)
- delete m_ranger;
BITMAP_FREE (m_has_cache_entry);
delete m_cache;
}
-// Return TRUE if NAME is an exit depenency for the path.
+// Return TRUE if NAME is an exit dependency for the path.
bool
path_range_query::exit_dependency_p (tree name)
@@ -153,7 +172,7 @@ path_range_query::range_on_path_entry (vrange &r, tree name)
{
gcc_checking_assert (defined_outside_path (name));
basic_block entry = entry_bb ();
- m_ranger->range_on_entry (r, entry, name);
+ m_ranger.range_on_entry (r, entry, name);
}
// Return the range of NAME at the end of the path being analyzed.
@@ -211,19 +230,19 @@ path_range_query::unreachable_path_p ()
return m_undefined_path;
}
-// Initialize the current path to PATH. The current block is set to
-// the entry block to the path.
-//
-// Note that the blocks are in reverse order, so the exit block is
-// path[0].
+// Reset the current path to PATH.
void
-path_range_query::set_path (const vec<basic_block> &path)
+path_range_query::reset_path (const vec<basic_block> &path,
+ const bitmap_head *dependencies)
{
gcc_checking_assert (path.length () > 1);
m_path = path.copy ();
m_pos = m_path.length () - 1;
+ m_undefined_path = false;
bitmap_clear (m_has_cache_entry);
+
+ compute_ranges (dependencies);
}
bool
@@ -248,7 +267,7 @@ path_range_query::ssa_range_in_phi (vrange &r, gphi *phi)
if (at_entry ())
{
- if (m_resolve && m_ranger->range_of_expr (r, name, phi))
+ if (m_resolve && m_ranger.range_of_expr (r, name, phi))
return;
// Try to fold the phi exclusively with global or cached values.
@@ -290,7 +309,7 @@ path_range_query::ssa_range_in_phi (vrange &r, gphi *phi)
range_on_path_entry (r, arg);
else
r.set_varying (TREE_TYPE (name));
- m_ranger->range_on_edge (tmp, e_in, arg);
+ m_ranger.range_on_edge (tmp, e_in, arg);
r.intersect (tmp);
return;
}
@@ -325,7 +344,7 @@ path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb)
}
if (bb && POINTER_TYPE_P (TREE_TYPE (name)))
- m_ranger->m_cache.m_exit.maybe_adjust_range (r, name, bb);
+ m_ranger.m_cache.m_exit.maybe_adjust_range (r, name, bb);
if (DEBUG_SOLVER && (bb || !r.varying_p ()))
{
@@ -441,7 +460,7 @@ path_range_query::compute_ranges_in_block (basic_block bb)
p->reset_path ();
}
- gori_compute &g = m_ranger->gori ();
+ gori_compute &g = m_ranger.gori ();
bitmap exports = g.exports (bb);
EXECUTE_IF_AND_IN_BITMAP (m_exit_dependencies, exports, 0, i, bi)
{
@@ -495,7 +514,7 @@ path_range_query::adjust_for_non_null_uses (basic_block bb)
else
r.set_varying (TREE_TYPE (name));
- if (m_ranger->m_cache.m_exit.maybe_adjust_range (r, name, bb))
+ if (m_ranger.m_cache.m_exit.maybe_adjust_range (r, name, bb))
set_cache (r, name);
}
}
@@ -515,12 +534,11 @@ path_range_query::add_to_exit_dependencies (tree name, bitmap dependencies)
// SSA names used to calculate the final conditional along the path.
void
-path_range_query::compute_exit_dependencies (bitmap dependencies,
- const vec<basic_block> &path)
+path_range_query::compute_exit_dependencies (bitmap dependencies)
{
// Start with the imports from the exit block...
- basic_block exit = path[0];
- gori_compute &gori = m_ranger->gori ();
+ basic_block exit = m_path[0];
+ gori_compute &gori = m_ranger.gori ();
bitmap_copy (dependencies, gori.imports (exit));
auto_vec<tree> worklist (bitmap_count_bits (dependencies));
@@ -538,7 +556,7 @@ path_range_query::compute_exit_dependencies (bitmap dependencies,
tree name = worklist.pop ();
gimple *def_stmt = SSA_NAME_DEF_STMT (name);
if (SSA_NAME_IS_DEFAULT_DEF (name)
- || !path.contains (gimple_bb (def_stmt)))
+ || !m_path.contains (gimple_bb (def_stmt)))
continue;
if (gphi *phi = dyn_cast <gphi *> (def_stmt))
@@ -549,7 +567,7 @@ path_range_query::compute_exit_dependencies (bitmap dependencies,
tree arg = gimple_phi_arg (phi, i)->def;
if (TREE_CODE (arg) == SSA_NAME
- && path.contains (e->src)
+ && m_path.contains (e->src)
&& bitmap_set_bit (dependencies, SSA_NAME_VERSION (arg)))
worklist.safe_push (arg);
}
@@ -565,9 +583,9 @@ path_range_query::compute_exit_dependencies (bitmap dependencies,
}
// Exported booleans along the path, may help conditionals.
if (m_resolve)
- for (i = 0; i < path.length (); ++i)
+ for (i = 0; i < m_path.length (); ++i)
{
- basic_block bb = path[i];
+ basic_block bb = m_path[i];
tree name;
FOR_EACH_GORI_EXPORT_NAME (gori, bb, name)
if (TREE_CODE (TREE_TYPE (name)) == BOOLEAN_TYPE)
@@ -583,32 +601,28 @@ path_range_query::compute_exit_dependencies (bitmap dependencies,
// calculated from the final conditional in the path.
void
-path_range_query::compute_ranges (const vec<basic_block> &path,
- const bitmap_head *dependencies)
+path_range_query::compute_ranges (const bitmap_head *dependencies)
{
if (DEBUG_SOLVER)
fprintf (dump_file, "\n==============================================\n");
- set_path (path);
- m_undefined_path = false;
-
if (dependencies)
bitmap_copy (m_exit_dependencies, dependencies);
else
- compute_exit_dependencies (m_exit_dependencies, m_path);
+ compute_exit_dependencies (m_exit_dependencies);
if (m_resolve)
{
path_oracle *p = get_path_oracle ();
- p->reset_path (m_ranger->oracle ());
+ p->reset_path (m_ranger.oracle ());
}
if (DEBUG_SOLVER)
{
fprintf (dump_file, "path_range_query: compute_ranges for path: ");
- for (unsigned i = path.length (); i > 0; --i)
+ for (unsigned i = m_path.length (); i > 0; --i)
{
- basic_block bb = path[i - 1];
+ basic_block bb = m_path[i - 1];
fprintf (dump_file, "%d", bb->index);
if (i > 1)
fprintf (dump_file, "->");
@@ -636,18 +650,6 @@ path_range_query::compute_ranges (const vec<basic_block> &path,
}
}
-// Convenience function to compute ranges along a path consisting of
-// E->SRC and E->DEST.
-
-void
-path_range_query::compute_ranges (edge e)
-{
- auto_vec<basic_block> bbs (2);
- bbs.quick_push (e->dest);
- bbs.quick_push (e->src);
- compute_ranges (bbs);
-}
-
// A folding aid used to register and query relations along a path.
// When queried, it returns relations as they would appear on exit to
// the path.
@@ -730,7 +732,7 @@ path_range_query::range_of_stmt (vrange &r, gimple *stmt, tree)
if (m_resolve)
{
fold_using_range f;
- jt_fur_source src (stmt, this, &m_ranger->gori (), m_path);
+ jt_fur_source src (stmt, this, &m_ranger.gori (), m_path);
if (!f.fold_stmt (r, stmt, src))
r.set_varying (type);
}
@@ -820,7 +822,7 @@ path_range_query::compute_outgoing_relations (basic_block bb, basic_block next)
else
gcc_unreachable ();
- jt_fur_source src (NULL, this, &m_ranger->gori (), m_path);
+ jt_fur_source src (NULL, this, &m_ranger.gori (), m_path);
src.register_outgoing_edges (cond, r, e0, e1);
}
}
diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h
index 3cb794e..483fde0 100644
--- a/gcc/gimple-range-path.h
+++ b/gcc/gimple-range-path.h
@@ -32,13 +32,14 @@ along with GCC; see the file COPYING3. If not see
class path_range_query : public range_query
{
public:
- path_range_query (bool resolve = true, class gimple_ranger *ranger = NULL);
+ path_range_query (class gimple_ranger &ranger,
+ const vec<basic_block> &path,
+ const bitmap_head *dependencies = NULL,
+ bool resolve = true);
+ path_range_query (gimple_ranger &ranger, bool resolve = true);
+ path_range_query (gimple_ranger &ranger, edge e, bool resolve = true);
virtual ~path_range_query ();
- void compute_ranges (const vec<basic_block> &,
- const bitmap_head *dependencies = NULL);
- void compute_ranges (edge e);
- void compute_exit_dependencies (bitmap dependencies,
- const vec<basic_block> &);
+ void reset_path (const vec<basic_block> &, const bitmap_head *dependencies);
bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
bool unreachable_path_p ();
@@ -47,6 +48,8 @@ public:
private:
bool internal_range_of_expr (vrange &r, tree name, gimple *);
+ void compute_ranges (const bitmap_head *dependencies);
+ void compute_exit_dependencies (bitmap_head *dependencies);
bool defined_outside_path (tree name);
void range_on_path_entry (vrange &r, tree name);
path_oracle *get_path_oracle () { return (path_oracle *)m_oracle; }
@@ -71,7 +74,6 @@ private:
bool relations_may_be_invalidated (edge);
// Path navigation.
- void set_path (const vec<basic_block> &);
basic_block entry_bb () { return m_path[m_path.length () - 1]; }
basic_block exit_bb () { return m_path[0]; }
basic_block curr_bb () { return m_path[m_pos]; }
@@ -99,7 +101,7 @@ private:
// A ranger used to resolve ranges for SSA names whose values come
// from outside the path.
- gimple_ranger *m_ranger;
+ gimple_ranger &m_ranger;
// Current path position.
unsigned m_pos;
@@ -109,10 +111,6 @@ private:
// Set if there were any undefined expressions while pre-calculating path.
bool m_undefined_path;
-
- // True if m_ranger was allocated in this class and must be freed at
- // destruction.
- bool m_alloced_ranger;
};
#endif // GCC_TREE_SSA_THREADSOLVER_H
diff --git a/gcc/match.pd b/gcc/match.pd
index 07d0a61..1bb936f 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -5796,6 +5796,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp (bit_and@2 @0 integer_pow2p@1) @1)
(icmp @2 { build_zero_cst (TREE_TYPE (@0)); })))
+#if GIMPLE
/* From fold_binary_op_with_conditional_arg handle the case of
rewriting (a ? b : c) > d to a ? (b > d) : (c > d) when the
compares simplify. */
@@ -5805,8 +5806,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Do not move possibly trapping operations into the conditional as this
pessimizes code and causes gimplification issues when applied late. */
(if (!FLOAT_TYPE_P (TREE_TYPE (@3))
- || operation_could_trap_p (cmp, true, false, @3))
+ || !operation_could_trap_p (cmp, true, false, @3))
(cond @0 (cmp! @1 @3) (cmp! @2 @3)))))
+#endif
(for cmp (ge lt)
/* x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
index b5bed53..003914e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
@@ -115,3 +115,13 @@ void test_10 (int32_t n)
char *ptr = malloc (7 * n);
free (ptr);
}
+
+void test_11 ()
+{
+ /* 3.0 is folded to an int before the analyzer runs. */
+ int32_t *ptr = malloc (3.0); /* { dg-line malloc11 } */
+ free (ptr);
+
+ /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc11 } */
+ /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc11 } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c b/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c
new file mode 100644
index 0000000..d8a3f48
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/imprecise-floating-point-1.c
@@ -0,0 +1,74 @@
+#include <stdlib.h>
+
+/* Tests warn on use of floating-point operands inside the calculation
+ of an allocation size.
+
+ The test cases here only test for warnings. The test cases inside
+ allocation-size-X.c should be plently enough to test for false positives. */
+
+void test_1 (float f)
+{
+ int *ptr = malloc (sizeof (int) * f); /* { dg-line test_1 } */
+ free (ptr);
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_1 } */
+ /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_1 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_1 } */
+}
+
+void test_2 (int n)
+{
+ int *ptr = malloc (n * 3.1); /* { dg-line test_2 } */
+ free (ptr);
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_2 } */
+ /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } test_2 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_2 } */
+}
+
+void *alloc_me (size_t size)
+{
+ return malloc (size); /* { dg-line test_3 } */
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_3 } */
+ /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_3 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_3 } */
+}
+
+void test_3 (float f)
+{
+ void *ptr = alloc_me (f); /* { dg-message "calling 'alloc_me' from 'test_3'" } */
+ free (ptr);
+}
+
+void test_4 (int n)
+{
+ int *ptr = calloc(1.7 * n, sizeof (int)); /* { dg-line test_4 } */
+ free (ptr);
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_4 } */
+ /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } test_4 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_4 } */
+}
+
+int test_5 (float f)
+{
+ int *ptr = __builtin_alloca (sizeof (int) * f); /* { dg-line test_5 } */
+ *ptr = 4;
+ return *ptr;
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_5 } */
+ /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_5 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_5 } */
+}
+
+int test_6 (float f)
+{
+ int *ptr = __builtin_alloca (1.7f * f * 2.3f); /* { dg-line test_6 } */
+ *ptr = 4;
+ return *ptr;
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } test_6 } */
+ /* { dg-message "operand 'f' is of type 'float'" "note" { target *-*-* } test_6 } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } test_6 } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106181.c b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
new file mode 100644
index 0000000..6a78b78
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
@@ -0,0 +1,11 @@
+#include <stdint.h>
+
+void *
+foo (int x)
+{
+ return __builtin_calloc (x * 1.1, 1); /* { dg-line calloc } */
+
+ /* { dg-warning "use of floating-point arithmetic here might yield unexpected results" "warning" { target *-*-* } calloc } */
+ /* { dg-message "operand '\(\\d|e|f|\\.|\\+|\)+' is of type 'double'" "note" { target *-*-* } calloc } */
+ /* { dg-message "only use operands of an integer type inside the size argument" "note" { target *-*-* } calloc } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr106617.c b/gcc/testsuite/gcc.dg/pr106617.c
new file mode 100644
index 0000000..4274b55
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr106617.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+
+int nr_cpu_ids;
+void fc_setup_exch_mgr() {
+ (((((((1UL << (((0, 0)
+ ? ((1)
+ ? (((nr_cpu_ids)) ? 0
+ : ((nr_cpu_ids)) & (21) ? 21
+ : ((nr_cpu_ids)) ? 20
+ : ((nr_cpu_ids)) & (19) ? 19
+ : ((nr_cpu_ids)) ? 18
+ : ((nr_cpu_ids)) & (17) ? 17
+ : ((nr_cpu_ids)) ? 16
+ : ((nr_cpu_ids)) & (15) ? 15
+ : ((nr_cpu_ids)) ? 14
+ : ((nr_cpu_ids)) & (13) ? 13
+ : ((nr_cpu_ids)) ? 12
+ : ((nr_cpu_ids)) & (11) ? 11
+ : ((nr_cpu_ids)) ? 10
+ : ((nr_cpu_ids)) & (9) ? 9
+ : ((nr_cpu_ids)) ? 8
+ : ((nr_cpu_ids)) & (7) ? 7
+ : ((nr_cpu_ids)) ? 6
+ : ((nr_cpu_ids)) & (5) ? 5
+ : ((nr_cpu_ids)) ? 4
+ : ((nr_cpu_ids)) & (3)
+ ? 3
+ : ((nr_cpu_ids)-1) & 1)
+ : 1)
+ : 0) +
+ 1))))) &
+ (1UL << 2)
+ ? 2
+ : 1))
+ );
+}
diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc
index 44dc27b..513e0c8 100644
--- a/gcc/tree-ssa-dom.cc
+++ b/gcc/tree-ssa-dom.cc
@@ -798,7 +798,7 @@ pass_dominator::execute (function *fun)
/* Recursively walk the dominator tree optimizing statements. */
gimple_ranger *ranger = enable_ranger (fun);
- path_range_query path_query (/*resolve=*/true, ranger);
+ path_range_query path_query (*ranger);
dom_jt_simplifier simplifier (avail_exprs_stack, ranger, &path_query);
dom_jt_state state (const_and_copies, avail_exprs_stack);
jump_threader threader (&simplifier, &state);
diff --git a/gcc/tree-ssa-loop-ch.cc b/gcc/tree-ssa-loop-ch.cc
index 3b91a89..96816b8 100644
--- a/gcc/tree-ssa-loop-ch.cc
+++ b/gcc/tree-ssa-loop-ch.cc
@@ -49,7 +49,7 @@ along with GCC; see the file COPYING3. If not see
be statically determined. */
static bool
-entry_loop_condition_is_static (class loop *l, path_range_query *query)
+entry_loop_condition_is_static (class loop *l, gimple_ranger *ranger)
{
edge e = loop_preheader_edge (l);
gcond *last = safe_dyn_cast <gcond *> (last_stmt (e->dest));
@@ -72,8 +72,8 @@ entry_loop_condition_is_static (class loop *l, path_range_query *query)
desired_static_value = boolean_true_node;
int_range<2> r;
- query->compute_ranges (e);
- query->range_of_stmt (r, last);
+ path_range_query query (*ranger, e);
+ query.range_of_stmt (r, last);
return r == int_range<2> (desired_static_value, desired_static_value);
}
@@ -385,7 +385,7 @@ ch_base::copy_headers (function *fun)
auto_vec<std::pair<edge, loop_p> > copied;
mark_dfs_back_edges ();
- path_range_query *query = new path_range_query;
+ gimple_ranger *ranger = new gimple_ranger;
for (auto loop : loops_list (cfun, 0))
{
int initial_limit = param_max_loop_header_insns;
@@ -409,7 +409,7 @@ ch_base::copy_headers (function *fun)
iteration. */
if (optimize_loop_for_size_p (loop)
&& !loop->force_vectorize
- && !entry_loop_condition_is_static (loop, query))
+ && !entry_loop_condition_is_static (loop, ranger))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
@@ -422,7 +422,7 @@ ch_base::copy_headers (function *fun)
candidates.safe_push (loop);
}
/* Do not use ranger after we change the IL and not have updated SSA. */
- delete query;
+ delete ranger;
for (auto loop : candidates)
{
diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index 7698e1f..3218ad9 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -116,7 +116,6 @@ private:
virtual void dump (FILE *out);
back_threader_registry m_registry;
- path_range_query *m_solver;
// Current path being analyzed.
auto_vec<basic_block> m_path;
@@ -136,6 +135,8 @@ private:
// with the ranger. Otherwise, unknown SSA names are assumed to be
// VARYING. Setting to true is more precise but slower.
function *m_fun;
+ // Ranger for the path solver.
+ gimple_ranger *m_ranger;
unsigned m_flags;
// Set to TRUE for the first of each thread[12] pass or the first of
// each threadfull[12] pass. This is used to differentiate between
@@ -162,13 +163,13 @@ back_threader::back_threader (function *fun, unsigned flags, bool first)
// The path solver needs EDGE_DFS_BACK in resolving mode.
if (flags & BT_RESOLVE)
mark_dfs_back_edges ();
- m_solver = new path_range_query (flags & BT_RESOLVE);
+
+ m_ranger = new gimple_ranger;
}
back_threader::~back_threader ()
{
- delete m_solver;
-
+ delete m_ranger;
loop_optimizer_finalize ();
}
@@ -305,8 +306,8 @@ back_threader::find_taken_edge_switch (const vec<basic_block> &path,
tree name = gimple_switch_index (sw);
int_range_max r;
- m_solver->compute_ranges (path, m_imports);
- m_solver->range_of_expr (r, name, sw);
+ path_range_query solver (*m_ranger, path, m_imports, m_flags & BT_RESOLVE);
+ solver.range_of_expr (r, name, sw);
if (r.undefined_p ())
return UNREACHABLE_EDGE;
@@ -329,10 +330,10 @@ back_threader::find_taken_edge_cond (const vec<basic_block> &path,
{
int_range_max r;
- m_solver->compute_ranges (path, m_imports);
- m_solver->range_of_stmt (r, cond);
+ path_range_query solver (*m_ranger, path, m_imports, m_flags & BT_RESOLVE);
+ solver.range_of_stmt (r, cond);
- if (m_solver->unreachable_path_p ())
+ if (solver.unreachable_path_p ())
return UNREACHABLE_EDGE;
int_range<2> true_range (boolean_true_node, boolean_true_node);
@@ -583,7 +584,6 @@ debug (const vec <basic_block> &path)
void
back_threader::dump (FILE *out)
{
- m_solver->dump (out);
fprintf (out, "\nCandidates for pre-computation:\n");
fprintf (out, "===================================\n");
diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
index e64e4f2..905a98c 100644
--- a/gcc/tree-ssa-threadedge.cc
+++ b/gcc/tree-ssa-threadedge.cc
@@ -1399,7 +1399,6 @@ jt_state::register_equivs_stmt (gimple *stmt, basic_block bb,
// Hybrid threader implementation.
-
hybrid_jt_simplifier::hybrid_jt_simplifier (gimple_ranger *r,
path_range_query *q)
{
@@ -1411,7 +1410,12 @@ tree
hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block,
jt_state *state)
{
- compute_ranges_from_state (stmt, state);
+ auto_bitmap dependencies;
+ auto_vec<basic_block> path;
+
+ state->get_path (path);
+ compute_exit_dependencies (dependencies, path, stmt);
+ m_query->reset_path (path, dependencies);
if (gimple_code (stmt) == GIMPLE_COND
|| gimple_code (stmt) == GIMPLE_ASSIGN)
@@ -1432,22 +1436,25 @@ hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block,
return NULL;
}
-// Use STATE to generate the list of imports needed for the solver,
-// and calculate the ranges along the path.
+// Calculate the set of exit dependencies for a path and statement to
+// be simplified. This is different than the
+// compute_exit_dependencies in the path solver because the forward
+// threader asks questions about statements not necessarily in the
+// path. Using the default compute_exit_dependencies in the path
+// solver gets noticeably less threads.
void
-hybrid_jt_simplifier::compute_ranges_from_state (gimple *stmt, jt_state *state)
+hybrid_jt_simplifier::compute_exit_dependencies (bitmap dependencies,
+ const vec<basic_block> &path,
+ gimple *stmt)
{
- auto_bitmap imports;
gori_compute &gori = m_ranger->gori ();
- state->get_path (m_path);
-
// Start with the imports to the final conditional.
- bitmap_copy (imports, gori.imports (m_path[0]));
+ bitmap_copy (dependencies, gori.imports (path[0]));
// Add any other interesting operands we may have missed.
- if (gimple_bb (stmt) != m_path[0])
+ if (gimple_bb (stmt) != path[0])
{
for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
{
@@ -1455,8 +1462,7 @@ hybrid_jt_simplifier::compute_ranges_from_state (gimple *stmt, jt_state *state)
if (op
&& TREE_CODE (op) == SSA_NAME
&& Value_Range::supports_type_p (TREE_TYPE (op)))
- bitmap_set_bit (imports, SSA_NAME_VERSION (op));
+ bitmap_set_bit (dependencies, SSA_NAME_VERSION (op));
}
}
- m_query->compute_ranges (m_path, imports);
}
diff --git a/gcc/tree-ssa-threadedge.h b/gcc/tree-ssa-threadedge.h
index ca70b33..790ac2e 100644
--- a/gcc/tree-ssa-threadedge.h
+++ b/gcc/tree-ssa-threadedge.h
@@ -69,11 +69,12 @@ public:
tree simplify (gimple *stmt, gimple *, basic_block, jt_state *) override;
private:
- void compute_ranges_from_state (gimple *stmt, jt_state *);
+ void compute_exit_dependencies (bitmap dependencies,
+ const vec<basic_block> &path,
+ gimple *stmt);
gimple_ranger *m_ranger;
path_range_query *m_query;
- auto_vec<basic_block> m_path;
};
// This is the high level threader. The entry point is