iPhone 4 和 XCode 4 上的霓虹点积问题
Posted
技术标签:
【中文标题】iPhone 4 和 XCode 4 上的霓虹点积问题【英文标题】:Trouble with neon dot product on iPhone 4 and XCode 4 【发布时间】:2012-09-26 23:30:56 【问题描述】:我正在尝试使用霓虹灯在 iPhone 4 上实现点积功能。基于本教程:http://www.delmarnorth.com/microwave/requirements/neon-test-tutorial.pdf 我在 XCode 4.5 中尝试了以下内容。当我设置 nruns=1 时,它可以工作,即,我从霓虹灯中得到与标准 C++ 版本相同的答案。但是,当我设置 nruns > 1 时,某些东西会损坏并出现垃圾(例如,如果我在第一次调用 dotProduct() 后打印出 a 数组的元素,它们就会损坏)。我不得不承认我没有使用霓虹灯的经验,但我所需要的就是能够做这个点积!有人有什么想法吗?
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 );
【问题讨论】:
【参考方案1】:您的 NEON 代码会修改指针“a”和“b”,因为您的加载指令 (vld1) 会增加地址寄存器(地址后的“!”就是这样做的)。
可能发生的事情是编译器没有意识到这些值可能会改变,因此您的代码第二次使用虚假的指针值。
您确实用“+”标记了这些内联汇编输入,这意味着“输入/输出操作数”,但我认为您需要在 output 操作数部分中列出它们,而不是在 input 第二个操作数才能工作。你的代码应该是
: "=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"
在编写内联汇编块时,请始终记住编译器不会,绝对no查看此类块的内容。关于块的行为和数据依赖关系的唯一信息来源是声明的输入和输出操作数,以及声明的 clobber 列表。并且编译器将在优化时积极使用该信息,尤其是当您使用-O2
或更高版本进行编译时。因此,这些声明中的任何遗漏都可能导致编译器生成不正确的代码。
【讨论】:
我回来了。在玩了很多之后,我意识到我仍然遇到错误。我终于意识到我的输入向量的维度必须是 2 的幂。我应该提到我也错误复制了链接中引用的教程中的示例,并且该链接中的实际代码反映了您在上面建议的更正.无论如何,现在它可以工作了。 为什么是 2 的幂?我想说,它们的维度需要被 8 整除,因为您的 NEON 代码以 8 为单位处理元素。顺便说一句,您的内联汇编也无法通知编译器您实际上是从指向的内存中读取的a
和 b
。我将再做一次编辑来解释如何解决这个问题。
再次正确。必须是 8 的倍数。期待您的编辑。以上是关于iPhone 4 和 XCode 4 上的霓虹点积问题的主要内容,如果未能解决你的问题,请参考以下文章
Xcode 5 / iOS7:尝试添加约束以在 iPhone 3.5" 和 4" 屏幕之间调整大小
更改 Xcode 4.3.2 的 iPad/iPhone 模拟器分辨率 [重复]
Xcode 4.6 iPhone/iPad 复制字段,使用 setText“不兼容的指针类型”