Hi Richard,

Thanks for the review comments!

on 2024/7/4 23:58, Richard Sandiford wrote:
> "Kewen.Lin" <li...@linux.ibm.com> writes:
>> Hi,
>>
>> With some historical reasons, rs6000 defines KFmode, TFmode
>> and IFmode to have different mode precision, but it causes
>> some issues and needs some workarounds such as r14-6478 for
>> PR112788.  So we are going to make all rs6000 128 bit scalar
>> FP modes have 128 bit precision.  Be prepared for that, this
>> patch is to make function convert_mode_scalar allow same
>> precision FP modes conversion if their underlying formats are
>> ibm_extended_format and ieee_quad_format respectively, just
>> like the existing special treatment on arm_bfloat_half_format
>> <-> ieee_half_format.  It also factors out all the relevant
>> checks into a lambda function.
>>
>> Bootstrapped and regtested on x86_64-redhat-linux and
>> powerpc64{,le}-linux-gnu.
>>
>> Is it ok for trunk?
>>
>> BR,
>> Kewen
>> -----
>>      PR target/112993
>>
>> gcc/ChangeLog:
>>
>>      * expr.cc (convert_mode_scalar): Allow same precision conversion
>>      between scalar floating point modes if whose underlying format is
>>      ibm_extended_format or ieee_quad_format, and refactor assertion
>>      with new lambda function acceptable_same_precision_modes.
>> ---
>>  gcc/expr.cc | 30 ++++++++++++++++++++++++------
>>  1 file changed, 24 insertions(+), 6 deletions(-)
>>
>> diff --git a/gcc/expr.cc b/gcc/expr.cc
>> index ffbac513692..eac4dcc982e 100644
>> --- a/gcc/expr.cc
>> +++ b/gcc/expr.cc
>> @@ -338,6 +338,29 @@ convert_mode_scalar (rtx to, rtx from, int unsignedp)
>>    enum rtx_code equiv_code = (unsignedp < 0 ? UNKNOWN
>>                            : (unsignedp ? ZERO_EXTEND : SIGN_EXTEND));
>>
>> +  auto acceptable_same_precision_modes
>> +    = [] (scalar_mode from_mode, scalar_mode to_mode) -> bool
>> +    {
>> +      if (DECIMAL_FLOAT_MODE_P (from_mode) != DECIMAL_FLOAT_MODE_P 
>> (to_mode))
>> +    return true;
>> +
>> +      /* arm_bfloat_half_format <-> ieee_half_format */
>> +      if ((REAL_MODE_FORMAT (from_mode) == &arm_bfloat_half_format
>> +       && REAL_MODE_FORMAT (to_mode) == &ieee_half_format)
>> +      || (REAL_MODE_FORMAT (to_mode) == &arm_bfloat_half_format
>> +          && REAL_MODE_FORMAT (from_mode) == &ieee_half_format))
>> +    return true;
>> +
>> +      /* ibm_extended_format <-> ieee_quad_format */
>> +      if ((REAL_MODE_FORMAT (from_mode) == &ibm_extended_format
>> +       && REAL_MODE_FORMAT (to_mode) == &ieee_quad_format)
>> +      || (REAL_MODE_FORMAT (from_mode) == &ieee_quad_format
>> +          && REAL_MODE_FORMAT (to_mode) == &ibm_extended_format))
>> +    return true;
>> +
>> +      return false;
>> +    };
>> +
>>    if (to_real)
>>      {
>>        rtx value;
>> @@ -346,12 +369,7 @@ convert_mode_scalar (rtx to, rtx from, int unsignedp)
>>
>>        gcc_assert ((GET_MODE_PRECISION (from_mode)
>>                 != GET_MODE_PRECISION (to_mode))
>> -              || (DECIMAL_FLOAT_MODE_P (from_mode)
>> -                  != DECIMAL_FLOAT_MODE_P (to_mode))
>> -              || (REAL_MODE_FORMAT (from_mode) == &arm_bfloat_half_format
>> -                  && REAL_MODE_FORMAT (to_mode) == &ieee_half_format)
>> -              || (REAL_MODE_FORMAT (to_mode) == &arm_bfloat_half_format
>> -                  && REAL_MODE_FORMAT (from_mode) == &ieee_half_format));
>> +              || acceptable_same_precision_modes (from_mode, to_mode));
>>
>>        if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
>>      {
>> --
>> 2.39.1
> 
> This part looks good to me FWIW, but what's the correct behaviour of:
> 
>       if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
>       {
>         if (REAL_MODE_FORMAT (to_mode) == &arm_bfloat_half_format
>             && REAL_MODE_FORMAT (from_mode) == &ieee_half_format)
>           /* libgcc implements just __trunchfbf2, not __extendhfbf2.  */
>           tab = trunc_optab;
>         else
>           /* Conversion between decimal float and binary float, same
>              size.  */
>           tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
> 
> for the new pairing?  The intent for bfloat/half seems to be that bfloat
> is treated as arbitrarily “lesser than” half, so half->bfloat is a
> truncation and bfloat->half is an extension.  It seems like it would be
> good to do something similar for the new pair, so that the float modes
> still form a total order in terms of extension & truncation.

Good question!  If I read it right, this special handling for half->bfloat is
to align with the previous implementation in libgcc and easy for backporting
, but isn't to keep the modes to form a total order, as Jakub's comments
PR114907 #c6 and #c8.  Similar to half vs. bfloat, neither of ibm128 nor ieee128
is a subset or superset of the other, the current behavior for this new paring 
is
that:
  1) define sext_optab for any two of TF/KF/IF (also bi-direction), since 
generic
     code above adopts sext_optab for same size conversion.
  2) for each define_expand in 1), it actually calls 
rs6000_expand_float128_convert
     which is one existing helper to handle conversions to/from __float128 and
     __ibm128, it will take care of the remaining (generate __extend* or 
__trunc*).
     Similar to half vs. bfloat which has extend and trunc libgcc functions, we
     have some extend and trunc libgcc functions for __float128 vs. __ibm128.

We can add some special treatment for the new pairing like what's for half vs. 
bfloat,
but since extend and truncate can be arbitrary for them, I thought we can just 
define
sext_optab to align with what generic code does and wants, then do the actual 
handling
in the corresponding expander (someone may argue that sext_optab is expected to 
be end
with libcall __extend*, it's surprising to end up with __trunc*, but considering
the extend/truncate here is arbitrary, guessing it's acceptable?).

Does it make sense to you?

BR,
Kewen

Reply via email to