过去两讲,我为你讲解了通过增加资源、停顿等待以及主动转发数据的方式,来解决结构冒险和数据冒险问题。对于结构冒险,由于限制来自于同一时钟周期不同的指令,要访问相同的硬件资源,解决方案是增加资源。对于数据冒险,由于限制来自于数据之间的各种依赖,我们可以提前把数据转发到下一个指令。
但是即便综合运用这三种技术,我们仍然会遇到不得不停下整个流水线,等待前面的指令完成的情况,也就是采用流水线停顿的解决方案。比如说,上一讲里最后给你的例子,即使我们进行了操作数前推,因为第二条加法指令依赖于第一条指令从内存中获取的数据,我们还是要插入一次 NOP 的操作。
那这个时候你就会想了,那我们能不能让后面没有数据依赖的指令,在前面指令停顿的时候先执行呢?
答案当然是可以的。毕竟,流水线停顿的时候,对应的电路闲着也是闲着。那我们完全可以先完成后面指令的执行阶段。
填上空闲的 NOP:上菜的顺序不必是点菜的顺序
之前我为你讲解的,无论是流水线停顿,还是操作数前推,归根到底,只要前面指令的特定阶段还没有执行完成,后面的指令就会被“阻塞”住。
但是这个“阻塞”很多时候是没有必要的。因为尽管你的代码生成的指令是顺序的,但是如果后面的指令不需要依赖前面指令的执行结果,完全可以不必等待前面的指令运算完成。