Index: asan.c
===================================================================
--- asan.c	(revision 269546)
+++ asan.c	(working copy)
@@ -1380,6 +1380,7 @@ asan_emit_stack_protection (rtx base, rt
   unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
   tree str_cst, decl, id;
   int use_after_return_class = -1;
+  unsigned int shift;
 
   if (shadow_ptr_types[0] == NULL_TREE)
     asan_init_shadow_ptr_types ();
@@ -1524,8 +1525,19 @@ asan_emit_stack_protection (rtx base, rt
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (id) = 1;
   emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
-  shadow_base = expand_binop (Pmode, lshr_optab, base,
-			      gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT),
+  shadow_base = base;
+  if (targetm.asan_shadow_left_shift
+      && (shift = targetm.asan_shadow_left_shift ()) > 0)
+    {
+      shadow_base = expand_binop (Pmode, ashl_optab, shadow_base,
+				  gen_int_shift_amount (Pmode, shift),
+				  NULL_RTX, 1, OPTAB_DIRECT);
+      shift += ASAN_SHADOW_SHIFT;
+    }
+  else
+    shift = ASAN_SHADOW_SHIFT;
+  shadow_base = expand_binop (Pmode, lshr_optab, shadow_base,
+			      gen_int_shift_amount (Pmode, shift),
 			      NULL_RTX, 1, OPTAB_DIRECT);
   shadow_base
     = plus_constant (Pmode, shadow_base,
@@ -2023,9 +2035,24 @@ build_shadow_mem_access (gimple_stmt_ite
 {
   tree t, uintptr_type = TREE_TYPE (base_addr);
   tree shadow_type = TREE_TYPE (shadow_ptr_type);
+  unsigned int shift;
   gimple *g;
 
-  t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
+  if (targetm.asan_shadow_left_shift
+      && (shift = targetm.asan_shadow_left_shift ()) > 0)
+    {
+      t = build_int_cst (uintptr_type, shift);
+      g = gimple_build_assign (make_ssa_name (uintptr_type), LSHIFT_EXPR,
+			       base_addr, t);
+      gimple_set_location (g, location);
+      gsi_insert_after (gsi, g, GSI_NEW_STMT);
+      base_addr = gimple_assign_lhs (g);
+      shift += ASAN_SHADOW_SHIFT;
+    }
+  else
+    shift = ASAN_SHADOW_SHIFT;
+
+  t = build_int_cst (uintptr_type, shift);
   g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
 			   base_addr, t);
   gimple_set_location (g, location);
Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 269546)
+++ config/sparc/sparc.c	(working copy)
@@ -674,6 +674,7 @@ static rtx sparc_struct_value_rtx (tree,
 static rtx sparc_function_value (const_tree, const_tree, bool);
 static rtx sparc_libcall_value (machine_mode, const_rtx);
 static bool sparc_function_value_regno_p (const unsigned int);
+static unsigned int sparc_asan_shadow_left_shift (void);
 static unsigned HOST_WIDE_INT sparc_asan_shadow_offset (void);
 static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static void sparc_file_end (void);
@@ -835,6 +836,9 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
 
+#undef TARGET_ASAN_SHADOW_LEFT_SHIFT
+#define TARGET_ASAN_SHADOW_LEFT_SHIFT sparc_asan_shadow_left_shift
+
 #undef TARGET_ASAN_SHADOW_OFFSET
 #define TARGET_ASAN_SHADOW_OFFSET sparc_asan_shadow_offset
 
@@ -12493,7 +12497,16 @@ sparc_init_machine_status (void)
 {
   return ggc_cleared_alloc<machine_function> ();
 }
-
+
+/* Implement the TARGET_ASAN_SHADOW_LEFT_SHIFT hook.  */
+
+static unsigned int
+sparc_asan_shadow_left_shift (void)
+{
+  /* This is tailored to the 52-bit VM layout on SPARC-T4 and later.  */
+  return TARGET_ARCH64 ? 12 : 0;
+}
+
 /* Implement the TARGET_ASAN_SHADOW_OFFSET hook.  */
 
 static unsigned HOST_WIDE_INT
Index: doc/tm.texi
===================================================================
--- doc/tm.texi	(revision 269546)
+++ doc/tm.texi	(working copy)
@@ -11975,10 +11975,17 @@ MIPS, where add-immediate takes a 16-bit
 is zero, which disables this optimization.
 @end deftypevr
 
+@deftypefn {Target Hook} {unsigned int} TARGET_ASAN_SHADOW_LEFT_SHIFT (void)
+Return the amount by which an address must first be shifted to the left
+and then back to the right, before being normally shifted to the right,
+to get the corresponding Address Sanitizer shadow address.  NULL means that
+such a left shift is not needed.
+@end deftypefn
+
 @deftypefn {Target Hook} {unsigned HOST_WIDE_INT} TARGET_ASAN_SHADOW_OFFSET (void)
-Return the offset bitwise ored into shifted address to get corresponding
-Address Sanitizer shadow memory address.  NULL if Address Sanitizer is not
-supported by the target.
+Return the offset added to a shifted address to get the corresponding
+Address Sanitizer shadow memory address.  NULL means that the Address
+Sanitizer is not supported by the target.
 @end deftypefn
 
 @deftypefn {Target Hook} {unsigned HOST_WIDE_INT} TARGET_MEMMODEL_CHECK (unsigned HOST_WIDE_INT @var{val})
Index: doc/tm.texi.in
===================================================================
--- doc/tm.texi.in	(revision 269546)
+++ doc/tm.texi.in	(working copy)
@@ -8110,6 +8110,8 @@ and the associated definitions of those
 
 @hook TARGET_CONST_ANCHOR
 
+@hook TARGET_ASAN_SHADOW_LEFT_SHIFT
+
 @hook TARGET_ASAN_SHADOW_OFFSET
 
 @hook TARGET_MEMMODEL_CHECK
Index: target.def
===================================================================
--- target.def	(revision 269546)
+++ target.def	(working copy)
@@ -4307,14 +4307,24 @@ DEFHOOK
 memory model bits are allowed.",
  unsigned HOST_WIDE_INT, (unsigned HOST_WIDE_INT val), NULL)
 
-/* Defines an offset bitwise ored into shifted address to get corresponding
-   Address Sanitizer shadow address, or -1 if Address Sanitizer is not
-   supported by the target.  */
+/* Defines the amount by which an address must first be shifted to the left
+   to get the corresponding Address Sanitizer shadow address.  */
+DEFHOOK
+(asan_shadow_left_shift,
+ "Return the amount by which an address must first be shifted to the left\n\
+and then back to the right, before being normally shifted to the right,\n\
+to get the corresponding Address Sanitizer shadow address.  NULL means that\n\
+such a left shift is not needed.",
+ unsigned int, (void),
+ NULL)
+ 
+/* Defines the offset added to a shifted address to get the corresponding
+   Address Sanitizer shadow address.  */
 DEFHOOK
 (asan_shadow_offset,
- "Return the offset bitwise ored into shifted address to get corresponding\n\
-Address Sanitizer shadow memory address.  NULL if Address Sanitizer is not\n\
-supported by the target.",
+ "Return the offset added to a shifted address to get the corresponding\n\
+Address Sanitizer shadow memory address.  NULL means that the Address\n\
+Sanitizer is not supported by the target.",
  unsigned HOST_WIDE_INT, (void),
  NULL)
 
