我对c / c ++的(部分)编译时评估非常感兴趣(不是像c ++中的模板参数)。让我们考虑以下情况(取自[1]):
double mypower(double x, int n) {
int i;
double ret = x;
for (i = 1; i < n; i++) {
ret *= x;
}
return ret;
}
然后在代码中的某个地方调用此函数:
mypower(x,3); // y varies all the time,
然后编译器可以优化它(例如循环展开)。我使用的一些常用函数可以从优化中获益(通过手动创建专用函数进行测试)。演示文稿[1]描述了一个搜索函数的过程,并由函数的专用版本替换。这似乎有效。但它似乎并不是非常普遍,需要为应该替换的函数编写代码。
该演示文稿似乎是从2008年开始,我找不到比此来源更多的信息。那么从那时起有什么改进吗?我更喜欢某种自动化,它对可能由属性语法控制的所有函数都做同样的事情(例如__attribute__(peval)
...)。此外,我希望同样适用于面向对象的代码,为不同的对象创建专门的类([2]似乎暗示这是不可能的)。
此外,我希望这种专业化不仅适用于代码中的常量。我正在考虑编译为LLVM IR(字节码)的程序可以执行以下操作:
在解释器的初始化阶段运行程序,在初始化阶段,程序可以从文件中读取一些配置。初始化后,解释器停止。
从那一点开始修复一些变量(包括成员变量)。提取这些变量(例如在编译期间由属性标记)。
创建专门的函数和类。将这些克隆到字节码中。
运行JIT以创建本机机器代码。
这是我要求的很多,只有少数计算密集型程序可以从这种优化中受益。但是有些人必须在努力。我可能只是不知道正确的搜索条件来提供谷歌。
注意:请不要建议使用非类型参数或手动专业化的模板类,我已经这样做了。我只是希望编译器为我工作。
链接:
答案 0 :(得分:1)
这主要是在过程间优化的舞台上。 llvm有一些,特别是IP常量传播,只有在翻译单元的所有呼叫站点使用mypower(x,3)时才有用。你所描述的是可能的,但还没有真正完成。改善IPCP通行证是您希望通过在特定呼叫站点克隆和专门化功能来实现的。如果你有足够的翻译单元,这可能导致一些相当大的代码膨胀,这就是为什么人们还没有真正考虑这样做。
当您可以查看程序中的所有调用时,这可能会在LTO级别有更多用途。
答案 1 :(得分:0)
您可以使用源到源转换来完成此操作。
我们的DMS Software Reengineering Toolkit可用于实现此目的。 DMS使用显式语言定义将源代码解析为AST,将AST重新打印回源代码,提供各种符号表,控制/数据流功能,并提供转换功能,使人们能够构建自定义源代码转换器。 DMS有many front ends for differenct languages,包括带有完整预处理器的C和C ++。
要使用DMS完成任务,您可以使用C解析器来解析系统的所有代码(因为您必须检查所有部分特化的所有调用站点)。您需要定义一种方法来指定您希望的部分评估;正如你所建议的那样,一种方法是编写一个带有参数bound-to constants的函数调用,但你可以将它概括为绑定到任意表达式的参数。这样的规范可以由DMS的模式解析器解析,它可以处理任意的lnaguage非终结符,例如函数调用: - }你需要将这些规范存放在某个地方;也许作为一个额外的外部文件,或作为相关呼叫网站或其附近的评论。
通过解析partial-eval规范,您需要查找函数调用名称以确定感兴趣的实际函数;它位于该堆源中的某处,符号表将使这很容易找到。 给定一个具有特化的调用站点,可以复制已识别函数的AST并替换参数;可能只使用少量转换,但你必须注意由专用函数内部的词法范围捕获一个参数。四处走动可能需要额外的转换。 在对指定函数的新名称和缩短的参数列表进行gensymming之后,您将在原始函数定义站点附近重新插入其AST,适当地修改调用站点,并吐出修改后的AST。无论您是想为特殊情况添加其他变换来展开循环,还是其他任何您感兴趣的变量,都是实用的。
已经使用DMS对C和C ++代码进行大规模转换;这似乎“技术上”容易。熟悉DMS之类的工具是件小问题;那里有一个公平的学习曲线。