How does the compiler implement bit field arithmetics?

╄→гoц情女王★ 提交于 2019-12-11 01:49:49

问题


When asking a question on how to do wrapped N bit signed subtraction I got the following answer:

template<int bits>
int
sub_wrap( int v, int s )
{
    struct Bits { signed int r: bits; } tmp;
    tmp.r = v - s;
    return tmp.r;
}

That's neat and all, but how will a compiler implement this? From this question I gather that accessing bit fields is more or less the same as doing it by hand, but what about when combined with arithmetic as in this example? Would it be as fast as a good manual bit-twiddling approach?

An answer for "gcc" in the role of "a compiler" would be great if anyone wants to get specific. I've tried reading the generated assembly, but it is currently beyond me.


回答1:


As written in the other question, unsigned wrapping math can be done as:

int tmp = (a - b) & 0xFFF;  /* 12 bit mask.  */

Writing to a (12bit) bitfield will do exactly that, signed or unsigned. The only difference is that you might get a warning message from the compiler.

For reading though, you need to do something a bit different.

For unsigned maths, it's enough to do this:

int result = tmp;  /* whatever bit count, we know tmp contains nothing else.  */

or

int result = tmp & 0xFFF;  /* 12bit, again, if we have other junk in tmp.  */

For signed maths, the extra magic is the sign-extend:

int result = (tmp << (32-12)) >> (32-12); /* asssuming 32bit int, and 12bit value. */

All that does is replicate the top bit of the bitfield (bit 11) across the wider int.

This is exactly what the compiler does for bitfields. Whether you code them by hand or as bitfields is up to you, but just make sure you get the magic numbers right.

(I have not read the standard, but I suspect that relying on bitfields to do the right thing on overflow might not be safe?)




回答2:


The compiler has knowledge about the size and exact position of r in your example. Suppose it is like

[xxxxrrrr]

Then

tmp.r = X;

could e.g. be expanded to (the b-suffix indicating binary literals, & is bitwise and, | is bitwise or)

tmp = (tmp & 11110000b)   // <-- get the remainder which is not tmp.r
    | (X   & 00001111b);  // <-- put X into tmp.r and filter away unwanted bits

Imagine your layout is

[xxrrrrxx]   // 4 bits, 2 left-shifts

the expansion could be

tmp = (tmp    & 11000011b)   // <-- get the remainder which is not tmp.r
    | ((X<<2) & 00111100b);  // <-- filter 4 relevant bits, then shift left 2

How X actually looks like, whether a complex formulation or just a literal, is actually irrelevant.

If your architecture does not support such bitwise operations, there are still multiplications and divisions by power of two to simulate shifting, and probably these can also be used to filter out unwanted bits.



来源:https://stackoverflow.com/questions/8313265/how-does-the-compiler-implement-bit-field-arithmetics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!