diff mbox

[Pointer,Bounds,Checker,14/x] Passes [1/n] Expand interfaces

Message ID 20141008185054.GA13454@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Oct. 8, 2014, 6:50 p.m. UTC
Hi,

This patch starts a series which is a result of split of Pointer Bounds Checker patch #14 (Pointer Bounds Checker passes).

This patch introduces compiler flags used by checker and helper functions mostly used by expand pass.

Thanks,
Ilya
--
2014-10-08  Ilya Enkovich  <ilya.enkovich@intel.com>

	* tree-chkp.c: New.
	* tree-chkp.h: New.
	* rtl-chkp.c: New.
	* rtl-chkp.h: New.
	* Makefile.in (OBJS): Add rtl-chkp.o and tree-chkp.o.
	(GTFILES): Add tree-chkp.c.
	* c-family/c.opt (fchkp-check-incomplete-type): New.
	(fchkp-zero-input-bounds-for-main): New.
	(fchkp-first-field-has-own-bounds): New.
	(fchkp-narrow-bounds): New.
	(fchkp-narrow-to-innermost-array): New.
	(fchkp-optimize): New.
	(fchkp-use-fast-string-functions): New.
	(fchkp-use-nochk-string-functions): New.
	(fchkp-use-static-bounds): New.
	(fchkp-use-static-const-bounds): New.
	(fchkp-treat-zero-dynamic-size-as-infinite): New.
	(fchkp-check-read): New.
	(fchkp-check-write): New.
	(fchkp-store-bounds): New.
	(fchkp-instrument-calls): New.
	(fchkp-instrument-marked-only): New.
	* cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add
	__CHKP__ macro when Pointer Bounds Checker is on.

Comments

Jeff Law Oct. 13, 2014, 9:11 p.m. UTC | #1
On 10/08/14 12:50, Ilya Enkovich wrote:
> Hi,
>
> This patch starts a series which is a result of split of Pointer Bounds Checker patch #14 (Pointer Bounds Checker passes).
>
> This patch introduces compiler flags used by checker and helper functions mostly used by expand pass.
>
> Thanks,
> Ilya
> --
> 2014-10-08  Ilya Enkovich  <ilya.enkovich@intel.com>
>
> 	* tree-chkp.c: New.
> 	* tree-chkp.h: New.
> 	* rtl-chkp.c: New.
> 	* rtl-chkp.h: New.
> 	* Makefile.in (OBJS): Add rtl-chkp.o and tree-chkp.o.
> 	(GTFILES): Add tree-chkp.c.
> 	* c-family/c.opt (fchkp-check-incomplete-type): New.
> 	(fchkp-zero-input-bounds-for-main): New.
> 	(fchkp-first-field-has-own-bounds): New.
> 	(fchkp-narrow-bounds): New.
> 	(fchkp-narrow-to-innermost-array): New.
> 	(fchkp-optimize): New.
> 	(fchkp-use-fast-string-functions): New.
> 	(fchkp-use-nochk-string-functions): New.
> 	(fchkp-use-static-bounds): New.
> 	(fchkp-use-static-const-bounds): New.
> 	(fchkp-treat-zero-dynamic-size-as-infinite): New.
> 	(fchkp-check-read): New.
> 	(fchkp-check-write): New.
> 	(fchkp-store-bounds): New.
> 	(fchkp-instrument-calls): New.
> 	(fchkp-instrument-marked-only): New.
> 	* cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add
> 	__CHKP__ macro when Pointer Bounds Checker is on.
OK for the trunk.

So at this point do we have any patches that have not been reviewed for 
this stage of the bounded pointers work?  Are there any which you have 
posted updated versions that you feel need further review?

Jeff
Ilya Enkovich Oct. 15, 2014, 5:54 p.m. UTC | #2
2014-10-14 1:11 GMT+04:00 Jeff Law <law@redhat.com>:
> On 10/08/14 12:50, Ilya Enkovich wrote:
>>
>> Hi,
>>
>> This patch starts a series which is a result of split of Pointer Bounds
>> Checker patch #14 (Pointer Bounds Checker passes).
>>
>> This patch introduces compiler flags used by checker and helper functions
>> mostly used by expand pass.
>>
>> Thanks,
>> Ilya
>> --
>> 2014-10-08  Ilya Enkovich  <ilya.enkovich@intel.com>
>>
>>         * tree-chkp.c: New.
>>         * tree-chkp.h: New.
>>         * rtl-chkp.c: New.
>>         * rtl-chkp.h: New.
>>         * Makefile.in (OBJS): Add rtl-chkp.o and tree-chkp.o.
>>         (GTFILES): Add tree-chkp.c.
>>         * c-family/c.opt (fchkp-check-incomplete-type): New.
>>         (fchkp-zero-input-bounds-for-main): New.
>>         (fchkp-first-field-has-own-bounds): New.
>>         (fchkp-narrow-bounds): New.
>>         (fchkp-narrow-to-innermost-array): New.
>>         (fchkp-optimize): New.
>>         (fchkp-use-fast-string-functions): New.
>>         (fchkp-use-nochk-string-functions): New.
>>         (fchkp-use-static-bounds): New.
>>         (fchkp-use-static-const-bounds): New.
>>         (fchkp-treat-zero-dynamic-size-as-infinite): New.
>>         (fchkp-check-read): New.
>>         (fchkp-check-write): New.
>>         (fchkp-store-bounds): New.
>>         (fchkp-instrument-calls): New.
>>         (fchkp-instrument-marked-only): New.
>>         * cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add
>>         __CHKP__ macro when Pointer Bounds Checker is on.
>
> OK for the trunk.
>
> So at this point do we have any patches that have not been reviewed for this
> stage of the bounded pointers work?  Are there any which you have posted
> updated versions that you feel need further review?

