【问题标题】:how to write inline assembly codes about LOOP in Xcode LLVM?如何在 Xcode LLVM 中编写有关 LOOP 的内联汇编代码?
【发布时间】:2012-01-26 16:19:12
【问题描述】:

我正在研究内联汇编。我想在 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;
    }
}

【问题讨论】:

  • 这样的功能也可以使用 OpenGL ES 和片段着色器来实现。如果这适用于您的问题。这将为您“免费”提供并行化,类似于 Matt 建议的 NEON 的使用。
  • 是的,你肯定可以使用 OpenGL ES。很大程度上取决于您在做什么以及是否要将其作为依赖项引入。
  • 如果他需要将计算的总和返回给 CPU,OpenGL ES 可能不够快。 iPad GPU 不是为高效执行此任务而制造的。

标签: iphone c assembly arm inline-assembly


【解决方案1】:

看看这里的循环部分 - 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"
                  "\t b 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"
                  "\t b 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 个像素的数据执行操作。哦,它也有饱和度,我想你会想要的。

【讨论】:

  • 这些代码运行良好!这对我的理解很有帮助。非常感谢您的建议~
【解决方案2】:

虽然此答案不是您问题的直接答案,但它更像是关于使用汇编器与现代编译器的一般建议。

在优化 C 代码方面,您通常很难击败编译器。当然,通过巧妙地利用有关数据行为方式的某些知识,您可能会对其进行微调。

其中一个原因是现代编译器在处理您所描述的代码时使用了多种技术,例如循环展开、指令重新排序以避免流水线停顿和气泡等。

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

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

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

【讨论】:

  • 也许他想把它作为学习的练习?或者想要确保正确使用来自 NEON 的向量指令?看起来他想用像素数据做一些事情,这肯定会受益于一些矢量指令。例如,您可以一次添加和饱和 16 个像素。
  • 尤其是在 ARM 上,编译器还没有达到你想象的水平。 SIMD 指令和位域操作的优化很差,你可以通过直接在 ARM 中编码来获得很大的加速。但请注意,AppStore 仅接受仅使用已记录 API 的应用程序。不确定内联汇编程序如何影响 AppStore 资格。
  • 内联汇编绝不会影响 App Store 资格。那不是使用未记录的 API。内联汇编是编译器/汇编器的功能,因此与框架的 API 无关。
猜你喜欢
  • 2019-11-30
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
相关资源
最近更新 更多