[PATCH] include/longlong.h: Remove incorrect lvalue to rvalue conversion from asm output constraints

Fāng-ruì Sòng maskray@google.com
Fri Oct 15 03:59:20 GMT 2021


On 2021-10-12, Jakub Jelinek wrote:
>On Tue, Oct 12, 2021 at 09:21:21AM -0700, Fāng-ruì Sòng wrote:
>> > > An output constraint takes a lvalue. While GCC happily strips the
>> > > incorrect lvalue to rvalue conversion, Clang rejects the code by default:
>> > >
>> > >     error: invalid use of a cast in a inline asm context requiring an lvalue: remove the cast or build with -fheinous-gnu-extensions
>> > >
>> > > The file appears to share the same origin with gmplib longlong.h but
>> > > they differ much now (gmplib version is much longer).
>> > >
>> > > I don't have write access to the git repo.
>> > > ---
>> > >  include/longlong.h | 186 ++++++++++++++++++++++-----------------------
>> > >  1 file changed, 93 insertions(+), 93 deletions(-)
>> > >
>> > > diff --git a/include/longlong.h b/include/longlong.h
>> > > index c3e92e54ecc..0a21a441d2d 100644
>> > > --- a/include/longlong.h
>> > > +++ b/include/longlong.h
>> > > @@ -194,8 +194,8 @@ extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype);
>> > >  #if defined (__arc__) && W_TYPE_SIZE == 32
>> > >  #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
>> > >    __asm__ ("add.f    %1, %4, %5\n\tadc       %0, %2, %3"             \
>> > > -        : "=r" ((USItype) (sh)),                                     \
>> > > -          "=&r" ((USItype) (sl))                                     \
>> > > +        : "=r" (sh),                                                 \
>> > > +          "=&r" (sl)                                                 \
>> > >          : "%r" ((USItype) (ah)),                                     \
>> > >            "rICal" ((USItype) (bh)),                                  \
>> > >            "%r" ((USItype) (al)),                                     \
>> >
>> > This seems to alter the meanining of existing programs if sh and sl do
>> > not have the expected type.
>> >
>> > I think you need to add a compound expression and temporaries of type
>> > USItype if you want to avoid the cast.
>>
>> Add folks who may comment on the output constraint behavior when a
>> lvalue to rvalue conversion like (`(USItype)`) is added.
>
>Allowing the casts in there is intentional, the comment about this
>e.g. in GCC's C FE says:
>Really, this should not be here.  Users should be using a
>proper lvalue, dammit.  But there's a long history of using casts
>in the output operands.  In cases like longlong.h, this becomes a
>primitive form of typechecking -- if the cast can be removed, then
>the output operand had a type of the proper width; otherwise we'll
>get an error.
>
>If you try e.g.:
>
>void
>foo (void)
>{
>  int i;
>  long l;
>  __asm ("" : "=r" ((unsigned) i));
>  __asm ("" : "=r" ((long) l));
>  __asm ("" : "=r" ((long long) l));
>  __asm ("" : "=r" ((int) l));
>  __asm ("" : "=r" ((long) i));
>}
>
>then on e.g. x86-64 the first 3 asms are accepted by GCC, the last two
>rejected, because the modes are different there.
>
>So the above change throws away important typechecking.  As it is
>used in a macro, something different should verify that if the casts are
>removed.
>
>	Jakub
>

Thanks for the detailed explanation. I see the type checking effect now.
In many cases the assembler can provide some checks, e.g.

   long foo(long a) {
     long r;
     __asm__ ("movq %1, %0" : "=r"(r) : "r"(a));
     return r;
   }

I came here from trying to build glibc with Clang where I came across errors like

In file included from strtof_l.c:44:
./strtod_l.c:1500:26: error: invalid use of a cast in a inline asm context requiring an lvalue: remove the cast or build with -fheinous-gnu-extensions
               udiv_qrnnd (quot, n, n, 0, d);
               ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
./longlong.h:518:24: note: expanded from macro 'udiv_qrnnd'
              "=d" ((UDItype) (r))                                       \
                    ~~~~~~~~~~~^~
In file included from strtof_l.c:44:
./strtod_l.c:1606:21: error: invalid use of a cast in a inline asm context requiring an lvalue: remove the cast or build with -fheinous-gnu-extensions
                       add_ssaaaa (n1, n0, r - d0, 0, 0, d0);
                       ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~

(Seems that building GCC with Clang doesn't run into the issues?)

If the desire to keep the checking is still strong, perhaps I will just stick with using the -f option for glibc.


More information about the Gcc-patches mailing list