c-了解易失性asm与易失性变量

我们考虑以下程序,这只是定时循环:

#include <cstdlib>

std::size_t count(std::size_t n)
{
#ifdef VOLATILEVAR
    volatile std::size_t i = 0;
#else
    std::size_t i = 0;
#endif
    while (i < n) {
#ifdef VOLATILEASM
        asm volatile("": : :"memory");
#endif
        ++i;
    }
    return i;
}

int main(int argc, char* argv[])
{
    return count(argc > 1 ? std::atoll(argv[1]) : 1);
}

为了便于阅读,具有volatile变量和volatile asm的版本如下:

#include <cstdlib>

std::size_t count(std::size_t n)
{
    volatile std::size_t i = 0;
    while (i < n) {
        asm volatile("": : :"memory");
        ++i;
    }
    return i;
}

int main(int argc, char* argv[])
{
    return count(argc > 1 ? std::atoll(argv[1]) : 1);
}

在g 8下使用g -Wall -Wextra -g -std = c 11 -O3循环进行编译.cpp -o循环大致给出以下时序:

>默认值:0m0.001s
> -DVOLATILEASM:0m1.171s
> -DVOLATILEVAR:0m5.954s
> -DVOLATILEVAR -DVOLATILEASM:0m5.965s

我的问题是:为什么呢?默认版本是正常的,因为编译器已对循环进行了优化.但是我很难理解为什么-DVOLATILEVAR比-DVOLATILEASM更长,因为两者都应强制循环运行.

Compiler explorer为-DVOLATILEASM提供以下计数功能:

count(unsigned long):
  mov rax, rdi
  test rdi, rdi
  je .L2
  xor edx, edx
.L3:
  add rdx, 1
  cmp rax, rdx
  jne .L3
.L2:
  ret

对于-DVOLATILEVAR(以及组合的-DVOLATILEASM -DVOLATILEVAR):

count(unsigned long):
  mov QWORD PTR [rsp-8], 0
  mov rax, QWORD PTR [rsp-8]
  cmp rdi, rax
  jbe .L2
.L3:
  mov rax, QWORD PTR [rsp-8]
  add rax, 1
  mov QWORD PTR [rsp-8], rax
  mov rax, QWORD PTR [rsp-8]
  cmp rax, rdi
  jb .L3
.L2:
  mov rax, QWORD PTR [rsp-8]
  ret

为什么会这样呢?为什么变量的volatile限定条件阻止编译器执行与asm volatile相同的循环?

解决方法:

当您使我不稳定时,您告诉编译器它不知道的某些内容可以更改其值.这意味着每次使用它时都必须加载它的值,并且每次写入它时都必须存储它.当我不稳定时,编译器可以优化该同步.

上一篇:linux-汇编和系统调用


下一篇:c – 使用xchg时我们需要mfence吗?