From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25910 invoked by alias); 26 Mar 2012 22:59:56 -0000 Received: (qmail 25889 invoked by uid 22791); 26 Mar 2012 22:59:53 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_NONE,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout06.t-online.de (HELO mailout06.t-online.de) (194.25.134.19) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 26 Mar 2012 22:59:39 +0000 Received: from fwd06.aul.t-online.de (fwd06.aul.t-online.de ) by mailout06.t-online.de with smtp id 1SCIsz-0006XD-T2; Tue, 27 Mar 2012 00:59:37 +0200 Received: from [192.168.0.104] (XNfuxBZdrh9SQKuMJSkbr1E0p+MUHOaDoNqr6whw5Z-zj5r4A7KgKbHULZc7LzsgWY@[93.218.191.75]) by fwd06.t-online.de with esmtp id 1SCIsx-0V4nh20; Tue, 27 Mar 2012 00:59:35 +0200 Subject: [SH] PR 50751 - rework displacement calculations From: Oleg Endo To: gcc-patches Content-Type: multipart/mixed; boundary="=-OIg0kcG/YnhdsgdDpooD" Date: Mon, 26 Mar 2012 22:59:00 -0000 Message-ID: <1332802773.1876.339.camel@yam-132-YW-E178-FTW> Mime-Version: 1.0 X-IsSubscribed: yes 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 X-SW-Source: 2012-03/txt/msg01691.txt.bz2 --=-OIg0kcG/YnhdsgdDpooD Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 1015 Hi, The attached patch generalizes the move insn displacement calculations a little bit. Before, the same address rebasing code was present in sh_legitimize_address as well as sh_legitimize_reload_address. I've pulled those out into a separate function as a preparation step for adding HImode displacement addressing support. Tested by doing 'make all' (c,c++), compiling newlib and by making sure that for the following variants the CSiBE set code size did not change: -m2a-single -mb -O2, -m2a-single -mb -Os, -m4a-single -mb -O2, -m4a-single -mb -Os, -m4a-single -ml -O2, -m4a-single -ml -Os, -m4-single -mb -O2, -m4-single -mb -Os, -m4-single -ml -O2, -m4-single -ml -Os I'm now also running the usual reg tests on sh-sim, just in case. Other than that, OK? Cheers, Oleg ChangeLog: PR target/50751 * config/sh/sh.c (sh_legitimize_address, sh_legitimize_reload_address): Rearrange conditional logic. Move displacement address calculations to ... (sh_find_mov_disp_adjust): ... this new function. --=-OIg0kcG/YnhdsgdDpooD Content-Disposition: attachment; filename="pr50751_adj_offset.patch" Content-Type: text/x-patch; name="pr50751_adj_offset.patch"; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 10636 Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 185768) +++ gcc/config/sh/sh.c (working copy) @@ -9663,10 +9663,12 @@ { if (MAYBE_BASE_REGISTER_RTX_P (x, strict)) return true; + else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) && ! TARGET_SHMEDIA && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) return true; + else if (GET_CODE (x) == PLUS && (mode != PSImode || reload_completed)) { @@ -9779,80 +9781,114 @@ return orig; } -/* Try machine-dependent ways of modifying an illegitimate address - to be legitimate. If we find one, return the new, valid address. - Otherwise, return X. +/* Given a (logical) mode size and an offset in bytes, try to find a the + appropriate displacement value for a mov insn. On SH the displacements + are limited to max. 60 bytes for SImode, max. 30 bytes in HImode and max. + 15 bytes in QImode. To compensate this we create a new base address by + adding an adjustment value to it. - For the SH, if X is almost suitable for indexing, but the offset is - out of range, convert it into a normal form so that CSE has a chance - of reducing the number of address registers used. */ + If the originally requested offset is greater than 127 we prefer using + values 124..127 over 128..131 to increase opportunities to use the + add #imm, Rn insn. + In some cases it is possible that a requested offset might seem unaligned + or inappropriate for the mode size, like offset = 2 and mode size = 4. + This is compensated by adjusting the base address so that the effective + address of the displacement move insn will be aligned. + + This is not the best possible way of rebasing the base address, as it + does not look at other present displacement addressings around it. + In some cases this can create more base address adjustments than would + actually be necessary. */ + +struct disp_adjust +{ + rtx offset_adjust; + rtx mov_disp; + int max_mov_disp; +}; + +static struct disp_adjust +sh_find_mov_disp_adjust (int mode_sz, HOST_WIDE_INT offset) +{ + struct disp_adjust res = { NULL_RTX, NULL_RTX, 0 }; + + /* The max. available mode for actual move insns is SImode. + Larger accesses will be split into multiple loads/stores. */ + const int max_mov_sz = GET_MODE_SIZE (SImode); + + const int mov_insn_size = mode_sz >= max_mov_sz ? max_mov_sz : mode_sz; + const HOST_WIDE_INT max_disp = 15 * mov_insn_size; + HOST_WIDE_INT align_modifier = offset > 127 ? mov_insn_size : 0; + + HOST_WIDE_INT offset_adjust; + + /* In some cases this actually does happen and we must check for it. */ + if (mode_sz < 1 || mode_sz > 8) + return res; + + /* FIXME: HImode with displacement addressing is not supported yet. + Make it purposefully fail for now. */ + if (mov_insn_size == 2) + return res; + + /* Keeps the previous behavior for QImode displacement addressing. + This just decides how the offset is re-based. Removing this special + case will result in slightly bigger code on average, but it's not that + bad actually. */ + if (mov_insn_size == 1) + align_modifier = 0; + + res.max_mov_disp = max_disp + mov_insn_size; + + offset_adjust = ((offset + align_modifier) & ~max_disp) - align_modifier; + + if (mode_sz + offset - offset_adjust <= res.max_mov_disp) + { + res.offset_adjust = GEN_INT (offset_adjust); + res.mov_disp = GEN_INT (offset - offset_adjust); + } + + return res; +} + +/* Try to modify an illegitimate address and make it legitimate. + If we find one, return the new, valid address. + Otherwise, return the original address. */ + static rtx sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) { if (flag_pic) x = legitimize_pic_address (oldx, mode, NULL_RTX); - if (GET_CODE (x) == PLUS - && (GET_MODE_SIZE (mode) == 4 - || GET_MODE_SIZE (mode) == 8) - && CONST_INT_P (XEXP (x, 1)) - && BASE_REGISTER_RTX_P (XEXP (x, 0)) - && ! TARGET_SHMEDIA - && ! ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) - && ! (TARGET_SH2E && mode == SFmode)) - { - rtx index_rtx = XEXP (x, 1); - HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; - rtx sum; + if (TARGET_SHMEDIA) + return x; - /* On rare occasions, we might get an unaligned pointer - that is indexed in a way to give an aligned address. - Therefore, keep the lower two bits in offset_base. */ - /* Instead of offset_base 128..131 use 124..127, so that - simple add suffices. */ - if (offset > 127) - offset_base = ((offset + 4) & ~60) - 4; - else - offset_base = offset & ~60; + if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) + || (TARGET_SH2E && mode == SFmode)) + return x; - /* Sometimes the normal form does not suit DImode. We - could avoid that by using smaller ranges, but that - would give less optimized code when SImode is - prevalent. */ - if (GET_MODE_SIZE (mode) + offset - offset_base <= 64) - { - sum = expand_binop (Pmode, add_optab, XEXP (x, 0), - GEN_INT (offset_base), NULL_RTX, 0, - OPTAB_LIB_WIDEN); + if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) + && BASE_REGISTER_RTX_P (XEXP (x, 0))) + { + const int mode_sz = GET_MODE_SIZE (mode); + struct disp_adjust adj = sh_find_mov_disp_adjust (mode_sz, + INTVAL (XEXP (x, 1))); - return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base)); - } - } - - /* This could be generalized for SImode, HImode, QImode displacement - addressing. */ - if (mode == QImode && GET_CODE (x) == PLUS - && BASE_REGISTER_RTX_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) - { - rtx index_rtx = XEXP (x, 1); - HOST_WIDE_INT offset = INTVAL (index_rtx); - HOST_WIDE_INT offset_base = offset & ~15; - - if (offset - offset_base <= 16) + if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) { rtx sum = expand_binop (Pmode, add_optab, XEXP (x, 0), - GEN_INT (offset_base), NULL_RTX, 0, - OPTAB_LIB_WIDEN); - - return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base)); + adj.offset_adjust, NULL_RTX, 0, + OPTAB_LIB_WIDEN); + return gen_rtx_PLUS (Pmode, sum, adj.mov_disp); } } return x; } -/* Attempt to replace *P, which is an address that needs reloading, with +/* Attempt to replace *p, which is an address that needs reloading, with a valid memory address for an operand of mode MODE. Like for sh_legitimize_address, for the SH we try to get a normal form of the address. That will allow inheritance of the address reloads. */ @@ -9862,75 +9898,71 @@ int itype) { enum reload_type type = (enum reload_type) itype; + const int mode_sz = GET_MODE_SIZE (mode); - if (GET_CODE (*p) == PLUS - && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8) - && CONST_INT_P (XEXP (*p, 1)) + if (TARGET_SHMEDIA) + return false; + + if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1)) && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true) - && ! TARGET_SHMEDIA - && ! (TARGET_SH4 && mode == DFmode) && ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS) && (ALLOW_INDEXED_ADDRESS || XEXP (*p, 0) == stack_pointer_rtx || XEXP (*p, 0) == hard_frame_pointer_rtx)) { - rtx index_rtx = XEXP (*p, 1); - HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; - rtx sum; + const HOST_WIDE_INT offset = INTVAL (XEXP (*p, 1)); + struct disp_adjust adj = sh_find_mov_disp_adjust (mode_sz, offset); if (TARGET_SH2A && mode == DFmode && (offset & 0x7)) { push_reload (*p, NULL_RTX, p, NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); - goto win; + return true; } + if (TARGET_SH2E && mode == SFmode) { *p = copy_rtx (*p); push_reload (*p, NULL_RTX, p, NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); - goto win; + return true; } - /* Instead of offset_base 128..131 use 124..127, so that - simple add suffices. */ - if (offset > 127) - offset_base = ((offset + 4) & ~60) - 4; - else - offset_base = offset & ~60; - /* Sometimes the normal form does not suit DImode. We could avoid - that by using smaller ranges, but that would give less optimized - code when SImode is prevalent. */ - if (GET_MODE_SIZE (mode) + offset - offset_base <= 64) + + /* FIXME: Do not allow to legitimize QImode and HImode displacement + moves because then reload has a problem figuring the constraint + that the move insn target/source reg must be R0. + Or maybe some handling is wrong in sh_secondary_reload for this + to work properly? */ + if ((mode_sz == 4 || mode_sz == 8) + && ! (TARGET_SH4 && mode == DFmode) + && adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) { - sum = gen_rtx_PLUS (Pmode, XEXP (*p, 0), GEN_INT (offset_base)); - *p = gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base)); + rtx sum = gen_rtx_PLUS (Pmode, XEXP (*p, 0), adj.offset_adjust); + *p = gen_rtx_PLUS (Pmode, sum, adj.mov_disp); push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); - goto win; + return true; } } + /* We must re-recognize what we created before. */ - else if (GET_CODE (*p) == PLUS - && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8) - && GET_CODE (XEXP (*p, 0)) == PLUS - && CONST_INT_P (XEXP (XEXP (*p, 0), 1)) - && MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true) - && CONST_INT_P (XEXP (*p, 1)) - && ! TARGET_SHMEDIA - && ! (TARGET_SH2E && mode == SFmode)) + if (GET_CODE (*p) == PLUS + && (mode_sz == 4 || mode_sz == 8) + && GET_CODE (XEXP (*p, 0)) == PLUS + && CONST_INT_P (XEXP (XEXP (*p, 0), 1)) + && MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true) + && CONST_INT_P (XEXP (*p, 1)) + && ! (TARGET_SH2E && mode == SFmode)) { /* Because this address is so complex, we know it must have been created by LEGITIMIZE_RELOAD_ADDRESS before; thus, it is already unshared, and needs no further unsharing. */ push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); - goto win; + return true; } return false; - - win: - return true; } /* In the name of slightly smaller debug output, and to cater to --=-OIg0kcG/YnhdsgdDpooD--