【问题标题】:Why are bgezal & bltzal basic instructions and not pseudo-instructions in MIPS?为什么 bgezal 和 bltzal 是基本指令而不是 MIPS 中的伪指令?
【发布时间】:2014-01-07 22:25:20
【问题描述】:

根据this MIPS instruction reference,有两条指令(bgezalbltzal)执行相对跳转和链接,而不是在采用分支时执行相对跳转。

这些指令可以分别用bgezbltz模拟,后跟jal,这意味着bgezalbltzal都应该被归类为伪指令。但是,两者都有分配给它们的操作码,因此它们被归类为基本指令。

将它们添加到基本指令集中而不是使它们成为伪指令的基本原理是什么?还有,为什么指令集中只包含bgezalbltzal而不包含blezalbgzal等?

【问题讨论】:

  • 您似乎想知道设计师必须这样设计它的原因。虽然我尊重这类问题,但它通常被视为离题,而且通常很难(或不可能)找到答案。

标签: assembly mips cpu-architecture


【解决方案1】:

bgez 和 bltz 不是伪指令。

bgezal 和 bltzal 是一样的,这并不奇怪。

虽然它是 RISC,但并非所有指令都应该是基本的。两条指令需要更多的内存,如果经常使用可能需要更多的时间,并且操作码中有很多空间,为什么不将它们合并为一个呢?

