diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index f606b97389f..460d333e3da 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -2369,6 +2369,14 @@ a unit of memory is accessed.  @var{alias} specifies an alias set for the
 reference.  In general two items are in different alias sets if they cannot
 reference the same memory address.
 
+The @var{addr} expression can represent either a scalar base address, or a
+vector of addresses (using an appropriate vector mode).  In the vector case,
+the number of lanes in the address mode must match the number of lanes in the
+data mode @var{m}.  Each vector lane can be viewed as an independent, parallel
+memory access of the corresponding scalar mode.  If multiple lanes represent
+the same, or overlapping, memory location then the effect is undefined.  All
+lanes are assumed to have the same attributes (address space, volatile, etc.).
+
 The construct @code{(mem:BLK (scratch))} is considered to alias all
 other memories.  Thus it may be used as a memory barrier in epilogue
 stack deallocation patterns.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index fc9acdb38da..07e9265585c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11497,16 +11497,27 @@ c_register_addr_space ("__ea", ADDR_SPACE_EA);
 @deftypefn {Target Hook} scalar_int_mode TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space})
 Define this to return the machine mode to use for pointers to
 @var{address_space} if the target supports named address spaces.
+
+Targets that support vectors of pointers should return only the scalar base
+mode here, but permit the vector modes in
+@code{TARGET_ADDR_SPACE_VALID_POINTER_MODE}.
+
 The default version of this hook returns @code{ptr_mode}.
 @end deftypefn
 
 @deftypefn {Target Hook} scalar_int_mode TARGET_ADDR_SPACE_ADDRESS_MODE (addr_space_t @var{address_space})
 Define this to return the machine mode to use for addresses in
 @var{address_space} if the target supports named address spaces.
+
+Targets that support vectors of addresses should return only the scalar base
+mode here, but permit the vector modes in
+@code{TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P} and
+@code{TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS}.
+
 The default version of this hook returns @code{Pmode}.
 @end deftypefn
 
-@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_VALID_POINTER_MODE (scalar_int_mode @var{mode}, addr_space_t @var{as})
+@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_VALID_POINTER_MODE (machine_mode @var{mode}, addr_space_t @var{as})
 Define this to return nonzero if the port can handle pointers
 with machine mode @var{mode} to address space @var{as}.  This target
 hook is the same as the @code{TARGET_VALID_POINTER_MODE} target hook,
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index 4a23eaefe02..ea4d757bed3 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -540,14 +540,29 @@ gen_rtx_CONST_INT (machine_mode mode ATTRIBUTE_UNUSED, HOST_WIDE_INT arg)
   return *slot;
 }
 
+/* Return a CONST_INT, CONST_POLY_INT, or CONST_VECTOR containing the given
+   value.  In the case of a vector, the value will be duplicated.  */
+
 rtx
 gen_int_mode (poly_int64 c, machine_mode mode)
 {
-  c = trunc_int_for_mode (c, mode);
+  machine_mode s_mode = (VECTOR_MODE_P (mode) ? GET_MODE_INNER (mode) : mode);
+  rtx val;
+
+  c = trunc_int_for_mode (c, s_mode);
   if (c.is_constant ())
-    return GEN_INT (c.coeffs[0]);
-  unsigned int prec = GET_MODE_PRECISION (as_a <scalar_mode> (mode));
-  return immed_wide_int_const (poly_wide_int::from (c, prec, SIGNED), mode);
+    val = GEN_INT (c.coeffs[0]);
+  else
+    {
+      unsigned int prec = GET_MODE_PRECISION (as_a <scalar_mode> (s_mode));
+      val = immed_wide_int_const (poly_wide_int::from (c, prec, SIGNED),
+				  s_mode);
+    }
+
+  if (VECTOR_MODE_P (mode))
+    val = gen_const_vec_duplicate (mode, val);
+
+  return val;
 }
 
 /* CONST_DOUBLEs might be created from pairs of integers, or from
@@ -2381,7 +2396,7 @@ adjust_address_1 (rtx memref, machine_mode mode, poly_int64 offset,
 {
   rtx addr = XEXP (memref, 0);
   rtx new_rtx;
-  scalar_int_mode address_mode;
+  machine_mode address_mode;
   class mem_attrs attrs (*get_mem_attrs (memref)), *defattrs;
   unsigned HOST_WIDE_INT max_align;
 #ifdef POINTERS_EXTEND_UNSIGNED
@@ -2415,7 +2430,10 @@ adjust_address_1 (rtx memref, machine_mode mode, poly_int64 offset,
   /* Convert a possibly large offset to a signed value within the
      range of the target address space.  */
   address_mode = get_address_mode (memref);
