位操作/数值统计类 warp 级内置函数,主要用于快速处理整数的二进制位信息,我会按功能分类整理,并说明每个函数的用途和示例,方便你理解和使用。
一、核心分类:与__popc同类的内置函数
__popc 的全称是 Population Count(人口计数),核心作用是统计整数二进制中 1 的个数。同类函数主要分为以下几类,均支持 int/unsigned int(32位)和 long long/unsigned long long(64位,函数名后缀加 ll):
| 函数名 | 中文名称 | 核心作用 | 示例(输入→输出) |
|---|---|---|---|
__popc(x) |
位计数(1的个数) | 统计x的二进制中1的位数 |
__popc(0b1010) → 2 |
__popcll(x) |
64位位计数 | 统计64位整数x的二进制中1的位数 |
__popcll(0x11LL) → 2 |
__clz(x) |
前导零计数 | 统计x的二进制中最高位1左侧的0的个数(32位) | __clz(0b1010) → 28(32位) |
__clzll(x) |
64位前导零计数 | 统计64位整数x的二进制中最高位1左侧的0的个数 | __clzll(0b1010LL) → 60 |
__ffs(x) |
第一个1的位置 | 查找x的二进制中最低位1的位置(从1开始计数,x=0返回0) | __ffs(0b1010) → 2 |
__ffsll(x) |
64位第一个1的位置 | 64位整数版本的__ffs | __ffsll(0x100LL) → 9 |
__brev(x) |
位反转 | 将x的二进制位按位反转(32位) | __brev(0b1010) → 0b0101<<28 |
__brevll(x) |
64位位反转 | 64位整数版本的__brev | - |
__byte_perm(x,y,mask) |
字节置换 | 按mask规则重新排列x和y的字节(常用于快速字节序转换) | 见下方示例 |
__funnelshift_l(x,y,s) |
漏斗移位(左) | 将x和y拼接后左移s位,返回低32位 | - |
__funnelshift_r(x,y,s) |
漏斗移位(右) | 将x和y拼接后右移s位,返回低32位 | - |
二、关键函数详解与示例
1. 前导零计数:__clz(最常用的补充函数)
__clz = Count Leading Zeros,统计最高位1左边的0的数量(32位整数总位数32,所以结果范围0~31)。
- 示例:
// 0b1010 的32位完整二进制:00000000 00000000 00000000 00001010 unsigned int x = 0b1010; int res = __clz(x); // res = 28(最高位1在第3位,左边有28个0) printf("__clz(0b1010) = %d\n", res); // 输出28
- 典型用途:快速计算整数的二进制位数(
32 - __clz(x))、归一化数值等。
2. 第一个1的位置:__ffs
__ffs = Find First Set,返回最低位1的位置(从1开始计数,若x=0则返回0)。
- 示例:
unsigned int x = 0b1010; // 二进制最低位1在第2位 int res = __ffs(x); // res = 2 printf("__ffs(0b1010) = %d\n", res); // 输出2 x = 0b1000; res = __ffs(x); // res = 4(最低位1在第4位)
- 典型用途:快速定位最低有效位、位掩码拆分等。
3. 位反转:__brev
__brev = Bit Reverse,将32位整数的二进制位完全反转(第0位和第31位交换,第1位和第30位交换...)。
- 示例:
unsigned int x = 0b1010; // 低4位是1010,高位全0 unsigned int res = __brev(x); // 反转后:低28位是0,高4位是0101 → 0x01010000(十进制1050624) printf("__brev(0b1010) = 0x%08x\n", res); // 输出0x01010000
- 典型用途:硬件接口数据格式转换、位序调整等。
4. 字节置换:__byte_perm
__byte_perm(x, y, mask) = Byte Permute,按mask的4个半字节(nibble)指定的索引,从x(字节0-3)和y(字节4-7)中取字节拼接成新整数。
- 示例:
unsigned int x = 0x11223344; // 字节0:44, 字节1:33, 字节2:22, 字节3:11 unsigned int y = 0x55667788; // 字节4:88, 字节5:77, 字节6:66, 字节7:55 // mask=0x3210 → 取x的字节3、2、1、0 → 0x11223344 unsigned int res1 = __byte_perm(x, y, 0x3210); // mask=0x7654 → 取y的字节7、6、5、4 → 0x55667788 unsigned int res2 = __byte_perm(x, y, 0x7654); // mask=0x0415 → 取x字节0、y字节4、x字节1、y字节5 → 0x33774488 unsigned int res3 = __byte_perm(x, y, 0x0415);
- 典型用途:快速转换大小端、重组字节数据(如RGB→BGR)。
三、warp级扩展:与__ballot_sync结合的函数
除了单线程位操作,还有一批warp级位操作函数(和你之前用的__ballot_sync同源),也是高频使用的“同类”函数:
| 函数名 | 作用 |
|---|---|
__ballot_sync(mask, p) |
生成warp中满足条件p的线程掩码(你已熟悉) |
__any_sync(mask, p) |
判断warp中是否有任意线程满足条件p(返回1/0) |
__all_sync(mask, p) |
判断warp中是否所有线程都满足条件p(返回1/0) |
__shfl_sync(mask, val, lane) |
从指定lane线程获取val值(warp内线程通信) |
__shfl_down_sync(mask, val, delta) |
从当前lane+delta线程获取val值 |
示例:__any_sync 和 __all_sync
__global__ void test_warp_func() {
int lane = threadIdx.x & 31;
int predicate = (lane % 2) == 0; // 偶数lane为1
// 判断是否有任意线程满足predicate=1
int any = __any_sync(0xffffffff, predicate);
// 判断是否所有线程都满足predicate=1
int all = __all_sync(0xffffffff, predicate);
if (lane == 0) {
printf("any: %d, all: %d\n", any, all); // 输出any:1, all:0
}
}四、使用注意事项
- 所有这些函数都是设备端内置函数(
__device__),只能在核函数/设备函数中使用; - 32位函数(如
__popc)参数为int/unsigned int,64位函数(如__popcll)参数为long long/unsigned long long,混用会导致编译错误; - 这些函数是硬件指令级实现,执行速度极快(单周期),远快于手动编写循环统计位信息。
总结
- 和
__popc最直接的同类函数:__clz(前导零)、__ffs(第一个1的位置)、__brev(位反转),分别用于统计0的位置、1的位置、位序反转; - 扩展的warp级位操作函数:
__any_sync、__all_sync、__shfl_sync,常用于warp内线程协作; - 所有函数均为硬件原生支持,优先使用这些内置函数而非手动实现,能大幅提升CUDA程序性能。