gcc中关于迭代999次的循环有何特别之处?

时间:2019-03-01 22:08:18

标签: 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选项的原因。

1 个答案:

答案 0 :(得分:2)

这基本上是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的价值,我得到了:

$ 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的编译器版本在未优化的情况下不使用这些向量指令,而是有条件jl跳转的序列,并且临界点略有不同,大概是由于其他优化。)