ARM CPU的 intrinsics指令集 - svsel_u32

在 ARM SVE(Scalable Vector Extension) intrinsics 指令集中,svsel_u32 是带选择掩码的向量选择指令,用于根据掩码(predicate)从两个无符号 32 位整数(uint32_t)向量中选择元素,生成新的向量。其核心功能是实现 “向量级的三目运算符”,根据掩码选择对应位置的元素来源(第一个向量或第二个向量)。

基本语法

svuint32_t svsel_u32(
    svbool_t pg,               // 选择掩码:决定元素来源
    svuint32_t then_vec,       // 当掩码位为1时,选择该向量的元素
    svuint32_t else_vec        // 当掩码位为0时,选择该向量的元素
);

参数说明

  1. pg(选择掩码)
    类型为 svbool_t 的掩码向量,每个 bit 决定对应位置的元素来源:
    • 若掩码位为1,则结果向量的对应位置选择 then_vec 的元素;
    • 若掩码位为0,则结果向量的对应位置选择 else_vec 的元素。
  2. then_vec 和 else_vec
    均为 svuint32_t 类型的 SVE 向量,存储待选择的无符号 32 位整数元素。两个向量的长度由当前硬件的 SVE 向量宽度决定(如 256 位向量可容纳 8 个 32 位元素)。

核心功能

svsel_u32 的核心是根据掩码对两个向量进行元素级选择,生成新的向量。它类似于标量中的三目运算符 (condition) ? a : b,但作用于整个向量的每个元素,实现并行选择。

 

  • 示例:
    假设向量长度为 4,
    • 掩码 pg = [1, 0, 1, 0]
    • then_vec = [10, 20, 30, 40]
    • else_vec = [100, 200, 300, 400]
      则选择结果为:
    • 第 0 位:掩码 1 → 选 then_vec[0] = 10
    • 第 1 位:掩码 0 → 选 else_vec[1] = 200
    • 第 2 位:掩码 1 → 选 then_vec[2] = 30
    • 第 3 位:掩码 0 → 选 else_vec[3] = 400
      最终结果向量为 [10, 200, 30, 400]

使用场景与示例

svsel_u32 常用于需要根据条件批量选择元素的场景,如数据替换、条件赋值、异常值处理等。以下是一个实际应用示例:

场景:将数组中大于阈值的元素保留原值,小于等于阈值的元素替换为 0(即 “截断” 低阈值元素)。

#include <arm_sve.h>
#include <stdint.h>

// 处理数组:元素>threshold则保留,否则置0
void threshold_filter(uint32_t* dst, const uint32_t* src, size_t len, uint32_t threshold) {
    size_t i = 0;
    svcount_t vl = svcntw(); // 获取32位元素的向量长度(如8)
    svbool_t pg = svwhilelt_b32(i, len); // 初始掩码:标记有效元素
    
    // 广播阈值到向量(用于比较)
    svuint32_t threshold_vec = svdup_u32(threshold);
    
    while (svptest_any(svptrue_b32(), pg)) {
        // 加载源向量
        svuint32_t src_vec = svld1_u32(pg, src + i);
        
        // 比较:src_vec[i] > threshold_vec[i],生成选择掩码
        svbool_t greater_mask = svcmpgt_u32(pg, src_vec, threshold_vec);
        
        // 生成全0向量(用于替换小于等于阈值的元素)
        svuint32_t zero_vec = svdup_u32(0);
        
        // 选择:greater_mask为1时保留src_vec元素,否则选择0
        svuint32_t dst_vec = svsel_u32(greater_mask, src_vec, zero_vec);
        
        // 存储结果
        svst1_u32(pg, dst + i, dst_vec);
        
        // 更新循环变量
        i += vl;
        pg = svwhilelt_b32(i, len);
    }
}

// 调用示例:
// uint32_t src[] = {15, 5, 25, 8, 30, 12};
// uint32_t dst[6];
// threshold_filter(dst, src, 6, 10); // 结果:[15, 0, 25, 0, 30, 12]

进阶用法:结合多个掩码的复杂选择

若需根据多个条件进行选择,可通过组合掩码实现。例如,将数组元素按范围分为 “低、中、高” 三档并替换为对应值:

// 将元素分为三档:<10→0,10~20→1,>20→2
void categorize(uint32_t* dst, const uint32_t* src, size_t len) {
    // ...(循环框架同上)
    svuint32_t src_vec = svld1_u32(pg, src + i);
    
    // 生成两个条件掩码
    svbool_t lt10 = svcmplt_u32(pg, src_vec, svdup_u32(10)); // <10
    svbool_t gt20 = svcmpgt_u32(pg, src_vec, svdup_u32(20)); // >20
    
    // 先按>20选择2或中间值(1)
    svuint32_t temp = svsel_u32(gt20, svdup_u32(2), svdup_u32(1));
    // 再按<10选择0或temp(即1或2)
    svuint32_t dst_vec = svsel_u32(lt10, svdup_u32(0), temp);
    // ...(存储结果)
}

关键注意事项

  1. 掩码作用范围:pg 掩码仅决定选择逻辑是否生效,而选择本身由 svsel_u32 的第一个参数(选择掩码)控制。在多数场景中,选择掩码与 pg 掩码可相同(如示例中用比较结果直接作为选择掩码)。
  2. 向量长度匹配:then_vecelse_vec 和掩码的长度必须一致(由当前硬件 SVE 宽度决定),否则会导致未定义行为。
  3. 性能优势:svsel_u32 是单条向量指令,比标量循环中用 if-else 逐个选择效率高得多,尤其适合大规模数据的条件替换场景。
  4. 与条件移动的区别:svsel_u32 是 “选择” 而非 “条件移动”,它不修改原始向量,而是生成新的向量,因此不会破坏输入数据。

总结

svsel_u32 是 SVE 中用于向量级元素选择的核心指令,通过掩码从两个向量中选择元素,实现并行的条件赋值逻辑。它在数据过滤、范围划分、异常处理等场景中应用广泛,是利用 SVE 向量并行性提升条件操作效率的重要工具。
 
 
posted @ 2025-08-13 17:30  lvmxh  阅读(18)  评论(0)    收藏  举报