From patchwork Thu Nov 6 12:32:14 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Enkovich X-Patchwork-Id: 407432 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3FA861400A6 for ; Thu, 6 Nov 2014 23:32:34 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=RLZ4oWx3vWFGGk9717Khi3bc40aOYlvM7Y9eI4yFc/7sXHFz9hu5N IWW5xSWiI94Q81VizVehjAbpeLgJ13M9ajgQpGjU/PGDZiWmWBuJiRgCsMcOYcqI 8qkmdN9v5zOD4EekzpiDXDLID45RkUCAQNgCeVZmg0LTBJFsxilvTo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=QIr8DntqxsIEipdqXnTtPKi+Tvg=; b=Kqhg6phFLdu0QZCQahv4 4lMrfgaPMIBurpU6jUBRLjZSa/BJd4MvAc+ZNhHlJgOeuJGkKHwaz1YGWOQPi0Io FY8Srq325t3+bM6ga2temiHniEr+wPRTXg/WH9PlGXtZcRvGCGIQugpDSDKwD1bN CSW0exEvXMIo1NqpgTDk+QQ= Received: (qmail 29767 invoked by alias); 6 Nov 2014 12:32:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 29752 invoked by uid 89); 6 Nov 2014 12:32:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pa0-f52.google.com Received: from mail-pa0-f52.google.com (HELO mail-pa0-f52.google.com) (209.85.220.52) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 06 Nov 2014 12:32:23 +0000 Received: by mail-pa0-f52.google.com with SMTP id fa1so1164783pad.39 for ; Thu, 06 Nov 2014 04:32:21 -0800 (PST) X-Received: by 10.68.138.137 with SMTP id qq9mr3952495pbb.73.1415277141107; Thu, 06 Nov 2014 04:32:21 -0800 (PST) Received: from msticlxl57.ims.intel.com (fmdmzpr01-ext.fm.intel.com. [192.55.54.36]) by mx.google.com with ESMTPSA id nu9sm5800526pbb.81.2014.11.06.04.32.18 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 06 Nov 2014 04:32:20 -0800 (PST) Date: Thu, 6 Nov 2014 15:32:14 +0300 From: Ilya Enkovich To: gcc-patches@gcc.gnu.org Subject: [PATCH, Pointer Bounds Checker, Builtins instrumentation 4/5] Use alternative instrumented string function calls Message-ID: <20141106123214.GC44122@msticlxl57.ims.intel.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi, This patch adds instrumentation optimization to use string function with no checks and/or bounds copy. Thanks, Ilya --- gcc/ 2014-11-06 Ilya Enkovich * 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/ 2014-11-06 Ilya Enkovich * 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. 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 index 0000000..c005041 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-1.c @@ -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 index 0000000..9b3c15f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-10.c @@ -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 index 0000000..7ef079c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-11.c @@ -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 index 0000000..94e936d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-12.c @@ -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 index 0000000..f6d38c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-13.c @@ -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 index 0000000..a7f43cb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-14.c @@ -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 index 0000000..041e885 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-15.c @@ -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 index 0000000..4b26d58 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-16.c @@ -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 index 0000000..c56656e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-2.c @@ -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 index 0000000..a91f007 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-3.c @@ -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 index 0000000..4ee2390 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-4.c @@ -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 index 0000000..8d08ee6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-5.c @@ -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 index 0000000..92f187e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-6.c @@ -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 index 0000000..eb1e61c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-7.c @@ -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 index 0000000..8c3b15d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-8.c @@ -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 index 0000000..da54c9c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/chkp-stropt-9.c @@ -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); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index ee10bc6..22b005a 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -8190,6 +8190,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. */ diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index 1e23fac..bc5967b 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -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 */ diff --git a/gcc/tree-chkp-opt.c b/gcc/tree-chkp-opt.c index 383c66f..ff390d7 100644 --- a/gcc/tree-chkp-opt.c +++ b/gcc/tree-chkp-opt.c @@ -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 ();