Question

My requirement is simple, I want to be able to count the number of bits in a number. With a little bit of research, I found that MSVC has __popcnt, GCC has __builtin_popcount and so on.

At this stage, it's one function. Later on here are some that would also be very useful in my program, but are again compiler-specific

  • _byteswap_uint64
  • __shiftright128, __shiftleft128

But then I would have to do

#if defined(_MSC_VER)
...
#elif defined(__GNUG__)
...
...
#endif 

to make it work on other compilers. But this makes the program look very ugly and very hard to maintain.

The question: Is it bad to use compiler-specific functions in your source? i.e Should I avoid using them?

Was it helpful?

Solution

Is it bad to use compiler-specific functions in your source? i.e Should I avoid using them?

The answer is "it depends." A naive hand-rolled popcount function requires but a few lines of code that are easy to understand, easy to test, and highly portable.

Suppose on performance testing you find that the CPU spends a tiny, tiny fraction of the execution time in this nice simple chunk of code. In this case, there is no reason to pollute your code with #ifdef this, #elif defined that, and #elif defined something_else. Optimized code oftentimes is rather ugly code, with #ifdef being about as ugly as it gets.

On the other hand, suppose on performance testing you find that the CPU spends a significant fraction of the execution time in this nice simple chunk of code, and suppose you find that the compiler-specific intrinsics reduce this by a significant amount. This can justify getting ugly, but keep in mind that that ugly code may be fragile. Your code is now at the mercy of vendors maintaining backward compatibility with their intrinsics. There is no guarantee that that will continue.

One final note: In the future you might well find that your naive hand-rolled popcount function suddenly becomes just as fast as the compiler-specific ugliness. Compiler writers (and hence compilers) have become ever more adept at recognizing the intent of code. A compiler might well recognize that your small number of lines of code does exactly what __popcount_using_specialized_assembly_instructions does, and thereby compiles your code to call that specialized function. You could have done the same using a bunch of macro commands. But what happens when the authors of the library change the name of the function? The compiler will be cognizant of that change and compile your naive hand-rolled popcount function to call the renamed function. Your macro plagued code will not.

OTHER TIPS

You should avoid using such compiler-specific functions in the main body of your code, exactly because of the #ifdef hell it creates.

If such a compiler-specific function is the best choice at some point in your code, you should wrap it in an (inline) function of your own. That way, you can

  • keep all the #ifdef logic in one place, or
  • provide multiple implementations in different files, where the build system ensures the correct file for the current compiler is chosen

You can define your own function in terms of the corresponding builtin, For example:

#if defined(_MSC_VER)
#define POPCOUNT(x) __popcnt(x)
#elif defined(GNUG)
#define POPCOUNT(x) __builtin_popcount(x)
#endif

Then in your code use POPCOUNT() and the correct builtin is used.

Licensed under: CC-BY-SA with attribution
scroll top