在C ++中强制执行语句顺序 [英] Enforcing statement order in C++

查看:192
本文介绍了在C ++中强制执行语句顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一些语句,我想在
中执行固定顺序。我想使用g ++优化级别2,所以一些
语句可以重新排序。



考虑下面的例子。

  using Clock = std :: chrono :: high_resolution_clock; 

auto t1 = Clock :: now(); // Statement 1
foo(); //语句2
auto t2 = Clock :: now(); //语句3

auto elapsedTime = t2 - t1;

在此示例中,语句1-3在
中执行很重要,订购。但是,编译器认为语句2是不是
独立于1和3并执行代码如下?

  using Clock = std :: chrono :: high_resolution_clock; 

foo(); //语句2
auto t1 = Clock :: now(); //语句1
auto t2 = Clock :: now(); //语句3

auto elapsedTime = t2 - t1;


解决方案

摘要 p>

似乎没有可靠的方法来防止重新排序,但只要链接时/全程序优化未启用,在单独的位置定位被调用的函数编译单元似乎是一个相当好的赌注。 (至少使用GCC,尽管逻辑意味着这可能与其他编译器一样。)这是以函数调用为代价的 - 内联代码是在同一个编译单元中定义的并且可以重新排序。



原始答案



GCC会对-O2优化下的通话进行重新排序:

  #include< chrono> 
static int foo(int x)//'static'或不在这里不影响排序。
{
return x * 2;
}
int fred(int x)
{
auto t1 = std :: chrono :: high_resolution_clock :: now();
int y = foo(x);
auto t2 = std :: chrono :: high_resolution_clock :: now();
return y;
}

GCC 5.3.0:


$ b b

g ++ -S --std = c + + 11 -O0 fred.cpp

  _ZL3fooi:
