diff mbox

[4/17] Outline instrumentation

Message ID 543F83D1.9060902@samsung.com
State New
Headers show

Commit Message

Yury Gribov Oct. 16, 2014, 8:37 a.m. UTC
4.9's Asan runtime library provides no support for these so I removed 
the tests. I've also changed default value of threshold to INT_MAX to 
completely disable outline instrumentation in userspace Asan.

Comments

Jakub Jelinek Oct. 16, 2014, 8:45 a.m. UTC | #1
On Thu, Oct 16, 2014 at 12:37:37PM +0400, Yury Gribov wrote:
> 4.9's Asan runtime library provides no support for these so I removed the
> tests. I've also changed default value of threshold to INT_MAX to completely
> disable outline instrumentation in userspace Asan.

> New asan-instrumentation-with-call-threshold parameter.
> 
> 2014-10-15  Yury Gribov  <y.gribov@samsung.com>
> 
> 	Backport from mainline
> 	2014-06-16  Yury Gribov  <y.gribov@samsung.com>
> 
> 	* asan.c (check_func): New function.
> 	(maybe_create_ssa_name): Likewise.
> 	(build_check_stmt_with_calls): Likewise.
> 	(use_calls_p): Likewise.
> 	(report_error_func): Change interface.
> 	(build_check_stmt): Allow non-integer lengths; add support
> 	for new parameter.
> 	(asan_instrument): Likewise.
> 	(instrument_mem_region_access): Moved code to
> 	build_check_stmt.
> 	(instrument_derefs): Likewise.
> 	(instrument_strlen_call): Likewise.
> 	* cfgcleanup.c (old_insns_match_p): Add support for new
> 	functions.
> 	* doc/invoke.texi: Describe new parameter.
> 	* params.def: Define new parameter.
> 	* params.h: Likewise.
> 	* sanitizer.def: Describe new builtins.
> 
> 	* c-c++-common/asan/instrument-with-calls-1.c: New test.
> 	* c-c++-common/asan/instrument-with-calls-2.c: Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-1.c: Update
> 	test patterns.
> 	* c-c++-common/asan/no-redundant-instrumentation-2.c:
> 	Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-4.c:
> 	Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-5.c:
> 	Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-6.c:
> 	Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-7.c:
> 	Likewise.
> 	* c-c++-common/asan/no-redundant-instrumentation-8.c:
> 	Likewise.

Ok.

	Jakub
diff mbox

Patch

New asan-instrumentation-with-call-threshold parameter.

2014-10-15  Yury Gribov  <y.gribov@samsung.com>

	Backport from mainline
	2014-06-16  Yury Gribov  <y.gribov@samsung.com>

	* asan.c (check_func): New function.
	(maybe_create_ssa_name): Likewise.
	(build_check_stmt_with_calls): Likewise.
	(use_calls_p): Likewise.
	(report_error_func): Change interface.
	(build_check_stmt): Allow non-integer lengths; add support
	for new parameter.
	(asan_instrument): Likewise.
	(instrument_mem_region_access): Moved code to
	build_check_stmt.
	(instrument_derefs): Likewise.
	(instrument_strlen_call): Likewise.
	* cfgcleanup.c (old_insns_match_p): Add support for new
	functions.
	* doc/invoke.texi: Describe new parameter.
	* params.def: Define new parameter.
	* params.h: Likewise.
	* sanitizer.def: Describe new builtins.

	* c-c++-common/asan/instrument-with-calls-1.c: New test.
	* c-c++-common/asan/instrument-with-calls-2.c: Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-1.c: Update
	test patterns.
	* c-c++-common/asan/no-redundant-instrumentation-2.c:
	Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-4.c:
	Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-5.c:
	Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-6.c:
	Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-7.c:
	Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-8.c:
	Likewise.

diff --git a/gcc/asan.c b/gcc/asan.c
index 820d8ef..5c091d0 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -242,6 +242,19 @@  static GTY(()) tree shadow_ptr_types[2];
 /* Decl for __asan_option_detect_stack_use_after_return.  */
 static GTY(()) tree asan_detect_stack_use_after_return;
 
+/* Number of instrumentations in current function so far.  */
+
+static int asan_num_accesses;
+
+/* Check whether we should replace inline instrumentation with calls.  */
+
+static inline bool
+use_calls_p ()
+{
+  return ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
+    && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
+}
+
 /* Hashtable support for memory references used by gimple
    statements.  */
 
@@ -1319,7 +1332,7 @@  asan_protect_global (tree decl)
    IS_STORE is either 1 (for a store) or 0 (for a load).  */
 
 static tree
-report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, bool slow_p)
+report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, int *nargs)
 {
   static enum built_in_function report[2][6]
     = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
@@ -1328,13 +1341,37 @@  report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, bool slow_p)
 	{ BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
 	  BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
 	  BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } };
