编译器设计与汇编语言程序员优化编程

1。前言
      1.1手册简介
       这个手册是五卷手册系列之三:
               1。C++中的优化设计软件:支持Windows,Linux和Mac平台的优化编程指导。
               2。汇编语言子程序优化设计:x86平台优化编程指导。
               3。Intel和AMD的CPU的微结构:汇编程序员和编译器设计者的优化编程指导。
               4。指令列表:Intel和AMD的CPU的指令周期,吞吐量和微操作故障列表。
               5。不同C++编译器和不同操作系统的调用惯例。
这些手册的最新版本可以从www.agner.org/optimize 网站获得
手册五列出了版权条件。
这卷手册详细描述了Intel和AMD的CPU的x86微处理器的微结构。但是没有涉及到Itanium处理器。这卷手册的目的是方便汇编程序员和编译器设计者对特定的微处理器优化设计软件的。主要焦点集中在与计算执行代码占用多少时间片断相关的细节上,比如不同的执行单元的周期,通道的各个部分的吞吐量。分支预取算法也包含在这些细节中。
这卷手册对微结构专业的学生也是很有意义的。但是必须注意到所说明的技术主要的基于我个人的研究,仅限于可以测量的情况。因此,管道的“机制”的说明仅限于可以由计数时钟循环或者为操作测量和从这些测量中可以减少的情况。这卷手册中的机制说明应该看作是预测微处理器行为的模型。我并不能够确切的知道它是否与微处理器的实际物理结构相一致。提供这个信息的主要目的是方便程序员和编译器设计者优化他们的代码的。
另外我的通过测量来推演信息的方法而不是依赖与微处理器制造商提供的许多新的信息的方法,在其他任何地方都是找不到的。微处理器制造商出版的技术细节总是肤浅的,不完整的,有选择的并且有时是误导的。
我的发现有时候会与微处理器制造商出版的数据不一致。这种矛盾的可能是这些数据是理论上的,而我的数据是在一个特定测试条件下的实验中获得的。我不认为这卷手册中的所有信息都准确。有时特别是很难或者不可能来精确的测量的时候,并且我不能访问微处理器制造商基于他们的技术手册实施更深层技术的信息。
我已经完成了多个处理器模型的测试:实模式和保护模式,16位的,32位的电荷64位的。大部分的时间结果独立于这些处理器模型的。适当的重要差别已经注明。大部分的远程跳转,远程调用和中端已经在16位模式下测试。调用门等等还没有测试。详细的时间结果在手册4:“指令列表”中列出。
这卷手册中的大部分信息基于我个人的研究。许多志愿者给我寄送了有用的信息和订正,我表示深切的感谢。当我又新的重要信息时,我会保持更新的。因此这卷手册比其他的资源信息更加详尽,全面和准确,并且包含任何其他地方都找不到的我个人研究的细节。
这卷手册不适合初学者。假定读者对汇编语言和微处理器结构有很好的理解。如果不是请阅读这个专业相关的书籍,获得一些编程经验之后再开始做复杂的优化。参考手册2:“汇编语言优化子程序设计”的参考文献列表。或者参考连接:www.anger.org/optimize
除非在嵌入设备中使用旧的微处理器或者对微处理器发展史有兴趣,你可以跳过描述旧处理器设计的章节。
不要把你的编程问题寄送给我,我不想替你做家庭作业!如果你在相关的书中或者手册中找不到答案,你可以在许多论坛中找到答案,因特网上有很多相关的论坛。
        1.2  手册包含的微处理器版本
