Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arm 有效使用vmlaq_s16_Arm_Simd_Neon - Fatal编程技术网

Arm 有效使用vmlaq_s16

Arm 有效使用vmlaq_s16,arm,simd,neon,Arm,Simd,Neon,当使用vmlaq_s16内部/VMLA.I16指令时,结果采用一组8个16位整数的形式。然而,指令中的乘法要求将结果存储在32位整数中,以防止溢出 在采用SSE2的英特尔处理器上,_mm_madd_epi16通过将向量的连续元素对相乘和相加(即 r0 := (a0 * b0) + (a1 * b1) r1 := (a2 * b2) + (a3 * b3) r2 := (a4 * b4) + (a5 * b5) r3 := (a6 * b6) + (a7 * b7) 其中r0、r1、r2、r3均

当使用vmlaq_s16内部/VMLA.I16指令时,结果采用一组8个16位整数的形式。然而,指令中的乘法要求将结果存储在32位整数中,以防止溢出

在采用SSE2的英特尔处理器上,_mm_madd_epi16通过将向量的连续元素对相乘和相加(即

r0 := (a0 * b0) + (a1 * b1)
r1 := (a2 * b2) + (a3 * b3)
r2 := (a4 * b4) + (a5 * b5)
r3 := (a6 * b6) + (a7 * b7)
其中r0、r1、r2、r3均为32位,a0-a7、b0-b7均为16位元素

vmlaq_s16指令是否有一个我没有的技巧,允许我仍然能够一次处理8个16位元素,并且结果不会溢出?或者,这条指令只是为固有的4位范围内的操作数提供的(非常可疑)

谢谢

编辑:因此我刚刚考虑了一个事实,即如果vmlaq_s16为结果中的每个元素设置溢出寄存器标志,那么很容易计算溢出并恢复结果

编辑2:供大家参考,下面介绍如何加载8个元素,并使用Intrinsic(使用VS2012编译的ARM目标概念验证代码)在128位寄存器上管道化两个长乘法加法:


这些操作不是直接等价的-
VMLA
将两个向量相乘,然后将结果元素添加到第三个向量,这与英特尔
PMADDWD
的自足半元素半水平疯狂不同。由于第三个向量是一个常规操作数,它必须存在于寄存器中,因此没有空间容纳256位累加器


如果您不想通过使用
VMLA
执行8x16*8x16+8x16操作来冒溢出风险,则可选择使用
VMLAL
执行4x16*4x16+4x32。显而易见的建议是将处理8x16向量的指令对管道化到两个4x32累加器中,然后在最后将它们相加,但我承认我对内部函数不太熟悉,所以我不知道它们会有多困难(与汇编相比,汇编可以利用“64位向量”和“128位向量”只是同一寄存器文件的可交换视图。)

谢谢。这就是我目前正在做的事——vmlal_s16,它只使用了“可用”的一半“带宽。因此,管道化成对指令的明显建议的优点是它节省了另一个负载,对吗?也就是说,我不是在块的开头加载两个8字节的数据,而是在块的开头加载一个16字节的数据,这样可以节省一次对内存和缓存的访问。事实上,如果数据已经在寄存器中,那么每个额外的
VMLAL
只需要多花费1个周期(在最初的~5-10个周期的结果延迟之上),我相信一些内核实际上会允许您使用同一个累加器寄存器来流水线传输多条指令,而不会产生任何额外的惩罚。据我所知,仔细预加载并保持L1满负荷比其他任何事情都重要——与加载/存储瓶颈相比,数据处理“带宽”几乎是免费的。这是一个好主意,但它只将我的代码速度提高了约10%。我将更深入地研究程序集,看看我是否能比MSVS ARM编译器更好地使用vmlal指令交错内存加载。遗憾的是,NEON没有标志寄存器的概念-最接近的是未限制的浮点异常状态位,这在这里毫无帮助:(
signed short vector1[] = {1, 2, 3, 4, 5, 6, 7, 8};
signed short vector2[] = {1, 2, 3, 4, 5, 6, 7, 8};

int16x8_t v1; // = vdupq_n_s16(0);
int16x8_t v2; // = vdupq_n_s16(0);

v1 = vld1q_s16(vector1);
v2 = vld1q_s16(vector2);

int32x4_t sum = vdupq_n_s16(0);
sum = vmlal_s16(sum, v1.s.low64, v2.s.low64);
sum = vmlal_s16(sum, v1.s.high64, v2.s.high64);

printf("sum: %d\n", sum.n128_i32[0]);