lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]




Le dim. 12 mai 2019 à 07:38, Andrew Gierth <andrew@tao11.riddles.org.uk> a écrit :
>>>>> "Philippe" == Philippe Verdy <verdy_p@wanadoo.fr> writes:

 >> fprintf(stderr,"n=%lli x=%llx
 >> <≤=≥>:%i%i%i%i%i\n",n,n,n<0,n<=0,n==0,n>=0,n>0);
 >> if (n<0) n=-n;
 >> fprintf(stderr,"n=%lli x=%llx
 >> <≤=≥>:%i%i%i%i%i\n",n,n,n<0,n<=0,n==0,n>=0,n>0);
 >>
 >> produces (GNU compiler):
 >>
 >> n=-9223372036854775808 x=8000000000000000  <≤=≥>:11000
 >> n=-9223372036854775808 x=8000000000000000  <≤=≥>:01010

 Philippe> What you show here is a bug of the C compiler in its
 Philippe> optimizer

Possibly unfortunately, this is not a bug. The program invokes undefined
behavior when it does n=-n on the the value shown; the compiler is
entitled to produce any output at all as a result.

In this case it's fairly obvious what happened: after seeing the line

if (n<0) n=-n;

the compiler is entitled to assume that n>=0 is true regardless of the
prior value of n, since only undefined behavior could cause that not to
be the case and the compiler is allowed to assume that undefined
behavior never occurs. So in the second fprintf, the compiler can
optimize (n>=0) to a constant 1, and (n<0) to a constant 0, while still
computing the remaining tests.

Such compiler assumption is wrong and it's clearly a bug in its optimizer , trying to infer constant values from code whose evaluation is clearly not constant here, that line does not mean that the result in n is necessarily positive. so it cannot assume that n>=0 after this line (even if C indicates that the result is undefined, then the further tests of n<0 and n>=0 must still be computed: an undefined value has no *constant* sign).

But with your code I do not get the same result as you, so I bet you use a bad version of GCC with this bug. I tried your code with several C or C++ compilers, none of them exhibit this, and the bits shown after "<≤=≥>:" are consistant.

Even if integers were natively implemented using floatting points, and the result of n=-n (when n is int_min) was an "NaN" value, which is not comparable (in any test) to 0 (or any value including another NaN), then the test bits you'd get would be "<≤=≥>:00000". In that case on such theoretical platform, the expressions (!(n<0)) and (n>=0) are not equivalent, and the compiler cannot also make any assumption and has to compte all tests.

Finally, not just the compiler version is important here: you may have used some advanced (but experimental) optimizing options on its command line to permit such unsafe assumptions (trying to infer constant from subexpressions or statements, and then propagating these constant to further reduce the code generation after them). I've tried to compile your code with optimization enabled (-O) and do not reproduce it, so it's possible you used some "long option" (--keyword).

Note that your code may not experiment this bug if there's a function call between the "if()" statement and the "fprintf" statement (whose parameters must be computed and passed before performing the call to that function... which may also be inlined using some compiler-specific intrinsic instead of performing an actual function call with parameters pushed on the stack). So changing 

    if (n<0) n=-n;
    fprintf(stderr,"n=%lli x=%llx <≤=≥>:%i%i%i%i%i\n",n,n,n<0,n<=0,n==0,n>=0,n>0);

just to:

    if (n<0) n=-n;
    fprintf(stderr,"n=%lli x=%llx",n,n)
    fprintf(stderr,"<≤=≥>:%i%i%i%i%i\n",n<0,n<=0,n==0,n>=0,n>0);

may not exhibit this bug on your platform (this also depends on where the variable "n" is declared: on the stack or as a global, or if the compiler can infer it is not aliased and the local variable is not modified by the first function call, acting as a "memory barrier").

My opinion is that your GCC compiler version has a bug or you used some unsupported options or non-standard/untested patch, or your Linux distribution is not reliable and delivers you very badly compiled products: change your Linux update source or switch to a reliable distribution.