3 ms·
Compiler developers do care about the C language. They just care about it as it's actually used. In real-world C, people write "for (int i = 0; i < array->lengt
by pcwalton 8y ago
Compiler developers do care about the C language. They just care about it as it's actually used. In real-world C, people write "for (int i = 0; i < array->length; i++)". The Linux kernel might not, but that's a choice the Linux kernel developers have made. Lots of C code uses different idioms from the Linux kernel, and users expect that code to run fast. Slowing down that code out of a notion of language purity (especially when "Friendly C" isn't even defined) does a disservice to users.
I can't speak for anyone but me, but I read the opposition to doing these kinds of optimizations in that Gist as preferring compiler warnings to suggest users use size_t when appropriate. This would be great, but I'm skeptical that, for example, Linux distros would be happy about that. Most Linux distributions consist of packages of vast amounts of unmaintained or mostly unmaintained C code. There simply isn't the manpower available to fix all that code to be properly 64-bit optimized (which is in fact why int is 32 bits on x86-64 Linux in the first place).
- petergeoghegan 8y agoI'm suggesting that compiler authors don't seem to pay sufficient attention to how C is actually used, though. It may well be true that I don't have the full picture here, but I don't think that these concerns can be waved away so easily. Postgres has code like "for (int i = 0; i < array->length; i++)" in many places. I believe that the same is true of the kernel.
- pcwalton 8y ago> I'm suggesting that compiler authors don't seem to pay sufficient attention to how C is actually used, though. Compiler developers pay more attention to how C is used than virtually anyone else. After all, they are the ones who have to deal with bug reports--often bug reports saying that code is slow. It's not like compiler engineers implement optimizations for no reason, or just to make themselves seem smart. They implement optimizations because somebody files a bug report saying that some code is slow, and they go to fix it. > Postgres has code like "for (int i = 0; i < array->length; i++)" in many places. I believe that the same is true of the kernel. If that's true, then Postgres is giving up performance on 64-bit for that, which can be significant. That is a decision they can opt into. It's not a decision everyone else should have to opt out of.
- brigade 8y ago> Most Linux distributions consist of packages of vast amounts of unmaintained or mostly unmaintained C code Well, that's exactly the kind of code I'd expect to simply break when the compiler becomes able to prove new optimizations based on undefined behavior. When that happened to me, I decided there was no way I was trawling through our massive legacy codebase to fix undefined behavior that ubsan can't catch. Resulted in -fwrapv -fno-strict-aliasing being added, and any speed loss was noise under 0.5% Then in our modern codebase, I did my absolute best to ensure we built it no undefined behaviour, including contortions to avoid undefined left shifts... and we still got screwed over by a new version of clang. For all the worry about "for (int i = 0; i < array->length; i++)" specifically, how often is that actually measurable whole-program? It's one additional sign extension in a tight loop, plus a store/load in a complex loop, which a modern CPU would completely hide 99.9% of the time.
- pcwalton 8y ago> It's one additional sign extension in a tight loop, plus a store/load in a complex loop, which a modern CPU would completely hide 99.9% of the time. Not true. It's a store/load in the tight, simple loops that are the problem. Sometimes making your loop too big will cause you to fall out of the uop cache on x86, which is a significant performance hit. Modern CPUs don't hide this inefficiency, which is why compiler developers implemented the optimizations in the first place. (LLVM and GCC benchmarking infrastructure is excellent; they test this stuff continuously and don't land changes that don't demonstrate benefits.)
- brigade 8y agoMy suspicion is that loops that need even a dozen registers are in general either not tight enough on modern CPUs that a spill is measurable (maybe they were that tight 10-15 years ago), or were optimized after 64-bit was common. Or maybe I'm just disappointed from all the times I've eliminated spills and other extraneous µops in small tight loops with no measurable gain even in microbenchmarks. I kinda wish that benchmarking infrastructure was reflected in my experience; I've spent entirely too much time fixing performance regressions in various inner loops caused by newer compilers. Though to be fair, only once has that regression exceeded 2x. To give some context: if a loop is large enough that it's on the verge of falling out of the µop cache, I'd consider that a massive loop. And from my experience any code that complex I definitely wouldn't trust newer compiler versions to not randomly add a dozen or two instructions. Anyway... exactly how much does -fwrapv impact LLVM or GCC's benchmarking testsuite?