Thanks for review!  I see no more patches not reviewed at all.  I see
4 more patches requiring approve before I can start a merge.

Two of them are parts of split #14 (Passes): #14.3 (Helper functions)
and #14.16 (Reduce bounds lifetime)

There is also #32 (hooks for i386 target). It has concern about TBAA
which I believe is not a problem in my case because accesses using
different types are not mixed.

The final one is #33 (MPX ABI).  I still see fail on one benchmark but
I don't feel ICE in LRA should prevent patch from been committed.

Thanks,
Ilya

>
> Jeff
>
Jeff Law Oct. 30, 2014, 5:37 a.m. UTC | #3
On 10/15/14 11:54, Ilya Enkovich wrote:
>
> Thanks for review!  I see no more patches not reviewed at all.  I see
> 4 more patches requiring approve before I can start a merge.
>
> Two of them are parts of split #14 (Passes): #14.3 (Helper functions)
> and #14.16 (Reduce bounds lifetime)
These are fine.  We can revisit LCM/anticipated in the future for the 
bounds lifetime reduction.


>
> There is also #32 (hooks for i386 target). It has concern about TBAA
> which I believe is not a problem in my case because accesses using
> different types are not mixed.
OK.  That was the only pending issue with that patch, so it's good to go 
as well.

>
> The final one is #33 (MPX ABI).  I still see fail on one benchmark but
> I don't feel ICE in LRA should prevent patch from been committed.
Assuming it doesn't fail unless you've turned on MPX, that seems 
reasonable at this stage.  Obviously we'd like to get that fixed during 
the general bugfixing phase.

As I discussed with Areg, I wanted this stuff to wait until the Darwin 
port had settled a bit after the recent problems.  While Darwin isn't 
happy yet, I think the remaining problems are manageable and isolated to 
the i686 code generator.  So if you could bootstrap Darwin 64 bit as a 
sanity test along with a final bootstrap & regression test on x86_64 
linux, then I think we're good to go.

jeff
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 97b439a..3113a9f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1328,6 +1328,7 @@  OBJS = \
 	reload1.o \
 	reorg.o \
 	resource.o \
+	rtl-chkp.o \
 	rtl-error.o \
 	rtl.o \
 	rtlhash.o \
@@ -1386,6 +1387,7 @@  OBJS = \
 	tree-outof-ssa.o \
 	tree-parloops.o \
 	tree-phinodes.o \
+	tree-chkp.o \
 	tree-predcom.o \
 	tree-pretty-print.o \
 	tree-profile.o \
@@ -2254,6 +2256,7 @@  GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
   $(srcdir)/gimple.h \
   $(srcdir)/gimple-ssa.h \
+  $(srcdir)/tree-chkp.c \
   $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \
   $(srcdir)/tree-cfg.c \
   $(srcdir)/tree-dfa.c \
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3c5ebc0..1ca5a95 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -955,6 +955,79 @@  Common Report Var(flag_check_pointer_bounds)
 Add Pointer Bounds Checker instrumentation.  fchkp-* flags are used to
 control instrumentation.  Currently available for C, C++ and ObjC.
 