这卷手册讨论了下列x86微处理器家族:
微处理器名字                                                                                         缩写
Intel Pentium (without name suffix)                                                              P1
Intel Pentium MMX                                                                                    PMMX
Intel Pentium Pro                                                                                         PPro
Intel Pentium II                                                                                            P2
Intel Pentium III                                                                                           P3
Intel Pentium 4 (NetBurst)                                                                            P4
Intel Pentium 4 with EM64T,                                                                        Pentium D, etc. P4E
Intel Pentium M, Core Solo, Core Duo                                                         PM
Intel Core 2                                                                                                  Core2
AMD Athlon                                                                                                AMD K7
AMD Athlon 64, Opteron, etc., 64-bit                                                         AMD K8
AMD Family 10h, Phenom, third generation Opteron                                    AMD K10
这里的缩写打算区分不同核心的微处理器,与商标无关。这些微处理器的商业名称总是混淆不同核心技术的不同。Celeron这个名字适用于比标准版本少携带缓存的P2,P3,P4或者PM微处理器。Xeon这个名字适用于比标准版携带更多缓存的P2,P3,P4或者Core2微处理器。Pentium D和Pentinum Core2这两个名字指的是带有双核心的P4E微处理器。Centrino这个名字适用于Pentium M,Core Solo和Core Duo处理器。Core Solo更像Pentium M。Core Duo也很像,但是有两个核心。
Sempron这个名字适用于携带少量缓存的的版本地Athlon64处理器。Turion 64是一个移动版本的。Operon是一个服务器版本的拥有更多的缓存。一些P4E,PM,Core2和AMD版本的处理器拥有多核心。
P1和PMMX处理器代表Intelx86系列微处理器的第5代,他们的处理器核心非常相似。PPro,P2和P3都是第六代核心。这三个处理器除了新模型增加了新指令之外几乎是相同的。P4时第七代中的第一个,由于未知的原因在Intel文档中没有称作第七代。相当出乎意料的是,P4的CPUID指令返回的代数不是7而是15。当后来的Intel的CPU:Pentium M,Core和Core2报告是6代时就完全混乱了。
读者应该意识到,不同代的微处理器表现相当不同。并且Intel和AMD微处理器也有很大的不同的。对于这一代或者这个品牌是最好的,对于其他的就是不好的。
2。乱序执行(除P1和PMMX之外的所有处理器)
从PPro开始的第六代微处理器增加了一个重要的改进设计,叫做乱序执行。他的思想是如果一个特定指令的执行延迟是由于这个指令的输入数据没有准备好,这个微处理器将会尝试执行后边的指令。显然,微处理器必须检查后来的指令是否需要前一个指令输出的数据。如果每条指令都依赖前一个指令的结果,那么我们没有机会适用乱序执行。这个称作依赖链。手册2:“汇编语言子程序优化”给出了怎样避免长的依赖链的例子。
检验输入数据的依赖性和当需要的输入数据准备好时尽可能快地执行指令的机制给我们提供了一个进一步的优势,就是微处理器可以同时做几件事情。如果我们同时进行加法或者乘法计算,没有指令依赖于其他指令的输出数据,那么我们就可以同时做这两件事,因为他们适用两个不同的执行单元。但是,如果我们只有一个乘法单元时的,我们不能够同时进行两个乘法运算。
典型的事例就是,为了改进提高吞吐量,微处理器的任何部分都是在流水线内高速流动运行的。否则,例如浮点数加法占用4个时钟周期,将T+4的时刻内完成,并且在T+1的时刻开始另一个加法计算,在T+5的时刻结束。因此,当代码组织成成功执行的指令之间的相互依赖性尽可能少的时候,这种技术是最先进的。
2.1指令被分解成微指令
有乱序执行指令功能的微处理器将所有的指令转换成微指令简记为uops。像ADD EAX,EBX这样的简单的指令只产生一个微指令,而像add eax,[mem1]这样的指令可能产生两个:一个是将内存中的数据读入一个暂存寄存器(未命名),另一个是将暂存寄存器的项目加进eax。add [mem1],eax指令可能产生三个微指令:一个是从内存中读出数据,另一个是加数据,最后一个是将结果写回内存。它的先进性在于微指令可以乱序的执行。
例如:
                                  ;example 2.1. out of order processing
                                  mov   eax,[mem1]
                                  imul    eax,5
                                  add    eax,[mem2]
                                  mov   [mem3],eax
这里,指令add eax,[mem2]分成两个微指令。它的先进性在于,微处理器可以做乘法的同时从[mem2]中取数据。如果数据都不在缓存中,然后微处理器将在开始取[mem1]中的数据之后立即开始取[mem2]中的数据,比乘法提前了很多。分离成微指令也可以使堆栈更有效的工作。考虑下列的程序:
                               ;example 2.2. Instructions split into uops
                               push    eax
                               call      func
指令push eax分离成两个微指令可以被代替为sub esp,4和mov [esp],eax这里的优势在于尽管eax的数值还没有准备好,微指令sub esp,4就可以进行。调用操作需要esp的新数值,因此如果push指令没有分离成微指令的时候,调用可能需要等待eax的数值。由于使用了微指令,从而在正常的程序中,堆栈指针决不会产生延迟。
2.2 寄存器重命名
考虑这个例子:
                            ;例子  2.3。寄存器重命名
                            mov     eax,[mem1]
                            imul      eax,6
                            mov      [mem2],eax
                            mov      eax,[mem3]
                            add       eax,2
                            mov       [mem4],eax
这片代码作两件毫不相干的事:6乘以[mem1]何2乘以[mem3]。如果我们在最后的三个指令中使用不同的寄存器,很显然他们是相互依赖的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值