【问题标题】:What compilers can inline indirect function calls?哪些编译器可以内联间接函数调用?
【发布时间】:2010-08-21 22:24:06
【问题描述】:

LLVM 的 LDC D 编译器可以在某些情况下内联间接函数调用,前提是它可以证明目标是静态已知的。这是可能发生这种情况的玩具示例(在 D 中):

void main() {
    uint num;

    void incNum() {
        num++;
    }

    auto myDelegate = &incNum;
    myDelegate();
}

在这种情况下,尽管myDelegate() 调用名义上是间接调用,但目标对于人类读者和 LLVM/LDC 的流分析来说是显而易见的,因此它被内联。

在现代编译器中,将间接函数调用内联到静态可知目标的能力有多广泛? LLVM 是唯一可以做到这一点的提前编译器吗? JIT 编译器更常见吗?

【问题讨论】:

    标签: performance language-agnostic delegates compiler-construction compiler-optimization


    【解决方案1】:

    如果大多数 C++ 编译器都进行这种优化,我不会感到惊讶,至少是其中的一些变体。实际上,这是非常特定于语言和编译器的。

    我不能代表 D 语言,但是对于 C/C++,由于指针运算,上面的这种优化可能很难进行。例如,如果它是这样的,你能优化代码吗?

    ++myDelegate;
    myDelegate();
    

    这在很大程度上取决于myDelegate 的类型。以上可以是有效的 C/C++,但内联 myDelegate() 可能不是编译器可以保证的。

    其他语言(例如 Java、C# 等)没有指针运算,因此可以做出更多假设。例如,Sun JVM 可以将间接的多态调用转换为直接调用,恕我直言,这非常酷。示例:

       public class A2 {
          private final B2 b;
          public A2(B2 b) {
            this.b = b;
          }
          public void run() {
            b.f();
          }
        }
    
        public interface B2 {
          public void f();
        }
    
        public class C2 implements B2 {
          public void f() {
          }
        }
    

    A2 a2 = new A2(new C2()); 实际上可以优化,Sun JVM 可以接受。

    我从Java Specialists newletter 157 得到了这个例子,我推荐阅读它来了解 WRT Java 的这种东西。

    【讨论】:

      【解决方案2】:

      我认为大多数优化编译都可以做类似的事情(考虑到他们无论如何都会做各种流分析)。

      Jit 编译器有时甚至可以更进一步,内联间接调用,它们无法证明目标是静态已知的(或者根本不知道)。对于这种情况,如果目标是函数调用之前的预期目标,他们会插入一个测试,并且仅在不是时才使用间接调用(并根据每条路径的使用频率重新调整)。 IIRC .Net Jit 会这样做,我认为 java 也会这样做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-19
        • 2020-09-26
        • 2011-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多