You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Aarch64 SUB指令基于AddWithCarry实现的原理疑问

Aarch64 SUB指令的AddWithCarry实现与进位机制

你疑惑的核心点其实是为啥用carry_in=1的AddWithCarry实现SUB,却没出现多减1的情况,本质是补码减法的数学逻辑在硬件上的落地:

在补码体系里,x - y完全等价于x + (-y),而负数-y的补码是~y + 1(对y按位取反后加1)。对应到SUB的实现代码:

  • 先对立即数imm取反得到operand2 = NOT(imm)(也就是~imm)
  • 再调用AddWithCarry(operand1, operand2, '1'),这里的进位输入1就是补码转换里必须的那个+1

两者凑在一起,实际计算的就是:

operand1 + ~imm + 1 = operand1 - imm

完全和减法操作等价,自然不会有"额外多减1"的问题。

拿你举的sub sp, sp, #0x20例子来说:

  • imm是0x20,64位下按位取反后是0xFFFFFFFFFFFFFFDF
  • 执行AddWithCarry(sp, 0xFFFFFFFFFFFFFFDF, 1),计算式是sp + 0xFFFFFFFFFFFFFFDF + 1
  • 而0xFFFFFFFFFFFFFFDF + 1正好等于-0x20的64位补码,所以最终结果就是sp - 0x20,和预期完全一致。

再结合AddWithCarry的定义来看,它的unsigned_sum是UInt(x) + UInt(y) + UInt(carry_in),这里y是~imm,carry_in是1,展开后就是:

UInt(x) + (2^N - 1 - UInt(imm)) + 1 = UInt(x) + 2^N - UInt(imm)

因为是N位运算,2^N会被截断掉(相当于模2^N),所以结果就是UInt(x) - UInt(imm),完全符合减法的无符号数计算逻辑。

SUB指令实现代码

bits(datasize) result;
bits(datasize) operand1 = if n == 31 then SP[]<datasize-1:0> else X[n, datasize];
bits(datasize) operand2;
operand2 = NOT(imm);
(result, -) = AddWithCarry(operand1, operand2, '1');
if d == 31 then
    SP[] = ZeroExtend(result, 64);
else
    X[d, datasize] = result;

AddWithCarry操作定义

(bits(N), bits(4)) AddWithCarry(bits(N) x, bits(N) y, bit carry_in)
    integer unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
    integer signed_sum = SInt(x) + SInt(y) + UInt(carry_in);
    bits(N) result = unsigned_sum<N-1:0>; // same value as signed_sum<N-1:0>
    bit n = result<N-1>;
    bit z = if IsZero(result) then '1' else '0';
    bit c = if UInt(result) == unsigned_sum then '0' else '1';
    bit v = if SInt(result) == signed_sum then '0' else '1';
    return (result, n:z:c:v);

简单说,这里的进位位1是补码转加法的关键一步,用来完成"取反加1"里的加1操作,让加法运算的结果等价于减法,所以实际执行时不会有额外偏移,结果完全符合预期。

内容的提问来源于stack exchange,提问作者Jorayen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:01:26