Commit e4727812 by Ilya Enkovich Committed by Ilya Enkovich

tree-chkp-opt.c (chkp_get_nobnd_fndecl): New.

gcc/

	* tree-chkp-opt.c (chkp_get_nobnd_fndecl): New.
	(chkp_get_nochk_fndecl): New.
	(chkp_optimize_string_function_calls): New.
	(chkp_opt_execute): Call chkp_optimize_string_function_calls.
	* tree-cfg.h (insert_cond_bb): New.
	* tree-cfg.c (insert_cond_bb): New.

gcc/testsuite/

	* gcc.target/i386/chkp-stropt-1.c: New.
	* gcc.target/i386/chkp-stropt-2.c: New.
	* gcc.target/i386/chkp-stropt-3.c: New.
	* gcc.target/i386/chkp-stropt-4.c: New.
	* gcc.target/i386/chkp-stropt-5.c: New.
	* gcc.target/i386/chkp-stropt-6.c: New.
	* gcc.target/i386/chkp-stropt-7.c: New.
	* gcc.target/i386/chkp-stropt-8.c: New.
	* gcc.target/i386/chkp-stropt-9.c: New.
	* gcc.target/i386/chkp-stropt-10.c: New.
	* gcc.target/i386/chkp-stropt-11.c: New.
	* gcc.target/i386/chkp-stropt-12.c: New.
	* gcc.target/i386/chkp-stropt-13.c: New.
	* gcc.target/i386/chkp-stropt-14.c: New.
	* gcc.target/i386/chkp-stropt-15.c: New.
	* gcc.target/i386/chkp-stropt-16.c: New.

