mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
Enable pointer_query caching in -Wrestrict.
gcc/ChangeLog: * gimple-ssa-warn-restrict.cc (class pass_wrestrict): Outline ctor. (pass_wrestrict::m_ptr_qry): New member. (wrestrict_walk): Rename... (pass_wrestrict::check_block): ...to this. (pass_wrestrict::execute): Set up and tear down pointer_query and ranger. (builtin_memref::builtin_memref): Change ctor argument. Simplify. (builtin_access::builtin_access): Same. (builtin_access::m_ptr_qry): New member. (check_call): Rename... (pass_wrestrict::check_call): ...to this. (check_bounds_or_overlap): Change argument. * gimple-ssa-warn-restrict.h (check_bounds_or_overlap): Same.
This commit is contained in:
@@ -62,46 +62,61 @@ const pass_data pass_data_wrestrict = {
|
||||
class pass_wrestrict : public gimple_opt_pass
|
||||
{
|
||||
public:
|
||||
pass_wrestrict (gcc::context *ctxt)
|
||||
: gimple_opt_pass (pass_data_wrestrict, ctxt)
|
||||
{ }
|
||||
|
||||
opt_pass *clone () { return new pass_wrestrict (m_ctxt); }
|
||||
pass_wrestrict (gcc::context *);
|
||||
|
||||
virtual bool gate (function *);
|
||||
virtual unsigned int execute (function *);
|
||||
|
||||
void check_call (gimple *);
|
||||
|
||||
void check_block (basic_block);
|
||||
|
||||
/* A pointer_query object to store information about pointers and
|
||||
their targets in. */
|
||||
pointer_query m_ptr_qry;
|
||||
};
|
||||
|
||||
pass_wrestrict::pass_wrestrict (gcc::context *ctxt)
|
||||
: gimple_opt_pass (pass_data_wrestrict, ctxt),
|
||||
m_ptr_qry ()
|
||||
{ }
|
||||
|
||||
bool
|
||||
pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return warn_array_bounds || warn_restrict || warn_stringop_overflow;
|
||||
}
|
||||
|
||||
static void check_call (range_query *, gimple *);
|
||||
|
||||
static void
|
||||
wrestrict_walk (range_query *query, basic_block bb)
|
||||
void
|
||||
pass_wrestrict::check_block (basic_block bb)
|
||||
{
|
||||
/* Iterate over statements, looking for function calls. */
|
||||
for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
|
||||
gsi_next (&si))
|
||||
for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
|
||||
{
|
||||
gimple *stmt = gsi_stmt (si);
|
||||
if (!is_gimple_call (stmt))
|
||||
continue;
|
||||
|
||||
check_call (query, stmt);
|
||||
check_call (stmt);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
pass_wrestrict::execute (function *fun)
|
||||
{
|
||||
gimple_ranger ranger;
|
||||
/* Create a new ranger instance and associate it with FUN. */
|
||||
m_ptr_qry.rvals = enable_ranger (fun);
|
||||
|
||||
basic_block bb;
|
||||
FOR_EACH_BB_FN (bb, fun)
|
||||
wrestrict_walk (&ranger, bb);
|
||||
check_block (bb);
|
||||
|
||||
m_ptr_qry.flush_cache ();
|
||||
|
||||
/* Release the ranger instance and replace it with a global ranger.
|
||||
Also reset the pointer since calling disable_ranger() deletes it. */
|
||||
disable_ranger (fun);
|
||||
m_ptr_qry.rvals = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -145,7 +160,7 @@ public:
|
||||
only the destination reference is. */
|
||||
bool strbounded_p;
|
||||
|
||||
builtin_memref (range_query *, gimple *, tree, tree);
|
||||
builtin_memref (pointer_query &, gimple *, tree, tree);
|
||||
|
||||
tree offset_out_of_bounds (int, offset_int[3]) const;
|
||||
|
||||
@@ -153,7 +168,7 @@ private:
|
||||
/* Call statement to the built-in. */
|
||||
gimple *stmt;
|
||||
|
||||
range_query *query;
|
||||
pointer_query &m_ptr_qry;
|
||||
|
||||
/* Ctor helper to set or extend OFFRANGE based on argument. */
|
||||
void extend_offset_range (tree);
|
||||
@@ -187,7 +202,8 @@ class builtin_access
|
||||
&& detect_overlap != &builtin_access::no_overlap);
|
||||
}
|
||||
|
||||
builtin_access (range_query *, gimple *, builtin_memref &, builtin_memref &);
|
||||
builtin_access (pointer_query &, gimple *,
|
||||
builtin_memref &, builtin_memref &);
|
||||
|
||||
/* Entry point to determine overlap. */
|
||||
bool overlap ();
|
||||
@@ -225,7 +241,7 @@ class builtin_access
|
||||
a size SIZE in bytes. If SIZE is NULL_TREE then the size is assumed
|
||||
to be unknown. STMT is the statement in which expr appears in. */
|
||||
|
||||
builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
|
||||
builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr,
|
||||
tree size)
|
||||
: ptr (expr),
|
||||
ref (),
|
||||
@@ -238,7 +254,7 @@ builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
|
||||
maxobjsize (tree_to_shwi (max_object_size ())),
|
||||
strbounded_p (),
|
||||
stmt (stmt),
|
||||
query (query)
|
||||
m_ptr_qry (ptrqry)
|
||||
{
|
||||
/* Unfortunately, wide_int default ctor is a no-op so array members
|
||||
of the type must be set individually. */
|
||||
@@ -257,7 +273,7 @@ builtin_memref::builtin_memref (range_query *query, gimple *stmt, tree expr,
|
||||
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 (query, size, stmt, range, SR_ALLOW_ZERO);
|
||||
get_size_range (m_ptr_qry.rvals, 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.
|
||||
@@ -334,9 +350,9 @@ builtin_memref::extend_offset_range (tree offset)
|
||||
/* A pointer offset is represented as sizetype but treated
|
||||
as signed. */
|
||||
wide_int min, max;
|
||||
value_range_kind rng;
|
||||
value_range_kind rng = VR_VARYING;
|
||||
value_range vr;
|
||||
if (query && query->range_of_expr (vr, offset, stmt))
|
||||
if (m_ptr_qry.rvals->range_of_expr (vr, offset, stmt))
|
||||
{
|
||||
rng = vr.kind ();
|
||||
if (!vr.undefined_p ())
|
||||
@@ -345,19 +361,7 @@ builtin_memref::extend_offset_range (tree offset)
|
||||
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. */
|
||||
get_range_query (cfun)->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 ());
|
||||
}
|
||||
}
|
||||
|
||||
if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
|
||||
{
|
||||
/* Convert an anti-range whose upper bound is less than
|
||||
@@ -674,7 +678,7 @@ builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[3]) const
|
||||
/* 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 (range_query *query, gimple *call,
|
||||
builtin_access::builtin_access (pointer_query &ptrqry, gimple *call,
|
||||
builtin_memref &dst,
|
||||
builtin_memref &src)
|
||||
: dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (),
|
||||
@@ -766,39 +770,28 @@ builtin_access::builtin_access (range_query *query, gimple *call,
|
||||
return;
|
||||
}
|
||||
|
||||
const offset_int maxobjsize = dst.maxobjsize;
|
||||
|
||||
/* Try to determine the size of the base object. compute_objsize
|
||||
expects a pointer so create one if BASE is a non-pointer object. */
|
||||
tree addr;
|
||||
if (dst.basesize < 0)
|
||||
{
|
||||
addr = dst.base;
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (addr)))
|
||||
addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
|
||||
|
||||
if (tree dstsize = compute_objsize (addr, call, ostype))
|
||||
dst.basesize = wi::to_offset (dstsize);
|
||||
else if (POINTER_TYPE_P (TREE_TYPE (addr)))
|
||||
dst.basesize = HOST_WIDE_INT_MIN;
|
||||
access_ref aref;
|
||||
if (ptrqry.get_ref (dst.base, call, &aref, ostype) && aref.base0)
|
||||
dst.basesize = aref.sizrng[1];
|
||||
else
|
||||
dst.basesize = maxobjsize;
|
||||
dst.basesize = HOST_WIDE_INT_MIN;
|
||||
}
|
||||
|
||||
if (src.base && src.basesize < 0)
|
||||
{
|
||||
addr = src.base;
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (addr)))
|
||||
addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
|
||||
|
||||
if (tree srcsize = compute_objsize (addr, call, ostype))
|
||||
src.basesize = wi::to_offset (srcsize);
|
||||
else if (POINTER_TYPE_P (TREE_TYPE (addr)))
|
||||
src.basesize = HOST_WIDE_INT_MIN;
|
||||
access_ref aref;
|
||||
if (ptrqry.get_ref (src.base, call, &aref, ostype) && aref.base0)
|
||||
src.basesize = aref.sizrng[1];
|
||||
else
|
||||
src.basesize = maxobjsize;
|
||||
src.basesize = HOST_WIDE_INT_MIN;
|
||||
}
|
||||
|
||||
const offset_int maxobjsize = dst.maxobjsize;
|
||||
|
||||
/* Make adjustments for references to the same object by string
|
||||
built-in functions to reflect the constraints imposed by
|
||||
the function. */
|
||||
@@ -814,7 +807,7 @@ builtin_access::builtin_access (range_query *query, gimple *call,
|
||||
|
||||
tree size = gimple_call_arg (call, sizeargno);
|
||||
tree range[2];
|
||||
if (get_size_range (query, size, call, range, true))
|
||||
if (get_size_range (ptrqry.rvals, size, call, range, true))
|
||||
{
|
||||
bounds[0] = wi::to_offset (range[0]);
|
||||
bounds[1] = wi::to_offset (range[1]);
|
||||
@@ -1895,8 +1888,8 @@ maybe_diag_access_bounds (gimple *call, tree func, int strict,
|
||||
/* Check a CALL statement for restrict-violations and issue warnings
|
||||
if/when appropriate. */
|
||||
|
||||
static void
|
||||
check_call (range_query *query, gimple *call)
|
||||
void
|
||||
pass_wrestrict::check_call (gimple *call)
|
||||
{
|
||||
/* Avoid checking the call if it has already been diagnosed for
|
||||
some reason. */
|
||||
@@ -1986,7 +1979,7 @@ check_call (range_query *query, gimple *call)
|
||||
|| (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
|
||||
return;
|
||||
|
||||
opt_code opt = check_bounds_or_overlap (query, call, dst, src, dstwr,
|
||||
opt_code opt = check_bounds_or_overlap (m_ptr_qry, call, dst, src, dstwr,
|
||||
NULL_TREE);
|
||||
/* Avoid diagnosing the call again. */
|
||||
suppress_warning (call, opt);
|
||||
@@ -2006,25 +1999,26 @@ 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,
|
||||
pointer_query ptrqry (get_range_query (cfun));
|
||||
return check_bounds_or_overlap (ptrqry,
|
||||
call, dst, src, dstsize, srcsize,
|
||||
bounds_only, do_warn);
|
||||
}
|
||||
|
||||
opt_code
|
||||
check_bounds_or_overlap (range_query *query,
|
||||
check_bounds_or_overlap (pointer_query &ptrqry,
|
||||
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 (query, call, dst, dstsize);
|
||||
builtin_memref srcref (query, call, src, srcsize);
|
||||
builtin_memref dstref (ptrqry, call, dst, dstsize);
|
||||
builtin_memref srcref (ptrqry, 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 (query, call, dstref, srcref);
|
||||
builtin_access acs (ptrqry, call, dstref, srcref);
|
||||
|
||||
/* Set STRICT to the value of the -Warray-bounds=N argument for
|
||||
string functions or when N > 1. */
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
extern opt_code check_bounds_or_overlap (gimple *, tree, tree, tree, tree,
|
||||
bool = false, bool = true);
|
||||
extern opt_code check_bounds_or_overlap (class range_query *, gimple *,
|
||||
extern opt_code check_bounds_or_overlap (class pointer_query &, gimple *,
|
||||
tree, tree, tree, tree,
|
||||
bool = false, bool = true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user