Richard Biener <richard.guent...@gmail.com> writes: > On Tue, Nov 7, 2017 at 7:04 PM, Richard Sandiford > <richard.sandif...@linaro.org> wrote: >> Richard Biener <richard.guent...@gmail.com> writes: >>> On Fri, Nov 3, 2017 at 5:32 PM, Richard Sandiford >>> <richard.sandif...@linaro.org> wrote: >>>> A general TARGET_MEM_REF is: >>>> >>>> BASE + STEP * INDEX + INDEX2 + OFFSET >>>> >>>> After classifying the address in this way, the code that builds >>>> TARGET_MEM_REFs tries to simplify the address until it's valid >>>> for the current target and for the mode of memory being addressed. >>>> It does this in a fixed order: >>>> >>>> (1) add SYMBOL to BASE >>>> (2) add INDEX * STEP to the base, if STEP != 1 >>>> (3) add OFFSET to INDEX or BASE (reverted if unsuccessful) >>>> (4) add INDEX to BASE >>>> (5) add OFFSET to BASE >>>> >>>> So suppose we had an address: >>>> >>>> &symbol + offset + index * 8 (e.g. "a[i + 1]" for a global "a") >>>> >>>> on a target that only allows an index or an offset, not both. Following >>>> the steps above, we'd first create: >>>> >>>> tmp = symbol >>>> tmp2 = tmp + index * 8 >>>> >>>> Then if the given offset value was valid for the mode being addressed, >>>> we'd create: >>>> >>>> MEM[base:tmp2, offset:offset] >>>> >>>> while if it was invalid we'd create: >>>> >>>> tmp3 = tmp2 + offset >>>> MEM[base:tmp3, offset:0] >>>> >>>> The problem is that this could happen if ivopts had decided to use >>>> a scaled index for an address that happens to have a constant base. >>>> The old procedure failed to give an indexed TARGET_MEM_REF in that case, >>>> and adding the offset last prevented later passes from being able to >>>> fold the index back in. >>>> >>>> The patch avoids this by skipping (2) if BASE + INDEX * STEP >>>> is a legitimate address and if OFFSET is stopping the address >>>> being valid. >>>> >>>> Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64-linux-gnu. >>>> OK to install? >>>> >>>> Richard >>>> >>>> >>>> 2017-10-31 Richard Sandiford <richard.sandif...@linaro.org> >>>> Alan Hayward <alan.hayw...@arm.com> >>>> David Sherwood <david.sherw...@arm.com> >>>> >>>> gcc/ >>>> * tree-ssa-address.c (keep_index_p): New function. >>>> (create_mem_ref): Use it. Only split out the INDEX * STEP >>>> component if that is invalid even with the symbol and offset >>>> removed. >>>> >>>> Index: gcc/tree-ssa-address.c >>>> =================================================================== >>>> --- gcc/tree-ssa-address.c 2017-11-03 12:15:44.097060121 +0000 >>>> +++ gcc/tree-ssa-address.c 2017-11-03 12:21:18.060359821 +0000 >>>> @@ -746,6 +746,20 @@ gimplify_mem_ref_parts (gimple_stmt_iter >>>> true, GSI_SAME_STMT); >>>> } >>>> >>>> +/* Return true if the STEP in PARTS gives a valid BASE + INDEX * STEP >>>> + address for type TYPE and if the offset is making it appear invalid. >>>> */ >>>> + >>>> +static bool >>>> +keep_index_p (tree type, mem_address parts) >>> >>> mem_ref_valid_without_offset_p (...) >>> >>> ? >> >> OK. >> >>>> +{ >>>> + if (!parts.base) >>>> + return false; >>>> + >>>> + gcc_assert (!parts.symbol); >>>> + parts.offset = NULL_TREE; >>>> + return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), >>>> &parts); >>>> +} >>>> + >>>> /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary >>>> computations are emitted in front of GSI. TYPE is the mode >>>> of created memory reference. IV_CAND is the selected iv candidate in >>>> ADDR, >>>> @@ -809,7 +823,8 @@ create_mem_ref (gimple_stmt_iterator *gs >>> >>> Which means all of the following would be more naturally written as >>> >>>> into: >>>> index' = index << step; >>>> [... + index' + ,,,]. */ >>>> - if (parts.step && !integer_onep (parts.step)) >>>> + bool scaled_p = (parts.step && !integer_onep (parts.step)); >>>> + if (scaled_p && !keep_index_p (type, parts)) >>>> { >>> >>> if (mem_ref_valid_without_offset_p (...)) >>> { >>> ... >>> return create_mem_ref_raw (...); >>> } >> >> Is this inside the test for a scale: >> >> if (parts.step && !integer_onep (parts.step)) >> { >> if (mem_ref_valid_without_offset_p (...)) >> { >> tree tmp = parts.offset; >> if (parts.base) >> { >> tmp = fold_build_pointer_plus (parts.base, tmp); >> tmp = force_gimple_operand_gsi_1 (gsi, tmp, >> is_gimple_mem_ref_addr, >> NULL_TREE, true, >> GSI_SAME_STMT); >> } >> parts.base = tmp; >> parts.offset = NULL_TREE; >> mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); >> gcc_assert (mem_ref); >> return mem_ref; >> } >> ...current code... >> } >> >> ? I can do that if you don't mind the cut-&-paste. Or I could >> split the code that adds the offset out into a subroutine. > > Sorry for the late response. Yes, sth like that.
Sorry for the dropping the ball on this. Is the version below OK? Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64-linux-gnu. Thanks, Richard 2018-01-09 Richard Sandiford <richard.sandif...@linaro.org> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> gcc/ * tree-ssa-address.c (mem_ref_valid_without_offset_p): New function. (add_offset_to_base): New function, split out from... (create_mem_ref): ...here. When handling a scale other than 1, check first whether the address is valid without the offset. Add it into the base if so, leaving the index and scale as-is. Index: gcc/tree-ssa-address.c =================================================================== --- gcc/tree-ssa-address.c 2018-01-05 13:38:01.651810414 +0000 +++ gcc/tree-ssa-address.c 2018-01-09 14:36:36.533460131 +0000 @@ -746,6 +746,35 @@ gimplify_mem_ref_parts (gimple_stmt_iter true, GSI_SAME_STMT); } +/* Return true if the OFFSET in PARTS is the only thing that is making + it an invalid address for type TYPE. */ + +static bool +mem_ref_valid_without_offset_p (tree type, mem_address parts) +{ + if (!parts.base) + parts.base = parts.offset; + parts.offset = NULL_TREE; + return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts); +} + +/* Fold PARTS->offset into PARTS->base, so that there is no longer + a separate offset. Emit any new instructions before GSI. */ + +static void +add_offset_to_base (gimple_stmt_iterator *gsi, mem_address *parts) +{ + tree tmp = parts->offset; + if (parts->base) + { + tmp = fold_build_pointer_plus (parts->base, tmp); + tmp = force_gimple_operand_gsi_1 (gsi, tmp, is_gimple_mem_ref_addr, + NULL_TREE, true, GSI_SAME_STMT); + } + parts->base = tmp; + parts->offset = NULL_TREE; +} + /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary computations are emitted in front of GSI. TYPE is the mode of created memory reference. IV_CAND is the selected iv candidate in ADDR, @@ -812,6 +841,14 @@ create_mem_ref (gimple_stmt_iterator *gs if (parts.step && !integer_onep (parts.step)) { gcc_assert (parts.index); + if (parts.offset && mem_ref_valid_without_offset_p (type, parts)) + { + add_offset_to_base (gsi, &parts); + mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); + gcc_assert (mem_ref); + return mem_ref; + } + parts.index = force_gimple_operand_gsi (gsi, fold_build2 (MULT_EXPR, sizetype, parts.index, parts.step), @@ -906,18 +943,7 @@ create_mem_ref (gimple_stmt_iterator *gs [base']. */ if (parts.offset && !integer_zerop (parts.offset)) { - tmp = parts.offset; - parts.offset = NULL_TREE; - /* Add offset to base. */ - if (parts.base) - { - tmp = fold_build_pointer_plus (parts.base, tmp); - tmp = force_gimple_operand_gsi_1 (gsi, tmp, - is_gimple_mem_ref_addr, - NULL_TREE, true, GSI_SAME_STMT); - } - parts.base = tmp; - + add_offset_to_base (gsi, &parts); mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); if (mem_ref) return mem_ref;