gpt4 book ai didi

了解 "volatile"关键字和比较的工作原理

转载 作者:太空宇宙 更新时间:2023-11-04 05:22:37 26 4
gpt4 key购买 nike

如果未使用关键字 volatile 指定变量,编译器可能会进行缓存。变量必须总是从内存访问,否则直到它的事务单元结束。我想知道的一点在于组装部分。

int main() {
/* volatile */ int lock = 999;
while (lock);
}

关于 x86-64-clang-3.0.0 compiler ,其汇编代码如下。

main:                                   # @main
mov DWORD PTR [RSP - 4], 0
mov DWORD PTR [RSP - 8], 999


.LBB0_1: # =>This Inner Loop Header: Depth=1
cmp DWORD PTR [RSP - 8], 0
je .LBB0_3
jmp .LBB0_1


.LBB0_3:
mov EAX, DWORD PTR [RSP - 4]
ret

当注释volatile关键字时,结果如下。

main:                                   # @main
mov DWORD PTR [RSP - 4], 0
mov DWORD PTR [RSP - 8], 999


.LBB0_1: # =>This Inner Loop Header: Depth=1
mov EAX, DWORD PTR [RSP - 8]
cmp EAX, 0
je .LBB0_3
jmp .LBB0_1


.LBB0_3:
mov EAX, DWORD PTR [RSP - 4]
ret

我想知道和不明白的地方,

  • cmp DWORD PTR [RSP - 8], 0 . <---为什么用 0 进行比较,而 DWORD PTR [RSP - 8] 包含 999
  • 为什么 DWORD PTR [RSP - 8] 被复制到 EAX 中,为什么要在 0EAX 之间进行比较?

最佳答案

您似乎忘记启用优化。 -O0 处理所有 变量(register 变量除外)pretty similarly to volatile for consistent debugging .

启用优化后,编译器可以将非 volatile 负载提升到循环之外。 while(locked); 将像源代码一样编译

if (locked) {
while(1){}
}

或者由于 locked 有一个编译时常量初始化器,整个函数应该编译为 jmp main(一个无限循环)。

参见 MCU programming - C++ O2 optimization breaks while loop 了解更多详情。


Why is DWORD PTR [RSP - 8] copied into EAX and again why is the comparison done between 0 and EAX?

当您使用 volatile 时,一些编译器在将负载折叠到其他指令的内存操作数方面表现较差。我想这就是为什么你在这里得到一个单独的 mov 加载;这只是一个错过的优化。

(尽管 cmp [mem], imm 可能不太有效。我忘了它是否可以与 JCC 或其他东西进行宏融合。使用 RIP 相对寻址模式下它不能微熔断负载,但寄存器基数是可以的。)


cmp EAX, 0 很奇怪,我猜禁用优化的 clang 不会寻找 test eax,eax 作为与零比较的窥孔优化。

正如@user3386109 评论的那样, bool 上下文中的 locked 等同于 C/C++ 中的 locked != 0

关于了解 "volatile"关键字和比较的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55135478/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com