简体   繁体   English

GCC 编译为程序集:cmp 后跟调用而不是条件跳转

[英]GCC compile to assembly: cmp followed by call instead of conditional jump

Is this assembly code reasonable?这个汇编代码合理吗?

cmp op1, op2
pushf
call _func
popf
jz .L0

I am wondering under what circumstances that GCC as can generate such code that cmp is followed by call instead of conditional jump我想知道在什么情况下 GCC as可以生成这样的代码,即cmp后跟调用而不是条件跳转

No, GCC would never do that, it would always use setz bl or something (in a call-preserved register) if it wanted to materialize a boolean now for use after a call.不,GCC 永远不会那样做,它总是会使用setz bl或其他东西(在调用保留的寄存器中),如果它想现在实现一个布尔值以在调用后使用。 Or just make sure both args to cmp would be available after the call and do or redo the compare then.或者只是确保在调用后到cmp两个 args 都可用,然后执行或重做比较。

Either of these would be much cheaper;这两者中的任何一个都会便宜得多; popf is quite slow because it can modify FLAGS like AC, and (in kernel mode) FLAGS like IF. popf很慢,因为它可以像 AC 一样修改 FLAGS,并且(在内核模式下)像 IF 一样修改 FLAGS。 It needs conditional behaviour depending on CPU mode.它需要取决于 CPU 模式的条件行为。 It's microcoded as many uops.它被微编码为许多 uops。 (Check instruction tables at https://agner.org/optimize/ ). (在https://agner.org/optimize/查看说明表)。 Like 7 on Skylake-X, with a throughput of one per 21 cycles ( https://uops.info ).像 Skylake-X 上的 7 个,每 21 个周期的吞吐量为 1 个 ( https://uops.info )。

If a human programmer really wanted to save / restore multiple FLAGS including ZF, they'd use lahf / mov ebx, eax or something.如果人类程序员真的想保存/恢复多个 FLAGS 包括 ZF,他们会使用lahf / mov ebx, eax或其他东西。 I don't think GCC tends to do that either.我认为 GCC 也不会这样做。

GCC never uses push/pop around a call to save/restore something. GCC 从不在调用周围使用 push/pop 来保存/恢复某些东西。 It reserves space at the top of the function and saves any call-preserved registers it wants to use.它在函数顶部保留空间并保存它想要使用的任何保留调用的寄存器。 To spill something to memory before a call, it would use mov , not push.要在调用之前将某些内容溢出到内存中,它将使用mov而不是 push。

GCC only uses push before a call to pass stack args. GCC 仅在调用之前使用 push 来传递堆栈参数。 But we can rule that out for your example (and assume call _func takes no stack args) because functions own their stack args.但是我们可以排除您的示例(并假设call _func接受堆栈参数),因为函数拥有它们的堆栈参数。 So if pushf had been passing an arg, popf would be popping potential garbage that _func could have stepped on.因此,如果pushf一直在传递 arg,则popf将弹出_func可能踩到的潜在垃圾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM