diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 154964bd0687aaccccd9d0485bae8dbd81b614f2..2ca93e30e8f2a2298753435118149f983683a1d4 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -986,6 +986,18 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
 	    = backwards ^ reverse
 	      ? MAX ((int) bitsize - (i + 1) * BITS_PER_WORD, 0)
 	      : i * BITS_PER_WORD;
+
+	  /* No further action is needed if the target is a register and if
+	     this field lies completely outside that register.  */
+	  if (REG_P (op0) && known_ge (bitnum + bit_offset,
+				       GET_MODE_BITSIZE (GET_MODE (op0))))
+	    {
+	      if (backwards ^ reverse)
+		continue;
+	      /* For forward operation we are finished.  */
+	      return true;
+	    }
+
 	  /* Starting word number in the value.  */
 	  const unsigned int wordnum
 	    = backwards
diff --git a/gcc/testsuite/gcc.dg/torture/pr111821.c b/gcc/testsuite/gcc.dg/torture/pr111821.c
new file mode 100644
index 0000000000000000000000000000000000000000..eec6eed6c8ed026030c941dd59ced059b3d1d70a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr111821.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+
+typedef union { char a[__INT_MAX__ / 4]; } T;
+unsigned short f(const void *p)
+{
+  unsigned short v;
+  *(T *)(void *)(&v) = *(const T *)p;
+  return v;
+}