> This isn't intended to change the behaviour, just rewrite the > existing logic in a different (and hopefully clearer) way.
Yes, I agree that it's an improvement. A few remarks below. > diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c > index ca6cced..7c0acf5 100644 > --- a/gcc/rtlanal.c > +++ b/gcc/rtlanal.c > @@ -3601,31 +3601,28 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, unsigned int offset, machine_mode ymode, > struct subreg_info *info) > { > - int nregs_xmode, nregs_ymode; > - int mode_multiple, nregs_multiple; > - int offset_adj, y_offset, y_offset_adj; > - int regsize_xmode, regsize_ymode; > - bool rknown; > + unsigned int nregs_xmode, nregs_ymode; > > gcc_assert (xregno < FIRST_PSEUDO_REGISTER); > > - rknown = false; > + unsigned int xsize = GET_MODE_SIZE (xmode); > + unsigned int ysize = GET_MODE_SIZE (ymode); > + bool rknown = false; > > /* If there are holes in a non-scalar mode in registers, we expect > - that it is made up of its units concatenated together. */ > + that it is made up of its units concatenated together. Each scalar > + unit occupies at least one register. */ Why using "scalar unit" while the first sentence uses "unit"? Are they different units? What's the status of the new sentence? Assertion? Expectation? I'd also make the first sentence grammatical. > if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) > { > - machine_mode xmode_unit; > - > nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); > - xmode_unit = GET_MODE_INNER (xmode); > + unsigned int nunits = GET_MODE_NUNITS (xmode); > + machine_mode xmode_unit = GET_MODE_INNER (xmode); > gcc_assert (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode_unit)); > gcc_assert (nregs_xmode > - == (GET_MODE_NUNITS (xmode) > + == (nunits > * HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode_unit))); > gcc_assert (hard_regno_nregs[xregno][xmode] > - == (hard_regno_nregs[xregno][xmode_unit] > - * GET_MODE_NUNITS (xmode))); > + == hard_regno_nregs[xregno][xmode_unit] * nunits); > > /* You can only ask for a SUBREG of a value with holes in the middle > if you don't cross the holes. (Such a SUBREG should be done by > @@ -3635,11 +3632,9 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, 3 for each part, but in memory it's two 128-bit parts. > Padding is assumed to be at the end (not necessarily the 'high part') > of each unit. */ > - if ((offset / GET_MODE_SIZE (xmode_unit) + 1 > - < GET_MODE_NUNITS (xmode)) > + if ((offset / GET_MODE_SIZE (xmode_unit) + 1 < nunits) > && (offset / GET_MODE_SIZE (xmode_unit) > - != ((offset + GET_MODE_SIZE (ymode) - 1) > - / GET_MODE_SIZE (xmode_unit)))) > + != ((offset + ysize - 1) / GET_MODE_SIZE (xmode_unit)))) > { > info->representable_p = false; > rknown = true; This part is OK. > @@ -3651,18 +3646,17 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, nregs_ymode = hard_regno_nregs[xregno][ymode]; > > /* Paradoxical subregs are otherwise valid. */ > - if (!rknown > - && offset == 0 > - && GET_MODE_PRECISION (ymode) > GET_MODE_PRECISION (xmode)) > + if (!rknown && offset == 0 && ysize > xsize) > { > info->representable_p = true; > /* If this is a big endian paradoxical subreg, which uses more > actual hard registers than the original register, we must > return a negative offset so that we find the proper highpart > of the register. */ > - if (GET_MODE_SIZE (ymode) > UNITS_PER_WORD > - ? REG_WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN) > - info->offset = nregs_xmode - nregs_ymode; > + if (REG_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN && ysize > > UNITS_PER_WORD + ? REG_WORDS_BIG_ENDIAN > + : byte_lowpart_offset (ymode, xmode) != 0) > + info->offset = (int) nregs_xmode - (int) nregs_ymode; > else > info->offset = 0; > info->nregs = nregs_ymode; This part is not OK, it turns straightforward code into convoluted code. > @@ -3673,31 +3667,23 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, modes, we cannot generally form this subreg. */ > if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode) > && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode) > - && (GET_MODE_SIZE (xmode) % nregs_xmode) == 0 > - && (GET_MODE_SIZE (ymode) % nregs_ymode) == 0) > + && (xsize % nregs_xmode) == 0 > + && (ysize % nregs_ymode) == 0) > { > - regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; > - regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; > - if (!rknown && regsize_xmode > regsize_ymode && nregs_ymode > 1) > - { > - info->representable_p = false; > - info->nregs > - = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; > - info->offset = offset / regsize_xmode; > - return; > - } > - if (!rknown && regsize_ymode > regsize_xmode && nregs_xmode > 1) > + int regsize_xmode = xsize / nregs_xmode; > + int regsize_ymode = ysize / nregs_ymode; > + if (!rknown > + && ((nregs_ymode > 1 && regsize_xmode > regsize_ymode) > + || (nregs_xmode > 1 && regsize_ymode > regsize_xmode))) > { > info->representable_p = false; > - info->nregs > - = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; > + info->nregs = CEIL (ysize, regsize_xmode); > info->offset = offset / regsize_xmode; > return; > } > /* It's not valid to extract a subreg of mode YMODE at OFFSET that > would go outside of XMODE. */ > - if (!rknown > - && GET_MODE_SIZE (ymode) + offset > GET_MODE_SIZE (xmode)) > + if (!rknown && ysize + offset > xsize) > { > info->representable_p = false; > info->nregs = nregs_ymode; This part is OK. > @@ -3717,7 +3703,7 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, info->representable_p = true; > info->nregs = nregs_ymode; > info->offset = offset / regsize_ymode; > - gcc_assert (info->offset + info->nregs <= nregs_xmode); > + gcc_assert (info->offset + nregs_ymode <= nregs_xmode); > return; > } > } This part is not OK, the assertion is intended to be on INFO. > @@ -3736,47 +3722,39 @@ subreg_get_info (unsigned int xregno, machine_mode > xmode, } > } > > - /* This should always pass, otherwise we don't know how to verify > - the constraint. These conditions may be relaxed but > - subreg_regno_offset would need to be redesigned. */ > - gcc_assert ((GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)) == 0); > + /* Set NUM_BLOCKS to the number of independently-representable YMODE > + values there are in (reg:XMODE XREGNO). We can view the register > + as consisting of this number of independent "blocks", where each > + block occupies NREGS_YMODE registers and contains exactly one > + representable YMODE value. */ > gcc_assert ((nregs_xmode % nregs_ymode) == 0); > + unsigned int num_blocks = nregs_xmode / nregs_ymode; I find the "exactly" slightly confusing here, because it can make you think that it contains the number of bytes of a YMODE value; a possible better wording would be "a single" instead of "exactly one". > - if (WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN > - && GET_MODE_SIZE (xmode) > UNITS_PER_WORD) > - { > - HOST_WIDE_INT xsize = GET_MODE_SIZE (xmode); > - HOST_WIDE_INT ysize = GET_MODE_SIZE (ymode); > - HOST_WIDE_INT off_low = offset & (ysize - 1); > - HOST_WIDE_INT off_high = offset & ~(ysize - 1); > - offset = (xsize - ysize - off_high) | off_low; > - } > - /* The XMODE value can be seen as a vector of NREGS_XMODE > - values. The subreg must represent a lowpart of given field. > - Compute what field it is. */ > - offset_adj = offset; > - offset_adj -= subreg_lowpart_offset (ymode, > - mode_for_size (GET_MODE_BITSIZE (xmode) > - / nregs_xmode, > - MODE_INT, 0)); > - > - /* Size of ymode must not be greater than the size of xmode. */ > - mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); > - gcc_assert (mode_multiple != 0); > - > - y_offset = offset / GET_MODE_SIZE (ymode); > - y_offset_adj = offset_adj / GET_MODE_SIZE (ymode); > - nregs_multiple = nregs_xmode / nregs_ymode; > - > - gcc_assert ((offset_adj % GET_MODE_SIZE (ymode)) == 0); > - gcc_assert ((mode_multiple % nregs_multiple) == 0); > + /* Calculate the number of bytes in each block. This must always > + be exact, otherwise we don't know how to verify the constraint. > + These conditions may be relaxed but subreg_regno_offset would > + need to be redesigned. */ > + gcc_assert ((xsize % num_blocks) == 0); > + unsigned int bytes_per_block = xsize / num_blocks; > + > + /* Get the number of the first block that contains the subreg and the > byte + offset of the subreg from the start of that block. */ > + unsigned int block_number = offset / bytes_per_block; > + unsigned int subblock_offset = offset % bytes_per_block; > > if (!rknown) > { > - info->representable_p = (!(y_offset_adj % (mode_multiple / > nregs_multiple))); + /* Only the lowpart of each block is > representable. */ > + info->representable_p > + = (subblock_offset > + == subreg_size_lowpart_offset (ysize, bytes_per_block)); > rknown = true; > } > - info->offset = (y_offset / (mode_multiple / nregs_multiple)) * > nregs_ymode; + This part is OK. > + if (WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN) > + info->offset = (num_blocks - block_number - 1) * nregs_ymode; > + else > + info->offset = block_number * nregs_ymode; > info->nregs = nregs_ymode; > } Why was the test on the mode size dropped? -- Eric Botcazou