Intel, AMD及VIA CPU的微架构(2)

来源:互联网 发布:淘宝818开学季 商城 编辑:程序博客网 时间:2024/05/17 04:39

2.      乱序执行(除了P1,PMMX的所有处理器)

从Ppro开始的第六代Intel微处理器,在微架构实际上,提供了一个重要的,称为乱序执行的改进。思想是,如果由于输入数据尚不可用,一条特定指令的执行被推迟,那么处理器将尝试在后续指令中找出它可以执行的第一条,如果该指令的输入数据已就绪。显然,微处理器必须检查后续指令是否需要前面指令的输出。如果每条指令都依赖之前指令的结果,那么我们没有乱序执行的机会。这称为依赖链。手册2:“优化汇编例程”给出了如何避免长依赖链的例子。

确定输入依赖的逻辑,以及一旦必须的输入就像就执行指令的机制,给予我们更多好处——微处理器同时可以完成几件事情。如果我们需要做一次加法与一次乘法,并且两者彼此不依赖,那么我们可以同时进行两者,因为它们使用两个不同的执行单元。但如果只有一个乘法单元,我们无法同时执行两个乘法。

通常,这些微处理器中的一切都是高度流水线化的,以提升吞吐率。例如,如果浮点加法需要4时钟周期,并且执行单元完全流水线化,那么在T时刻我们开始一次加法,它将在T+4时刻完成,而在T+1时刻开始另一次加法,它将在T+5时刻完成。因此,如果代码可以组织成在相邻指令间的依赖性尽可能少,这个技术的优势是最大的。

2.1.      指令被分解为微操作

具有乱序执行能力的微处理器把所有的指令翻译为微操作——缩写为μops或uops。简单指令,像ADDEAX, EBX仅产生一个μops,而像ADDEAX, [MEM1]的指令可能产生两个μops:一个用于从内存读入一个临时(匿名)寄存器,另一个将临时寄存器的内容加到EAX内容上。指令ADD[MEM1], EAX可能产生三个μops:一个读入内存,一个执行加法,一个将结果写回内存。这样的好处是μops可以乱序执行。例如:

;Example 2.1. Out of order processing

moveax, [mem1]

imuleax, 5

addeax, [mem2]

mov[mem3], eax

这里,指令ADDEAX, [MEM2]被分解为两个μops。这样的好处是,微处理器可以在进行乘法的同时获取[MEM2]的值。如果数据不在缓存里,在开始获取[MEM1]后,微处理器将立即开始获取[MEM2],远在乘法可以开始之前。分解为μops还使得栈的工作更有效。考虑这个序列:

;Example 2.2. Instructions split into μops

pusheax

callfunc 10

指令PUSHEAX可能被分解为两个可以表示为SUBESP, 4及MOV[ES], EAX的μops。这样的好处是,即使EAX的值还未就绪,也可以执行μopsSUB ESP, 4。操作CALL需要ESP的新的值,因此,如果指令PUSH没有分解为μops,CALL必须等待EAX的值。归功于μops的使用,栈指针的值几乎从不会导致普通程序的延迟。

2.2.      寄存器重命名

考虑这个例子:

;Example 2.3. Register renaming

moveeax, [mem1]

imuleax, 6

mov[mem2], eax

moveax, [mem3]

addeax, 2

mov[mem4], eax

这段代码执行两件彼此无关的事情:[MEM1]乘上6,[MEM3]加上2。如果在最后三条指令中,我们使用另一个寄存器,那么无关性就很明显。事实上,微处理器胜任这个工作。在最后三条指令中,它使用别的临时寄存器,因此它可以并行进行乘法与加法。IA32指令集仅提供7个32位通用寄存器,通常我们耗尽它们。因此我们承受不起为每次计算使用一个新寄存器的奢侈行为。但微处理器有大量的临时寄存器可用。微处理器可以重命名这些临时寄存器中的任一个来代表一个逻辑寄存器,比如EAX。

寄存器重命名以一个非常简单的方式,完全自动完成。每次指令写或修改一个逻辑可寄存器时,微处理器将一个新临时寄存器分配给逻辑寄存器。上面第一条指令将分配一个临时寄存器给EAX。第二条指令将新的值放入EAX,因此这里将分配一个新临时寄存器。换而言之。乘法指令将使用两个不同的寄存器,一个用于输入,另一个用于输出。下一个例子展示这样的好处:

;Exampe 2.4. Register renaming

moveax, [mem1]

movebx, [mem2]

addebx, eax

imuleax, 6

mov[mem3], eax

mov[mem4], ebx

现在,假定[MEM1]在缓存里,而[MEM2]不在。这意味着乘法可以先于加法开始。对乘法结果使用一个新临时寄存器的好处是,我们仍然有EAX旧的值,必须保留它,直到EBX对加法就绪。如果我们对乘法的输入、输出使用相同的寄存器,那么乘法将必须等待,直到载入EBX且加法完成。在所有的操作完成后,代表代码序列中EAX最终值的临时寄存器的值被写入永久的EAX寄存器,这个过程称为回收(retire)(参考81页)。

所有通用寄存器,栈寄存器,标记,浮点寄存器,向量寄存器及可能段寄存器可以重命名。许多处理器不允许重命名控制l1字,浮点状态字,这是为什么修改这些寄存器的代码慢的原因。