pushq%rbp
movq%rsp,%rbp
movl%ecx,16(%rbp)
movl 16(%rbp) ,%eax
addl%eax,%eax
popq%rbp
ret
_Z4fredi:
pushq%rbp
movq%rsp,%rbp
subq $ 64,%rsp
movl%ecx,16(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq%rax,-16(%rbp)
movl 16(%rbp) ,%ecx
call _ZL3fooi
movl%eax,-4(%rbp)
call _ZNSt6chrono3_V212system_clock3nowEv
movq%rax,-32(%rbp)
movl -4 (%rbp),%eax
addq $ 64,%rsp
popq%rbp
ret

但:



g ++ -S --std = c ++ 11 -O2 fred.cpp

  _Z4fredi:
pushq%rbx
subq $ 32,%rsp
movl%ecx,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
call _ZNSt6chrono3_V212system_clock3nowEv
leal(%rbx,%rbx),%eax
addq $ 32,%rsp
popq%rbx
ret

现在,使用foo()作为extern函数:

  #include< chrono> 
int foo(int x);
int fred(int x)
{
auto t1 = std :: chrono :: high_resolution_clock :: now();
int y = foo(x);
auto t2 = std :: chrono :: high_resolution_clock :: now();
return y;
}

g ++ -S --std = c ++ 11 -O2 fred.cpp

  _Z4fredi:
pushq%rbx $ b b subq $ 32,%rsp
movl%ecx,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl%ebx,%ecx
call _Z3fooi
movl%eax,%ebx
call _ZNSt6chrono3_V212system_clock3nowEv
movl%ebx,%eax
addq $ 32,%rsp
popq%rbx
ret

但是,如果使用-flto(链接时优化)链接:

  0000000100401710< main>:
100401710:53 push%rbx
100401711:48 83 ec 20 sub $ 0x20,%rsp
100401715:89 cb mov%ecx,%ebx
100401717:e8 e4 ff ff ff callq 100401700< _ _ main>
10040171c:e8 bf f9 ff ff callq 1004010e0< _ZNSt6chrono3_V212system_clock3nowEv>
100401721:e8 ba f9 ff ff callq 1004010e0< _ZNSt6chrono3_V212system_clock3nowEv>
100401726:8d 04 1b lea(%rbx,%rbx,1),%eax
100401729:48 83 c4 20 add $ 0x20,%rsp
10040172d:5b pop%rbx
10040172e:c3 retq


Suppose I have a number of statements that I want to execute in a fixed order. I want to use g++ with optimization level 2, so some statements could be reordered. What tools does one have to enforce a certain ordering of statements?

Consider the following example.

using Clock = std::chrono::high_resolution_clock;

auto t1 = Clock::now(); // Statement 1
foo();                  // Statement 2
auto t2 = Clock::now(); // Statement 3

auto elapsedTime = t2 - t1;

In this example it is important that the statements 1-3 are executed in the given order. However, can't the compiler think statement 2 is independent of 1 and 3 and execute the code as follows?

using Clock=std::chrono::high_resolution_clock;

foo();                  // Statement 2
auto t1 = Clock::now(); // Statement 1
auto t2 = Clock::now(); // Statement 3

auto elapsedTime = t2 - t1;

解决方案

Summary:

There seems to be no guaranteed way to prevent reordering, but as long as link-time/full-program optimisation is not enabled, locating the called function in a separate compilation unit seems a fairly good bet. (At least with GCC, although logic would suggest that this is likely with other compilers too.) This comes at the cost of the function call - inlined code is by definition in the same compilation unit and open to reordering.

Original answer:

GCC reorders the calls under -O2 optimisation:

#include <chrono>
static int foo(int x)    // 'static' or not here doesn't affect ordering.
{
    return x*2;
}
int fred(int x)
{
    auto t1 = std::chrono::high_resolution_clock::now();
    int y = foo(x);
    auto t2 = std::chrono::high_resolution_clock::now();
    return y;
}

GCC 5.3.0:

g++ -S --std=c++11 -O0 fred.cpp :

_ZL3fooi:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %ecx, 16(%rbp)
        movl    16(%rbp), %eax
        addl    %eax, %eax
        popq    %rbp
        ret
_Z4fredi:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $64, %rsp
        movl    %ecx, 16(%rbp)
        call    _ZNSt6chrono3_V212system_clock3nowEv
        movq    %rax, -16(%rbp)
        movl    16(%rbp), %ecx
        call    _ZL3fooi
        movl    %eax, -4(%rbp)
        call    _ZNSt6chrono3_V212system_clock3nowEv
        movq    %rax, -32(%rbp)
        movl    -4(%rbp), %eax
        addq    $64, %rsp
        popq    %rbp
        ret

But:

g++ -S --std=c++11 -O2 fred.cpp :

_Z4fredi:
        pushq   %rbx
        subq    $32, %rsp
        movl    %ecx, %ebx
        call    _ZNSt6chrono3_V212system_clock3nowEv
        call    _ZNSt6chrono3_V212system_clock3nowEv
        leal    (%rbx,%rbx), %eax
        addq    $32, %rsp
        popq    %rbx
        ret

Now, with foo() as an extern function:

#include <chrono>
int foo(int x);
int fred(int x)
{
    auto t1 = std::chrono::high_resolution_clock::now();
    int y = foo(x);
    auto t2 = std::chrono::high_resolution_clock::now();
    return y;
}

g++ -S --std=c++11 -O2 fred.cpp :

_Z4fredi:
        pushq   %rbx
        subq    $32, %rsp
        movl    %ecx, %ebx
        call    _ZNSt6chrono3_V212system_clock3nowEv
        movl    %ebx, %ecx
        call    _Z3fooi
        movl    %eax, %ebx
        call    _ZNSt6chrono3_V212system_clock3nowEv
        movl    %ebx, %eax
        addq    $32, %rsp
        popq    %rbx
        ret

BUT, if this is linked with -flto (link-time optimisation):

0000000100401710 <main>:
   100401710:   53                      push   %rbx
   100401711:   48 83 ec 20             sub    $0x20,%rsp
   100401715:   89 cb                   mov    %ecx,%ebx
   100401717:   e8 e4 ff ff ff          callq  100401700 <__main>
   10040171c:   e8 bf f9 ff ff          callq  1004010e0 <_ZNSt6chrono3_V212system_clock3nowEv>
   100401721:   e8 ba f9 ff ff          callq  1004010e0 <_ZNSt6chrono3_V212system_clock3nowEv>
   100401726:   8d 04 1b                lea    (%rbx,%rbx,1),%eax
   100401729:   48 83 c4 20             add    $0x20,%rsp
   10040172d:   5b                      pop    %rbx
   10040172e:   c3                      retq

这篇关于在C ++中强制执行语句顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