我正在尝试使用霓虹灯在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恰好位于其中一个被破坏的寄存器中,您的代码似乎也是正确的,因为您从未读过它,而只是在最后写了它。我以前在上面写警告时想念它。

编辑:内联程序集传递指针ab而不是作为内存区域(带有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/

10-11 22:26