tree-chkp-opt.c (chkp_get_nobnd_fndecl): New.
authorIlya Enkovich <ilya.enkovich@intel.com>
Mon, 17 Nov 2014 13:52:37 +0000 (13:52 +0000)
committerIlya Enkovich <ienkovich@gcc.gnu.org>
Mon, 17 Nov 2014 13:52:37 +0000 (13:52 +0000)
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

21 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/chkp-stropt-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-10.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-11.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-12.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-13.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-14.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-15.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-16.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/chkp-stropt-9.c [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-cfg.h
gcc/tree-chkp-opt.c

index 123166c95629c6ce32bfe9f6964bca6381aee20b..a67defd5bdaf8c6dc16f9e98863b8ffbca990343 100644 (file)
@@ -1,3 +1,12 @@
+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
index 2a5f8fc47ad589dac3b2cc879c56b6ff05005afe..2701c114a4e69a9e33b83b53b6bbaf3386dce015 100644 (file)
@@ -1,3 +1,22 @@
+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
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-1.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-1.c
new file mode 100644 (file)
index 0000000..c005041
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-10.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-10.c
new file mode 100644 (file)
index 0000000..9b3c15f
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-11.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-11.c
new file mode 100644 (file)
index 0000000..7ef079c
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-12.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-12.c
new file mode 100644 (file)
index 0000000..94e936d
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-13.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-13.c
new file mode 100644 (file)
index 0000000..f6d38c8
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-14.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-14.c
new file mode 100644 (file)
index 0000000..a7f43cb
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-15.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-15.c
new file mode 100644 (file)
index 0000000..041e885
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-16.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-16.c
new file mode 100644 (file)
index 0000000..4b26d58
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-2.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-2.c
new file mode 100644 (file)
index 0000000..c56656e
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-3.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-3.c
new file mode 100644 (file)
index 0000000..a91f007
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-4.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-4.c
new file mode 100644 (file)
index 0000000..4ee2390
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-5.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-5.c
new file mode 100644 (file)
index 0000000..8d08ee6
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-6.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-6.c
new file mode 100644 (file)
index 0000000..92f187e
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-7.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-7.c
new file mode 100644 (file)
index 0000000..eb1e61c
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-8.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-8.c
new file mode 100644 (file)
index 0000000..8c3b15d
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
diff --git a/gcc/testsuite/gcc.target/i386/chkp-stropt-9.c b/gcc/testsuite/gcc.target/i386/chkp-stropt-9.c
new file mode 100644 (file)
index 0000000..da54c9c
--- /dev/null
@@ -0,0 +1,12 @@
+/* { 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);
+}
index ae7734c5c6a55d667f5b3254de2a1357abff7dc4..9dd8961cb8f9421fe1ef7e4710835506c5c0cd55 100644 (file)
@@ -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.  */
 
index 1e23fac923d4399c63a09dcb487568fbd1230f73..bc5967be0bc276d01d0dacd81a617702f265d869 100644 (file)
@@ -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  */
index 383c66fcaa5e917a8cf8fe0f5ca20c7e5e926cf3..ff390d7bb3ddc0a9cc2d9660d502a09479519d04 100644 (file)
@@ -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 ();