LLVM将Loop*存储在std::vector中

LLVM storing Loop* in std::vector

本文关键字:std vector 存储 Loop LLVM      更新时间:2023-10-16

我偶然发现了一件非常奇特的事情——我正在编写一个LLVM模块Pass。我迭代模块的所有函数,然后迭代每个非声明函数的所有循环,并将指向循环的指针存储在std::vector中。来源:

virtual bool runOnModule(Module& Mod){
  std::vector<Loop*> loops;
  // first gather all loop info
  for(Module::iterator f = Mod.begin(), fend = Mod.end(); f != fend; ++f){
    if (!(*f).isDeclaration()){
      LoopInfo& LI = getAnalysis<LoopInfo>(*f);
      for(LoopInfo::iterator l = LI.begin(), lend = LI.end(); l != lend; ++l){
          loops.push_back(*l);
      }
    }
  }
  for (auto& l: loops) errs () << *l << " ";
}

现在,如果我运行这个,我会得到一个运行时错误-它无法打印循环,不知怎么的,我正在做一个空指针取消引用或其他什么。有什么想法吗?

您必须确保LoopInfo过程在您的过程之前实际运行

class AnalyzeLoops : public FunctionPass {
public:
  AnalyzeLoops()
      : FunctionPass(ID) {}
  void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<LoopInfo>();
  }
  virtual bool runOnFunction(Function &F) {
    LoopInfo &LI = getAnalysis<LoopInfo>();
    for (LoopInfo::iterator L = LI.begin(), LE = LI.end(); L != LE; ++L) {
      (*L)->dump();
    }
    return false;
  }
  static char ID;
};

此外,在创建通行证时,执行:

  PassManager PM;
  PM.add(new LoopInfo());
  PM.add(new AnalyzeLoops());
  PM.run(*Mod);

我怀疑要使opt在通过之前真正运行LoopInfo,您也应该通过-loops

此外,请注意,我定义了getAnalysisUsage——如果LoopInfo在此过程之前没有运行,这将使LLVM抱怨,从而使问题更加明显。


注意,LoopInfo具体地是FunctionPass,并且作为分析,它必须从另一个FunctionPass使用。LoopInfo数据结构在不同的函数之间并不能真正存活下来,而且由于它拥有自己的数据(那些Loop*对象),它们也会被销毁。

如果您真的需要ModulePass,您可以做的一件事就是手动调用LoopInfo,而不是作为分析。迭代模块中的函数时,为每个函数创建一个新的LoopInfo对象并使用其runOnFunction方法。尽管即使在这种情况下,如果您想使用给定的Loop*,您也必须确保拥有该CCD_19的LoopInfo仍然存在。

首先,LoopInfo应该在for循环之前运行一次。第二个LoopInfo::迭代器只包括Function的顶级循环。为了访问所有循环,您还需要迭代每个循环的子循环。它既可以用递归函数实现,也可以用WorkList实现,比如

virtual bool runOnFunction(Function &F) {
  LoopInfo *loopinfo;
  loopinfo = &getAnalysis<LoopInfo>();
  std::vector<Loop*> allLoops;
  for (LoopInfo::iterator Li = loopinfo->begin(), Le = loopinfo->end();
       Li != Le; Li++) {
    Loop *L = *Li;
    allLoops.push_back(L);
    dfsOnLoops(L, loopinfo, allLoops);
  }
}
void dfsOnLoops(Loop *L, LoopInfo *loopinfo, std::vector<Loop*> LoopS) {
  std::vector<Loop *> subloops = L->getSubLoops();
  if (subloops.size()) {
    // recursive on subloops
    for (std::vector<Loop *>::iterator Li = subloops.begin();Li != subloops.end(); Li++){
        LoopS.push_back(*Li);
        dfsOnLoops(*Li, loopinfo, LoopS);
    }
  }
}
` 

没有一个答案真的有帮助,但我自己设法解决了这个问题。基本上,每个llvm传递都可以定义一个releaseMemory()方法,请在此处阅读更多信息。LoopInfo类实现了该方法,因此每当我们从对getAnalysis的调用中脱离作用域时,分析信息就会丢失。我只是删除了Loopinfo.h中的releaseMemory()方法,内存就不再被释放了。请注意,这引发了代码库的巨大变化,甚至不得不重建opt,所以一般来说这样做可能是个坏主意,而且这肯定不会被轻易接受为对llvm的更改(我推测,不确定)。

我认为解决这个问题的最佳方法是显式创建LoopInfo对象并保存它们。这是LLVM 3.5 的代码

using LoopInfoType=llvm::LoopInfoBase<llvm::BasicBlock, llvm::Loop>;
std::vector<llvm::Loop*> loopVec;
std::vector<LoopInfoType*> loopInfoVec;
for(llvm::Module::iterator F = M.begin(); F!= M.end(); F++){
      //skip declrations
      if(F->isDeclaration()){
        continue;
      }

  //TODO that scope problem
  llvm::DominatorTree DT = llvm::DominatorTree();
  DT.recalculate(*F);
  LoopInfoType *loopInfo = new LoopInfoType();
  loopInfo->releaseMemory();
  loopInfo->Analyze(DT);
  loopInfoVec.push_back(loopInfo);
  for(llvm::LoopInfo::iterator lit = loopInfo->begin(); lit != loopInfo->end(); lit++){
    Loop * L = * lit;
    loopVec.push_back(L);
    //L->dump();
  }
}//for all functions
cin.get();
for(auto loop : loopVec){
  std::cout << "loopn";
  loop->dump();
  for(llvm::Loop::block_iterator bit = loop->block_begin(); bit != loop->block_end(); bit++){
    llvm::BasicBlock * B = * bit;
    B->dump();
    std::cout << "nn";
  }
}