-  if ((size_in_bytes & (size_in_bytes - 1)) != 0
-      || size_in_bytes > 16
-      || slow_p)
-    return builtin_decl_implicit (report[is_store][5]);
+  if (size_in_bytes == -1)
+    {
+      *nargs = 2;
+      return builtin_decl_implicit (report[is_store][5]);
+    }
+  *nargs = 1;
   return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]);
 }
 
+/* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
+   IS_STORE is either 1 (for a store) or 0 (for a load).  */
+
+static tree
+check_func (bool is_store, int size_in_bytes, int *nargs)
+{
+  static enum built_in_function check[2][6]
+    = { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
+      BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
+      BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
+	{ BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
+      BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
+      BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } };
+  if (size_in_bytes == -1)
+    {
+      *nargs = 2;
+      return builtin_decl_implicit (check[is_store][5]);
+    }
+  *nargs = 1;
+  return builtin_decl_implicit (check[is_store][exact_log2 (size_in_bytes)]);
+}
+
 /* Split the current basic block and create a condition statement
    insertion point right before or after the statement pointed to by
    ITER.  Return an iterator to the point at which the caller might
@@ -1494,6 +1531,76 @@  build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
   return gimple_assign_lhs (g);
 }
 
+/* BASE can already be an SSA_NAME; in that case, do not create a
+   new SSA_NAME for it.  */
+
+static tree
+maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
+		       bool before_p)
+{
+  if (TREE_CODE (base) == SSA_NAME)
+    return base;
+  gimple g
+    = gimple_build_assign_with_ops (TREE_CODE (base),
+				    make_ssa_name (TREE_TYPE (base), NULL),
+				    base, NULL_TREE);
+  gimple_set_location (g, loc);
+  if (before_p)
+    gsi_insert_before (iter, g, GSI_SAME_STMT);
+  else
+    gsi_insert_after (iter, g, GSI_NEW_STMT);
+  return gimple_assign_lhs (g);
+}
+
+/* Instrument the memory access instruction using callbacks.
+   Parameters are similar to BUILD_CHECK_STMT.  */
+
+static void
+build_check_stmt_with_calls (location_t loc, tree base, tree len,
+			     HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
+			     bool before_p, bool is_store, bool is_scalar_access)
+{
+  gimple_stmt_iterator gsi = *iter;
+  tree base_ssa = maybe_create_ssa_name (loc, base, &gsi, before_p);
+
+  gimple g
+    = gimple_build_assign_with_ops (NOP_EXPR,
+				    make_ssa_name (pointer_sized_int_node, NULL),
+				    base_ssa, NULL_TREE);
+  gimple_set_location (g, loc);
+  if (before_p)
+    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
+  else
+    gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  int nargs;
+  tree fun
+    = check_func (is_store, is_scalar_access ? size_in_bytes : -1, &nargs);
+  if (nargs == 1)
+    g = gimple_build_call (fun, 1, base_addr);
+  else
+    {
+      gcc_assert (nargs == 2);
+      g = gimple_build_assign_with_ops (NOP_EXPR,
+					make_ssa_name (pointer_sized_int_node,
+						       NULL),
+					len, NULL_TREE);
+      gimple_set_location (g, loc);
+      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+      tree sz_arg = gimple_assign_lhs (g);
+      g = gimple_build_call (fun, nargs, base_addr, sz_arg);
+    }
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  if (!before_p)
+    {
+      gsi_next (&gsi);
+      *iter = gsi;
+    }
+}
+
 /* Instrument the memory access instruction BASE.  Insert new
    statements before or after ITER.
 
@@ -1501,111 +1608,192 @@  build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
    SSA_NAME, or a non-SSA expression.  LOCATION is the source code
    location.  IS_STORE is TRUE for a store, FALSE for a load.
    BEFORE_P is TRUE for inserting the instrumentation code before
-   ITER, FALSE for inserting it after ITER.
+   ITER, FALSE for inserting it after ITER.  IS_SCALAR_ACCESS is TRUE
+   for a scalar memory access and FALSE for memory region access.
+   NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
+   length.  ALIGN tells alignment of accessed memory object.
+
+   START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
+   memory region have already been instrumented.
 
    If BEFORE_P is TRUE, *ITER is arranged to still point to the
    statement it was pointing to prior to calling this function,
    otherwise, it points to the statement logically following it.  */
 
 static void
-build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
-		  bool before_p, bool is_store, HOST_WIDE_INT size_in_bytes,
-		  bool slow_p = false)
+build_check_stmt (location_t location, tree base, tree len,
+		  HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
+		  bool non_zero_len_p, bool before_p, bool is_store,
+		  bool is_scalar_access, unsigned int align = 0,
+		  bool start_instrumented = false,
+		  bool end_instrumented = false)
 {
-  gimple_stmt_iterator gsi;
-  basic_block then_bb, else_bb;
-  tree t, base_addr, shadow;
+  gimple_stmt_iterator gsi = *iter;
   gimple g;
-  tree shadow_ptr_type = shadow_ptr_types[size_in_bytes == 16 ? 1 : 0];
-  tree shadow_type = TREE_TYPE (shadow_ptr_type);
   tree uintptr_type
     = build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (base)), 1);
