我有以下代码将位变成一个字节。
__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技巧。
答案 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;
}