扩展编译器以评估"复杂"编译时的函数(具有已知输入值),来自`constexpr`到达

时间:2015-04-24 21:24:44

标签: c++ gcc compiler-optimization constexpr

请查看this example。尝试使用constexpr来获得编译时评估将是非常困难的,如果不是不可能的话。

但是,在调用函数的地方,所有参数在编译时都是已知的。理论上,(存在一些优化属性?),编译器可以暂停解析,用函数创建一个小程序,编译它,运行它,并获得结果来创建一个char常量,用于主程序编译。

我理解其中一个问题就是例如交叉编译:如果编译器可以构建一个可以在正在构建的机器上运行的程序,那么你只能从编译器运行一个程序。但这似乎无法克服。

毫无疑问:我不是第一个考虑它的人。但我试图搜索,我只能找到constexprtemplate的东西。是否有计划在未来的任何编译器中实现此类功能?该功能也可以改为:允许在C ++源代码中编写C ++程序,编译器可以根据请求编译和运行,以创建常量。

2 个答案:

答案 0 :(得分:3)

constexprtemplate是C ++中强制编译器在编译时执行某些操作的唯一方法。 在许多情况下,优化器也能够找出更复杂的功能。 但是,您可能会无意中离开编译器的“舒适区”,例如,通过一些分配和/或指针算法。

正如Marc Glisse在评论中指出的那样,在您的具体示例中,您使用的是std::string而不是本地char*,并且由于在该类的实现中完成了魔法,优化器可能会丢失

话虽这么说,你可能会欢迎C ++ 14,它放宽了对constexpr功能的要求。 您现在可以声明局部变量,具有变异对象并具有基本控制流结构。 您也可以操作原始字符串。

https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr

从更广泛的角度来看,正在进行一项研究,以便为编程语言提供升级服务。 暂存是通过显式代码构造部分评估程序的想法,甚至允许在编译时执行最复杂的函数。 从不同角度来看问题的一些示例方法:

请注意,这些都没有尝试在C ++中这样做。

答案 1 :(得分:2)

你基本上想要的东西与标准C ++提供的不同。请注意,语言标准没有定义需要哪些优化,而只是大多数优化都是合法的。

CyghusX1 answer给出一些一般性提示。

如果您使用的是POSIX(例如Linux),您还可以在“运行时”生成一些专用的 C ++代码,分叉它的编译,并使用动态加载工具(即{{1} })生成的“插件”;更具体一点:

  • 有一些你想要生成的C ++子集AST的模型
  • 使用dlopen
  • 编译和链接您的主程序
  • 定义了一些有关如何调用插件的约定,例如:决定你想要一些-rdynamic -ldl功能。
  • 编写一些声明该AST类型的代码
  • 在某个文件中编写将该AST作为C ++代码发出的代码,生成的C ++代码应遵循您的插件约定(因此将提供您想要的extern "C" int foo(const char*)函数;避免name mangling
  • 具体地说,在临时文件中发出C ++代码int foo(const char*)
  • 通过运行类似/tmp/temp1234.cc的内容将其编译作为共享对象进行分支,例如使用system(3)或其他内容
  • 使用g++ -O -Wall -fPIC /tmp/temp1234.cc -shared -o /tmp/temp1234.so/tmp/temp1234.so上致电dlopen(3);检查是否失败(否则,请使用RTLD_NOW|RTLD_GLOBAL
  • 使用dlerror()外部名称在dlsym提供的句柄上调用dlopen。这给出了一个函数指针,稍后可以调用它。

在Linux上,您可以重复多次(实际上,至少数十万次,请参阅我的manydl.c示例)。我的GCC MELT工具正在做这些事情。

实际上,GCC MELT用于自定义和扩展GCC编译器,您甚至可以用于实现目标,因为它可以自定义GCC;所以你可以添加一些标记你想要专门化的函数的新属性或编译指示,并对进行专业化的MELT扩展进行编码(你需要理解GCC internals,特别是Gimple,这样就可以了超过一周,您的foo可以使用您的MELT扩展程序提供的部分附加 GCC内置版本。)

所以有像

这样的东西
__COMPACT_PRETTY_FUNCTION__

并编写实现新#define __COMPACT_PRETTY_FUNCTION__ _builtin_compact_pretty_function() 内置编译器的MELT扩展。