美文网首页
[DEBUG]CreateGEP中的索引问题

[DEBUG]CreateGEP中的索引问题

作者: HAPPYers | 来源:发表于2019-10-03 23:25 被阅读0次

    本来按照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;
    }
    

    相关文章

      网友评论

          本文标题:[DEBUG]CreateGEP中的索引问题

          本文链接:https://www.haomeiwen.com/subject/flljpctx.html