From-SVN: r217656
parent edcf72f3
2014-11-17 Ilya Enkovich <ilya.enkovich@intel.com>
* tree-chkp-opt.c (chkp_get_nobnd_fndecl): New.
(chkp_get_nochk_fndecl): New.
(chkp_optimize_string_function_calls): New.
(chkp_opt_execute): Call chkp_optimize_string_function_calls.
* tree-cfg.h (insert_cond_bb): New.
* tree-cfg.c (insert_cond_bb): New.
2014-11-17 Ilya Enkovich <ilya.enkovich@intel.com>
* tree-core.h (built_in_class): Add builtin codes to be used
by Pointer Bounds Checker for instrumented builtin functions.
* tree-streamer-in.c: Include ipa-chkp.h.
2014-11-17 Ilya Enkovich <ilya.enkovich@intel.com>
* gcc.target/i386/chkp-stropt-1.c: New.
* gcc.target/i386/chkp-stropt-2.c: New.
* gcc.target/i386/chkp-stropt-3.c: New.
* gcc.target/i386/chkp-stropt-4.c: New.
* gcc.target/i386/chkp-stropt-5.c: New.
* gcc.target/i386/chkp-stropt-6.c: New.
* gcc.target/i386/chkp-stropt-7.c: New.
* gcc.target/i386/chkp-stropt-8.c: New.
* gcc.target/i386/chkp-stropt-9.c: New.
* gcc.target/i386/chkp-stropt-10.c: New.
* gcc.target/i386/chkp-stropt-11.c: New.
* gcc.target/i386/chkp-stropt-12.c: New.
* gcc.target/i386/chkp-stropt-13.c: New.
* gcc.target/i386/chkp-stropt-14.c: New.
* gcc.target/i386/chkp-stropt-15.c: New.
* gcc.target/i386/chkp-stropt-16.c: New.
2014-11-17 H.J. Lu <hongjiu.lu@intel.com>
* g++.dg/ipa/pr63894.C (new): Replace unsigned long with
......
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions" } */
/* { dg-final { scan-tree-dump "memcpy_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump-not "memset_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (void *buf1, int c, size_t len)
{
memset (buf1, c, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump-not "memmove_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (void *buf1, void *buf2, size_t len)
{
memmove (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions -D_GNU_SOURCE" } */
/* { dg-final { scan-tree-dump-not "mempcpy_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (void *buf1, void *buf2, size_t len)
{
mempcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memcpy_nobnd_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memset_nobnd_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int c, size_t len)
{
memset (buf1, c, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memmove_nobnd_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memmove (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions -fchkp-use-fast-string-functions -D_GNU_SOURCE" } */
/* { dg-final { scan-tree-dump "mempcpy_nobnd_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
mempcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions" } */
/* { dg-final { scan-tree-dump "memset_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int c, size_t len)
{
memset (buf1, c, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions" } */
/* { dg-final { scan-tree-dump "memmove_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memmove (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-nochk-string-functions -D_GNU_SOURCE" } */
/* { dg-final { scan-tree-dump "mempcpy_nochk" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
mempcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memcpy_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memset_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int c, size_t len)
{
memset (buf1, c, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump "memmove_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
memmove (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions -D_GNU_SOURCE" } */
/* { dg-final { scan-tree-dump "mempcpy_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (int *buf1, int *buf2, size_t len)
{
mempcpy (buf1, buf2, len);
}
/* { dg-do compile } */
/* { dg-require-effective-target mpx } */
/* { dg-options "-fcheck-pointer-bounds -mmpx -O2 -fdump-tree-chkpopt -fchkp-use-fast-string-functions" } */
/* { dg-final { scan-tree-dump-not "memcpy_nobnd" "chkpopt" } } */
/* { dg-final { cleanup-tree-dump "chkpopt" } } */
#include "string.h"
void test (void *buf1, void *buf2, size_t len)
{
memcpy (buf1, buf2, len);
}
......@@ -8178,6 +8178,46 @@ make_pass_split_crit_edges (gcc::context *ctxt)
}
/* Insert COND expression which is GIMPLE_COND after STMT
in basic block BB with appropriate basic block split
and creation of a new conditionally executed basic block.
Return created basic block. */
basic_block
insert_cond_bb (basic_block bb, gimple stmt, gimple cond)
{
edge fall = split_block (bb, stmt);
gimple_stmt_iterator iter = gsi_last_bb (bb);
basic_block new_bb;
/* Insert cond statement. */
gcc_assert (gimple_code (cond) == GIMPLE_COND);
if (gsi_end_p (iter))
gsi_insert_before (&iter, cond, GSI_CONTINUE_LINKING);
else
gsi_insert_after (&iter, cond, GSI_CONTINUE_LINKING);
/* Create conditionally executed block. */
new_bb = create_empty_bb (bb);
make_edge (bb, new_bb, EDGE_TRUE_VALUE);
make_single_succ_edge (new_bb, fall->dest, EDGE_FALLTHRU);
/* Fix edge for split bb. */
fall->flags = EDGE_FALSE_VALUE;
/* Update dominance info. */
if (dom_info_available_p (CDI_DOMINATORS))
{
set_immediate_dominator (CDI_DOMINATORS, new_bb, bb);
set_immediate_dominator (CDI_DOMINATORS, fall->dest, bb);
}
/* Update loop info. */
if (current_loops)
add_bb_to_loop (new_bb, bb->loop_father);
return new_bb;
}
/* Build a ternary operation and gimplify it. Emit code before GSI.
Return the gimple_val holding the result. */
......
......@@ -100,5 +100,6 @@ extern tree gimplify_build1 (gimple_stmt_iterator *, enum tree_code,
extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
extern unsigned int execute_fixup_cfg (void);
extern unsigned int split_critical_edges (void);
extern basic_block insert_cond_bb (basic_block, gimple, gimple);
#endif /* _TREE_CFG_H */
......@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify-me.h"
#include "expr.h"
#include "tree-chkp.h"
#include "ipa-chkp.h"
#include "diagnostic.h"
enum check_type
......@@ -845,6 +846,265 @@ chkp_remove_constant_checks (void)
}
}
/* Return fast version of string function FNCODE. */
static tree
chkp_get_nobnd_fndecl (enum built_in_function fncode)
{
/* Check if we are allowed to use fast string functions. */
if (!flag_chkp_use_fast_string_functions)
return NULL_TREE;
tree fndecl = NULL_TREE;
switch (fncode)
{
case BUILT_IN_MEMCPY_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
break;
case BUILT_IN_MEMPCPY_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
break;
case BUILT_IN_MEMMOVE_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
break;
case BUILT_IN_MEMSET_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
break;
case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
break;
default:
break;
}
if (fndecl)
fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
return fndecl;
}
/* Return no-check version of string function FNCODE. */
static tree
chkp_get_nochk_fndecl (enum built_in_function fncode)
{
/* Check if we are allowed to use fast string functions. */
if (!flag_chkp_use_nochk_string_functions)
return NULL_TREE;
tree fndecl = NULL_TREE;
switch (fncode)
{
case BUILT_IN_MEMCPY_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
break;
case BUILT_IN_MEMPCPY_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
break;
case BUILT_IN_MEMMOVE_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
break;
case BUILT_IN_MEMSET_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
break;
case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
break;
case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
break;
default:
break;
}
if (fndecl)
fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
return fndecl;
}
/* Find memcpy, mempcpy, memmove and memset calls, perform
checks before call and then call no_chk version of
functions. We do it on O2 to enable inlining of these
functions during expand.
Also try to find memcpy, mempcpy, memmove and memset calls
which are known to not write pointers to memory and use
faster function versions for them. */
static void
chkp_optimize_string_function_calls (void)
{
basic_block bb;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Searching for replaceable string function calls...\n");
FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator i;
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
gimple stmt = gsi_stmt (i);
tree fndecl;
if (gimple_code (stmt) != GIMPLE_CALL
|| !gimple_call_with_bounds_p (stmt))
continue;
fndecl = gimple_call_fndecl (stmt);
if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
continue;
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
{
tree dst = gimple_call_arg (stmt, 0);
tree dst_bnd = gimple_call_arg (stmt, 1);
bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
tree fndecl_nochk;
gimple_stmt_iterator j;
basic_block check_bb;
address_t size_val;
int sign;
bool known;
/* We may replace call with corresponding __chkp_*_nobnd
call in case destination pointer base type is not
void or pointer. */
if (POINTER_TYPE_P (TREE_TYPE (dst))
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
&& !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
{
tree fndecl_nobnd
= chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
if (fndecl_nobnd)
fndecl = fndecl_nobnd;
}
fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
if (fndecl_nochk)
fndecl = fndecl_nochk;
if (fndecl != gimple_call_fndecl (stmt))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Replacing call: ");
print_gimple_stmt (dump_file, stmt, 0,
TDF_VOPS|TDF_MEMSYMS);
}
gimple_call_set_fndecl (stmt, fndecl);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "With a new call: ");
print_gimple_stmt (dump_file, stmt, 0,
TDF_VOPS|TDF_MEMSYMS);
}
}
/* If there is no nochk version of function then
do nothing. Otherwise insert checks before
the call. */
if (!fndecl_nochk)
continue;
/* If size passed to call is known and > 0
then we may insert checks unconditionally. */
size_val.pol.create (0);
chkp_collect_value (size, size_val);
known = chkp_is_constant_addr (size_val, &sign);
size_val.pol.release ();
/* If we are not sure size is not zero then we have
to perform runtime check for size and perform
checks only when size is not zero. */
if (!known)
{
gimple check = gimple_build_cond (NE_EXPR,
size,
size_zero_node,
NULL_TREE,
NULL_TREE);
/* Split block before string function call. */
gsi_prev (&i);
check_bb = insert_cond_bb (bb, gsi_stmt (i), check);
/* Set position for checks. */
j = gsi_last_bb (check_bb);
/* The block was splitted and therefore we
need to set iterator to its end. */
i = gsi_last_bb (bb);
}
/* If size is known to be zero then no checks
should be performed. */
else if (!sign)
continue;
else
j = i;
size = size_binop (MINUS_EXPR, size, size_one_node);
if (!is_memset)
{
tree src = gimple_call_arg (stmt, 2);
tree src_bnd = gimple_call_arg (stmt, 3);
chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
src_bnd, j, gimple_location (stmt),
integer_zero_node);
}
chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
dst_bnd, j, gimple_location (stmt),
integer_one_node);
}
}
}
}
/* Intrumentation pass inserts most of bounds creation code
in the header of the function. We want to move bounds
creation closer to bounds usage to reduce bounds lifetime.
......@@ -1026,6 +1286,10 @@ chkp_opt_execute (void)
{
chkp_opt_init();
/* This optimization may introduce new checks
and thus we put it before checks search. */
chkp_optimize_string_function_calls ();
chkp_gather_checks_info ();
chkp_remove_excess_intersections ();
......
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