x32和x64架构在数字操作上的差异

x32和x64架构在数字操作上的差异

例如,在 Java 编程语言中,我们可以使用 int(32 位)或 long(64 位)值。据我所知,32 位 CPU 可以在一个周期内处理 32 位数。有 32 位和 64 位 CPU。因此,问题是 32 位 CPU 如何处理 long 值(64 位)。如果能提供一些文献,将不胜感激。

还有一个问题,为什么 32 位处理器只能在 4 GB 及更低的 RAM 下工作?

答案1

双倍整数精度只是任意精度。在汇编语言层面,如何实现这一点取决于 ISA。(即使您具体询问的是 x86,我也会提供一些其他信息。)

对于加法和减法,许多 ISA(例如 ARM、Power、x86)提供进位(借位减法)位和特殊的带进位加法和带借位减法指令。

ADD r1, r2, r3; // r1 = r2 + r3, set or clear carry bit
ADDC r4, r5, r6; // r4 = r5 + r6 + carry bit (also sets/clears carry)

某些 ISA(例如 Alpha [始终为 64 位]、MIPS)不提供进位位和特殊的加/减指令。这些指令可能使用小于设置指令(如果不小于,则将寄存器设置为零,如果小于,则设置为一)来测试结果是否小于其中一个操作数(这确定结果是否产生进位)。

ADD r1, r2, r3; // r1 = r2 + r3
ADD r4, r5, r6; // r4 = r5 + r6
SLT r7, r1, r2; // r7 = (r1 < r2)? 1 : 0 (determining carry)
ADD r4, r4, r7; // r4 = r4 + r7 (adding in carry)

(选择不提供进位位的 ISA 设计人员这样做是因为多精度运算并不常见,单个进位位会引入阻碍超标量运算的数据依赖性,并且特殊位使无序执行的寄存器重命名更加复杂。)

对于乘法,双精度可能不足以使复杂算法更高效,因此可能更倾向于采用生成部分乘积并对结果求和的直接方法。这使用以下公式(其中 a 和 c 是双精度值的上半部分):

(a + b) * (c + d) = a*c + a*d + b*c + b*d.

(为简单起见,以下假设结果精度加倍,并忽略任何多余的部分。这意味着乘积项 a*c 被完全忽略。)

对于通过一次乘法提供高位结果和低位结果的 ISA(例如 MIPS、x86),操作相当简单。以下是粗糙的x86 的近似值(我不熟悉细节):

 MUL r2:r0, r3, r7; // multiply a*d
 MOV r1, r0;  // preserve low result of a*d
 MUL r2:r0, r5, r6; // multiply b*c
 MOV [temp], R0; // preserve low result on stack at temp
 MUL r2:r0, r5, r7; // multiply b*d
 ADD r2, r1; // add high b*d and low b*c for part of 
                  // higher result
 ADD r2, [temp]; // add partial higher result and low a*d
 // doubled precision product is now in r2:r0

对于为高结果提供单独的乘法,为低结果提供单独的乘法指令(乘法自然会产生双倍精度的值),此操作有些类似:

// a*c result is beyond doubled precision range
MULL r16, r1, r4; // low multiply result (a*d)
// high a*d result is beyond doubled precision range
MULL r17, r2, r3; // low multiply result (b*c)
// high b*c result is beyond doubled precision range
MULL r18, r2, r4; // low multiply result (b*d)
MULH r19, r2, r4; // high multiply result (b*d)
ADD  r20, r19, r17; // sum high (b*d) and low (b*c)
                    // for part of higher result
ADD  r20, r20, r16; // sum partial result and low (a*d)
// double precision result is in r20:r16

(有些 ISA 不提供获取乘法更高结果的方法。对于此类 ISA,可以将操作数分成半大小的单元并执行四倍精度乘法,尽管可能存在更复杂的算法。具有乘法加法指令的 ISA 显然可以将加法和两个乘法合并为乘法加法。)

上述伪汇编代码假设溢出不是问题(并且未针对性能进行优化)。实际实现会妥善处理此类问题。

GNU 多精度算术库,一个用于任意精度运算的开源库,将提供实际实现的细节。

地址空间限制

32 位处理器(简单来说)只能使用 4 GiB 内存的原因是它使用 32 位指针/地址并使用字节寻址(因此有 2 32个地址可用)。传统上,即使使用虚拟内存系统,支持大于 4 GiB 的物理地址空间(顺便说一下,包括内存映射的 I/O 地址)也被认为是不必要的。(4 GiB 物理地址空间对于 32 位页表条目也很方便,允许在使用 4 KiB 页面时使用 10 位来定义有效性、权限和其他元数据。使用 64 位页表条目往往会在小型系统中使用过多的内存,而最初的 32 位系统很小。)

为了延长 32 位 ISA 的使用寿命,一些 ISA(例如 ARM、x86)添加了物理地址扩展,使用 64 位页表条目来允许更大的物理地址。这种解决方法很尴尬,尤其是对于必须管理所有物理内存的操作系统而言。

一些 ISA(如 HP PA-RISC)提供了分段系统,允许用户级程序通过在地址顶部附加专用段寄存器来寻址更大的地址空间。(Power[PC] 也使用段,但非特权 [即应用程序] 软件无法修改这些值。)

(理论上,ISA 可以使用寄存器对来扩展内存寻址能力,就像某些 8 位处理器一样。但是,到那时,转向 64 位 ISA 通常更有意义。)

相关内容