4 ms·
On the contrary, compiler built-ins can make your code more portable (across different hw architectures) at the expense of some other compilers. GCC and Clang
by exDM69 8y ago
On the contrary, compiler built-ins can make your code more portable (across different hw architectures) at the expense of some other compilers.
GCC and Clang have mostly compatible compiler intrinsics and with those two compilers you can compile your software to almost any platform out there.
If you need to get your code compiled on MSVC or ICC or some niche C compiler, you can work around this by adding some kind of wrapper around them with #ifdefs (not pretty).
With compiler built-ins you get SIMD, atomics, bitops (popcnt, clz, etc) that are portable to almost any CPU instruction set out there. Without them, you have to re-write that code for every instruction set you intend to support.
So your options are:
1) Stick to standard C and write code that compiles to suboptimal output code (such as using division to get multiply-with-overflow)
2) Use compiler built-ins and get portability across different HW at the expense of not supporting other compilers
3) Write wrappers around compiler built-ins with #ifdefs to support all the compilers you want (add fallback to standard C if you need to)
4) Write your code using HW-specific intrinsics or inline assembly
Out of these, option 2) will give you maximum portability with least amount of effort. The other options are more effort and the benefits are arguable. If you think there are other viable options, please do share.
- BeeOnRope 8y agoA variant of (3) that seems close to ideal is to use conditionally defined functions as suggested, that someone else has already written and generously shared, such as portable-snippets [0]. It has a component specifically to offer cross platform builtins with fallback/emulation on plaforms without direct support. [0] https://github.com/nemequ/portable-snippets https://github.com/nemequ/portable-snippets
- exDM69 8y agoThanks for the link, that looks quite useful if compiler portability is needed. It's still more effort than option #2, but quite an acceptable trade-off.
- Annatar 8y ago“2) Use compiler built-ins and get portability across different HW at the expense of not supporting other compilers” Writing code to two specific compilers (clang and gcc) is NOT portable code. This is absolutely unacceptable behavior.
- AstralStorm 8y agoThe absolutely unacceptable thing is C still not having standard (optional) SIMD syntax. It at least finally got atomics. But wait, that's not portable to Keil so you cannot use that ;) The reaction is, if you dislike fast but non standard code, push for standardization of those features, not begrudge developers for doing the right thing and using them.
- exDM69 8y agoI agree that it's unacceptable that SIMD Vector extensions [0] are not standardized yet. However, they already work acceptably in GCC and Clang. There are only minor differences (e.g. __builtin_shufflevector) but it's usable with very minimal #ifdeffing. Example: typedef float vec4f __attribute__((vector_size(16))); // initializer vec4f a = { 1.0, 2.0, 3.0, 4.0 }; // literal expression vec4f b = a + (vec4f){ 5.0, 6.0, 7.0, 8.0 }; // standard infix operators vec4f c = -b * (a+b); // with --ffast-math, this will be a mad() It's not perfect but it's quite usable and I've been using vector extensions in C for years. [0] https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
- Annatar 8y agoSIMD is processor specific, and is important only in certain scenarios. Trading portability for performance is a trade-off that most developers shouldn’t be willing to make if they are open sourcing their software, because it will prevent someone from running their software on that user’s desired platform, thereby showing the user the middle finger. That’s just wrong.