C静态内联参数评估优化

时间:2016-07-03 23:00:57

标签: c optimization language-lawyer

假设一个API,其中每个函数都返回一个错误代码,如果没有错误则为零,错误值为非零。

int foo(...);
int bar(...);

是此API中的函数。设有一个代码片段,其中必须按顺序调用foobar ,并且foo和bar应该始终被调用,而不管以前的错误但是第一个返回的非零错误代码将被传播,即

int foobar(...)
{
    int rc = 0, rc_;
    /* ... */
    rc_ = foo(...); rc = rc ? rc : rc_;
    rc_ = bar(...); rc = rc ? rc : rc_;
    return rc;
}

写入rc,rc_多路复用是累人且容易出错(无论是否使用三元运算符,if / else或其他东西)。

让传播帮助函数的错误

static inline
int rc_propagate(int r, int p){ return p ? p : r; }

这可以在foobar中使用

int foobar(...)
{
    int rc = 0;
    /* ... */
    rc = rc_propagate(foo(...), rc);
    rc = rc_propagate(bar(...), rc);
    return rc;
}

C标准是否允许通过将rc_propagate的第一个参数(一个静态内联函数)的评估推入三元组来进行优化,以便由于三元运算符评估规则它可能无法执行参数p是非零的?

1 个答案:

答案 0 :(得分:3)

只要程序保持不变,就允许编译器(或者硬件)优化程序 1 ,即你不能证明执行的程序与程序不同你写的。

在这种情况下,您编写的程序将始终调用外部函数,因为它不会出现在三元运算符中,可能无法对其进行求值。该函数可能具有不同的有趣副作用,并且编译器不知道。这意味着程序的优化版本必须在某个时刻调用外部函数(代码可以重新排序)以保留该行为。

如果这不是真的,你可以证明所执行的程序与你编写的程序不同。这样做很容易;将printf(或等效的)语句放入外部函数调用。

<子> 1。抽象程序在执行时存在的概念,而不是生成的机器代码或可执行文件。

使用来自权限的参数,您可以看到没有编译器实际上会优化对foo()和bar()的调用:

gcc版本4.9.2,5.3或6.1 with -O2:

foobar():
pushq   %rbx    
call    foo()    
movl    %eax, %ebx    
call    bar()    
testl   %ebx, %ebx    
cmove   %eax, %ebx    
movl    %ebx, %eax    
popq    %rbx    
ret

clang版本3.7.1,或3.8与-O2:

foobar():                          
pushq   %rbx    
callq   foo()    
movl    %eax, %ebx    
callq   bar()    
testl   %ebx, %ebx    
cmovnel %ebx, %eax    
popq    %rbx