Loops 在x86/x86_64中,我如何;如果不是零,则跳转“;不影响进位标志?

Loops 在x86/x86_64中,我如何;如果不是零,则跳转“;不影响进位标志?,loops,assembly,x86,compare,x86-64,Loops,Assembly,X86,Compare,X86 64,我有一个循环,它本质上是添加两个动态宽度整数(实际上,它稍微展开了一点,但这在这里并不重要)。寄存器RCX包含目标地址,RDX包含源地址,R8包含数组长度 clc # Clear CF flag before beginning .Lloop0: movq (%rdx), %rax # Load memory for next addition adcq %rax, (%rcx) # Perform additio

我有一个循环,它本质上是添加两个动态宽度整数(实际上,它稍微展开了一点,但这在这里并不重要)。寄存器
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
复制
标志
寄存器,并在循环开始时使用
SAHF
还原它,但如果有办法,我希望避免这种情况。

您可以交换上面
%r8
%rcx
的角色以产生:

    clc
    .p2align 4 # just a thought...
.Lloop0:
    jrcxz .Lloop0_end
    ...
    leaq  -1(%rcx), %rcx
    jmp   .Lloop0
.Lloop0_end:

您可以使用
dec%r8
,但请注意,不建议这样做,因为不更新
CF
会导致部分标志寄存器暂停:)它会自动设置
ZF
。您只需执行
dec%r8;jnz Lloop0
。或者,您可以重写代码以使用
rcx
作为计数器,然后使用
循环
指令(这也是不推荐的,但不如
dec
:)x86 CPU是复杂的。
JNZ
将根据分支预测推测执行,因此如果您多次循环,它应该是有效的。您还可以使用
rcx
(而不是
r8
)作为计数器和
循环
指令。
loop
指令隐式地使用
rcx
作为计数器,并且不影响进位标志。如果
rcx
不为零,则不会出现类似于
JRCXNZ
的情况。不,这不存在,@matt。但实际上没有理由使用
jrcxz
或神秘的
jrcxnz
。这比将指令分成两部分要慢。