assembly - 如何确定是否应保留寄存器

标签 assembly mips cpu-registers calling-convention

我正在学习MIPS,我正在尝试用MIPS来表达用C语言编写的代码。

其中,当我研究应该保留的寄存器时,我认为通过简单地考虑寄存器的类型来决定是否保留它们。

int leaf_example (int g, int h, int i , int j)
{
    int f;
    f = (g+h)-(i+j);
    return f;
 }

比如有上面的代码,有条件g~j$a0~a3f$s0,返回值存储在$v0中。

此时,由于条件问题,f存储在$s中,而$s需要保留,所以我了解到 $s0 的值存储在堆栈中,然后 $s 被恢复。

void sort(int v[],int n)
{
    int i, j;
    for (i = 0 i < n; i++){
        for (j = i - 1; j >= 0 && v[j] > v[j + 1]; j-=1){
            swap(v, j);
        }
    }
}

但是,当有像上面这样的代码时,它以MIPS表示如下:

image

为什么作为sort()函数的参数传入的两个值是分开存储的,然后在它们没有存储在$s中时使用>?我不知道如何确定应该保留哪些寄存器。

在上面的代码中,我想知道为什么需要保留$a0 $a1。也就是说,如果您能告诉我如何区分代码中应保留哪些值,我将非常感激。

最佳答案

在 C 或伪代码中,我们有生命周期有限的逻辑变量,它们按作用域来来去去(例如局部变量和参数),而在汇编中我们有物理存储。当我们将算法翻译成汇编语言时,我们必须将逻辑变量映射到物理存储中。

为变量选择的特定存储必须满足其生命周期和使用要求。按照软件惯例,MIPS 将寄存器(物理存储)分割为调用保留寄存器和调用破坏寄存器。

我们需要做的是分析变量及其使用方式。您想要回答以下问题:对于每个变量,它所保存的值是在函数调用之前定义并在函数调用之后使用的。如果任何变量的答案是肯定的,则该变量必须存储在函数调用后仍保留的保留位置中,这些位置要么是 $s 寄存器,要么是(本地)堆栈内存。但无论哪种方式,都直接涉及内存,在后一种情况下,而在前一种情况下使用 $s 寄存器时,必须保留这些寄存器本身以遵循约定。

如果代码多次使用变量(通过动态计数),则 $s 寄存器是有利且理想的,就像循环的情况一样。否则,例如,如果变量仅使用一次(或者在意外或对性能不重要的动态路径上),那么内存可能是比 $s 寄存器更好的位置。


在第一个函数中,使用 $s 寄存器来存储局部变量 f 是愚蠢的 - f 应该放在 中>$v0。为什么?两个原因:

  • $v0 可用,并且从第一次使用 f 到最后一次使用该函数所做的任何事情都不会破坏,并且,
  • 函数以return f;结束,这意味着在函数结束时,f的值需要位于$v0.

因此,将其放在第一位是有意义的,并且避免了使用 $s 寄存器的开销,而且不需要在最后复制到 $v0 中.


在第二个函数中,它在循环内调用swap,所以,然后

  • 假设函数调用会清除所有参数寄存器(它们是调用破坏集的一部分)
  • sort 本身将清除作为该函数调用的参数传递部分的 $a0$a1

变量ijvn均在函数调用之前定义并使用后。 i++ 既是 i 的一种用法,也是它的另一种定义——该变量应该在函数调用后继续存在。 j-- 也是如此。 vn 都是在函数入口处定义并重复使用的,因此显然它们也必须在 swap 函数调用(或者下一次迭代)中幸存下来循环将不起作用)。

由于这 4 个变量使用得相当频繁,$s 寄存器是很好的候选者,因为替代方案内存需要将额外的加载和存储插入到循环体中。

权衡是在序言和尾声中分别对 $s 寄存器进行一次保存和恢复,而不是在循环体中进行加载和存储,并且如果循环执行多次这是一笔不错的交易。


当我们将逻辑变量映射到物理存储时,这些变量不一定是永久的,因此有时逻辑变量“存在”(映射到)代码的一部分中的物理存储与另一部分中的不同物理存储。

关于assembly - 如何确定是否应保留寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69413034/

相关文章:

MIPS指令寄存器

assembly - 在数据段中输入后直接保存输出

assembly - MIPS中大于,小于等于,大于等于

assembly - 为什么 MIPS 堆栈指针需要保持双字对齐?

assembly - .double 类型的变量是否存储在两个寄存器中?

x86 - GDB 寄存器与处理器寄存器不同吗?

c - pt_regs 和 user_struct_regs 的区别

assembly - 在汇编代码 Easy 68k (68000) 中插入换行符

linux - 我正在 Linux 上学习汇编,[] 符号让我感到困惑。 (NASM)

arrays - x86-64 汇编中的数组元素比较(AT&T 语法)