-  tree base_ssa = base;
-  HOST_WIDE_INT real_size_in_bytes = size_in_bytes;
-  tree sz_arg = NULL_TREE;
-
-  if (size_in_bytes == 1)
-    slow_p = false;
-  else if ((size_in_bytes & (size_in_bytes - 1)) != 0
-	   || size_in_bytes > 16
-	   || slow_p)
+
+  gcc_assert (!(size_in_bytes > 0 && !non_zero_len_p));
+
+  if (len)
+    len = unshare_expr (len);
+  else
+    {
+      gcc_assert (size_in_bytes != -1);
+      len = build_int_cst (pointer_sized_int_node, size_in_bytes);
+    }
+
+  if (size_in_bytes > 1)
     {
-      real_size_in_bytes = 1;
-      slow_p = true;
+      if ((size_in_bytes & (size_in_bytes - 1)) != 0
+	  || size_in_bytes > 16)
+	size_in_bytes = -1;
+      else if (align && align < size_in_bytes * BITS_PER_UNIT)
+	{
+	  /* On non-strict alignment targets, if
+	     16-byte access is just 8-byte aligned,
+	     this will result in misaligned shadow
+	     memory 2 byte load, but otherwise can
+	     be handled using one read.  */
+	  if (size_in_bytes != 16
+	      || STRICT_ALIGNMENT
+	      || align < 8 * BITS_PER_UNIT)
+	    size_in_bytes = -1;
+	}
+    }
+
+  HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
+
+  tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
+  tree shadow_type = TREE_TYPE (shadow_ptr_type);
+
+  base = unshare_expr (base);
+
+  if (use_calls_p ())
+    {
+      gsi = *iter;
+      build_check_stmt_with_calls (location, base, len, size_in_bytes, iter,
+				   before_p, is_store, is_scalar_access);
+      return;
+    }
+
+  ++asan_num_accesses;
+
+  if (!non_zero_len_p)
+    {
+      gcc_assert (before_p);
+
+      /* So, the length of the memory area to asan-protect is
+	 non-constant.  Let's guard the generated instrumentation code
+	 like:
+
+	 if (len != 0)
+	   {
+	     //asan instrumentation code goes here.
+	   }
+	 // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+			     len,
+			     build_int_cst (TREE_TYPE (len), 0),
+			     NULL_TREE, NULL_TREE);
+      gimple_set_location (g, location);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true,
+				  &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+	 pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+	 we'll generate the asan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+      build_check_stmt (location, base, len, size_in_bytes, &gsi,
+			/*non_zero_len_p*/true, /*before_p*/true, is_store,
+			is_scalar_access, align,
+			start_instrumented, end_instrumented);
+      return;
     }
 
   /* Get an iterator on the point where we can add the condition
      statement for the instrumentation.  */
