如何在Xcode LLVM中编写关于LOOP的内联汇编代码?

我正在研究内联assembly。 我想在Xcode 4 LLVM 3.0编译器下在iPhone中编写一个简单的例程。 我成功编写了基本的内联汇编代码。

例子:

int sub(int a, int b) { int c; asm ("sub %0, %1, %2" : "=r" (c) : "r" (a), "r" (b)); return c; } 

我在stackoverflow.com找到它并且它工作得很好。 但是,我不知道如何编写有关LOOP的代码。

我需要汇编代码

 void brighten(unsigned char* src, unsigned char* dst, int numPixels, int intensity) { for(int i=0; i<numPixels; i++) { dst[i] = src[i] + intensity; } } 

请看一下循环部分 – http://en.wikipedia.org/wiki/ARM_architecture

基本上你会想要这样的东西:

 void brighten(unsigned char* src, unsigned char* dst, int numPixels, int intensity) { asm volatile ( "\t mov r3, #0\n" "Lloop:\n" "\t cmp r3, %2\n" "\t bge Lend\n" "\t ldrb r4, [%0, r3]\n" "\t add r4, r4, %3\n" "\t strb r4, [%1, r3]\n" "\t add r3, r3, #1\n" "\tb Lloop\n" "Lend:\n" : "=r"(src), "=r"(dst), "=r"(numPixels), "=r"(intensity) : "0"(src), "1"(dst), "2"(numPixels), "3"(intensity) : "cc", "r3", "r4"); } 

更新:

这是NEON版本:

 void brighten_neon(unsigned char* src, unsigned char* dst, int numPixels, int intensity) { asm volatile ( "\t mov r4, #0\n" "\t vdup.8 d1, %3\n" "Lloop2:\n" "\t cmp r4, %2\n" "\t bge Lend2\n" "\t vld1.8 d0, [%0]!\n" "\t vqadd.s8 d0, d0, d1\n" "\t vst1.8 d0, [%1]!\n" "\t add r4, r4, #8\n" "\tb Lloop2\n" "Lend2:\n" : "=r"(src), "=r"(dst), "=r"(numPixels), "=r"(intensity) : "0"(src), "1"(dst), "2"(numPixels), "3"(intensity) : "cc", "r4", "d1", "d0"); } 

所以这个NEON版本一次会做8个。 但它确实没有检查numPixels是否可以被8整除,所以你肯定想要这样做,否则事情就会出错! 无论如何,这只是向您展示可以做些什么的开始。 注意相同数量的指令,但同时对8个像素的数据执行操作。 哦,它也在那里饱和,我认为你会想要。

虽然这个答案不能直接解答您的问题,但它更多地是关于使用汇编程序与现代编译程序的一般建议。

您通常很难击败编译器以优化C代码。 当然,通过巧妙地使用有关数据行为方式的某些知识,您可能只需调整几个百分点。

其中一个原因是现代编译器在处理代码时使用了许多技术,例如循环展开,指令重新排序以避免管道停滞和气泡等。

如果你真的想让这个算法尖叫,你应该考虑在C中重新设计算法,这样你就可以避免最严重的延迟。 例如,与寄存器访问相比,读取和写入存储器是昂贵的。

实现此目的的一种方法是让代码通过使用unsigned long一次加载4个字节,然后在寄存器中对此进行数学运算,然后在一个存储操作中将这4个字节写回。

所以回顾一下,让你的算法更聪明,而不是更难。