为什么编译器为什么要在从函数返回的MIPS“ j”指令之后放置指令?

时间:2019-12-01 22:10:54

标签: assembly mips

我正在查看MIPS平台的一些编译器输出,并努力了解函数如何返回以及允许的内容。

这是一个简单的例子:

int two_x_squared(int x)
{
    return 2*x*x;
}

如果我compile it with Compiler Explorer看到

two_x_squared(int):
        sll     $2,$4,1
        mult    $2,$4
        mflo    $2
        j       $31
        nop

好的,在这里没什么大不了的,我猜想j $31会跳转到返回地址,而nop可能是防止管道中的推测性执行所必需的。

但是随后我在-O2下使用XC32进行编译,我得到了

two_x_squared:
    mul $4,$4,$4
    j   $31
    sll $2,$4,1

那么... j $31之后的行在跳转之后的 之后执行了!!

1 个答案:

答案 0 :(得分:6)

这称为branch delay slot。是的,分支实际执行的指令比您期望的要晚,并且编译器应该用一些有用的东西填充延迟槽—通过将在分支之前逻辑地完成的操作移入该槽,或者通过将在分支之后发生的事情移动插入该插槽。

它被引入到原始的MIPS架构(以及HP PA RISC等)中,以帮助流水线处理器,因为它们必须排空并重新填充已采用分支上的流水线,这浪费了指令周期。

此功能已在更高版本的MIPS处理器以及开源RISC V硬件中的后续版本中删除。更现代的硬件使用其他方法来减轻与管道重新填充相关的浪费周期,包括分支预测,一些乱序执行,推测,在管道中更早执行分支。