From patchwork Wed Oct 8 18:55:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Enkovich X-Patchwork-Id: 397686 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 90FCC1400D6 for ; Thu, 9 Oct 2014 05:55:24 +1100 (EST) 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:cc:subject:message-id:mime-version:content-type; q=dns; s=default; b=vSdVK2/MHJs9RcgmX+Gb3cort//sQmlH8uVAbG+Mj6fsDKy7/S Yjr6dPCRYoO/C48Zyf7fCJD1SR4MAiKuU2CTXThSCGh1FCDRAXsxVk5MjKLU00xr BEssN2kMofc91F6GhUIR1TuJCYPpOTXFvtnLeTlsecEaZdMTD/bRSDJfk= 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:cc:subject:message-id:mime-version:content-type; s= default; bh=Mc8+xxQJ+efqdjXmhyHTwOUUHgE=; b=rSgvdpA1l+d8wVf21Sb2 GHibH85W/SG2Rsp1PdHt5ewcjxt2pl/zWdCaL1vrbRfprgbRyc9rejO73sbvvYWJ es+jFVqen5xUO3yHZyMuVw40UELt9ZH0v5cHogY6BLdh/qGfEVVSNNABxiv1KLSL Xvzos/Hfu/EOLRNw3ZNHadQ= Received: (qmail 22116 invoked by alias); 8 Oct 2014 18:55:17 -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 22107 invoked by uid 89); 8 Oct 2014 18:55:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.0 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pd0-f182.google.com Received: from mail-pd0-f182.google.com (HELO mail-pd0-f182.google.com) (209.85.192.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 08 Oct 2014 18:55:14 +0000 Received: by mail-pd0-f182.google.com with SMTP id y10so7232542pdj.41 for ; Wed, 08 Oct 2014 11:55:12 -0700 (PDT) X-Received: by 10.66.226.203 with SMTP id ru11mr13096037pac.74.1412794512140; Wed, 08 Oct 2014 11:55:12 -0700 (PDT) Received: from msticlxl57.ims.intel.com (fmdmzpr02-ext.fm.intel.com. [192.55.55.37]) by mx.google.com with ESMTPSA id ra4sm685922pab.33.2014.10.08.11.55.09 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 08 Oct 2014 11:55:11 -0700 (PDT) Date: Wed, 8 Oct 2014 22:55:06 +0400 From: Ilya Enkovich To: gcc-patches@gcc.gnu.org Cc: Jeff Law Subject: [PATCH, Pointer Bounds Checker 14/x] Passes [2/n] IPA passes Message-ID: <20141008185506.GB13454@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 introduces two IPA passes used by Pointer Bounds Checker. One pass creates clones for instrumentation. The other one transforms unneeded functions into thunks. Thanks, Ilya --- 2014-10-08 Ilya Enkovich * ipa-chkp.c: New. * ipa-chkp.h: New. * Makefile.in (OBJS): Add ipa-chkp.o. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 3113a9f..d8c8488 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1253,6 +1253,7 @@ OBJS = \ incpath.o \ init-regs.o \ internal-fn.o \ + ipa-chkp.o \ ipa-cp.o \ ipa-devirt.o \ ipa-split.o \ diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c new file mode 100644 index 0000000..f7ac713 --- /dev/null +++ b/gcc/ipa-chkp.c @@ -0,0 +1,622 @@ +/* Pointer Bounds Checker IPA passes. + Copyright (C) 2014 Free Software Foundation, Inc. + Contributed by Ilya Enkovich (ilya.enkovich@intel.com) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree-core.h" +#include "stor-layout.h" +#include "tree.h" +#include "tree-pass.h" +#include "stringpool.h" +#include "bitmap.h" +#include "gimple-expr.h" +#include "function.h" +#include "tree-chkp.h" +#include + +/* Pointer Bounds Checker has two IPA passes to support code instrumentation. + + In instrumented code each pointer is provided with bounds. For input + pointer parameters it means we also have bounds passed. For calls it + means we have additional bounds arguments for pointer arguments. + + To have all IPA optimizations working correctly we have to express + dataflow between passed and received bounds explicitly via additional + entries in function declaration arguments list and in function type. + Since we may have both instrumented and not instrumented code at the + same time, we cannot replace all original functions with their + instrumented variants. Therefore we create clones (versions) instead. + + Instrumentation clones creation is a separate IPA pass which is a part + of early local passes. Clones are created after SSA is built (because + instrumentation pass works on SSA) and before any transformations + which may change pointer flow and therefore lead to incorrect code + instrumentation (possibly causing false bounds check failures). + + Instrumentation clones have pointer bounds arguments added right after + pointer arguments. Clones have assembler name of the original + function with suffix added. New assembler name is in transparent + alias chain with the original name. Thus we expect all calls to the + original and instrumented functions look similar in assembler. + + During instrumentation versioning pass we create instrumented versions + of all function with body and also for all their aliases and thunks. + Clones for functions with no body are created on demand (usually + during call instrumentation). + + Original and instrumented function nodes are connected with IPA + reference IPA_REF_CHKP. It is mostly done to have reachability + analysis working correctly. We may have no references to the + instrumented function in the code but it still should be counted + as reachable if the original function is reachable. + + When original function bodies are not needed anymore we release + them and transform functions into a special kind of thunks. Each + thunk has a call edge to the instrumented version. These thunks + help to keep externally visible instrumented functions visible + when linker reolution files are used. Linker has no info about + connection between original and instrumented function and + therefore we may wrongly decide (due to difference in assember + names) that instrumented function version is local and can be + removed. */ + +#define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_" + +/* Build a clone of FNDECL with a modified name. */ + +static tree +chkp_build_instrumented_fndecl (tree fndecl) +{ + tree new_decl = copy_node (fndecl); + tree new_name; + std::string s; + + /* We want called_as_built_in recall instrumented calls + to instrumented built-in functions. Therefore use + DECL_NAME for cloning instead of DECL_ASSEMBLER_NAME. */ + s = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + s += ".chkp"; + DECL_NAME (new_decl) = get_identifier (s.c_str ()); + + /* References to the original and to the instrumented version + should look the same in the output assembly. And we cannot + use the same assembler name for the instrumented version + because it conflicts with decl merging algorithms in LTO. + Achieve the result by using transparent alias name for the + instrumented version. */ + s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); + s += ".chkp"; + new_name = get_identifier (s.c_str ()); + IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1; + TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl); + SET_DECL_ASSEMBLER_NAME (new_decl, new_name); + + /* For functions with body versioning will make a copy of arguments. + For functions with no body we need to do it here. */ + if (!gimple_has_body_p (fndecl)) + DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl)); + + /* We are going to modify attributes list and therefore should + make own copy. */ + DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl)); + + return new_decl; +} + + +/* Fix operands of attribute from ATTRS list named ATTR_NAME. + Integer operands are replaced with values according to + INDEXES map having LEN elements. For operands out of len + we just add DELTA. */ + +static void +chkp_map_attr_arg_indexes (tree attrs, const char *attr_name, + unsigned *indexes, int len, int delta) +{ + tree attr = lookup_attribute (attr_name, attrs); + tree op; + + if (!attr) + return; + + TREE_VALUE (attr) = copy_list (TREE_VALUE (attr)); + for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op)) + { + int idx; + + if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST) + continue; + + idx = TREE_INT_CST_LOW (TREE_VALUE (op)); + + /* If idx exceeds indexes length then we just + keep it at the same distance from the last + known arg. */ + if (idx > len) + idx += delta; + else + idx = indexes[idx - 1] + 1; + TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx); + } +} + +/* Make a copy of function type ORIG_TYPE adding pointer + bounds as additional arguments. */ + +tree +chkp_copy_function_type_adding_bounds (tree orig_type) +{ + tree type; + tree arg_type, attrs, t; + unsigned len = list_length (TYPE_ARG_TYPES (orig_type)); + unsigned *indexes = XALLOCAVEC (unsigned, len); + unsigned idx = 0, new_idx = 0; + + for (arg_type = TYPE_ARG_TYPES (orig_type); + arg_type; + arg_type = TREE_CHAIN (arg_type)) + if (TREE_VALUE (arg_type) == void_type_node) + continue; + else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type)) + || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)), + TREE_VALUE (arg_type), true) + || chkp_type_has_pointer (TREE_VALUE (arg_type))) + break; + + /* We may use original type if there are no bounds passed. */ + if (!arg_type) + return orig_type; + + type = copy_node (orig_type); + TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type)); + + for (arg_type = TYPE_ARG_TYPES (type); + arg_type; + arg_type = TREE_CHAIN (arg_type)) + { + indexes[idx++] = new_idx++; + + /* pass_by_reference returns 1 for void type, + so check for it first. */ + if (TREE_VALUE (arg_type) == void_type_node) + continue; + else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type)) + || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)), + TREE_VALUE (arg_type), true)) + { + tree new_type = build_tree_list (NULL_TREE, + pointer_bounds_type_node); + TREE_CHAIN (new_type) = TREE_CHAIN (arg_type); + TREE_CHAIN (arg_type) = new_type; + + arg_type = TREE_CHAIN (arg_type); + new_idx++; + } + else if (chkp_type_has_pointer (TREE_VALUE (arg_type))) + { + bitmap slots = chkp_find_bound_slots (TREE_VALUE (arg_type)); + bitmap_iterator bi; + unsigned bnd_no; + + EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi) + { + tree new_type = build_tree_list (NULL_TREE, + pointer_bounds_type_node); + TREE_CHAIN (new_type) = TREE_CHAIN (arg_type); + TREE_CHAIN (arg_type) = new_type; + + arg_type = TREE_CHAIN (arg_type); + new_idx++; + } + BITMAP_FREE (slots); + } + } + + /* If function type has attribute with arg indexes then + we have to copy it fixing attribute ops. Map for + fixing is in indexes array. */ + attrs = TYPE_ATTRIBUTES (type); + if (lookup_attribute ("nonnull", attrs) + || lookup_attribute ("format", attrs) + || lookup_attribute ("format_arg", attrs)) + { + int delta = new_idx - len; + attrs = copy_list (TYPE_ATTRIBUTES (type)); + chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta); + chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta); + chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta); + TYPE_ATTRIBUTES (type) = attrs; + } + + t = TYPE_MAIN_VARIANT (orig_type); + if (orig_type != t) + { + TYPE_MAIN_VARIANT (type) = t; + TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t); + TYPE_NEXT_VARIANT (t) = type; + } + else + { + TYPE_MAIN_VARIANT (type) = type; + TYPE_NEXT_VARIANT (type) = NULL; + } + + + return type; +} + +/* For given function FNDECL add bounds arguments to arguments + list. */ + +static void +chkp_add_bounds_params_to_function (tree fndecl) +{ + tree arg; + + for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg)) + if (BOUNDED_P (arg)) + { + std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX; + tree new_arg; + + if (DECL_NAME (arg)) + new_name += IDENTIFIER_POINTER (DECL_NAME (arg)); + else + { + char uid[25]; + snprintf (uid, 25, "D.%u", DECL_UID (arg)); + new_name += uid; + } + + new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL, + get_identifier (new_name.c_str ()), + pointer_bounds_type_node); + DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node; + DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg); + DECL_ARTIFICIAL (new_arg) = 1; + DECL_CHAIN (new_arg) = DECL_CHAIN (arg); + DECL_CHAIN (arg) = new_arg; + + arg = DECL_CHAIN (arg); + + } + else if (chkp_type_has_pointer (TREE_TYPE (arg))) + { + tree orig_arg = arg; + bitmap slots = chkp_find_bound_slots (TREE_TYPE (arg)); + bitmap_iterator bi; + unsigned bnd_no; + + EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi) + { + std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX; + tree new_arg; + char offs[25]; + + if (DECL_NAME (orig_arg)) + new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg)); + else + { + snprintf (offs, 25, "D.%u", DECL_UID (arg)); + new_name += offs; + } + snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT); + + new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg), + PARM_DECL, + get_identifier (new_name.c_str ()), + pointer_bounds_type_node); + DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node; + DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg); + DECL_ARTIFICIAL (new_arg) = 1; + DECL_CHAIN (new_arg) = DECL_CHAIN (arg); + DECL_CHAIN (arg) = new_arg; + + arg = DECL_CHAIN (arg); + } + BITMAP_FREE (slots); + } + + TREE_TYPE (fndecl) = + chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl)); +} + +/* Return clone created for instrumentation of NODE or NULL. */ + +cgraph_node * +chkp_maybe_create_clone (tree fndecl) +{ + cgraph_node *node = cgraph_node::get_create (fndecl); + cgraph_node *clone = node->instrumented_version; + + gcc_assert (!node->instrumentation_clone); + + if (!clone) + { + tree new_decl = chkp_build_instrumented_fndecl (fndecl); + struct cgraph_edge *e; + struct ipa_ref *ref; + int i; + + clone = node->create_version_clone (new_decl, vNULL, NULL); + clone->externally_visible = node->externally_visible; + clone->local = node->local; + clone->address_taken = node->address_taken; + clone->thunk = node->thunk; + clone->alias = node->alias; + clone->weakref = node->weakref; + clone->cpp_implicit_alias = node->cpp_implicit_alias; + clone->instrumented_version = node; + clone->orig_decl = fndecl; + clone->instrumentation_clone = true; + node->instrumented_version = clone; + + if (gimple_has_body_p (fndecl)) + { + /* If function will not be instrumented, then it's instrumented + version is a thunk for the original. */ + if (lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl)) + || (flag_chkp_instrument_marked_only + && !lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))) + { + clone->thunk.thunk_p = true; + clone->thunk.add_pointer_bounds_args = true; + clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE); + } + else + { + tree_function_versioning (fndecl, new_decl, NULL, false, + NULL, false, NULL, NULL); + clone->lowered = true; + } + } + + /* New params are inserted after versioning because it + actually copies args list from the original decl. */ + chkp_add_bounds_params_to_function (new_decl); + + /* Clones have the same comdat group as originals. */ + if (node->same_comdat_group + || DECL_ONE_ONLY (node->decl)) + clone->add_to_same_comdat_group (node); + + if (gimple_has_body_p (fndecl)) + symtab->call_cgraph_insertion_hooks (clone); + + /* Clone all aliases. */ + for (i = 0; node->iterate_referring (i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = dyn_cast (ref->referring); + struct cgraph_node *chkp_alias + = chkp_maybe_create_clone (alias->decl); + chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL); + } + + /* Clone all thunks. */ + for (e = node->callers; e; e = e->next_caller) + if (e->caller->thunk.thunk_p) + { + struct cgraph_node *thunk + = chkp_maybe_create_clone (e->caller->decl); + /* Redirect thunk clone edge to the node clone. */ + thunk->callees->redirect_callee (clone); + } + + /* For aliases and thunks we should make sure target is cloned + to have proper references and edges. */ + if (node->thunk.thunk_p) + chkp_maybe_create_clone (node->callees->callee->decl); + else if (node->alias) + { + struct cgraph_node *target; + + ref = node->ref_list.first_reference (); + if (ref) + chkp_maybe_create_clone (ref->referred->decl); + + if (node->alias_target) + { + if (TREE_CODE (node->alias_target) == FUNCTION_DECL) + { + target = chkp_maybe_create_clone (node->alias_target); + clone->alias_target = target->decl; + } + else + clone->alias_target = node->alias_target; + } + } + + /* Add IPA reference. It's main role is to keep instrumented + version reachable while original node is reachable. */ + ref = node->create_reference (clone, IPA_REF_CHKP, NULL); + } + + return clone; +} + +/* Create clone for all functions to be instrumented. */ + +static unsigned int +chkp_versioning (void) +{ + struct cgraph_node *node; + + FOR_EACH_DEFINED_FUNCTION (node) + { + if (!node->instrumentation_clone + && !node->instrumented_version + && !node->alias + && !node->thunk.thunk_p + && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)) + && (!flag_chkp_instrument_marked_only + || lookup_attribute ("bnd_instrument", + DECL_ATTRIBUTES (node->decl))) + /* No builtins instrumentation for now. */ + && DECL_BUILT_IN_CLASS (node->decl) == NOT_BUILT_IN) + chkp_maybe_create_clone (node->decl); + } + + /* Mark all aliases and thunks of functions with no instrumented + version as legacy function. */ + FOR_EACH_DEFINED_FUNCTION (node) + { + if (!node->instrumentation_clone + && !node->instrumented_version + && (node->alias || node->thunk.thunk_p) + && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl))) + DECL_ATTRIBUTES (node->decl) + = tree_cons (get_identifier ("bnd_legacy"), NULL, + DECL_ATTRIBUTES (node->decl)); + } + + return 0; +} + +/* In this pass we remove bodies of functions having + instrumented version. Functions with removed bodies + become a special kind of thunks to provide a connection + between calls to the original version and instrumented + function. */ + +static unsigned int +chkp_produce_thunks (void) +{ + struct cgraph_node *node; + + FOR_EACH_DEFINED_FUNCTION (node) + { + if (!node->instrumentation_clone + && node->instrumented_version + && gimple_has_body_p (node->decl) + && gimple_has_body_p (node->instrumented_version->decl)) + { + node->release_body (); + node->remove_callees (); + node->remove_all_references (); + + node->thunk.thunk_p = true; + node->thunk.add_pointer_bounds_args = true; + node->create_edge (node->instrumented_version, NULL, + 0, CGRAPH_FREQ_BASE); + node->create_reference (node->instrumented_version, + IPA_REF_CHKP, NULL); + } + } + + /* Mark instrumentation clones created for aliases and thunks + as insttrumented so they could be removed as unreachable + now. */ + FOR_EACH_DEFINED_FUNCTION (node) + { + if (node->instrumentation_clone + && (node->alias || node->thunk.thunk_p) + && !chkp_function_instrumented_p (node->decl)) + chkp_function_mark_instrumented (node->decl); + } + + symtab->remove_unreachable_nodes (true, dump_file); + + return 0; +} + +const pass_data pass_data_ipa_chkp_versioning = +{ + SIMPLE_IPA_PASS, /* type */ + "chkp_versioning", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +const pass_data pass_data_ipa_chkp_produce_thunks = +{ + SIMPLE_IPA_PASS, /* type */ + "chkp_cleanup", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +class pass_ipa_chkp_versioning : public simple_ipa_opt_pass +{ +public: + pass_ipa_chkp_versioning (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt) + {} + + /* opt_pass methods: */ + virtual opt_pass * clone () + { + return new pass_ipa_chkp_versioning (m_ctxt); + } + + virtual bool gate (function *) + { + return flag_check_pointer_bounds; + } + + virtual unsigned int execute (function *) + { + return chkp_versioning (); + } + +}; // class pass_ipa_chkp_versioning + +class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass +{ +public: + pass_ipa_chkp_produce_thunks (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt) + {} + + /* opt_pass methods: */ + virtual opt_pass * clone () + { + return new pass_ipa_chkp_produce_thunks (m_ctxt); + } + + virtual unsigned int execute (function *) + { + return chkp_produce_thunks (); + } + +}; // class pass_chkp_produce_thunks + +simple_ipa_opt_pass * +make_pass_ipa_chkp_versioning (gcc::context *ctxt) +{ + return new pass_ipa_chkp_versioning (ctxt); +} + +simple_ipa_opt_pass * +make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt) +{ + return new pass_ipa_chkp_produce_thunks (ctxt); +} diff --git a/gcc/ipa-chkp.h b/gcc/ipa-chkp.h new file mode 100644 index 0000000..9c92c04 --- /dev/null +++ b/gcc/ipa-chkp.h @@ -0,0 +1,29 @@ +/* Declaration of interface functions of Pointer Bounds Checker. + Copyright (C) 2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_IPA_CHKP_H +#define GCC_IPA_CHKP_H + +#include "tree.h" +#include "cgraph.h" + +extern tree chkp_copy_function_type_adding_bounds (tree orig_type); +extern cgraph_node *chkp_maybe_create_clone (tree fndecl); + +#endif /* GCC_IPA_CHKP_H */