snr*_*snr 0 c assembly x86-64 volatile
如果未使用关键字指定变量volatile,则编译器可能会进行缓存。必须始终从内存访问该变量,否则直到其事务单元结束。我想知道的重点在于装配零件。
int main() {
/* volatile */ int lock = 999;
while (lock);
}
Run Code Online (Sandbox Code Playgroud)
在x86-64-clang-3.0.0编译器上,其汇编代码如下。
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
Run Code Online (Sandbox Code Playgroud)
当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
Run Code Online (Sandbox Code Playgroud)
我想知道和不理解的要点
cmp DWORD PTR [RSP - 8], 0。<---为什么比较完成的0,同时DWORD PTR [RSP - 8]拥有999内?DWORD PTR [RSP - 8]复制到中EAX,为什么还要在0和之间进行比较EAX?您好像忘记了启用优化。 -O0对待所有变量(变量除外register)的方式与volatile一致性调试非常相似。
启用优化后,编译器可以将非易失性负载提升到循环之外。while(locked);将像源一样编译
if (locked) {
while(1){}
}
Run Code Online (Sandbox Code Playgroud)
或由于locked具有编译时常数初始化器,因此整个函数应编译为jmp main(无限循环)。
有关更多详细信息,请参见MCU编程-C ++ O2优化在循环时中断。
为什么要
DWORD PTR [RSP - 8]复制到EAX中,又为什么要在0和EAX之间进行比较?
当您使用时,某些编译器在将负载折叠到其他指令的内存操作数中时效果更差volatile。我认为这就是为什么您在mov这里得到单独的负担。这只是一个错过的优化。
(尽管效率cmp [mem], imm可能较低。我忘记了它是否可以与JCC或其他宏宏融合。在具有RIP相对寻址模式的情况下,它无法对融合负载进行微融合,但是寄存器基可以。)
cmp EAX, 0很奇怪,我猜禁用优化的clang不会test eax,eax作为比较零的窥视孔优化。
正如@ user3386109所评论的,locked在布尔上下文中等效locked != 0于C / C ++。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |