编译器是否检测到多次计算的变量?

Does compiler detect variables that are calculated more than one time?

我的问题涉及以下构造:

uint16_t flag = 0x1f;
while (curCase) {
        if ((curCase->i == i) && (curCase->j == j)) flag ^= 0x10;
        if ((curCase->i == i-1) && (curCase->j == j)) flag ^= 0x01;         
        if ((curCase->i == i) && (curCase->j == j+1)) flag ^= 0x02;
        if ((curCase->i == i+1) && (curCase->j == j)) flag ^= 0x04;
        if ((curCase->i == i) && (curCase->j == j-1)) flag ^= 0x08;
        if (!(flag ^ 0xf0)) return; // if none of the neighbors are candidates (ignore first bits)
        curCase = curCase->suiv;
    }

curCase只是链表的一个元素,有2个int属性i和j,下一个元素suiv;

知道我的程序在单线程上运行,因此指向的值在 while 的迭代期间不能改变;

我想知道编译器是否足够聪明(我想答案是肯定的,但我想确定)来检测代码是否需要计算指针 curCase->i 和 curCase-> j 5 次,我本可以在循环开始时声明 2 个临时指针并分配 curCase->i 和 curCase->j;

更普遍的是,如果它检测到多次计算的变量并因此进行优化。

我已经用不同的列表大小对这两个选项进行了测试,但我没有发现一个比另一个快得多。

对于这种大小的代码,很难找到基于编译器优化的性能差异(只是评论)。我 认为 这完全取决于编译器实现,它可以完成,但这取决于对范围的分析。

为了检验假设,我对您的代码进行了一些调整以使用 Compile Explorer,如下所示:

struct cur { int i; int j; void * suiv;} typedef cur;
int i;
int j;

void function(cur *curCase) {
    int flag = 0x1f;
    while (curCase) {
        if ((curCase->i == i) && (curCase->j == j)) flag ^= 0x10;
        if ((curCase->i == i-1) && (curCase->j == j)) flag ^= 0x01;         
        if ((curCase->i == i) && (curCase->j == j+1)) flag ^= 0x02;
        if ((curCase->i == i+1) && (curCase->j == j)) flag ^= 0x04;
        if ((curCase->i == i) && (curCase->j == j-1)) flag ^= 0x08;
        if (!(flag ^ 0xf0)) return; // if none of the neighbors are candidates (ignore first bits)
        curCase = curCase->suiv;
    }
}

而且 gcc 和 CLang 的汇编代码似乎没有隔离您提到的指令。

你可以在这里找到代码分析:https://godbolt.org/z/afQxxd

正如我在评论中所述,您必须告诉编译器进行优化,否则它不会做太多事情。此外,标志未使用,因此我将其修改为 returned,以便编译器会关心它。

这里是对 return 和 flag 稍作修改的同一示例,并进行了优化,以便您可以看到编译器真正可以做什么。

https://godbolt.org/z/B_maur