【发布时间】:2015-04-18 10:33:11
【问题描述】:
我有这个循环,它本质上添加了两个动态宽度的整数(实际上,它被展开了一点,但这并不重要)。寄存器RCX包含目标地址,RDX包含源地址,R8包含数组长度。
clc # Clear CF flag before beginning
.Lloop0:
movq (%rdx), %rax # Load memory for next addition
adcq %rax, (%rcx) # Perform addition with carry (i.e. using CF flag)
leaq 8(%rcx), %rcx # Increment destination address (without affecting CF)
leaq 8(%rdx), %rdx # Increment source address (without affecting CF)
leaq -1(%r8), %r8 # Decrement length (without affecting CF)
testq %r8, %r8 # Test if length is zero (affects CF!)
jne Lloop0
问题在于TEST 指令清除了CF 标志,这是下一个ADC 所需要的。 CMP 指令也会产生类似的效果。
我当然可以在测试前使用LAHF 复制FLAGS 寄存器,并在循环开始时使用SAHF 恢复它,但如果有办法绕过它,我想避免这种情况。
【问题讨论】:
-
您可以使用
dec %r8,但请注意不建议这样做,因为不更新CF会导致部分标志寄存器停止:) -
它自动设置
ZF。你可以做dec %r8; jnz Lloop0。 -
或者,您可以重写代码以使用
rcx作为计数器,然后使用loop指令(这也不推荐,但不如dec:)) -
x86 cpus 是复杂的野兽。
JNZ会根据分支预测推测执行,所以如果循环多次,应该是有效率的。 -
您也可以使用
rcx(而不是r8)作为您的计数器和loop指令。loop指令隐式使用rcx作为计数器,不影响进位标志。
标签: loops assembly x86 compare x86-64