如何将每一位变成一个字节

时间:2019-01-28 09:15:33

标签: c++ cuda bit-manipulation

我有以下代码将位变成一个字节。

__device__ UINT64 bitToByte(const UINT8 input) {
    UINT64 b = ((0x8040201008040201ULL * input) >> 7) & 0x0101010101010101ULL; 
    //reverse the byte order <<-- this step is missing
    return b;
}

但是,字节顺序错误,字节顺序相反。 在CPU上,我可以简单地通过bswap reg,reg来解决此问题,但是在GPU上该怎么办?

或者,我可以使用类似的技巧来使字节正确摆放,即,最高有效位进入最高有效字节,这样我就不需要bswap技巧。

3 个答案:

答案 0 :(得分:3)

感谢@tera,这是答案:

//Expand every bit into a byte
__device__ static UINT64 Add012(const UINT8 input) {
    const UINT64 b = ((0x8040201008040201ULL * input) >> 7) & 0x0101010101010101ULL; //extract every bit into a byte
    //unfortunatly this returns the wrong byte order
    UINT32* const b2 = (UINT32*)&b;
    UINT64 Result;
    UINT32* const Result2 = (UINT32*)&Result;
    Result2[0] = __byte_perm(b2[0]/*LSB*/, b2[1], 0x4567);  //swap the bytes around, the MSB's go into the LSB in reverse order
    Result2[1] = __byte_perm(b2[0]/*LSB*/, b2[1], 0x0123);  //and the LSB -> MSB reversed.
    return Result;
}

__byte_perm replaces the bswap指令。

或者可以使用__brev (bit-reverse) intrinsic反转输入:

//Expand every bit into a byte
__device__ static UINT64 Add012(const UINT8 input) {
    const UINT32 reversed = (__brev(input) >> 24);
    return ((0x8040201008040201ULL * reversed) >> 7) & 0x0101010101010101ULL; //extract every bit into a byte
}

第二个版本看起来更容易。

答案 1 :(得分:2)

您可以颠倒input,而不用颠倒结果,here中介绍了任何技巧。例如,使用this answer

static UINT8 lookup[16] = {
    0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
    0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };

UINT8 reverse(UINT8 n) {
    return (lookup[n & 0xF] << 4) | lookup[n >> 4];
}

__device__ UINT64 bitToByte(const UINT8 input) {
    UINT64 b = ((0x8040201008040201ULL * reverse(input)) >> 7) & 0x0101010101010101ULL; 
    return b;
}

答案 2 :(得分:2)

要反转字节顺序,可以用相同的技巧来完成位提取,但是要交换在乘法中执行移位的系数。但是,为避免乘法冲突,对于偶数和奇数位,必须分两步完成。这样,两个字节可以自由保存每次乘法的结果,这足以确保结果的完整性。

__device__ UINT64 bitToByte(const UINT8 input) {
  UINT64 b = ( ((0x0002000800200080ULL * input) >> 7) & 0x0001000100010001ULL) 
          |  ( ((0x0100040010004000ULL * input) >> 7) & 0x0100010001000100ULL);

    return b;
}

正如评论中所指出的那样,为了进行优化,可以将这些移位因素分解。

__device__ UINT64 bitToByte(const UINT8 input) {
  UINT64 b =  ( ((0x0002000800200080ULL * input) & 0x0080008000800080ULL) 
              | ((0x0100040010004000ULL * input) & 0x8000800080008000ULL) )
                >> 7 ;
    return b;
}