-  gsi = create_cond_insert_point (iter, before_p,
+  basic_block then_bb, else_bb;
+  gsi = create_cond_insert_point (&gsi, before_p,
 				  /*then_more_likely_p=*/false,
 				  /*create_then_fallthru_edge=*/false,
 				  &then_bb,
 				  &else_bb);
 
-  base = unshare_expr (base);
-
-  /* BASE can already be an SSA_NAME; in that case, do not create a
-     new SSA_NAME for it.  */
-  if (TREE_CODE (base) != SSA_NAME)
-    {
-      g = gimple_build_assign_with_ops (TREE_CODE (base),
-					make_ssa_name (TREE_TYPE (base), NULL),
-					base, NULL_TREE);
-      gimple_set_location (g, location);
-      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-      base_ssa = gimple_assign_lhs (g);
-    }
+  tree base_ssa = maybe_create_ssa_name (location, base, &gsi,
+					 /*before_p*/false);
 
   g = gimple_build_assign_with_ops (NOP_EXPR,
 				    make_ssa_name (uintptr_type, NULL),
 				    base_ssa, NULL_TREE);
   gimple_set_location (g, location);
   gsi_insert_after (&gsi, g, GSI_NEW_STMT);
-  base_addr = gimple_assign_lhs (g);
+  tree base_addr = gimple_assign_lhs (g);
 
-  /* Build
-     (base_addr >> ASAN_SHADOW_SHIFT) + targetm.asan_shadow_offset ().  */
-  shadow = build_shadow_mem_access (&gsi, location, base_addr,
-				    shadow_ptr_type);
-
-  if (real_size_in_bytes < 8)
+  tree t;
+  if (real_size_in_bytes >= 8)
+    {
+      tree shadow = build_shadow_mem_access (&gsi, location, base_addr,
+					     shadow_ptr_type);
+      t = shadow;
+    }
+  else
     {
-      /* Slow path for 1, 2 and 4 byte accesses.
-	 Test (shadow != 0)
-	      & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow).  */
-      gimple_seq seq = NULL;
-      gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
-      gimple_seq_add_stmt (&seq, shadow_test);
-      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, base_addr, 7));
-      gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
-                                                  gimple_seq_last (seq)));
-      if (real_size_in_bytes > 1)
-        gimple_seq_add_stmt (&seq,
-                             build_assign (PLUS_EXPR, gimple_seq_last (seq),
-					   real_size_in_bytes - 1));
-      gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, gimple_seq_last (seq),
-                                               shadow));
-      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
-                                               gimple_seq_last (seq)));
-      t = gimple_assign_lhs (gimple_seq_last (seq));
-      gimple_seq_set_location (seq, location);
-      gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
-      /* For weird access sizes or misaligned, check first and last byte.  */
-      if (slow_p)
+      /* Slow path for 1, 2 and 4 byte accesses.  */
+
+      if (!start_instrumented)
 	{
+	  /* Test (shadow != 0)
+		  & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow).  */
+	  tree shadow = build_shadow_mem_access (&gsi, location, base_addr,
+						 shadow_ptr_type);
+	  gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
+	  gimple_seq seq = NULL;
+	  gimple_seq_add_stmt (&seq, shadow_test);
+	  gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, base_addr, 7));
+	  gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
+						      gimple_seq_last (seq)));
+	  if (real_size_in_bytes > 1)
+	    gimple_seq_add_stmt (&seq,
+				 build_assign (PLUS_EXPR, gimple_seq_last (seq),
+					       real_size_in_bytes - 1));
+	  gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
+						   gimple_seq_last (seq),
+						   shadow));
+	  gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
+						   gimple_seq_last (seq)));
+	  t = gimple_assign_lhs (gimple_seq_last (seq));
+	  gimple_seq_set_location (seq, location);
+	  gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
+	}
+
+      /* For non-constant, misaligned or otherwise weird access sizes,
+	 check first and last byte.  */
+      if (size_in_bytes == -1 && !end_instrumented)
+	{
+	  g = gimple_build_assign_with_ops (MINUS_EXPR,
+					    make_ssa_name (uintptr_type, NULL),
+					    len,
+					    build_int_cst (uintptr_type, 1));
+	  gimple_set_location (g, location);
+	  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+	  tree last = gimple_assign_lhs (g);
 	  g = gimple_build_assign_with_ops (PLUS_EXPR,
 					    make_ssa_name (uintptr_type, NULL),
 					    base_addr,
-					    build_int_cst (uintptr_type,
-							   size_in_bytes - 1));
+					    last);
 	  gimple_set_location (g, location);
 	  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
 	  tree base_end_addr = gimple_assign_lhs (g);
 
-	  shadow = build_shadow_mem_access (&gsi, location, base_end_addr,
-					    shadow_ptr_type);
-	  seq = NULL;
-	  shadow_test = build_assign (NE_EXPR, shadow, 0);
+	  tree shadow = build_shadow_mem_access (&gsi, location, base_end_addr,
+						 shadow_ptr_type);
+	  gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
+	  gimple_seq seq = NULL;
 	  gimple_seq_add_stmt (&seq, shadow_test);
 	  gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
 						   base_end_addr, 7));
@@ -1616,16 +1804,14 @@  build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
 						   shadow));
 	  gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
 						   gimple_seq_last (seq)));
-	  gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
-						   gimple_seq_last (seq)));
+	  if (!start_instrumented)
+	    gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
+						     gimple_seq_last (seq)));
 	  t = gimple_assign_lhs (gimple_seq_last (seq));
 	  gimple_seq_set_location (seq, location);
 	  gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
-	  sz_arg = build_int_cst (pointer_sized_int_node, size_in_bytes);
 	}
     }
-  else
-    t = shadow;
 
   g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
 			 NULL_TREE, NULL_TREE);
@@ -1634,8 +1820,23 @@  build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
 
   /* Generate call to the run-time library (e.g. __asan_report_load8).  */
   gsi = gsi_start_bb (then_bb);
-  g = gimple_build_call (report_error_func (is_store, size_in_bytes, slow_p),
-			 sz_arg ? 2 : 1, base_addr, sz_arg);
+  int nargs;
+  tree fun = report_error_func (is_store, is_scalar_access ? size_in_bytes : -1,
+				&nargs);
+  if (nargs == 1)
+      g = gimple_build_call (fun, 1, base_addr);
+  else
+    {
+      gcc_assert (nargs == 2);
+      g = gimple_build_assign_with_ops (NOP_EXPR,
+					make_ssa_name (pointer_sized_int_node,
+						       NULL),
+					len, NULL_TREE);
+      gimple_set_location (g, location);
+      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+      tree sz_arg = gimple_assign_lhs (g);
+      g = gimple_build_call (fun, nargs, base_addr, sz_arg);
+    }
   gimple_set_location (g, location);
   gsi_insert_after (&gsi, g, GSI_NEW_STMT);
 
