Segmentation faults running the new llvm ModulePassManager with default pipeline

I am currently writing a frontend language compiling to LLVM IR using the LLVM c++ API (LLVM version 13), however I see some erratic behavior with segmentation faults when running the new ModulePassManager. Specifically I see the debugger halts execution in the llvm::EarlyCSEPass::run function call when a segmentation fault occurs. Can’t see where exactly the seg fault happens inside this function as I am not currently using a debug build for the LLVM source code itself.

I think the seg fault might have something to do with the way I set up my pass manager and run the pass manger on new instances of llvm::Module without any kind of reset to the pass analysis manager (not sure if this guess is correct though). I have highlighted my current code that sets up and runs the pass manager below. I would be grateful if you could give any insights into what I might be doing wrong and how it should be done correctly.

Best, Sanket

I have a "CodeGenerator" class object that holds the pass manager and the other related objects as public members

class CodeGenerator {
   llvm::PassBuilder passBuilder;
   llvm::LoopAnalysisManager loopAnalysisManager; 
   llvm::FunctionAnalysisManager functionAnalysisManager;
   llvm::CGSCCAnalysisManager cGSCCAnalysisManager;
   llvm::ModuleAnalysisManager moduleAnalysisManager;
   llvm::ModulePassManager modulePassManager;
   CodeGenerator(); // constructor for the class
   // other code that handles emitting the LLVM IR from the parsed AST of the front-end code

   // I keep the llvm::Module and llvm::Context instances to which the ir is emitted within this class as members
   llvm::orc::ThreadSafeContext Ctx; 
   std::unique_ptr<llvm::Module> TheModule;


I initialize the ModulePassManager in the class constructor
CodeGenerator(): Ctx(std::make_unique<llvm::LLVMContext>()) {
     loopAnalysisManager, functionAnalysisManager, cGSCCAnalysisManager, 
  modulePassManager =  passBuilder.buildPerModuleDefaultPipeline(llvm::PassBuilder::OptimizationLevel::O0);

After calling the constructor for the above class

I initialize the Module to which the llvm ir is emitted.

CodeGenerator CG = CodeGenerator();

CG.TheModule = std::make_unique<llvm::Module>("module_name", *(CG.Ctx.getContext()));

// I parse my front end code and emit my llvm ir code to TheModule here

// then I call the ModulePassManager here to optimize the module*CG.TheModule, CG.moduleAnalysisManager);
// I move the optimized module to my JIT interpreter
auto TSM = llvm::orc::ThreadSafeModule(std::move(CG.TheModule),CG.Ctx);

// Then, I create a new instance of llvm::Module to emit some other ir code

CG.TheModule = std::make_unique<llvm::Module>(ModuleName, *(CG.Ctx.getContext()));

// emit ir 

// then call the optimizer again*CG.TheModule, CG.moduleAnalysisManager);

// I repeat this several times changing TheModule to a new instance
// of llvm::Module to contain some new ir code and run the optimizer.

// one of these calls to ends up giving the segmentation fault 
// there is no specific fixed instance of llvm::Module that this happens for
// The segmentation fault seems to happen at random for any one of the instances, on some runs there is no seg fault 
// The ir being emitted is also not changed on any of the runs

My suspicion is that CG.moduleAnalysisManager might need some kind of reset after I change the Module instance before I can run the ModulePassManager on the newly emitted ir. Or maybe I am missing something else in how the pass manager needs to be setup. Any help would be great.


The issue is probably that the analyses are not being cleared between runs and you end up using stale analyses. I’d recommend that you use a new instance of all the pass/analysis managers every time you perform codegen. (if you really want, you could call the clear() method on all the analysis managers, but that’s a bit more sketchy)

Thanks Aurthur.

That seems to have been the problem. I changed the code to use a new instances for all the pass and analysis managers for every new module added and that fixed the issue. Didn’t try using the ‘clear()’ method since the code seems to be working for now and I can move on to solving some other problems.

Thanks a lot for your help.