Stam Markianos-Wright <stam.markianos-wri...@arm.com> writes:
> On 1/31/20 1:45 PM, Richard Sandiford wrote:
>> Stam Markianos-Wright <stam.markianos-wri...@arm.com> writes:
>>> On 1/30/20 10:01 AM, Richard Sandiford wrote:
>>>> Stam Markianos-Wright <stam.markianos-wri...@arm.com> writes:
>>>>> On 1/29/20 12:42 PM, Richard Sandiford wrote:
>>>>>> Stam Markianos-Wright <stam.markianos-wri...@arm.com> writes:
>>>>>>> Hi all,
>>>>>>>
>>>>>>> This fixes:
>>>>>>>
>>>>>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93300
>>>>>>>
>>>>>>> Genmodes.c was generating the "wider_mode" chain as follows:
>>>>>>>
>>>>>>> HF -> BF -> SF - > DF -> TF -> VOID
>>>>>>>
>>>>>>> This caused issues in some rare cases where conversion between modes
>>>>>>> was needed, such as the above PR93300 where BFmode was being picked up
>>>>>>> as a valid mode for:
>>>>>>>
>>>>>>> optabs.c:prepare_float_lib_cmp
>>>>>>>
>>>>>>> which then led to the ICE at expr.c:convert_mode_scalar.
>>>>>
>>>>> Hi Richard,
>>>>>
>>>>>>
>>>>>> Can you go into more details about why this chain was a problem?
>>>>>> Naively, it's the one I'd have expected: HF should certainly have
>>>>>> priority over BF,
>>>>>
>>>>> Is that because functionally it looks like genmodes puts things in reverse
>>>>> alphabetical order if all else is equal? (If I'm reading the comment about
>>>>> MODE_RANDOM, MODE_CC correctly)
>>>>>
>>>>>> but BF coming before SF doesn't seem unusual in itself.
>>>>>>
>>>>>> I'm not saying the patch is wrong.  It just wasn't clear why it was
>>>>>> right either.
>>>>>>
>>>>> Yes, I see what you mean. I'll go through my thought process here:
>>>>>
>>>>> In investigating the ICE PR93300 I found that the diversion from pre-bf16
>>>>> behaviour was specifically at `optabs.c:prepare_float_lib_cmp`, where a
>>>>> `FOR_EACH_MODE_FROM (mode, orig_mode)` is used to then go off and generate
>>>>> library calls for conversions.
>>>>>
>>>>> This was then being caught further down by the gcc_assert at expr.c:325 
>>>>> where
>>>>> GET_MODE_PRECISION (from_mode) was equal to GET_MODE_PRECISION (to_mode) 
>>>>> because
>>>>> it was trying to emit a HF->BF conversion libcall as `bl __extendhfbf2` 
>>>>> (which
>>>>> is what happened if i removed the gcc_assert at expr.c:325)
>>>>>
>>>>> With BFmode being a target-defined mode, I didn't want to add something 
>>>>> like `if
>>>>> (mode != BFmode)` to specifically exclude BFmode from being selected for 
>>>>> this.
>>>>> (and there's nothing different between HFmode and BFmode here to allow me 
>>>>> to
>>>>> make this distinction?)
>>>>>
>>>>> Also I couldn't find anywhere where the target back-end is not consulted 
>>>>> for a
>>>>> "is this supported: yes/no" between the `FOR_EACH_MODE_FROM` loop and the
>>>>> libcall being created later on as __extendhfbf2.
>>>>
>>>> Yeah, prepare_float_lib_cmp just checks for libfuncs rather than
>>>> calling target hooks directly.  The libfuncs themselves are under
>>>> the control of the target though.
>>>>
>>>> By default we assume all float modes have associated libfuncs.
>>>> It's then up to the target to remove functions that don't exist
>>>> (or redirect them to other functions).  So I think we need to remove
>>>> BFmode libfuncs in arm_init_libfuncs in the same way as we currently
>>>> do for HFmode.
>>>>
>>>> I guess we should also nullify the conversion libfuncs for BFmode,
>>>> not just the arithmetic and comparison ones.
>>>
>>> Ahhh now this works, thank you for the suggestion!
>>>
>>> I was aware of arm_init_libfuncs, but I had not realised that returning NULL
>>> would have the desired effect for us, in this case. So I have essentially 
>>> rolled
>>> back the whole previous version of the patch and done this in the new diff.
>>> It seems to have fixed the ICE and I am currently in the process of 
>>> regression
>>> testing!
>> 
>> LGTM behaviourally, just a couple of requests about how it's written:
>> 
>>>
>>> Thank you!
>>> Stam
>>>
>>>>
>>>> Thanks,
>>>> Richard
>>>>
>>>>> Finally, because we really don't want __bf16 to be in the same 
>>>>> "conversion rank"
>>>>> as standard float modes for things like automatic promotion, this seemed 
>>>>> like a
>>>>> reasonable solution to that problem :)
>>>>>
>>>>> Let me know of your thoughts!
>>>>>
>>>>> Cheers,
>>>>> Stam
>>>
>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>> index c47fc232f39..18055d4a75e 100644
>>> --- a/gcc/config/arm/arm.c
>>> +++ b/gcc/config/arm/arm.c
>>> @@ -2643,6 +2643,30 @@ arm_init_libfuncs (void)
>>>       default:
>>>         break;
>>>       }
>>> +
>>> +  /* For all possible libcalls in BFmode, return NULL.  */
>>> +  /* Conversions.  */
>>> +  set_conv_libfunc (trunc_optab, BFmode, HFmode, (NULL));
>>> +  set_conv_libfunc (sext_optab, HFmode, BFmode, (NULL));
>>> +  set_conv_libfunc (trunc_optab, BFmode, SFmode, (NULL));
>>> +  set_conv_libfunc (sext_optab, SFmode, BFmode, (NULL));
>>> +  set_conv_libfunc (trunc_optab, BFmode, DFmode, (NULL));
>>> +  set_conv_libfunc (sext_optab, DFmode, BFmode, (NULL));
>> 
>> It might be slightly safer to do:
>> 
>>    FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_FLOAT)
>> 
>> to iterate over all float modes on the non-BF side.
>
> Done :)
>> 
>>> +  /* Arithmetic.  */
>>> +  set_optab_libfunc (add_optab, BFmode, NULL);
>>> +  set_optab_libfunc (sdiv_optab, BFmode, NULL);
>>> +  set_optab_libfunc (smul_optab, BFmode, NULL);
>>> +  set_optab_libfunc (neg_optab, BFmode, NULL);
>>> +  set_optab_libfunc (sub_optab, BFmode, NULL);
>>> +
>>> +  /* Comparisons.  */
>>> +  set_optab_libfunc (eq_optab, BFmode, NULL);
>>> +  set_optab_libfunc (ne_optab, BFmode, NULL);
>>> +  set_optab_libfunc (lt_optab, BFmode, NULL);
>>> +  set_optab_libfunc (le_optab, BFmode, NULL);
>>> +  set_optab_libfunc (ge_optab, BFmode, NULL);
>>> +  set_optab_libfunc (gt_optab, BFmode, NULL);
>>> +  set_optab_libfunc (unord_optab, BFmode, NULL);
>> 
>> Could you split this part out into a subroutine and reuse it for the
>> existing HFmode code too?
>
> Done
>
> Let me know if you spot any other issues or nits of course!
>
> Cheers,
> Stam
>
> New changelog:
>
> gcc/ChangeLog:
>
> 2020-02-04  Stam Markianos-Wright  <stam.markianos-wri...@arm.com>
>
>       * config/arm/arm.c (arm_block_arith_comp_libfuncs_for_mode): New.
>       (arm_init_libfuncs): Add BFmode support to block spurious BF libfuncs.
>       Use arm_block_arith_comp_libfuncs_for_mode for HFmode.
>
>
>> 
>> Thanks,
>> Richard
>> 
>
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index c47fc232f39..80425f77f9d 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -2491,10 +2491,35 @@ arm_set_fixed_conv_libfunc (convert_optab optable, 
> machine_mode to,
>  
>  static GTY(()) rtx speculation_barrier_libfunc;
>  
> +/* Return NULL to block arithmetic and comparison libfuncs in
> +   a specific machine_mode.  */

"Return" to me sounds like this is talking about the return value
of the function.  Maybe something like:

/* Record that we have no arithmetic or comparison libfuncs for
   machinde mode MODE.  */

> +
> +static void
> +arm_block_arith_comp_libfuncs_for_mode (machine_mode mode)
> +{
> +      /* Arithmetic.  */
> +      set_optab_libfunc (add_optab, mode, NULL);
> +      set_optab_libfunc (sdiv_optab, mode, NULL);
> +      set_optab_libfunc (smul_optab, mode, NULL);
> +      set_optab_libfunc (neg_optab, mode, NULL);
> +      set_optab_libfunc (sub_optab, mode, NULL);
> +
> +      /* Comparisons.  */
> +      set_optab_libfunc (eq_optab, mode, NULL);
> +      set_optab_libfunc (ne_optab, mode, NULL);
> +      set_optab_libfunc (lt_optab, mode, NULL);
> +      set_optab_libfunc (le_optab, mode, NULL);
> +      set_optab_libfunc (ge_optab, mode, NULL);
> +      set_optab_libfunc (gt_optab, mode, NULL);
> +      set_optab_libfunc (unord_optab, mode, NULL);

Too much indentation, should just be two spaces.

> +}
> +
>  /* Set up library functions unique to ARM.  */
>  static void
>  arm_init_libfuncs (void)
>  {
> +  machine_mode mode_iter;
> +
>    /* For Linux, we have access to kernel support for atomic operations.  */
>    if (arm_abi == ARM_ABI_AAPCS_LINUX)
>      init_sync_libfuncs (MAX_SYNC_LIBFUNC_SIZE);
> @@ -2623,27 +2648,22 @@ arm_init_libfuncs (void)
>                        ? "__gnu_d2h_ieee"
>                        : "__gnu_d2h_alternative"));
>  
> -      /* Arithmetic.  */
> -      set_optab_libfunc (add_optab, HFmode, NULL);
> -      set_optab_libfunc (sdiv_optab, HFmode, NULL);
> -      set_optab_libfunc (smul_optab, HFmode, NULL);
> -      set_optab_libfunc (neg_optab, HFmode, NULL);
> -      set_optab_libfunc (sub_optab, HFmode, NULL);
> +      arm_block_arith_comp_libfuncs_for_mode (HFmode);
>  
> -      /* Comparisons.  */
> -      set_optab_libfunc (eq_optab, HFmode, NULL);
> -      set_optab_libfunc (ne_optab, HFmode, NULL);
> -      set_optab_libfunc (lt_optab, HFmode, NULL);
> -      set_optab_libfunc (le_optab, HFmode, NULL);
> -      set_optab_libfunc (ge_optab, HFmode, NULL);
> -      set_optab_libfunc (gt_optab, HFmode, NULL);
> -      set_optab_libfunc (unord_optab, HFmode, NULL);
>        break;

Nit: no need for a blank line before "break;".

>  
>      default:
>        break;
>      }
>  
> +  /* For all possible libcalls in BFmode, return NULL.  */
> +  FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_FLOAT)
> +    {
> +      set_conv_libfunc (trunc_optab, BFmode, mode_iter, (NULL));
> +      set_conv_libfunc (sext_optab, mode_iter, BFmode, (NULL));

It would probably be safer to use both argument orders for each optab,
since BFmode isn't necessarily the "narrowest" mode.

Nit: no need for brackets around NULL.

Thanks,
Richard

> +    }
> +  arm_block_arith_comp_libfuncs_for_mode (BFmode);
> +
>    /* Use names prefixed with __gnu_ for fixed-point helper functions.  */
>    {
>      const arm_fixed_mode_set fixed_arith_modes[] =

Reply via email to