[CHKP] Fix for PR79990

Submitted by Alexander Ivchenko on April 20, 2017, 9:27 a.m.

Details

Message ID CACysShg_2=mMGaX-+CLwn5fXzZFKsgTF6Lcx2UfSPRaphm7zUg@mail.gmail.com
State New
Headers show

Commit Message

Alexander Ivchenko April 20, 2017, 9:27 a.m.
Thanks for correcting the usage of get_base_address. I fixed that.
Plus addressed the comment about the avoiding the usage of
chkp_find_bounds.


gcc/testsuite/ChangeLog:

2017-04-20  Alexander Ivchenko  <alexander.ivchenko@intel.com>

        * gcc.target/i386/mpx/hard-reg-2-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-2-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-2-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-1-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-1-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-1-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-2-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-2-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-2-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-3-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-4-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-4-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-4-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-1-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-1-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-1-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-2-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-2-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-5-2-ubv.c: New test.
        * gcc.target/i386/mpx/hard-reg-6-lbv.c: New test.
        * gcc.target/i386/mpx/hard-reg-6-nov.c: New test.
        * gcc.target/i386/mpx/hard-reg-6-ubv.c: New test.

gcc/ChangeLog:

2017-04-20  Alexander Ivchenko  <alexander.ivchenko@intel.com>

        * tree-chkp.c (chkp_get_hard_register_var_fake_base_address):
New function to provide a base address for
chkp_get_hard_register_fake_addr_expr.
        (chkp_get_hard_register_fake_addr_expr): New function to build
fake address expression for an expr that resides on a hard
register.
        (chkp_build_addr_expr): Add checks for hard reg cases.
        (chkp_parse_array_and_component_ref): Create/find bounds if the
var resides on a hard reg.


I already had a testcases for struct with a pointer - "hard-reg-4-*".
Here is the instrumentation of the foo function:

__attribute__((chkp instrumented))
foo.chkp (int i)
{
  __bounds_type __bound_tmp.1;
  register struct S2 b __asm__ (*xmm0);
  int k;
  int * _1;
  long unsigned int _2;
  long unsigned int _3;
  int * _4;
  int * _5;
  int _11;
  int * _18;

  <bb 4> [0.00%]:
  __bound_tmp.1_17 = __chkp_zero_bounds;
  __bound_tmp.1_14 = __builtin_ia32_bndmk (&k, 4);
  __bound_tmp.1_13 = __builtin_ia32_bndmk (-2147483648B, 16);

  <bb 3> [0.00%]:

  <bb 2> [0.00%]:
  k = 5;
  b.f3 = &k;
  __builtin_ia32_bndstx (&k, __bound_tmp.1_14, -2147483648B);
  _1 = b.f3;
  __bound_tmp.1_15 = __builtin_ia32_bndldx (-2147483648B, _1);
  _2 = (long unsigned int) i_9(D);
  _3 = _2 * 4;
  _4 = _1 + _3;
  b.f3 = _4;
  __builtin_ia32_bndstx (_4, __bound_tmp.1_15, -2147483648B);
  _5 = b.f3;
  __bound_tmp.1_16 = __builtin_ia32_bndldx (-2147483648B, _5);
  __builtin_ia32_bndcl (_5, __bound_tmp.1_16);
  _18 = _5 + 3;
  __builtin_ia32_bndcu (_18, __bound_tmp.1_16);
  _11 = *_5;
  k ={v} {CLOBBER};
  return _11;

}

Which is the most suspicious one, because we have ldx and stx. I'm not
sure whether this is OK.

Here is the chkp dump for foo function of newly added hard-reg-6* case:

__attribute__((chkp instrumented))
foo.chkp (int i, int * kp1, __bounds_type __chkp_bounds_of_kp1)
{
  __bounds_type __bound_tmp.1;
  int D.2873;
  register struct S2 b __asm__ (*xmm0);
  int k2;
  int * _1;
  long unsigned int _2;
  long unsigned int _3;
  int * _4;
  int * _5;
  int _13;
  int * _31;

  <bb 5> [0.00%]:
  __bound_tmp.1_22 = __builtin_ia32_bndmk (&k2, 4);
  __bound_tmp.1_17 = __chkp_zero_bounds;
  __bound_tmp.1_15 = __builtin_ia32_bndmk (-2147483648B, 16);

  <bb 4> [0.00%]:

  <bb 2> [0.00%]:
  k2 = 5;
  __bound_tmp.1_16 = __builtin_ia32_bndmk (-2147483648B, 16);
  __bound_tmp.1_18 = __builtin_ia32_bndint (__bound_tmp.1_16, __bound_tmp.1_15);
  __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_18);
  __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_18);
  b.f[0] = kp1_8(D);
  __builtin_ia32_bndstx (kp1_8(D), __chkp_bounds_of_kp1_19(D), -2147483648B);
  __bound_tmp.1_20 = __builtin_ia32_bndmk (-2147483648B, 16);
  __bound_tmp.1_21 = __builtin_ia32_bndint (__bound_tmp.1_20, __bound_tmp.1_15);
  __builtin_ia32_bndcl (-2147483640B, __bound_tmp.1_21);
  __builtin_ia32_bndcu (-2147483633B, __bound_tmp.1_21);
  b.f[1] = &k2;
  __builtin_ia32_bndstx (&k2, __bound_tmp.1_22, -2147483640B);
  __bound_tmp.1_23 = __builtin_ia32_bndmk (-2147483648B, 16);
  __bound_tmp.1_24 = __builtin_ia32_bndint (__bound_tmp.1_23, __bound_tmp.1_15);
  __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_24);
  __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_24);
  _1 = b.f[0];
  __bound_tmp.1_27 = __builtin_ia32_bndldx (-2147483648B, _1);
  _2 = (long unsigned int) i_11(D);
  _3 = _2 * 4;
  _4 = _1 + _3;
  __bound_tmp.1_25 = __builtin_ia32_bndmk (-2147483648B, 16);
  __bound_tmp.1_26 = __builtin_ia32_bndint (__bound_tmp.1_25, __bound_tmp.1_15);
  __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_26);
  __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_26);
  b.f[0] = _4;
  __builtin_ia32_bndstx (_4, __bound_tmp.1_27, -2147483648B);
  __bound_tmp.1_28 = __builtin_ia32_bndmk (-2147483648B, 16);
  __bound_tmp.1_29 = __builtin_ia32_bndint (__bound_tmp.1_28, __bound_tmp.1_15);
  __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_29);
  __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_29);
  _5 = b.f[0];
  __bound_tmp.1_30 = __builtin_ia32_bndldx (-2147483648B, _5);
  __builtin_ia32_bndcl (_5, __bound_tmp.1_30);
  _31 = _5 + 3;
  __builtin_ia32_bndcu (_31, __bound_tmp.1_30);
  _13 = *_5;
  k2 ={v} {CLOBBER};

<L0> [0.00%]:
  return _13;
}

..which looks fine to me. And here is the dump-chkp for the basic case
of hard-reg-2:

__attribute__((chkp instrumented))
foo.chkp (int i)
{
  __bounds_type __bound_tmp.1;
  int D.2863;
  register v16 u __asm__ (*xmm0);
  int _3;
  long unsigned int _6;
  sizetype _7;
  void * _8;
  sizetype _9;
  sizetype _10;
  sizetype _11;
  sizetype _12;
  void * _13;

  <bb 5> [0.00%]:
  __bound_tmp.1_5 = __chkp_zero_bounds;
  __bound_tmp.1_4 = __builtin_ia32_bndmk (-2147483648B, 16);

  <bb 4> [0.00%]:

  <bb 2> [0.00%]:
  _6 = (long unsigned int) i_2(D);
  _7 = _6 * 4;
  _8 = -2147483648B + _7;
  __builtin_ia32_bndcl (_8, __bound_tmp.1_4);
  _9 = (sizetype) i_2(D);
  _10 = _9 + 1;
  _11 = _10 * 4;
  _12 = _11 + 18446744073709551615;
  _13 = -2147483648B + _12;
  __builtin_ia32_bndcu (_13, __bound_tmp.1_4);
  _3 = VIEW_CONVERT_EXPR<int[4]>(u)[i_2(D)];

<L0> [0.00%]:
  return _3;

}

So overall we have these fails (they all have the same backtrace as
PR80270) and other combinations pass:

FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
FAIL: gcc.target/i386/mpx/hard-reg-6-lbv.c   -O0  (internal compiler error)
FAIL: gcc.target/i386/mpx/hard-reg-6-lbv.c   -O0  (test for excess errors)



Here is the patch itself:
   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
@@ -679,6 +681,45 @@ chkp_erase_completed_bounds (void)
   chkp_completed_bounds_set = new hash_set<tree>;
 }

+/* This function is used to provide a base address for
+   chkp_get_hard_register_fake_addr_expr.  */
+static tree
+chkp_get_hard_register_var_fake_base_address ()
+{
+  tree base = fold_convert (ptr_type_node, integer_zero_node);
+  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
+  return fold_build_pointer_plus_hwi (base, offset);
+}
+
+/* If we check bounds for a hard register variable, we cannot
+   use its address - it is illegal, so instead of that we use
+   this fake value.  */
+static tree
+chkp_get_hard_register_fake_addr_expr (tree obj)
+{
+  tree addr = chkp_get_hard_register_var_fake_base_address ();
+  tree outer = obj;
+  while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF)
+    {
+      if (TREE_CODE (outer) == COMPONENT_REF)
+ {
+  addr = fold_build_pointer_plus (addr,
+  component_ref_field_offset (outer));
+  outer = TREE_OPERAND (outer, 0);
+ }
+      else if (TREE_CODE (outer) == ARRAY_REF)
+ {
+  tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1));
+  tree offset = size_binop (MULT_EXPR,
+    array_ref_element_size (outer), indx);
+  addr = fold_build_pointer_plus (addr, offset);
+  outer = TREE_OPERAND (outer, 0);
+ }
+    }
+
+  return addr;
+}
+
 /* Mark BOUNDS associated with PTR as incomplete.  */
 static void
 chkp_register_incomplete_bounds (tree bounds, tree ptr)
