Stam Markianos-Wright <stam.markianos-wri...@arm.com> writes: > On 2/4/20 12:02 PM, Richard Sandiford wrote: >> 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. */ > Done >> >>> + >>> +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. > Done, sorry I didn't see that! >> >>> +} >>> + >>> /* 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;". > Done >> >>> >>> 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. > Done > > Let me know if this is good to go now :)
Yeah, this is OK, thanks. Richard > > Thank you so much for the help getting this finalised! > > Cheers, > Stam >> >> 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[] = > > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c > index c47fc232f39..ad1c1fa8e3b 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; > > +/* Record that we have no arithmetic or comparison libfuncs for > + machine 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); > +} > + > /* 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,23 @@ 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); > - > - /* 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); > + arm_block_arith_comp_libfuncs_for_mode (HFmode); > break; > > default: > break; > } > > + /* For all possible libcalls in BFmode, record NULL. */ > + FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_FLOAT) > + { > + set_conv_libfunc (trunc_optab, BFmode, mode_iter, NULL); > + set_conv_libfunc (trunc_optab, mode_iter, BFmode, NULL); > + set_conv_libfunc (sext_optab, mode_iter, BFmode, NULL); > + set_conv_libfunc (sext_optab, BFmode, mode_iter, NULL); > + } > + 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[] =