how to correctly pass data structures between custom llvm passes

Viewed 579

I have a Function pass, called firstPass, which does some analysis and populates:

A a;

where

typedef std::map< std::string, B* > A;
class firstPass : public FunctionPass {  
   A a;
}

typedef std::vector< C* > D;
class B {
   D d;
}

class C {
   // some class packing information about basic blocks;
}

Hence I have a map of vectors traversed by std::string. I wrote associated destructors for these classes. This pass works successfully on its own.

I have another Function pass, called secondPass, needing this structure of type A to make some transformations. I used

bool secondPass::doInitialization(Module &M) {
  errs() << "now running secondPass\n";
  a = getAnalysis<firstPass>().getA();
  return false;
}

void secondPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<firstPass>();
  AU.setPreservesAll();
}

The whole code compiles fine, but I get a segmentation fault when printing this structure at the end of my first pass only if I call my second pass (since B* is null).

To be clear:

opt -load ./libCustomLLVMPasses.so -passA < someCode.bc

prints in doFinalization() and exits successfully

opt -load ./libCustomLLVMPasses.so -passA -passB < someCode.bc

gives a segmentation fault.

How should I wrap this data structure and pass it to the second pass without issues? I tried std::unique_ptr instead of raw ones but I couldn't make it work. I'm not sure if this is the correct approach anyway, so any help will be appreciated.

EDIT: I solved the problem of seg. fault. It was basically me calling getAnalysis in doInitialization(). I wrote a ModulePass to combine my firstPass and secondPass whose runOnModule is shown below.

bool MPass::runOnModule(Module &M) {
  for(Function& F : M) {
    errs() << "F: " << F.getName() << "\n";
    if(!F.getName().equals("main") && !F.isDeclaration())
      getAnalysis<firstPass>(F);
  }

  StringRef main = StringRef("main");
  A& a = getAnalysis<firstPass>(*(M.getFunction(main))).getA();

  return false;
 }

This also gave me to control the order of the functions processed. Now I can get the output of a pass but cannot use it as an input to another pass. I think this shows that the passes in llvm are self-contained.

1 Answers

I'm not going to comment on the quality of the data structures based on their C++ merit (it's hard to comment on that just by this minimal example).

Moreover, I wouldn't use the doInitialization method, if the actual initialization is that simple, but this is a side comment too. (The doc does not mention anything explicitly about it, but if it is ran once per Module while the runOn method is ran on every Function of that module, it might be an issue).

I suspect that the main issue seems to stem from the fact A a in your firstPass is bound to the lifetime of the pass object, which is over once the pass is done. The simplest change would be to allocate that object on the heap (e.g. new) and return a pointer to it when calling getAnalysis<firstPass>().getA();.

Please note that using this approach might require manual cleanup if you decide to use a raw pointer.

Related