首页 文章

GCC优化纯函数

提问于
浏览
5

我对GCC关于优化 pure 函数(来自online docs)的保证感到困惑:

纯净
除返回值外,许多函数都没有效果,它们的返回值仅取决于参数和/或全局变量 . (...)有趣的非纯函数是具有无限循环的函数或者取决于易失性存储器或其他系统资源的函数,它们可以在两个连续调用(例如多线程环境中的feof)之间改变 .

对于 const

const
许多函数不检查除参数之外的任何值,除了返回值之外没有任何效果 . 基本上,这只是比下面的纯属性稍微严格的类,因为该函数不允许读取全局内存 . 请注意,具有指针参数并检查指向的数据的函数不能声明为const . 同样,调用非const函数的函数通常不能是const .

所以,我尝试创建一个接受指针参数的函数,并尝试将其标记为 pure . 但是,我尝试使用GCC在线编译此功能(我尝试了 constpure ):

typedef struct
{
    int32_t start;
    int32_t end;
}
Buffer;

inline __attribute__((pure,always_inline)) int32_t getLen(Buffer * b) 
{
    return b->end - b->start;
}

并注意到GCC(至少我试过的几个_2903563):

如果传递的 Buffer* 参数指向全局值,则

  • doesn't optimize 调用此函数(即多次调用它),
    如果传递的指针指向本地(堆栈)变量,则

  • optimizes 调用此函数(即仅调用一次) .

  • 即使我将函数 const 而不是 pure 标记,两种情况都是一样的,但如果有一个指针参数,可能会忽略 const

This is a good thing ,因为全局 Buffer 可能随时由不同的线程/中断改变,而本地 Buffer 对于优化是完全安全的 .

但是我对传递指针的言论感到困惑 . 是否有一个地方为接受指针参数的 pure 函数明确定义了GCC的行为?

2 回答

  • 1

    是否存在为接受指针参数的纯函数显式定义GCC行为的地方?

    行为与不带指针参数的纯函数没有什么不同;他们可以读取程序中的任何内存,但不能写入内存或执行IO .

    通过将pure和const函数编写为内联,你已经非常困惑了 . 在调用站点,编译器可以使用函数体,它可以自己解决被调用函数执行的操作 . pure和const属性在函数体不可见的情况下最有用,因为它将在单独的编译单元中定义 .

    例如,考虑以下非纯,纯和const函数的集合:

    __attribute__((__pure__)) int a();
    __attribute__((__const__)) int b();
    void c();
    

    如果我们连续两次调用 a ,没有操作插入,我们可以将其折叠为单个调用,因为 a 保证仅访问全局内存才能读取它;即使另一个线程在同一时间写入全局内存, a 也无法与该线程通信,因此编译器可以假定写入发生在两次调用 a 之前或之后:

    int f() {
        int i = a();
        i += a();
        return i;  // optimized to "return a() * 2;"
    }
    

    如果我们在 a 的调用之间调用 c ,我们必须假设 c 的返回值可能会受到 c 调用的影响:

    int g() {
        int i = a();
        c();
        i += a();
        return i;  // no optimization possible
    }
    

    但是,如果我们调用const b 而不是纯 b ,我们可以将其折叠为单个调用,因为 b 无法读取 c 可能写入的任何内存:

    int h() {
        int i = b();
        c();
        i += b();
        return i;  // optimized to "c(); return b() * 2;"
    }
    
  • 4

    “GCC提出的保证” .

    它没有 . pureconst 属性是您对GCC做出的承诺 .

    当您做出这些承诺时,优化器可能能够 Build 某些变量的非锯齿 . 但即使它可以,非锯齿也可能与优化无关(因为它不够或不相关) . 添加 pureconst 无关紧要 .

相关问题