3

索引寻址模式通常用于访问数组,因为数组是连续存储的。我们有一个索引寄存器,它在每次迭代中都会增加,当添加到基地址时会给出数组元素地址。我不明白这种寻址模式的实际需要。为什么我们不能用直接寻址来做到这一点?我们有基地址,每次访问时我们都可以加1。为什么我们需要具有索引寄存器开销的索引寻址模式?

我不确定隐含寻址模式的指令格式。假设我们有一条指令 INC AC。指令中是否指定了 AC 的地址,或者是否有一个特殊的操作码表示“INC AC”并且我们不包括 AC(累加器)的地址?

4

1 回答 1

2

我不明白这种寻址模式的实际需要。为什么我们不能通过直接寻址来做到这一点?

你可以; MIPS 只有一种寻址模式,编译器仍然可以为其生成代码。但有时它必须使用额外的 shift +add指令来计算地址(如果它不只是循环遍历数组)。

寻址模式的重点是保存指令和保存寄存器,特别是在像 x86 这样的 2 操作数指令集中,其中用结果 ( )add eax, ecx覆盖,这与 MIPS 或其他 3 指令 ISA 不同。在 x86 上,这需要一个副本 ( ) 和一个. (或者在这种特殊情况下,: x86 可以使用与内存操作数相同的指令编码进行复制和添加(和移位)。)eaxeax += ecxaddu $t2, $t1, $t0t2 = t1 + t0movaddlea edx, [eax+ecx]

考虑一个直方图问题:您以不可预测的顺序生成数组索引,并且必须索引一个数组。在 x86-64 上,add dword [rbx + rdi*4], 1将使用单个 4 字节指令在内存中增加一个 32 位计数器,该指令仅解码为 2 uop,以便前端发出到现代 Intel CPU 上的无序内核。(http://agner.org/optimize/)。(rbx是基址寄存器,rdi是缩放索引)。拥有一个缩放的索引是非常强大的;x86 16 位寻址模式支持 2 个寄存器,但不支持缩放索引。

经典 MIPS 仅具有单独的移位和加法指令,尽管 MIPS32 确实为地址计算添加了缩放加法指令。这将在这里保存一条指令。作为加载存储机器,加载和存储始终必须是单独的指令(与 x86 不同,在 x86 上,添加解码为微融合加载+添加和存储。请参阅INC 指令与 ADD 1:这有关系吗?)。

与 MIPS 相比,ARM 可能是一个更好的比较:它也是一个加载存储 RISC 机器。但它确实有多种寻址模式,包括使用桶形移位器的缩放索引。因此,您不需要为每个数组索引单独移位/添加,而是使用LDR R0, [R1, R2, LSL #2], add r0, r0, #1/str具有相同的寻址模式。

通常在遍历数组时,最好只增加 x86 上的指针。但它也是使用索引的一种选择,特别是对于使用相同索引的多个数组的循环,例如C[i] = A[i] + B[i]. 不过,索引寻址模式有时在硬件中的效率会稍低一些,因此当编译器展开循环时,它通常应该使用指针,即使它必须分别递增所有 3 个指针而不是一个索引。


指令集设计的重点不仅仅是图灵完备,它还支持高效的代码,以更少的时钟周期和/或更小的代码大小完成更多的工作,或者让程序员可以选择实现这些目标中的任何一个。

计算机可编程的最低阈值非常低,例如参见各种单指令集计算机体系结构。(没有真正实现,只是在纸上设计,以表明可以编写程序,只需要一个减法和分支,如果小于零指令,内存操作数编码在指令中。

在易于解码(尤其是并行解码)与紧凑之间存在权衡。x86 是可怕的,因为它演变为一系列扩展,通常没有太多计划为未来的扩展留出空间。如果您对 ISA 设计决策感兴趣,请查看 Agner Fog 的博客,了解有关为高性能 CPU 设计 ISA 的有趣讨论,该 CPU 结合了 x86 的优点(大量工作与一条指令,例如内存操作数作为ALU 指令)具有 RISC 的最佳特性(易于解码,大量寄存器):理想可扩展指令集的建议

在指令字中使用位的方式也有一个权衡,特别是在像大多数 RISC 一样的固定指令宽度 ISA 中。不同的 ISA 做出了不同的选择。

  • PowerPC 将大量编码空间用于强大的位域指令,例如rlwinm(向左旋转并屏蔽位窗口)和大量操作码。IDK 如果通常无法发音且难以记住的助记符与此有关...
  • ARM 使用高 4 位基于条件代码预测执行任何指令。它为桶形移位器使用更多位(第二个源操作数可选地通过立即数或来自另一个寄存器的计数进行移位或旋转)。
  • MIPS 的直接操作数比较大,基本简单。

x86 32/64 位寻址模式使用可变长度编码,当有索引时使用额外的字节 SIB(缩放/索引/基)字节,以及可选的 disp8 或 disp32 立即位移。(例如add esi, [rax + rdx + 12340],编码需要 2 + 1 + 4 个字节,而add esi, [rax].

x86 16 位寻址模式受到更多限制,并将除了可选的 disp8/disp16 位移之外的所有内容打包到 ModR/M 字节中。


假设我们有一条指令 INC AC。指令中是否指定了 AC 的地址,或者是否有一个特殊的操作码表示“INC AC”并且我们不包括 AC(累加器)的地址?

是的,某些 ISA 中某些指令的机器代码格式包括隐式操作数。许多机器都有push/pop指令隐式使用特定寄存器作为堆栈指针。例如,在 x86-64 中push rax,RAX 是一个显式寄存器操作数(使用缩写形式以单字节操作码的低 3 位编码push r64),而 RSP 是一个隐式操作数。

较旧的 8 位 CPU 通常具有 DECA 之类的指令(用于递减累加器 A)。即该寄存器有一个特定的操作码。这可能与在操作码字节中有一些位的 DEC 指令指定哪个寄存器(就像 x86 在 x86-64 将短 INC/DEC 编码重新用作 REX 前缀之前所做的那样:注意“NE”(不可编码) )的 64 位模式列dec r32。但是如果没有规则模式,那么它绝对可以被认为是一个隐式操作数。

有时将事物归入整齐的类别会失败,因此不要太担心使用带有操作码字节的位对于 x86 而言是隐式还是显式。这是一种花费更多操作码空间来节省常用指令的代码大小的方法,同时仍然允许与不同的寄存器一起使用。

一些 ISA 按照惯例只使用某个寄存器作为堆栈指针,没有隐式使用。MIPS 是这样的。

ARM32(在 ARM 中,不是 Thumb 模式)也在 push/pop 中使用显式操作数。它的 push/pop 助记符只是 store-multiple decrement-before / load-multiple increment-after (LDMIA / STMDB) 的别名,用于实现全降序堆栈。请参阅ARM 的LDM/STM 文档,其中解释了这一点,以及您可以对这些指令的一般情况执行什么操作,例如 LDMDB 递减指针然后加载(与 POP 的相反方向)。

于 2017-12-18T16:12:20.090 回答