C ++ / LLVM:运行时代码生成和STL容器

时间:2013-12-21 11:50:39

标签: c++ stl llvm jit

假设一个简单的部分评估方案:

#include <vector>

/* may be known at runtime */
int someConstant();

/* can be partially evaluated */
double foo(std::vector<double> args) {
  return args[someConstant()] * someConstant();
}

假设someConstant()已知并且在运行时不会更改(例如由用户提供一次),并且可以由相应的int literal替换。如果foo是热门路径的一部分,我预计会有显着的性能提升:

/* partially evaluated, someConstant() == 2 */
double foo(std::vector<double> args) {
  return args[2] * 2;
}

我目前对该问题的看法是在运行时生成LLVM IR,因为我知道部分评估代码的结构(因此我不需要通用的部分求值程序)。 所以我想编写一个函数foo_ir来生成与foo完全相同但不调用someConstant()的IR代码,因为它在运行时是已知的。 很简单,不是吗?然而,当我查看上面代码生成的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
}

我看到,[]包含在STL定义(函数@_ZNSt6vectorIdSaIdEEixEm)中 - 足够公平。问题是:它可能是一些成员函数,甚至是直接数据访问,我根本无法假设数据布局在任何地方都是相同的,所以在开发时,我不知道具体的std::vector主机的布局。

有没有办法使用C ++元编程在编译时获取所需的信息?即是否有某种方法可以让llvm为std::vector的{​​{1}}方法提供IR?

作为奖励:我宁愿不用clang强制编译库,相反,LLVM应该是运行时依赖,所以只需在编译时调用clang(即使我不知道如何执行此操作)是第二好的解决方案。

1 个答案:

答案 0 :(得分:3)

回答我自己的问题:

虽然我仍然没有针对一般情况的解决方案(例如std::map),但std::vector存在一个简单的解决方案:

根据the C++ standard,以下适用于成员函数data()

  

返回指向内部使用的内存数组的直接指针   矢量来存储其拥有的元素。

     

因为矢量中的元素保证存储在   连续存储位置的顺序与表示的顺序相同   向量,检索到的指针可以被偏移以访问任何元素   数组。

事实上,std::vector的对象级布局由标准修复。