Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
gcc是否会自动执行;展开;如果语句?_C_Optimization_Gcc_Unroll - Fatal编程技术网

gcc是否会自动执行;展开;如果语句?

gcc是否会自动执行;展开;如果语句?,c,optimization,gcc,unroll,C,Optimization,Gcc,Unroll,假设我有一个如下所示的循环: for(int i = 0; i < 10000; i++) { /* Do something computationally expensive */ if (i < 200 && !(i%20)) { /* Do something else */ } } for(int i=0;i

假设我有一个如下所示的循环:

for(int i = 0; i < 10000; i++) {
    /* Do something computationally expensive */
    if (i < 200 && !(i%20)) {
        /* Do something else */
    }
}
for(int i=0;i<10000;i++){
/*做一些计算上昂贵的事情*/
如果(i<200&!(i%20)){
/*做点别的*/
}
}
其中一些琐碎的任务被一个只运行了几次的if语句所阻塞。 我一直听说“如果循环中的语句很慢!”因此,为了(稍微)提高性能,我将循环分成以下几个部分:

for(int i = 0; i < 200; i++) {
    /* Do something computationally expensive */
    if (!(i%20)) {
        /* Do something else */
    }
}

for(int i = 200; i < 10000; i++) {
    /* Do something computationally expensive */
}
for(int i=0;i<200;i++){
/*做一些计算上昂贵的事情*/
如果(!(i%20)){
/*做点别的*/
}
}
对于(int i=200;i<10000;i++){
/*做一些计算上昂贵的事情*/
}

gcc(使用适当的标志,如-O3)会自动将一个循环分解为两个,还是只展开以减少迭代次数?

为什么不直接分解程序并亲自查看?但我们走了。这是测试程序:

int main() {
    int sum = 0;
    int i;
    for(i = 0; i < 10000; i++) {
        if (i < 200 && !(i%20)) {
            sum += 0xC0DE;
        }
        sum += 0xCAFE;
    }
    printf("%d\n", sum);
    return 0;
}
intmain(){
整数和=0;
int i;
对于(i=0;i<10000;i++){
如果(i<200&!(i%20)){
总和+=0xC0DE;
}
总和+=0xCAFE;
}
printf(“%d\n”,总和);
返回0;
}
这是使用gcc 4.3.3和-o3编译的反汇编代码中有趣的部分:

0x08048404 <main+20>:   xor    ebx,ebx
0x08048406 <main+22>:   push   ecx
0x08048407 <main+23>:   xor    ecx,ecx
0x08048409 <main+25>:   sub    esp,0xc
0x0804840c <main+28>:   lea    esi,[esi+eiz*1+0x0]
0x08048410 <main+32>:   cmp    ecx,0xc7
0x08048416 <main+38>:   jg     0x8048436 <main+70>
0x08048418 <main+40>:   mov    eax,ecx
0x0804841a <main+42>:   imul   esi
0x0804841c <main+44>:   mov    eax,ecx
0x0804841e <main+46>:   sar    eax,0x1f
0x08048421 <main+49>:   sar    edx,0x3
0x08048424 <main+52>:   sub    edx,eax
0x08048426 <main+54>:   lea    edx,[edx+edx*4]
0x08048429 <main+57>:   shl    edx,0x2
0x0804842c <main+60>:   cmp    ecx,edx
0x0804842e <main+62>:   jne    0x8048436 <main+70>
0x08048430 <main+64>:   add    ebx,0xc0de
0x08048436 <main+70>:   add    ecx,0x1
0x08048439 <main+73>:   add    ebx,0xcafe
0x0804843f <main+79>:   cmp    ecx,0x2710
0x08048445 <main+85>:   jne    0x8048410 <main+32>
0x08048447 <main+87>:   mov    DWORD PTR [esp+0x8],ebx
0x0804844b <main+91>:   mov    DWORD PTR [esp+0x4],0x8048530
0x08048453 <main+99>:   mov    DWORD PTR [esp],0x1
0x0804845a <main+106>:  call   0x8048308 <__printf_chk@plt>
0x08048404:xor ebx,ebx
0x08048406:推送ecx
0x08048407:xor ecx,ecx
0x08048409:子esp,0xc
0x0804840c:lea esi[esi+eiz*1+0x0]
0x08048410:cmp ecx,0xc7
0x08048416:jg 0x8048436
0x08048418:mov eax,ecx
0x0804841a:imul esi
0x0804841c:mov eax,ecx
0x0804841e:sar eax,0x1f
0x08048421:sar edx,0x3
0x08048424:子edx,eax
0x08048426:lea edx,[edx+edx*4]
0x08048429:shl edx,0x2
0x0804842c:cmp ecx,edx
0x0804842e:jne 0x8048436
0x08048430:添加ebx,0xc0de
0x08048436:添加ecx,0x1
0x08048439:添加ebx,0xcafe
0x0804843f:cmp ecx,0x2710
0x08048445:jne 0x8048410
0x08048447:mov DWORD PTR[esp+0x8],ebx
0x080484B:mov DWORD PTR[esp+0x4],0x8048530
0x08048453:mov DWORD PTR[esp],0x1
0x0804845a:调用0x8048308
正如我们所看到的,对于这个特殊的例子,不,它不是。我们只有一个从main+32开始到main+85结束的循环。如果在读取汇编代码ecx=i时遇到问题;ebx=总和

但是,您的里程数可能会有所不同-谁知道在这种特殊情况下使用了什么样的启发式算法,因此您必须编译心中的代码,并查看更长/更复杂的计算对优化器的影响


尽管在任何现代CPU上,分支预测器在这样简单的代码上都能做得很好,所以在这两种情况下都不会有太多性能损失。如果您的计算密集型代码需要数十亿个周期,那么一些预测失误会造成什么性能损失?

我当然记得GCC邮件列表中对此的讨论-至少有一些支持。通过检查汇编程序输出或
-da
,可能最容易验证它在您的情况下是否真的会这样做;它可能只展开了0或最大循环的情况,我不记得了。然而,在您的情况下(对于200-10000,它将是:test iYou可能会通过在每个迭代器上检查i的lsb来优化(和混淆)代码,因为奇数不会被20整除。如果iYou总是听到“循环中的If语句很慢”你从哪里听说的?只是好奇而已。啊,非常感谢!我从来不知道如何去分析反汇编代码。