iphone - iPhone 4 和 XCode 4 上的 NEON 点产品出现问题

标签 iphone xcode neon

我正在尝试使用 neon 在 iPhone 4 上实现点积函数。基于本教程:http://www.delmarnorth.com/microwave/requirements/neon-test-tutorial.pdf 我在 XCode 4.5 中尝试了以下操作。当我设置 nruns=1 时,它起作用,即,我从 neon 得到与标准 C++ 版本相同的答案。然而,当我设置 nruns > 1 时,某些东西会被损坏,并且会出现垃圾(例如,如果我在第一次调用 dotProduct() 后打印出 a 数组的元素,它们就会被损坏)。我必须承认我没有使用 NEON 的经验,但我所需要的只是能够做这个点积!有人有什么想法吗?

   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 碰巧存在于一个被破坏的寄存器中,您的代码似乎也是正确的,因为您从未读过它,所以它只在最结尾。当我写上面的警告时,我错过了这一点。

编辑:您的内联程序集将指针 ab 传递,而不是作为内存区域(带有 m -约束),但作为通用寄存器中的普通值。因此,编译器不知道您实际上正在从这些内存位置读取数据,因此可能会错误地将汇编 block 移过其他存储区到这些位置。现在,由于您的内存区域具有可变大小,因此您无法轻松使用m-Constraints,因为它们假设大小是静态确定的。相反,您可以将 "memory" 添加到 clobber 列表中,该列表告诉编译器汇编 block 可以从任意内存位置读取和写入。当您这样做时,您还应该添加“cc”,因为您的汇编 block 会修改条件代码寄存器(包含测试指令结果的寄存器)。输入/输出声明如下所示

: "=w"(sum), "+r"(a), "+r"(b), "+r"(n)
: /* No inputs */
: "q0", "q1", "q2", "q3", "q8", "q9", "cc", "memory"

在编写内联汇编 block 时,请始终记住编译器不会、绝对不会查看此类 block 的内容。它是有关 block 行为和数据依赖性的唯一信息来源是声明的输入和输出操作数以及声明的破坏列表。编译器在优化时会积极使用这些信息,尤其是使用 -O2 或更高版本进行编译时。因此,这些声明中的任何遗漏都可能导致编译器生成不正确的代码。

关于iphone - iPhone 4 和 XCode 4 上的 NEON 点产品出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12611977/

相关文章:

iphone - UIAlertView 中 UIView 中的 UITextField 不起作用?

iphone - 什么是iOS的常驻和脏内存?

将代码转换为 Neon 程序集

c - 如何加载 4 个无符号字符并使用 NEON 将它们转换为带符号的短裤?

ios - Swift - Xcode 无法识别现有的成员变量

android - Android 程序如何使用 NEON SIMD?

iphone - 如何在 iPhone 中追踪手指的长按操作?

android - 如何使元素之间的边距在方向上相同?

json - 循环 Json 链接 Swift

ios - 模拟器运行之间的iOS共享目录