为了有效地做到x = x*10 + 1,它可能是最佳使用方式
lea eax, [rax + rax*4] ; x*=5
lea eax, [1 + rax*2] ; x = x*2 + 1
3-component LEA has higher latency关于现代英特尔CPU,例如3个周期与Sandybridge系列的1个周期相比,所以 disp32 + index2 is faster than disp8 + base + index1 on SnB-family ,即我们关心优化的大多数主流x86 CPU . (这主要仅适用于LEA,而不适用于加载/存储,因为LEA在ALU执行单元上运行,而不是在大多数现代x86 CPU中运行 . )AMD CPU具有3个组件的LEA较慢或 scale > 1
(http://agner.org/optimize/)
但是NASM和YASM将使用 [1 + rax + rax*1]
为第二个LEA优化代码大小,它只需要一个disp8而不是一个disp32 . (寻址模式始终具有基址寄存器或disp32) .
即他们总是将 reg*2
分成 base+index
,因为对于代码大小来说,这永远不会更糟 .
我可以强制使用带有 lea eax, [dword 1 + rax*2]
的disp32,但是这似乎没有记录在比例因子上使用the strict keyword的方法,并且 [1 + strict rax*2]
没有汇编 . Is there a way to use strict or some other syntax to force the desired encoding of an addressing mode ?
nasm -O0
禁用优化不起作用 . 显然,只控制多次通过分支位移优化,而不是NASM所做的所有优化 . 当然,您不希望首先对整个源文件执行此操作,即使它确实有效 . 我还是得到的
8d 84 00 01 00 00 00 lea eax,[rax+rax*1+0x1]
我能想到的唯一解决方法是使用 db
手动编码 . 这非常不方便 . 为了记录,手动编码是:
db 0x8d, 0x04, 0x45 ; opcode, modrm, SIB for lea eax, [disp32 + rax*2]
dd 1 ; disp32
比例因子编码在SIB字节的高2位中 . 我收集了 lea eax, [dword 1 + rax*4]
以获取正确寄存器的机器代码,因为NASM的优化仅适用于 *2
. SIB为 0x85
,并且递减字节顶部的2位字段将比例因子从4减小到2 .
但问题是: how to write it in a nicely readable way that makes it easy to change registers, and get NASM to encode the addressing mode for you? (我想一个巨大的宏可以通过文本处理和手动 db
编码实现这一点,但是's not really the answer I' m正在寻找 . 我现在实际上并不需要这个,我主要是想知道NASM还是YASM有语法强迫这个 . )
我所知道的其他优化,如 mov rax, 1
汇编到5字节 mov eax,1
是所有CPU上的纯胜利,除非你想要更长的指令来获得没有NOP的填充,and can be disabled用 mov rax, strict dword 1
来获得7字节符号扩展编码,或 strict qword
for 10字节的imm64 .
天然气不做这个或大多数其他优化(只有立即和分支位移的大小): lea 1(,%rax,2), %eax
汇编到8d 04 45 01 00 00 00 lea eax,[rax*2+0x1]
,和 .intel_syntax noprefix
版本相同 .
但是MASM或其他汇编程序的答案也会很有趣 .
1 回答
NOSPLIT: