/*
a = b + e
b = b + f
*/
lw $t1, 0($t0) // load b
lw $t2, 4($t0) // load e
add $t3, $t1, $t2 // a = b + e
sw t3, 12($t0) // save a to memory 12
lw $t4, 8($t0) // load fabs
add $t5, $t1, $t4 // b = b + f
sw $t5, 16($t0) // save b to memory 16
/*
可以看见 add 指令都需要先取得数才行,所以 lw 指令会阻塞。
此时如果将指令重排一下就可以提高性能,如下
*/
lw $t1, 0($t0) // load b
lw $t2, 4($t0) // load e
lw $t4, 8($t0) // load f
add $t3, $t1, $t2 // a = b + e
sw t3, 12($t0) // save a to memory 12
add $t5, $t1, $t4 // b = b + f
sw $t5, 16($t0) // save b to memory 16
/*
这里等到 b和e 取的时候,
继续取f,在取 f 的过程中,
然后再将 a = b + e 的操作,
可以减小阻塞情况的发生,前面的代码是说必须取得 b, e才能执行后续指令,
而此时 b 和 e 很可能在执行 f 的过程中就取完了
*/
===========================================================
/* 目标:实现原子交换,即 $s4 中的值和内存中锁单元的值交换,锁单元的基址保存在 $s1 中 */
again: addi $t0, $zero, 1 // $t0 = 0 + $s4,此时 $t0 中保存了 $s4 的值 1
ll $t1, 0($s1) // $t1 = Memory[$s1 + 0],此时 $t1 中保存了 $s1 指向的锁单元的值 ?
sc $t0, 0($s1) /* Memory[$s1 + 0] = $t0,当执行成功,此时 $s1 所指向的锁单元的值就是 $s4 的值了,并且将 $t0 的值修改为 1。
* 当执行失败,不保存 $s4 的值到锁单元,并且将 $t0 的值修改为 0。
*/
beq $t0, $zero, again /* if $tp == $zero, jump again; else continue,如果 $t0 为 0,则说明执行失败,应该跳到 again,
* 如果 $t0 为 1,则说明锁单元的值已经是 s4 了,
* 接下来只需要将 s4 中的值改为锁单元的值就行了
*/
add $s4, $zero, $t1 // $s4 = $zero + $t1,前面将锁单元的值放在了 $t1 中,只需要将其赋值到 $s4 即可
/* 提出思考:按照常理来说交换俩个值使用一个 temp 即可,
* 但是此时却采用了两个 temp,
* 这里多出来的 temp0 其实有两个作用:
* ① 是 sc 执行成功与失败的开关,
* ② 携带 $s4 的值,便于交换
* 如果没有 temp0 的话,那么将要修改 $s4 的值作为开关,这样是不可取的