Say I have a loop variable and when I declare it I set a default value of zero. Later on I have a for loop that also sets it to zero.
That's a mistake. If you want it to be zero at the start of the loop, you should set it to zero at the start of the loop, not before. Setting it before eliminates the desirable warning about modifying an uninitialized variable should you mistakenly reference it before the start of your loop (-Wmaybe-uninitialized, enabled by -Wall).
As for your LED code, you *should* be warned about that if you've asked for -Wall. If you don't want to be warned, don't ask for all warnings.
Why would you want your object to map directly to your source
Why are you having trouble getting this? If I've told the compiler to optimize with -O2 then I want it to optimize, not "map directly to my source." If I've also told it to warn me about questionable constructions that are easy to avoid (-Wall) then I expect it to warn me when the optimizer decides it can remove an if{} block because the expression always evaluates to false. That's a VERY questionable construct!
#ifdefs are intended to remove blocks of code. You don't have to warn me when I explicitly tell you to remove a block of code.
If program behaviour is undefined, then all optimizations are valid
If 1=0 then everything is both true and false. Especially your statement.
What bunch of BS. That part of the code for the tun handler was wrong doesn't give the optimizer an excuse to make an entirely different part of the code wrong too.
If you find it convenient to code that way, be my guest. I'd even be in favor of a compiler warning level which excludes branch elimination from the warnings so that you need not be troubled by optimizer behavior you desire. But when I ask for *all* warnings, I mean all warnings... especially a determination by the optimizer that some of my code is unreachable and can thus be excluded.
No. No, I don't. Listen to the words that are coming out of my mouth. I want it to determine that it can eliminate the conditional. I want it to eliminate the conditional. And then I want it to tell me that it eliminated the conditional so that I can review my code,decide whether or not that was a sensible thing to do and correct my code as needed.
Lets look at an example: even though invalid type casting bugs are frequently exposed by type based alias analysis, it would not be useful to produce a warning that "the optimizer is assuming that P and P[i] don't alias" when optimizing "zero_array" (from Part #1 of our series).
float *P;
void zero_array() {
int i;
for (i = 0; i < 10000; ++i)
P[i] = 0.0f; }
But that statement makes no sense. P[i] is not a pointer, it's a single float. It can't be an alias for the pointer P. Hence there is no assumption for the optimizer to warn about.
P+i would be a pointer. But P[i] is the same as saying *(P+i).
And yes, I did see your comment. Did you see my response?
Sure. Except I #define BossMood and then #ifdef BossMood. That way anybody reading my code clearly understands that one branch is intended to be eliminated at compile time. From a documentation perspective, your version is confusing and opaque.
Then the STL author has included code in his header files. That makes him a bad boy who should be liberally spanked -- because code embedded in header files, with or without branches, is most emphatically *not* correct.
A warning would lead me to examine the code and, realizing that I've done something architecture dependent, #ifdef it for that architecture. If it's architecture dependent, I don't want it to be there quietly.
The results of arithmetic overflow is undefined in the language, not the architecture. Don't warn. Punt to the CPU and accept its result. If you optimize in a way that potentially corrupts the result from the CPU then I expect you to warn... and give me a compiler flag to turn the specific optimization off.
I'd expect it to work left to right, pass f(1,2) and leave the value 3 in i. Just like everything else in the language that works left to right and top to bottom. If I got any other result, I'd call the compiler broken.
Violating Type Rules: It is undefined behavior to cast an int* to a float* and dereference it (accessing the "int" as if it were a "float"). C requires that these sorts of type conversions happen through memcpy: using pointer casts is not correct and undefined behavior results. The rules for this are quite nuanced and I don't want to go into the details here (there is an exception for char*, vectors have special properties, unions change things, etc). This behavior enables an analysis known as "Type-Based Alias Analysis" (TBAA) which is used by a broad range of memory access optimizations in the compiler, and can significantly improve performance of the generated code. For example, this rule allows clang to optimize this function:
float *P;
void zero_array() {
int i;
for (i = 0; i < 10000; ++i)
P[i] = 0.0f;
}
Okay, maybe it's too early in the morning but where exactly did this function cast an int* to a float*? Where's the "undefined behavior"?
And anyway, how is casting int* to float* undefined behavior? You set this pointer to that pointer and now you're looking at the data a different way. It won't be sensible data unless you know what architecture you're programming to, but who says you don't?
No, I meant as written. When you encounter something undefined, turn the optimizer off and do the statements exactly as written. Whatever happens, make it happen in the order and steps that the programmer wrote. It'll still be wrong (most likely) but it'll be the programmer's wrong, not the compiler's wrong.
Do you work for Apple? Perhaps you're a voice inside my head? No? Then I would politely suggest that I have a better idea what *I want* than you do.
Serious coding shops treat warnings as errors because they are. If a compiler finds itself able to remove my if statement then either it's wrong or far more likely I made a mistake.
You would #pragma that off? Stay away from my code man.
RTFM. It's possible in some circumstances to map a page to 0x0 which contains exploit code, then call bad code. If the compiler hadn't optimized out the check for tun=0, the exploit would still fail in spite of the bug in the code.
If the compiler decides it can delete a conditional because it's always true or always false, I most certainly do want a warning!
That section of code has a bug: either I wrote the conditional wrong or I typo-ed something like using = instead of ==. Either way I want to know about it so I can fix my code.
One of the examples from the paper was this snippet from the Linux kernel:
struct sock *sk = tun->sk; if (!tun) return POLLERR;
gcc's optimizer deleted "if (!tun) return POLLERR;" because *sk=tun->sk implies that tun!=NULL.
Okay, I buy that. But if gcc did so without a warning with -Wall set then it gcc is broken. The author obviously expects it to be possible for tun==NULL, so if gcc decides it can't be that's a warning! Duh!
If I tell the compiler to give me warnings, it detects a code whose behavior is undefined in the standard, but then fails to issue a warning then the compiler is broken. If it goes on to make a fancy assumption about the undefined behavior instead of letting it fall through to runtime as written then it's doubly broken.
If I've set -Wall, I want a warning about "*a=1 is useless code." If the compiler optimizes it away without that warning, I'm going to cry about it sooner or later because there's a bug in my code. If I had meant *a=(*b)+1 I would have written it that way.
Understand: I want the compiler to optimize my code. I don't want it to drop sections of my code. If it thinks it can drop a section of my code entirely, or that a conditional can have only one result, that's almost certainly a bug and I want to know about it. After all -- if *I* thought the conditional could have only one result, I wouldn't have bothered checking it!
That code is bad for many reasons, not the least of which is that it's semantically ambiguous whether the result of malloc() should be assigned to a or *a.
However, the compiler here clearly can't make any valid assumptions about the contents of *a following the realloc. That's what undefined means: it holds a value about which you can't make any assumptions. Because the behavior is undefined, no *valid* optimization is possible.
Clang is wrong. If it's smart enough to recognize the undefined behavior then it should (a) warn the user and (b) make no optimization attempts to any code which later references *a.
You don't need to warn me about computing literals at compile time. You damn well better warn be about computing constants at compile time -- if that's what I wanted to happen, I'd have used a macro for a literal. If the compiler finds two constants it can combine then I've usually made a mistake in my code... even if it's nothing more than treating something that should be a variable as a constant.
So... for political reasons Nebraska's government wants a study which assesses only that portion of climate change which has resulted / is resulting from non-human factors. They aren't asking for a directed finding. They won't suppress the resulting report. They just insist on knowing what's happening on the climate change front that *isn't* human-caused.
'Cause, you know, the earth endured massive climate change for millions of years before humans evolved. It'd be hubris to think that human activity is solely responsible for current climate change patterns. As politicians consider how to respond, it'd be nice to be able to separate the factors under human control from the factors which are not.
And no climate change scientist will research this. Am I the only one who has a problem with the scientists' behavior here? This is scientists playing politician. Scientists should play scientist instead -- they're far better at it.
Say I have a loop variable and when I declare it I set a default value of zero. Later on I have a for loop that also sets it to zero.
That's a mistake. If you want it to be zero at the start of the loop, you should set it to zero at the start of the loop, not before. Setting it before eliminates the desirable warning about modifying an uninitialized variable should you mistakenly reference it before the start of your loop (-Wmaybe-uninitialized, enabled by -Wall).
As for your LED code, you *should* be warned about that if you've asked for -Wall. If you don't want to be warned, don't ask for all warnings.
Why would you want your object to map directly to your source
Why are you having trouble getting this? If I've told the compiler to optimize with -O2 then I want it to optimize, not "map directly to my source." If I've also told it to warn me about questionable constructions that are easy to avoid (-Wall) then I expect it to warn me when the optimizer decides it can remove an if{} block because the expression always evaluates to false. That's a VERY questionable construct!
#ifdefs are intended to remove blocks of code. You don't have to warn me when I explicitly tell you to remove a block of code.
If program behaviour is undefined, then all optimizations are valid
If 1=0 then everything is both true and false. Especially your statement.
What bunch of BS. That part of the code for the tun handler was wrong doesn't give the optimizer an excuse to make an entirely different part of the code wrong too.
Who else would I speak for?
If you find it convenient to code that way, be my guest. I'd even be in favor of a compiler warning level which excludes branch elimination from the warnings so that you need not be troubled by optimizer behavior you desire. But when I ask for *all* warnings, I mean all warnings... especially a determination by the optimizer that some of my code is unreachable and can thus be excluded.
Right, you want optimization turned off.
No. No, I don't. Listen to the words that are coming out of my mouth. I want it to determine that it can eliminate the conditional. I want it to eliminate the conditional. And then I want it to tell me that it eliminated the conditional so that I can review my code,decide whether or not that was a sensible thing to do and correct my code as needed.
From your link:
Lets look at an example: even though invalid type casting bugs are frequently exposed by type based alias analysis, it would not be useful to produce a warning that "the optimizer is assuming that P and P[i] don't alias" when optimizing "zero_array" (from Part #1 of our series).
float *P;
void zero_array() {
int i;
for (i = 0; i < 10000; ++i)
P[i] = 0.0f;
}
But that statement makes no sense. P[i] is not a pointer, it's a single float. It can't be an alias for the pointer P. Hence there is no assumption for the optimizer to warn about.
P+i would be a pointer. But P[i] is the same as saying *(P+i).
And yes, I did see your comment. Did you see my response?
Sure. Except I #define BossMood and then #ifdef BossMood. That way anybody reading my code clearly understands that one branch is intended to be eliminated at compile time. From a documentation perspective, your version is confusing and opaque.
Then the STL author has included code in his header files. That makes him a bad boy who should be liberally spanked -- because code embedded in header files, with or without branches, is most emphatically *not* correct.
A warning would lead me to examine the code and, realizing that I've done something architecture dependent, #ifdef it for that architecture. If it's architecture dependent, I don't want it to be there quietly.
The results of arithmetic overflow is undefined in the language, not the architecture. Don't warn. Punt to the CPU and accept its result. If you optimize in a way that potentially corrupts the result from the CPU then I expect you to warn... and give me a compiler flag to turn the specific optimization off.
Not following the logic that an infinite loop is "undefined." Seems pretty well defined to me. Bugged. But perfectly well defined.
I'd expect it to work left to right, pass f(1,2) and leave the value 3 in i. Just like everything else in the language that works left to right and top to bottom. If I got any other result, I'd call the compiler broken.
From the blog post:
Violating Type Rules: It is undefined behavior to cast an int* to a float* and dereference it (accessing the "int" as if it were a "float"). C requires that these sorts of type conversions happen through memcpy: using pointer casts is not correct and undefined behavior results. The rules for this are quite nuanced and I don't want to go into the details here (there is an exception for char*, vectors have special properties, unions change things, etc). This behavior enables an analysis known as "Type-Based Alias Analysis" (TBAA) which is used by a broad range of memory access optimizations in the compiler, and can significantly improve performance of the generated code. For example, this rule allows clang to optimize this function:
float *P;
void zero_array() {
int i;
for (i = 0; i < 10000; ++i)
P[i] = 0.0f;
}
Okay, maybe it's too early in the morning but where exactly did this function cast an int* to a float*? Where's the "undefined behavior"?
And anyway, how is casting int* to float* undefined behavior? You set this pointer to that pointer and now you're looking at the data a different way. It won't be sensible data unless you know what architecture you're programming to, but who says you don't?
No, I meant as written. When you encounter something undefined, turn the optimizer off and do the statements exactly as written. Whatever happens, make it happen in the order and steps that the programmer wrote. It'll still be wrong (most likely) but it'll be the programmer's wrong, not the compiler's wrong.
Do you work for Apple? Perhaps you're a voice inside my head? No? Then I would politely suggest that I have a better idea what *I want* than you do.
Serious coding shops treat warnings as errors because they are. If a compiler finds itself able to remove my if statement then either it's wrong or far more likely I made a mistake.
You would #pragma that off? Stay away from my code man.
RTFM. It's possible in some circumstances to map a page to 0x0 which contains exploit code, then call bad code. If the compiler hadn't optimized out the check for tun=0, the exploit would still fail in spite of the bug in the code.
If the compiler decides it can delete a conditional because it's always true or always false, I most certainly do want a warning!
That section of code has a bug: either I wrote the conditional wrong or I typo-ed something like using = instead of ==. Either way I want to know about it so I can fix my code.
One of the examples from the paper was this snippet from the Linux kernel:
struct sock *sk = tun->sk;
if (!tun) return POLLERR;
gcc's optimizer deleted "if (!tun) return POLLERR;" because *sk=tun->sk implies that tun!=NULL.
Okay, I buy that. But if gcc did so without a warning with -Wall set then it gcc is broken. The author obviously expects it to be possible for tun==NULL, so if gcc decides it can't be that's a warning! Duh!
If I tell the compiler to give me warnings, it detects a code whose behavior is undefined in the standard, but then fails to issue a warning then the compiler is broken. If it goes on to make a fancy assumption about the undefined behavior instead of letting it fall through to runtime as written then it's doubly broken.
If I've set -Wall, I want a warning about "*a=1 is useless code." If the compiler optimizes it away without that warning, I'm going to cry about it sooner or later because there's a bug in my code. If I had meant *a=(*b)+1 I would have written it that way.
Yeah, that's helpful.
Understand: I want the compiler to optimize my code. I don't want it to drop sections of my code. If it thinks it can drop a section of my code entirely, or that a conditional can have only one result, that's almost certainly a bug and I want to know about it. After all -- if *I* thought the conditional could have only one result, I wouldn't have bothered checking it!
That code is bad for many reasons, not the least of which is that it's semantically ambiguous whether the result of malloc() should be assigned to a or *a.
However, the compiler here clearly can't make any valid assumptions about the contents of *a following the realloc. That's what undefined means: it holds a value about which you can't make any assumptions. Because the behavior is undefined, no *valid* optimization is possible.
Clang is wrong. If it's smart enough to recognize the undefined behavior then it should (a) warn the user and (b) make no optimization attempts to any code which later references *a.
You don't need to warn me about computing literals at compile time. You damn well better warn be about computing constants at compile time -- if that's what I wanted to happen, I'd have used a macro for a literal. If the compiler finds two constants it can combine then I've usually made a mistake in my code... even if it's nothing more than treating something that should be a variable as a constant.
If I set -Wall and the compiler fails to warn me that it optimized out a piece of my code then the compiler is wrong. Period. Full stop.
I don't care what "unstable" justification its authors gleaned from the standard, don't mess with my code without telling me you did so.
So... for political reasons Nebraska's government wants a study which assesses only that portion of climate change which has resulted / is resulting from non-human factors. They aren't asking for a directed finding. They won't suppress the resulting report. They just insist on knowing what's happening on the climate change front that *isn't* human-caused.
'Cause, you know, the earth endured massive climate change for millions of years before humans evolved. It'd be hubris to think that human activity is solely responsible for current climate change patterns. As politicians consider how to respond, it'd be nice to be able to separate the factors under human control from the factors which are not.
And no climate change scientist will research this. Am I the only one who has a problem with the scientists' behavior here? This is scientists playing politician. Scientists should play scientist instead -- they're far better at it.