On 2018-03-21 00:08, Linus Torvalds wrote:
> On Tue, Mar 20, 2018 at 3:13 PM, Uecker, Martin
> <[email protected]> wrote:
>>
>> here is an idea:
> 
> That's not "an idea".
> 
> That is either genius, or a seriously diseased mind.
> 
> I can't quite tell which.
> 
>> a test for integer constant expressions which returns an
>> integer constant expression itself which should be suitable
>> for passing to __builtin_choose_expr might be:
>>
>> #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : 
>> (int*)1)))

Wow. This is absolutely awesome.

>> This also does not evaluate x itself on gcc although this is
>> not guaranteed by the standard. (And I haven't tried any older
>> gcc.)
> 
> Oh, I think it's guaranteed by the standard that 'sizeof()' doesn't
> evaluate the argument value, only the type.

Even if there's some hypothetical scenario where x ends up containing
something of variably-modified type, could one just use 0? instead of 1?
. That doesn't affect the type of the whole expression.

> I'm in awe of your truly marvelously disgusting hack. That is truly a
> work of art.

I'm not really worthy of commenting or trying to improve on this, but I
think it's important that 'git blame' will forever give Martin the
credit for this, so two minor suggestions:

- Cast (x) to (long) to allow x to have type u64 on a 32-bit platform
without giving "warning: cast to pointer from integer of different
size". That also allows x to have pointer type (it's theoretically
useful to take max() of two pointers into an array), and not so
important for the kernel, floating point type.

- Maybe use (int*)4 to avoid the compiler complaining about creating a
non-aligned pointer.

> I'm sure it doesn't work or causes warnings for various reasons, but
> it's still a thing of beaty.

I tried putting the below ugly test code through various gcc versions.
In no cases could I get different optimization options to generate
different results. I also couldn't get -Wall -Wextra to produce any
warnings that wasn't just due to the silly input (i.e., yes, I know I
have a comma expression with no side effects....). Most importantly,
ICE_P was always accepted as an ICE itself. Everything from 4.6 onwards
gives the same and expected output, namely 1 in the first four lines, 0
otherwise. gcc 4.4 instead produces this:

4                       1
sizeof(long)            1
5ull - 3u               1
3.2                     1
square(2)               0
square(argc)            0
squarec(2)              1
squarec(argc)           1
1+argc-argc             1
1+argc+argc+1-argc-argc 1
bignum() - 1            0
0*bignum()              0
0*bignumc()             1
sizeof(foo)             0
p                       1
p < q                   1
p++                     0
main                    1
malloc(8)               0
v = malloc(8)           0
v                       1
x++                     0
y++                     0
(3, 2, 1)               0
({x++; 0; })            0
({square(y--); 0; })    0
(square(x), 3)          0
(squarec(x), 3)         0
({squarec(x); 3;})      0
({squarec(x);})         1

So it seems to accept/treat (x)*0l as NULL as long as x has no
side-effects - where a function call is treated as having side effects
unless the function is declared with the const attribute,
comma-expressions are hard-coded as having side-effects [and what else
would they be good for, so that's not totally unreasonable...], and
statement expressions have side effects if they have more than one
statement.

Rasmus


#include <stdio.h>
#include <stdlib.h>

static inline __attribute__((__const__)) unsigned squarec(unsigned n)
{
        return n*n;
}

static inline unsigned square(unsigned n)
{
        return n*n;
}

static inline unsigned long long bignum(void)
{
        return 1000000000000ULL;
}

static inline __attribute__((__const__)) unsigned long long bignumc(void)
{
        return 1000000000000ULL;        
}

/* #define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((long)(x) *
0l)) : (int*)1))) */
#define ICE_P(x) (__builtin_types_compatible_p(typeof(0 ?
((void*)((long)(x) * 0l)) : (int*)1), int*))

#define t(x) printf("%-20s\t%d\n", #x, __builtin_choose_expr(ICE_P(x),
1, 0))

int main(int argc, char *argv[])
{
        char foo[argc++];
        char **p, **q;
        int x = 5, y = 8;
        void *v;
        
        p = &argv[3];
        q = &argv[6];
        
        t(4);
        t(sizeof(long));
        t(5ull - 3u);
        t(3.2);
        t(square(2));
        t(square(argc));
        t(squarec(2));
        t(squarec(argc));
        t(1+argc-argc);
        t(1+argc+argc+1-argc-argc);
        t(bignum() - 1);
        t(0*bignum());
        t(0*bignumc());
        t(sizeof(foo));
        t(p);
        t(p < q);
        t(p++);
        t(main);
        t(malloc(8));
        t(v = malloc(8));
        t(v);
        t(x++);
        t(y++);
        t((3, 2, 1));
        t(({x++; 0; }));
        t(({square(y--); 0; }));
        t((square(x), 3));
        t((squarec(x), 3));
        t(({squarec(x); 3;}));
        t(({squarec(x);}));

        /* Shutup distracting warnings. */
        if (argc > 100000) {
                printf("%llu", square(argc) + squarec(argc) + bignum() + 
bignumc());
        }
        
        return 0;
}



Reply via email to