aboutsummaryrefslogtreecommitdiff
path: root/gcc/emit-rtl.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2017-11-09 14:22:39 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2017-11-09 14:22:39 +0000
commit1eae67f812a0b7b6b7132d0375e662bc6200d68a (patch)
treee02e90a2cdf27652857018bc9d0d760419f103b0 /gcc/emit-rtl.c
parente4373d41d67060e14bab0c984fb9f7cbc4c93f1b (diff)
downloadgcc-1eae67f812a0b7b6b7132d0375e662bc6200d68a.zip
gcc-1eae67f812a0b7b6b7132d0375e662bc6200d68a.tar.gz
gcc-1eae67f812a0b7b6b7132d0375e662bc6200d68a.tar.bz2
Base subreg rules on REGMODE_NATURAL_SIZE rather than UNITS_PER_WORD
Originally subregs operated at the word level and subreg offsets were measured in words. The offset units were later changed from words to bytes (SUBREG_WORD became SUBREG_BYTE), but the fundamental assumption that subregs should operate at the word level remained. Whether (subreg:M1 (reg:M2 R2) N) is well-formed depended on the way that M1 and M2 partitioned into words and whether the subword part of N represented a lowpart. However, some questions depended instead on the macro REGMODE_NATURAL_SIZE, which was introduced as part of the patch that moved from SUBREG_WORD to SUBREG_BYTE. It is used to decide whether setting (subreg:M1 (reg:M2 R2) N) clobbers all of R2 or just part of it (df_read_modify_subreg). Using words doesn't really make sense for modern vector architectures. Vector registers are usually bigger than a word and: (a) setting the scalar lowpart of them usually clobbers the rest of the register (contrary to the subreg rules, where only the containing words should be clobbered). (b) high words of vector registers are often not independently addressable, even though that's what the subreg rules expect. This patch therefore uses REGMODE_NATURAL_SIZE instead of UNITS_PER_WORD to determine the size of the independently addressable blocks in an inner register. This is needed for SVE because the number of words in a vector mode isn't known at compile time, so isn't a sensible basis for calculating the number of registers. The only existing port to define REGMODE_NATURAL_SIZE is 64-bit SPARC, where FP registers are 32 bits. (This is the opposite of the use case for SVE, since the natural division is smaller than a word.) I compiled the testsuite before and after the patch for sparc64-linux-gnu and the only test whose assembly changed was g++.dg/debug/pr65678.C, where the order of two independent stores was reversed and where a different register was picked for one pseudo. The new code was otherwise equivalent to the old code. 2017-11-09 Richard Sandiford <richard.sandiford@linaro.org> Alan Hayward <alan.hayward@arm.com> David Sherwood <david.sherwood@arm.com> gcc/ * doc/rtl.texi: Rewrite the subreg rules so that they partition the inner register into REGMODE_NATURAL_SIZE bytes rather than UNITS_PER_WORD bytes. * emit-rtl.c (validate_subreg): Divide subregs into blocks based on REGMODE_NATURAL_SIZE of the inner mode. (gen_lowpart_common): Split the SCALAR_FLOAT_MODE_P and !SCALAR_FLOAT_MODE_P cases. Use REGMODE_NATURAL_SIZE for the latter. * expmed.c (lowpart_bit_field_p): Divide the value up into chunks of REGMODE_NATURAL_SIZE rather than UNITS_PER_WORD. * expr.c (store_constructor): Use REGMODE_NATURAL_SIZE to test whether something is likely to occupy more than one register. Co-Authored-By: Alan Hayward <alan.hayward@arm.com> Co-Authored-By: David Sherwood <david.sherwood@arm.com> From-SVN: r254583
Diffstat (limited to 'gcc/emit-rtl.c')
-rw-r--r--gcc/emit-rtl.c51
1 files changed, 33 insertions, 18 deletions
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index da4f533..ac6fd6a 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -816,6 +816,8 @@ validate_subreg (machine_mode omode, machine_mode imode,
if (offset >= isize)
return false;
+ unsigned int regsize = REGMODE_NATURAL_SIZE (imode);
+
/* ??? This should not be here. Temporarily continue to allow word_mode
subregs of anything. The most common offender is (subreg:SI (reg:DF)).
Generally, backends are doing something sketchy but it'll take time to
@@ -824,7 +826,7 @@ validate_subreg (machine_mode omode, machine_mode imode,
;
/* ??? Similarly, e.g. with (subreg:DF (reg:TI)). Though store_bit_field
is the culprit here, and not the backends. */
- else if (osize >= UNITS_PER_WORD && isize >= osize)
+ else if (osize >= regsize && isize >= osize)
;
/* Allow component subregs of complex and vector. Though given the below
extraction rules, it's not always clear what that means. */
@@ -876,17 +878,23 @@ validate_subreg (machine_mode omode, machine_mode imode,
}
/* For pseudo registers, we want most of the same checks. Namely:
- If the register no larger than a word, the subreg must be lowpart.
- If the register is larger than a word, the subreg must be the lowpart
- of a subword. A subreg does *not* perform arbitrary bit extraction.
- Given that we've already checked mode/offset alignment, we only have
- to check subword subregs here. */
- if (osize < UNITS_PER_WORD
+
+ Assume that the pseudo register will be allocated to hard registers
+ that can hold REGSIZE bytes each. If OSIZE is not a multiple of REGSIZE,
+ the remainder must correspond to the lowpart of the containing hard
+ register. If BYTES_BIG_ENDIAN, the lowpart is at the highest offset,
+ otherwise it is at the lowest offset.
+
+ Given that we've already checked the mode and offset alignment,
+ we only have to check subblock subregs here. */
+ if (osize < regsize
&& ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
{
- machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
- unsigned int low_off = subreg_lowpart_offset (omode, wmode);
- if (offset % UNITS_PER_WORD != low_off)
+ unsigned int block_size = MIN (isize, regsize);
+ unsigned int offset_within_block = offset % block_size;
+ if (BYTES_BIG_ENDIAN
+ ? offset_within_block != block_size - osize
+ : offset_within_block != 0)
return false;
}
return true;
@@ -1439,14 +1447,21 @@ gen_lowpart_common (machine_mode mode, rtx x)
if (innermode == mode)
return x;
- /* MODE must occupy no more words than the mode of X. */
- if ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
- > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
- return 0;
-
- /* Don't allow generating paradoxical FLOAT_MODE subregs. */
- if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize)
- return 0;
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ /* Don't allow paradoxical FLOAT_MODE subregs. */
+ if (msize > xsize)
+ return 0;
+ }
+ else
+ {
+ /* MODE must occupy no more of the underlying registers than X. */
+ unsigned int regsize = REGMODE_NATURAL_SIZE (innermode);
+ unsigned int mregs = CEIL (msize, regsize);
+ unsigned int xregs = CEIL (xsize, regsize);
+ if (mregs > xregs)
+ return 0;
+ }
scalar_int_mode int_mode, int_innermode, from_mode;
if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)