Jeff Law <jeffreya...@gmail.com> writes:
> On 11/27/23 05:12, Richard Sandiford wrote:
>> check_asm_operands was inconsistent about how it handled "p" after
>> RA compared to before RA.  Before RA it tested the address with a
>> void (unknown) memory mode:
>> 
>>          case CT_ADDRESS:
>>            /* Every address operand can be reloaded to fit.  */
>>            result = result || address_operand (op, VOIDmode);
>>            break;
>> 
>> After RA it deferred to constrain_operands, which used the mode
>> of the operand:
>> 
>>              if ((GET_MODE (op) == VOIDmode
>>                   || SCALAR_INT_MODE_P (GET_MODE (op)))
>>                  && (strict <= 0
>>                      || (strict_memory_address_p
>>                           (recog_data.operand_mode[opno], op))))
>>                win = true;
>> 
>> Using the mode of the operand matches reload's behaviour:
>> 
>>        else if (insn_extra_address_constraint
>>             (lookup_constraint (constraints[i])))
>>      {
>>        address_operand_reloaded[i]
>>          = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
>>                                  recog_data.operand[i],
>>                                  recog_data.operand_loc[i],
>>                                  i, operand_type[i], ind_levels, insn);
>> 
>> It allowed the special predicate address_operand to be used, with the
>> mode of the operand being the mode of the addressed memory, rather than
>> the mode of the address itself.  For example, vax has:
>> 
>> (define_insn "*movaddr<mode>"
>>    [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
>>      (match_operand:VAXfp 1 "address_operand" "p"))
>>     (clobber (reg:CC VAX_PSL_REGNUM))]
>>    "reload_completed"
>>    "mova<VAXfp:fsfx> %a1,%0")
>> 
>> where operand 1 is an SImode expression that can address memory of
>> mode VAXfp.  GET_MODE (recog_data.operand[1]) is SImode (or VOIDmode),
>> but recog_data.operand_mode[1] is <VAXfp:MODE>mode.
>> 
>> But AFAICT, ira and lra (like pre-reload check_asm_operands) do not
>> do this, and instead pass VOIDmode.  So I think this traditional use
>> of address_operand is effectively an old-reload-only feature.
>> 
>> And it seems like no modern port cares.  I think ports have generally
>> moved to using different address constraints instead, rather than
>> relying on "p" with different operand modes.  Target-specific address
>> constraints post-date the code above.
>> 
>> The big advantage of using different constraints is that it works
>> for asms too.  And that (to finally get to the point) is the problem
>> fixed in this patch.  For the aarch64 test:
>> 
>>    void f(char *p) { asm("prfm pldl1keep, %a0\n" :: "p" (p + 6)); }
>> 
>> everything up to and including RA required the operand to be a
>> valid VOIDmode address.  But post-RA check_asm_operands and
>> constrain_operands instead required it to be valid for
>> recog_data.operand_mode[0].  Since asms have no syntax for
>> specifying an operand mode that's separate from the operand itself,
>> operand_mode[0] is simply Pmode (i.e. DImode).
>> 
>> This meant that we required one mode before RA and a different mode
>> after RA.  On AArch64, VOIDmode is treated as a wildcard and so has a
>> more conservative/restricted range than DImode.  So if a post-RA pass
>> tried to form a new address, it would use a laxer condition than the
>> pre-RA passes.
> This was initially a bit counter-intuitive, my first reaction was that a 
> wildcard mode is more general.  And that's true, but it necessarily 
> means the addresses accepted are more restrictive because any mode is 
> allowed.

Right.  I should probably have a conservative, common subset.

>> This happened with the late-combine pass that I posted in October:
>> https://gcc.gnu.org/pipermail/gcc-patches/2023-October/634166.html
>> which in turn triggered an error from aarch64_print_operand_address.
>> 
>> This patch takes the (hopefully) conservative fix of using VOIDmode for
>> asms but continuing to use the operand mode for .md insns, so as not
>> to break ports that still use reload.
> Sadly I didn't get as far as I would have liked in removing reload, 
> though we did get a handful of ports converted this cycle
>
>> 
>> Fixing this made me realise that recog_level2 was doing duplicate
>> work for asms after RA.
>> 
>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
>> 
>> Richard
>> 
>> 
>> gcc/
>>      * recog.cc (constrain_operands): Pass VOIDmode to
>>      strict_memory_address_p for 'p' constraints in asms.
>>      * rtl-ssa/changes.cc (recog_level2): Skip redundant constrain_operands
>>      for asms.
>> 
>> gcc/testsuite/
>>      * gcc.target/aarch64/prfm_imm_offset_2.c: New test.
> It all seems a bit hackish.  I don't think ports have had much success 
> using 'p' through the decades.  I think I generally ended up having to 
> go with distinct constraints rather than relying on 'p'.
>
> OK for the trunk, but ewww.

Thanks, pushed.  And yeah, eww is fair.  I'd be happy for this to become
an unconditional VOIDmode once reload is removed.

Richard

Reply via email to