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; +}