sha*_*oth 3 c optimization c99 compiler-optimization
我不太了解5.1.2.3/3的以下部分:
实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用).
假设我有以下代码:
char data[size];
int i;
int found;
/* initialize data to some values in here */
found = 0;
for( i = 0; i < size; i++ ) {
if( data[i] == 0 ) {
found = 1;
/* no break in here */
}
}
/* i no longer used, do something with "found" here */
Run Code Online (Sandbox Code Playgroud)
请注意,found
以&开头0
可以保持不变或变为1
.它不能变成1
然后变成别的东西.因此,以下代码将产生相同的结果(除了i
在循环之后未使用的值):
char data[size];
int i;
int found;
/* initialize data to some values in here */
found = 0;
for( i = 0; i < size; i++ ) {
if( data[i] == 0 ) {
found = 1;
break;
}
}
/* i no longer used, do something with "found" here */
Run Code Online (Sandbox Code Playgroud)
现在是什么标准说的不一定对表达式求值的一部分关于found = 1
和循环控制表达式随后在其控制内得到第一次迭代if
?
显然,如果found
在此代码之后的某处使用,编译器必须发出遍历数组的代码并有条件地计算found = 1
表达式.
是否需要对found = 1
数组中找到的每个零进行一次评估,或者是否可以将其评估为一次,因此在编译第一个代码段时有效地为第二个代码段发出代码?
它可以代替评估它一次,并在编译第一个片段时有效地为第二个片段发出代码吗?
是的,编译器有权执行该优化.这似乎是一个非常积极的优化,但它是合法的.
看一个更符合文本精神的例子可能会很有趣:
实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用).
假设我们有:
int x = pureFunction(y) * otherPureFunction(z);
Run Code Online (Sandbox Code Playgroud)
假设编译器知道两个函数都是int返回"纯"函数; 也就是说,它们没有副作用,它们的结果完全取决于论点.假设编译器也认为这otherPureFunction
是一个非常昂贵的操作.编译器可以选择像您编写的那样实现代码:
int temp = pureFunction(y);
int x = temp == 0 ? 0 : temp * otherPureFunction(z);
Run Code Online (Sandbox Code Playgroud)
也就是说,确定在某些条件下不需要计算,otherPureFunction()
因为一旦已知左操作数为零,则已知乘法的结果.没有必要的副作用将被省略,因为没有副作用.
是的,它可以执行此优化,因为没有I/O操作,从volatile
位置读取或优化代码省略的外部可见写入内存,因此保留了行为.
作为这种优化的一个例子,GCC将编译
void noop(const char *s)
{
for (size_t i = 0; i < strlen(s); i++) {
}
}
Run Code Online (Sandbox Code Playgroud)
一个完全空的功能:
noop:
.LFB33:
.cfi_startproc
rep ret
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
允许这样做是因为标准保证了行为strlen
,编译器知道它对s
任何其他内存都没有外部可见的影响,并且它可以推断整个函数没有行为.(令人惊讶的是,这种简单的优化将复杂性从二次变为常数.)