[DEBUG]CreateGEP中的索引问题

2019-10-03  本文已影响0人  HAPPYers

本来按照LLVM essential书上关于计算内存地址的方法写了一段用GEP函数获取内存的示例代码
这个代码是用来获取函数参数列表的第二个参数的

  FunArgs.push_back ( "a" );
    static IRBuilder<> Builder ( Context );
    Function* fooFunc = createFunc ( Builder, "foo" );
    setFuncArgs ( fooFunc, FunArgs );
    Value* Base = fooFunc->arg_begin();
......
    Value* gep =  getGEP(Builder, Base, ConstantInt::get(Context, APInt(32, 1)));
    Value* load = getLoad ( Builder, gep );

getGEP函数其实是个wrapper

Value *getGEP(IRBuilder<> &Builder, Value *Base, Value *Offset) {
  return Builder.CreateGEP(
      Builder.getInt32Ty(),
      Base, Offset, "a1");
}

但是运行的时候在CreateGEP的时候出现了类型不匹配的断言错误。

Assertion failed: PointeeType == cast<PointerType> ( Ptr->getType()->getScalarType() )->getElementType(), file C:\Users\pcy19\Desktop\llvm-8.0.1.src\include\llvm/IR/Instructions.h, line 954

然后在解决问题的时候尝试了很多方法思路。
首先我尝试dump不同参数的Type,然后发现Base(函数参数列表)是<2 x i32>*类型的,Base->getType()->getScalarType()得到的是<2 x i32>*,但是cast<PointerType> ( Base->getType()->getScalarType() )->getElementType()->dump();得到的居然还是<2 x i32>.

后来翻到LLVM文档中关于GEP困惑的一篇很好的文章
http://llvm.org/docs/GetElementPtr.html
里面就提到了extra 0 index的问题,就是

GEP需要额外的Indexing,第一个索引解开第一层指针,这时取出是你的vector数组本身,其余的索引才是索引这个结构体/数组/vector内部具体的元素。

然后我也找到了CreateGEP不同的重载函数,由于需要一个索引列表(表示两次索引),故用如下的重载函数

Value *CreateGEP(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
                   const Twine &Name = "") 

发现这个第三个参数需要ArrayRef<Value *>类型,于是又老老实实地创建了这个ArrayRef

ArrayRef<Value*> listOffset ( {ConstantInt::get ( Context, APInt ( 32, 0 ) ),
            ConstantInt::get ( Context, APInt ( 32, 0 ) )
        } );

而后去翻ArrayRef的源码,发现它也不过是一个在小量数据时优化过的数组,这么手动创建略显麻烦,直接写入数组也是可以的。(这个主要是在GitHub搜GEP代码时发现的)

然后就去索引把这个本身的vector解引用出来,再获取vector中元素的值,下面的代码在LLVM8.0.1中测试通过。

outs() << "Now create first GEP\n";
  Value *vector_self = Builder.CreateGEP(
      cast<PointerType>(Base->getType()->getScalarType())->getElementType(),
      Base,
      {
          ConstantInt::get(Context, APInt(32, 0)),
          ConstantInt::get(Context, APInt(32, 1)),
      },
      "a");
  outs() << "Now create second GEP\n";
  Value *gep = Builder.CreateGEP(Builder.getInt32Ty(), vector_self,
                                 ConstantInt::get(Context, APInt(32, 0)), "a2");
  gep->getType()->dump();
  Value *load = getLoad(Builder, gep);
  Builder.CreateRet(load);

运行结果

Now create first GEP
Now create second GEP
i32*   // This is the gep type

; ModuleID = 'my compiler'
source_filename = "my compiler"

define i32 @foo(<2 x i32>* %a) {
entry:
  %a1 = getelementptr <2 x i32>, <2 x i32>* %a, i32 0, i32 1
  %a2 = getelementptr i32, i32* %a1, i32 0
  %load = load i32, i32* %a2
  ret i32 %load
}

Something Important

思索良久,发现其实只要修改getGEP这个wrapper就可以了。
现在的做法代码如下,这样动态获取类型,然后只要给offset传入数组即可。

Value* getGEP ( IRBuilder<>& Builder, Value* Base, ArrayRef<Value*>Offset ) {
    return Builder.CreateGEP (
            cast<PointerType> ( Base->getType()->getScalarType() )->getElementType(),
            Base, Offset, "a" );
}

这样调用的时候代码很简洁

Value *gep = getGEP(Builder, Base, {Builder.getInt32(0), Builder.getInt32(1)});
gep = getGEP(Builder, gep, {Builder.getInt32(0)});
Value *load = getLoad(Builder, gep);

补充(非常重要)

第三天又发现重载函数中不需要传入第一个Type参数也是可以的
(这个其实是在翻c1interpreter的源码的时候看到的用法)
例如

Value *gep =  Builder.CreateGEP(Base, {Builder.getInt32(0) ,Builder.getInt32(0)});

这样出来的ir就是

; ModuleID = 'my compiler'
source_filename = "my compiler"

define i32 @foo(<2 x i32>* %a) {
entry:
  %0 = getelementptr <2 x i32>, <2 x i32>* %a, i32 0, i32 1
  %load = load i32, i32* %0
  ret i32 %load
}

