Compiler construction 编译器级的分支预测

Compiler construction 编译器级的分支预测,compiler-construction,cpu,Compiler Construction,Cpu,我一直在阅读有关分支预测的文章,但我发现的唯一实现大多是在计算机的硬件方面。处理器似乎处理了大部分预测。我的问题是,编译器可以进行分支预测吗? 我只找到了两个方法,函数内联和循环展开。这些被认为是正确的吗?它们还在用吗?当然。编译器可以获得预测信息,前提是它知道: 通过检测运行收集的统计分支概率 通过仪器运行收集的变量值的统计分布;然后,它可以预测条件分支的平均结果,从而预测分支 程序员关于条件语句的频率或偏差的断言 基于范围的循环边界估计(如果未知,则默认为“10”) 分支向后到达循环顶部的

我一直在阅读有关分支预测的文章,但我发现的唯一实现大多是在计算机的硬件方面。处理器似乎处理了大部分预测。我的问题是,编译器可以进行分支预测吗?
我只找到了两个方法,函数内联和循环展开。这些被认为是正确的吗?它们还在用吗?

当然。编译器可以获得预测信息,前提是它知道:

  • 通过检测运行收集的统计分支概率
  • 通过仪器运行收集的变量值的统计分布;然后,它可以预测条件分支的平均结果,从而预测分支
  • 程序员关于条件语句的频率或偏差的断言
  • 基于范围的循环边界估计(如果未知,则默认为“10”)
  • 分支向后到达循环顶部的知识(预测“take”
使用这些信息,它可以预测条件语句的可能结果,然后生成倾向于通过硬件“预测”正确的分支指令

一些编译器执行的一组特别有趣的优化是,它根据顺序遇到的分支的概率通过代码确定路径集。通过确定概率最高的路径,编译器可以跨整个路径而不是仅在基本块内执行优化

有时编译器会生成间接使用硬件分支预测功能的分支代码。编译的OO语言(静态或JITted)必须编译方法调用,而跳转间接调用代价高昂。一个便宜的技巧是在每个调用站点保留最近调用的方法的小动态缓存,并检查正在调度的对象类型。如果在调用站点经常使用相同类型的对象进行调度,则第一个调用的比较/分支序列缓存中的条目(第二个条目的可能性较小),执行的代码因此避免了预测失误。这比间接跳转要好得多

最后一个标准技巧:如果可以避免执行分支,则不必正确预测它!许多代码序列如下所示:

  if (exp1 relop exp2)
      X = Y
  endif
现代CPU有“谓词”指令,实际上是“MOV_if_relop A to B”, 对于所有关系条件,包括相等、不相等、较小等。 因此,编译器不会为上述构造生成分支,而是生成:

  <compute exp1 and exp2>
  CMP  exp1,exp2 ; sets condition code
  MOVif_relop  X,Y

CMP exp1、exp2;设置条件代码
MOVif_relop X,Y