LLVM和优化的未来

时间:2011-07-12 22:32:50

标签: optimization gcc compiler-construction llvm compiler-optimization

我意识到LLVM还有很长的路要走,但从理论上讲,可以在GCC / ICC /等中进行优化。个别语言应用于LLVM字节代码?如果是这样,这是否意味着编译为LLVM字节代码的任何语言都有可能同样快速?或者是特定于语言的优化(在LLVM字节码阶段之前)将始终在优化任何特定程序中发挥重要作用。

我对编译器或优化知之甚少(只是危险),所以如果这个问题没有明确定义我会道歉。

7 个答案:

答案 0 :(得分:21)

一般来说,没有。

例如,在Haskell中,常见的优化是严格性分析,它允许编译器确定哪些变量始终处于头部正常形式,因此可以强制+内联而不改变程序语义。 LLVM无法做到这一点。

说明:在Haskell中,函数(Int, Int) -> Int或多或少等同于C中的类型:

typedef int (*returns_int)();
struct pair { returns_int first, second};
typedef struct pair *(*returns_pair)();

int function(returns_pair arg);

编译器可以分析function并确定它总是评估其参数并始终提取内容,将函数转换为:

int function(int x, int y); // note that it takes *two* arguments now

这远远超出了LLVM的能力。也许,在未来,有一些非常繁重的过程间优化......但实际上,这在可预见的未来不会发生。

示例2:有些Java VM可以将虚函数调用转换为直接函数调用。但是,这不是LLVM可以执行的操作 - 因为如果加载另一个实现相同接口的类,则必须动态撤消此转换。

通常,当您将程序编译为LLVM时,会丢失大部分有关原始程序的语义信息。 LLVM字节码能够表示任何代码,但其类型系统相当有限 - 您选择的类型系统会影响您可以执行的优化。

答案 1 :(得分:10)

除了Dietrich的优秀答案之外,我认为重要的是要认识到编程语言的速度不仅仅是编译器。除了给定语言可能允许/禁止的各种优化之外,还有如何您在各种编程语言中执行某些任务的问题以及允许您的语言做。

例如,优化C代码以最大化缓存效率(减少从内存的慢读取)相对容易,而在Haskell中这要困难得多。在Java中,指针黑客是不可能的。正如分配大量内存并手动分配的策略一样。

因此,一些语言总是会变慢,因为它们不允许相同级别的优化。请注意,我并不一定说这是一件坏事,因为这种缓慢会带来极其强大的结构。

我认为更好的方法是查看它,LLVM将允许将一组优化应用于编译到它的所有语言。因此,虽然它使这些语言更快,但它不会使它们同样快。

编辑:Haskell中的指针黑客攻击。这么多的可能性......

答案 2 :(得分:5)

这是一个有趣的问题,但我担心你缺乏一些关于编译器的概念。

编译器中总会有几个优化阶段。

  • 某些优化依赖于语言规则,例如在C ++中,您可以优化一些复制/移动构造函数调用。
  • 广泛可用的一些优化(循环变换,尾调用)
  • 某些优化取决于硬件(SSE,MMX)

LLVM编译器应用全部3 ...但是从LLVM IR开始,而不是从C或Java或其他任何东西开始。

提供合适的LLVM IR是前端的工作。

例如,如@Dietrich Epp所述,IR并不适合功能语言。因此,在将表示降低到IR之前,必须执行许多Haskell优化

非优化的另一个来源是特定的运行时可能带有语言。 Haskell具有复杂的运行时,包括火花池,轻量级线程,系统调用之前的抢占,工作窃取等...... IR不适合代表这种丰富的环境,并且不对该组织进行优化。

答案 3 :(得分:2)

LLVM已成为一个很有前途的替代GCC(它甚至成功编译Linux内核,有一些补丁)。它在许多情况下也比GCC(编译器和生成的可执行文件)更快,并且具有使得为任意语言编写前端非常容易的结构。

但是为了允许广泛的优化,前端同样重要,因为它知道有关正在编译的程序的更多细节。 LLVM堆栈无法轻易找到的东西。因此,为了生成有效的程序,前端还必须优化代码。

答案 4 :(得分:1)

回到你的问题“理论上可行吗?”, 让我们想象/假设 - 仅仅为了讨论 - 以下:

  • 我们有字节码,甚至是机器码
  • 我们知道它是用给定的编译器X
  • 生成的
  • 源语言是L
  • 输入程序的大小有限。
恕我直言 - 从计算机科学的角度来看,几乎所有东西都是资源问题。

现在让我们试试

function machinecode_to_sourcecode( given_machinecode ){
  it = all_posibble_strings_iterator()
  while (true) {
    possible_sourcecode = it->get_string()
    machine_code = compile possible_sourcecode with X
    if (compilation succeeded)
        if(machine_code == given_machinecode)
           return possible_sourcecode;
    else
       it = it->next_string()
  }
}

所以我们尝试所有可能的字符串,作为编译器X的输入,如果编译成功 - 结果相同,我们有源。

一旦我们有了源代码,我们就会尽可能多地提供有关程序的信息,因此我们可以应用所有可能的优化。

所有看起来都很昂贵,但正如你在理论上问过的那样,我会说

  • 需要有限的时间

,因为

  • 输入源代码有限长度

所以

  • 迭代所有这些字符串需要有限的时间
  • 我假设,编译器在有限的时间内处理任何源代码(这是我们在考虑编译器时通常假设的那样;)。)

整个操作将花费有限的计算时间。

答案 5 :(得分:0)

我不知道有关LLVM使用的字节码格式的任何细节,但我认为你的问题的答案是否定的。

请考虑以下内容:动态与静态类型。动态类型化的编程语言可能比静态类型语言慢,因为大多数类型检查都是在运行时执行的。

编程语言之间也可能存在一些其他差异,这可能会影响性能。

答案 6 :(得分:0)

在这里,我找到了报告,很容易让begginers概述GCC与LLVM的差异: Clang/LLVM Maturity Evaluation Report by Dominic Fandrey