+fchkp-check-incomplete-type
+C ObjC C++ ObjC++ Report Var(flag_chkp_incomplete_type) Init(1)
+Generate pointer bounds checks for variables with incomplete type
+
+fchkp-zero-input-bounds-for-main
+C ObjC C++ ObjC++ Report Var(flag_chkp_zero_input_bounds_for_main) Init(0)
+Use zero bounds for all incoming arguments in 'main' function.  It helps when
+instrumented binaries are used with legacy libs.
+
+fchkp-first-field-has-own-bounds
+C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_first_field_has_own_bounds)
+Forces Pointer Bounds Checker to use narrowed bounds for address of the first
+field in the structure.  By default pointer to the first field has the same
+bounds as pointer to the whole structure.
+
+fchkp-narrow-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_narrow_bounds) Init(1)
+Control how Pointer Bounds Checker handle pointers to object fields.  When
+narrowing is on, field bounds are used.  Otherwise full object bounds are used.
+
+fchkp-narrow-to-innermost-array
+C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_narrow_to_innermost_arrray)
+Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
+nested static arryas access.  By default outermost array is used.
+
+fchkp-optimize
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
+Allow Pointer Bounds Checker optimizations.  By default allowed
+on optimization levels >0.
+
+fchkp-use-fast-string-functions
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_fast_string_functions) Init(0)
+Allow to use *_nobnd versions of string functions by Pointer Bounds Checker.
+
+fchkp-use-nochk-string-functions
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_nochk_string_functions) Init(0)
+Allow to use *_nochk versions of string functions by Pointer Bounds Checker.
+
+fchkp-use-static-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_bounds) Init(1)
+Use statically initialized variable for vars bounds instead of
+generating them each time it is required.
+
+fchkp-use-static-const-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_const_bounds) Init(-1)
+Use statically initialized variable for constant bounds instead of
+generating them each time it is required.
+
+fchkp-treat-zero-dynamic-size-as-infinite
+C ObjC C++ ObjC++ Report Var(flag_chkp_zero_dynamic_size_as_infinite) Init(0)
+With this option zero size obtained dynamically for objects with
+incomplete type will be treated as infinite.
+
+fchkp-check-read
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_read) Init(1)
+Generate checks for all read accesses to memory.
+
+fchkp-check-write
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_write) Init(1)
+Generate checks for all write accesses to memory.
+
+fchkp-store-bounds
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_store_bounds) Init(1)
+Generate bounds stores for pointer writes.
+
+fchkp-instrument-calls
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_calls) Init(1)
+Generate bounds passing for calls.
+
+fchkp-instrument-marked-only
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_marked_only) Init(0)
+Instrument only functions marked with bnd_instrument attribute.
+
 fcilkplus
 C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0)
 Enable Cilk Plus
diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c
index fbcd9b0..3fc2f8a 100644
--- a/gcc/cppbuiltin.c
+++ b/gcc/cppbuiltin.c
@@ -107,6 +107,9 @@  define_builtin_macros_for_compilation_flags (cpp_reader *pfile)
 			flag_finite_math_only);
   if (flag_cilkplus)
     cpp_define (pfile, "__cilk=200");
+
+  if (flag_check_pointer_bounds)
+    cpp_define (pfile, "__CHKP__");
 }
 
 
