SUB指令的目的是什么?
What is the purpose of SUB Instruction?
我正在自学汇编,有一个困惑想解决。
据我了解,x86 计算机使用相同的电路进行加法和减法。对于减法,负数被转换为其 2 补码,然后加法电路可用于执行减法。例如:等式4 - 2
转换为4 + (-2)
所以如果减法可以使用 2 补码完成,那么 SUB
指令的目的是什么?
在2的补码世界中,整数的取反可以通过取1的补码(所有位取反)加1得到。例如,在8位世界中:
A: 0x00000002 ; my number
~A: 0xFFFFFFFD ; 1's complement of my number
-A: 0xFFFFFFFE ; 2's complement of my number (negative A)
要减去A-B
,当然可以加上负数,A+(-B)
:
NOT B ; invert each bit in the 8-bit value, B
ADD B, 1 ; add 1, giving the 2's complement negated B
ADD A, B
当然,我必须先修改 B
(否定它),然后才能添加它。如果我希望 B
保持完整怎么办?
PUSH B ; save B
NOT B ; invert each bit in the 8-bit value, B
INC A ; add 1, giving the 2's complement negated B
ADD A, B
POP B ; restore B
或者
NOT B ; invert each bit in the 8-bit value, B
INC A ; add 1, giving the 2's complement negated B
ADD A, B
NOT B ; restore B
这样就可以了。但是如果有一个 SUB
指令不是更容易吗?
SUB A, B
如果您编写汇编语言来进行大量算术运算,您更喜欢哪种方法?而且,在第一种情况下,我使用了 INC A
指令。我可以在没有 INC
的情况下逃脱,只需使用 ADD A, 1
。但是在许多微处理器上,ADD A, 1
要求我从指令存储器中获取更多内容以执行以获得立即的 1
值。因此,由于这种操作很常见,所以提供了 INC
。
当微处理器设计人员确定要使用的指令集时,他们会考虑最常用的操作类型。减法很常见,所以 SUB
指令非常方便。因此,它几乎存在于您能找到的任何指令集中。指令集中还有其他指令,其存在的原因不太明显。例如,x86 有 XLAT
指令,以及所有 "string" 指令,LODS
、STOS
等。当我可以做到所有这些时,为什么它们存在使用 MOV
和 INC
等?因为有人认为这些操作足够普遍,值得使用一条指令。
所以 SUB
指令背后的目的,就像 CPU 实现的许多其他指令一样,是提供一种更快(执行时间)和更简单的方法来执行最常执行的操作软件,与可以执行的指令数量存在实际限制这一事实相平衡。
TL;DR
因为它是最常见的操作之一,所以有专门的指令有助于提高速度。设计师知道如何让它变得更快,并且不需要像你想象的那样单独取反
从David Money Harris, Sarah L. Harris的计算机体系结构名著Computer Organization and Design, Fourth Edition: The Hardware/Software Interface by David A. Patterson and John L. Hennessy and Digital Design and Computer Architecture中我们知道MIPS的设计原则如下
- 设计原则1:简单有利于规律。
- 设计原则 2:快速处理常见情况。
- 设计原则3:越小越快
- 设计原则 4:好的设计需要好的妥协。
这些在其他架构中也是正确的。在 x86 和许多其他(主要是较旧的)体系结构中,由于向后兼容性,有些无法实现,但要点适用。
由于1st和3rd原则,我们需要使指令集尽可能紧凑可能 并且如果我们可以使用其他指令来创建新指令,则不要创建新指令。然而,根据原则 2 和 4,我们需要使常见操作尽可能快。
事实上大多数指令都是冗余的因为我们可以拥有图灵完备指令集只有one instruction. x86 itself is not an OISC architecture but it's still possible to do anything with just a single mov
or add
/sub
because they're proved to be Turing-complete. There's even a compiler to compile valid C code into a program with only MOV (or only either of XOR, SUB, ADD, XADD, ADC, SBB, AND/OR, PUSH/POP, 1-bit shifts, or CMPXCHG/XCHG) named movfuscator
因此,使用 add
或 sub
我们可以轻松获得移位、按位运算和 multiplication/division。然而,这些基本操作可能需要非常长的一系列指令来模拟,用户不会对此感到满意。
这就是制造商不断向新的微架构添加新指令的原因,因为新的需求会使一些东西在大量使用之前变得不常见。例如,他们决定添加 SIMD instructions for vector and 3D operations when 3D applications was becoming a new trend, and matrix operations are also common. And then when increasing security requirements make encryption more common, AES instructions were introduced to boost cryptography applications. But that's not enough, as cryptography and many other applications use a lot of multiprecision arithmetics, Intel added MULX/ADOX/ADCX instructions 以加快速度。现在您将看到加速 AI 操作的指令开始进入架构
回到主要问题,减法非常普遍,因此值得单独说明。没有它,您将不得不 negate
一个操作数,然后 add
,这至少要花费两倍的时间和指令 space。 sub a, b
优于 neg b; add a, b
.
然而减法并不一定像你想象的那样因为取反而变慢,因为设计者使用了一个聪明的技巧让加法器在同一个数中同时做add
和sub
时钟 通过仅添加一个 muxer 和一个非门以及新输入 Binvert 以便有条件地反转第二个输入,如下所示
Computer Architecture - Full Adder
它的基本原理是实现二进制补码 -b = ~b + 1
,因此 a - b = a + ~b + 1
。这意味着我们只需要将进位设置为 1(或取反进位以借入)并反转第二个输入。
这种ALU在我开头提到的书里也有提到。不幸的是,由于许可问题我不能引用它,但我在教授的另一本书中找到了。帕特森和教授。轩尼诗:
Computer Organization and Design RISC-V Edition: The Hardware Software Interface
如您所见,通过另一个非常简单的修改,他们现在可以使用单个 ALU 执行 6 种不同的操作:add、sub、slt、and、or、nor
CSE 675.02: Introduction to Computer Architecture
您可以在 ALU 设计课程中找到更多信息,或者在 Google 上使用关键字 Binvert/Bnegate
我正在自学汇编,有一个困惑想解决。
据我了解,x86 计算机使用相同的电路进行加法和减法。对于减法,负数被转换为其 2 补码,然后加法电路可用于执行减法。例如:等式4 - 2
转换为4 + (-2)
所以如果减法可以使用 2 补码完成,那么 SUB
指令的目的是什么?
在2的补码世界中,整数的取反可以通过取1的补码(所有位取反)加1得到。例如,在8位世界中:
A: 0x00000002 ; my number
~A: 0xFFFFFFFD ; 1's complement of my number
-A: 0xFFFFFFFE ; 2's complement of my number (negative A)
要减去A-B
,当然可以加上负数,A+(-B)
:
NOT B ; invert each bit in the 8-bit value, B
ADD B, 1 ; add 1, giving the 2's complement negated B
ADD A, B
当然,我必须先修改 B
(否定它),然后才能添加它。如果我希望 B
保持完整怎么办?
PUSH B ; save B
NOT B ; invert each bit in the 8-bit value, B
INC A ; add 1, giving the 2's complement negated B
ADD A, B
POP B ; restore B
或者
NOT B ; invert each bit in the 8-bit value, B
INC A ; add 1, giving the 2's complement negated B
ADD A, B
NOT B ; restore B
这样就可以了。但是如果有一个 SUB
指令不是更容易吗?
SUB A, B
如果您编写汇编语言来进行大量算术运算,您更喜欢哪种方法?而且,在第一种情况下,我使用了 INC A
指令。我可以在没有 INC
的情况下逃脱,只需使用 ADD A, 1
。但是在许多微处理器上,ADD A, 1
要求我从指令存储器中获取更多内容以执行以获得立即的 1
值。因此,由于这种操作很常见,所以提供了 INC
。
当微处理器设计人员确定要使用的指令集时,他们会考虑最常用的操作类型。减法很常见,所以 SUB
指令非常方便。因此,它几乎存在于您能找到的任何指令集中。指令集中还有其他指令,其存在的原因不太明显。例如,x86 有 XLAT
指令,以及所有 "string" 指令,LODS
、STOS
等。当我可以做到所有这些时,为什么它们存在使用 MOV
和 INC
等?因为有人认为这些操作足够普遍,值得使用一条指令。
所以 SUB
指令背后的目的,就像 CPU 实现的许多其他指令一样,是提供一种更快(执行时间)和更简单的方法来执行最常执行的操作软件,与可以执行的指令数量存在实际限制这一事实相平衡。
TL;DR
因为它是最常见的操作之一,所以有专门的指令有助于提高速度。设计师知道如何让它变得更快,并且不需要像你想象的那样单独取反
从David Money Harris, Sarah L. Harris的计算机体系结构名著Computer Organization and Design, Fourth Edition: The Hardware/Software Interface by David A. Patterson and John L. Hennessy and Digital Design and Computer Architecture中我们知道MIPS的设计原则如下
- 设计原则1:简单有利于规律。
- 设计原则 2:快速处理常见情况。
- 设计原则3:越小越快
- 设计原则 4:好的设计需要好的妥协。
这些在其他架构中也是正确的。在 x86 和许多其他(主要是较旧的)体系结构中,由于向后兼容性,有些无法实现,但要点适用。
由于1st和3rd原则,我们需要使指令集尽可能紧凑可能 并且如果我们可以使用其他指令来创建新指令,则不要创建新指令。然而,根据原则 2 和 4,我们需要使常见操作尽可能快。
事实上大多数指令都是冗余的因为我们可以拥有图灵完备指令集只有one instruction. x86 itself is not an OISC architecture but it's still possible to do anything with just a single mov
or add
/sub
because they're proved to be Turing-complete. There's even a compiler to compile valid C code into a program with only MOV (or only either of XOR, SUB, ADD, XADD, ADC, SBB, AND/OR, PUSH/POP, 1-bit shifts, or CMPXCHG/XCHG) named movfuscator
因此,使用 add
或 sub
我们可以轻松获得移位、按位运算和 multiplication/division。然而,这些基本操作可能需要非常长的一系列指令来模拟,用户不会对此感到满意。
这就是制造商不断向新的微架构添加新指令的原因,因为新的需求会使一些东西在大量使用之前变得不常见。例如,他们决定添加 SIMD instructions for vector and 3D operations when 3D applications was becoming a new trend, and matrix operations are also common. And then when increasing security requirements make encryption more common, AES instructions were introduced to boost cryptography applications. But that's not enough, as cryptography and many other applications use a lot of multiprecision arithmetics, Intel added MULX/ADOX/ADCX instructions 以加快速度。现在您将看到加速 AI 操作的指令开始进入架构
回到主要问题,减法非常普遍,因此值得单独说明。没有它,您将不得不 negate
一个操作数,然后 add
,这至少要花费两倍的时间和指令 space。 sub a, b
优于 neg b; add a, b
.
然而减法并不一定像你想象的那样因为取反而变慢,因为设计者使用了一个聪明的技巧让加法器在同一个数中同时做add
和sub
时钟 通过仅添加一个 muxer 和一个非门以及新输入 Binvert 以便有条件地反转第二个输入,如下所示
Computer Architecture - Full Adder
它的基本原理是实现二进制补码 -b = ~b + 1
,因此 a - b = a + ~b + 1
。这意味着我们只需要将进位设置为 1(或取反进位以借入)并反转第二个输入。
这种ALU在我开头提到的书里也有提到。不幸的是,由于许可问题我不能引用它,但我在教授的另一本书中找到了。帕特森和教授。轩尼诗:
Computer Organization and Design RISC-V Edition: The Hardware Software Interface
如您所见,通过另一个非常简单的修改,他们现在可以使用单个 ALU 执行 6 种不同的操作:add、sub、slt、and、or、nor
CSE 675.02: Introduction to Computer Architecture
您可以在 ALU 设计课程中找到更多信息,或者在 Google 上使用关键字 Binvert/Bnegate