@@ -1731,31 +1932,10 @@  instrument_derefs (gimple_stmt_iterator *iter, tree t,
   base = build_fold_addr_expr (t);
   if (!has_mem_ref_been_instrumented (base, size_in_bytes))
     {
-      bool slow_p = false;
-      if (size_in_bytes > 1)
-	{
-	  if ((size_in_bytes & (size_in_bytes - 1)) != 0
-	      || size_in_bytes > 16)
-	    slow_p = true;
-	  else
-	    {
-	      unsigned int align = get_object_alignment (t);
-	      if (align < size_in_bytes * BITS_PER_UNIT)
-		{
-		  /* On non-strict alignment targets, if
-		     16-byte access is just 8-byte aligned,
-		     this will result in misaligned shadow
-		     memory 2 byte load, but otherwise can
-		     be handled using one read.  */
-		  if (size_in_bytes != 16
-		      || STRICT_ALIGNMENT
-		      || align < 8 * BITS_PER_UNIT)
-		    slow_p = true;
-		}
-	    }
-	}
-      build_check_stmt (location, base, iter, /*before_p=*/true,
-			is_store, size_in_bytes, slow_p);
+      unsigned int align = get_object_alignment (t);
+      build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
+			/*non_zero_len_p*/size_in_bytes > 0, /*before_p=*/true,
+			is_store, /*is_scalar_access*/true, align);
       update_mem_ref_hash_table (base, size_in_bytes);
       update_mem_ref_hash_table (t, size_in_bytes);
     }
@@ -1780,142 +1960,24 @@  instrument_mem_region_access (tree base, tree len,
       || integer_zerop (len))
     return;
 
-  gimple_stmt_iterator gsi = *iter;
-
-  basic_block fallthrough_bb = NULL, then_bb = NULL;
-
   /* If the beginning of the memory region has already been
      instrumented, do not instrument it.  */
   bool start_instrumented = has_mem_ref_been_instrumented (base, 1);
 
   /* If the end of the memory region has already been instrumented, do
-     not instrument it. */
+     not instrument it.  */
   tree end = asan_mem_ref_get_end (base, len);
   bool end_instrumented = has_mem_ref_been_instrumented (end, 1);
 
-  if (start_instrumented && end_instrumented)
-    return;
+  HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
 
-  if (!is_gimple_constant (len))
-    {
-      /* So, the length of the memory area to asan-protect is
-	 non-constant.  Let's guard the generated instrumentation code
-	 like:
+  build_check_stmt (location, base, len, size_in_bytes, iter,
+		    /*non_zero_len_p*/size_in_bytes > 0, /*before_p*/true,
+		    is_store, /*is_scalar_access*/false, /*align*/0,
+		    start_instrumented, end_instrumented);
 
