如何给出关于循环计数的gcc的提示

时间:2013-01-10 10:50:08

标签: c optimization gcc

知道循环将经历的迭代次数允许编译器进行一些优化。考虑下面的两个循环:

未知的迭代次数:

static void bitreverse(vbuf_desc * vbuf)
{
    unsigned int idx = 0;
    unsigned char * img = vbuf->usrptr;

    while(idx < vbuf->bytesused) {
        img[idx] = bitrev[img[idx]];
        idx++;
    }

}

已知迭代次数

static void bitreverse(vbuf_desc * vbuf)
{
    unsigned int idx = 0;
    unsigned char * img = vbuf->usrptr;

    while(idx < 1280*400) {
        img[idx] = bitrev[img[idx]];
        idx++;
    }

}

第二个版本将编译为更快的代码,因为它将被展开两次(至少在ARM上使用gcc 4.6.3和-O2)。有没有办法对gcc在优化时考虑的循环计数进行断言?

2 个答案:

答案 0 :(得分:6)

函数有hot属性可以向编译器提供有关热点的提示:http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html。只是在你的职能之前abb:

static void bitreverse(vbuf_desc * vbuf) __attribute__ ((pure));

此处有关于来自gcc的“hot”的文档:

  

hot 函数的hot属性用于通知编译器   该函数是编译程序的热点。功能   优化得更加积极,并在许多目标上进行优化   文本部分的特殊部分,所以出现所有热门功能   密切合作改善地方。当个人资料反馈可用时,   通过-fprofile-use,可以自动检测热门功能   属性被忽略。

     

函数的hot属性未在GCC版本中实现   早于4.3。

     

标签上的hot属性用于通知编译器该路径   跟随标签的可能性比不是这样的路径更可能   注释。此属性用于__builtin_expect的情况   不能使用,例如使用计算goto或asm goto。

     

标签上的hot属性未在之前的GCC版本中实现   比4.8。

此外,您可以尝试在idx < vbuf->bytesused周围添加__builtin_expect - 这将暗示在大多数情况下表达式为真。

在这两种情况下,我都不确定你的循环是否会被优化。

或者,您可以尝试使用配置文件引导优化。使用-fprofile-generate构建生成配置文件的程序版本;在目标上运行它,将配置文件数据复制到build-host并使用-fprofile-use重建。这将为编译器提供大量信息。

在某些编译器中(不在GCC 中),存在循环编译指示,包括“#pragma loop count (N)”和“#pragma unroll (M)”,例如在Intel; unroll in IBM; vectorizing pragmas in MSVC

ARM编译器(armcc)也有一些循环编译指示:unroll(n)(通过1):

  

循环展开:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0348b/CJACACFE.htmlhttp://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0348b/CJAHJDAB.html

__promise内在:

  

使用__promise来改善矢量化

     

__promise(expr)内在函数是编译器对给定表达式非零的承诺。这使编译器能够通过优化远离代码来改进矢量化,这些代码基于您所做的承诺是多余的。   示例3.21的反汇编输出显示了__promise产生的差异,通过删除标量修正循环将反汇编减少为简单的矢量化循环。

     

例3.21。使用__promise(expr)来改进矢量化代码

void f(int *x, int n)
{
    int i;
    __promise((n > 0) && ((n&7)==0));
    for (i=0; i<n;i++) x[i]++;
}

答案 1 :(得分:0)

您实际上可以使用__builtin_expect指定确切的计数,如下所示:

while (idx < __builtin_expect(vbuf->bytesused, 1280*400)) {

这告诉gcc vbuf->bytesused在运行时预计为1280 * 400。

唉,这对于使用当前的gcc版本进行优化没有任何帮助。但是没有试过4.8。

编辑:刚刚意识到每个标准C编译器都有一种通过断言准确指定循环计数的方法。自断言

#include <assert.h>
...
assert(loop_count == 4096);
for (i = 0; i < loop_count; i++) ...
如果条件不为真,

将调用exit()或abort(),任何具有值传播的编译器都将知道loop_count的确切值。我一直认为这将是提供这种优化提示的最优雅和符合标准的方式。现在,我想要一个实际使用此信息的C编译器。

请注意,如果要更快地进行此操作,则按字节展开可能不如使用更宽的查找表有效。 16位表占用128K,因此通常适合CPU高速缓存。如果数据不是完全随机的,则更宽的表(3个字节)可能有效。

2字节示例:

unsigned short *bitrev2;
...
for (idx = 0; idx < vbuf->bytesused; idx += 2) {
    *(unsigned short *)(&img[idx]) = bitrev2[*(unsigned short *)(&img[idx]);
}

这是编译器无法执行的优化,无论您提供哪些信息。