baibo
baibo

Reputation: 458

LLVM storing Loop* in std::vector

I've stumbled into something very peculiar - I'm writing an LLVM module Pass. I iterate over all functions of the module and then all loops of every non-declaration function and I store pointers to loops in a std::vector. Here's the source:

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 << " ";
}

Now if I run this I get a runtime error - it can't print the loops, somehow I'm doing a null pointer dereference or sth. Any ideas?

Upvotes: 3

Views: 1608

Answers (4)

leandro souza rosa
leandro souza rosa

Reputation: 327

I think the best way to solve this is to explicitly create LoopInfo objects and save them. Here is the Code for 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 << "loop\n";
  loop->dump();
  for(llvm::Loop::block_iterator bit = loop->block_begin(); bit != loop->block_end(); bit++){
    llvm::BasicBlock * B = * bit;
    B->dump();
    std::cout << "\n\n";
  }
}

Upvotes: 0

baibo
baibo

Reputation: 458

None of the answers really helped but I managed to solve the problem myself. Basically, each llvm pass can define a releaseMemory() method, read more here. The LoopInfo class had that method implemented and thus the analysis information would be lost every time we get out of scope from the call to getAnalysis. I simply removed the releaseMemory() method in Loopinfo.h and the memory was no longer released. Note that this triggered a big change in the codebase and even opt had to be rebuilt so doing this in general is probably a bad idea and this would definitely not be easily accepted as a change to llvm (I speculate, not sure).

Upvotes: 1

hadi sadeghi
hadi sadeghi

Reputation: 537

First of all LoopInfo should run just once before the for loop. Secondly LoopInfo::iterator just includes top level loops of the Function. in order to visit all loops you also need to iterate over subloops of every loop. it can be implemented either as recursive function or by WorkList, like this`

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);
    }
  }
}
` 

Upvotes: 1

Eli Bendersky
Eli Bendersky

Reputation: 273844

You have to make sure that the LoopInfo pass actually runs before your pass. Here is a complete example - stanalone from opt:

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;
};

In addition, when creating the passes, do:

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

I suspect that to make opt actually run LoopInfo before your pass, you should pass -loops too.

Also, note that I define getAnalysisUsage - this will make LLVM complain if LoopInfo didn't run before this pass, making the problem more obvious.


Note that LoopInfo is specifically a FunctionPass, and as an analysis it has to be used from another FunctionPass. The LoopInfo data structure doesn't really survive between different functions, and since it owns its data (those Loop* objects) they will be destroyed as well.

One thing you could do if you really need a ModulePass is just invoke LoopInfo manually and not as an analysis. When you iterate the functions in the module, for each function create a new LoopInfo object and use its runOnFunction method. Though even in this case, you have to make sure the LoopInfo that owns a given Loop* survives if you want to use the latter.

Upvotes: 1

Related Questions