-  offset = trunc_int_for_mode (offset, address_mode);
+  if (!VECTOR_MODE_P (address_mode))
+    offset = trunc_int_for_mode (offset, address_mode);
+  else
+    offset = trunc_int_for_mode (offset, GET_MODE_INNER (address_mode));
 
   if (adjust_address)
     {
diff --git a/gcc/explow.cc b/gcc/explow.cc
index ec2bc9bc9b6..9c7c834aaab 100644
--- a/gcc/explow.cc
+++ b/gcc/explow.cc
@@ -298,8 +298,13 @@ convert_memory_address_addr_space_1 (scalar_int_mode to_mode ATTRIBUTE_UNUSED,
 				     bool in_const ATTRIBUTE_UNUSED,
 				     bool no_emit ATTRIBUTE_UNUSED)
 {
+  machine_mode xmode = GET_MODE (x);
+  bool vecaddr_p = VECTOR_MODE_P (GET_MODE (x));
+  if (vecaddr_p)
+    xmode = GET_MODE_INNER (xmode);
+
 #ifndef POINTERS_EXTEND_UNSIGNED
-  gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
+  gcc_assert (xmode == to_mode || xmode == VOIDmode);
   return x;
 #else /* defined(POINTERS_EXTEND_UNSIGNED) */
   scalar_int_mode pointer_mode, address_mode, from_mode;
@@ -307,9 +312,12 @@ convert_memory_address_addr_space_1 (scalar_int_mode to_mode ATTRIBUTE_UNUSED,
   enum rtx_code code;
 
   /* If X already has the right mode, just return it.  */
-  if (GET_MODE (x) == to_mode)
+  if (xmode == to_mode)
     return x;
 
+  /* TODO: support vector conversions.  */
+  gcc_assert (!vecaddr_p);
+
   pointer_mode = targetm.addr_space.pointer_mode (as);
   address_mode = targetm.addr_space.address_mode (as);
   from_mode = to_mode == pointer_mode ? address_mode : pointer_mode;
diff --git a/gcc/recog.cc b/gcc/recog.cc
index f9cff68e457..f0553fdfd05 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -1632,7 +1632,9 @@ address_operand (rtx op, machine_mode mode)
 {
   /* Wrong mode for an address expr.  */
   if (GET_MODE (op) != VOIDmode
-      && ! SCALAR_INT_MODE_P (GET_MODE (op)))
+      && !(SCALAR_INT_MODE_P (GET_MODE (op))
+	   || (VECTOR_MODE_P (GET_MODE (op))
+	       && SCALAR_INT_MODE_P (GET_MODE_INNER (GET_MODE (op))))))
     return false;
 
   return memory_address_p (mode, op);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 01b4c6fd957..380e32b1fd4 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3691,7 +3691,7 @@ inline rtx single_set (const rtx_insn *insn)
   return single_set_2 (insn, PATTERN (insn));
 }
 
-extern scalar_int_mode get_address_mode (rtx mem);
+extern machine_mode get_address_mode (rtx mem);
 extern bool rtx_addr_can_trap_p (const_rtx);
 extern bool nonzero_address_p (const_rtx);
 extern bool rtx_unstable_p (const_rtx);
diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc
index 5274a5c59cf..f741093f70e 100644
--- a/gcc/rtlanal.cc
+++ b/gcc/rtlanal.cc
@@ -6295,7 +6295,7 @@ low_bitmask_len (machine_mode mode, unsigned HOST_WIDE_INT m)
 
 /* Return the mode of MEM's address.  */
 
-scalar_int_mode
+machine_mode
 get_address_mode (rtx mem)
 {
   machine_mode mode;
@@ -6303,7 +6303,7 @@ get_address_mode (rtx mem)
   gcc_assert (MEM_P (mem));
   mode = GET_MODE (XEXP (mem, 0));
   if (mode != VOIDmode)
-    return as_a <scalar_int_mode> (mode);
+    return mode;
   return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
 }
 
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 92a2a6e954a..c62eba41743 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -8679,7 +8679,10 @@ simplify_context::simplify_subreg (machine_mode outermode, rtx op,
       && (! MEM_VOLATILE_P (op)
 	  || ! have_insn_for (SET, innermode))
       && !(STRICT_ALIGNMENT && MEM_ALIGN (op) < GET_MODE_ALIGNMENT (outermode))
-      && known_le (outersize, innersize))
+      && known_le (outersize, innersize)
+      /* You can't get the Nth element of a vector of addresses by adding
+	 offsets.  */
+      && !VECTOR_MODE_P (GET_MODE (XEXP (op, 0))))
     return adjust_address_nv (op, outermode, byte);
 
   /* Handle complex or vector values represented as CONCAT or VEC_CONCAT
diff --git a/gcc/target.def b/gcc/target.def
index 884fe1bd57e..283b81220d1 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3448,7 +3448,10 @@ HOOK_VECTOR (TARGET_ADDR_SPACE_HOOKS, addr_space)
 DEFHOOK
 (pointer_mode,
  "Define this to return the machine mode to use for pointers to\n\
-@var{address_space} if the target supports named address spaces.\n\
+@var{address_space} if the target supports named address spaces.\n\n\
+Targets that support vectors of pointers should return only the scalar base\n\
+mode here, but permit the vector modes in\n\
+@code{TARGET_ADDR_SPACE_VALID_POINTER_MODE}.\n\n\
 The default version of this hook returns @code{ptr_mode}.",
  scalar_int_mode, (addr_space_t address_space),
  default_addr_space_pointer_mode)
@@ -3457,7 +3460,11 @@ The default version of this hook returns @code{ptr_mode}.",
 DEFHOOK
 (address_mode,
  "Define this to return the machine mode to use for addresses in\n\
-@var{address_space} if the target supports named address spaces.\n\
+@var{address_space} if the target supports named address spaces.\n\n\
+Targets that support vectors of addresses should return only the scalar base\n\
+mode here, but permit the vector modes in\n\
+@code{TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P} and\n\
+@code{TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS}.\n\n\
 The default version of this hook returns @code{Pmode}.",
  scalar_int_mode, (addr_space_t address_space),
  default_addr_space_address_mode)
@@ -3473,7 +3480,7 @@ except that it includes explicit named address space support.  The default\n\
 version of this hook returns true for the modes returned by either the\n\
 @code{TARGET_ADDR_SPACE_POINTER_MODE} or @code{TARGET_ADDR_SPACE_ADDRESS_MODE}\n\
 target hooks for the given address space.",
- bool, (scalar_int_mode mode, addr_space_t as),
+ bool, (machine_mode mode, addr_space_t as),
  default_addr_space_valid_pointer_mode)
 
 /* True if an address is a valid memory address to a given named address
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 388f696c8aa..e89e9feb79e 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -1728,10 +1728,10 @@ default_addr_space_address_mode (addr_space_t addrspace ATTRIBUTE_UNUSED)
    To match the above, the same modes apply to all address spaces.  */
 
 bool
-default_addr_space_valid_pointer_mode (scalar_int_mode mode,
+default_addr_space_valid_pointer_mode (machine_mode mode,
 				       addr_space_t as ATTRIBUTE_UNUSED)
 {
-  return targetm.valid_pointer_mode (mode);
+  return targetm.valid_pointer_mode (as_a <scalar_int_mode> (mode));
 }
 
 /* Some places still assume that all pointer or address modes are the
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 86de6ef8a69..798a84d0e13 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -206,8 +206,7 @@ extern bool default_valid_pointer_mode (scalar_int_mode);
 extern bool default_ref_may_alias_errno (class ao_ref *);
 extern scalar_int_mode default_addr_space_pointer_mode (addr_space_t);
 extern scalar_int_mode default_addr_space_address_mode (addr_space_t);
-extern bool default_addr_space_valid_pointer_mode (scalar_int_mode,
-						   addr_space_t);
+extern bool default_addr_space_valid_pointer_mode (machine_mode, addr_space_t);
 extern bool default_addr_space_legitimate_address_p (machine_mode, rtx, bool,
 						     addr_space_t, code_helper);
 extern rtx default_addr_space_legitimize_address (rtx, rtx, machine_mode,
