【问题标题】:In x86/x86_64, how can I "jump if not zero" without affecting the carry flag?在 x86/x86_64 中,如何在不影响进位标志的情况下“不为零就跳转”?
【发布时间】: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


【解决方案1】:

你可以将上面%r8%rcx的角色互换为yield:

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

【讨论】:

  • 不会碰巧有像JRCXNZ 这样的东西,如果RCX 为零,它会跳转?
  • 不,那不存在,@matt。但实际上没有理由使用jrcxz 或神话般的jrcxnz。它比将指令分成两部分要慢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多