Not the first discussion of this topic, by any means. In this case, I've tried to boil it down to the essential points a practical programmer needs to know, but the article still ended up longer than I initially aimed for.
One hopefully constructive comment… I didn’t find this a motivating example as intended:
int foo_or_bar(int which) {
// Assumes you don't mind both functions being called
int x = foo();
int y = bar();
return *(&x + which);
}
The argument being (if I understood right) if x has to have an address, it can’t be put in a register, so that must be UB or we can’t use registers. Well, how about the rule is that if I take the address of x, it can’t be put in a register? That seems like an obvious rule, and I seem to remember that was a safe assumption before the “great UBification” of compilers.
I’m sure there’s a better example of why UB helps optimization, but this one didn’t work for me.
Ohhh. I misunderstood the example. That would not only depend on a lack of register usage, but depend on where the variables are stored on the stack, which I don’t think anyone could reasonably demand even in 1976.
So I still feel there must be a more reasonable and therefore motivating example of optimizations one would want that are enabled by surprising you with UB. (Which I think was the idea behind this example.)
depend on where the variables are stored on the stack, which I don’t think anyone could reasonably demand even in 1976
You'd be surprised. A typical compiler of that era would be single-pass, and allocating variables on the stack in order in which they were declared was not uncommon. Don't forget, we're talking about a language that actually had a "register" keyword solely to tell the compiler to enregister the variable!
Comments
Not the first discussion of this topic, by any means. In this case, I've tried to boil it down to the essential points a practical programmer needs to know, but the article still ended up longer than I initially aimed for.
One hopefully constructive comment… I didn’t find this a motivating example as intended:
The argument being (if I understood right) if x has to have an address, it can’t be put in a register, so that must be UB or we can’t use registers. Well, how about the rule is that if I take the address of x, it can’t be put in a register? That seems like an obvious rule, and I seem to remember that was a safe assumption before the “great UBification” of compilers.I’m sure there’s a better example of why UB helps optimization, but this one didn’t work for me.
The issue is that y might end up in a register, and you didn't take the address of y.
Ohhh. I misunderstood the example. That would not only depend on a lack of register usage, but depend on where the variables are stored on the stack, which I don’t think anyone could reasonably demand even in 1976.
So I still feel there must be a more reasonable and therefore motivating example of optimizations one would want that are enabled by surprising you with UB. (Which I think was the idea behind this example.)
You'd be surprised. A typical compiler of that era would be single-pass, and allocating variables on the stack in order in which they were declared was not uncommon. Don't forget, we're talking about a language that actually had a "register" keyword solely to tell the compiler to enregister the variable!
Well, now that you mention it, that’s true, I was there. :) But I just want to go back to 1992, not 1976.