Commit 7ec02c04 by Frank Ch. Eigler Committed by Frank Ch. Eigler

tree-mudflap.c (mudflap_init): Mark cache-lookup decls to prevent their later…

tree-mudflap.c (mudflap_init): Mark cache-lookup decls to prevent their later unnecessary registration.

2004-10-28  Frank Ch. Eigler  <fche@redhat.com>

	* tree-mudflap.c (mudflap_init): Mark cache-lookup decls to
	prevent their later unnecessary registration.
	(mf_build_check_statement_for): Remove "addr" argument, and
	related "__mf_value" generated code.  Update callers.
	(mf_decl_eligible_p): New function, factored from mx_register_decls.
	(mx_register_decls): Call it.
	(mf_xform_derefs_1): Rewrite COMPONENT_REF and ARRAY_REF cases
	to restore support for complex nested expressions.
	(mudflap_enqueue_decl): Simplify.  Move registration call emission
	out ...
	(mudflap_finish_file): ... to here.
	(mudflap_enqueue_constant): Remove dump code.

From-SVN: r89784
parent 306ae32b
2004-10-28 Frank Ch. Eigler <fche@redhat.com>
* tree-mudflap.c (mudflap_init): Mark cache-lookup decls to
prevent their later unnecessary registration.
(mf_build_check_statement_for): Remove "addr" argument, and
related "__mf_value" generated code. Update callers.
(mf_decl_eligible_p): New function, factored from mx_register_decls.
(mx_register_decls): Call it.
(mf_xform_derefs_1): Rewrite COMPONENT_REF and ARRAY_REF cases
to restore support for complex nested expressions.
(mudflap_enqueue_decl): Simplify. Move registration call emission
out ...
(mudflap_finish_file): ... to here.
(mudflap_enqueue_constant): Remove dump code.
2004-10-28 Zack Weinberg <zack@codesourcery.com> 2004-10-28 Zack Weinberg <zack@codesourcery.com>
PR 18199 PR 18199
......
...@@ -378,6 +378,11 @@ mudflap_init (void) ...@@ -378,6 +378,11 @@ mudflap_init (void)
unsigned_char_type_node); unsigned_char_type_node);
mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask", mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask",
mf_uintptr_type); mf_uintptr_type);
/* Don't process these in mudflap_enqueue_decl, should they come by
there for some reason. */
mf_mark (mf_cache_array_decl);
mf_mark (mf_cache_shift_decl);
mf_mark (mf_cache_mask_decl);
mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check", mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check",
mf_check_register_fntype); mf_check_register_fntype);
mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register", mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register",
...@@ -484,17 +489,15 @@ mf_decl_clear_locals (void) ...@@ -484,17 +489,15 @@ mf_decl_clear_locals (void)
} }
static void static void
mf_build_check_statement_for (tree base, tree addr, tree limit, mf_build_check_statement_for (tree base, tree limit,
block_stmt_iterator *instr_bsi, block_stmt_iterator *instr_bsi,
location_t *locus, tree dirflag) location_t *locus, tree dirflag)
{ {
tree_stmt_iterator head, tsi; tree_stmt_iterator head, tsi;
tree ptrtype = TREE_TYPE (addr);
block_stmt_iterator bsi; block_stmt_iterator bsi;
basic_block cond_bb, then_bb, join_bb; basic_block cond_bb, then_bb, join_bb;
edge e; edge e;
tree cond, t, u, v, l1, l2; tree cond, t, u, v, l1, l2;
tree mf_value;
tree mf_base; tree mf_base;
tree mf_elem; tree mf_elem;
tree mf_limit; tree mf_limit;
...@@ -558,24 +561,17 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, ...@@ -558,24 +561,17 @@ mf_build_check_statement_for (tree base, tree addr, tree limit,
} }
/* Build our local variables. */ /* Build our local variables. */
mf_value = create_tmp_var (ptrtype, "__mf_value");
mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem"); mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
mf_base = create_tmp_var (mf_uintptr_type, "__mf_base"); mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
mf_limit = create_tmp_var (mf_uintptr_type, "__mf_limit"); mf_limit = create_tmp_var (mf_uintptr_type, "__mf_limit");
/* Build: __mf_value = <address expression>. */
t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
SET_EXPR_LOCUS (t, locus);
gimplify_to_stmt_list (&t);
head = tsi_start (t);
tsi = tsi_last (t);
/* Build: __mf_base = (uintptr_t) <base address expression>. */ /* Build: __mf_base = (uintptr_t) <base address expression>. */
t = build (MODIFY_EXPR, void_type_node, mf_base, t = build (MODIFY_EXPR, void_type_node, mf_base,
convert (mf_uintptr_type, unshare_expr (base))); convert (mf_uintptr_type, unshare_expr (base)));
SET_EXPR_LOCUS (t, locus); SET_EXPR_LOCUS (t, locus);
gimplify_to_stmt_list (&t); gimplify_to_stmt_list (&t);
tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); head = tsi_start (t);
tsi = tsi_last (t);
/* Build: __mf_limit = (uintptr_t) <limit address expression>. */ /* Build: __mf_limit = (uintptr_t) <limit address expression>. */
t = build (MODIFY_EXPR, void_type_node, mf_limit, t = build (MODIFY_EXPR, void_type_node, mf_limit,
...@@ -679,8 +675,7 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, ...@@ -679,8 +675,7 @@ mf_build_check_statement_for (tree base, tree addr, tree limit,
: *locus), : *locus),
NULL_TREE); NULL_TREE);
u = tree_cons (NULL_TREE, dirflag, u); u = tree_cons (NULL_TREE, dirflag, u);
/* NB: we pass the overall [base..limit] range to mf_check, /* NB: we pass the overall [base..limit] range to mf_check. */
not the [mf_value..mf_value+size-1] range. */
u = tree_cons (NULL_TREE, u = tree_cons (NULL_TREE,
fold (build (PLUS_EXPR, integer_type_node, fold (build (PLUS_EXPR, integer_type_node,
fold (build (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base)), fold (build (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base)),
...@@ -712,11 +707,33 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, ...@@ -712,11 +707,33 @@ mf_build_check_statement_for (tree base, tree addr, tree limit,
bsi_next (instr_bsi); bsi_next (instr_bsi);
} }
/* Check whether the given decl, generally a VAR_DECL or PARM_DECL, is
eligible for instrumentation. For the mudflap1 pass, this implies
that it should be registered with the libmudflap runtime. For the
mudflap2 pass this means instrumenting an indirection operation with
respect to the object.
*/
static int
mf_decl_eligible_p (tree decl)
{
return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
/* The decl must have its address taken. In the case of
arrays, this flag is also set if the indexes are not
compile-time known valid constants. */
&& TREE_ADDRESSABLE (decl)
/* The type of the variable must be complete. */
&& COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
/* The decl hasn't been decomposed somehow. */
&& DECL_VALUE_EXPR (decl) == NULL);
}
static void static void
mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
location_t *locus, tree dirflag) location_t *locus, tree dirflag)
{ {
tree type, ptr_type, addr, base, size, limit, t; tree type, ptr_type, base, limit, addr, size, t;
/* Don't instrument read operations. */ /* Don't instrument read operations. */
if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
...@@ -733,80 +750,70 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, ...@@ -733,80 +750,70 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
switch (TREE_CODE (t)) switch (TREE_CODE (t))
{ {
case ARRAY_REF: case ARRAY_REF:
case COMPONENT_REF:
{
/* This is trickier than it may first appear. The reason is
that we are looking at expressions from the "inside out" at
this point. We may have a complex nested aggregate/array
expression (e.g. "a.b[i].c"), maybe with an indirection as
the leftmost operator ("p->a.b.d"), where instrumentation
is necessary. Or we may have an innocent "a.b.c"
expression that must not be instrumented. We need to
recurse all the way down the nesting structure to figure it
out: looking just at the outer node is not enough. */
tree var;
int component_ref_only = TREE_CODE (t) == COMPONENT_REF;
/* Iterate to the top of the ARRAY_REF/COMPONENT_REF
containment hierarchy to find the outermost VAR_DECL. */
var = TREE_OPERAND (t, 0);
while (1)
{ {
/* Omit checking if we can statically determine that the access is if (TREE_CODE (var) == ARRAY_REF)
valid. For non-addressable local arrays this is not optional, {
since we won't have called __mf_register for the object. */ component_ref_only = 0;
tree op0, op1; var = TREE_OPERAND (var, 0);
}
op0 = TREE_OPERAND (t, 0); else if (TREE_CODE (var) == COMPONENT_REF)
op1 = TREE_OPERAND (t, 1); var = TREE_OPERAND (var, 0);
while (TREE_CODE (op1) == INTEGER_CST) else if (INDIRECT_REF_P (var))
{ {
tree dom = TYPE_DOMAIN (TREE_TYPE (op0)); component_ref_only = 0;
/* Test for index in range. Break if not. */
if (!dom
|| (! TYPE_MIN_VALUE (dom)
|| ! really_constant_p (TYPE_MIN_VALUE (dom)))
|| (! TYPE_MAX_VALUE (dom)
|| ! really_constant_p (TYPE_MAX_VALUE (dom)))
|| (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
|| tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
break; break;
}
/* If we're looking at a non-external VAR_DECL, then the else
access must be ok. */ {
if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0)) gcc_assert (TREE_CODE (var) == VAR_DECL
|| TREE_CODE (var) == PARM_DECL);
/* Don't instrument this access if the underlying
variable is not "eligible". This test matches
those arrays that have only known-valid indexes,
and thus are not labeled TREE_ADDRESSABLE. */
if (! mf_decl_eligible_p (var))
return; return;
else
/* Only continue if we're still looking at an array. */
if (TREE_CODE (op0) != ARRAY_REF)
break; break;
op1 = TREE_OPERAND (op0, 1);
op0 = TREE_OPERAND (op0, 0);
} }
/* If we got here, we couldn't statically the check. */
ptr_type = build_pointer_type (type);
addr = build1 (ADDR_EXPR, ptr_type, t);
base = build1 (ADDR_EXPR, ptr_type, op0);
limit = fold (build (MINUS_EXPR, mf_uintptr_type,
fold (build2 (PLUS_EXPR, mf_uintptr_type, addr, size)),
integer_one_node));
} }
break;
case INDIRECT_REF: /* Handle the case of ordinary non-indirection structure
addr = TREE_OPERAND (t, 0); accesses. These have only nested COMPONENT_REF nodes (no
ptr_type = TREE_TYPE (addr); INDIRECT_REF), but pass through the above filter loop.
base = addr; Note that it's possible for such a struct variable to match
limit = fold (build (MINUS_EXPR, ptr_type_node, the eligible_p test because someone else might take its
fold (build (PLUS_EXPR, ptr_type_node, base, size)), address sometime. */
integer_one_node)); if (component_ref_only)
break;
case ARRAY_RANGE_REF:
warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
return; return;
case COMPONENT_REF: ptr_type = build_pointer_type (type);
{
tree field;
/* If we're not dereferencing something, then the access
must be ok. */
if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
return;
field = TREE_OPERAND (t, 1);
/* If we're looking at a bit field, then we can't take its address /* We need special processing for bitfield components, because
with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do their addresses cannot be taken. */
things the hard way with PLUS. */ if (TREE_CODE (t) == COMPONENT_REF
if (DECL_BIT_FIELD_TYPE (field)) && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1)))
{ {
tree field = TREE_OPERAND (t, 1);
if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
size = DECL_SIZE_UNIT (field); size = DECL_SIZE_UNIT (field);
...@@ -817,20 +824,35 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, ...@@ -817,20 +824,35 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
byte_position (field)))); byte_position (field))));
} }
else else
{ addr = build1 (ADDR_EXPR, build_pointer_type (type), t);
ptr_type = build_pointer_type (type);
addr = build1 (ADDR_EXPR, ptr_type, t); if (INDIRECT_REF_P (var))
base = TREE_OPERAND (var, 0);
else
base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var);
limit = fold (build (MINUS_EXPR, mf_uintptr_type,
fold (build2 (PLUS_EXPR, mf_uintptr_type,
convert (mf_uintptr_type, addr),
size)),
integer_one_node));
} }
break;
/* XXXXXX */ case INDIRECT_REF:
addr = TREE_OPERAND (t, 0);
ptr_type = TREE_TYPE (addr);
base = addr; base = addr;
limit = fold (build (MINUS_EXPR, ptr_type_node, limit = fold (build (MINUS_EXPR, ptr_type_node,
fold (build (PLUS_EXPR, ptr_type_node, base, size)), fold (build (PLUS_EXPR, ptr_type_node, base, size)),
integer_one_node)); integer_one_node));
}
break; break;
case ARRAY_RANGE_REF:
warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
return;
case BIT_FIELD_REF: case BIT_FIELD_REF:
/* ??? merge with COMPONENT_REF code above? */
{ {
tree ofs, rem, bpu; tree ofs, rem, bpu;
...@@ -864,7 +886,7 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, ...@@ -864,7 +886,7 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
return; return;
} }
mf_build_check_statement_for (base, addr, limit, iter, locus, dirflag); mf_build_check_statement_for (base, limit, iter, locus, dirflag);
} }
static void static void
...@@ -959,19 +981,12 @@ mx_register_decls (tree decl, tree *stmt_list) ...@@ -959,19 +981,12 @@ mx_register_decls (tree decl, tree *stmt_list)
while (decl != NULL_TREE) while (decl != NULL_TREE)
{ {
/* Eligible decl? */ if (mf_decl_eligible_p (decl)
if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) /* Not already processed. */
/* It must be a non-external, automatic variable. */ && ! mf_marked_p (decl)
/* Automatic variable. */
&& ! DECL_EXTERNAL (decl) && ! DECL_EXTERNAL (decl)
&& ! TREE_STATIC (decl) && ! TREE_STATIC (decl))
/* The decl must have its address taken. */
&& TREE_ADDRESSABLE (decl)
/* The type of the variable must be complete. */
&& COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
/* The decl hasn't been decomposed somehow. */
&& DECL_VALUE_EXPR (decl) == NULL
/* Don't process the same decl twice. */
&& ! mf_marked_p (decl))
{ {
tree size = NULL_TREE, variable_name; tree size = NULL_TREE, variable_name;
tree unregister_fncall, unregister_fncall_params; tree unregister_fncall, unregister_fncall_params;
...@@ -1180,50 +1195,13 @@ mudflap_enqueue_decl (tree obj) ...@@ -1180,50 +1195,13 @@ mudflap_enqueue_decl (tree obj)
if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj)) if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
return; return;
if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
{
tree object_size;
mf_mark (obj);
object_size = size_in_bytes (TREE_TYPE (obj));
if (dump_file)
{
fprintf (dump_file, "enqueue_decl obj=`");
print_generic_expr (dump_file, obj, dump_flags);
fprintf (dump_file, "' size=");
print_generic_expr (dump_file, object_size, dump_flags);
fprintf (dump_file, "\n");
}
/* NB: the above condition doesn't require TREE_USED or
TREE_ADDRESSABLE. That's because this object may be a global
only used from other compilation units. XXX: Maybe static
objects could require those attributes being set. */
mudflap_register_call (obj, object_size, mf_varname_tree (obj));
}
else
{
size_t i;
if (! deferred_static_decls) if (! deferred_static_decls)
VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list"); VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
/* Ugh, linear search... */
for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
if (VARRAY_TREE (deferred_static_decls, i) == obj)
{
warning ("mudflap cannot track unknown size extern %qs",
IDENTIFIER_POINTER (DECL_NAME (obj)));
return;
}
VARRAY_PUSH_TREE (deferred_static_decls, obj); VARRAY_PUSH_TREE (deferred_static_decls, obj);
}
} }
void void
mudflap_enqueue_constant (tree obj) mudflap_enqueue_constant (tree obj)
{ {
...@@ -1237,15 +1215,6 @@ mudflap_enqueue_constant (tree obj) ...@@ -1237,15 +1215,6 @@ mudflap_enqueue_constant (tree obj)
else else
object_size = size_in_bytes (TREE_TYPE (obj)); object_size = size_in_bytes (TREE_TYPE (obj));
if (dump_file)
{
fprintf (dump_file, "enqueue_constant obj=`");
print_generic_expr (dump_file, obj, dump_flags);
fprintf (dump_file, "' size=");
print_generic_expr (dump_file, object_size, dump_flags);
fprintf (dump_file, "\n");
}
if (TREE_CODE (obj) == STRING_CST) if (TREE_CODE (obj) == STRING_CST)
varname = mf_build_string ("string literal"); varname = mf_build_string ("string literal");
else else
...@@ -1261,24 +1230,6 @@ mudflap_finish_file (void) ...@@ -1261,24 +1230,6 @@ mudflap_finish_file (void)
{ {
tree ctor_statements = NULL_TREE; tree ctor_statements = NULL_TREE;
/* Try to give the deferred objects one final try. */
if (deferred_static_decls)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
{
tree obj = VARRAY_TREE (deferred_static_decls, i);
/* Call enqueue_decl again on the same object it has previously
put into the table. (It won't modify the table this time, so
infinite iteration is not a problem.) */
mudflap_enqueue_decl (obj);
}
VARRAY_CLEAR (deferred_static_decls);
}
/* Insert a call to __mf_init. */ /* Insert a call to __mf_init. */
{ {
tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE); tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE);
...@@ -1294,6 +1245,41 @@ mudflap_finish_file (void) ...@@ -1294,6 +1245,41 @@ mudflap_finish_file (void)
append_to_statement_list (call_stmt, &ctor_statements); append_to_statement_list (call_stmt, &ctor_statements);
} }
/* Process all enqueued object decls. */
if (deferred_static_decls)
{
size_t i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
{
tree obj = VARRAY_TREE (deferred_static_decls, i);
gcc_assert (DECL_P (obj));
if (mf_marked_p (obj))
continue;
/* Omit registration for static unaddressed objects. NB:
Perform registration for non-static objects regardless of
TREE_USED or TREE_ADDRESSABLE, because they may be used
from other compilation units. */
if (TREE_STATIC (obj) && ! TREE_ADDRESSABLE (obj))
continue;
if (! COMPLETE_TYPE_P (TREE_TYPE (obj)))
{
warning ("mudflap cannot track unknown size extern %qs",
IDENTIFIER_POINTER (DECL_NAME (obj)));
continue;
}
mudflap_register_call (obj,
size_in_bytes (TREE_TYPE (obj)),
mf_varname_tree (obj));
}
VARRAY_CLEAR (deferred_static_decls);
}
/* Append all the enqueued registration calls. */ /* Append all the enqueued registration calls. */
if (enqueued_call_stmt_chain) if (enqueued_call_stmt_chain)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment