对于每条指令,都记录了它是否(以及如何)编写 EFLAGS。Intel 的指令集参考手册在每条指令的条目中都有一个 Flags Affected 部分。对于某些人来说,它只是无。
http://ref.x86asm.net/coder32.html有一个方便的指令表,包括一列显示它们读取和修改的标志,以及哪些修改的标志是明确定义的还是未定义的。(单击列标题以获取说明)。
大多数整数 ALU 指令,如sub
and add
,会“根据结果”更新 FLAGS;这是设置 SF = 高位等常见描述的地方。cmp
类似的 指令test
只产生一个 FLAGS 结果,不修改任何一个整数输入。
lea
并且not
是不设置标志的值得注意的 ALU 异常。数据移动指令不设置 FLAGS,例如mov
和push
/ pop
。例如受影响的标志:无。
inc
/dec
设置除 CF 之外的标志,它们保持不变。(大多数 CPU 仍然可以有效地处理这个问题)
SSE 和 fp 指令addsd xmm, xmm/mem
通常不会写入标志。comisd xmm, xmm/mem
您可以使用(SSE2) 或fcomi st?
(x87 + Pentium Pro)在现代 x86 上将 FP 与 EFLAGS 进行比较。
英特尔第 2 卷手册中的一些示例:
以“有趣”方式编写标志的指令通常也在其“操作”部分伪代码中定义这一点。例如bsf
add
:受影响的标志
OF、SF、ZF、AF、CF 和 PF 标志根据结果设置。
(如果您查看 Intel 的 vol.2 手册或 vol.1 的 PDF,我认为他们准确地定义了“根据结果”的含义。)
imul
:受影响的标志:
对于单操作数形式的指令,当有效位进入结果的上半部分时设置 CF 和 OF 标志,并在结果正好适合结果的下半部分时清除标志。对于指令的二操作数和三操作数形式,当结果必须被截断以适合目标操作数大小时设置 CF 和 OF 标志,并在结果完全适合目标操作数大小时清除。SF、ZF、AF 和 PF 标志未定义。
sar
//shl
shr
受影响的标志:
CF 标志包含移出目标操作数的最后一位的值;对于计数大于或等于目标操作数的大小(以位为单位)的 SHL 和 SHR 指令,它是未定义的。OF 标志仅对 1 位移位产生影响(参见上面的“说明”);否则,它是未定义的。根据结果设置 SF、ZF 和 PF 标志。如果计数为 0,则标志不受影响。对于非零计数,AF 标志未定义。
为 count=0 保留未修改的标志是高性能实现要处理的另一个疯狂的 CISC 坑。(微架构必须为正确实现 x86 语义而支付的“x86 税”的一部分)。在英特尔 Sandybridge 系列上,这意味着可变计数移位(使用 count in cl
)解码为 3 uop。SHLX(BMI2 无标志移位)只有 1 uop。
另一种回答“频率”问题的方法:每个时钟周期最多 4 次。或 5 在 Zen 或 Ice Lake。(每条指令最多一次。)
现代英特尔 CPU 是 4 宽超标量。它们可以在同一时钟周期内重命名 EFLAGS 4 次,允许它们在add reg,reg
每个时钟周期运行 4 条独立指令,每条指令将其标志结果写入逻辑 EFLAGS 寄存器,但实际上是不同的物理寄存器。(并且真的在保存整数结果的物理寄存器上搭载 EFLAGS 输出,除非这样cmp
的指令没有整数结果。)
见https://agner.org/optimize/