diff --git a/gcc/rtl-chkp.c b/gcc/rtl-chkp.c
new file mode 100644
index 0000000..4c68119
--- /dev/null
+++ b/gcc/rtl-chkp.c
@@ -0,0 +1,299 @@ 
+/* RTL manipulation functions exported by Pointer Bounds Checker.
+   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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "rtl-chkp.h"
+#include "tree-chkp.h"
+#include "expr.h"
+#include "target.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "is-a.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "bitmap.h"
+
+struct hash_map<tree, rtx> *chkp_rtx_bounds_map;
+
+/* Get bounds rtx associated with NODE via
+   chkp_set_rtl_bounds call.  */
+rtx
+chkp_get_rtl_bounds (tree node)
+{
+  rtx *slot;
+
+  if (!chkp_rtx_bounds_map)
+    return NULL_RTX;
+
+  slot = chkp_rtx_bounds_map->get (node);
+  return slot ? *slot : NULL_RTX;
+}
+
+/* Associate bounds rtx VAL with NODE.  */
+void
+chkp_set_rtl_bounds (tree node, rtx val)
+{
+  if (!chkp_rtx_bounds_map)
+    chkp_rtx_bounds_map = new hash_map<tree, rtx>;
+
+  chkp_rtx_bounds_map->put (node, val);
+}
+
+/* Reset all bounds stored via chkp_set_rtl_bounds.  */
+void
+chkp_reset_rtl_bounds ()
+{
+  if (!chkp_rtx_bounds_map)
+    return;
+
+  delete chkp_rtx_bounds_map;
+  chkp_rtx_bounds_map = NULL;
+}
+
+/* Split SLOT identifying slot for function value or
+   argument into two parts SLOT_VAL and SLOT_BND.
+   First is the slot for regular value and the other one is
+   for bounds.  */
+void
+chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd)
+{
+  int i;
+  int val_num = 0;
+  int bnd_num = 0;
+  rtx *val_tmps;
+  rtx *bnd_tmps;
+
+  *slot_bnd = 0;
+
+  if (!slot
+      || GET_CODE (slot) != PARALLEL)
+    {
+      *slot_val = slot;
+      return;
+    }
+
+  val_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
+  bnd_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
+
+  for (i = 0; i < XVECLEN (slot, 0); i++)
+    {
+      rtx elem = XVECEXP (slot, 0, i);
+      rtx reg = GET_CODE (elem) == EXPR_LIST ? XEXP (elem, 0) : elem;
+
+      if (!reg)
+	continue;
+
+      if (POINTER_BOUNDS_MODE_P (GET_MODE (reg)) || CONST_INT_P (reg))
+	bnd_tmps[bnd_num++] = elem;
+      else
+	val_tmps[val_num++] = elem;
+    }
+
+  gcc_assert (val_num);
+
+  if (!bnd_num)
+    {
+      *slot_val = slot;
+      return;
+    }
+
+  if ((GET_CODE (val_tmps[0]) == EXPR_LIST) || (val_num > 1))
+    *slot_val = gen_rtx_PARALLEL (GET_MODE (slot),
+				  gen_rtvec_v (val_num, val_tmps));
+  else
+    *slot_val = val_tmps[0];
+
+  if ((GET_CODE (bnd_tmps[0]) == EXPR_LIST) || (bnd_num > 1))
+    *slot_bnd = gen_rtx_PARALLEL (VOIDmode,
+				  gen_rtvec_v (bnd_num, bnd_tmps));
+  else
+    *slot_bnd = bnd_tmps[0];
+}
+
+/* Join previously splitted to VAL and BND rtx for function
+   value or argument and return it.  */
+rtx
+chkp_join_splitted_slot (rtx val, rtx bnd)
+{
+  rtx res;
+  int i, n = 0;
+
+  if (!bnd)
+    return val;
+
+  if (GET_CODE (val) == PARALLEL)
+    n += XVECLEN (val, 0);
+  else
+    n++;
+
+  if (GET_CODE (bnd) == PARALLEL)
+    n += XVECLEN (bnd, 0);
+  else
+    n++;
+
+  res = gen_rtx_PARALLEL (GET_MODE (val), rtvec_alloc (n));
+
+  n = 0;
+
+  if (GET_CODE (val) == PARALLEL)
+    for (i = 0; i < XVECLEN (val, 0); i++)
+      XVECEXP (res, 0, n++) = XVECEXP (val, 0, i);
+  else
+    XVECEXP (res, 0, n++) = val;
+
+  if (GET_CODE (bnd) == PARALLEL)
+    for (i = 0; i < XVECLEN (bnd, 0); i++)
+      XVECEXP (res, 0, n++) = XVECEXP (bnd, 0, i);
+  else
+    XVECEXP (res, 0, n++) = bnd;
+
+  return res;
+}
+
+/* If PAR is PARALLEL holding registers then transform
+   it into PARALLEL holding EXPR_LISTs of those regs
+   and zero constant (similar to how function value
+   on multiple registers looks like).  */
+void
+chkp_put_regs_to_expr_list (rtx par)
+{
+  int n;
+
+  if (GET_CODE (par) != PARALLEL
+      || GET_CODE (XVECEXP (par, 0, 0)) == EXPR_LIST)
+    return;
+
+  for (n = 0; n < XVECLEN (par, 0); n++)
+    XVECEXP (par, 0, n) = gen_rtx_EXPR_LIST (VOIDmode,
+					     XVECEXP (par, 0, n),
+					     const0_rtx);
+}
+
+/*  Search rtx PAR describing function return value for an
+    item related to value at offset OFFS and return it.
+    Return NULL if item was not found.  */
+rtx
+chkp_get_value_with_offs (rtx par, rtx offs)
+{
+  int n;
+
+  gcc_assert (GET_CODE (par) == PARALLEL);
+
+  for (n = 0; n < XVECLEN (par, 0); n++)
+    {
+      rtx par_offs = XEXP (XVECEXP (par, 0, n), 1);
+      if (INTVAL (offs) == INTVAL (par_offs))
+	return XEXP (XVECEXP (par, 0, n), 0);
+    }
+
+  return NULL;
+}
+
+/* Emit instructions to store BOUNDS for pointer VALUE
+   stored in MEM.
+   Function is used by expand to pass bounds for args
+   passed on stack.  */
+void
+chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem)
+{
+  gcc_assert (MEM_P (mem));
+
+  if (REG_P (bounds) || CONST_INT_P (bounds))
+    {
+      rtx ptr;
+
+      if (REG_P (value))
+	ptr = value;
+      else
+	{
+	  rtx slot = adjust_address (value, Pmode, 0);
+	  ptr = gen_reg_rtx (Pmode);
+	  emit_move_insn (ptr, slot);
+	}
+
+      if (CONST_INT_P (bounds))
+	bounds = targetm.calls.load_bounds_for_arg (value, ptr, bounds);
+
+      targetm.calls.store_bounds_for_arg (ptr, mem,
+					  bounds, NULL);
+    }
+  else
+    {
+      int i;
+
+      gcc_assert (GET_CODE (bounds) == PARALLEL);
+      gcc_assert (GET_CODE (value) == PARALLEL || MEM_P (value) || REG_P (value));
+
+      for (i = 0; i < XVECLEN (bounds, 0); i++)
+	{
+	  rtx reg = XEXP (XVECEXP (bounds, 0, i), 0);
+	  rtx offs = XEXP (XVECEXP (bounds, 0, i), 1);
+	  rtx slot = adjust_address (mem, Pmode, INTVAL (offs));
+	  rtx ptr;
+
+	  if (GET_CODE (value) == PARALLEL)
+	    ptr = chkp_get_value_with_offs (value, offs);
+	  else if (MEM_P (value))
+	    {
+	      rtx tmp = adjust_address (value, Pmode, INTVAL (offs));
+	      ptr = gen_reg_rtx (Pmode);
+	      emit_move_insn (ptr, tmp);
+	    }
+	  else
+	    ptr = gen_rtx_SUBREG (Pmode, value, INTVAL (offs));
+
+	  targetm.calls.store_bounds_for_arg (ptr, slot, reg, NULL);
+	}
+    }
+}
+
+/* Emit code to copy bounds for structure VALUE of type TYPE
+   copied to SLOT.  */
+void
+chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type)
+{
+  bitmap have_bound = chkp_find_bound_slots (type);
+  bitmap_iterator bi;
+  unsigned i;
+  rtx tmp = NULL, bnd;
+
+  gcc_assert (TYPE_SIZE (type));
+  gcc_assert (MEM_P (value));
+  gcc_assert (MEM_P (slot));
+  gcc_assert (RECORD_OR_UNION_TYPE_P (type));
+
+  EXECUTE_IF_SET_IN_BITMAP (have_bound, 0, i, bi)
+    {
+      rtx ptr = adjust_address (value, Pmode, i * POINTER_SIZE / 8);
+      rtx to = adjust_address (slot, Pmode, i * POINTER_SIZE / 8);
+
+      if (!tmp)
+	tmp = gen_reg_rtx (Pmode);
+
+      emit_move_insn (tmp, ptr);
+      bnd = targetm.calls.load_bounds_for_arg (ptr, tmp, NULL);
+      targetm.calls.store_bounds_for_arg (tmp, to, bnd, NULL);
+    }
+
+  BITMAP_FREE (have_bound);
+}
diff --git a/gcc/rtl-chkp.h b/gcc/rtl-chkp.h
new file mode 100644
index 0000000..543cc83
--- /dev/null
+++ b/gcc/rtl-chkp.h
@@ -0,0 +1,40 @@ 
+/* 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_RTL_CHKP_H
+#define GCC_RTL_CHKP_H
+
+#include "coretypes.h"
+
+#define DECL_BOUNDS_RTL(NODE) (chkp_get_rtl_bounds (DECL_WRTL_CHECK (NODE)))
+
+#define SET_DECL_BOUNDS_RTL(NODE, VAL) \
+  (chkp_set_rtl_bounds (DECL_WRTL_CHECK (NODE), VAL))
+
+extern rtx chkp_get_rtl_bounds (tree node);
+extern void chkp_set_rtl_bounds (tree node, rtx val);
+extern void chkp_reset_rtl_bounds ();
+extern void chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd);
+extern rtx chkp_join_splitted_slot (rtx val, rtx bnd);
+extern rtx chkp_get_value_with_offs (rtx par, rtx offs);
+extern void chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type);
+extern void chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem);
+extern void chkp_put_regs_to_expr_list (rtx par);
+
+#endif /* GCC_RTL_CHKP_H */
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
new file mode 100644
index 0000000..4ab8de6
--- /dev/null
+++ b/gcc/tree-chkp.c
@@ -0,0 +1,528 @@ 
+/* Pointer Bounds Checker insrumentation pass.
+   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
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "tree.h"
+#include "target.h"
+#include "tree-iterator.h"
+#include "tree-cfg.h"
+#include "langhooks.h"
+#include "tree-pass.h"
+#include "hashtab.h"
+#include "diagnostic.h"
+#include "ggc.h"
+#include "output.h"
+#include "internal-fn.h"
+#include "is-a.h"
+#include "predict.h"
+#include "cfgloop.h"
+#include "stringpool.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-operands.h"
+#include "tree-ssa-address.h"
+#include "tree-ssa.h"
+#include "ipa-inline.h"
+#include "basic-block.h"
+#include "tree-ssa-loop-niter.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "tree-phinodes.h"
+#include "gimple-ssa.h"
+#include "ssa-iterators.h"
+#include "gimple-pretty-print.h"
+#include "gimple-iterator.h"
+#include "gimplify.h"
+#include "gimplify-me.h"
+#include "print-tree.h"
+#include "expr.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
+#include "tree-chkp.h"
+#include "gimple-walk.h"
+#include "rtl.h" /* For MEM_P, assign_temp.  */
+#include "tree-dfa.h"
+
+#define chkp_bndldx_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
+#define chkp_bndstx_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX))
+#define chkp_checkl_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
+#define chkp_checku_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
+#define chkp_bndmk_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
+#define chkp_ret_bnd_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET))
+#define chkp_intersect_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
+#define chkp_narrow_bounds_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW))
+#define chkp_sizeof_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF))
+#define chkp_extract_lower_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER))
+#define chkp_extract_upper_fndecl \
+  (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER))
+
+static GTY (()) tree chkp_zero_bounds_var;
+
+struct hash_map<tree, tree> *chkp_bounds_map;
+
+#define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
+
+/* Return 1 if function FNDECL is instrumented by Pointer
+   Bounds Checker.  */
+bool
+chkp_function_instrumented_p (tree fndecl)
+{
+  return fndecl
+    && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl));
+}
+
+/* Mark function FNDECL as instrumented.  */
+void
+chkp_function_mark_instrumented (tree fndecl)
+{
+  if (chkp_function_instrumented_p (fndecl))
+    return;
+
+  DECL_ATTRIBUTES (fndecl)
+    = tree_cons (get_identifier ("chkp instrumented"), NULL,
+		 DECL_ATTRIBUTES (fndecl));
+}
+
+/* Return true when STMT is builtin call to instrumentation function
+   corresponding to CODE.  */
+
+bool
+chkp_gimple_call_builtin_p (gimple call,
+			    enum built_in_function code)
+{
+  tree fndecl;
+  if (is_gimple_call (call)
+      && (fndecl = targetm.builtin_chkp_function (code))
+      && gimple_call_fndecl (call) == fndecl)
+    return true;
+  return false;
+}
+
+/* Emit code to store zero bounds for PTR located at MEM.  */
+void
+chkp_expand_bounds_reset_for_mem (tree mem, tree ptr)
+{
+  tree zero_bnd, bnd, addr, bndstx;
+
+  if (flag_chkp_use_static_const_bounds)
+    zero_bnd = chkp_get_zero_bounds_var ();
+  else
+    zero_bnd = chkp_build_make_bounds_call (integer_zero_node,
+					    integer_zero_node);
+  bnd = make_tree (pointer_bounds_type_node,
+		   assign_temp (pointer_bounds_type_node, 0, 1));
+  addr = build1 (ADDR_EXPR,
+		 build_pointer_type (TREE_TYPE (mem)), mem);
+  bndstx = chkp_build_bndstx_call (addr, ptr, bnd);
+
+  expand_assignment (bnd, zero_bnd, false);
+  expand_normal (bndstx);
+}
+
+/* Mark statement S to not be instrumented.  */
+static void
+chkp_mark_stmt (gimple s)
+{
+  gimple_set_plf (s, GF_PLF_1, true);
+}
+
+/* Mark statement S to be instrumented.  */
+static void
+chkp_unmark_stmt (gimple s)
+{
+  gimple_set_plf (s, GF_PLF_1, false);
+}
+
+/* Return 1 if statement S should not be instrumented.  */
+static bool
+chkp_marked_stmt_p (gimple s)
+{
+  return gimple_plf (s, GF_PLF_1);
+}
+
+/* Build and return bndmk call which creates bounds for structure
+   pointed by PTR.  Structure should have complete type.  */
+tree
+chkp_make_bounds_for_struct_addr (tree ptr)
+{
+  tree type = TREE_TYPE (ptr);
+  tree size;
+
+  gcc_assert (POINTER_TYPE_P (type));
+
+  size = TYPE_SIZE (TREE_TYPE (type));
+
+  gcc_assert (size);
+
+  return build_call_nary (pointer_bounds_type_node,
+			  build_fold_addr_expr (chkp_bndmk_fndecl),
+			  2, ptr, size);
+}
+
+/* Return 1 if type TYPE is a pointer type or a
+   structure having a pointer type as one of its fields.
+   Otherwise return 0.  */
+bool
+chkp_type_has_pointer (const_tree type)
+{
+  bool res = false;
+
+  if (BOUNDED_TYPE_P (type))
+    res = true;
+  else if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      tree field;
+
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	if (TREE_CODE (field) == FIELD_DECL)
+	  res = res || chkp_type_has_pointer (TREE_TYPE (field));
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    res = chkp_type_has_pointer (TREE_TYPE (type));
+
+  return res;
+}
+
+unsigned
+chkp_type_bounds_count (const_tree type)
+{
+  unsigned res = 0;
+
+  if (!type)
+    res = 0;
+  else if (BOUNDED_TYPE_P (type))
+    res = 1;
+  else if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      bitmap have_bound = chkp_find_bound_slots (type);
+      res = bitmap_count_bits (have_bound);
+      BITMAP_FREE (have_bound);
+    }
+
+  return res;
+}
+
+/* Get bounds associated with NODE via
+   chkp_set_bounds call.  */
+tree
+chkp_get_bounds (tree node)
+{
+  tree *slot;
+
+  if (!chkp_bounds_map)
+    return NULL_TREE;
+
+  slot = chkp_bounds_map->get (node);
+  return slot ? *slot : NULL_TREE;
+}
+
+/* Associate bounds VAL with NODE.  */
+void
+chkp_set_bounds (tree node, tree val)
+{
+  if (!chkp_bounds_map)
+    chkp_bounds_map = new hash_map<tree, tree>;
+
+  chkp_bounds_map->put (node, val);
+}
+
+/* Force OP to be suitable for using as an argument for call.
+   New statements (if any) go to SEQ.  */
+static tree
+chkp_force_gimple_call_op (tree op, gimple_seq *seq)
+{
+  gimple_seq stmts;
+  gimple_stmt_iterator si;
+
+  op = force_gimple_operand (unshare_expr (op), &stmts, true, NULL_TREE);
+
+  for (si = gsi_start (stmts); !gsi_end_p (si); gsi_next (&si))
+    chkp_mark_stmt (gsi_stmt (si));
+
+  gimple_seq_add_seq (seq, stmts);
+
+  return op;
+}
+
+/* Fill HAVE_BOUND output bitmap with information about
+   bounds requred for object of type TYPE.
+
+   OFFS is used for recursive calls and holds basic
+   offset of TYPE in outer structure in bits.
+
+   HAVE_BOUND[i] is set to 1 if there is a field
+   in TYPE which has pointer type and offset
+   equal to i * POINTER_SIZE - OFFS in bits.  */
+void
+chkp_find_bound_slots_1 (const_tree type, bitmap have_bound,
+			 HOST_WIDE_INT offs)
+{
+  if (BOUNDED_TYPE_P (type))
+    bitmap_set_bit (have_bound, offs / POINTER_SIZE);
+  else if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      tree field;
+
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	if (TREE_CODE (field) == FIELD_DECL)
+	  {
+	    HOST_WIDE_INT field_offs
+	      = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+	    if (DECL_FIELD_OFFSET (field))
+	      field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8;
+	    chkp_find_bound_slots_1 (TREE_TYPE (field), have_bound,
+				     offs + field_offs);
+	  }
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+      tree etype = TREE_TYPE (type);
+      HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
+      unsigned HOST_WIDE_INT cur;
+
+      if (!maxval || integer_minus_onep (maxval))
+	return;
+
+      for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++)
+	chkp_find_bound_slots_1 (etype, have_bound, offs + cur * esize);
+    }
+}
+
+/* Return bitmap holding information about bounds for
+   type TYPE.  See chkp_find_bound_slots_1 for more
+   details.
+
+   Caller is responsible for deallocation of returned
+   bitmap.  */
+bitmap
+chkp_find_bound_slots (const_tree type)
+{
+  bitmap res = BITMAP_ALLOC (NULL);
+  chkp_find_bound_slots_1 (type, res, 0);
+  return res;
+}
+
+/* Return constant static bounds var with specified LB and UB
+   if such var exists in varpool.  Return NULL otherwise.  */
+static tree
+chkp_find_const_bounds_var (HOST_WIDE_INT lb,
+			    HOST_WIDE_INT ub)
+{
+  tree val = targetm.chkp_make_bounds_constant (lb, ub);
+  struct varpool_node *node;
+
+  /* We expect bounds constant is represented as a complex value
+     of two pointer sized integers.  */
+  gcc_assert (TREE_CODE (val) == COMPLEX_CST);
+
+  FOR_EACH_VARIABLE (node)
+    if (POINTER_BOUNDS_P (node->decl)
+	&& TREE_READONLY (node->decl)
+	&& DECL_INITIAL (node->decl)
+	&& TREE_CODE (DECL_INITIAL (node->decl)) == COMPLEX_CST
+	&& tree_int_cst_equal (TREE_REALPART (DECL_INITIAL (node->decl)),
+			       TREE_REALPART (val))
+	&& tree_int_cst_equal (TREE_IMAGPART (DECL_INITIAL (node->decl)),
+			       TREE_IMAGPART (val)))
+      return node->decl;
+
+  return NULL;
+}
+
+/* Return constant static bounds var with specified bounds LB and UB.
+   If such var does not exists then new var is created with specified NAME.  */
+static tree
+chkp_make_static_const_bounds (HOST_WIDE_INT lb,
+			       HOST_WIDE_INT ub,
+			       const char *name)
+{
+  tree var;
+
+  /* With LTO we may have constant bounds already in varpool.
+     Try to find it.  */
+  var = chkp_find_const_bounds_var (lb, ub);
+
+  if (var)
+    return var;
+
+  var  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		     get_identifier (name), pointer_bounds_type_node);
+
+  TREE_PUBLIC (var) = 1;
+  TREE_USED (var) = 1;
+  TREE_READONLY (var) = 1;
+  TREE_STATIC (var) = 1;
+  TREE_ADDRESSABLE (var) = 0;
+  DECL_ARTIFICIAL (var) = 1;
+  DECL_COMDAT (var) = 1;
+  DECL_READ_P (var) = 1;
+  DECL_INITIAL (var) = targetm.chkp_make_bounds_constant (lb, ub);
+  /* We may use this symbol during ctors generation in chkp_finish_file
+     when all symbols are emitted.  Force output to avoid undefined
+     symbols in ctors.  */
+  varpool_node::get_create (var)->set_comdat_group (DECL_ASSEMBLER_NAME (var));
+  varpool_node::get_create (var)->force_output = 1;
+  varpool_node::finalize_decl (var);
+
+  return var;
+}
+
+/* Return var holding zero bounds.  */
+tree
+chkp_get_zero_bounds_var (void)
+{
+  if (!chkp_zero_bounds_var)
+    chkp_zero_bounds_var
+      = chkp_make_static_const_bounds (0, -1,
+				       CHKP_ZERO_BOUNDS_VAR_NAME);
+  return chkp_zero_bounds_var;
+}
+
+/* Return bounds used as returned by call
+   which produced SSA name VAL.  */
+gimple
+chkp_retbnd_call_by_val (tree val)
+{
+  if (TREE_CODE (val) != SSA_NAME)
+    return NULL;
+
+  gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val)) == GIMPLE_CALL);
+
+  imm_use_iterator use_iter;
+  use_operand_p use_p;
+  FOR_EACH_IMM_USE_FAST (use_p, use_iter, val)
+    if (gimple_code (USE_STMT (use_p)) == GIMPLE_CALL
+	&& gimple_call_fndecl (USE_STMT (use_p)) == chkp_ret_bnd_fndecl)
+      return USE_STMT (use_p);
+
+  return NULL;
+}
+
+/* Build and return CALL_EXPR for bndstx builtin with specified
+   arguments.  */
+tree
+chkp_build_bndldx_call (tree addr, tree ptr)
+{
+  tree fn = build1 (ADDR_EXPR,
+		    build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl)),
+		    chkp_bndldx_fndecl);
+  tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl)),
+			       fn, 2, addr, ptr);
+  CALL_WITH_BOUNDS_P (call) = true;
+  return call;
+}
+
+/* Build and return CALL_EXPR for bndstx builtin with specified
+   arguments.  */
+tree
+chkp_build_bndstx_call (tree addr, tree ptr, tree bounds)
+{
+  tree fn = build1 (ADDR_EXPR,
+		    build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl)),
+		    chkp_bndstx_fndecl);
+  tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl)),
+			       fn, 3, ptr, bounds, addr);
+  CALL_WITH_BOUNDS_P (call) = true;
+  return call;
+}
+
+/* Insert code to store BOUNDS for PTR stored by ADDR.
+   New statements are inserted after position pointed
+   by GSI.  */
+void
+chkp_build_bndstx (tree addr, tree ptr, tree bounds,
+		   gimple_stmt_iterator *gsi)
+{
+  gimple_seq seq;
+  gimple stmt;
+
+  seq = NULL;
+
+  addr = chkp_force_gimple_call_op (addr, &seq);
+  ptr = chkp_force_gimple_call_op (ptr, &seq);
+
+  stmt = gimple_build_call (chkp_bndstx_fndecl, 3, ptr, bounds, addr);
+  chkp_mark_stmt (stmt);
+  gimple_call_set_with_bounds (stmt, true);
+
+  gimple_seq_add_stmt (&seq, stmt);
+
+  gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING);
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Generated bndstx for pointer store ");
+      print_gimple_stmt (dump_file, gsi_stmt (*gsi), 0, TDF_VOPS|TDF_MEMSYMS);
+      print_gimple_stmt (dump_file, stmt, 2, TDF_VOPS|TDF_MEMSYMS);
+    }
+}
+
+/* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE.  */
+tree
+chkp_build_make_bounds_call (tree lower_bound, tree size)
+{
+  tree call = build1 (ADDR_EXPR,
+		      build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl)),
+		      chkp_bndmk_fndecl);
+  return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl)),
+			  call, 2, lower_bound, size);
+}
+
+/* Return 1 if TYPE has fields with zero size or fields
+   marked with chkp_variable_size attribute.  */
+bool
+chkp_variable_size_type (tree type)
+{
+  bool res = false;
+  tree field;
+
+  if (RECORD_OR_UNION_TYPE_P (type))
+    for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+      {
+	if (TREE_CODE (field) == FIELD_DECL)
+	  res = res
+	    || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field))
+	    || chkp_variable_size_type (TREE_TYPE (field));
+      }
+  else
+    res = !TYPE_SIZE (type)
+      || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+      || tree_to_uhwi (TYPE_SIZE (type)) == 0;
+
+  return res;
+}
+
+#include "gt-tree-chkp.h"
diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h
new file mode 100644
index 0000000..0357658
--- /dev/null
+++ b/gcc/tree-chkp.h
@@ -0,0 +1,51 @@ 
+/* 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
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_TREE_CHKP_H
+#define GCC_TREE_CHKP_H
+
+#include "tree.h"
+#include "cgraph.h"
+
+#define DECL_BOUNDS(NODE) (chkp_get_bounds (DECL_WRTL_CHECK (NODE)))
+
+#define SET_DECL_BOUNDS(NODE, VAL) \
+  (chkp_set_bounds (DECL_WRTL_CHECK (NODE), VAL))
+
+extern tree chkp_get_bounds (tree node);
+extern void chkp_set_bounds (tree node, tree val);
+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);
+extern tree chkp_get_zero_bounds_var (void);
+extern bool chkp_variable_size_type (tree type);
+extern tree chkp_build_make_bounds_call (tree lb, tree size);
+extern tree chkp_build_bndldx_call (tree addr, tree ptr);
+extern tree chkp_build_bndstx_call (tree addr, tree ptr, tree bounds);
+extern bitmap chkp_find_bound_slots (const_tree type);
+extern void chkp_build_bndstx (tree addr, tree ptr, tree bounds,
+			       gimple_stmt_iterator *gsi);
+extern gimple chkp_retbnd_call_by_val (tree val);
+extern bool chkp_function_instrumented_p (tree fndecl);
+extern void chkp_function_mark_instrumented (tree fndecl);
+extern bool chkp_gimple_call_builtin_p (gimple call,
+					enum built_in_function code);
+extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr);
+
+#endif /* GCC_TREE_CHKP_H */