楼主你好,其实我感觉有很多实现细节你没讲到,当然并不是对你做出什么要求,说一下我希望知道的细节: 1. 分支预测失败时,如何对本地历史寄存器, local branch history register进行修复,这个问题难度很大,很少有论文讲到这个方面,最新的和本地分支预测相关的论文是Intel写的"Towards the adoption of Local Branch Predictors in Modern Out-of-Order Superscalar Processors". 同理还有Return Address Stack的修复操作,难度也很大。相比之下全局分支历史寄存器, GHR的修复代价就小很多,每个分支指令只需要携带他自己看到的一个几十bit的GHR就能修复。 2. 高性能cpu每个周期能取8/16/32-Byte的指令,这里边可能包含多条分支,此时如何同时对多条分支进行预测,理论上,前面的指令的跳转预测结果会影响后面的指令的预测,但是似乎不可能等前面的指令的预测结果出来了再预测后面的,不然的话会流水线stall很多个周期。
楼主,我新开一个楼层跟你讨论一下。 楼主你好,你似乎并没理解我说的第一个问题,有效的分支预测器都应当做到预测性更新,即用预测结果来更新预测器的状态, 而不是分支指令的执行结果来更新预测器的状态。比如一条beq指令,在frontend中就要用它的预测结果来更新本地历史了, 而不是beq指令进入后端执行流水线中的branch_unit之后才更新。所以这就会有一个问题, 所有的分支都在预测性的更新, 那么假设有这样的分支指令序列: beq, bne, blt, bge, call, ret, 假设先执行beq, beq本身预测错误,当cpu在分支解析单元中发现beq执行错误的时候 此时后面5条分支指令已经改变了本地历史和ras的内容,理论上来说此时cpu应当将本地历史和ras恢复到beq执行之前的内容,并且用 beq的执行结果来更新本地历史,然而这个代价是非常大的,因为从beq预测完毕到执行结果出现之前,这段时间内cpu可能已经在frontend里 取了几十条分支指令了,BHT (Branch History Table)不可能有几十个写端口,假设cpu每周期只能向bht中写入1个数据,那么如果要完美地修复 分支预测错误对bht/ras的污染,很可能需要几十个周期才能完成。 call指令在预测的时候应当进行压栈,即把call指令的pc+1写入ras,对于ras这种栈结构类型的存储器来说,错误取指路径上的多条call指令可能在frontend里就把 ras中有效的内容破坏了,而此时似乎是没有办法恢复的。 当然这种技术细节intel/amd/arm/apple等公司也不可能公布。 关于预测更新的必要性,可以参考论文: Speculative Updates of Local and Global Branch History, A Quantitative Analysis The effect of speculative updating branch history
今天再更新一点 上次讲了Skewed预测器,今天讲讲O-GEHL预测器,O-GEHL是Optimized Geometric History Length的简称,翻译过来就是优化几何历史长度。说到几何历史长度,大家也需还记得TAGE预测器。O-GEHL和TAGE一样,也使用了几何历史长度的BHR,或者更严谨的说,应该是TAGE借鉴了O-GEHL的几何历史长度BHR设计。在我看来O-GEHL介于Skewed和TAGE之间,具体实现原理和Skewed类似,由数个Gshare组成,同一般的Gshare一样,PHT的索引使用部分指令地址与BHR的哈希值,不同的是参与哈希计算的BHR值的长度从0开始呈几何级数增长,例如0、2、4、8……。另一个不同的地方是PHT中的饱和计数器值被视为带符号的值,首位1为正数,表示跳转,首位0为负数,表示不跳转。预测时,每组PHT根据各自的哈希值索引具体的项并输出该项的所有值(而非首位值),然后将各组PHT输出的值相加,结果为正数时预测为跳转,负数时预测为不跳转。这种算法的优势在于将之前2bit饱和计数器中10、01这种弱跳转、弱不跳转的状态也作为一种权重参与进预测计算,而不是简单的两分法,有点带有基于感知器的神经网络预预测器的感觉。O-GEHL预测器整体上来看具有类似本地/局部分支预测器的思路,细节上使用了类似Gshare的方法提高了PHT表的利用率并降低了别名干扰,技术还上参合了感知器的原理,和TAGE一样采用了几何历史长度的BHR,但却没TAGE未命中和高延迟的问题,个人感觉是一个集大成者,是我非常中意的一种分支预测器设计。