假设一个简单的部分评估场景:
#include <vector>
/* may be known at runtime */
int someConstant();
/* can be partially evaluated */
double foo(std::vector<double> args) {
return args[someConstant()] * someConstant();
}
Run Code Online (Sandbox Code Playgroud)
假设它someConstant()是已知的并且在运行时不会改变(例如,由用户给出一次)并且可以由相应的int文字替换.如果foo是热门路径的一部分,我预计会有显着的性能提升:
/* partially evaluated, someConstant() == 2 */
double foo(std::vector<double> args) {
return args[2] * 2;
}
Run Code Online (Sandbox Code Playgroud)
我目前对该问题的看法是在运行时生成LLVM IR,因为我知道部分评估代码的结构(所以我不需要通用的部分求值程序).所以我想编写一个foo_ir生成IR代码的函数,它执行相同的操作foo但不调用someConstant(),因为它在运行时已知.很简单,不是吗?然而,当我查看上面代码生成的IR时:
; Function Attrs: uwtable
define double @_Z3fooSt6vectorIdSaIdEE(%"class.std::vector"* %args) #0 {
%1 = call i32 @_Z12someConstantv()
%2 = sext i32 %1 to i64
%3 = call double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %args, i64 %2)
%4 = load double* %3
%5 = call i32 @_Z12someConstantv()
%6 = sitofp i32 %5 to double
%7 = fmul double %4, %6
ret double %7
}
; Function Attrs: nounwind uwtable
define linkonce_odr double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %this, i64 %__n) #1 align 2 {
%1 = alloca %"class.std::vector"*, align 8
%2 = alloca i64, align 8
store %"class.std::vector"* %this, %"class.std::vector"** %1, align 8
store i64 %__n, i64* %2, align 8
%3 = load %"class.std::vector"** %1
%4 = bitcast %"class.std::vector"* %3 to %"struct.std::_Vector_base"*
%5 = getelementptr inbounds %"struct.std::_Vector_base"* %4, i32 0, i32 0
%6 = getelementptr inbounds %"struct.std::_Vector_base<double, std::allocator<double> >::_Vector_impl"* %5, i32 0, i32 0
%7 = load double** %6, align 8
%8 = load i64* %2, align 8
%9 = getelementptr inbounds double* %7, i64 %8
ret double* %9
}
Run Code Online (Sandbox Code Playgroud)
我知道,这[]是从STL定义(功能@_ZNSt6vectorIdSaIdEEixEm)中包含的 - 足够公平.问题是:它可能是一些成员函数,甚至是直接数据访问,我根本无法假设数据布局到处都是一样的,所以在开发时,我不知道std::vector主机的具体布局.
有没有办法使用C++元编程在编译时获取所需的信息?即是有某种方式来问LLVM提供IR std::vector的[]方法是什么?
作为奖励:我宁愿不强制铿锵库的编译,相反,LLVM应是运行时的依赖性,所以才调用铛在编译时(即使我不知道如何做到这一点)是第二 - 最好的解决方案