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. */
+
+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,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;
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));
+ }
+ 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[] =