On Wed, Mar 09, 2022 at 08:24:24PM +0100, Jakub Jelinek wrote:
> On Wed, Mar 09, 2022 at 12:34:06PM -0600, Segher Boessenkool wrote:
> > > rs6000_expand_builtin has (but at an incorrect spot) code to remap
> > > __builtin_{,un}pack_ibm128 to __builtin_{,un}pack_longdouble under the 
> > > hood,
> > > for 2 reasons:
> > > 1) __ibm128 type is only supported when VSX is enabled,
> > 
> > Ugh, another bug.  *^*ET*(^(*^TE($^TW(*T(W
> 
> I agree, but I don't have much energy to fix all the bugs in the backend in 
> one
> patch.

Yes, but this is a very fundamental thing that causes a lot of
unnecessary complexity :-(

> Probably it could be fixed with incremental:
> 
> --- gcc/config/rs6000/rs6000-builtin.cc.jj    2022-03-09 19:55:31.879255798 
> +0100
> +++ gcc/config/rs6000/rs6000-builtin.cc       2022-03-09 20:10:53.778612345 
> +0100
> @@ -713,9 +713,9 @@ rs6000_init_builtins (void)
>       For IEEE 128-bit floating point, always create the type __ieee128.  If 
> the
>       user used -mfloat128, rs6000-c.cc will create a define from __float128 
> to
>       __ieee128.  */
> -  if (TARGET_FLOAT128_TYPE)
> +  if (TARGET_LONG_DOUBLE_128 && (!TARGET_IEEEQUAD || TARGET_FLOAT128_TYPE))
>      {
> -      if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
> +      if (!TARGET_IEEEQUAD)
>       ibm128_float_type_node = long_double_type_node;
>        else
>       {
> @@ -727,7 +727,12 @@ rs6000_init_builtins (void)
>        t = build_qualified_type (ibm128_float_type_node, TYPE_QUAL_CONST);
>        lang_hooks.types.register_builtin_type (ibm128_float_type_node,
>                                             "__ibm128");
> +    }
> +  else
> +    ibm128_float_type_node = NULL_TREE;
>  
> +  if (TARGET_FLOAT128_TYPE)
> +    {
>        if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
>       ieee128_float_type_node = long_double_type_node;
>        else
> @@ -737,7 +742,7 @@ rs6000_init_builtins (void)
>                                             "__ieee128");
>      }
>    else
> -    ieee128_float_type_node = ibm128_float_type_node = NULL_TREE;
> +    ieee128_float_type_node = NULL_TREE;
>  
>    /* Vector pair and vector quad support.  */
>    vector_pair_type_node = make_node (OPAQUE_TYPE);
> @@ -3419,11 +3424,10 @@ rs6000_expand_builtin (tree exp, rtx tar
>        return const0_rtx;
>      }
>  
> -  if (bif_is_ibm128 (*bifaddr)
> -      && !(ibm128_float_type_node || FLOAT128_2REG_P (TFmode)))
> +  if (bif_is_ibm128 (*bifaddr) && !ibm128_float_type_node)
>      {
> -      error ("%qs requires %<__ibm128%> type support or %<long double%> "
> -          "to be IBM 128-bit format", bifaddr->bifname);
> +      error ("%qs requires %<__ibm128%> type support",
> +          bifaddr->bifname);
>        return const0_rtx;
>      }

Something like that yes.  It still is all way more complicated than it
should be.  Not your fault of course.

> which ought to support __ibm128 as the same thing as long double
> if long double is double double, and also as a separate IFmode
> double double if -mabi=ieeelongdouble and TARGET_FLOAT128_TYPE
> (i.e. both IFmode and KFmode are supported).

It should support __ibm128 always, and __ieee128 whenever VSX is
supported (it should be whenever VMX is supported, and even *always* as
well imnsho, but I haven't won that fight yet).

> > >    seems the intent
> > >    was that those 2 builtins can be used interchangeably unless
> > >    long double is the same as __ieee128, in which case
> > >    __builtin_{,un}pack_longdouble errors and
> > >    __builtin_{,un}pack_ibm128 works and returns/takes __ibm128
> > 
> > Aha.
> > 
> > But the type "if" always means the same thing, in the builtins language.
> 
> True.  Before the patch it means ibm128_float_type_node, which is
> a tree connected to __ibm128 type if it exists (but could very well be
> equal to long_double_type_node) or long_double_type if it doesn't.
> With the patch it means the same thing, except that ibm128_float_type_node
> is NULL if __ibm128 isn't supported, and at that point if means
> long_double_type_node.  So, on the builtins side, if is the same thing
> as before.

Ah good.

> > > 2) even with VSX, unless -mlong-double-128 -mabi=ieeelongdouble is in
> > >    effect, ibm128_float_type_node has TFmode rather than IFmode,
> > >    so we can't use the {,un}packif expanders but need {,un}packtf
> > >    instead
> > 
> > TFmode *is* IFmode, in that case.  TFmode is a workaround for
> > shortcomings in the generic parts of GCC.  This almost works as well
> > even!  But it is confusing no end.
> 
> TFmode isn't IFmode in that case, otherwise there wouldn't be the ICE on
> (insn 9 8 10 2 (set (reg:IF 119)
>          (unspec:TF [
>                 (reg:DF 120)
>                 (reg:DF 122)
>             ] UNSPEC_PACK_128BIT)) "prqquu.C":4:32 -1
>      (nil))
> etc.  IFmode and TFmode clearly are separate modes, which in those
> cases have the same REAL_MODE_FORMAT.  So, under the hood they are handled
> the same, but still it isn't acceptable in RTL to mix the two modes
> in cases where RTL requires the same mode.  Like in the SET_DEST/SET_SRC
> case must have the same mode, or operands of most arithmetic ops and the
> result have to have the same mode, ...

Yes, for some strange reason that I still do not understand we do not
#define one mode to the other.  Buy you agree TFmode is what IFmode is
otherwise...  This stuff is too complicated to explain :-(

> > > Which means the
> > >   ibm128_float_type_node ? ibm128_float_type_node : long_double_type_node
> > > is actually the right thing (except for -mlong-double-64 but the
> > > patch will reject those builtins in that case) - if
> > > ibm128_float_type_node is NULL but long_double_type_node is TFmode,
> > > we want __builtin_{,un}pack_ibm128 to work like
> > > __builtin_{,un}pack_longdouble and use long double, if
> > > ibm128_float_type_node is non-NULL and long_double_type_node is TFmode,
> > > ibm128_float_type_node == long_double_type_node and again we want it to
> > > work like __builtin_{,un}pack_longdouble and finally if
> > > ibm128_float_type_node is non-NULL and long_double_type_node is KFmode,
> > > it will use ibm128_float_type_node with IFmode.
> > 
> > ibm128_float_type_node should always be defined if we can use double-
> > double.  That is the whole point of having __ibm128 and __ieee128 types
> > at all: they exist whenever they can, and always mean the same thing.
> > We should never (have to) do strange gymnastics to access those types.
> 
> With the above incremental patch, perhaps (if it works).

The way it was *meant to be*.  Not how it was implemented it seems :-(

> But still we can't make if be NULL if __ibm128 isn't supported, because
> we'll ICE already during creation of the builtins.
> Perhaps error_mark_node might be a possibility (though very risky), but
> because of the builtins generator that isn't an option (it appends
> "_type_node" and error_mark_node doesn't end with "_type_node").
> Using long double will keep the existing behavior for that case and
> we'll reject calls to the builtin.

But __ibm128 should *always* be supported, so this is a hypothetical
problem.

> > > E.g. C++
> > > auto foo (void) { return __builtin_pack_ibm128 (100000000.0, 
> > > 0.0000000001); }
> > > double bar (long double x) { return __builtin_unpack_ibm128 (x, 0); }
> > > double baz (long double x) { return __builtin_unpack_ibm128 (x, 1); }
> > > used to be strangely accepted with -mlong-double-64 but did just a weird
> > > thing (now is rejected),
> > 
> > Neither is correct; it should do the simple and correct thing in both
> > cases.  Whatever your long double is: long double has nothing whatsoever
> > to do with __ibm128 and __ieee128.
> 
> With the above incremental patch I could use there __ibm128 instead of
> long double in the testcase (but even if I don't, there is just
> an extra long double to __ibm128 conversion which is either nop
> conversion or __float128 to __ibm128 conversion).
> What I wanted to say is that with e.g. -mlong-double-64 when there
> just isn't any double double there is nothing to pack or unpack,
> we should reject it rather than doing something weird.

Ah.  Yet Another bug?  -mlong-double-64 should not mean at all that
double-double does not exist / is not meaningful, just that this isn't
what long double uses.

> > > +  if (bif_is_ibm128 (*bifaddr)
> > > +      && !(ibm128_float_type_node || FLOAT128_2REG_P (TFmode)))
> > > +    {
> > > +      error ("%qs requires %<__ibm128%> type support or %<long double%> "
> > > +      "to be IBM 128-bit format", bifaddr->bifname);
> > > +      return const0_rtx;
> > > +    }
> > 
> > So this part is wrong imo.
> 
> The incremental patch tweaks this.
> 
> > > +  if (bif_is_ibm128 (*bifaddr) && TARGET_LONG_DOUBLE_128 && 
> > > !TARGET_IEEEQUAD)
> > > +    {
> > > +      if (fcode == RS6000_BIF_PACK_IF)
> > > + {
> > > +   icode = CODE_FOR_packtf;
> > > +   fcode = RS6000_BIF_PACK_TF;
> > > +   uns_fcode = (size_t) fcode;
> > > + }
> > > +      else if (fcode == RS6000_BIF_UNPACK_IF)
> > > + {
> > > +   icode = CODE_FOR_unpacktf;
> > > +   fcode = RS6000_BIF_UNPACK_TF;
> > > +   uns_fcode = (size_t) fcode;
> > > + }
> > > +    }
> > 
> > And this.
> 
> This is really necessary.  I could check
> && TYPE_MODE (ibm128_float_type_node) == TFmode
> with the incremental patch if that is better understandable, but still, due
> to TFmode != IFmode it is required, and after all, it has been there
> before too, just done too late so that it already did a wrong thing before.

If you are fed up with all this, please commit what you have now (after
testing of course ;-) ), and I'll pick up things myself.  Either way,
thank you for all your work on this!


Segher

Reply via email to