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 :)

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[] =

Reply via email to