c - gcc 中关于迭代 999 次的循环有什么特别之处?

标签 c gcc

背景

使用 gcc 7.2 我发现当循环迭代 999 次时编译器输出会发生变化。

特别是这个程序(link to compiler explorer using gcc 7.2):

int f()
{
    int i=0x7fffffff-998;
    while (i+1>i)
        i++;
    return i;
}

编译(使用 -O3 -fwrapv)为:

f():
  mov eax, 2147483647
  ret

但是,如果我将 998 更改为 999,它会编译为:

f():
  xor eax, eax
  movdqa xmm0, XMMWORD PTR .LC0[rip]
  movdqa xmm2, XMMWORD PTR .LC1[rip]
  jmp .L2
.L3:
  movdqa xmm0, xmm1
.L2:
  movdqa xmm1, xmm0
  add eax, 1
  cmp eax, 250
  paddd xmm1, xmm2
  jne .L3
  pshufd xmm0, xmm0, 255
  movd eax, xmm0
  ret
.LC0:
  .long 2147482648
  .long 2147482649
  .long 2147482650
  .long 2147482651
.LC1:
  .long 4
  .long 4
  .long 4
  .long 4

问题

为什么输出会改变,是否有一个开关来控制行为改变的阈值?

注意事项

由于有符号溢出是未定义的行为,默认情况下编译器会将此程序变成无限循环。这就是编译期间需要 -fwrapv 选项的原因。

最佳答案

这基本上是 GCC 源代码中任意常量的结果。

GCC 有一个内部参数,用于控制在优化过程中循环暂时展开的次数:

/* The maximum number of iterations of a loop the brute force algorithm
   for analysis of # of iterations of the loop tries to evaluate.  */
DEFPARAM(PARAM_MAX_ITERATIONS_TO_TRACK,
        "max-iterations-to-track",
        "Bound on the number of iterations the brute force #"
        " of iterations analysis algorithm evaluates.",
        1000, 0, 0)

如果 GCC 没有特殊的逻辑来执行某种代数转换以获得迭代计数,这将用于分析循环。

如果您将此参数更改为不同的值,则从结果到另一个的切换将以不同的魔法值发生。有了你原来的 998 值(value),我得到这个:

$ gcc -O3 -fwrapv -S -o- --param max-iterations-to-track=997 t.c | grep jl
    jl  .L3
$ gcc -O3 -fwrapv -S -o- --param max-iterations-to-track=998 t.c | grep jl
    jl  .L3
$ gcc -O3 -fwrapv -S -o- --param max-iterations-to-track=999 t.c | grep jl
$ gcc -O3 -fwrapv -S -o- --param max-iterations-to-track=1000 t.c | grep jl

这些参数是一个内部实现细节,可以随时改变含义,或者完全消失。

(我使用的编译器版本,基于GCC 6.3,没有使用那些未优化情况下的 vector 指令,而是一个有条件的jl跳转的序列,截断点略微不同,大概是由于其他优化。)

关于c - gcc 中关于迭代 999 次的循环有什么特别之处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54952960/

相关文章:

c - 是否是 memcpy 所期望的

c - C 中的返回值函数

c++ - 如何以跨本地方式在 Crosstools-NG 中使用 canadian 以在 arm board 上获取 gcc?

C++ 错误 : was not declared in this scope with private after public

c - strlen 函数的意外输出

C/C++ : Disable mouse in Linux (X11 - xinput)

c - 如何做好复杂功能的基准测试?

限制 gcc 内联 x86_64 程序集中的 r10 寄存器

C++11 std::regex_match 返回额外字符

c++ - 简单类的GCC去虚拟化