Will It Optimize?
ridiculousfish.com
ridiculousfish.com
This was the one time i was on the side of academia...
On my Linux machine, on the other hand, strlen() is marked pure, and there the optimization persists even with -fno-builtin.
So, it must know a bit about what strlen() does, mustn't it -- otherwise it wouldn't know that it has to ensure that \0 isn't written to s inside the loop body.
* Pedants will point out all subtleties about C pointer aliasing rules apply here. But for the purpose of explanation, assume that nothing assigning throuh s means "s is constant".
unsigned sum(const unsigned char *s, char *t) {
unsigned result = 0;
for (size_t i=0; i < strlen(s); i++) {
result += s[i];
*t = 'x';
}
return result;
}
gcc can't hoist strlen() in this case, because *t = 'x' could potentially overwrite the null termination of s.But yes, if all your functions are marked inline and visible to the compiler, there's no theoretical limit to GCC's ability to hoist constants out of the innermost parts of the loop. In practice, there are surely some performance limits to how much inlining will be expanded.
3. Multiplication by 2 to addition - integer
Will GCC transform an integer multiplication by 2 to addition?
The statement (not function) x * 2 is shift x left 1 bit on almost all compilers. Shift has a lot less dependencies than ADD/LEA and has better reciprocal throughput. Meh.Nope. Usually it's the reverse: Atom, for example, can only do one shift per cycle, but it can dual-issue adds.
It's the kind of thing that got skimped on in Atom. Lots of stuff runs surprisingly slow on Atom. Another one I find striking is that there are two pipes for ADD/SUB instructions, but ADC/SBB (the carry/borrow variants) are not just single-issue, but apparently unpipelined. Intel lists their throughput at 3 instead of 0.5!
Agner Fog lists ADC/SBB on Atom as having latency 2 and throughput 1/2. I guess Intel could have made them run with ADD/SUB-level performance in cases where there are no intra-pair dependencies on the carry/borrow flag, but the extra interlocks for handling that were probably not worth the cost.
You're right to say that TCO guarantees increase the expressiveness of a language. If we could provide the same guarantees for an even larger class of recursive functions, it stands to reason our expressiveness would increase even further!
void function(int x) {
switch (x) {
case 0: f0(); break;
case 1: f1(); break;
case 2: f2(); break;
case 3: f3(); break;
case 4: f4(); break;
case 5: f5(); break;
default:
}
}Section 6.8.4.2, item 5 of http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf (page 134)
(Pedantic note: It's technically incorrect to say that the switch statement does nothing.
switch(FunctionThatDoesSomethingAndReturns1()) {
case 2:
// foo
}
The switch body does nothing, but the actual statement does something.)