乱序流水线(动态调度)

介绍

因为需要乱序执行指令以便减少数据冲突,需要采用动态调度的方法。动态调度可以通过软件或者硬件的方式进行实现。接下来介绍什么是动态规划以及其特点。

动态调度(dynamic scheduling)

动态调度是通过逐步获得的消息,重新安排指令的顺序。
个人理解这里逐步获得的消息指,在issue过程中得知不同指令的依赖。如果前部指令依赖未执行完的指令,动态调度就会选择别的没有依赖的指令进行issue。

动态调度的要点

*动态调度的池子(instruction window)需要比较大才能保证找到独立的指令。
*遇见中断能把乱序执行的指令回滚成顺序的状态。
*能迅速issue指令。(寄存器的依赖可以很快判断,但是涉及memory的依赖就需要时间并且更麻烦)

个人理解动态调度有软件优化和硬件的实现组成。
编译器需要对指令进行loop unrolling以提高找到独立指令的几率。(变相提高动态调度的池子)

例子(出现了WAW冲突,但是可以靠register renaming去除,之后详解)

这个例子不知道恰不恰当。(不太清楚j指令有没有依赖)

1
2
3
4
5
6
#r2 = 1000
#r1 = 0
loop:
beq r1,r2,#2
addf r1,r1,#1
j loop

#改循环已经运行了一段时间

instruction beq r1,r2,#2 addf r1,r1,#1 j loop beq r1,r2,#2 addf r1,r1,#1 j loop
dependency r1 r1 none r1 r1 none

如上述例子,因为beq和adddi有依赖的关系。当addf还在计算中,因为addi可以通过register forward不需要等待 ,但是浮点数的运算需要花更多的时间,所以后续的beq需要等待addf完成才能运算,尽管运用了乱序的动态调度。但是如果运用了loop unrooling。

1
2
3
4
5
6
7
8
9
10
11
12
13
#r2 = 1000
#r1 = 0
loop:
bge r1,r2,#5
addf r1,r1,#1
addf r1,r1,#1
addf r1,r1,#1
addf r1,r1,#1
j loop
loop 1:
beq r1,r2,#5
subf r1,r1,#1
j loop1
instruction beq r1,r2,#2 addf r1,r1,#1 addf r1,r1,#1 addf r1,r1,#1 addf r1,r1,#1 j loop
dependency r1 r1 WAW WAW WAW none

如上述例子就可以从软件上解决动态调度的问题,以上例子不太准确,可能有很多问题,但是大致思路是loop unrolling释放更多指令池,方便有依赖时调用独立的指令。

硬件则需要全部实现动态调度,因为少一些面向软件的接口,硬件能更快速,更节省占用面积。