-	 if (len != 0)
-	   {
-	     //asan instrumentation code goes here.
-	   }
-	   // falltrough instructions, starting with *ITER.  */
-
-      gimple g = gimple_build_cond (NE_EXPR,
-				    len,
-				    build_int_cst (TREE_TYPE (len), 0),
-				    NULL_TREE, NULL_TREE);
-      gimple_set_location (g, location);
-      insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true,
-				  &then_bb, &fallthrough_bb);
-      /* Note that fallthrough_bb starts with the statement that was
-	 pointed to by ITER.  */
-
-      /* The 'then block' of the 'if (len != 0) condition is where
-	 we'll generate the asan instrumentation code now.  */
-      gsi = gsi_last_bb (then_bb);
-    }
-
-  if (!start_instrumented)
-    {
-      /* Instrument the beginning of the memory region to be accessed,
-	 and arrange for the rest of the intrumentation code to be
-	 inserted in the then block *after* the current gsi.  */
-      build_check_stmt (location, base, &gsi, /*before_p=*/true, is_store, 1);
-
-      if (then_bb)
-	/* We are in the case where the length of the region is not
-	   constant; so instrumentation code is being generated in the
-	   'then block' of the 'if (len != 0) condition.  Let's arrange
-	   for the subsequent instrumentation statements to go in the
-	   'then block'.  */
-	gsi = gsi_last_bb (then_bb);
-      else
-        {
-          *iter = gsi;
-	  /* Don't remember this access as instrumented, if length
-	     is unknown.  It might be zero and not being actually
-	     instrumented, so we can't rely on it being instrumented.  */
-          update_mem_ref_hash_table (base, 1);
-	}
-    }
-
-  if (end_instrumented)
-    return;
-
-  /* We want to instrument the access at the end of the memory region,
-     which is at (base + len - 1).  */
-
-  /* offset = len - 1;  */
-  len = unshare_expr (len);
-  tree offset;
-  gimple_seq seq = NULL;
-  if (TREE_CODE (len) == INTEGER_CST)
-    offset = fold_build2 (MINUS_EXPR, size_type_node,
-			  fold_convert (size_type_node, len),
-			  build_int_cst (size_type_node, 1));
-  else
-    {
-      gimple g;
-      tree t;
-
-      if (TREE_CODE (len) != SSA_NAME)
-	{
-	  t = make_ssa_name (TREE_TYPE (len), NULL);
-	  g = gimple_build_assign_with_ops (TREE_CODE (len), t, len, NULL);
-	  gimple_set_location (g, location);
-	  gimple_seq_add_stmt_without_update (&seq, g);
-	  len = t;
-	}
-      if (!useless_type_conversion_p (size_type_node, TREE_TYPE (len)))
-	{
-	  t = make_ssa_name (size_type_node, NULL);
-	  g = gimple_build_assign_with_ops (NOP_EXPR, t, len, NULL);
-	  gimple_set_location (g, location);
-	  gimple_seq_add_stmt_without_update (&seq, g);
-	  len = t;
-	}
-
-      t = make_ssa_name (size_type_node, NULL);
-      g = gimple_build_assign_with_ops (MINUS_EXPR, t, len,
-					build_int_cst (size_type_node, 1));
-      gimple_set_location (g, location);
-      gimple_seq_add_stmt_without_update (&seq, g);
-      offset = gimple_assign_lhs (g);
-    }
-
-  /* _1 = base;  */
-  base = unshare_expr (base);
-  gimple region_end =
-    gimple_build_assign_with_ops (TREE_CODE (base),
-				  make_ssa_name (TREE_TYPE (base), NULL),
-				  base, NULL);
-  gimple_set_location (region_end, location);
-  gimple_seq_add_stmt_without_update (&seq, region_end);
-
-  /* _2 = _1 + offset;  */
-  region_end =
-    gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
-				  make_ssa_name (TREE_TYPE (base), NULL),
-				  gimple_assign_lhs (region_end),
-				  offset);
-  gimple_set_location (region_end, location);
-  gimple_seq_add_stmt_without_update (&seq, region_end);
-  gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
-
-  /* instrument access at _2;  */
-  gsi = gsi_for_stmt (region_end);
-  build_check_stmt (location, gimple_assign_lhs (region_end),
-		    &gsi, /*before_p=*/false, is_store, 1);
-
-  if (then_bb == NULL)
+  update_mem_ref_hash_table (base, 1);
+  if (size_in_bytes != -1)
     update_mem_ref_hash_table (end, 1);
 
   *iter = gsi_for_stmt (gsi_stmt (*iter));
@@ -1957,47 +2019,30 @@  instrument_strlen_call (gimple_stmt_iterator *iter)
   location_t loc = gimple_location (call);
   tree str_arg = gimple_call_arg (call, 0);
 
-  /* Instrument the access to the first byte of str_arg.  i.e:
-
-     _1 = str_arg; instrument (_1); */
   tree cptr_type = build_pointer_type (char_type_node);
   gimple str_arg_ssa =
     gimple_build_assign_with_ops (NOP_EXPR,
 				  make_ssa_name (cptr_type, NULL),
 				  str_arg, NULL);
   gimple_set_location (str_arg_ssa, loc);
-  gimple_stmt_iterator gsi = *iter;
-  gsi_insert_before (&gsi, str_arg_ssa, GSI_NEW_STMT);
-  build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), &gsi,
-		    /*before_p=*/false, /*is_store=*/false, 1);
+  gsi_insert_before (iter, str_arg_ssa, GSI_SAME_STMT);
 
-  /* If we initially had an instruction like:
+  build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), NULL_TREE, 1, iter,
+		    /*non_zero_len_p*/true, /*before_p=*/true,
+		    /*is_store=*/false, /*is_scalar_access*/false, /*align*/0);
 
-	 int n = strlen (str)
-
-     we now want to instrument the access to str[n], after the
-     instruction above.*/
-
-  /* So let's build the access to str[n] that is, access through the
-     pointer_plus expr: (_1 + len).  */
   gimple stmt =
-    gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
-				  make_ssa_name (cptr_type, NULL),
-				  gimple_assign_lhs (str_arg_ssa),
-				  len);
+    gimple_build_assign_with_ops (PLUS_EXPR,
+				  make_ssa_name (TREE_TYPE (len), NULL),
+				  len,
+				  build_int_cst (TREE_TYPE (len), 1));
   gimple_set_location (stmt, loc);
-  gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
-
-  build_check_stmt (loc, gimple_assign_lhs (stmt), &gsi,
-		    /*before_p=*/false, /*is_store=*/false, 1);
-
-  /* Ensure that iter points to the statement logically following the
-     one it was initially pointing to.  */
-  *iter = gsi;
-  /* As *ITER has been advanced to point to the next statement, let's
-     return true to inform transform_statements that it shouldn't
-     advance *ITER anymore; otherwises it will skip that next
-     statement, which wouldn't be instrumented.  */
+  gsi_insert_after (iter, stmt, GSI_NEW_STMT);
+
+  build_check_stmt (loc, gimple_assign_lhs (stmt), len, 1, iter,
+		    /*non_zero_len_p*/true, /*before_p=*/false,
+		    /*is_store=*/false, /*is_scalar_access*/false, /*align*/0);
+
   return true;
 }
 
