【问题标题】:Optimize away memory loads by jit-compiling value as immediate通过即时编译值优化内存负载
【发布时间】:2017-05-27 08:51:32
【问题描述】:

假设我们在某种抽象编程语言中有以下代码-sn-p:

map<string, int> user_settings;
//somewhere at run-time user_settings are populated
for(i=0; i < 1000000000000; i++) {
    if (user_settings["do_stuff"] == 1) { do some stuff... }
    else { do other stuff }
}

这里的问题是,我们会在一些事情的运行时在循环内做很多负载,即“运行时常量”(即用户设置的某个值)。有可能通过立即加载提供价值,甚至完全优化无用的分支并仅使用所需的 then-else-branch 代码。
是否有执行此类优化的系统/编程语言/jit 编译器?我能找到的唯一相关工作是某个 MIT 家伙的论文:http://groups.csail.mit.edu/cag/rio/josh-meng-thesis.pdf
PS 我不是要优化 this em> 代码。我知道,您可以预先加载该值,该值将加载到本地寄存器中。在某些情况下,您无法手动执行此类“优化”。

【问题讨论】:

  • 甚至不需要结果是“运行时常量”——重要的是循环体不会改变它。对于每个优化器来说,将这种不变的评估从循环中移出几乎是标准的。
  • @Holger 你能提供例子吗?因为据我所知,只有 CS 研究 jit 编译器可以做到这一点,但没有生产就绪语言
  • 我不确定您认为哪种优化是一个障碍。认识到表达式是循环不变的,需要对其代码进行内联,这就是为什么要积极执行内联,例如在JVM内部。其余的是最先进的,例如The Hotspot whitepaper 说“优化器执行所有经典优化,包括死代码消除、循环不变提升、公共子表达式消除、常量传播、全局值编号和全局代码运动”...
  • 好吧,也许你已经假设这是不可能的。但是通过一些别名分析来确保 user_settings["do_stuff"] 只在循环内被访问而不是在循环内修改,结合循环不变的代码运动应该把它拉出循环。这是一个非常常见的优化。

标签: optimization compiler-construction compiler-optimization jit trace


【解决方案1】:

例如在动态链接器中使用的一种简洁方法可能在这里有用:

让您的编译器生成动态代码,以便知道是谁调用了它。

这样,如果动态代码发现它接收到的数据永远不会改变,它可以在调用站点重写代码。所以代替CALL get_user_setting "do_stuff" 它将用PUSH int 1 或其他东西替换指令,也许还有一些NOPs 来填充CALL 指令的大小。

动态链接器经常这样做。第一次尝试调用动态链接函数时,它们实际上会跳转到加载程序。它加载实际函数,然后重写 CALL 指令,以便调用加载的函数而不是例程来加载函数。然后,任何未来的调用都不必再次进行查找。 (我在博客上写过这个here

【讨论】:

    【解决方案2】:

    一个好的编译器优化步骤会可能从字典中预加载和测试“做的东西”,然后一起放弃迭代。如果它可以确定没有副作用会改变字典中“do stuff”的值,它就会这样做。

    如果您正在编写自己的编译器,则有大量的优化技术。当然,它们会根据您是在开发命令式语言还是函数式语言以及随之而来的tenets 而有所不同。

    例如,在大多数函数式语言中,我确信大多数模块声明的数据类型(列表、集合、映射)的内容不会随着时间的推移而改变(是持久的)。在某些情况下,这些语言支持副作用或变异功能,在这种情况下,您的优化也必须考虑到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      • 2012-02-03
      • 1970-01-01
      • 1970-01-01
      • 2018-12-30
      • 2018-07-19
      相关资源
      最近更新 更多