为什么GCC把两个相似的循环不同? [英] Why does GCC treat two similar loops differently?

查看:125
本文介绍了为什么GCC把两个相似的循环不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的理解如下code正确的,这将跳过整个循环,因为当比较无符号(j)和签署(-1),似乎-1将转换为 UINT_MAX 。 (像这样的question解释

If I understand the following code right, it will skip the whole loop, because when compare unsigned (j) and signed (-1), it seems that the -1 will be convert to UINT_MAX. (like this question explained)

第一个循环:

unsigned int j = 10;

for (; j > -1; --j) {     --->  `>`
    printf("%u", j);
}

第一圈组装code的部分:

Part of assembly code of first loop:

movq    %rsp, %rbp
.cfi_def_cfa_register 6
movl    %edi, -20(%rbp)
movq    %rsi, -32(%rbp)
movl    $10, -4(%rbp)
nop                           --->**elision**
popq    %rbp
.cfi_def_cfa 7, 8
ret

第二回路的第二回路

The second loop of second loop:

unsigned int j = 10;

for (; j >= -1; --j) {  --->  `>=`
    printf("%u", j);
}

组装code的部分:

Part of assembly code:

movq    %rsp, %rbp
.cfi_def_cfa_register 6
subq    $32, %rsp
movl    %edi, -20(%rbp)
movq    %rsi, -32(%rbp)
movl    $10, -4(%rbp)
jmp .L2                        --->** still a loop here **

.L3:

movl    -4(%rbp), %eax
movl    %eax, %esi
movl    $.LC0, %edi
movl    $0, %eax
call    printf
subl    $1, -4(%rbp)

.L2:

cmpl    $-1, -4(%rbp)
je  .L3
leave
.cfi_def_cfa 7, 8
ret

所以我的问题是


  • 为什么海湾合作委员会(我用GCC:(Ubuntu的4.8.2-19ubuntu1)4.8.2)处理过类似的情况,它的优化第一个,但没有第二个? (*或我的理解code是错的?)(它是与大会?)

  • Why the gcc (I use GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2) treat a similar situation, it optimize the first one but didn't the second? (* Or my understand of the code is wrong?) (it has something to do with the assembly?)

编辑::您可以去这个网站检查。如果你的只需使用 -S 编译器选项(或没有编译器选项),您将得到同样的结果,因为我做的。 (感谢@Raymond陈为提醒)

You can go to this site to check. If you just use -S compiler option(or no compiler option) you will get the same result as I do. (Thanks @Raymond Chen for reminder)

打开上述网站,并复制以下code至code Eidtor。

Open above site and copy the following code to Code Eidtor.

 #include <stdio.h>
 int main (int argc, char *argv[]) {

   unsigned int j = 10;

   for (; j > -1; --j) {    
      printf("%u", j);
   }
 }

步骤2:

选择 G ++ 4.8 的编译器。的编译器选项是空的。(或-S)

您获得第一种情况。现在,更改 J&GT; -1 J&GT; = -1 ,你可以看到第二个

You get the first situation. Now, change the j > -1 to j >= -1 and you can see the second.

推荐答案

适用的转换是在C标准n1570 S6.3.1.3描述如下:

The applicable conversion is described in the C standard n1570 S6.3.1.3 as follows:

...如果新类型是无符号的值是通过反复增加或转换
  减去超过可重新$ P $在新型psented最大值多一个
  直到该值是在新的类型的范围。

...if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

所以 1 转换为 UINT_MAX 这对32位运算是为0xffffffff。这是相同的位模式,所以在汇编语言方面,它是一个空操作。

So -1 is converted to UINT_MAX which for 32-bit arithmetic is 0xffffffff. This is the same bit pattern, so in assembly language terms it's a no-op.

在第一种情况下,编译器可以建立循环退出条件为循环变量的所有值平凡真。无需进一步的分析和优化的适当水平的循环将被省略。

In the first case the compiler can establish that the loop exit condition is trivially true for all values of the loop variable. No further analysis is needed and at a suitable level of optimisation the loop should be elided.

在第二种情况下没有可用这些琐碎的分析。然而,如果编译器执行数据流分析它会发现,循环退出条件被满足进入循环之前。在优化一个合适的(但可能不同)级这个循环也可以省略。

In the second case there is no such trivial analysis available. However, if the compiler performs a data flow analysis it will discover that the loop exit condition is satisfied before the loop is entered. At a suitable (but perhaps different) level of optimisation this loop can also be elided.

所需的分析是在第二种情况下在每种情况下不同,更难。不过,我不会在意predict该编译器会在何种情况下进行循环省音。你将不得不对其进行测试,找出(像你一样)。

The analysis required is different in each case and harder in the second case. However, I would not care to predict which compilers would perform loop elision in which cases. You would have to test them to find out (as you did).

关于术语的说明:术语省音是一个比较precise说明当一个编译器决定省略code完全。这个词的优化是当编译器对不同的可能code代之间的战略选择更好的利用,或许速度和空间之间进行选择。

A note on terminology: the term elision is a more precise description when a compiler decides to omit code entirely. The term optimisation is better used when the compiler makes choices between different possible code generation strategies, perhaps choosing between speed and space.

这篇关于为什么GCC把两个相似的循环不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