范围与编译器优化的相关性

时间:2019-04-05 15:46:26

标签: c++ scope compiler-optimization

我有一个library,它在编译时进行了大量的循环展开。我还使用了基准标记工具,该工具通过实例化作用域内的结构来工作,在销毁时它会测量从创建到销毁之间的时间并返回收集的值。现在,通过在其中插入一些函数调用,它可以测量函数调用的时间。我想知道的是,编译器可以跳转范围吗?(请参见下面的代码)

PerfEvent ev;
{
    PerfEventBlock bl(ev, countPE);
    ev.setParam("name","FTensor3D");
    res(l,m,n,o) = t1(l,m,k)*t2(k,n,o);
}

或者换句话说:编译器可以将“外包”工作扩展到范围之外(我得到了奇怪的结果并且很纳闷)

2 个答案:

答案 0 :(得分:4)

只要代码的可观察结果(由标准定义)相同-在优化之前和之后,编译器就可以进行所需的任何转换

注意:例如,执行速度不是 视为可观察的结果。另外,如果您的程序包含未定义行为,则任何结果是可以接受的。

答案 1 :(得分:2)

如果您的PerfEventBlock构造函数和析构函数执行系统调用,则编译器将无法证明它没有可观察到的副作用。但是,只要能够证明这样做不会从抽象机器的角度改变可观察到的行为,它仍然可以(理论上)在这些代码之前或之后对间歇代码进行重新排序。另请参见here

示例:

void inc(int& a) { ++a; }

void foo();

int bar()
{
    int a = 1;
    foo();
    inc(a);
    foo();
    return a;
}

https://godbolt.org/z/gOr7aU

编译器不知道foo()所做的事情,因此必须假定存在明显的副作用。尽管如此,您仍可以在程序集中看到inc如此琐碎,编译器将其内联(并固定折叠)。在这两种副作用之间,没有义务执行inc(a)中涉及的任何内容,因为inc本身本身没有外部可观察到的效果。

因此,编译器可能会将您要分析的代码从PerfEventBlock的构造函数和析构函数之间移出。实际上,通过链接时优化,此选项可以在表上的保留位置超出您的想象(对另一个编译单元的函数调用-如此处的foo()-对于编译器而言可能是不透明的,但对链接器而言是不透明的)。