【讨论】:

    【解决方案2】:

    主要原因是效率。

    您最初的假设(即执行bgez 后跟jal 可以由beqzal 模拟或在功能上等同于执行beqzal)是正确的,但这样做可能效率较低。

    为什么首先存在伪指令?马里兰大学在pseudoinstructionsbranching 上的注释解释了这一点。答案在于 MIPS 的设计方式。 MIPS 是精简指令集。如果速度有显着提高,指令可能会保留在 ISA 中。如果它可以使用两条或更多条指令编写,并且没有明显的延迟(因为它们不经常使用),那么这些指令就不包含在 MIPS ISA 中。相反,它们变成了伪指令。

    让我们采用另一个伪指令,例如la,或加载地址。 la 是一个伪指令,可以分解为 lui 指令和 ori 指令。在 32 位 MIPS 架构上,每条指令以及每个寄存器的大小都是 32 位。因此,为了存储 32 位地址,使用了两条指令。有关la 指令的更多信息,请参见here

    bgezalbltzal 指令很可能不是伪指令,因为在一条指令中执行完整操作更有效。硬件必须能够执行条件检查,跳转到分支地址,并将返回地址存储在一条指令中。如果jal 指令被分离出来,这不仅是对空间的不必要使用,而且在某些硬件实现中,这条额外的指令可能会占用处理器数据路径的一个执行周期,从而有效地减慢程序的执行速度。

    其他来源:

    【讨论】:

    • 我不相信有单周期 MIPS 实现
    • @KonradLindenbach 最初的 MIPS R2000R3000 芯片每个周期只能完成大约一条指令。
    • 我的理解是,由于 MIPS 是冯诺依曼架构,它不可能是一个需要将内存分离为指令和数据的单周期实现。
    • 也许我不应该使用“单周期”这个短语,我的意思是像 R2000 这样以每个周期执行一条指令的速度执行的实现。我已经编辑了我的答案。感谢@KonradLindenbach 指出这一点。
    • jal 是半绝对的(替换 PC 的低 28 位),而 bgezal / bltzal` 是相对的(添加 18 位位移,imm16jal 不同,您甚至可以使用一个将当前PC 放入寄存器并找出您正在执行的位置)。 How to Calculate Jump Target Address and Branch Target Address?
    【解决方案3】:

    将它们添加到基本指令集中而不是使它们成为伪指令的基本原理是什么?

    仅仅因为可以将指令分成几部分并不意味着它应该是。我知道这是一个 RISC,但仍然需要在指令集的大小和整个系统的性能之间进行权衡。

    与单条指令相比,两条指令意味着更长的执行时间,因此设计团队可能在看到这条指令对流行基准测试产生的影响后决定将其包含在内。


    另外,为什么指令集中只包含bgezalbltzal 而没有,例如blezalbgzal 等?

    对此我能给出的最简单的解释是,这些指令最容易实现:对于bgezalbltzal,只需检查符号位。

    【讨论】:

    • 我希望 MIPS 的设计者可能期望,在处理“正常”分支指令时,需要使用一个流水线级来获取寄存器操作数,并在系统能够执行之前使用另一个流水线级来比较它们。知道它是否应该进行分支,但是只需要检查一个源寄存器的一位的逻辑可以被压缩到操作数获取周期中,从而允许这样的分支比其他情况更快地运行一个周期。跨度>
    • @supercat:在操作数获取期间进行比较听起来是个不错的主意,直到您考虑slt / bne 序列的问题,并且通常从先前的 ALU 指令转发。 MIPS I (R2000) 实际上所做的是在 EX 的前半周期运行分支条件,而 IF 仅在第二个半周期开始,因此可以转发并且将分支延迟限制为 1循环,被 1 个延迟槽完全隐藏。 How does MIPS I handle branching on the previous ALU instruction without stalling?
    【解决方案4】:

    jal 使用半绝对目标编码(替换 PC 的低 28 位),而 bgezal / bltzal 是相对的(添加 18 位有符号位移,imm16<<2)。 How to Calculate Jump Target Address and Branch Target Address?

    它们是经典 MIPS 唯一的分支和链接(而不是跳转和链接),因此对于与位置无关的可重定位代码很重要。(您甚至可以使用一个来获取当前将 PC 放入一个寄存器并找出你从哪里执行,这与 jal 不同)。

    您可以将bal(无条件相对函数调用)编码为bgezal $zero, target

    您无需任何其他设置即可获得$ra=PC 和未采用的bltzal $zero, anywhere 使用bgezal 进行此操作将需要一个小于零的输入寄存器,该寄存器需要一个insn 创建。 b...al 指令 总是 写入 $ra,即使分支未被采用。对于 PC 相关代码,您需要此功能,直到 MIPS32r6 为我们提供 addiupc 以更好地生成 PC 相关地址。

    由于它们像其他 branch 指令一样使用 I 型指令格式,因此在一个寄存器的编码中有空间,因此将其设为可选条件而不是 只是 bal 指令。执行“和链接”的硬件逻辑已经存在,所有其他相关分支指令都是有条件的。另外,对于 $zero 而言,具有未采用的条件可能会方便阅读 pc

    请记住,MIPS 指令编码在早期 MIPS 硬件中直接用作内部控制信号,因此它们之间不同的编码中的一位可能被连接到一个异或门,该异或门反转(或不反转)对符号位的检查. (正如 Konrad 的回答所指出的,这些分支条件仅取决于寄存器的 MSB,因为它总是反对零,因此等待 32 位加法器产生比较结果没有延迟。)

    来自http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html

    0000 01ss sss1 0001 iiii iiii iiii iiii   BGEZAL
    0000 01ss sss1 0000 iiii iiii iiii iiii   BLTZAL
    

    指令编码缺乏灵活性(因为它直接驱动内部控制信号,而不需要在解码中进行大量转换)可能是为什么不只有一个具有 28 位范围的bal(从 26 -位相对位移)。相关分支的硬件是为 16 位立即数的 I 型指令设置的。


    TL:DR:有 2 个条件分支和链接指令,因为其中一个实现无条件 bal 是很自然的,而另一个几乎是免费的。

    MIPS b(无链接的无条件相对分支)也是beq $zero, $zero, target 的伪指令,或者由汇编程序选择,用于bgez $zero, target。 (What is the difference between unconditional branch and unconditional jump (instructions in MIPS)?)。 MIPS R3000 manual 建议 beq $zero,$zero。 (并且更清楚地记录了$ra=PC 无论分支如何都会发生;这在我最初编写此答案时正在查看的快速参考表中并不清楚。)

    比较零编码只有一个 5 位寄存器字段,因此它们消耗的编码空间比beq / bne 少。这可能是选择 bgezal 而不是 beqal 作为要提供的一对条件分支之一的一个可能原因。

    【讨论】:

    • 我认为您所说的两条指令存在是因为原始 MIPS 芯片的设计使其成为实现 BAL 指令的最自然方式,如果是这样,我同意您的看法。我不相信其他答案确实如此,这两条指令的全部功能实际上经常被使用到足以证明它们的存在。
    • A not-taken branch-and-link 仍然写入链接寄存器,但实际上可以使用 taken bal 来读取 PC,使用相对目标地址是失败的地方:分支延迟槽之后的指令。这可能效率较低,尽管如果在addiupc 存在之前它已成为 MIPS 的常用习语,那么微架构可能会有一些特殊情况下的分支置换。 (比如 x86 avoids the equivalent 32-bit PIC idiom unbalancing return-address prediction.)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2014-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多