aarch64 xtn2 清除下半部分

aarch64 xtn2 clearing lower half

是否有类似于xtn2但实际上清除了下半部分而不是保持原样的操作?我有一个 128 位向量 v0,其视图 4s{a,x,b,y},x 和 y 无关。我想获得{0,0,a,b}。如果我这样做

xtn2     v0.4s, v0.2d
mov      v0.d[0], xzr

我得到了我想要的结果。有没有办法用一条指令或以更有效的方式来做到这一点?

(感谢原始建议的 fuz)

如果你可以腾出另一个寄存器来保持零,比如v1,那么你可以做到

uzp1 v0.4s, v1.4s, v0.4s

通常uzp1 vd.t, vn.t, vm.tvn的偶数元素(从零开始)打包到vd的低半部分,vm的偶数元素进入上半场。 (uzp2 对奇数元素做同样的事情。)所以如果 v1 是零,那么你在结果的低半部分得到零,而 v0 的第 0 个和第 2 个元素在上半部分,即您的 ab.

请注意,如果您多次执行此操作,则 v1 可以初始化为零一次并在整个代码中使用,因为它不是由该指令编写的。 (如果 ARM 提供了一个零 SIMD 寄存器 vzr 会更容易。)如果我们忽略它的开销,那么这是非常有效的。例如查看 Cortex A-72 时序(因为我碰巧手边有它的优化指南),uzp1 是最便宜的 SIMD 指令,3 个周期延迟和每个周期 2 个周期的吞吐量(它可以执行两个 SIMD 算术流水线)。

原始版本的一个性能说明是在 SIMD 和通用寄存器之间移动非常昂贵,应尽可能避免。在 Cortex A-72 上,mov v*, x*ins 的特殊情况别名)是 8 个周期延迟和每个周期 1 个吞吐量,它需要加载管道(其中只有一个)作为以及两个 SIMD 算术流水线之一。可以想象 xzr 可能有一个特例,但没有提到 Cortex A-72。

不幸的是,据我所知,没有直接的替代方法可以将 SIMD 寄存器中的一个元素置零; movi 将立即数写入所有元素,而不仅仅是其中的一些元素。因此,即使您坚持使用 xtn2,您也可能希望在另一个寄存器中保留零,因为 ins v0.d[0], v1.d[0] 很便宜。