索引寻址模式和隐含寻址模式

时间:2017-12-18 12:04:59

标签: cpu-architecture cpu-registers risc

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

我不确定隐含寻址模式的指令格式。假设我们有INC AC指令。是指令中指定的AC的地址还是有一个特殊的操作码,这意味着'INC AC'而我们不包括AC(累加器)的地址?

1 个答案:

答案 0 :(得分:2)

  

我不了解这种寻址模式的实际需要。为什么我们不能直接寻址?

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

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

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

经典MIPS只有单独的移位和添加指令,尽管MIPS32确实添加了一个用于地址计算的缩放添加指令。那会在这里保存一条指令。作为一个加载存储机器,加载和存储总是必须是单独的指令(与x86不同,在那里添加解码为微融合负载+添加和存储。请参阅INC instruction vs ADD 1: Does it matter?)。

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

通常在循环数组时,最好只在x86上增加指针。但它也是使用索引的一种选择,特别是对于使用相同索引的多个数组的循环,如C[i] = A[i] + B[i]。索引寻址模式有时可能是slightly less efficient in hardware,所以当编译器展开循环时,它通常应该使用指针,即使它必须分别增加所有3个指针而不是一个索引。

指令集设计的重点不仅仅是图灵完成,而是启用高效代码,以更少的时钟周期和/或更小的代码大小完成更多的工作,或者让程序员选择针对这两个目标。

计算机可编程的最低阈值非常低,例如参见各种One instruction set computer架构。 (没有实现真实的,只是在纸上设计,表明它可以用除了减法和分支 - 如果少于零的指令编写程序,并在指令中编码内存操作数。 / p>

在易于解码(尤其是并行解码)与紧凑之间进行权衡。 x86很糟糕,因为它演变为一系列扩展,通常没有很多计划为未来扩展留出空间。如果您对ISA设计决策感兴趣,请查看Agner Fog的博客,了解有关为高性能CPU设计ISA的有趣讨论,它结合了x86的优点(许多工作与一条指令,例如内存操作数作为ALU指令的一部分)具有RISC的最佳功能(易于解码,有大量寄存器):Proposal for an ideal extensible instruction set

在如何将这些位花费在指令字中,尤其是像大多数RISC这样的固定指令宽度ISA中,也存在权衡。不同的ISA做出了不同的选择。

  • PowerPC将大量编码空间用于强大的位域指令,如rlwinm(向左旋转并屏蔽一个位窗口)和许多操作码。 IDK,如果通常不可发音和难以记忆的助记符与...相关...
  • ARM使用高4位来根据条件代码执行任何指令。它为the barrel shifter使用更多位(第二个源操作数可选择通过立即移位或旋转或从另一个寄存器移位)。
  • MIPS具有相对较大的即时操作数,基本上很简单。

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

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

  

假设我们有INC AC指令。是指令中指定的AC的地址,还是有一个特殊的操作码,这意味着' INC AC'而且我们不包含AC(累加器)的地址?

是的,某些ISA中某些指令的机器代码格式包含隐式操作数。许多机器都有push / pop指令隐式使用特定寄存器作为堆栈指针。例如,在x86-64' push rax中,RAX是显式寄存器操作数(encoded in the low 3 bits of the one-byte opcode using the push r64 short form),而RSP是隐式操作数。

较旧的8位CPU通常具有DECA等指令(递减累加器A)。即该寄存器有一个特定的操作码。这可能与具有DEC指令的操作相同,操作码字节中的一些位指定哪个寄存器(如x86在x86-64之前将short INC/DEC encodings重新用作REX前缀:注意" N.E&# 34; dec r32的64位模式列中的(不可编码)。但如果没有规则模式,那么它绝对可以被认为是一个隐含的操作数。

有时候把东西放到整齐的类别中会崩溃,所以不要过分担心使用带有操作码字节的位是否为x86隐式或显式。这是一种花费更多操作码空间来节省常用指令的代码大小同时仍允许使用不同寄存器的方法。

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

ARM32(在ARM中,而不是Thumb模式)也在push / pop中使用显式操作数。它的推/弹助记符只是存储多次递减 - 加载 - 加载 - 递增 - 后(LDMIA / STMDB)实现完全降序堆栈的别名。有关LDM / STM的详细信息,请参阅ARM's docs,以及您可以对这些说明的一般情况采取的措施,例如: LDMDB递减指针然后加载(在POP的相反方向)。