不必手动指定类型,不仅不用受类型不匹配之苦,还写起来简洁。

murmur

这里非常感谢 @mayuyu 大佬在我困惑整整一天后点拨我,让我有了解决思路。
原书上的API用法可能仅在旧版本有效,但是书上对于vector的元素取法应该是错误的。
整个调试花了整整两天,(虽然有段时间溜达去了),但是查阅了无数资料最后能解决的感觉是挺好的。

书上的多少有些过时,写出来的不兼容(填坑三天了),还是官方文档好。

一个vector的写法

std::vector<Value *> ind_list;
auto Zero = ConstantInt::get(Type::getInt32Ty(Context), 0, true);
auto index = ConstantInt::get(Type::getInt32Ty(Context), 1, true);

ind_list.push_back(Zero);
ind_list.push_back(index);

完整的代码

实现了arg_vector[1]的load

简洁版

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include <vector>
using namespace llvm;

static LLVMContext Context;

static Module *ModuleOb = new Module("my compiler", Context);
static std::vector<std::string> FunArgs;

Function *createFunc(IRBuilder<> &Builder, std::string Name) {
  Type *u32Ty = Type::getInt32Ty(Context);
  Type *vecTy = VectorType::get(u32Ty, 2);
  Type *ptrTy = vecTy->getPointerTo(0);
  FunctionType *funcType =
      FunctionType::get(Builder.getInt32Ty(), ptrTy, false);
  Function *fooFunc =
      Function::Create(funcType, Function::ExternalLinkage, Name, ModuleOb);
  return fooFunc;
}

void setFuncArgs(Function *fooFunc, std::vector<std::string> FunArgs) {
  unsigned Idx = 0;
  Function::arg_iterator AI, AE;

  for (AI = fooFunc->arg_begin(), AE = fooFunc->arg_end(); AI != AE;
       ++AI, ++Idx)
    AI->setName(FunArgs[Idx]);
}

BasicBlock *createBB(Function *fooFunc, std::string Name) {
  return BasicBlock::Create(Context, Name, fooFunc);
}

Value *getLoad(IRBuilder<> &Builder, Value *Address) {
  return Builder.CreateLoad(Address, "load");
}

int main(int argc, char *argv[]) {
  FunArgs.push_back("a");
  static IRBuilder<> Builder(Context);
  Function *fooFunc = createFunc(Builder, "foo");
  setFuncArgs(fooFunc, FunArgs);
  Value *Base = fooFunc->arg_begin();
  BasicBlock *entry = createBB(fooFunc, "entry");
  Builder.SetInsertPoint(entry);
  Value *gep =  Builder.CreateGEP(Base, {Builder.getInt32(0) ,Builder.getInt32(0)});
  Value *load = getLoad(Builder, gep);
  Builder.CreateRet(load);
  verifyFunction(*fooFunc);
  ModuleOb->dump();
  return 0;
}

原始版

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include <vector>
using namespace llvm;

static LLVMContext Context;

static Module *ModuleOb = new Module("my compiler", Context);
static std::vector<std::string> FunArgs;

Function *createFunc(IRBuilder<> &Builder, std::string Name) {
  Type *u32Ty = Type::getInt32Ty(Context);
  Type *vecTy = VectorType::get(u32Ty, 2);
  Type *ptrTy = vecTy->getPointerTo(0);
  FunctionType *funcType =
      FunctionType::get(Builder.getInt32Ty(), ptrTy, false);
  Function *fooFunc =
      Function::Create(funcType, Function::ExternalLinkage, Name, ModuleOb);
  return fooFunc;
}

void setFuncArgs(Function *fooFunc, std::vector<std::string> FunArgs) {
  unsigned Idx = 0;
  Function::arg_iterator AI, AE;

  for (AI = fooFunc->arg_begin(), AE = fooFunc->arg_end(); AI != AE;
       ++AI, ++Idx)
    AI->setName(FunArgs[Idx]);
}

BasicBlock *createBB(Function *fooFunc, std::string Name) {
  return BasicBlock::Create(Context, Name, fooFunc);
}
Value *getLoad(IRBuilder<> &Builder, Value *Address) {
  return Builder.CreateLoad(Address, "load");
}

int main(int argc, char *argv[]) {
  FunArgs.push_back("a");
  static IRBuilder<> Builder(Context);
  Function *fooFunc = createFunc(Builder, "foo");
  setFuncArgs(fooFunc, FunArgs);
  Value *Base = fooFunc->arg_begin();
  BasicBlock *entry = createBB(fooFunc, "entry");
  Builder.SetInsertPoint(entry);
  Value *vector_self = Builder.CreateGEP(
      cast<PointerType>(Base->getType()->getScalarType())->getElementType(),
      Base,
      {
          ConstantInt::get(Context, APInt(32, 0)),
          ConstantInt::get(Context, APInt(32, 1)),
      },
      "a1");
  Value *gep = Builder.CreateGEP(Builder.getInt32Ty(), vector_self,
                                 ConstantInt::get(Context, APInt(32, 0)), "a2");
  Value *load = getLoad(Builder, gep);
  Builder.CreateRet(load);
  verifyFunction(*fooFunc);
  ModuleOb->dump();
  return 0;
}
上一篇下一篇

猜你喜欢

热点阅读