在ARM架构中,SIMD(Single Instruction Multiple Data)技术通过单条指令同时处理多个数据元素来实现并行计算。这种技术特别适合处理多媒体、信号处理等需要大量数据并行运算的场景。AdvSIMD作为ARM的SIMD指令扩展,提供了丰富的向量运算指令,其中SQDMULH和SQDMULL就是两个典型的带符号饱和双倍乘法指令。
SIMD指令的核心优势在于它能够:
SQDMULH(Signed Saturating Doubling Multiply returning High half)指令执行以下操作:
数学表达式可以表示为:
code复制result = saturate((2 * a * b) >> esize)
其中esize是元素大小(16位或32位)。
SQDMULH有两种编码形式:标量(Scalar)和向量(Vector)。
code复制31 30 29 28|27 26 25 24|23 22 21 20|19 18 17 16|15 14 13 12|11 10 9 8|7 6 5 4|3 2 1 0
0 1 0 1 |1 1 1 1 |size L M Rm|1 1 0 0 |H 0 Rn |Rd |U op
code复制31 30 29 28|27 26 25 24|23 22 21 20|19 18 17 16|15 14 13 12|11 10 9 8|7 6 5 4|3 2 1 0
0 Q 0 0 |1 1 1 1 |size L M Rm|1 1 0 0 |H 0 Rn |Rd |U op
关键字段说明:
假设我们要计算两个16位向量的高半部分乘积:
assembly复制// 初始化寄存器
mov w0, 0x40004000 // 向量[0x4000, 0x4000]
mov w1, 0x20002000 // 向量[0x2000, 0x2000]
dup v0.4h, w0 // v0 = [0x4000,0x4000,0x4000,0x4000]
dup v1.4h, w1 // v1 = [0x2000,0x2000,0x2000,0x2000]
// 执行SQDMULH
sqdmulh v2.4h, v0.4h, v1.4h // v2 = [(2*0x4000*0x2000)>>16,...]
这个例子中,我们计算:
code复制2 * 0x4000 * 0x2000 = 0x10000000
结果右移16位得到0x1000
SQDMULH常用于:
SQDMULL(Signed Saturating Doubling Multiply Long)指令执行以下操作:
数学表达式:
code复制result = saturate(2 * a * b)
其中结果的大小是输入元素的两倍(如16位输入产生32位结果)。
SQDMULL也有标量和向量两种形式:
code复制31 30 29 28|27 26 25 24|23 22 21 20|19 18 17 16|15 14 13 12|11 10 9 8|7 6 5 4|3 2 1 0
0 1 0 1 |1 1 1 1 |size L M Rm|1 0 1 1 |H 0 Rn |Rd |U opcode
code复制31 30 29 28|27 26 25 24|23 22 21 20|19 18 17 16|15 14 13 12|11 10 9 8|7 6 5 4|3 2 1 0
0 Q 0 0 |1 1 1 1 |size L M Rm|1 0 1 1 |H 0 Rn |Rd |U opcode
计算两个16位向量的长整型乘积:
assembly复制// 初始化
mov w0, 0x40004000
mov w1, 0x20002000
dup v0.4h, w0
dup v1.4h, w1
// 执行SQDMULL
sqdmull v2.4s, v0.4h, v1.4h // v2 = [2*0x4000*0x2000,...]
计算结果:
code复制2 * 0x4000 * 0x2000 = 0x10000000
SQDMULL有两个变体:
SQDMULL适用于:
当结果超出目标数据类型能表示的范围时,处理器会:
例如,对于16位有符号数:
使用这些指令时应注意:
| 特性 | SMULH/SMULL | SQDMULH/SQDMULL |
|---|---|---|
| 饱和处理 | 无 | 有 |
| 双倍乘积 | 无 | 有 |
| 结果截断 | 无 | SQDMULH有 |
| 标志位设置 | 无 | 饱和时设置QC |
在4x4矩阵乘法中,可以使用SQDMULH/SQDMULL来优化计算:
assembly复制// 假设v0-v3存储第一个矩阵的行,v4-v7存储第二个矩阵的列
// 计算第一行点积
sqdmull v16.4s, v0.4h, v4.4h
sqdmull v17.4s, v0.4h, v5.4h
sqdmull v18.4s, v0.4h, v6.4h
sqdmull v19.4s, v0.4h, v7.4h
// 累加其他行...
FIR滤波器可以使用SQDMULH来实现高效的乘积累加:
assembly复制// v0:输入样本,v1-v4:滤波器系数
sqdmulh v5.4s, v0.4s, v1.4s // 第一组乘积高半部分
sqdmulh v6.4s, v0.4s, v2.4s // 第二组乘积高半部分
...
RGB到YUV的转换涉及大量定点乘法:
assembly复制// R,G,B分量在v0.8h中
// 转换系数在v1.8h,v2.8h,v3.8h中
sqdmulh v4.8h, v0.8h, v1.8h // R * coeff
sqdmulh v5.8h, v0.8h, v2.8h // G * coeff
sqdmulh v6.8h, v0.8h, v3.8h // B * coeff
mrs x0, FPSR读取FPSR寄存器检查QC标志print $q0等命令查看NEON寄存器内容在选择使用SQDMULH还是SQDMULL时,考虑以下因素:
精度需求:
数据范围:
后续操作:
性能考量:
SQDMULH和SQDMULL指令的支持情况:
| ARM架构版本 | 支持情况 |
|---|---|
| ARMv7-A | 需要NEON扩展 |
| ARMv8-A | 基本指令集部分 |
| ARMv8.1-A | 增强功能 |
| ARMv9-A | 完全支持 |
在编写可移植代码时,应使用CPUID类指令检查硬件支持:
assembly复制mrs x0, ID_AA64ISAR0_EL1
tbz x0, #20, not_supported // 检查AdvSIMD支持
通过合理使用SQDMULH和SQDMULL指令,可以在ARM平台上实现高效的向量化计算,显著提升多媒体处理、信号处理等计算密集型应用的性能。