diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe1d9c3b257..a9263afaef2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2016-11-16 Richard Sandiford + Alan Hayward + David Sherwood + + * expr.c (emit_group_load_1): Tighten check for whether an + access involves only one operand of a CONCAT. Use extract_bit_field + for constants if the bit range does span the whole operand. + 2016-11-16 Richard Sandiford Alan Hayward David Sherwood diff --git a/gcc/expr.c b/gcc/expr.c index 0b0946de345..985c2b3285f 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2175,19 +2175,22 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize) { unsigned int slen = GET_MODE_SIZE (GET_MODE (src)); unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0))); + unsigned int elt = bytepos / slen0; + unsigned int subpos = bytepos % slen0; - if ((bytepos == 0 && bytelen == slen0) - || (bytepos != 0 && bytepos + bytelen <= slen)) + if (subpos + bytelen <= slen0) { /* The following assumes that the concatenated objects all have the same size. In this case, a simple calculation can be used to determine the object and the bit field to be extracted. */ - tmps[i] = XEXP (src, bytepos / slen0); - if (! CONSTANT_P (tmps[i]) - && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode)) + tmps[i] = XEXP (src, elt); + if (subpos != 0 + || subpos + bytelen != slen0 + || (!CONSTANT_P (tmps[i]) + && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))) tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT, - (bytepos % slen0) * BITS_PER_UNIT, + subpos * BITS_PER_UNIT, 1, NULL_RTX, mode, mode, false); } else