Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

检查 ARM NEON 寄存器是否为零

Posted on 2025-01-20

您的手机可能运行在 64 位 ARM 处理器上。这些处理器无处不在:它们为 Nintendo Switch 提供动力,为 Amazon AWS 和 Microsoft Azure 的云服务器提供动力,为快速笔记本电脑提供动力,等等。 ARM 处理器具有称为 ARM NEON 的特殊强大指令。它们提供了一种称为单指令多数据 (SIMD) 的特定类型的并行性。例如,您可以使用一条指令将 16 个值与其他 16 个值相加。

使用称为内在函数的特殊函数,您可以编写一个 C 函数,将两个数组中的值相加并将结果写入第三个数组:

 #包含< arm_neon.h >  无效向量_int_add ( int32_t * a , int32_t * b , int32_t *结果, int len ) { 整数i = 0 ;  // 一次循环处理 4 个元素,直到我们不能再处理为止 for ( ; i < len - 3 ; i + = 4 ) { // 将 'a' 中的 4 个 32 位整数加载到 NEON 寄存器中  int32x4_t vec_a = vld1q_s32 ( a + i ) ;          // 将 'b' 中的 4 个 32 位整数加载到另一个 NEON 寄存器中  int32x4_t vec_b = vld1q_s32 ( b + i ) ;          // 执行向量加法  int32x4_t vec_res = vaddq_s32 ( vec_a , vec_b ) ;          // 将结果存回内存  vst1q_s32 (结果+ i , vec_res ) ; }  // 处理所有不能被 4 整除的剩余元素 for ( ; i < len ; i ++ ) {  结果[ i ] = a [ i ] + b [ i ] ; } }

在此代码中, int32x4_t 类型表示四个 32 位整数。您可以类似地将 16 个 8 位整数表示为 int8x16_t 等等。

内部函数vld1q_s32 和 vst1q_s32 加载和存储 16 字节数据。内部函数 vaddq_s32 进行求和。

一个简单但看似棘手的任务是确定寄存器是否仅包含零。这在算法中经常出现。不幸的是,与 Intel/AMD 指令集(AVX2、AVX-512)不同,ARM NEON 中没有相应的指令。

ARM NEON 有许多不同的有效方法,但它们都需要多条指令。为了简单起见,我假设您正在接收 16 个 8 位整数 (uint8x16_t)。实际上,您可以将 16 个字节重新解释为您喜欢的任何内容(例如,从 uint8x16_t 到int32x4_t),而无需任何成本。

我最喜欢的方法是利用 ARM NEON 可以计算 SIMD 寄存器中的最大值或最小值这一事实:内在 vmaxvq_u32(对应于指令 umaxv)计算向量所有元素的最大值并将其作为标量返回(不是向量)。根据您的数据类型,还有其他变体,例如 vmaxvq_u8,但 vmaxvq_u32 往往是性能最高的方法。代码可能如下所示:

 int veq_non_zero_max ( uint8x16_t v ) { 返回vmaxvq_u32 ( vreinterpretq_u32_u8 ( v ) ) ! = 0 ; } 

它编译为三个基本指令:umaxv、fmov 和比较 (cmp)。我们需要 fmov 指令或等效指令将数据从 SIMD 寄存器移动到标量寄存器。整体代码并不好:umaxv 至少有三个周期的延迟,fmov 也是如此。

有一种更复杂但可能更有用的基于缩小偏移的方法。 vshrn_n_u16 内在函数(对应于 shrn 指令)将 8 个 16 位整数右移 4 位,并将结果缩小到 8 位。结果是一个 64 位值,其中包含原始 16 字节寄存器中每个字节的 4 个最高有效位。我们可以检查寄存器是否为零,如下所示:

 int veq_non_zero_narrow ( uint8x16_t v ) { 返回vget_lane_u64 ( vshrn_n_u16 ( vreinterpretq_u16_u8 ( v ) , 4 ) , 0 ) ! = 0 ; }

它编译为三个指令:shrn、fmov 和比较。速度并没有更快。

罗伯特·克劳塞克向我指出了一种更快的方法。我们可以利用 SIMD 寄存器也用作浮点寄存器的事实,而不是将数据从 SIMD 寄存器移动到标量寄存器。因此我们可以将数据保留在原处。它适用于目前提出的两种技术( vmaxvq_u32 和vshrn_n_u16)。这是 vshrn_n_u16 的版本:

 int veq_non_zero_float ( uint8x16_t v ) {  uint8x8_t 缩小= vshrn_n_u16 ( vreinterpretq_u16_u8 ( v ) , 4 ) ; return ( vdupd_lane_f64 ( vreinterpret_f64_u16 (缩小) , 0 ) ! = 0.0 ) ; }

这仅编译为两条指令:shrn 和 fcmp。因此速度要快得多。

那么为什么不使用浮点方法呢?

  • 我们有两个不同的值 0.0 和 -0.0,它们被认为是相等的。
  • 浮点标准包括称为次正常值的微小值,在某些配置下可以将其视为等于零。
  • 我们可能会生成一个信号 NaN 值,这可能会导致发出信号。

如果你小心的话,你可以避免所有这些问题,但这并不能使它成为一个好的通用解决方案。

较新的 64 位 ARM 处理器具有另一个指令集系列:SVE 或标量向量扩展。据我所知,它不能直接与 ARM NEON 互操作……但它确实有一个由以下代码生成的专用指令(cmpeq):

布尔check_all_zeros ( svbool_t 掩码, svint8_t vec ) {  svbool_t cmp = svcmpeq_n_s8 (掩码, vec , 0 ) ; 返回svptest_any ( pg , cmp ) ; }

SVE 代码更加复杂:它需要一个掩码来指示哪些值是“活动的”。要将所有值设置为活动状态,您可能需要生成一个真实掩码:例如,像“svbool_t pg = svptrue_b8()”一样。然而,它更强大:您可以检查所有活动值是否为零……

不幸的是,SVE 尚未普及。

原文: https://lemire.me/blog/2025/01/20/checking-whether-an-arm-neon-register-is-zero/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme