Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-time checking if right shift is arithmetic on signed types

I am wondering what is the most portable way of checking whether right shift is arithmetic when operating for on signed types (e.g. whether -2 >> 1 is -1) at compile-time.

My idea is to check this somehow on compile time and be able to detect this, so I can compile different versions of the function (depending whether the operator >> is really arithmetic shift or not).

By reading the topic Verifying that C / C++ signed right shift is arithmetic for a particular compiler? I came to the idea to initialize a flag

static const bool is_arithmetic_rs = (((signed int)-1)>>1) == ((signed int)-1));

and to test it at run-time like this:

if (is_arithmetic_rs) {
  // some fast algorithm using arithmetic right shifts (using >> operator)
} else {
  // the same algorithm without arithmetic right shifts (much slower)
}

However, I would like to avoid this branching if possible every time. For simplicity, let's suppose I want to implement a portable arithmetic right shift; if I had to check this every time a function is called, this would be a huge performance impact, so I would like to do it at compile time, if possible.

If there exist no portable way of doing this check, is there a way to do this by checking on the best-effort basis, like checking with ifdefs for a specific compiler/platform?

like image 846
eold Avatar asked Feb 25 '11 22:02

eold


4 Answers

The best way to perform such checks is what e.g. GNU autotools do:

  • Compile a small program on your target platform and test what happens

  • Set an appropriate #define in a header file

  • Include that header file in your source files

  • Optionally, use appropriately defined macros so that you don't clutter your code with #ifdef directives for every little thing.

  • Compile your main project

That way you avoid having to create tables with the supported features and the various quirks of each hardware platform and operating system in the wild - let alone their combinations. If you do not build your code on your target, however, you will have to replace the first step with a pre-supplied table/list of features for your target.

You should probably have a look at widely used build systems such as GNU autotools or CMake, in order to reuse existing macros and platform-specific information and avoid having to create your own and therefore reinvent the wheel.

BTW, any decent compiler these days should optimise-out simple tests with constant expressions, so using a runtime test where necessary - perhaps through a macro - should not hurt performance too much. You should test and profile your code to find out.

like image 199
thkala Avatar answered Sep 22 '22 23:09

thkala


The branch could be avoided by using a preprocessing-time test

#if ((-1)>>1) == (-1))
...
#else
...
#endif
like image 36
Giuseppe Guerrini Avatar answered Sep 20 '22 23:09

Giuseppe Guerrini


Really more of a comment than answer (but apparently I'm not reputable)

A couple of the answers here use pre-processor checks like

#if ((-1)>>1) == (-1))

Personally, I wouldn't trust the pre-processor to tell me what kind of code the compiler generates.

like image 30
user1174627 Avatar answered Sep 22 '22 23:09

user1174627


Have you actually verified that your compiler doesn't optimize division into arithmetic shift when it's available?

Otherwise I think you can use templates.

template <bool B>
void do_work();

template <>
void do_work<true>()
{
    // Do stuff with H/W.
}

template <>
void do_work<false>()
{
    // Do slow stuff with S/W.
}

do_work<(-2 >> 1) == -1>();

Then make it prettier to use with an inline function:

inline real_do_work()
{
    do_work<(-2 >> 1) == -1>();
}
like image 44
Mark B Avatar answered Sep 22 '22 23:09

Mark B