在C中运行时“内联”(种类)函数

时间:2010-05-05 17:33:15

标签: c lisp metaprogramming inline jit

我正在考虑一个非常JIT能够解决的典型问题,但很难用原始C进行处理。该场景设置了一系列将被“组合”的函数指针(如数学函数组合)一旦在运行时,然后调用很多次。

以明显的方式执行它涉及许多虚拟调用,这些调用很昂贵,如果有足够的嵌套函数来完全填充CPU分支预测表,那么性能会大幅下降。

在像Lisp这样的语言中,我可能会处理代码并用函数的实际内容替换“虚拟”调用,然后调用compile来获得优化版本,但这看起来非常h​​acky和错误容易在C中做,并且使用C是这个问题的要求; - )

那么,你知道在C中是否有一种标准,便携和安全的方法来实现这一目标吗?

干杯

3 个答案:

答案 0 :(得分:6)

您可能希望查看LLVM。他们有一个允许来自C的JITing代码(以及更多东西)的库,它支持许多平台,它是一个开源项目:http://llvm.org/

答案 1 :(得分:1)

我有两条关于消除虚拟功能调用的建议, if 表现必不可少。为了便于说明,假设您有一个函数指针作为参数的函数:

void my_algorithm(int (*func)(...), ...)
{
    /* ... */
}

并且假设您事先知道 函数指针可以采用的所有可能值。例如:

my_algorithm(func_1, ...);
//...
my_algorithm(func_2, ...);

首先将原始my_algorithm()转换为宏:

#define MY_ALGORITHM(func, ...)       \
{                                     \
    /* ... */                         \
}

然后将my_algorithm()重写为:

extern int func_1(...);
extern int func_2(...);

void my_algorithm(int (*func)(...), ...)
{
    if (func == func_1)
        MY_ALGORITHM(func_1, ...)
    else if (func == func_2)
        MY_ALGORITHM(func_2, ...)
    else
        assert(0 && "Unexpected function arg to my_algorithm()");
}

这当然会使编译对象文件的大小加倍。并且,从表面上看,它只删除了一个间接层。但是如果内联func_1和/或func_2,你可以获得相当大的加速。

你甚至可以'传递'宏,如:

#define HYPOT_Y(x) hypot(x, y)
MY_ALGORITHM(HYPOT_Y, ...);     //assumes y is known

第二个建议是使用X宏(http://en.wikipedia.org/wiki/C_preprocessor#X-Macros)的变体。而不是#define,将原始my_algorithm()的主体放入一个单独的文件my_algorithm.h中。然后将my_algorithm()重写为:

void my_algorithm(int (*func)(...), ...)
{
    if (func == func_1)
        #define func func_1
        #include "my_algorithm.h"
        #undef func
    else if (func == func_2)
        #define func func_2
        #include "my_algorithm.h"
        #undef func
    else
        assert(0 && "Unexpected function arg to my_algorithm()");
}

如果代码超过几十行,我可能会使用X宏。它的优点包括(没有双关语):

  • 没有丑陋的反斜杠
  • 更容易调试(例如回溯和单步)。

这是所有标准C.但相当老派。

答案 2 :(得分:0)

如果你只支持x86,你可以尝试嵌入TCC:

http://bellard.org/tcc/