Unexpected crash in IndVarSimplify after injecting custom pass

Hi:
Here in our downstream project we use a ModulePass to schedule our TransformPasses through creating and executing Module/FunctionPassManagers internally.
This “wrapper” pass is registered at ExtensionPoint EP_ModuleOptimizerEarly.

However, when certain passes in our Pipeline are disabled, LLVM optimization process crashes later in the pipeline with:


Assertion failed: (L->getLoopPreheader() && "Can't expand add recurrences without a loop preheader!"), function getAddRecExprPHILiterally, file LLVM/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp, line 1275
1. <eof> parser at end of file
2. Per-module optimization passes
3. Running pass 'CallGraph Pass Manager' on module 'src.cpp'.
4. Running pass 'Loop Pass Manager' on function '@_ZNK8XXXX'
5. Running pass 'Induction Variable Simplification' on basic block '%for.body110'
0 clang++ 0x0000000103df5535 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
1 clang++ 0x0000000103df4765 llvm::sys::RunSignalHandlers() + 85
2 clang++ 0x0000000103df4cc0 llvm::sys::CleanupOnSignal(unsigned long) + 208
3 clang++ 0x0000000103d45f2a (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) + 106
4 clang++ 0x0000000103d460b7 CrashRecoverySignalHandler(int) + 135
5 libsystem_platform.dylib 0x00007fff2055ed7d _sigtramp + 29
6 libdyld.dylib 0x00007fff20534473 dyldGlobalLockRelease() + 0
7 libsystem_c.dylib 0x00007fff2046d720 abort + 120
8 libsystem_c.dylib 0x00007fff2046c9d6 err + 0
9 clang++ 0x0000000106c11a83 llvm::SCEVExpander::getAddRecExprPHILiterally(llvm::SCEVAddRecExpr const*, llvm::Loop const*, llvm::Type*, llvm::Type*, llvm::Type*&, bool&) (.cold.1) + 35
10 clang++ 0x0000000103eb9643 llvm::SCEVExpander::getAddRecExprPHILiterally(llvm::SCEVAddRecExpr const*, llvm::Loop const*, llvm::Type*, llvm::Type*, llvm::Type*&, bool&) + 4259
11 clang++ 0x0000000103eb9bda llvm::SCEVExpander::expandAddRecExprLiterally(llvm::SCEVAddRecExpr const*) + 1066
12 clang++ 0x0000000103eb5f23 llvm::SCEVExpander::expand(llvm::SCEV const*) + 1027
13 clang++ 0x0000000103eb5aac llvm::SCEVExpander::expandCodeFor(llvm::SCEV const*, llvm::Type*) + 28
14 clang++ 0x0000000103ebbc31 llvm::SCEVVisitor<llvm::SCEVExpander, llvm::Value*>::visit(llvm::SCEV const*) + 193
15 clang++ 0x0000000103eb5f23 llvm::SCEVExpander::expand(llvm::SCEV const*) + 1027
16 clang++ 0x0000000103eb5aac llvm::SCEVExpander::expandCodeFor(llvm::SCEV const*, llvm::Type*) + 28
17 clang++ 0x0000000103eb8c49 llvm::SCEVExpander::getAddRecExprPHILiterally(llvm::SCEVAddRecExpr const*, llvm::Loop const*, llvm::Type*, llvm::Type*, llvm::Type*&, bool&) + 1705
18 clang++ 0x0000000103eb9bda llvm::SCEVExpander::expandAddRecExprLiterally(llvm::SCEVAddRecExpr const*) + 1066
19 clang++ 0x0000000103eb5f23 llvm::SCEVExpander::expand(llvm::SCEV const*) + 1027
20 clang++ 0x0000000103eb5aac llvm::SCEVExpander::expandCodeFor(llvm::SCEV const*, llvm::Type*) + 28
21 clang++ 0x0000000103eb9794 llvm::SCEVExpander::expandCodeFor(llvm::SCEV const*, llvm::Type*, llvm::Instruction*) + 148
22 clang++ 0x0000000103b3969a (anonymous namespace)::IndVarSimplify::run(llvm::Loop*) + 8522
23 clang++ 0x0000000103b463c7 (anonymous namespace)::IndVarSimplifyLegacyPass::runOnLoop(llvm::Loop*, llvm::LPPassManager&) + 951
24 clang++ 0x00000001030ee209 llvm::LPPassManager::runOnFunction(llvm::Function&) + 1513
25 clang++ 0x00000001036afe41 llvm::FPPassManager::runOnFunction(llvm::Function&) + 1073
26 clang++ 0x0000000102ff4534 (anonymous namespace)::CGPassManager::runOnModule(llvm::Module&) + 1540
27 clang++ 0x00000001036b049f llvm::legacy::PassManagerImpl::run(llvm::Module&) + 1103
28 clang++ 0x000000010407b653 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::DataLayout const&, llvm::Module*, clang::BackendAction, std::__1::unique_ptr<llvm::raw_pwrite_stream, std::__1::default_delete<llvm::raw_pwrite_stream> >) + 15075
29 clang++ 0x00000001043456fb clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) + 1131
30 clang++ 0x0000000105438483 clang::ParseAST(clang::Sema&, bool, bool) + 643
31 clang++ 0x0000000104612d04 clang::FrontendAction::Execute() + 84
32 clang++ 0x00000001045b9f13 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 2179
33 clang++ 0x00000001046878fb clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 1435
34 clang++ 0x00000001025db371 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 2081

I added createVerifierPass() at the end of our “WrapperPass” and the transformed IR passed the verification. I also didn’t overload getAnalysisUsage, which, if my understanding is correct, invalidates all previous analysis including Loops Identified.

I’m kinda lost about why this issue exists and any hint would be much appreciated

Zhang

Hi,

Thanks Florian.
To confirm, just leaving getAnalysisUsage unimplemented in my outside ModulePass is the correct way to instruct the remaining pipeline that “I’ve transformed Input enough that all previous analysis are no longer valid”, right?

Zhang

I’ve tried to dump the IR out at the end of my pipeline and invoking opt separately with the following output:

opt -verify O3bug.ll

is fine from LLVM12 stock opt.

Yet running opt -O3 O3bug.ll yields the exact same crash.

Is there any infrastructure to help me reduce the IR for bug reporting? The full IR contains some sensitive information that we’d avoid posting publicly.
Thanks a lot

There is bugpoint [1] and llvm-reduce [2] for reducing test cases.
llvm-reduce is the newer one, but seems to not have documentation yet.

Michael

[1] https://www.llvm.org/docs/CommandGuide/bugpoint.html
[2] https://blog.regehr.org/archives/2109