当前位置: 首页 > news >正文

ARM intrinsics 指令集介绍 - Gather/Scatter

在 ARM SVE(Scalable Vector Extension) intrinsics 指令集中,svld1_gather_s32index_f32 和 svst1_scatter_s32index_f32 是用于非连续内存访问的向量加载 / 存储指令,分别实现 “聚集加载(gather)” 和 “散列存储(scatter)” 操作。它们通过 32 位整数索引(index)定位内存地址,适用于处理稀疏数据或非连续数组元素的场景(如机器学习中的嵌入层、稀疏矩阵运算等)。

1. svld1_gather_s32index_f32:聚集加载指令

功能

根据一组 32 位整数索引(相对于基地址的偏移量),从内存中非连续地加载单精度浮点数(float32) 到向量中,仅加载掩码(predicate)为1的元素位置。

语法

svfloat32_t svld1_gather_s32index_f32(svbool_t pg,               // 掩码:指示哪些元素需要加载const float32_t *base,     // 基地址:索引的参考起点svint32_t indices          // 32位整数索引向量:每个元素是相对于base的偏移量(单位:字节)
);

参数说明

  • pgsvbool_t 类型的掩码,只有掩码位为1的位置会执行加载操作,其他位置结果未定义(通常用0填充)。
  • base:内存基地址,所有索引均相对于该地址计算实际访问地址(实际地址 = base + indices[i])。
  • indices:SVE 向量,每个元素是 32 位整数,表示相对于base的字节偏移量(需注意内存对齐,避免未定义行为)。

返回值

svfloat32_t 类型的向量,其中掩码pg1的位置存储从base + indices[i]加载的float32值,其他位置无效(通常忽略)。

2. svst1_scatter_s32index_f32:散列存储指令

功能

将向量中的单精度浮点数(float32)非连续地存储到内存,存储位置由一组 32 位整数索引(相对于基地址的偏移量)指定,仅存储掩码(predicate)为1的元素。

语法

void svst1_scatter_s32index_f32(svbool_t pg,               // 掩码:指示哪些元素需要存储float32_t *base,           // 基地址:索引的参考起点svint32_t indices,         // 32位整数索引向量:每个元素是相对于base的偏移量(单位:字节)svfloat32_t data           // 待存储的单精度浮点数向量
);

参数说明

  • pgsvbool_t 类型的掩码,只有掩码位为1的位置会执行存储操作。
  • base:内存基地址,实际存储地址为base + indices[i]
  • indices:SVE 向量,每个元素是 32 位整数,表示相对于base的字节偏移量。
  • datasvfloat32_t 类型的向量,包含待存储的浮点数数据。

使用场景与示例

假设需要从一个稀疏数组中加载指定索引的元素并计算平均值,再将结果存储到另一个稀疏数组的指定位置。传统标量实现可能需要循环逐个访问,而 SVE 的 gather/scatter 指令可一次性处理多个元素:
#include <arm_sve.h>
#include <stdint.h>// 从稀疏数组加载元素并计算平均值,再存储到目标稀疏数组
void sparse_operation(const float* src, const int32_t* src_indices, float* dst, const int32_t* dst_indices, int count) {int i = 0;// 生成初始掩码:i < count 时置位(适配SVE向量长度)svbool_t pg = svwhilelt_b32(i, count);while (svptest_any(svptrue_b32(), pg)) {// 1. 加载当前批次的索引(src_indices[i], src_indices[i+1], ...)svint32_t src_idx = svld1_s32(pg, src_indices + i);// 2. 聚集加载:从src[src_indices[i]]加载float32元素svfloat32_t src_data = svld1_gather_s32index_f32(pg, src, src_idx);// 3. 计算平均值(示例:简单累加后除以向量长度)float sum = svaddv_f32(pg, src_data);int num_elements = svcntw(); // 获取32位元素的向量长度float avg = sum / num_elements;svfloat32_t avg_vec = svdup_f32(avg); // 广播平均值到向量// 4. 加载目标索引(dst_indices[i], ...)svint32_t dst_idx = svld1_s32(pg, dst_indices + i);// 5. 散列存储:将平均值存储到dst[dst_indices[i]]
        svst1_scatter_s32index_f32(pg, dst, dst_idx, avg_vec);// 更新循环变量和掩码i += num_elements;pg = svwhilelt_b32(i, count);}
}

关键注意事项

  1. 内存安全:
    • 索引indices必须指向有效内存地址(base + indices[i] 不能越界),否则会导致未定义行为(如崩溃)。
    • 无需严格对齐(与普通svld1不同),但对齐访问可提升性能。
  2. 掩码作用:
    • 掩码pg决定了哪些元素参与加载 / 存储,适用于处理长度非向量倍数的场景(如count不是svcntw()的整数倍)。
  3. 性能考量:
    • Gather/Scatter 指令适用于非连续访问场景,但性能通常低于连续内存访问(如svld1/svst1),应避免在连续数据上滥用。
    • SVE 的向量长度可伸缩(如 128 位、256 位),指令会自动适配硬件,无需手动调整向量长度。

总结

  • svld1_gather_s32index_f32:通过 32 位索引从非连续内存位置加载 float32 数据到向量,适合稀疏数据读取。
  • svst1_scatter_s32index_f32:通过 32 位索引将向量中的 float32 数据存储到非连续内存位置,适合稀疏数据写入。

 

两者是处理非连续内存访问的核心指令,在稀疏计算、机器学习等场景中可显著提升效率,充分发挥 SVE 的向量处理能力。
http://www.sczhlp.com/news/11022/

相关文章:

  • 召回场景- PforDelta Unpack 算子
  • 【PostgreSQL17】6 条件表达式
  • umask 权限掩码
  • 基于视觉推理的Img2LaTeX转换技术突破
  • docker常见命令汇总
  • mysql5.7 版本 only_full_group_by 导致原 sql 语句报错
  • chattr命令
  • Mysql连接数过多,导致连接不上数据库
  • inode与block详解
  • ARM intrinsics 指令集介绍 - svwhilelt_b32
  • localhost 上的 mysql 无法连接
  • 【日记】我真没想过还能这样整人(835 字)
  • localhost/IP 地址连接不上
  • Fluent Bit 日志合并正则表达式(下) - 实践
  • 欧洲蘑菇巨头 Okechamp 如何用 6 周升级物流调度系统?
  • redis-7.0.15 安装配置
  • 【渲染流水线】[几何阶段]-[曲面细分]以UnityURP为例
  • 打编程之026:职员时序安排模型
  • Homebrew构建来源探秘 - 实现可验证的软件供应链安全
  • 【完结22章】LLM应用全流程开发 全新技术+多案例实战+私有化部署
  • 2025.8.9 CSP-S模拟赛31
  • Luogu P2397 yyy loves Maths VI (mode) / Leetcode 229 多数元素 II 题解 [ 橙 ] [ 摩尔投票 ]
  • OMV
  • 参考第三方链接
  • GAS_Aura-Replication Mode
  • Gitee企业版效能度量升级:用数据“透视镜”驱动研发效能革命
  • C# Web开发教程(二)
  • vue-router 加载动态路由不能动态引入解决方案
  • Daily Probs 2
  • 深入解析:B-树与B+树