Ilya Enkovich
2014-10-08 19:10:05 UTC
Hi,
This patch introduces functions to handle static pointers and static bounds.
Thanks,
Ilya
--
2014-10-08 Ilya Enkovich <***@intel.com>
* tree-chkp.c (MAX_STMTS_IN_STATIC_CHKP_CTOR): New.
(chkp_ctor_stmt_list): New.
(chkp_register_var_initializer): New.
(chkp_add_modification_to_stmt_list): New.
(chkp_output_static_bounds): New.
(chkp_finish_file): New.
(chkp_instrument_function): Remove useless statements
from static bounds constructors.
* tree-chkp.h (chkp_register_var_initializer): New.
(chkp_finish_file): New.
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index b424af8..4b5a773 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -394,6 +394,27 @@ static bool in_chkp_pass;
#define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
#define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds"
+/* Static checker constructors may become very large and their
+ compilation with optimization may take too much time.
+ Therefore we put a limit to number of statements in one
+ construcor. Tests with 100 000 statically initialized
+ pointers showed following compilation times on Sandy Bridge
+ server (used -O2):
+ limit 100 => ~18 sec.
+ limit 300 => ~22 sec.
+ limit 1000 => ~30 sec.
+ limit 3000 => ~49 sec.
+ limit 5000 => ~55 sec.
+ limit 10000 => ~76 sec.
+ limit 100000 => ~532 sec. */
+#define MAX_STMTS_IN_STATIC_CHKP_CTOR (optimize > 0 ? 5000 : 100000)
+
+struct chkp_ctor_stmt_list
+{
+ tree stmts;
+ int avail;
+};
+
/* Return 1 if function FNDECL is instrumented by Pointer
Bounds Checker. */
bool
@@ -871,6 +892,53 @@ chkp_set_bounds (tree node, tree val)
chkp_bounds_map->put (node, val);
}
+/* Check if statically initialized variable VAR require
+ static bounds initilization. If VAR is added into
+ bounds initlization list then 1 is returned. Otherwise
+ return 0. */
+extern bool
+chkp_register_var_initializer (tree var)
+{
+ if (!flag_check_pointer_bounds)
+ return false;
+
+ gcc_assert (TREE_CODE (var) == VAR_DECL);
+ gcc_assert (DECL_INITIAL (var)
+ && DECL_INITIAL (var) != error_mark_node);
+
+ if (TREE_STATIC (var)
+ && chkp_type_has_pointer (TREE_TYPE (var)))
+ {
+ varpool_node::get_create (var)->need_bounds_init = 1;
+ return true;
+ }
+
+ return false;
+}
+
+/* Helper function for chkp_finish_file.
+
+ Add new modification statement (RHS is assigned to LHS)
+ into list of static initilizer statementes (passed in ARG).
+ If statements list becomes too big, emit checker constructor
+ and start the new one. */
+static void
+chkp_add_modification_to_stmt_list (tree lhs,
+ tree rhs,
+ void *arg)
+{
+ struct chkp_ctor_stmt_list *stmts = (struct chkp_ctor_stmt_list *)arg;
+ tree modify;
+
+ if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
+ rhs = build1 (CONVERT_EXPR, TREE_TYPE (lhs), rhs);
+
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);
+ append_to_statement_list (modify, &stmts->stmts);
+
+ stmts->avail--;
+}
+
/* Build and return ADDR_EXPR for specified object OBJ. */
static tree
chkp_build_addr_expr (tree obj)
@@ -880,6 +948,64 @@ chkp_build_addr_expr (tree obj)
: build_fold_addr_expr (obj);
}
+/* Helper function for chkp_finish_file.
+ Initialize bound variable BND_VAR with bounds of variable
+ VAR to statements list STMTS. If statements list becomes
+ too big, emit checker constructor and start the new one. */
+static void
+chkp_output_static_bounds (tree bnd_var, tree var,
+ struct chkp_ctor_stmt_list *stmts)
+{
+ tree lb, ub, size;
+
+ if (TREE_CODE (var) == STRING_CST)
+ {
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var) - 1);
+ }
+ else if (DECL_SIZE (var)
+ && !chkp_variable_size_type (TREE_TYPE (var)))
+ {
+ /* Compute bounds using statically known size. */
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ size = size_binop (MINUS_EXPR, DECL_SIZE_UNIT (var), size_one_node);
+ }
+ else
+ {
+ /* Compute bounds using dynamic size. */
+ tree call;
+
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ call = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl)),
+ chkp_sizeof_fndecl);
+ size = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl)),
+ call, 1, var);
+
+ if (flag_chkp_zero_dynamic_size_as_infinite)
+ {
+ tree max_size, cond;
+
+ max_size = build2 (MINUS_EXPR, size_type_node, size_zero_node, lb);
+ cond = build2 (NE_EXPR, boolean_type_node, size, size_zero_node);
+ size = build3 (COND_EXPR, size_type_node, cond, size, max_size);
+ }
+
+ size = size_binop (MINUS_EXPR, size, size_one_node);
+ }
+
+ ub = size_binop (PLUS_EXPR, lb, size);
+ stmts->avail -= targetm.chkp_initialize_bounds (bnd_var, lb, ub,
+ &stmts->stmts);
+ if (stmts->avail <= 0)
+ {
+ cgraph_build_static_cdtor ('B', stmts->stmts,
+ MAX_RESERVED_INIT_PRIORITY + 2);
+ stmts->avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts->stmts = NULL;
+ }
+}
+
/* Return entry block to be used for checker initilization code.
Create new block if required. */
static basic_block
@@ -3402,6 +3528,74 @@ chkp_copy_bounds_for_elem (tree lhs, tree rhs, void *arg)
chkp_build_bndstx (addr, rhs, bounds, iter);
}
+/* Emit static bound initilizers and size vars. */
+void
+chkp_finish_file (void)
+{
+ struct varpool_node *node;
+ struct chkp_ctor_stmt_list stmts;
+
+ if (seen_error ())
+ return;
+
+ /* Iterate through varpool and generate bounds initialization
+ constructors for all statically initialized pointers. */
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ FOR_EACH_VARIABLE (node)
+ /* Check that var is actually emitted and we need and may initialize
+ its bounds. */
+ if (node->need_bounds_init
+ && !POINTER_BOUNDS_P (node->decl)
+ && DECL_RTL (node->decl)
+ && MEM_P (DECL_RTL (node->decl))
+ && TREE_ASM_WRITTEN (node->decl))
+ {
+ chkp_walk_pointer_assignments (node->decl,
+ DECL_INITIAL (node->decl),
+ &stmts,
+ chkp_add_modification_to_stmt_list);
+
+ if (stmts.avail <= 0)
+ {
+ cgraph_build_static_cdtor ('P', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 3);
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ }
+ }
+
+ if (stmts.stmts)
+ cgraph_build_static_cdtor ('P', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 3);
+
+ /* Iterate through varpool and generate bounds initialization
+ constructors for all static bounds vars. */
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ FOR_EACH_VARIABLE (node)
+ if (node->need_bounds_init
+ && POINTER_BOUNDS_P (node->decl)
+ && TREE_ASM_WRITTEN (node->decl))
+ {
+ tree bnd = node->decl;
+ tree var;
+
+ gcc_assert (DECL_INITIAL (bnd)
+ && TREE_CODE (DECL_INITIAL (bnd)) == ADDR_EXPR);
+
+ var = TREE_OPERAND (DECL_INITIAL (bnd), 0);
+ chkp_output_static_bounds (bnd, var, &stmts);
+ }
+
+ if (stmts.stmts)
+ cgraph_build_static_cdtor ('B', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 2);
+
+ delete chkp_static_var_bounds;
+ delete chkp_bounds_map;
+}
+
/* An instrumentation function which is called for each statement
having memory access we want to instrument. It inserts check
code and bounds copy code.
@@ -3689,7 +3883,9 @@ chkp_replace_function_pointers (gimple_stmt_iterator *gsi)
}
/* This function instruments all statements working with memory,
- calls and rets. */
+ calls and rets.
+
+ It also removes excess statements from static initializers. */
static void
chkp_instrument_function (void)
{
@@ -3754,6 +3950,18 @@ chkp_instrument_function (void)
}
gsi_next (&i);
+
+ /* We do not need any actual pointer stores in checker
+ static initializer. */
+ if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl))
+ && gimple_code (s) == GIMPLE_ASSIGN
+ && gimple_store_p (s))
+ {
+ gimple_stmt_iterator del_iter = gsi_for_stmt (s);
+ gsi_remove (&del_iter, true);
+ unlink_stmt_vdef (s);
+ release_defs(s);
+ }
}
bb = next;
}
diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h
index 0357658..81306ba 100644
--- a/gcc/tree-chkp.h
+++ b/gcc/tree-chkp.h
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see
extern tree chkp_get_bounds (tree node);
extern void chkp_set_bounds (tree node, tree val);
+extern bool chkp_register_var_initializer (tree var);
+extern void chkp_finish_file (void);
extern bool chkp_type_has_pointer (const_tree type);
extern unsigned chkp_type_bounds_count (const_tree type);
extern tree chkp_make_bounds_for_struct_addr (tree ptr);
This patch introduces functions to handle static pointers and static bounds.
Thanks,
Ilya
--
2014-10-08 Ilya Enkovich <***@intel.com>
* tree-chkp.c (MAX_STMTS_IN_STATIC_CHKP_CTOR): New.
(chkp_ctor_stmt_list): New.
(chkp_register_var_initializer): New.
(chkp_add_modification_to_stmt_list): New.
(chkp_output_static_bounds): New.
(chkp_finish_file): New.
(chkp_instrument_function): Remove useless statements
from static bounds constructors.
* tree-chkp.h (chkp_register_var_initializer): New.
(chkp_finish_file): New.
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index b424af8..4b5a773 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -394,6 +394,27 @@ static bool in_chkp_pass;
#define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
#define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds"
+/* Static checker constructors may become very large and their
+ compilation with optimization may take too much time.
+ Therefore we put a limit to number of statements in one
+ construcor. Tests with 100 000 statically initialized
+ pointers showed following compilation times on Sandy Bridge
+ server (used -O2):
+ limit 100 => ~18 sec.
+ limit 300 => ~22 sec.
+ limit 1000 => ~30 sec.
+ limit 3000 => ~49 sec.
+ limit 5000 => ~55 sec.
+ limit 10000 => ~76 sec.
+ limit 100000 => ~532 sec. */
+#define MAX_STMTS_IN_STATIC_CHKP_CTOR (optimize > 0 ? 5000 : 100000)
+
+struct chkp_ctor_stmt_list
+{
+ tree stmts;
+ int avail;
+};
+
/* Return 1 if function FNDECL is instrumented by Pointer
Bounds Checker. */
bool
@@ -871,6 +892,53 @@ chkp_set_bounds (tree node, tree val)
chkp_bounds_map->put (node, val);
}
+/* Check if statically initialized variable VAR require
+ static bounds initilization. If VAR is added into
+ bounds initlization list then 1 is returned. Otherwise
+ return 0. */
+extern bool
+chkp_register_var_initializer (tree var)
+{
+ if (!flag_check_pointer_bounds)
+ return false;
+
+ gcc_assert (TREE_CODE (var) == VAR_DECL);
+ gcc_assert (DECL_INITIAL (var)
+ && DECL_INITIAL (var) != error_mark_node);
+
+ if (TREE_STATIC (var)
+ && chkp_type_has_pointer (TREE_TYPE (var)))
+ {
+ varpool_node::get_create (var)->need_bounds_init = 1;
+ return true;
+ }
+
+ return false;
+}
+
+/* Helper function for chkp_finish_file.
+
+ Add new modification statement (RHS is assigned to LHS)
+ into list of static initilizer statementes (passed in ARG).
+ If statements list becomes too big, emit checker constructor
+ and start the new one. */
+static void
+chkp_add_modification_to_stmt_list (tree lhs,
+ tree rhs,
+ void *arg)
+{
+ struct chkp_ctor_stmt_list *stmts = (struct chkp_ctor_stmt_list *)arg;
+ tree modify;
+
+ if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
+ rhs = build1 (CONVERT_EXPR, TREE_TYPE (lhs), rhs);
+
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);
+ append_to_statement_list (modify, &stmts->stmts);
+
+ stmts->avail--;
+}
+
/* Build and return ADDR_EXPR for specified object OBJ. */
static tree
chkp_build_addr_expr (tree obj)
@@ -880,6 +948,64 @@ chkp_build_addr_expr (tree obj)
: build_fold_addr_expr (obj);
}
+/* Helper function for chkp_finish_file.
+ Initialize bound variable BND_VAR with bounds of variable
+ VAR to statements list STMTS. If statements list becomes
+ too big, emit checker constructor and start the new one. */
+static void
+chkp_output_static_bounds (tree bnd_var, tree var,
+ struct chkp_ctor_stmt_list *stmts)
+{
+ tree lb, ub, size;
+
+ if (TREE_CODE (var) == STRING_CST)
+ {
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var) - 1);
+ }
+ else if (DECL_SIZE (var)
+ && !chkp_variable_size_type (TREE_TYPE (var)))
+ {
+ /* Compute bounds using statically known size. */
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ size = size_binop (MINUS_EXPR, DECL_SIZE_UNIT (var), size_one_node);
+ }
+ else
+ {
+ /* Compute bounds using dynamic size. */
+ tree call;
+
+ lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
+ call = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl)),
+ chkp_sizeof_fndecl);
+ size = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl)),
+ call, 1, var);
+
+ if (flag_chkp_zero_dynamic_size_as_infinite)
+ {
+ tree max_size, cond;
+
+ max_size = build2 (MINUS_EXPR, size_type_node, size_zero_node, lb);
+ cond = build2 (NE_EXPR, boolean_type_node, size, size_zero_node);
+ size = build3 (COND_EXPR, size_type_node, cond, size, max_size);
+ }
+
+ size = size_binop (MINUS_EXPR, size, size_one_node);
+ }
+
+ ub = size_binop (PLUS_EXPR, lb, size);
+ stmts->avail -= targetm.chkp_initialize_bounds (bnd_var, lb, ub,
+ &stmts->stmts);
+ if (stmts->avail <= 0)
+ {
+ cgraph_build_static_cdtor ('B', stmts->stmts,
+ MAX_RESERVED_INIT_PRIORITY + 2);
+ stmts->avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts->stmts = NULL;
+ }
+}
+
/* Return entry block to be used for checker initilization code.
Create new block if required. */
static basic_block
@@ -3402,6 +3528,74 @@ chkp_copy_bounds_for_elem (tree lhs, tree rhs, void *arg)
chkp_build_bndstx (addr, rhs, bounds, iter);
}
+/* Emit static bound initilizers and size vars. */
+void
+chkp_finish_file (void)
+{
+ struct varpool_node *node;
+ struct chkp_ctor_stmt_list stmts;
+
+ if (seen_error ())
+ return;
+
+ /* Iterate through varpool and generate bounds initialization
+ constructors for all statically initialized pointers. */
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ FOR_EACH_VARIABLE (node)
+ /* Check that var is actually emitted and we need and may initialize
+ its bounds. */
+ if (node->need_bounds_init
+ && !POINTER_BOUNDS_P (node->decl)
+ && DECL_RTL (node->decl)
+ && MEM_P (DECL_RTL (node->decl))
+ && TREE_ASM_WRITTEN (node->decl))
+ {
+ chkp_walk_pointer_assignments (node->decl,
+ DECL_INITIAL (node->decl),
+ &stmts,
+ chkp_add_modification_to_stmt_list);
+
+ if (stmts.avail <= 0)
+ {
+ cgraph_build_static_cdtor ('P', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 3);
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ }
+ }
+
+ if (stmts.stmts)
+ cgraph_build_static_cdtor ('P', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 3);
+
+ /* Iterate through varpool and generate bounds initialization
+ constructors for all static bounds vars. */
+ stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
+ stmts.stmts = NULL;
+ FOR_EACH_VARIABLE (node)
+ if (node->need_bounds_init
+ && POINTER_BOUNDS_P (node->decl)
+ && TREE_ASM_WRITTEN (node->decl))
+ {
+ tree bnd = node->decl;
+ tree var;
+
+ gcc_assert (DECL_INITIAL (bnd)
+ && TREE_CODE (DECL_INITIAL (bnd)) == ADDR_EXPR);
+
+ var = TREE_OPERAND (DECL_INITIAL (bnd), 0);
+ chkp_output_static_bounds (bnd, var, &stmts);
+ }
+
+ if (stmts.stmts)
+ cgraph_build_static_cdtor ('B', stmts.stmts,
+ MAX_RESERVED_INIT_PRIORITY + 2);
+
+ delete chkp_static_var_bounds;
+ delete chkp_bounds_map;
+}
+
/* An instrumentation function which is called for each statement
having memory access we want to instrument. It inserts check
code and bounds copy code.
@@ -3689,7 +3883,9 @@ chkp_replace_function_pointers (gimple_stmt_iterator *gsi)
}
/* This function instruments all statements working with memory,
- calls and rets. */
+ calls and rets.
+
+ It also removes excess statements from static initializers. */
static void
chkp_instrument_function (void)
{
@@ -3754,6 +3950,18 @@ chkp_instrument_function (void)
}
gsi_next (&i);
+
+ /* We do not need any actual pointer stores in checker
+ static initializer. */
+ if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl))
+ && gimple_code (s) == GIMPLE_ASSIGN
+ && gimple_store_p (s))
+ {
+ gimple_stmt_iterator del_iter = gsi_for_stmt (s);
+ gsi_remove (&del_iter, true);
+ unlink_stmt_vdef (s);
+ release_defs(s);
+ }
}
bb = next;
}
diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h
index 0357658..81306ba 100644
--- a/gcc/tree-chkp.h
+++ b/gcc/tree-chkp.h
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see
extern tree chkp_get_bounds (tree node);
extern void chkp_set_bounds (tree node, tree val);
+extern bool chkp_register_var_initializer (tree var);
+extern void chkp_finish_file (void);
extern bool chkp_type_has_pointer (const_tree type);
extern unsigned chkp_type_bounds_count (const_tree type);
extern tree chkp_make_bounds_for_struct_addr (tree ptr);