5 ms·
Here's something I was wondering about: Suppose I've got some nasty DSP algos that depend on undefined behavior of type-punning in C. To address this I use the
by jancsika 8y ago
Here's something I was wondering about:
Suppose I've got some nasty DSP algos that depend on undefined behavior of type-punning in C. To address this I use the union member access trick which is supported by a gcc extension.
If my only target is web assembly, then what are the reason that I should care that my binary is actually a gcc dialect of c and not standard c?
- raphlinus 8y agoThat puts you pretty firmly in what I call the "semi-portable" category (I would say "unportable" but wasm is very likely going to have flavors, such as a 64 bit pointer variant). But if you're being careful, you can do type-punning. The "modern" way is generally with memcpy, but union can be valid if done carefully. The clearest statement I was able to find of this is [1]. I find it frustrating that it's so hard to get a clear read on this. For example, if as Regehr says union-based punning is reliable, then what was the concern that the linked Linux kernel patch trying to address? I haven't dug into it in super detail. [1] https://blog.regehr.org/archives/1307#comment-18418 https://blog.regehr.org/archives/1307#comment-18418
- saagarjha 8y agoIMO it’s pretty iffy and you should steer clear of it, since the rules around it seem to be murky. I think the actual rule is that it’s illegal in C++, and valid in C99 and C11 but only because it was included in a footer note as an afterthought in the standard.
- comex 8y agoFrom a standards perspective that’s pretty much right AFAIK. From a practical perspective, it’s also explicitly endorsed in the GCC manual, so I don’t think there’s much risk of popular compilers breaking it in the foreseeable future: > The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above works as expected. https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
- jancsika 8y agoSo what is the well-defined and performant way to fetch the exponent and mantissa of a double in standard C?
- saagarjha 8y agoUse frexp from <math.h>.
- jancsika 8y agoThe implementation for frexp uses type-punning. Also, it adds a denormal and inf check which I don't need in this particular hot loop.
- saagarjha 8y agoDoes it? On my computer it's a builtin (__builtin_frexp). But even if it did use type-punning, that doesn't make it legal for your program to do it. I don't believe there's any requirements on the C standard library to follow the standard themselves. To answer the second part of your response, the correct way to do this yourself would be to memcpy the double and then inspect the result directly. Any compiler worth its salt will end up generating the assembly code you want (namely, no call to memcpy, just a couple of arithmetic shifts and masks).
- jancsika 8y ago> To answer the second part of your response, the correct way to do this yourself would be to memcpy the double and then inspect the result directly. Any compiler worth its salt will end up generating the assembly code you want (namely, no call to memcpy, just a couple of arithmetic shifts and masks). What does a compiler "worth its salt" do with the memcpy at "-O0"?
- saagarjha 8y agoSee for yourself: https://godbolt.org/z/nsg9nt https://godbolt.org/z/nsg9nt
- userbinator 8y agoThat article seems to imply that the only way out of this mess is to turn off strict aliasing, since easy type punning and other related low-level processing is literally one of the main reasons to use C. I agree completely.
- jancsika 8y agoTo be clear, the use case I have in mind has a soft realtime performance requirements. So I only see two options: 1. Use memcpy, blindly hope that gcc optimizes it to the same bitmath I'm currently using, and blindly hope that gcc supports that optimized path for the foreseeable future. 2. Use the union type-punning trick, and blindly hope gcc supports their extension for the foreseeable future. #1 above requires me to blindly hope twice, whereas #2 requires only one instance of blind hope. Furthermore, I already know how the blind hope of gcc optimizing memcpy into bitmath turns out-- gcc does not optimize it in this way. So I cannot see any alternative to relying on the union type-punning trick in this case. Edit: clarification
- lmm 8y ago> If my only target is web assembly, then what are the reason that I should care that my binary is actually a gcc dialect of c and not standard c? How much do you trust the GCC implementors to a) maintain the behaviour that's relevant to your program b) maintain GCC at all? How much do you trust that the rest of the ecosystem will continue to support GCC and/or this GCC dialect? Think of "the gcc dialect of c" the same way you'd think of any semi-obscure programming language, and ask the same questions you would: what kind of debuggers/profilers exist for it? How easy is it to hire people with experience in it? How much momentum is there behind it?
- jancsika 8y agoThe obvious and uncontroversial answer is that there is no sane way this gcc extension can be dropped. Dropping the extension would mean there is no performant way to get at the bits of IEEE 754 floating point data in C (and perhaps other data types, but that's the one in my use case).