@@ -1044,6 +1085,12 @@ chkp_add_modification_to_stmt_list (tree lhs,
 static tree
 chkp_build_addr_expr (tree obj)
 {
+  /* We first check whether it is a "hard reg case".  */
+  tree base = get_base_address (obj);
+  if (VAR_P (base) && DECL_HARD_REGISTER (base))
+    return chkp_get_hard_register_fake_addr_expr (obj);
+
+  /* If not - return regular ADDR_EXPR.  */
   return TREE_CODE (obj) == TARGET_MEM_REF
     ? tree_mem_ref_addr (ptr_type_node, obj)
     : build_fold_addr_expr (obj);
@@ -3442,6 +3489,13 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
   || TREE_CODE (var) == SSA_NAME);

       *ptr = chkp_build_addr_expr (var);
+
+      /* For hard register cases chkp_build_addr_expr returns INTEGER_CST
+ and later on chkp_find_bounds will fail to find proper bounds.
+ In order to avoid that, we find/create bounds right aways using
+ the var itself.  */
+      if (DECL_HARD_REGISTER (var))
+ *bounds = chkp_make_addressed_object_bounds (var, iter);
     }

   /* In this loop we are trying to find a field access

2017-04-19 21:32 GMT+02:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
> 2017-04-19 19:48 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>> Hi,
>>
>> Thanks for the comments, that was a good idea to place all the logic inside
>> of chkp_build_addr_expr function. I followed it and here is what I got:
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2017-04-19  Alexander Ivchenko  <aivchenk@gmail.com>
>>
>>         * gcc.target/i386/mpx/hard-reg-2-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-2-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-2-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-1-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-1-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-1-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-2-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-2-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-2-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-3-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-4-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-4-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-4-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-1-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-1-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-1-ubv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-2-lbv.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-2-nov.c: New test.
>>         * gcc.target/i386/mpx/hard-reg-5-2-ubv.c: New test.
>>
>> gcc/ChangeLog:
>>
>> 2017-04-19  Alexander Ivchenko  <aivchenk@gmail.com>
>>
>>         * tree-chkp.c (chkp_get_hard_register_var_fake_base_address):
>> New function to provide a base address for.
>> chkp_get_hard_register_fake_addr_expr
>>         (chkp_get_hard_register_fake_addr_expr): New function to build
>> fake address expression for an expr that resides on a hard
>> register.
>>         (chkp_build_addr_expr): Add checks for hard reg cases.
>>         (chkp_parse_array_and_component_ref): Create/find bounds if the
>> var resides on a hard reg.
>>         (chkp_find_bounds_1): Check for hard register cases.
>>
>>
>>
>>
>>
>> And the patch itself:
>>
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>> new file mode 100644
>> index 0000000..319e1ec
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>> @@ -0,0 +1,21 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__((vector_size(16)));
>> +
>> +int foo(int i) {
>> +  register v16 u asm("xmm0");
>> +  return u[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>> new file mode 100644
>> index 0000000..3c6d39a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>> @@ -0,0 +1,18 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__((vector_size(16)));
>> +
>> +int foo (int i) {
>> +  register v16 u asm ("xmm0");
>> +  return u[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (3));
>> +  printf ("%d\n", foo (0));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>> new file mode 100644
>> index 0000000..7fe76c4
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>> @@ -0,0 +1,21 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__((vector_size(16)));
>> +
>> +int foo (int i) {
>> +  register v16 u asm ("xmm0");
>> +  return u[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (5));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>> new file mode 100644
>> index 0000000..7e4451f
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>> @@ -0,0 +1,33 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1.s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>> new file mode 100644
>> index 0000000..73bd7fb
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>> @@ -0,0 +1,30 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1.s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (0));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>> new file mode 100644
>> index 0000000..166b6b9
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>> @@ -0,0 +1,33 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1.s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (3));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>> new file mode 100644
>> index 0000000..7820c2f
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>> @@ -0,0 +1,33 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f2 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f2[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f2 (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>> new file mode 100644
>> index 0000000..0816e58
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>> @@ -0,0 +1,30 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f2 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f2[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f2 (0));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>> new file mode 100644
>> index 0000000..94261a7
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>> @@ -0,0 +1,33 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1;
>> +  v8 s2f2;
>> +};
>> +
>> +int foo_s2f2 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f2[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f2 (3));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>> new file mode 100644
>> index 0000000..f273d58
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>> @@ -0,0 +1,27 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__ ((vector_size (16)));
>> +
>> +struct S1
>> +{
>> +  v16 s1f1;
>> +};
>> +
>> +int foo_s1f1 (int i)
>> +{
>> +  register struct S1 b asm ("xmm0");
>> +  return b.s1f1[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s1f1 (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>> new file mode 100644
>> index 0000000..aa8f7b9
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>> @@ -0,0 +1,24 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__ ((vector_size (16)));
>> +
>> +struct S1
>> +{
>> +  v16 s1f1;
>> +};
>> +
>> +int foo_s1f1 (int i)
>> +{
>> +  register struct S1 b asm ("xmm0");
>> +  return b.s1f1[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s1f1 (0));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>> new file mode 100644
>> index 0000000..3d0c9b2
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>> @@ -0,0 +1,27 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v16 __attribute__ ((vector_size (16)));
>> +
>> +struct S1
>> +{
>> +  v16 s1f1;
>> +};
>> +
>> +int foo_s1f1 (int i)
>> +{
>> +  register struct S1 b asm ("xmm0");
>> +  return b.s1f1[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s1f1 (7));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>> new file mode 100644
>> index 0000000..e81b942
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>> @@ -0,0 +1,31 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S2
>> +{
>> +  v8 s2f2;
>> +  int* f3;
>> +};
>> +
>> +int foo (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  int k = 5;
>> +  b.f3 = &k;
>> +  b.f3 = b.f3 + i;
>> +  return *b.f3;
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>> new file mode 100644
>> index 0000000..4b1f1ac
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>> @@ -0,0 +1,28 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S2
>> +{
>> +  v8 s2f2;
>> +  int* f3;
>> +};
>> +
>> +int foo (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  int k = 5;
>> +  b.f3 = &k;
>> +  b.f3 = b.f3 + i;
>> +  return *b.f3;
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (0));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>> new file mode 100644
>> index 0000000..e95e68f
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>> @@ -0,0 +1,31 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S2
>> +{
>> +  v8 s2f2;
>> +  int* f3;
>> +};
>> +
>> +int foo (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  int k = 5;
>> +  b.f3 = &k;
>> +  b.f3 = b.f3 + i;
>> +  return *b.f3;
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo (1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>> new file mode 100644
>> index 0000000..201b62d
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>> @@ -0,0 +1,32 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[0].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>> new file mode 100644
>> index 0000000..f94a879
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>> @@ -0,0 +1,30 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[0].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>> new file mode 100644
>> index 0000000..6ab981d
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>> @@ -0,0 +1,32 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[0].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (4));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>> new file mode 100644
>> index 0000000..cc58e8a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>> @@ -0,0 +1,32 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[1].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (-1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>> new file mode 100644
>> index 0000000..5898c3b
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>> @@ -0,0 +1,30 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[1].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (1));
>> +  return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>> new file mode 100644
>> index 0000000..2910795
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>> @@ -0,0 +1,32 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "bounds violation" } */
>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>> +
>> +
>> +#define SHOULDFAIL
>> +
>> +#include "mpx-check.h"
>> +
>> +typedef int v8 __attribute__ ((vector_size (8)));
>> +
>> +struct S1
>> +{
>> +  v8 s1f;
>> +};
>> +
>> +struct S2
>> +{
>> +  struct S1 s2f1[2];
>> +};
>> +
>> +int foo_s2f1 (int i)
>> +{
>> +  register struct S2 b asm ("xmm0");
>> +  return b.s2f1[1].s1f[i];
>> +}
>> +
>> +int mpx_test (int argc, const char **argv)
>> +{
>> +  printf ("%d\n", foo_s2f1 (4));
>> +  return 0;
>> +}
>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>> index b1ff218..6a48a55 100644
>> --- a/gcc/tree-chkp.c
>> +++ b/gcc/tree-chkp.c
>> @@ -679,6 +679,46 @@ chkp_erase_completed_bounds (void)
>>    chkp_completed_bounds_set = new hash_set<tree>;
>>  }
>>
>> +/* This function is used to provide a base address for
>> +   chkp_get_hard_register_fake_addr_expr.  */
>> +static tree
>> +chkp_get_hard_register_var_fake_base_address ()
>> +{
>> +  tree base = fold_convert (ptr_type_node, integer_zero_node);
>> +  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
>> +  return fold_build_pointer_plus_hwi (base, offset);
>> +}
>> +
>> +/* If we check bounds for a hard register variable, we cannot
>> +   use its address - it is illegal, so instead of that we use
>> +   this fake value.  */
>> +static tree
>> +chkp_get_hard_register_fake_addr_expr (tree obj)
>> +{
>> +  tree addr = chkp_get_hard_register_var_fake_base_address ();
>> +  tree outer = obj;
>> +  while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF)
>> +    {
>> +      if (TREE_CODE (outer) == COMPONENT_REF)
>> + {
>> +  addr = fold_build_pointer_plus (addr,
>> +  component_ref_field_offset (outer));
>> +  outer = TREE_OPERAND (outer, 0);
>> + }
>> +      else if (TREE_CODE (outer) == ARRAY_REF)
>> + {
>> +  tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1));
>> +  tree offset = size_binop (MULT_EXPR,
>> +    array_ref_element_size (outer), indx);
>> +  addr = fold_build_pointer_plus (addr, offset);
>> +  outer = get_base_address (outer);
>
> Hi!
>
> I don't think get_base_address is what you want here because it goes to
> the most inner base.
>
>> + }
>> +    }
>> +  gcc_assert (VAR_P (outer) && DECL_HARD_REGISTER (outer));
>> +
>> +  return addr;
>> +}
>> +
>>  /* Mark BOUNDS associated with PTR as incomplete.  */
>>  static void
>>  chkp_register_incomplete_bounds (tree bounds, tree ptr)
>> @@ -1044,6 +1084,18 @@ chkp_add_modification_to_stmt_list (tree lhs,
>>  static tree
>>  chkp_build_addr_expr (tree obj)
>>  {
>> +  /* We first check whether it is a "hard reg case".  */
>> +  tree outer = obj;
>> +  while (TREE_CODE (outer) == COMPONENT_REF
>> + || TREE_CODE (outer) == ARRAY_REF)
>> +    if (TREE_CODE (outer) == COMPONENT_REF)
>> +      outer = TREE_OPERAND (outer, 0);
>> +    else
>> +      outer = get_base_address (outer);
>
> And here simple call to get_base_address might replace the whole loop.
>
>> +  if (VAR_P (outer) && DECL_HARD_REGISTER (outer))
>> +    return chkp_get_hard_register_fake_addr_expr (obj);
>> +
>> +  /* If not - return regular ADDR_EXPR.  */
>>    return TREE_CODE (obj) == TARGET_MEM_REF
>>      ? tree_mem_ref_addr (ptr_type_node, obj)
>>      : build_fold_addr_expr (obj);
>> @@ -3442,6 +3494,13 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>    || TREE_CODE (var) == SSA_NAME);
>>
>>        *ptr = chkp_build_addr_expr (var);
>> +
>> +      /* For hard register cases chkp_build_addr_expr returns INTEGER_CST
>> + and later on chkp_find_bounds will fail to find proper bounds.
>> + In order to avoid that, we find/create bounds right aways using
>> + the var itself.  */
>> +      if (DECL_HARD_REGISTER (var))
>> + *bounds = chkp_find_bounds (var, iter);
>
> Current semantics of this call is to get bounds for the pointer read from var.
> I know we never get here fo pointer vars but still...
>
> I propose to just call chkp_make_addressed_object_bounds here instead of
> chkp_find_bounds to avoid this non-intuitive interpretation of non-pointer
> hardreg variable in chkp_find_bounds_1.
>
> BTW what if we have a structure with a pointer field or vector of pointers?
> If we read this pointer then we might have some fun trying to find its bounds.
> Let's make a test! :)
>
> Also what code do we produce now? Do we create static bounds variable
> to hold fake bounds of hard reg variable? Is it initialized statically
> or dynamically?
>
>>      }
>>
>>    /* In this loop we are trying to find a field access
>> @@ -3639,6 +3698,8 @@ chkp_find_bounds_1 (tree ptr, tree ptr_src,
>> gimple_stmt_iterator *iter)
>>      addr = chkp_build_addr_expr (ptr_src);
>>      bounds = chkp_build_bndldx (addr, ptr, iter);
>>    }
>> +      else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>> + bounds = chkp_make_addressed_object_bounds (ptr_src, iter);
>>        else
>>   bounds = chkp_get_nonpointer_load_bounds ();
>>        break;
>>
>>
>>
>>
>>
>> As before, the following added testcases fail because of PR80270:
>
> That makes hard to confirm patch correctness. Please at least check
> GIMPLE for some of these tests are produced correctly by chkp phase.
>
> Overall this version looks much simpler and better. New MPX feature
> to catch non-memory bounds violation is almost done!
>
> Thanks,
> Ilya
>
>>
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>>
>> hard-reg-4-* looks suspicious to me. May be we need to handle that
>> case differently, but it is hard to say because of the ICE now.
>>
>>
>> 2017-04-10 23:21 GMT+02:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>>> 2017-04-02 23:52 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>>> Hi,
>>>>
>>>> Here is the patch that roughly follows your idea.
>>>> Some comments:
>>>>
>>>> - There are more cases than array_ref overflow. We need to take care
>>>> of component_ref and both underflows/overflows are possible
>>>> - I could not make it work with "0" as a fake address, because then
>>>> catching lower bounds violation is getting hard at O2 and above. E.g.
>>>> consider this:
>>>>
>>>>    0x00000000004005f8 <+8>:     bndmk  0x7(%rax),%bnd0
>>>>    0x00000000004005fd <+13>:    mov    $0x400734,%edi
>>>> => 0x0000000000400602 <+18>:    bndcl  0xfffffffffffffffc,%bnd0
>>>>             (gdb) p $bnd0
>>>>             $1 = {lbound = 0x0, ubound = 0x7} : size 8
>>>>   0x000000000040060b <+27>:    callq  0x400500 <printf@plt>
>>>>
>>>>     - bndcu is removed as not necessary and underflowed access is not
>>>> caught. I used another fake value for lower bound address, which is
>>>> 2^(bitness - 1)
>>>
>>> Hi,
>>>
>>> Looks like CHKP optimizations don't let us catch cases when pointer
>>> arithmetc overflows. Using any fake value doesn't guarantee you don't
>>> have overflow.
>>>
>>> This overoptimization is definately a separate issue. It should be easy
>>> to write a test where usage of a huge index in array causes
>>> uncought bounds violation because of removed bndcl/bndcu. You should
>>> file a bug for that.
>>>
>>> If we don't try to work around overflow issues in this patch then using 0
>>> should be more efficient because it allows you to always use bndcu only
>>> (you just can't violate zero lower bound).
>>>
>>> BTW please don't forget ChangeLogs for your patches.
>>>
>>>>
>>>> - hard-reg-3-[1,2]* tests fail with ICE right now because of PR80270.
>>>> I will mark them as XFAIL if the patch is approved and the mentioned
>>>> bug is not fixed
>>>>
>>>>
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>> new file mode 100644
>>>> index 0000000..319e1ec
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>> @@ -0,0 +1,21 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>> +
>>>> +int foo(int i) {
>>>> +  register v16 u asm("xmm0");
>>>> +  return u[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (-1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>> new file mode 100644
>>>> index 0000000..3c6d39a
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>> @@ -0,0 +1,18 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>> +
>>>> +int foo (int i) {
>>>> +  register v16 u asm ("xmm0");
>>>> +  return u[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (3));
>>>> +  printf ("%d\n", foo (0));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>> new file mode 100644
>>>> index 0000000..7fe76c4
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>> @@ -0,0 +1,21 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>> +
>>>> +int foo (int i) {
>>>> +  register v16 u asm ("xmm0");
>>>> +  return u[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (5));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>> new file mode 100644
>>>> index 0000000..7e4451f
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>> @@ -0,0 +1,33 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f1 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f1.s1f[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f1 (-1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>> new file mode 100644
>>>> index 0000000..73bd7fb
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>> @@ -0,0 +1,30 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f1 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f1.s1f[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f1 (0));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>> new file mode 100644
>>>> index 0000000..166b6b9
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>> @@ -0,0 +1,33 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f1 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f1.s1f[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f1 (3));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>> new file mode 100644
>>>> index 0000000..7820c2f
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>> @@ -0,0 +1,33 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f2 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f2[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f2 (-1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>> new file mode 100644
>>>> index 0000000..0816e58
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>> @@ -0,0 +1,30 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f2 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f2[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f2 (0));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>> new file mode 100644
>>>> index 0000000..94261a7
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>> @@ -0,0 +1,33 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v8 s1f;
>>>> +};
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  struct S1 s2f1;
>>>> +  v8 s2f2;
>>>> +};
>>>> +
>>>> +int foo_s2f2 (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  return b.s2f2[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s2f2 (3));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>> new file mode 100644
>>>> index 0000000..f273d58
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>> @@ -0,0 +1,27 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v16 s1f1;
>>>> +};
>>>> +
>>>> +int foo_s1f1 (int i)
>>>> +{
>>>> +  register struct S1 b asm ("xmm0");
>>>> +  return b.s1f1[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s1f1 (-1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>> new file mode 100644
>>>> index 0000000..aa8f7b9
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>> @@ -0,0 +1,24 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v16 s1f1;
>>>> +};
>>>> +
>>>> +int foo_s1f1 (int i)
>>>> +{
>>>> +  register struct S1 b asm ("xmm0");
>>>> +  return b.s1f1[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s1f1 (0));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>> new file mode 100644
>>>> index 0000000..3d0c9b2
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>> @@ -0,0 +1,27 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>> +
>>>> +struct S1
>>>> +{
>>>> +  v16 s1f1;
>>>> +};
>>>> +
>>>> +int foo_s1f1 (int i)
>>>> +{
>>>> +  register struct S1 b asm ("xmm0");
>>>> +  return b.s1f1[i];
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo_s1f1 (7));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>> new file mode 100644
>>>> index 0000000..e81b942
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>> @@ -0,0 +1,31 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  v8 s2f2;
>>>> +  int* f3;
>>>> +};
>>>> +
>>>> +int foo (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  int k = 5;
>>>> +  b.f3 = &k;
>>>> +  b.f3 = b.f3 + i;
>>>> +  return *b.f3;
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (-1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>> new file mode 100644
>>>> index 0000000..4b1f1ac
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>> @@ -0,0 +1,28 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  v8 s2f2;
>>>> +  int* f3;
>>>> +};
>>>> +
>>>> +int foo (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  int k = 5;
>>>> +  b.f3 = &k;
>>>> +  b.f3 = b.f3 + i;
>>>> +  return *b.f3;
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (0));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>> new file mode 100644
>>>> index 0000000..e95e68f
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>> @@ -0,0 +1,31 @@
>>>> +/* { dg-do run } */
>>>> +/* { dg-shouldfail "bounds violation" } */
>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>> +
>>>> +
>>>> +#define SHOULDFAIL
>>>> +
>>>> +#include "mpx-check.h"
>>>> +
>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>> +
>>>> +struct S2
>>>> +{
>>>> +  v8 s2f2;
>>>> +  int* f3;
>>>> +};
>>>> +
>>>> +int foo (int i)
>>>> +{
>>>> +  register struct S2 b asm ("xmm0");
>>>> +  int k = 5;
>>>> +  b.f3 = &k;
>>>> +  b.f3 = b.f3 + i;
>>>> +  return *b.f3;
>>>> +}
>>>> +
>>>> +int mpx_test (int argc, const char **argv)
>>>> +{
>>>> +  printf ("%d\n", foo (1));
>>>> +  return 0;
>>>> +}
>>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>>> index b1ff218..15c0da6 100644
>>>> --- a/gcc/tree-chkp.c
>>>> +++ b/gcc/tree-chkp.c
>>>> @@ -679,6 +679,17 @@ chkp_erase_completed_bounds (void)
>>>>    chkp_completed_bounds_set = new hash_set<tree>;
>>>>  }
>>>>
>>>> +/* If we check bounds for a hard register variable, we cannot
>>>> +   use its address - it is illegal, so instead of that we use
>>>> +   this fake value.  */
>>>> +static tree
>>>> +chkp_get_hard_register_var_fake_address ()
>>>> +{
>>>> +  tree base = fold_convert (ptr_type_node, integer_zero_node);
>>>> +  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
>>>> +  return fold_build_pointer_plus_hwi (base, offset);
>>>> +}
>>>> +
>>>>  /* Mark BOUNDS associated with PTR as incomplete.  */
>>>>  static void
>>>>  chkp_register_incomplete_bounds (tree bounds, tree ptr)
>>>> @@ -1040,10 +1051,24 @@ chkp_add_modification_to_stmt_list (tree lhs,
>>>>    stmts->avail--;
>>>>  }
>>>>
>>>> -/* Build and return ADDR_EXPR for specified object OBJ.  */
>>>> +/* Build and return ADDR_EXPR for specified object OBJ.
>>>> +   There is a special case for which we cannot return
>>>> +   ADDR_EXPR - if the object is declared to be placed
>>>> +   on a fixed hard register - in this case we cannot
>>>> +   take its address, so we use the object itself. The
>>>> +   caller of this function must be aware of that and
>>>> +   use proper checks if necessary.  */
>>>
>>> I don't follow the idea of this change.
>>>
>>> If we want to use fake address for register vars then why not to
>>> return this fake value by this function? In case of accessing a
>>> component of register var we should return fake value + required
>>> offset then.
>>>
>>>>  static tree
>>>>  chkp_build_addr_expr (tree obj)
>>>>  {
>>>> +  /* We first check whether it is a "hard reg case".  */
>>>> +  tree outer = obj;
>>>> +  while (TREE_CODE (outer) == COMPONENT_REF)
>>>> +    outer = TREE_OPERAND (outer, 0);
>>>
>>> What about ARRAY_REF? Probably get_base_address is what you need.
>>>
>>>> +  if (VAR_P (outer) && DECL_HARD_REGISTER (outer))
>>>> +      return obj;
>>>> +
>>>> +  /* If not - return regular ADDR_EXPR.  */
>>>>    return TREE_CODE (obj) == TARGET_MEM_REF
>>>>      ? tree_mem_ref_addr (ptr_type_node, obj)
>>>>      : build_fold_addr_expr (obj);
>>>> @@ -3170,6 +3195,11 @@ chkp_get_bounds_for_decl_addr (tree decl)
>>>>        gcc_assert (VAR_P (decl));
>>>>        bounds = chkp_generate_extern_var_bounds (decl);
>>>>      }
>>>> +  else if (VAR_P (decl) && DECL_HARD_REGISTER (decl))
>>>> +    {
>>>> +      tree lb = chkp_get_hard_register_var_fake_address ();
>>>> +      bounds = chkp_make_bounds(lb, DECL_SIZE_UNIT (decl), NULL, false);
>>>> +    }
>>>>    else
>>>>      {
>>>>        tree lb = chkp_build_addr_expr (decl);
>>>> @@ -3351,6 +3381,8 @@ chkp_narrow_bounds_to_field (tree bounds, tree component,
>>>>    tree field_ptr = chkp_build_addr_expr (component);
>>>>    tree field_bounds;
>>>>
>>>> +  if (!BOUNDED_P (field_ptr))
>>>> +    field_ptr = chkp_get_hard_register_var_fake_address ();
>>>
>>> This gives you fake pointer instead of fake pointer + offset. No?
>>>
>>>>    field_bounds = chkp_make_bounds (field_ptr, size, iter, false);
>>>>
>>>>    return chkp_intersect_bounds (field_bounds, bounds, iter);
>>>> @@ -3639,6 +3671,8 @@ chkp_find_bounds_1 (tree ptr, tree ptr_src,
>>>> gimple_stmt_iterator *iter)
>>>>      addr = chkp_build_addr_expr (ptr_src);
>>>>      bounds = chkp_build_bndldx (addr, ptr, iter);
>>>>    }
>>>> +      else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>>>> + bounds = chkp_make_addressed_object_bounds (ptr_src, iter);
>>>
>>> I don't get what this piece of code is for.
>>>
>>>>        else
>>>>   bounds = chkp_get_nonpointer_load_bounds ();
>>>>        break;
>>>> @@ -4031,7 +4065,19 @@ chkp_process_stmt (gimple_stmt_iterator *iter, tree node,
>>>>        addr_first,
>>>>        byte_position (field));
>>>>            }
>>>> -        else
>>>> +        else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>>>> +  {
>>>> +    gcc_assert (TREE_CODE (node) == ARRAY_REF
>>>> + || TREE_CODE (node) == COMPONENT_REF);
>>>
>>> This may never hit because this code is in a switch block filtering
>>> node to ARRAY_REF and COMPONENT_REF already.
>>>
>>>> +
>>>> +    tree base = chkp_get_hard_register_var_fake_address ();
>>>> +    tree indx = fold_convert_loc (loc,
>>>> +  size_type_node,
>>>> +  TREE_OPERAND (node, 1));
>>>
>>> Code looks like it expects ARRAY_REF only but COMPONENT_REF
>>> is also possible.
>>>
>>>> +    tree offset = size_binop_loc (loc, MULT_EXPR, size, indx);
>>>
>>> 'size' here holds a size of memory access, not size of array element.
>>>
>>> Overall it looks like all you need is a proper fix in chkp_build_addr_expr
>>> to use fake value when required. Many (all?) other changes might just
>>> go away then.
>>>
>>> Thanks,
>>> Ilya
>>>
>>>> +    addr_first = fold_build_pointer_plus_loc (loc, base, offset);
>>>> +  }
>>>> + else
>>>>            addr_first = chkp_build_addr_expr (node);
>>>>        }
>>>>        break;
>>>>
>>>> 2017-03-23 20:57 GMT+01:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>>>>> 2017-03-23 17:18 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>>>>> Hi,
>>>>>>
>>>>>> The patch below attempts to fix the PR. I checked that it did not
>>>>>> break any of mpx.exp tests, but I did not run the full testing yet.
>>>>>> Would like to know whether this approach is generally correct or not.
>>>>>>
>>>>>> The issue is that we have the hard reg vector variable:
>>>>>>
>>>>>> typedef int U __attribute__ ((vector_size (16)));
>>>>>> register U u asm("xmm0");
>>>>>>
>>>>>> and chkp tries to instrument access to it:
>>>>>>
>>>>>> return u[i];
>>>>>>
>>>>>> by doing that:
>>>>>>
>>>>>> __bound_tmp.0_4 = __builtin_ia32_bndmk (&u, 16);
>>>>>>
>>>>>> However, you cannot take an address of a register variable (in fact if
>>>>>> you do that, the compiler will give you "address of register variable
>>>>>> ā€˜uā€™ requested" error), so expand, sensibly, gives an ICE on on &u
>>>>>> here. I believe that if there is no pointers, pointer bounds checker
>>>>>> shouldn't get involved into that business. What do you think?
>>>>>
>>>>> Hi!
>>>>>
>>>>> I think with this patch I can call foo with any index and thus access
>>>>> some random stack slot. The first thing we should answer is 'do we
>>>>> want to catch array index overflows in such cases'? If we want to (and
>>>>> this looks reasonable thing to do because it prevents invalid memory
>>>>> accesses) then this patch doesn't resolve the problem.
>>>>>
>>>>> I'm not sure it can affect the patch, but please consider more complex
>>>>> cases. E.g.:
>>>>>
>>>>> typedef int v8 __attribute__ ((vector_size(8)));
>>>>>
>>>>> struct U {
>>>>>   v8 a;
>>>>>   v8 b;
>>>>> };
>>>>>
>>>>> int
>>>>> foo (int i)
>>>>> {
>>>>>   register struct U u asm ("xmm0");
>>>>>   return u.b[i];
>>>>> }
>>>>>
>>>>> One way to catch overflow in such cases might be to use some fake
>>>>> pointer value (e.g. 0) for such not addressible variable. This fake value
>>>>> would be used as base for memory access and as lower bound. I don't
>>>>> see other cases except array_ref overflow check where such value
>>>>> might be used. So this fake value will not be passed somewhere and
>>>>> will not be stored to Bounds Table.
>>>>>
>>>>> Thanks,
>>>>> Ilya
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>>>>> index 75caf83..e39ec9a 100644
>>>>>> --- a/gcc/tree-chkp.c
>>>>>> +++ b/gcc/tree-chkp.c
>>>>>> @@ -3383,6 +3383,7 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>    tree comp_to_narrow = NULL_TREE;
>>>>>>    tree last_comp = NULL_TREE;
>>>>>>    bool array_ref_found = false;
>>>>>> +  bool is_register_var = false;
>>>>>>    tree *nodes;
>>>>>>    tree var;
>>>>>>    int len;
>>>>>> @@ -3440,6 +3441,9 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>                   || TREE_CODE (var) == STRING_CST
>>>>>>                   || TREE_CODE (var) == SSA_NAME);
>>>>>>
>>>>>> +      if (VAR_P (var) && DECL_HARD_REGISTER (var))
>>>>>> +       is_register_var = true;
>>>>>> +
>>>>>>        *ptr = chkp_build_addr_expr (var);
>>>>>>      }
>>>>>>
>>>>>> @@ -3455,7 +3459,11 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>
>>>>>>        if (TREE_CODE (var) == ARRAY_REF)
>>>>>>         {
>>>>>> -         *safe = false;
>>>>>> +         // Mark it as unsafe, unless the array being accessed
>>>>>> +         // has been explicitly placed on a register: in this
>>>>>> +         // case we cannot take a pointer of this variable,
>>>>>> +         // so we don't instrument the access.
>>>>>> +         *safe = is_register_var;
>>>>>>           array_ref_found = true;
>>>>>>           if (flag_chkp_narrow_bounds
>>>>>>               && !flag_chkp_narrow_to_innermost_arrray
>>>>>> @@ -4001,6 +4009,19 @@ chkp_process_stmt (gimple_stmt_iterator *iter, tree node,
>>>>>>         bool bitfield;
>>>>>>         tree elt;
>>>>>>
>>>>>> +       {
>>>>>> +         // We don't instrument accesses to arrays that
>>>>>> +         // are explicitely assigned to hard registers.
>>>>>> +         HOST_WIDE_INT bitsize, bitpos;
>>>>>> +         tree base, offset;
>>>>>> +         machine_mode mode;
>>>>>> +         int unsignedp, reversep, volatilep = 0;
>>>>>> +         base = get_inner_reference (node, &bitsize, &bitpos, &offset, &mode,
>>>>>> +                                     &unsignedp, &reversep, &volatilep);
>>>>>> +         if (VAR_P (base) && DECL_HARD_REGISTER (base))
>>>>>> +           safe = true;
>>>>>> +       }
>>>>>> +
>>>>>>         if (safe)
>>>>>>           {
>>>>>>             /* We are not going to generate any checks, so do not
>>>>>>
>>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>> b/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>> new file mode 100644
>>>>>> index 0000000..a27734d
>>>>>> --- /dev/null
>>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>> @@ -0,0 +1,18 @@
>>>>>> +/* { dg-do compile } */
>>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>>> +
>>>>>> +typedef int U __attribute__ ((vector_size (16)));
>>>>>> +
>>>>>> +int
>>>>>> +foo (int i)
>>>>>> +{
>>>>>> +#if __SSE2__
>>>>>> +  register
>>>>>> +#endif
>>>>>> +    U u
>>>>>> +#if __SSE2__
>>>>>> +      asm ("xmm0")
>>>>>> +#endif
>>>>>> +      ;
>>>>>> +  return u[i];
>>>>>> +}
>>>>>>
>>>>>> regards,
>>>>>> Alexander

Comments

Ilya Enkovich April 20, 2017, 5:17 p.m.
2017-04-20 12:27 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
> Thanks for correcting the usage of get_base_address. I fixed that.
> Plus addressed the comment about the avoiding the usage of
> chkp_find_bounds.
>
>
> gcc/testsuite/ChangeLog:
>
> 2017-04-20  Alexander Ivchenko  <alexander.ivchenko@intel.com>
>
>         * gcc.target/i386/mpx/hard-reg-2-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-2-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-2-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-1-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-1-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-1-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-2-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-2-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-2-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-3-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-4-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-4-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-4-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-1-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-1-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-1-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-2-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-2-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-5-2-ubv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-6-lbv.c: New test.
>         * gcc.target/i386/mpx/hard-reg-6-nov.c: New test.
>         * gcc.target/i386/mpx/hard-reg-6-ubv.c: New test.
>
> gcc/ChangeLog:
>
> 2017-04-20  Alexander Ivchenko  <alexander.ivchenko@intel.com>
>
>         * tree-chkp.c (chkp_get_hard_register_var_fake_base_address):
> New function to provide a base address for
> chkp_get_hard_register_fake_addr_expr.
>         (chkp_get_hard_register_fake_addr_expr): New function to build
> fake address expression for an expr that resides on a hard
> register.
>         (chkp_build_addr_expr): Add checks for hard reg cases.
>         (chkp_parse_array_and_component_ref): Create/find bounds if the
> var resides on a hard reg.
>
>
> I already had a testcases for struct with a pointer - "hard-reg-4-*".
> Here is the instrumentation of the foo function:
>
> __attribute__((chkp instrumented))
> foo.chkp (int i)
> {
>   __bounds_type __bound_tmp.1;
>   register struct S2 b __asm__ (*xmm0);
>   int k;
>   int * _1;
>   long unsigned int _2;
>   long unsigned int _3;
>   int * _4;
>   int * _5;
>   int _11;
>   int * _18;
>
>   <bb 4> [0.00%]:
>   __bound_tmp.1_17 = __chkp_zero_bounds;
>   __bound_tmp.1_14 = __builtin_ia32_bndmk (&k, 4);
>   __bound_tmp.1_13 = __builtin_ia32_bndmk (-2147483648B, 16);
>
>   <bb 3> [0.00%]:
>
>   <bb 2> [0.00%]:
>   k = 5;
>   b.f3 = &k;
>   __builtin_ia32_bndstx (&k, __bound_tmp.1_14, -2147483648B);
>   _1 = b.f3;
>   __bound_tmp.1_15 = __builtin_ia32_bndldx (-2147483648B, _1);
>   _2 = (long unsigned int) i_9(D);
>   _3 = _2 * 4;
>   _4 = _1 + _3;
>   b.f3 = _4;
>   __builtin_ia32_bndstx (_4, __bound_tmp.1_15, -2147483648B);
>   _5 = b.f3;
>   __bound_tmp.1_16 = __builtin_ia32_bndldx (-2147483648B, _5);
>   __builtin_ia32_bndcl (_5, __bound_tmp.1_16);
>   _18 = _5 + 3;
>   __builtin_ia32_bndcu (_18, __bound_tmp.1_16);
>   _11 = *_5;
>   k ={v} {CLOBBER};
>   return _11;
>
> }
>
> Which is the most suspicious one, because we have ldx and stx. I'm not
> sure whether this is OK.

It is not OK because single entry in BT may be used by multiple hardreg
variables. There is a code in chkp_find_bounds_1 to use zero bounds in
case we load bounds from register var. I believe here we should do the
same. In chkp_find_bounds_1 at ARRAY_REF/COMPONENT_REF
case check if addr is register var and use zero bounds.

Thanks,
Ilya


>
> Here is the chkp dump for foo function of newly added hard-reg-6* case:
>
> __attribute__((chkp instrumented))
> foo.chkp (int i, int * kp1, __bounds_type __chkp_bounds_of_kp1)
> {
>   __bounds_type __bound_tmp.1;
>   int D.2873;
>   register struct S2 b __asm__ (*xmm0);
>   int k2;
>   int * _1;
>   long unsigned int _2;
>   long unsigned int _3;
>   int * _4;
>   int * _5;
>   int _13;
>   int * _31;
>
>   <bb 5> [0.00%]:
>   __bound_tmp.1_22 = __builtin_ia32_bndmk (&k2, 4);
>   __bound_tmp.1_17 = __chkp_zero_bounds;
>   __bound_tmp.1_15 = __builtin_ia32_bndmk (-2147483648B, 16);
>
>   <bb 4> [0.00%]:
>
>   <bb 2> [0.00%]:
>   k2 = 5;
>   __bound_tmp.1_16 = __builtin_ia32_bndmk (-2147483648B, 16);
>   __bound_tmp.1_18 = __builtin_ia32_bndint (__bound_tmp.1_16, __bound_tmp.1_15);
>   __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_18);
>   __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_18);
>   b.f[0] = kp1_8(D);
>   __builtin_ia32_bndstx (kp1_8(D), __chkp_bounds_of_kp1_19(D), -2147483648B);
>   __bound_tmp.1_20 = __builtin_ia32_bndmk (-2147483648B, 16);
>   __bound_tmp.1_21 = __builtin_ia32_bndint (__bound_tmp.1_20, __bound_tmp.1_15);
>   __builtin_ia32_bndcl (-2147483640B, __bound_tmp.1_21);
>   __builtin_ia32_bndcu (-2147483633B, __bound_tmp.1_21);
>   b.f[1] = &k2;
>   __builtin_ia32_bndstx (&k2, __bound_tmp.1_22, -2147483640B);
>   __bound_tmp.1_23 = __builtin_ia32_bndmk (-2147483648B, 16);
>   __bound_tmp.1_24 = __builtin_ia32_bndint (__bound_tmp.1_23, __bound_tmp.1_15);
>   __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_24);
>   __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_24);
>   _1 = b.f[0];
>   __bound_tmp.1_27 = __builtin_ia32_bndldx (-2147483648B, _1);
>   _2 = (long unsigned int) i_11(D);
>   _3 = _2 * 4;
>   _4 = _1 + _3;
>   __bound_tmp.1_25 = __builtin_ia32_bndmk (-2147483648B, 16);
>   __bound_tmp.1_26 = __builtin_ia32_bndint (__bound_tmp.1_25, __bound_tmp.1_15);
>   __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_26);
>   __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_26);
>   b.f[0] = _4;
>   __builtin_ia32_bndstx (_4, __bound_tmp.1_27, -2147483648B);
>   __bound_tmp.1_28 = __builtin_ia32_bndmk (-2147483648B, 16);
>   __bound_tmp.1_29 = __builtin_ia32_bndint (__bound_tmp.1_28, __bound_tmp.1_15);
>   __builtin_ia32_bndcl (-2147483648B, __bound_tmp.1_29);
>   __builtin_ia32_bndcu (-2147483641B, __bound_tmp.1_29);
>   _5 = b.f[0];
>   __bound_tmp.1_30 = __builtin_ia32_bndldx (-2147483648B, _5);
>   __builtin_ia32_bndcl (_5, __bound_tmp.1_30);
>   _31 = _5 + 3;
>   __builtin_ia32_bndcu (_31, __bound_tmp.1_30);
>   _13 = *_5;
>   k2 ={v} {CLOBBER};
>
> <L0> [0.00%]:
>   return _13;
> }
>
> ..which looks fine to me. And here is the dump-chkp for the basic case
> of hard-reg-2:
>
> __attribute__((chkp instrumented))
> foo.chkp (int i)
> {
>   __bounds_type __bound_tmp.1;
>   int D.2863;
>   register v16 u __asm__ (*xmm0);
>   int _3;
>   long unsigned int _6;
>   sizetype _7;
>   void * _8;
>   sizetype _9;
>   sizetype _10;
>   sizetype _11;
>   sizetype _12;
>   void * _13;
>
>   <bb 5> [0.00%]:
>   __bound_tmp.1_5 = __chkp_zero_bounds;
>   __bound_tmp.1_4 = __builtin_ia32_bndmk (-2147483648B, 16);
>
>   <bb 4> [0.00%]:
>
>   <bb 2> [0.00%]:
>   _6 = (long unsigned int) i_2(D);
>   _7 = _6 * 4;
>   _8 = -2147483648B + _7;
>   __builtin_ia32_bndcl (_8, __bound_tmp.1_4);
>   _9 = (sizetype) i_2(D);
>   _10 = _9 + 1;
>   _11 = _10 * 4;
>   _12 = _11 + 18446744073709551615;
>   _13 = -2147483648B + _12;
>   __builtin_ia32_bndcu (_13, __bound_tmp.1_4);
>   _3 = VIEW_CONVERT_EXPR<int[4]>(u)[i_2(D)];
>
> <L0> [0.00%]:
>   return _3;
>
> }
>
> So overall we have these fails (they all have the same backtrace as
> PR80270) and other combinations pass:
>
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
> FAIL: gcc.target/i386/mpx/hard-reg-6-lbv.c   -O0  (internal compiler error)
> FAIL: gcc.target/i386/mpx/hard-reg-6-lbv.c   -O0  (test for excess errors)
>
>
>
> Here is the patch itself:
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
> new file mode 100644
> index 0000000..319e1ec
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
> @@ -0,0 +1,21 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__((vector_size(16)));
> +
> +int foo(int i) {
> +  register v16 u asm("xmm0");
> +  return u[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
> new file mode 100644
> index 0000000..3c6d39a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
> @@ -0,0 +1,18 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__((vector_size(16)));
> +
> +int foo (int i) {
> +  register v16 u asm ("xmm0");
> +  return u[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (3));
> +  printf ("%d\n", foo (0));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
> new file mode 100644
> index 0000000..7fe76c4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
> @@ -0,0 +1,21 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__((vector_size(16)));
> +
> +int foo (int i) {
> +  register v16 u asm ("xmm0");
> +  return u[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (5));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
> new file mode 100644
> index 0000000..7e4451f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
> @@ -0,0 +1,33 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1.s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
> new file mode 100644
> index 0000000..73bd7fb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
> @@ -0,0 +1,30 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1.s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (0));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
> new file mode 100644
> index 0000000..166b6b9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
> @@ -0,0 +1,33 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1.s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (3));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
> new file mode 100644
> index 0000000..7820c2f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
> @@ -0,0 +1,33 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f2 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f2[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f2 (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
> new file mode 100644
> index 0000000..0816e58
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
> @@ -0,0 +1,30 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f2 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f2[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f2 (0));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
> new file mode 100644
> index 0000000..94261a7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
> @@ -0,0 +1,33 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1;
> +  v8 s2f2;
> +};
> +
> +int foo_s2f2 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f2[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f2 (3));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
> new file mode 100644
> index 0000000..f273d58
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
> @@ -0,0 +1,27 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__ ((vector_size (16)));
> +
> +struct S1
> +{
> +  v16 s1f1;
> +};
> +
> +int foo_s1f1 (int i)
> +{
> +  register struct S1 b asm ("xmm0");
> +  return b.s1f1[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s1f1 (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
> new file mode 100644
> index 0000000..aa8f7b9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
> @@ -0,0 +1,24 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__ ((vector_size (16)));
> +
> +struct S1
> +{
> +  v16 s1f1;
> +};
> +
> +int foo_s1f1 (int i)
> +{
> +  register struct S1 b asm ("xmm0");
> +  return b.s1f1[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s1f1 (0));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
> new file mode 100644
> index 0000000..3d0c9b2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
> @@ -0,0 +1,27 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v16 __attribute__ ((vector_size (16)));
> +
> +struct S1
> +{
> +  v16 s1f1;
> +};
> +
> +int foo_s1f1 (int i)
> +{
> +  register struct S1 b asm ("xmm0");
> +  return b.s1f1[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s1f1 (7));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
> new file mode 100644
> index 0000000..e81b942
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  v8 s2f2;
> +  int* f3;
> +};
> +
> +int foo (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k = 5;
> +  b.f3 = &k;
> +  b.f3 = b.f3 + i;
> +  return *b.f3;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
> new file mode 100644
> index 0000000..4b1f1ac
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
> @@ -0,0 +1,28 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  v8 s2f2;
> +  int* f3;
> +};
> +
> +int foo (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k = 5;
> +  b.f3 = &k;
> +  b.f3 = b.f3 + i;
> +  return *b.f3;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (0));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
> new file mode 100644
> index 0000000..e95e68f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  v8 s2f2;
> +  int* f3;
> +};
> +
> +int foo (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k = 5;
> +  b.f3 = &k;
> +  b.f3 = b.f3 + i;
> +  return *b.f3;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo (1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
> new file mode 100644
> index 0000000..201b62d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[0].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
> new file mode 100644
> index 0000000..f94a879
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
> @@ -0,0 +1,30 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[0].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
> new file mode 100644
> index 0000000..6ab981d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[0].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (4));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
> new file mode 100644
> index 0000000..cc58e8a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[1].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (-1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
> new file mode 100644
> index 0000000..5898c3b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
> @@ -0,0 +1,30 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[1].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
> new file mode 100644
> index 0000000..2910795
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S1
> +{
> +  v8 s1f;
> +};
> +
> +struct S2
> +{
> +  struct S1 s2f1[2];
> +};
> +
> +int foo_s2f1 (int i)
> +{
> +  register struct S2 b asm ("xmm0");
> +  return b.s2f1[1].s1f[i];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  printf ("%d\n", foo_s2f1 (4));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
> new file mode 100644
> index 0000000..b160915
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
> @@ -0,0 +1,34 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  int* f[2];
> +};
> +
> +int foo (int i, int *kp1)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k2 = 5;
> +
> +  b.f[0] = kp1;
> +  b.f[1] = &k2;
> +
> +  b.f[1] = b.f[1] + i;
> +  return *b.f[1];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  int k1 = 10;
> +  printf ("%d\n", foo (-1, &k1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
> new file mode 100644
> index 0000000..584b3e5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  int* f[2];
> +};
> +
> +int foo (int i, int *kp1)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k2 = 5;
> +
> +  b.f[0] = kp1;
> +  b.f[1] = &k2;
> +
> +  b.f[0] = b.f[0] + i;
> +  return *b.f[0];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  int k1 = 10;
> +  printf ("%d\n", foo (0, &k1));
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
> new file mode 100644
> index 0000000..92fa793
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
> @@ -0,0 +1,34 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +typedef int v8 __attribute__ ((vector_size (8)));
> +
> +struct S2
> +{
> +  int* f[2];
> +};
> +
> +int foo (int i, int *kp1)
> +{
> +  register struct S2 b asm ("xmm0");
> +  int k2 = 5;
> +
> +  b.f[0] = kp1;
> +  b.f[1] = &k2;
> +
> +  b.f[0] = b.f[0] + i;
> +  return *b.f[0];
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  int k1 = 10;
> +  printf ("%d\n", foo (1, &k1));
> +  return 0;
> +}
> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
> index b1ff218..3ef73a9 100644
> --- a/gcc/tree-chkp.c
> +++ b/gcc/tree-chkp.c
> @@ -327,6 +327,8 @@ static void chkp_parse_array_and_component_ref
> (tree node, tree *ptr,
>   bool innermost_bounds);
>  static void chkp_parse_bit_field_ref (tree node, location_t loc,
>        tree *offset, tree *size);
> +static tree
> +chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter);
>
>  #define chkp_bndldx_fndecl \
>    (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
> @@ -679,6 +681,45 @@ chkp_erase_completed_bounds (void)
>    chkp_completed_bounds_set = new hash_set<tree>;
>  }
>
> +/* This function is used to provide a base address for
> +   chkp_get_hard_register_fake_addr_expr.  */
> +static tree
> +chkp_get_hard_register_var_fake_base_address ()
> +{
> +  tree base = fold_convert (ptr_type_node, integer_zero_node);
> +  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
> +  return fold_build_pointer_plus_hwi (base, offset);
> +}
> +
> +/* If we check bounds for a hard register variable, we cannot
> +   use its address - it is illegal, so instead of that we use
> +   this fake value.  */
> +static tree
> +chkp_get_hard_register_fake_addr_expr (tree obj)
> +{
> +  tree addr = chkp_get_hard_register_var_fake_base_address ();
> +  tree outer = obj;
> +  while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF)
> +    {
> +      if (TREE_CODE (outer) == COMPONENT_REF)
> + {
> +  addr = fold_build_pointer_plus (addr,
> +  component_ref_field_offset (outer));
> +  outer = TREE_OPERAND (outer, 0);
> + }
> +      else if (TREE_CODE (outer) == ARRAY_REF)
> + {
> +  tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1));
> +  tree offset = size_binop (MULT_EXPR,
> +    array_ref_element_size (outer), indx);
> +  addr = fold_build_pointer_plus (addr, offset);
> +  outer = TREE_OPERAND (outer, 0);
> + }
> +    }
> +
> +  return addr;
> +}
> +
>  /* Mark BOUNDS associated with PTR as incomplete.  */
>  static void
>  chkp_register_incomplete_bounds (tree bounds, tree ptr)
> @@ -1044,6 +1085,12 @@ chkp_add_modification_to_stmt_list (tree lhs,
>  static tree
>  chkp_build_addr_expr (tree obj)
>  {
> +  /* We first check whether it is a "hard reg case".  */
> +  tree base = get_base_address (obj);
> +  if (VAR_P (base) && DECL_HARD_REGISTER (base))
> +    return chkp_get_hard_register_fake_addr_expr (obj);
> +
> +  /* If not - return regular ADDR_EXPR.  */
>    return TREE_CODE (obj) == TARGET_MEM_REF
>      ? tree_mem_ref_addr (ptr_type_node, obj)
>      : build_fold_addr_expr (obj);
> @@ -3442,6 +3489,13 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>    || TREE_CODE (var) == SSA_NAME);
>
>        *ptr = chkp_build_addr_expr (var);
> +
> +      /* For hard register cases chkp_build_addr_expr returns INTEGER_CST
> + and later on chkp_find_bounds will fail to find proper bounds.
> + In order to avoid that, we find/create bounds right aways using
> + the var itself.  */
> +      if (DECL_HARD_REGISTER (var))
> + *bounds = chkp_make_addressed_object_bounds (var, iter);
>      }
>
>    /* In this loop we are trying to find a field access
>
> 2017-04-19 21:32 GMT+02:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>> 2017-04-19 19:48 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>> Hi,
>>>
>>> Thanks for the comments, that was a good idea to place all the logic inside
>>> of chkp_build_addr_expr function. I followed it and here is what I got:
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 2017-04-19  Alexander Ivchenko  <aivchenk@gmail.com>
>>>
>>>         * gcc.target/i386/mpx/hard-reg-2-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-2-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-2-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-1-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-1-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-1-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-2-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-2-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-2-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-3-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-4-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-4-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-4-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-1-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-1-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-1-ubv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-2-lbv.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-2-nov.c: New test.
>>>         * gcc.target/i386/mpx/hard-reg-5-2-ubv.c: New test.
>>>
>>> gcc/ChangeLog:
>>>
>>> 2017-04-19  Alexander Ivchenko  <aivchenk@gmail.com>
>>>
>>>         * tree-chkp.c (chkp_get_hard_register_var_fake_base_address):
>>> New function to provide a base address for.
>>> chkp_get_hard_register_fake_addr_expr
>>>         (chkp_get_hard_register_fake_addr_expr): New function to build
>>> fake address expression for an expr that resides on a hard
>>> register.
>>>         (chkp_build_addr_expr): Add checks for hard reg cases.
>>>         (chkp_parse_array_and_component_ref): Create/find bounds if the
>>> var resides on a hard reg.
>>>         (chkp_find_bounds_1): Check for hard register cases.
>>>
>>>
>>>
>>>
>>>
>>> And the patch itself:
>>>
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>> new file mode 100644
>>> index 0000000..319e1ec
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>> @@ -0,0 +1,21 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__((vector_size(16)));
>>> +
>>> +int foo(int i) {
>>> +  register v16 u asm("xmm0");
>>> +  return u[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>> new file mode 100644
>>> index 0000000..3c6d39a
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>> @@ -0,0 +1,18 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__((vector_size(16)));
>>> +
>>> +int foo (int i) {
>>> +  register v16 u asm ("xmm0");
>>> +  return u[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (3));
>>> +  printf ("%d\n", foo (0));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>> new file mode 100644
>>> index 0000000..7fe76c4
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>> @@ -0,0 +1,21 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__((vector_size(16)));
>>> +
>>> +int foo (int i) {
>>> +  register v16 u asm ("xmm0");
>>> +  return u[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (5));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>> new file mode 100644
>>> index 0000000..7e4451f
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>> @@ -0,0 +1,33 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1.s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>> new file mode 100644
>>> index 0000000..73bd7fb
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>> @@ -0,0 +1,30 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1.s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (0));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>> new file mode 100644
>>> index 0000000..166b6b9
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>> @@ -0,0 +1,33 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1.s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (3));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>> new file mode 100644
>>> index 0000000..7820c2f
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>> @@ -0,0 +1,33 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f2 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f2[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f2 (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>> new file mode 100644
>>> index 0000000..0816e58
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>> @@ -0,0 +1,30 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f2 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f2[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f2 (0));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>> new file mode 100644
>>> index 0000000..94261a7
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>> @@ -0,0 +1,33 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1;
>>> +  v8 s2f2;
>>> +};
>>> +
>>> +int foo_s2f2 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f2[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f2 (3));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>> new file mode 100644
>>> index 0000000..f273d58
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>> @@ -0,0 +1,27 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>> +
>>> +struct S1
>>> +{
>>> +  v16 s1f1;
>>> +};
>>> +
>>> +int foo_s1f1 (int i)
>>> +{
>>> +  register struct S1 b asm ("xmm0");
>>> +  return b.s1f1[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s1f1 (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>> new file mode 100644
>>> index 0000000..aa8f7b9
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>> @@ -0,0 +1,24 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>> +
>>> +struct S1
>>> +{
>>> +  v16 s1f1;
>>> +};
>>> +
>>> +int foo_s1f1 (int i)
>>> +{
>>> +  register struct S1 b asm ("xmm0");
>>> +  return b.s1f1[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s1f1 (0));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>> new file mode 100644
>>> index 0000000..3d0c9b2
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>> @@ -0,0 +1,27 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>> +
>>> +struct S1
>>> +{
>>> +  v16 s1f1;
>>> +};
>>> +
>>> +int foo_s1f1 (int i)
>>> +{
>>> +  register struct S1 b asm ("xmm0");
>>> +  return b.s1f1[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s1f1 (7));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>> new file mode 100644
>>> index 0000000..e81b942
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>> @@ -0,0 +1,31 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S2
>>> +{
>>> +  v8 s2f2;
>>> +  int* f3;
>>> +};
>>> +
>>> +int foo (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  int k = 5;
>>> +  b.f3 = &k;
>>> +  b.f3 = b.f3 + i;
>>> +  return *b.f3;
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>> new file mode 100644
>>> index 0000000..4b1f1ac
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>> @@ -0,0 +1,28 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S2
>>> +{
>>> +  v8 s2f2;
>>> +  int* f3;
>>> +};
>>> +
>>> +int foo (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  int k = 5;
>>> +  b.f3 = &k;
>>> +  b.f3 = b.f3 + i;
>>> +  return *b.f3;
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (0));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>> new file mode 100644
>>> index 0000000..e95e68f
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>> @@ -0,0 +1,31 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S2
>>> +{
>>> +  v8 s2f2;
>>> +  int* f3;
>>> +};
>>> +
>>> +int foo (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  int k = 5;
>>> +  b.f3 = &k;
>>> +  b.f3 = b.f3 + i;
>>> +  return *b.f3;
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo (1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>>> new file mode 100644
>>> index 0000000..201b62d
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
>>> @@ -0,0 +1,32 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[0].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>>> new file mode 100644
>>> index 0000000..f94a879
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
>>> @@ -0,0 +1,30 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[0].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>>> new file mode 100644
>>> index 0000000..6ab981d
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
>>> @@ -0,0 +1,32 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[0].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (4));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>>> new file mode 100644
>>> index 0000000..cc58e8a
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
>>> @@ -0,0 +1,32 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[1].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (-1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>>> new file mode 100644
>>> index 0000000..5898c3b
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
>>> @@ -0,0 +1,30 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[1].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (1));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>>> new file mode 100644
>>> index 0000000..2910795
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
>>> @@ -0,0 +1,32 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "bounds violation" } */
>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>> +
>>> +
>>> +#define SHOULDFAIL
>>> +
>>> +#include "mpx-check.h"
>>> +
>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>> +
>>> +struct S1
>>> +{
>>> +  v8 s1f;
>>> +};
>>> +
>>> +struct S2
>>> +{
>>> +  struct S1 s2f1[2];
>>> +};
>>> +
>>> +int foo_s2f1 (int i)
>>> +{
>>> +  register struct S2 b asm ("xmm0");
>>> +  return b.s2f1[1].s1f[i];
>>> +}
>>> +
>>> +int mpx_test (int argc, const char **argv)
>>> +{
>>> +  printf ("%d\n", foo_s2f1 (4));
>>> +  return 0;
>>> +}
>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>> index b1ff218..6a48a55 100644
>>> --- a/gcc/tree-chkp.c
>>> +++ b/gcc/tree-chkp.c
>>> @@ -679,6 +679,46 @@ chkp_erase_completed_bounds (void)
>>>    chkp_completed_bounds_set = new hash_set<tree>;
>>>  }
>>>
>>> +/* This function is used to provide a base address for
>>> +   chkp_get_hard_register_fake_addr_expr.  */
>>> +static tree
>>> +chkp_get_hard_register_var_fake_base_address ()
>>> +{
>>> +  tree base = fold_convert (ptr_type_node, integer_zero_node);
>>> +  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
>>> +  return fold_build_pointer_plus_hwi (base, offset);
>>> +}
>>> +
>>> +/* If we check bounds for a hard register variable, we cannot
>>> +   use its address - it is illegal, so instead of that we use
>>> +   this fake value.  */
>>> +static tree
>>> +chkp_get_hard_register_fake_addr_expr (tree obj)
>>> +{
>>> +  tree addr = chkp_get_hard_register_var_fake_base_address ();
>>> +  tree outer = obj;
>>> +  while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF)
>>> +    {
>>> +      if (TREE_CODE (outer) == COMPONENT_REF)
>>> + {
>>> +  addr = fold_build_pointer_plus (addr,
>>> +  component_ref_field_offset (outer));
>>> +  outer = TREE_OPERAND (outer, 0);
>>> + }
>>> +      else if (TREE_CODE (outer) == ARRAY_REF)
>>> + {
>>> +  tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1));
>>> +  tree offset = size_binop (MULT_EXPR,
>>> +    array_ref_element_size (outer), indx);
>>> +  addr = fold_build_pointer_plus (addr, offset);
>>> +  outer = get_base_address (outer);
>>
>> Hi!
>>
>> I don't think get_base_address is what you want here because it goes to
>> the most inner base.
>>
>>> + }
>>> +    }
>>> +  gcc_assert (VAR_P (outer) && DECL_HARD_REGISTER (outer));
>>> +
>>> +  return addr;
>>> +}
>>> +
>>>  /* Mark BOUNDS associated with PTR as incomplete.  */
>>>  static void
>>>  chkp_register_incomplete_bounds (tree bounds, tree ptr)
>>> @@ -1044,6 +1084,18 @@ chkp_add_modification_to_stmt_list (tree lhs,
>>>  static tree
>>>  chkp_build_addr_expr (tree obj)
>>>  {
>>> +  /* We first check whether it is a "hard reg case".  */
>>> +  tree outer = obj;
>>> +  while (TREE_CODE (outer) == COMPONENT_REF
>>> + || TREE_CODE (outer) == ARRAY_REF)
>>> +    if (TREE_CODE (outer) == COMPONENT_REF)
>>> +      outer = TREE_OPERAND (outer, 0);
>>> +    else
>>> +      outer = get_base_address (outer);
>>
>> And here simple call to get_base_address might replace the whole loop.
>>
>>> +  if (VAR_P (outer) && DECL_HARD_REGISTER (outer))
>>> +    return chkp_get_hard_register_fake_addr_expr (obj);
>>> +
>>> +  /* If not - return regular ADDR_EXPR.  */
>>>    return TREE_CODE (obj) == TARGET_MEM_REF
>>>      ? tree_mem_ref_addr (ptr_type_node, obj)
>>>      : build_fold_addr_expr (obj);
>>> @@ -3442,6 +3494,13 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>    || TREE_CODE (var) == SSA_NAME);
>>>
>>>        *ptr = chkp_build_addr_expr (var);
>>> +
>>> +      /* For hard register cases chkp_build_addr_expr returns INTEGER_CST
>>> + and later on chkp_find_bounds will fail to find proper bounds.
>>> + In order to avoid that, we find/create bounds right aways using
>>> + the var itself.  */
>>> +      if (DECL_HARD_REGISTER (var))
>>> + *bounds = chkp_find_bounds (var, iter);
>>
>> Current semantics of this call is to get bounds for the pointer read from var.
>> I know we never get here fo pointer vars but still...
>>
>> I propose to just call chkp_make_addressed_object_bounds here instead of
>> chkp_find_bounds to avoid this non-intuitive interpretation of non-pointer
>> hardreg variable in chkp_find_bounds_1.
>>
>> BTW what if we have a structure with a pointer field or vector of pointers?
>> If we read this pointer then we might have some fun trying to find its bounds.
>> Let's make a test! :)
>>
>> Also what code do we produce now? Do we create static bounds variable
>> to hold fake bounds of hard reg variable? Is it initialized statically
>> or dynamically?
>>
>>>      }
>>>
>>>    /* In this loop we are trying to find a field access
>>> @@ -3639,6 +3698,8 @@ chkp_find_bounds_1 (tree ptr, tree ptr_src,
>>> gimple_stmt_iterator *iter)
>>>      addr = chkp_build_addr_expr (ptr_src);
>>>      bounds = chkp_build_bndldx (addr, ptr, iter);
>>>    }
>>> +      else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>>> + bounds = chkp_make_addressed_object_bounds (ptr_src, iter);
>>>        else
>>>   bounds = chkp_get_nonpointer_load_bounds ();
>>>        break;
>>>
>>>
>>>
>>>
>>>
>>> As before, the following added testcases fail because of PR80270:
>>
>> That makes hard to confirm patch correctness. Please at least check
>> GIMPLE for some of these tests are produced correctly by chkp phase.
>>
>> Overall this version looks much simpler and better. New MPX feature
>> to catch non-memory bounds violation is almost done!
>>
>> Thanks,
>> Ilya
>>
>>>
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O3 -g  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-1-ubv.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O3 -g  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-3-2-nov.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-lbv.c   -O0  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-nov.c   -O0  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-4-ubv.c   -O0  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O3 -g  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>>> -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>>> FAIL: gcc.target/i386/mpx/hard-reg-5-2-nov.c   -O2 -flto
>>> -fuse-linker-plugin -fno-fat-lto-objects  (test for excess errors)
>>>
>>> hard-reg-4-* looks suspicious to me. May be we need to handle that
>>> case differently, but it is hard to say because of the ICE now.
>>>
>>>
>>> 2017-04-10 23:21 GMT+02:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>>>> 2017-04-02 23:52 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>>>> Hi,
>>>>>
>>>>> Here is the patch that roughly follows your idea.
>>>>> Some comments:
>>>>>
>>>>> - There are more cases than array_ref overflow. We need to take care
>>>>> of component_ref and both underflows/overflows are possible
>>>>> - I could not make it work with "0" as a fake address, because then
>>>>> catching lower bounds violation is getting hard at O2 and above. E.g.
>>>>> consider this:
>>>>>
>>>>>    0x00000000004005f8 <+8>:     bndmk  0x7(%rax),%bnd0
>>>>>    0x00000000004005fd <+13>:    mov    $0x400734,%edi
>>>>> => 0x0000000000400602 <+18>:    bndcl  0xfffffffffffffffc,%bnd0
>>>>>             (gdb) p $bnd0
>>>>>             $1 = {lbound = 0x0, ubound = 0x7} : size 8
>>>>>   0x000000000040060b <+27>:    callq  0x400500 <printf@plt>
>>>>>
>>>>>     - bndcu is removed as not necessary and underflowed access is not
>>>>> caught. I used another fake value for lower bound address, which is
>>>>> 2^(bitness - 1)
>>>>
>>>> Hi,
>>>>
>>>> Looks like CHKP optimizations don't let us catch cases when pointer
>>>> arithmetc overflows. Using any fake value doesn't guarantee you don't
>>>> have overflow.
>>>>
>>>> This overoptimization is definately a separate issue. It should be easy
>>>> to write a test where usage of a huge index in array causes
>>>> uncought bounds violation because of removed bndcl/bndcu. You should
>>>> file a bug for that.
>>>>
>>>> If we don't try to work around overflow issues in this patch then using 0
>>>> should be more efficient because it allows you to always use bndcu only
>>>> (you just can't violate zero lower bound).
>>>>
>>>> BTW please don't forget ChangeLogs for your patches.
>>>>
>>>>>
>>>>> - hard-reg-3-[1,2]* tests fail with ICE right now because of PR80270.
>>>>> I will mark them as XFAIL if the patch is approved and the mentioned
>>>>> bug is not fixed
>>>>>
>>>>>
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>>> new file mode 100644
>>>>> index 0000000..319e1ec
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
>>>>> @@ -0,0 +1,21 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>>> +
>>>>> +int foo(int i) {
>>>>> +  register v16 u asm("xmm0");
>>>>> +  return u[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (-1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>>> new file mode 100644
>>>>> index 0000000..3c6d39a
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
>>>>> @@ -0,0 +1,18 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>>> +
>>>>> +int foo (int i) {
>>>>> +  register v16 u asm ("xmm0");
>>>>> +  return u[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (3));
>>>>> +  printf ("%d\n", foo (0));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>>> new file mode 100644
>>>>> index 0000000..7fe76c4
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
>>>>> @@ -0,0 +1,21 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__((vector_size(16)));
>>>>> +
>>>>> +int foo (int i) {
>>>>> +  register v16 u asm ("xmm0");
>>>>> +  return u[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (5));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>>> new file mode 100644
>>>>> index 0000000..7e4451f
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
>>>>> @@ -0,0 +1,33 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f1 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f1.s1f[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f1 (-1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>>> new file mode 100644
>>>>> index 0000000..73bd7fb
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
>>>>> @@ -0,0 +1,30 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f1 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f1.s1f[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f1 (0));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>>> new file mode 100644
>>>>> index 0000000..166b6b9
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
>>>>> @@ -0,0 +1,33 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f1 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f1.s1f[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f1 (3));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>>> new file mode 100644
>>>>> index 0000000..7820c2f
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
>>>>> @@ -0,0 +1,33 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f2 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f2[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f2 (-1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>>> new file mode 100644
>>>>> index 0000000..0816e58
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
>>>>> @@ -0,0 +1,30 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f2 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f2[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f2 (0));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>>> new file mode 100644
>>>>> index 0000000..94261a7
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
>>>>> @@ -0,0 +1,33 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v8 s1f;
>>>>> +};
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  struct S1 s2f1;
>>>>> +  v8 s2f2;
>>>>> +};
>>>>> +
>>>>> +int foo_s2f2 (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  return b.s2f2[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s2f2 (3));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>>> new file mode 100644
>>>>> index 0000000..f273d58
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
>>>>> @@ -0,0 +1,27 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v16 s1f1;
>>>>> +};
>>>>> +
>>>>> +int foo_s1f1 (int i)
>>>>> +{
>>>>> +  register struct S1 b asm ("xmm0");
>>>>> +  return b.s1f1[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s1f1 (-1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>>> new file mode 100644
>>>>> index 0000000..aa8f7b9
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
>>>>> @@ -0,0 +1,24 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v16 s1f1;
>>>>> +};
>>>>> +
>>>>> +int foo_s1f1 (int i)
>>>>> +{
>>>>> +  register struct S1 b asm ("xmm0");
>>>>> +  return b.s1f1[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s1f1 (0));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>>> new file mode 100644
>>>>> index 0000000..3d0c9b2
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
>>>>> @@ -0,0 +1,27 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v16 __attribute__ ((vector_size (16)));
>>>>> +
>>>>> +struct S1
>>>>> +{
>>>>> +  v16 s1f1;
>>>>> +};
>>>>> +
>>>>> +int foo_s1f1 (int i)
>>>>> +{
>>>>> +  register struct S1 b asm ("xmm0");
>>>>> +  return b.s1f1[i];
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo_s1f1 (7));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>>> new file mode 100644
>>>>> index 0000000..e81b942
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
>>>>> @@ -0,0 +1,31 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  v8 s2f2;
>>>>> +  int* f3;
>>>>> +};
>>>>> +
>>>>> +int foo (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  int k = 5;
>>>>> +  b.f3 = &k;
>>>>> +  b.f3 = b.f3 + i;
>>>>> +  return *b.f3;
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (-1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>>> new file mode 100644
>>>>> index 0000000..4b1f1ac
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
>>>>> @@ -0,0 +1,28 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  v8 s2f2;
>>>>> +  int* f3;
>>>>> +};
>>>>> +
>>>>> +int foo (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  int k = 5;
>>>>> +  b.f3 = &k;
>>>>> +  b.f3 = b.f3 + i;
>>>>> +  return *b.f3;
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (0));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>>> b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>>> new file mode 100644
>>>>> index 0000000..e95e68f
>>>>> --- /dev/null
>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
>>>>> @@ -0,0 +1,31 @@
>>>>> +/* { dg-do run } */
>>>>> +/* { dg-shouldfail "bounds violation" } */
>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>> +
>>>>> +
>>>>> +#define SHOULDFAIL
>>>>> +
>>>>> +#include "mpx-check.h"
>>>>> +
>>>>> +typedef int v8 __attribute__ ((vector_size (8)));
>>>>> +
>>>>> +struct S2
>>>>> +{
>>>>> +  v8 s2f2;
>>>>> +  int* f3;
>>>>> +};
>>>>> +
>>>>> +int foo (int i)
>>>>> +{
>>>>> +  register struct S2 b asm ("xmm0");
>>>>> +  int k = 5;
>>>>> +  b.f3 = &k;
>>>>> +  b.f3 = b.f3 + i;
>>>>> +  return *b.f3;
>>>>> +}
>>>>> +
>>>>> +int mpx_test (int argc, const char **argv)
>>>>> +{
>>>>> +  printf ("%d\n", foo (1));
>>>>> +  return 0;
>>>>> +}
>>>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>>>> index b1ff218..15c0da6 100644
>>>>> --- a/gcc/tree-chkp.c
>>>>> +++ b/gcc/tree-chkp.c
>>>>> @@ -679,6 +679,17 @@ chkp_erase_completed_bounds (void)
>>>>>    chkp_completed_bounds_set = new hash_set<tree>;
>>>>>  }
>>>>>
>>>>> +/* If we check bounds for a hard register variable, we cannot
>>>>> +   use its address - it is illegal, so instead of that we use
>>>>> +   this fake value.  */
>>>>> +static tree
>>>>> +chkp_get_hard_register_var_fake_address ()
>>>>> +{
>>>>> +  tree base = fold_convert (ptr_type_node, integer_zero_node);
>>>>> +  unsigned HOST_WIDE_INT offset = 1 << (TYPE_PRECISION (ptr_type_node) - 1);
>>>>> +  return fold_build_pointer_plus_hwi (base, offset);
>>>>> +}
>>>>> +
>>>>>  /* Mark BOUNDS associated with PTR as incomplete.  */
>>>>>  static void
>>>>>  chkp_register_incomplete_bounds (tree bounds, tree ptr)
>>>>> @@ -1040,10 +1051,24 @@ chkp_add_modification_to_stmt_list (tree lhs,
>>>>>    stmts->avail--;
>>>>>  }
>>>>>
>>>>> -/* Build and return ADDR_EXPR for specified object OBJ.  */
>>>>> +/* Build and return ADDR_EXPR for specified object OBJ.
>>>>> +   There is a special case for which we cannot return
>>>>> +   ADDR_EXPR - if the object is declared to be placed
>>>>> +   on a fixed hard register - in this case we cannot
>>>>> +   take its address, so we use the object itself. The
>>>>> +   caller of this function must be aware of that and
>>>>> +   use proper checks if necessary.  */
>>>>
>>>> I don't follow the idea of this change.
>>>>
>>>> If we want to use fake address for register vars then why not to
>>>> return this fake value by this function? In case of accessing a
>>>> component of register var we should return fake value + required
>>>> offset then.
>>>>
>>>>>  static tree
>>>>>  chkp_build_addr_expr (tree obj)
>>>>>  {
>>>>> +  /* We first check whether it is a "hard reg case".  */
>>>>> +  tree outer = obj;
>>>>> +  while (TREE_CODE (outer) == COMPONENT_REF)
>>>>> +    outer = TREE_OPERAND (outer, 0);
>>>>
>>>> What about ARRAY_REF? Probably get_base_address is what you need.
>>>>
>>>>> +  if (VAR_P (outer) && DECL_HARD_REGISTER (outer))
>>>>> +      return obj;
>>>>> +
>>>>> +  /* If not - return regular ADDR_EXPR.  */
>>>>>    return TREE_CODE (obj) == TARGET_MEM_REF
>>>>>      ? tree_mem_ref_addr (ptr_type_node, obj)
>>>>>      : build_fold_addr_expr (obj);
>>>>> @@ -3170,6 +3195,11 @@ chkp_get_bounds_for_decl_addr (tree decl)
>>>>>        gcc_assert (VAR_P (decl));
>>>>>        bounds = chkp_generate_extern_var_bounds (decl);
>>>>>      }
>>>>> +  else if (VAR_P (decl) && DECL_HARD_REGISTER (decl))
>>>>> +    {
>>>>> +      tree lb = chkp_get_hard_register_var_fake_address ();
>>>>> +      bounds = chkp_make_bounds(lb, DECL_SIZE_UNIT (decl), NULL, false);
>>>>> +    }
>>>>>    else
>>>>>      {
>>>>>        tree lb = chkp_build_addr_expr (decl);
>>>>> @@ -3351,6 +3381,8 @@ chkp_narrow_bounds_to_field (tree bounds, tree component,
>>>>>    tree field_ptr = chkp_build_addr_expr (component);
>>>>>    tree field_bounds;
>>>>>
>>>>> +  if (!BOUNDED_P (field_ptr))
>>>>> +    field_ptr = chkp_get_hard_register_var_fake_address ();
>>>>
>>>> This gives you fake pointer instead of fake pointer + offset. No?
>>>>
>>>>>    field_bounds = chkp_make_bounds (field_ptr, size, iter, false);
>>>>>
>>>>>    return chkp_intersect_bounds (field_bounds, bounds, iter);
>>>>> @@ -3639,6 +3671,8 @@ chkp_find_bounds_1 (tree ptr, tree ptr_src,
>>>>> gimple_stmt_iterator *iter)
>>>>>      addr = chkp_build_addr_expr (ptr_src);
>>>>>      bounds = chkp_build_bndldx (addr, ptr, iter);
>>>>>    }
>>>>> +      else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>>>>> + bounds = chkp_make_addressed_object_bounds (ptr_src, iter);
>>>>
>>>> I don't get what this piece of code is for.
>>>>
>>>>>        else
>>>>>   bounds = chkp_get_nonpointer_load_bounds ();
>>>>>        break;
>>>>> @@ -4031,7 +4065,19 @@ chkp_process_stmt (gimple_stmt_iterator *iter, tree node,
>>>>>        addr_first,
>>>>>        byte_position (field));
>>>>>            }
>>>>> -        else
>>>>> +        else if (VAR_P (ptr) && DECL_HARD_REGISTER (ptr))
>>>>> +  {
>>>>> +    gcc_assert (TREE_CODE (node) == ARRAY_REF
>>>>> + || TREE_CODE (node) == COMPONENT_REF);
>>>>
>>>> This may never hit because this code is in a switch block filtering
>>>> node to ARRAY_REF and COMPONENT_REF already.
>>>>
>>>>> +
>>>>> +    tree base = chkp_get_hard_register_var_fake_address ();
>>>>> +    tree indx = fold_convert_loc (loc,
>>>>> +  size_type_node,
>>>>> +  TREE_OPERAND (node, 1));
>>>>
>>>> Code looks like it expects ARRAY_REF only but COMPONENT_REF
>>>> is also possible.
>>>>
>>>>> +    tree offset = size_binop_loc (loc, MULT_EXPR, size, indx);
>>>>
>>>> 'size' here holds a size of memory access, not size of array element.
>>>>
>>>> Overall it looks like all you need is a proper fix in chkp_build_addr_expr
>>>> to use fake value when required. Many (all?) other changes might just
>>>> go away then.
>>>>
>>>> Thanks,
>>>> Ilya
>>>>
>>>>> +    addr_first = fold_build_pointer_plus_loc (loc, base, offset);
>>>>> +  }
>>>>> + else
>>>>>            addr_first = chkp_build_addr_expr (node);
>>>>>        }
>>>>>        break;
>>>>>
>>>>> 2017-03-23 20:57 GMT+01:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>>>>>> 2017-03-23 17:18 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>>>>>> Hi,
>>>>>>>
>>>>>>> The patch below attempts to fix the PR. I checked that it did not
>>>>>>> break any of mpx.exp tests, but I did not run the full testing yet.
>>>>>>> Would like to know whether this approach is generally correct or not.
>>>>>>>
>>>>>>> The issue is that we have the hard reg vector variable:
>>>>>>>
>>>>>>> typedef int U __attribute__ ((vector_size (16)));
>>>>>>> register U u asm("xmm0");
>>>>>>>
>>>>>>> and chkp tries to instrument access to it:
>>>>>>>
>>>>>>> return u[i];
>>>>>>>
>>>>>>> by doing that:
>>>>>>>
>>>>>>> __bound_tmp.0_4 = __builtin_ia32_bndmk (&u, 16);
>>>>>>>
>>>>>>> However, you cannot take an address of a register variable (in fact if
>>>>>>> you do that, the compiler will give you "address of register variable
>>>>>>> ā€˜uā€™ requested" error), so expand, sensibly, gives an ICE on on &u
>>>>>>> here. I believe that if there is no pointers, pointer bounds checker
>>>>>>> shouldn't get involved into that business. What do you think?
>>>>>>
>>>>>> Hi!
>>>>>>
>>>>>> I think with this patch I can call foo with any index and thus access
>>>>>> some random stack slot. The first thing we should answer is 'do we
>>>>>> want to catch array index overflows in such cases'? If we want to (and
>>>>>> this looks reasonable thing to do because it prevents invalid memory
>>>>>> accesses) then this patch doesn't resolve the problem.
>>>>>>
>>>>>> I'm not sure it can affect the patch, but please consider more complex
>>>>>> cases. E.g.:
>>>>>>
>>>>>> typedef int v8 __attribute__ ((vector_size(8)));
>>>>>>
>>>>>> struct U {
>>>>>>   v8 a;
>>>>>>   v8 b;
>>>>>> };
>>>>>>
>>>>>> int
>>>>>> foo (int i)
>>>>>> {
>>>>>>   register struct U u asm ("xmm0");
>>>>>>   return u.b[i];
>>>>>> }
>>>>>>
>>>>>> One way to catch overflow in such cases might be to use some fake
>>>>>> pointer value (e.g. 0) for such not addressible variable. This fake value
>>>>>> would be used as base for memory access and as lower bound. I don't
>>>>>> see other cases except array_ref overflow check where such value
>>>>>> might be used. So this fake value will not be passed somewhere and
>>>>>> will not be stored to Bounds Table.
>>>>>>
>>>>>> Thanks,
>>>>>> Ilya
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>>>>>> index 75caf83..e39ec9a 100644
>>>>>>> --- a/gcc/tree-chkp.c
>>>>>>> +++ b/gcc/tree-chkp.c
>>>>>>> @@ -3383,6 +3383,7 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>>    tree comp_to_narrow = NULL_TREE;
>>>>>>>    tree last_comp = NULL_TREE;
>>>>>>>    bool array_ref_found = false;
>>>>>>> +  bool is_register_var = false;
>>>>>>>    tree *nodes;
>>>>>>>    tree var;
>>>>>>>    int len;
>>>>>>> @@ -3440,6 +3441,9 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>>                   || TREE_CODE (var) == STRING_CST
>>>>>>>                   || TREE_CODE (var) == SSA_NAME);
>>>>>>>
>>>>>>> +      if (VAR_P (var) && DECL_HARD_REGISTER (var))
>>>>>>> +       is_register_var = true;
>>>>>>> +
>>>>>>>        *ptr = chkp_build_addr_expr (var);
>>>>>>>      }
>>>>>>>
>>>>>>> @@ -3455,7 +3459,11 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>>>>>
>>>>>>>        if (TREE_CODE (var) == ARRAY_REF)
>>>>>>>         {
>>>>>>> -         *safe = false;
>>>>>>> +         // Mark it as unsafe, unless the array being accessed
>>>>>>> +         // has been explicitly placed on a register: in this
>>>>>>> +         // case we cannot take a pointer of this variable,
>>>>>>> +         // so we don't instrument the access.
>>>>>>> +         *safe = is_register_var;
>>>>>>>           array_ref_found = true;
>>>>>>>           if (flag_chkp_narrow_bounds
>>>>>>>               && !flag_chkp_narrow_to_innermost_arrray
>>>>>>> @@ -4001,6 +4009,19 @@ chkp_process_stmt (gimple_stmt_iterator *iter, tree node,
>>>>>>>         bool bitfield;
>>>>>>>         tree elt;
>>>>>>>
>>>>>>> +       {
>>>>>>> +         // We don't instrument accesses to arrays that
>>>>>>> +         // are explicitely assigned to hard registers.
>>>>>>> +         HOST_WIDE_INT bitsize, bitpos;
>>>>>>> +         tree base, offset;
>>>>>>> +         machine_mode mode;
>>>>>>> +         int unsignedp, reversep, volatilep = 0;
>>>>>>> +         base = get_inner_reference (node, &bitsize, &bitpos, &offset, &mode,
>>>>>>> +                                     &unsignedp, &reversep, &volatilep);
>>>>>>> +         if (VAR_P (base) && DECL_HARD_REGISTER (base))
>>>>>>> +           safe = true;
>>>>>>> +       }
>>>>>>> +
>>>>>>>         if (safe)
>>>>>>>           {
>>>>>>>             /* We are not going to generate any checks, so do not
>>>>>>>
>>>>>>> diff --git a/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>>> b/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..a27734d
>>>>>>> --- /dev/null
>>>>>>> +++ b/gcc/testsuite/gcc.target/i386/mpx/pr79990.c
>>>>>>> @@ -0,0 +1,18 @@
>>>>>>> +/* { dg-do compile } */
>>>>>>> +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
>>>>>>> +
>>>>>>> +typedef int U __attribute__ ((vector_size (16)));
>>>>>>> +
>>>>>>> +int
>>>>>>> +foo (int i)
>>>>>>> +{
>>>>>>> +#if __SSE2__
>>>>>>> +  register
>>>>>>> +#endif
>>>>>>> +    U u
>>>>>>> +#if __SSE2__
>>>>>>> +      asm ("xmm0")
>>>>>>> +#endif
>>>>>>> +      ;
>>>>>>> +  return u[i];
>>>>>>> +}
>>>>>>>
>>>>>>> regards,
>>>>>>> Alexander

Patch hide | download patch | download mbox

diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
new file mode 100644
index 0000000..319e1ec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-lbv.c
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__((vector_size(16)));
+
+int foo(int i) {
+  register v16 u asm("xmm0");
+  return u[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
new file mode 100644
index 0000000..3c6d39a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-nov.c
@@ -0,0 +1,18 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__((vector_size(16)));
+
+int foo (int i) {
+  register v16 u asm ("xmm0");
+  return u[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (3));
+  printf ("%d\n", foo (0));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
new file mode 100644
index 0000000..7fe76c4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-2-ubv.c
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__((vector_size(16)));
+
+int foo (int i) {
+  register v16 u asm ("xmm0");
+  return u[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (5));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
new file mode 100644
index 0000000..7e4451f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-lbv.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1.s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
new file mode 100644
index 0000000..73bd7fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-nov.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1.s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (0));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
new file mode 100644
index 0000000..166b6b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-1-ubv.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1.s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (3));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
new file mode 100644
index 0000000..7820c2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-lbv.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f2 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f2[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f2 (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
new file mode 100644
index 0000000..0816e58
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-nov.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f2 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f2[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f2 (0));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
new file mode 100644
index 0000000..94261a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-2-ubv.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1;
+  v8 s2f2;
+};
+
+int foo_s2f2 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f2[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f2 (3));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
new file mode 100644
index 0000000..f273d58
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-lbv.c
@@ -0,0 +1,27 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__ ((vector_size (16)));
+
+struct S1
+{
+  v16 s1f1;
+};
+
+int foo_s1f1 (int i)
+{
+  register struct S1 b asm ("xmm0");
+  return b.s1f1[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s1f1 (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
new file mode 100644
index 0000000..aa8f7b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-nov.c
@@ -0,0 +1,24 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__ ((vector_size (16)));
+
+struct S1
+{
+  v16 s1f1;
+};
+
+int foo_s1f1 (int i)
+{
+  register struct S1 b asm ("xmm0");
+  return b.s1f1[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s1f1 (0));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
new file mode 100644
index 0000000..3d0c9b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-3-ubv.c
@@ -0,0 +1,27 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v16 __attribute__ ((vector_size (16)));
+
+struct S1
+{
+  v16 s1f1;
+};
+
+int foo_s1f1 (int i)
+{
+  register struct S1 b asm ("xmm0");
+  return b.s1f1[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s1f1 (7));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
new file mode 100644
index 0000000..e81b942
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-lbv.c
@@ -0,0 +1,31 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  v8 s2f2;
+  int* f3;
+};
+
+int foo (int i)
+{
+  register struct S2 b asm ("xmm0");
+  int k = 5;
+  b.f3 = &k;
+  b.f3 = b.f3 + i;
+  return *b.f3;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
new file mode 100644
index 0000000..4b1f1ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-nov.c
@@ -0,0 +1,28 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  v8 s2f2;
+  int* f3;
+};
+
+int foo (int i)
+{
+  register struct S2 b asm ("xmm0");
+  int k = 5;
+  b.f3 = &k;
+  b.f3 = b.f3 + i;
+  return *b.f3;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (0));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
new file mode 100644
index 0000000..e95e68f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-4-ubv.c
@@ -0,0 +1,31 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  v8 s2f2;
+  int* f3;
+};
+
+int foo (int i)
+{
+  register struct S2 b asm ("xmm0");
+  int k = 5;
+  b.f3 = &k;
+  b.f3 = b.f3 + i;
+  return *b.f3;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo (1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
new file mode 100644
index 0000000..201b62d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-lbv.c
@@ -0,0 +1,32 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[0].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
new file mode 100644
index 0000000..f94a879
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-nov.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[0].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
new file mode 100644
index 0000000..6ab981d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-1-ubv.c
@@ -0,0 +1,32 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[0].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (4));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
new file mode 100644
index 0000000..cc58e8a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-lbv.c
@@ -0,0 +1,32 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[1].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (-1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
new file mode 100644
index 0000000..5898c3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-nov.c
@@ -0,0 +1,30 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[1].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
new file mode 100644
index 0000000..2910795
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-5-2-ubv.c
@@ -0,0 +1,32 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S1
+{
+  v8 s1f;
+};
+
+struct S2
+{
+  struct S1 s2f1[2];
+};
+
+int foo_s2f1 (int i)
+{
+  register struct S2 b asm ("xmm0");
+  return b.s2f1[1].s1f[i];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  printf ("%d\n", foo_s2f1 (4));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
new file mode 100644
index 0000000..b160915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-lbv.c
@@ -0,0 +1,34 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  int* f[2];
+};
+
+int foo (int i, int *kp1)
+{
+  register struct S2 b asm ("xmm0");
+  int k2 = 5;
+
+  b.f[0] = kp1;
+  b.f[1] = &k2;
+
+  b.f[1] = b.f[1] + i;
+  return *b.f[1];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  int k1 = 10;
+  printf ("%d\n", foo (-1, &k1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
new file mode 100644
index 0000000..584b3e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-nov.c
@@ -0,0 +1,31 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  int* f[2];
+};
+
+int foo (int i, int *kp1)
+{
+  register struct S2 b asm ("xmm0");
+  int k2 = 5;
+
+  b.f[0] = kp1;
+  b.f[1] = &k2;
+
+  b.f[0] = b.f[0] + i;
+  return *b.f[0];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  int k1 = 10;
+  printf ("%d\n", foo (0, &k1));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
new file mode 100644
index 0000000..92fa793
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/hard-reg-6-ubv.c
@@ -0,0 +1,34 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+typedef int v8 __attribute__ ((vector_size (8)));
+
+struct S2
+{
+  int* f[2];
+};
+
+int foo (int i, int *kp1)
+{
+  register struct S2 b asm ("xmm0");
+  int k2 = 5;
+
+  b.f[0] = kp1;
+  b.f[1] = &k2;
+
+  b.f[0] = b.f[0] + i;
+  return *b.f[0];
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  int k1 = 10;
+  printf ("%d\n", foo (1, &k1));
+  return 0;
+}
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index b1ff218..3ef73a9 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -327,6 +327,8 @@  static void chkp_parse_array_and_component_ref
(tree node, tree *ptr,
  bool innermost_bounds);
 static void chkp_parse_bit_field_ref (tree node, location_t loc,
       tree *offset, tree *size);
+static tree
+chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter);

 #define chkp_bndldx_fndecl \