Skip to content

Commit

Permalink
update L10
Browse files Browse the repository at this point in the history
  • Loading branch information
lzzsG committed Aug 24, 2024
1 parent c165dba commit b8f38d6
Showing 1 changed file with 9 additions and 16 deletions.
25 changes: 9 additions & 16 deletions docs/L10 RISC-V Procedures.md
Original file line number Diff line number Diff line change
Expand Up @@ -628,28 +628,30 @@ int sumSquare(int x, int y) {
> >
> > ### 如果`Leaf` 函数使用临时寄存器
> >
> > 是的,正是因为在被调用的函数(Callee)过程中,可能会再次调用其他函数,这会导致临时寄存器(`t0-t6`)被修改,从而破坏当前函数对这些寄存器值的依赖。因此,临时寄存器不适合在需要保持跨函数调用的值时使用。
> > 判断使用哪种寄存器通常是编译器的任务,但在手动优化和特定场景下,程序员也需要做出相应的决策。如果程序员知道某个寄存器的值不会被函数调用破坏,可以使用临时寄存器。例如,在一个简单的计算过程中,没有调用其他函数,使用临时寄存器可以简化代码。
> >
> > 不过在被调用的函数(Callee)过程中,可能会再次调用其他函数,这会导致临时寄存器(`t0-t6`)被修改,从而破坏当前函数对这些寄存器值的依赖。因此,临时寄存器不适合在需要保持跨函数调用的值时使用。
> >
> > #### 1. **临时寄存器的特性**
> >
> > 临时寄存器(`t0-t6`)在 RISC-V 的调用约定中属于“调用者保存”的寄存器。这意味着调用者在调用函数之前,如果需要保留这些寄存器中的值,就必须自己保存(通常是保存到栈上),然后在函数调用返回后恢复这些寄存器的值。被调用者(即被调用的函数)可以自由地使用这些寄存器,而不需要在返回之前恢复它们的值。
> >
> > #### 2. **函数的嵌套调用**
> >
> > 在被调用的函数(如你示例中的 `Leaf` 函数)中,通常会有多层函数调用。例如,`Leaf` 函数可能会再次调用其他函数:
> > 在被调用的函数(如示例中的 `Leaf` 函数)中,可能会有多层函数调用。例如,`Leaf` 函数可能会再次调用其他函数:
> >
> > ```python
> > Leaf:
> > addi sp, sp, -8 # 调整栈以容纳 2 个条目
> > sw s1, 4(sp) # 保存 s1 供后续使用
> > sw s0, 0(sp) # 保存 s0 供后续使用
> >
> >
> > add s0, a0, a1 # f = g + h
> > add s1, a2, a3 # s1 = i + j
> > call some_function # 调用其他函数
> >
> >
> > sub a0, s0, s1 # 返回值 (g + h) - (i + j)
> >
> >
> > lw s0, 0(sp) # 恢复调用者的寄存器 s0
> > lw s1, 4(sp) # 恢复调用者的寄存器 s1
> > addi sp, sp, 8 # 调整栈以删除 2 个条目
Expand All @@ -666,18 +668,9 @@ int sumSquare(int x, int y) {
> >
> > 保存寄存器(`s0-s11`)则不同。它们是“被调用者保存”的寄存器,即如果 `Leaf` 函数使用了这些寄存器,它有责任在使用这些寄存器之前保存它们的值,并在函数返回之前恢复它们的值。这样可以确保在 `Leaf` 函数调用 `some_function` 之后,`s0` 和 `s1` 的值仍然是函数调用之前的状态,这样就可以安全地继续使用这些寄存器。
> >
> > > 虽然在某些情况下,比如在最内层的被调用函数中,确实没有进一步调用其他函数的计划,因此在理论上使用临时寄存器可能不会立即引发问题。然而,RISC-V 调用约定的设计初衷是为了确保代码的可维护性和通用性。
> > >
> > > ### 为什么总是使用保存寄存器更合适:
> > >
> > > 1. **可维护性**:
> > > - 随着程序的演进,原本没有调用其他函数的最内层函数,可能会在未来版本中增加新的功能或调用其他函数。如果原本使用了临时寄存器,那么将来一旦修改代码,容易引发难以察觉的错误。使用保存寄存器可以避免这种潜在问题,使得代码更加稳定和易于维护。
> > >
> > > 2. **统一的调用约定**:
> > > - 统一的调用约定确保了函数在不同的上下文中调用时能够保持一致的行为。即使当前函数看似不需要保存寄存器,但保持使用保存寄存器的习惯可以确保函数在任何情况下都能够安全运行,不会因为函数嵌套或修改而引发问题。
> > > 虽然在某些情况下,比如在最内层的被调用函数中,确实没有进一步调用其他函数的计划,因此在理论上使用临时寄存器可能不会立即引发问题。不过使用保存寄存器可以避免增加新的功能或调用其他函数后的潜在问题,使得代码更加稳定和易于维护。
> > >
> > > 3. **避免难以追踪的错误**:
> > > - 在调试或维护代码时,假设所有函数都严格遵守调用约定(即保存寄存器在使用前保存、使用后恢复),那么可以更容易地追踪和调试代码中的问题。相反,如果某些函数违反了这一约定,可能会引入难以发现的错误,尤其是在复杂的程序中。
> > > 程序员在手写汇编或特定优化场景中,可以自己决定使用哪种寄存器。程序员需要了解寄存器的用途和调用约定,以正确选择合适的寄存器。
## And in Conclusion, the RV32 So Far...
Expand Down

0 comments on commit b8f38d6

Please sign in to comment.