我正在尝试使用霓虹灯在iPhone 4上实现点积功能。基于本教程:http://www.delmarnorth.com/microwave/requirements/neon-test-tutorial.pdf
我在XCode 4.5中尝试了以下方法。当我设置nruns = 1时,它可以工作,即从霓虹灯得到的答案与标准C ++版本相同。但是,当我将nruns设置为> 1时,某些东西会损坏并且会产生垃圾(例如,如果我在第一次调用dotProduct()之后打印出数组的元素,则它们会损坏)。我必须承认我对霓虹灯没有经验,但是我所需要的只是能够制造这种点状产品!有人有什么想法吗?
float dotProduct ( float *a, float *b, int n) {
float sum=0.0f;
__asm__ volatile (
"vmov.f32 q8, #0.0 \n\t"
"vmov.f32 q9, #0.0 \n\t"
"1: \n\t"
"subs %3, %3, #8 \n\t"
"vld1.f32 {d0,d1,d2,d3}, [%1]! \n\t"
"vld1.f32 {d4,d5,d6,d7}, [%2]! \n\t"
"vmla.f32 q8, q0, q2 \n\t"
"vmla.f32 q9, q1, q3 \n\t"
"bgt 1b \n\t"
"vadd.f32 q8, q8, q9 \n\t"
"vpadd.f32 d0, d16, d17 \n\t"
"vadd.f32 %0, s0, s1 \n\t"
: "=w"(sum)
: "+r"(a), "+r"(b), "+r"(n)
: "q0", "q1", "q2", "q3", "q8", "q9");
return sum;
}
void test_dotProduct_neon()
{
int n=16, i, k;
int nruns = 2;
float dp;
float *a = new float[n];
float *b = new float[n];
for (i=0; i < n; i++) {
a[i] = (float) i;
b[i] = (float) (2*i);
}
for (i=0; i<nruns; i++) {
dp=0.0f;
for( k=0; k < n; k++) {
dp += a[k] * b[k];
}
}
printf(" C Result: %f\n", dp );
for (i=0; i<nruns; i++) {
dp = dotProduct( a, b, n);
}
printf(" Neon Result: %f\n", dp );
}
最佳答案
您的NEON代码修改了指针“ a”和“ b”,因为加载指令(vld1)使地址寄存器递增(这就是地址后面的“!”)。
据推测,正在发生的事情是编译器没有意识到这些值可能会更改,因此您的代码第二次使用伪造的指针值。
您确实用“ +”标记了这些内联汇编输入,这意味着“输入/输出操作数”,但是我认为您需要在输出操作数部分中列出它们,而不是在输入操作数中列出才能起作用。您的代码应阅读
: "=w"(sum), "+r"(a), "+r"(b), "+r"(n)
: /* No inputs */
: "q0", "q1", "q2", "q3", "q8", "q9"
此外,输入,输出和破坏寄存器的集合也不脱节!将寄存器标记为已破坏不会阻止编译器将其用作输入寄存器AFAIR,因为它假定输入在发生破坏之前已被消耗。现在,由于您的输入是ARM寄存器,而被破坏的寄存器是NEON寄存器,因此对于输出和被破坏的寄存器也不相同,您应该是安全的。我建议您检查http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html以确保。
编辑:即使
sum
恰好位于其中一个被破坏的寄存器中,您的代码似乎也是正确的,因为您从未读过它,而只是在最后写了它。我以前在上面写警告时想念它。编辑:内联程序集传递指针
a
和b
而不是作为内存区域(带有m
-Constraint),而是作为通用寄存器中的纯值。因此,编译器不会意识到您实际上正在从这些内存位置读取数据,因此可能会错误地将程序集块从其他存储区移至那些位置。现在,由于您的内存区域具有可变大小,因此您不能轻易使用m
-Constraints,因为这些假设假定大小是静态确定的。相反,您可以将"memory"
添加到Clobber列表中,该列表告诉编译器该汇编块可以在任意内存位置进行读写操作。并且在使用时,还应该添加“ cc
”,因为汇编块会修改条件代码寄存器(包含测试指令结果的寄存器)。输入/输出声明然后如下所示: "=w"(sum), "+r"(a), "+r"(b), "+r"(n)
: /* No inputs */
: "q0", "q1", "q2", "q3", "q8", "q9", "cc", "memory"
编写内联汇编块时,请始终记住编译器不看,绝对不看这种块的内容。声明的输入和输出操作数以及声明的Clobber列表是有关块行为和数据依赖性的唯一信息来源。并且在优化时,编译器会积极使用该信息,尤其是如果您使用
-O2
或更高版本进行编译时。因此,这些声明中的任何遗漏都可能导致编译器生成不正确的代码。关于iphone - iPhone 4和XCode 4上的 NEON 点产品出现问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12611977/