From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 127452 invoked by alias); 15 Nov 2016 16:41:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 127424 invoked by uid 89); 15 Nov 2016 16:41:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.7 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=representable, holes X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 15 Nov 2016 16:41:07 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A227F28; Tue, 15 Nov 2016 08:41:05 -0800 (PST) Received: from localhost (e105548-lin.manchester.arm.com [10.45.32.67]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A41B73F24D for ; Tue, 15 Nov 2016 08:41:04 -0800 (PST) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: Rework subreg_get_info Date: Tue, 15 Nov 2016 16:41:00 -0000 Message-ID: <87oa1g1ysh.fsf@e105548-lin.cambridge.arm.com> User-Agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-SW-Source: 2016-11/txt/msg01488.txt.bz2 This isn't intended to change the behaviour, just rewrite the existing logic in a different (and hopefully clearer) way. The new form -- particularly the part based on the "block" concept -- is easier to convert to polynomial sizes. Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? Thanks, Richard [ This patch is part of the SVE series posted here: https://gcc.gnu.org/ml/gcc/2016-11/msg00030.html ] gcc/ 2016-11-15 Richard Sandiford Alan Hayward David Sherwood * rtlanal.c (subreg_get_info): Use more local variables. Remark that for HARD_REGNO_NREGS_HAS_PADDING, each scalar unit occupies at least one register. Use byte_lowpart_offset to check for big-endian offsets unless REG_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN. Share previously-duplicated if block. Rework the main handling so that it operates on independently- addressable YMODE-sized blocks. Use subreg_size_lowpart_offset to check lowpart offsets, without trying to find an equivalent integer mode first. Handle WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN as a final register-endianness correction. 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. */ 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; @@ -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; @@ -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; @@ -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; } } @@ -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; - 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; + + 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; }