我们考虑以下程序,这只是定时循环:
#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相同的循环?
解决方法:
当您使我不稳定时,您告诉编译器它不知道的某些内容可以更改其值.这意味着每次使用它时都必须加载它的值,并且每次写入它时都必须存储它.当我不稳定时,编译器可以优化该同步.