GCC缓存循环变量吗?

Mui*_*uis 2 c optimization performance gcc c99

当我有一个像这样的循环:

for (int i = 0; i < SlowVariable; i++)
{
   //
}
Run Code Online (Sandbox Code Playgroud)

我知道在VB6中,SlowVariable每次迭代循环都会访问它,使得以下内容更有效:

int cnt = SlowVariable;

for (int i = 0; i < cnt; i++)
{
   //
}
Run Code Online (Sandbox Code Playgroud)

我是否需要在GCC中进行相同的优化?或者它只评估SlowVariable一次?

Ste*_*sop 5

这被称为"悬挂" SlowVariabele循环.

只有当它能够证明SlowVariabele每次的值相同时,编译器才能这样做,并且评估SlowVariabele没有副作用.

因此,例如考虑以下代码(我假设为了示例,通过指针访问由于某种原因"慢"):

void foo1(int *SlowVariabele, int *result) {
    for (int i = 0; i < *SlowVariabele; ++i) {
       --*result;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器不能(通常)提升,因为它知道它将被调用result == SlowVariabele,因此值*SlowVariabele在循环期间发生变化.

另一方面:

void foo2(int *result) {
    int val = 12;
    int *SlowVariabele = &val;
    for (int i = 0; i < *SlowVariabele; ++i) {
       --*result;
    }
}
Run Code Online (Sandbox Code Playgroud)

至少在原理上,编译器可以知道val循环中永远不会发生变化,因此它可以提升.它是否真的这样做是因为优化器的积极程度以及它对函数的分析有多好,但我希望任何认真的编译器能够胜任它.

类似地,如果foo1使用指针调用,编译器可以确定(在调用站点处)是不相等的,并且如果调用内联,则编译器可以提升.这restrict是为了:

void foo3(int *restrict SlowVariabele, int *restrict result) {
    for (int i = 0; i < *SlowVariabele; ++i) {
       --*result;
    }
}
Run Code Online (Sandbox Code Playgroud)

restrict(在C99中引入)意味着"你不能用result == SlowVariabele" 调用这个函数",并允许编译器提升.

同理:

void foo4(int *SlowVariabele, float *result) {
    for (int i = 0; i < *SlowVariabele; ++i) {
       --*result;
    }
}
Run Code Online (Sandbox Code Playgroud)

严格的别名规则意味着SlowVariable并且result不得引用相同的位置(或者程序具有未定义的行为),因此编译器也可以提升.