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.t
将vn
的偶数元素(从零开始)打包到vd
的低半部分,vm
的偶数元素进入上半场。 (uzp2
对奇数元素做同样的事情。)所以如果 v1
是零,那么你在结果的低半部分得到零,而 v0
的第 0 个和第 2 个元素在上半部分,即您的 a
和 b
.
请注意,如果您多次执行此操作,则 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]
很便宜。
是否有类似于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.t
将vn
的偶数元素(从零开始)打包到vd
的低半部分,vm
的偶数元素进入上半场。 (uzp2
对奇数元素做同样的事情。)所以如果 v1
是零,那么你在结果的低半部分得到零,而 v0
的第 0 个和第 2 个元素在上半部分,即您的 a
和 b
.
请注意,如果您多次执行此操作,则 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]
很便宜。