@@ -2570,6 +2615,7 @@  asan_instrument (void)
 {
   if (shadow_ptr_types[0] == NULL_TREE)
     asan_init_shadow_ptr_types ();
+  asan_num_accesses = 0;
   transform_statements ();
   return 0;
 }
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index de307da..53ea300 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -1174,7 +1174,7 @@  old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
 		      && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
 			 >= BUILT_IN_ASAN_REPORT_LOAD1
 		      && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
-			 <= BUILT_IN_ASAN_REPORT_STORE16)
+			 <= BUILT_IN_ASAN_STOREN)
 		    return dir_none;
 		}
 	    }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index a152472..4012f08 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10134,6 +10134,12 @@  is enabled by default when using @option{-fsanitize=address} option.
 To disable use-after-return detection use 
 @option{--param asan-use-after-return=0}.
 
+@item asan-instrumentation-with-call-threshold
+Once number of memory accesses  in function becomes greater
+or equal than this number, use callbacks instead of
+generating inline code.  E.g. to disable inline code use
+@option{--param asan-instrumentation-with-call-threshold=0}.
+
 @end table
 @end table
 
diff --git a/gcc/params.def b/gcc/params.def
index dd2e2cd..a258c08 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1084,6 +1084,12 @@  DEFPARAM (PARAM_ASAN_USE_AFTER_RETURN,
          "Enable asan builtin functions protection",
          1, 0, 1)
 
+DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD,
+         "asan-instrumentation-with-call-threshold",
+         "Use callbacks instead of inline code once number of accesses "
+         " in function becomes greater or equal than this threshold",
+         INT_MAX, 0, INT_MAX)
+
 DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS,
 	  "uninit-control-dep-attempts",
 	  "Maximum number of nested calls to search for control dependencies "
diff --git a/gcc/params.h b/gcc/params.h
index 0d6daa2..d488e32 100644
--- a/gcc/params.h
+++ b/gcc/params.h
@@ -232,5 +232,7 @@  extern void init_param_values (int *params);
   PARAM_VALUE (PARAM_ASAN_MEMINTRIN)
 #define ASAN_USE_AFTER_RETURN \
   PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN)
+#define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \
+  PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD)
 
 #endif /* ! GCC_PARAMS_H */
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 0bb4682a..b1e6f04 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -29,7 +29,7 @@  along with GCC; see the file COPYING3.  If not see
 /* Address Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v3",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
-/* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
+/* Do not reorder the BUILT_IN_ASAN_{REPORT,CHECK}* builtins, e.g. cfgcleanup.c
    relies on this order.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
 		      BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
@@ -57,6 +57,30 @@  DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N, "__asan_report_store_n",
 		      BT_FN_VOID_PTR_PTRMODE,
 		      ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD1, "__asan_load1",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD2, "__asan_load2",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD4, "__asan_load4",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD8, "__asan_load8",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD16, "__asan_load16",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOADN, "__asan_loadN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE1, "__asan_store1",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE2, "__asan_store2",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE4, "__asan_store4",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE8, "__asan_store8",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE16, "__asan_store16",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STOREN, "__asan_storeN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
 		      "__asan_register_globals",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/c-c++-common/asan/instrument-with-calls-1.c b/gcc/testsuite/c-c++-common/asan/instrument-with-calls-1.c
new file mode 100644
index 0000000..80f7620
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/instrument-with-calls-1.c
@@ -0,0 +1,10 @@ 
+/* { dg-do assemble } */
+/* { dg-options "--param asan-instrumentation-with-call-threshold=0 -save-temps" } */
+
+void f(char *a, int *b) {
+  *b = *a;
+}
+
+/* { dg-final { scan-assembler "__asan_load1" } } */
+/* { dg-final { scan-assembler "__asan_store4" } } */
+/* { dg-final { cleanup-saved-temps } } */
diff --git a/gcc/testsuite/c-c++-common/asan/instrument-with-calls-2.c b/gcc/testsuite/c-c++-common/asan/instrument-with-calls-2.c
new file mode 100644
index 0000000..570f796
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/instrument-with-calls-2.c
@@ -0,0 +1,16 @@ 
+/* { dg-do assemble } */
+/* { dg-options "--param asan-instrumentation-with-call-threshold=1 -save-temps" } */
+
+int x;
+
+void f(int *a, int *b) {
+  *a = 0;
+  asm volatile ("" ::: "memory");
+  x = *b;
+}
+
+/* { dg-final { scan-assembler-not "__asan_store4" } } */
+/* { dg-final { scan-assembler "__asan_report_store4" } } */
+/* { dg-final { scan-assembler "__asan_load4" } } */
+/* { dg-final { scan-assembler-not "__asan_report_load4" } } */
+/* { dg-final { cleanup-saved-temps } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c
index fa52e0c..c7c594e 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c
@@ -16,12 +16,11 @@  test0 ()
   tab[0] = 1;
   tab[1] = 2;
 
-  /* __builtin___asan_report_load1 called 1 time for the store
-     below.  */
-  char t0 = tab[1];
-
   /* This load should not be instrumented because it is to the same
      memory location as above.  */
