【Microarchitecture of Intel and AMD CPU】 2 Out-of-order execution

Intel 的第六代微处理器,从PPro开始,提供了一种重要的技术提升,乱序执行。如果一条指令的输入因为某些原因在当前时刻还未准备好,那么我们可以尝试执行这条指令后面的指令。当然,处理器需要检查时候后面的指令需要前面的指令的执行结果。如果每一条指令都依赖于前一条指令的结果,那么这就叫做依赖链。

判断输入依赖关系的逻辑,和一旦其所依赖的数据一旦准备好,就立即执行机制已经就绪,这使得处理器可以在同一时间并行做多件事。如果我们需要进行加法或者乘法,并且他们指令互不依赖,那么我们就可以同时执行他们,因为我们使用两种不同的执行单元。但是我们不能同时执行两个乘法指令,如果我们只有一个乘法单元。

处理器一般按照顺序进行流水,以增加吞吐量。如果浮点加法需要4拍,并且执行单元完全pipeline,那么我们可以在时间T开始执行一个加法,在T+4时,将会得到加法的结果;在T+1时执行另一笔加法,在T+5时得到下一笔的结果。这个技术的优势将会得到最大化,如果code被组织成连续之间没有依赖关系的形式。

2.1 指令分解为uops

乱序执行的微处理器将会将执行分解为微操做,简记为uops. 一个简单的指令,比如 ADD EAX,EBX 通常是一条uop,然而ADD EAX,[MEM1] 通常会被分解为两条指令:

1)从MEM1处加载数据到临时寄存器;

2)将临时寄存器和EAX的值累加到EAX上。

指令ADD [MEM1],EAX则会分解为三条uop

1)从MEM1处加载数据到临时寄存器;

2)将临时寄存器和EAX的值累加到临时寄存器上;

3)将临时寄存器的值写回memory。

这个操作的优势就是uops可以被乱序执行

; Example 2.1. Out of order processing
mov eax, [mem1]
imul eax, 5
add eax, [mem2]
mov [mem3], eax

此处,ADD EAX,[MEM2] 指令会被分解为两条微指令。这个的好处就是可以同时加载mem2处的数据,同时执行imul的乘法。如果这些数据都不在cache中,微处理器将会在读取mem1处的数据之后,立刻读取mem2处的数据,可以远早于乘法的执行。

将指令分解为微指令也可以使得栈工作的效率提升,考虑下面的sequence

; Example 2.2. Instructions split into μops
push eax
call func

push eax指令会分解为两条uop:SUB ESP,4和MOV [ESP],EAX。这样做的优势就是SUB ESP,4可以提前执行,即使此时EAX还没有准备好。CALL指令需要ESP的最新值(将EBP设置为ESP的值)。 如果 PUSH指令没有被分解为两条微指令,那么CALL指令需要等待PUSH指令的执行完毕。幸好我们使用了微指令,栈指针的基本不会耽误我们的程序。

2.2 寄存器重命名

考虑下面的例子:

; Example 2.3. Register renaming
mov eax, [mem1]
imul eax, 6
mov [mem2], eax
mov eax, [mem3]
add eax, 2
mov [mem4], eax

这个代码片段中执行了两个毫不相关的指令,【mem1】*6 和【mem2】+2。如果最后三条指令使用不同的寄存器,那么它们就明显的不相关。实际上,微处理器可以实现这个技术。它会为后面的三条指令使用不同的临时寄存器,这样就可以同时执行加法和乘法了。IA32指令只给了我们7个32bit的通用寄存器,通常我们会用光。所以我们没法给每个计算都配置一个新的寄存器。但是微处理器有大量的临时寄存器可以使用。微处理器可以重命名任意的临时寄存器,以代表逻辑架构寄存器EAX。

寄存器重命名可以十分的自动化并且以非常简单的方式工作。每次一条指令想要写入逻辑寄存器,处理器都会为这个逻辑寄存器分配一个新的临时寄存器。上面例子中的第一条指令要写如EAX,所以一个新的临时寄存器会被分配。换句话说,乘法指令将要使用两个不同的寄存器,一个用于输入,一个用于输出。(译者注:原例 imul eax 6 是将eax的值乘6后再写入EAX)下面的例子介绍了这样做的优势

; Example 2.4. Register renaming
mov eax, [mem1]
mov ebx, [mem2]
add ebx, eax
imul eax, 6
mov [mem3], eax
mov [mem4], ebx

假如【MEM1】在cache中,但是【MEM2】不在。这意味着乘法将会在加法之前启动。使用临时寄存器的优势就是,即使后面再执行加法,那么我们也不会破坏eax原始的值。如果我们使用同一个寄存器既做输入又做输出,那么乘法需要等待ebx的加载完毕,然后加法才能执行。

在所有的指令执行完毕之后,代码段中最新的临时寄存器中的值将会被写入逻辑架构EAX寄存器。这个阶段又叫做retirement(退休)。

所有的上述通用寄存器,栈寄存器,标志位,浮点寄存器和向量寄存器和段寄存器都可以被重命名。多数处理器不允许控制字和浮点状态字被重命名,这就是代码修改这些寄存器较慢的原因。


翻译自【Microarchitecture of Intel and AMD CPU  An optimization guide for assembly programmers and compiler makers

                                                                                                                    -------------------欢迎关注我的公众号《处理器与AI芯片》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值