Hi,

Instrumented function pointer may be propagated into not instrumented indirect 
call and vice versa.  It requires additional call modifications (either remove 
bounds or change callee).  Bootstrapped and tested on x86_64-unknown-linux-gnu. 
 OK for trunk?


Thanks,
Ilya
--
gcc/

2015-03-12  Ilya Enkovich  <ilya.enkov...@intel.com>

        * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Add
        redirection for instrumented calls.
        * tree-chkp.h (chkp_copy_call_skip_bounds): New.
        (chkp_redirect_edge): New.
        * tree-chkp.c (chkp_copy_call_skip_bounds): New.
        (chkp_redirect_edge): New.

gcc/testsuite/

2015-03-12  Ilya Enkovich  <ilya.enkov...@intel.com>

        * gcc.target/i386/mpx/chkp-fix-calls-1.c: New.
        * gcc.target/i386/mpx/chkp-fix-calls-2.c: New.


diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 5ca1901..a0b0465 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1278,14 +1278,25 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
 {
   cgraph_edge *e = this;
 
-  tree decl = gimple_call_fndecl (e->call_stmt);
-  tree lhs = gimple_call_lhs (e->call_stmt);
+  tree decl;
+  tree lhs;
   gcall *new_stmt;
   gimple_stmt_iterator gsi;
+  bool skip_bounds = false;
 #ifdef ENABLE_CHECKING
   cgraph_node *node;
 #endif
 
+  /* We might propagate instrumented function pointer into
+     not instrumented function and vice versa.  In such a
+     case we need to either fix function declaration or
+     remove bounds from call statement.  */
+  if (callee)
+    skip_bounds = chkp_redirect_edge (e);
+
+  decl = gimple_call_fndecl (e->call_stmt);
+  lhs = gimple_call_lhs (e->call_stmt);
+
   if (e->speculative)
     {
       cgraph_edge *e2;
@@ -1391,7 +1402,8 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
     }
 
   if (e->indirect_unknown_callee
-      || decl == e->callee->decl)
+      || (decl == e->callee->decl
+         && !skip_bounds))
     return e->call_stmt;
 
 #ifdef ENABLE_CHECKING
@@ -1416,13 +1428,19 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
        }
     }
 
-  if (e->callee->clone.combined_args_to_skip)
+  if (e->callee->clone.combined_args_to_skip
+      || skip_bounds)
     {
       int lp_nr;
 
-      new_stmt
-       = gimple_call_copy_skip_args (e->call_stmt,
-                                     e->callee->clone.combined_args_to_skip);
+      new_stmt = e->call_stmt;
+      if (e->callee->clone.combined_args_to_skip)
+       new_stmt
+         = gimple_call_copy_skip_args (new_stmt,
+                                       e->callee->clone.combined_args_to_skip);
+      if (skip_bounds)
+       new_stmt = chkp_copy_call_skip_bounds (new_stmt);
+
       gimple_call_set_fndecl (new_stmt, e->callee->decl);
       gimple_call_set_fntype (new_stmt, gimple_call_fntype (e->call_stmt));
 
diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c 
b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c
new file mode 100644
index 0000000..cb4d229
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcheck-pointer-bounds -mmpx" } */
+
+#include "math.h"
+
+double
+test1 (double x, double y, double (*fn)(double, double))
+{
+  return fn (x, y);
+}
+
+double
+test2 (double x, double y)
+{
+  return test1 (x, y, copysign);
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c 
b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c
new file mode 100644
index 0000000..951e7de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/chkp-fix-calls-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcheck-pointer-bounds -mmpx -fno-inline" } */
+
+#include "math.h"
+
+double
+test1 (double x, double y, double (*fn)(double, double))
+{
+  return fn (x, y);
+}
+
+double
+test2 (double x, double y)
+{
+  return test1 (x, y, copysign);
+}
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index d2df4ba..2d2090f 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -500,6 +500,62 @@ chkp_expand_bounds_reset_for_mem (tree mem, tree ptr)
   expand_normal (bndstx);
 }
 
+/* Build a GIMPLE_CALL identical to CALL but skipping bounds
+   arguments.  */
+
+gcall *
+chkp_copy_call_skip_bounds (gcall *call)
+{
+  bitmap bounds;
+  unsigned i;
+
+  bitmap_obstack_initialize (NULL);
+  bounds = BITMAP_ALLOC (NULL);
+
+  for (i = 0; i < gimple_call_num_args (call); i++)
+    if (POINTER_BOUNDS_P (gimple_call_arg (call, i)))
+      bitmap_set_bit (bounds, i);
+
+  call = gimple_call_copy_skip_args (call, bounds);
+  gimple_call_set_with_bounds (call, false);
+
+  BITMAP_FREE (bounds);
+  bitmap_obstack_release (NULL);
+
+  return call;
+}
+
+/* Redirect edge E to the correct node according to call_stmt.
+   Return 1 if bounds removal from call_stmt should be done
+   instead of redirection.  */
+
+bool
+chkp_redirect_edge (cgraph_edge *e)
+{
+  bool instrumented = false;
+
+  if (e->callee->instrumentation_clone
+      || chkp_function_instrumented_p (e->callee->decl))
+    instrumented = true;
+
+  if (instrumented
+      && !gimple_call_with_bounds_p (e->call_stmt))
+    e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl));
+  else if (!instrumented
+          && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL)
+          && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU)
+          && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX)
+          && gimple_call_with_bounds_p (e->call_stmt))
+    {
+      if (e->callee->instrumented_version)
+       e->redirect_callee (e->callee->instrumented_version);
+      else
+       return true;
+    }
+
+  return false;
+}
+
 /* Mark statement S to not be instrumented.  */
 static void
 chkp_mark_stmt (gimple s)
diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h
index 86f3618..40e2489 100644
--- a/gcc/tree-chkp.h
+++ b/gcc/tree-chkp.h
@@ -54,5 +54,7 @@ extern void chkp_copy_bounds_for_assign (gimple assign,
 extern bool chkp_gimple_call_builtin_p (gimple call,
                                        enum built_in_function code);
 extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr);
+extern gcall *chkp_copy_call_skip_bounds (gcall *call);
+extern bool chkp_redirect_edge (cgraph_edge *e);
 
 #endif /* GCC_TREE_CHKP_H */

Reply via email to