+  char t0 = tab[1];
+
+  /* Likewise.  */
   char t1 = tab[1];
 
   return t0 + t1;
@@ -36,7 +35,7 @@  test1 (int i)
     the initialization.  */
   foo[i] = 1;
 
-  /*__builtin___asan_report_store1 called 2 times here to instrument
+  /*__builtin___asan_report_store_n called once here to instrument
     the store to the memory region of tab.  */
   __builtin_memset (tab, 3, sizeof (tab));
 
@@ -44,8 +43,8 @@  test1 (int i)
   __builtin_memset (tab, 4, sizeof (tab));
   __builtin_memset (tab, 5, sizeof (tab));
 
-  /* There are 2 calls to __builtin___asan_report_store1 and 2 calls
-     to __builtin___asan_report_load1 to instrument the store to
+  /* There is a call to __builtin___asan_report_store_n and a call
+     to __builtin___asan_report_load_n to instrument the store to
      (subset of) the memory region of tab.  */
   __builtin_memcpy (&tab[1], foo + i, 3);
 
@@ -53,7 +52,7 @@  test1 (int i)
      the reference to tab[1] has been already instrumented above.  */
   return tab[1];
 
-  /* So for these function, there should be 7 calls to
+  /* So for these functions, there should be 3 calls to
      __builtin___asan_report_store1.  */
 }
 
@@ -63,6 +62,7 @@  main ()
   return test0 () && test1 (0);
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 2 "asan0" }  } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 3 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 1 "asan0" }  } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-2.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-2.c
index 28525e0..143312f 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-2.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-2.c
@@ -20,6 +20,7 @@  main ()
   __builtin_memset (tab, 1, 3);
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 3 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report" 3 "asan0" }  } */
+/* { dg-final { scan-tree-dump-times "& 7" 3 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report" 2 "asan0" }  } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-4.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-4.c
index b2e7284..da91cd5 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-4.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-4.c
@@ -5,9 +5,13 @@ 
 void
 foo  (int *a, char *b, char *c)
 {
+  /* One check for c[0], one check for a[], one check for c, two checks for b.  */
   __builtin_memmove (c, b, a[c[0]]);
+  /* For a total of 5 checks.  */
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 3 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-5.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-5.c
index ead3f58..134be66 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-5.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-5.c
@@ -5,9 +5,14 @@ 
 void
 foo  (int *a, char *b, char *c)
 {
+  /* One check for b[0], one check for a[], 2 checks for c and one checks for b.  */
   __builtin_memmove (c, b, a[b[0]]);
+  /* For a total of 5 checks.  */
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 2 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-6.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-6.c
index e4691bc..55c8ee3 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-6.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-6.c
@@ -5,10 +5,16 @@ 
 void
 foo  (int *a, char *b, char *c)
 {
+  /* One check for c[0], one check for a[], one check for c and 2 checks for b.  */
   __builtin_memmove (c, b, a[c[0]]);
+  /* One check for a[], one check for c and one check for b.  */
   __builtin_memmove (c, b, a[b[0]]);
+  /* For a total of 8 checks.  */
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 5 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "& 7" 8 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-7.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-7.c
index bf40a03..a04956d 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-7.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-7.c
@@ -13,11 +13,15 @@  struct S
 int
 foo  (int *a, char *b, char *c)
 {
+  /* 2 checks for s.a, 2 checks for e.  */
   int d = __builtin_memcmp (s.a, e, 100);
+  /* One check for s.a and one check for e.  */
   d += __builtin_memcmp (s.a, e, 200);
+  /* For a total of 6 checks.  */
   return d;
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 6 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "& 7" 6 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 4 "asan0" } } */
 /* { dg-final { scan-tree-dump-not "__builtin___asan_report_store" "asan0" } } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-8.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-8.c
index 38ea7a2..308a133 100644
--- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-8.c
+++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-8.c
@@ -5,10 +5,16 @@ 
 char
 foo  (int *a, char *b, char *c)
 {
+  /* One check for b[0], one check for a[], two checks for c and one check for b.  */
   __builtin_memmove (c, b, a[b[0]]);
+  /* No checks here.  */
   return c[0] + b[0];
+  /* For a total of 5 checks.  */
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 3 "asan0" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
 /* { dg-final { cleanup-tree-dump "asan0" } } */