#include "backend.h"
#include "tree.h"
#include "gimple.h"
-#include "domwalk.h"
#include "tree-pass.h"
#include "builtins.h"
#include "ssa.h"
#include "calls.h"
#include "cfgloop.h"
#include "intl.h"
+#include "gimple-range.h"
namespace {
return warn_array_bounds || warn_restrict || warn_stringop_overflow;
}
-/* Class to walk the basic blocks of a function in dominator order. */
-class wrestrict_dom_walker : public dom_walker
-{
- public:
- wrestrict_dom_walker () : dom_walker (CDI_DOMINATORS) {}
+static void check_call (range_query *, gimple *);
- edge before_dom_children (basic_block) FINAL OVERRIDE;
- bool handle_gimple_call (gimple_stmt_iterator *);
-
- private:
- void check_call (gimple *);
-};
-
-edge
-wrestrict_dom_walker::before_dom_children (basic_block bb)
+static void
+wrestrict_walk (range_query *query, basic_block bb)
{
/* Iterate over statements, looking for function calls. */
for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
if (!is_gimple_call (stmt))
continue;
- check_call (stmt);
+ check_call (query, stmt);
}
-
- return NULL;
}
-/* Execute the pass for function FUN, walking in dominator order. */
-
unsigned
pass_wrestrict::execute (function *fun)
{
- calculate_dominance_info (CDI_DOMINATORS);
-
- wrestrict_dom_walker walker;
- walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
+ gimple_ranger ranger;
+ basic_block bb;
+ FOR_EACH_BB_FN (bb, fun)
+ wrestrict_walk (&ranger, bb);
return 0;
}
only the destination reference is. */
bool strbounded_p;
- builtin_memref (tree, tree);
+ builtin_memref (range_query *, gimple *, tree, tree);
tree offset_out_of_bounds (int, offset_int[3]) const;
private:
+ /* Call statement to the built-in. */
+ gimple *stmt;
+
+ range_query *query;
/* Ctor helper to set or extend OFFRANGE based on argument. */
void extend_offset_range (tree);
&& detect_overlap != &builtin_access::no_overlap);
}
- builtin_access (gimple *, builtin_memref &, builtin_memref &);
+ builtin_access (range_query *, gimple *, builtin_memref &, builtin_memref &);
/* Entry point to determine overlap. */
bool overlap ();
/* Initialize a memory reference representation from a pointer EXPR and
a size SIZE in bytes. If SIZE is NULL_TREE then the size is assumed
- to be unknown. */
+ to be unknown. STMT is the statement in which expr appears in. */
-builtin_memref::builtin_memref (tree expr, tree size)
+builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
+ tree size)
: ptr (expr),
ref (),
base (),
offrange (),
sizrange (),
maxobjsize (tree_to_shwi (max_object_size ())),
- strbounded_p ()
+ strbounded_p (),
+ stmt (stmt),
+ query (query)
{
/* Unfortunately, wide_int default ctor is a no-op so array members
of the type must be set individually. */
tree range[2];
/* Determine the size range, allowing for the result to be [0, 0]
for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX. */
- get_size_range (size, range, SR_ALLOW_ZERO);
+ get_size_range (query, size, stmt, range, SR_ALLOW_ZERO);
sizrange[0] = wi::to_offset (range[0]);
sizrange[1] = wi::to_offset (range[1]);
/* get_size_range returns SIZE_MAX for the maximum size.
/* A pointer offset is represented as sizetype but treated
as signed. */
wide_int min, max;
- value_range_kind rng = get_range_info (offset, &min, &max);
+ value_range_kind rng;
+ value_range vr;
+ if (query && query->range_of_expr (vr, offset, stmt))
+ {
+ rng = vr.kind ();
+ if (!vr.undefined_p ())
+ {
+ min = wi::to_wide (vr.min ());
+ max = wi::to_wide (vr.max ());
+ }
+ }
+ else
+ {
+ /* There is a global version here because
+ check_bounds_or_overlap may be called from gimple
+ fold during gimple lowering. */
+ rng = get_range_info (offset, &min, &max);
+ }
if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
{
/* Convert an anti-range whose upper bound is less than
/* Create an association between the memory references DST and SRC
for access by a call EXPR to a memory or string built-in funtion. */
-builtin_access::builtin_access (gimple *call, builtin_memref &dst,
+builtin_access::builtin_access (range_query *query, gimple *call,
+ builtin_memref &dst,
builtin_memref &src)
: dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (),
dstoff (), srcoff (), dstsiz (), srcsiz ()
tree size = gimple_call_arg (call, sizeargno);
tree range[2];
- if (get_size_range (size, range, true))
+ if (get_size_range (query, size, call, range, true))
{
bounds[0] = wi::to_offset (range[0]);
bounds[1] = wi::to_offset (range[1]);
/* Check a CALL statement for restrict-violations and issue warnings
if/when appropriate. */
-void
-wrestrict_dom_walker::check_call (gimple *call)
+static void
+check_call (range_query *query, gimple *call)
{
/* Avoid checking the call if it has already been diagnosed for
some reason. */
|| (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
return;
- if (!check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE))
+ if (!check_bounds_or_overlap (query, call, dst, src, dstwr, NULL_TREE))
return;
/* Avoid diagnosing the call again. */
check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
tree srcsize, bool bounds_only /* = false */,
bool do_warn /* = true */)
+{
+ return check_bounds_or_overlap (/*range_query=*/NULL,
+ call, dst, src, dstsize, srcsize,
+ bounds_only, do_warn);
+}
+
+int
+check_bounds_or_overlap (range_query *query,
+ gimple *call, tree dst, tree src, tree dstsize,
+ tree srcsize, bool bounds_only /* = false */,
+ bool do_warn /* = true */)
{
tree func = gimple_call_fndecl (call);
- builtin_memref dstref (dst, dstsize);
- builtin_memref srcref (src, srcsize);
+ builtin_memref dstref (query, call, dst, dstsize);
+ builtin_memref srcref (query, call, src, srcsize);
/* Create a descriptor of the access. This may adjust both DSTREF
and SRCREF based on one another and the kind of the access. */
- builtin_access acs (call, dstref, srcref);
+ builtin_access acs (query, call, dstref, srcref);
/* Set STRICT to the value of the -Warray-bounds=N argument for
string functions or when N > 1. */