Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deeply-nested chain hangs with Item = u32 #70749

Open
cuviper opened this issue Apr 3, 2020 · 6 comments
Open

deeply-nested chain hangs with Item = u32 #70749

cuviper opened this issue Apr 3, 2020 · 6 comments
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-hang Issue: The compiler never terminates, due to infinite loops, deadlock, livelock, etc. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cuviper
Copy link
Member

cuviper commented Apr 3, 2020

I tried this code:

pub fn foo() -> Box<Iterator<Item = u32>> {
    use std::iter::empty;

    Box::new(empty()
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty()) // 10th .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty())
        .chain(empty()) // 16th .chain(empty())
    )
}

This is adapted from the deeply-nested test, just changing Item = () to Item = u32.

Building with rustc +nightly --crate-type lib -Copt-level=2 src/lib.rs seems to hang indefinitely.

I expected to see this happen: completion in a few seconds at most.

Instead, this happened: I'm still waiting...

Meta

rustc --version --verbose:

rustc 1.44.0-nightly (537ccdf3a 2020-04-02)
binary: rustc
commit-hash: 537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae
commit-date: 2020-04-02
host: x86_64-unknown-linux-gnu
release: 1.44.0-nightly
LLVM version: 9.0

Also happens on 1.42.0 and 1.43.0-beta.3.

Attaching rust-gdb, I see two busy LLVM threads:

Backtrace

Thread 6 (Thread 0x7f70bd5ff700 (LWP 207946)):
#0  0x00007f70c72133db in llvm::DominatorTreeBase<llvm::BasicBlock, false>::dominates(llvm::BasicBlock const*, llvm::BasicBlock const*) const () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#1  0x00007f70c7e2298a in llvm::GVN::findLeader(llvm::BasicBlock const*, unsigned int) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#2  0x00007f70c7e23279 in llvm::GVN::processInstruction(llvm::Instruction*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#3  0x00007f70c7e24977 in llvm::GVN::processBlock(llvm::BasicBlock*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#4  0x00007f70c7e1aff0 in llvm::GVN::runImpl(llvm::Function&, llvm::AssumptionCache&, llvm::DominatorTree&, llvm::TargetLibraryInfo const&, llvm::AAResults&, llvm::MemoryDependenceResults*, llvm::LoopInfo*, llvm::OptimizationRemarkEmitter*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#5  0x00007f70c7e27098 in llvm::gvn::GVNLegacyPass::runOnFunction(llvm::Function&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#6  0x00007f70c727842f in llvm::FPPassManager::runOnFunction(llvm::Function&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#7  0x00007f70c8233a78 in (anonymous namespace)::CGPassManager::runOnModule(llvm::Module&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#8  0x00007f70c7279030 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#9  0x00007f70c71e210a in LLVMRunPassManager () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#10 0x00007f70caa79b43 in rustc_codegen_llvm::back::write::optimize () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#11 0x00007f70caa3ef17 in rustc_codegen_ssa::back::write::execute_work_item () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#12 0x00007f70cab2680e in std::sys_common::backtrace::__rust_begin_short_backtrace () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#13 0x00007f70caa08eb5 in core::ops::function::FnOnce::call_once{{vtable-shim}} () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#14 0x00007f70c9fe92ff in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#15 0x00007f70ca01c813 in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#16 std::sys_common::thread::start_thread () at src/libstd/sys_common/thread.rs:13
#17 std::sys::unix::thread::Thread::new::thread_start () at src/libstd/sys/unix/thread.rs:80
#18 0x00007f70c9f534e2 in start_thread () from /lib64/libpthread.so.0
#19 0x00007f70c9e706d3 in clone () from /lib64/libc.so.6

Thread 5 (Thread 0x7f70be1ff700 (LWP 207945)):
#0  0x00007f70c7213354 in llvm::DominatorTreeBase<llvm::BasicBlock, false>::dominates(llvm::BasicBlock const*, llvm::BasicBlock const*) const () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#1  0x00007f70c7e2298a in llvm::GVN::findLeader(llvm::BasicBlock const*, unsigned int) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#2  0x00007f70c7e23279 in llvm::GVN::processInstruction(llvm::Instruction*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#3  0x00007f70c7e24977 in llvm::GVN::processBlock(llvm::BasicBlock*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#4  0x00007f70c7e1aff0 in llvm::GVN::runImpl(llvm::Function&, llvm::AssumptionCache&, llvm::DominatorTree&, llvm::TargetLibraryInfo const&, llvm::AAResults&, llvm::MemoryDependenceResults*, llvm::LoopInfo*, llvm::OptimizationRemarkEmitter*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#5  0x00007f70c7e27098 in llvm::gvn::GVNLegacyPass::runOnFunction(llvm::Function&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#6  0x00007f70c727842f in llvm::FPPassManager::runOnFunction(llvm::Function&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#7  0x00007f70c8233a78 in (anonymous namespace)::CGPassManager::runOnModule(llvm::Module&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#8  0x00007f70c7279030 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#9  0x00007f70c71e210a in LLVMRunPassManager () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#10 0x00007f70caa79b43 in rustc_codegen_llvm::back::write::optimize () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#11 0x00007f70caa3ef17 in rustc_codegen_ssa::back::write::execute_work_item () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#12 0x00007f70cab2680e in std::sys_common::backtrace::__rust_begin_short_backtrace () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#13 0x00007f70caa08eb5 in core::ops::function::FnOnce::call_once{{vtable-shim}} () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#14 0x00007f70c9fe92ff in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#15 0x00007f70ca01c813 in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#16 std::sys_common::thread::start_thread () at src/libstd/sys_common/thread.rs:13
#17 std::sys::unix::thread::Thread::new::thread_start () at src/libstd/sys/unix/thread.rs:80
#18 0x00007f70c9f534e2 in start_thread () from /lib64/libpthread.so.0
#19 0x00007f70c9e706d3 in clone () from /lib64/libc.so.6

@cuviper cuviper added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Apr 3, 2020
@cuviper
Copy link
Member Author

cuviper commented Apr 3, 2020

I found this in the process of evaluating changes to Chain: #70332 (comment)

Importantly, this test code does not hang with those changes. So if the compiler is fixed to handle this better, it should probably come with a self-contained regression test including the "old" Chain (assuming my changes do land).

@jonas-schievink jonas-schievink added the I-hang Issue: The compiler never terminates, due to infinite loops, deadlock, livelock, etc. label Apr 3, 2020
@cuviper
Copy link
Member Author

cuviper commented Apr 4, 2020

Instead, this happened: I'm still waiting...

The good news is that it did finish when I wasn't looking -- then I ran it again to actually time it:

real    39m25.171s
user    50m13.046s
sys     0m5.276s

@wesleywiser
Copy link
Member

I ran into a very similar issue while trying to enable the MIR inline pass by default. (More info in this Zulip thread)

If I remember correctly, using -Znew-llvm-pass-manager seemed to resolve the issue.

@cuviper
Copy link
Member Author

cuviper commented Apr 4, 2020

Hmm, with new PM it completed in "only" 8 minutes here, and then 13 minutes the second time, with a snapshot of the stack like this:

Backtrace

Thread 5 (Thread 0x7f79b23ff700 (LWP 218091)):
#0  0x00007f79bb8c4354 in llvm::DominatorTreeBase<llvm::BasicBlock, false>::dominates(llvm::BasicBlock const*, llvm::BasicBlock const*) const () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#1  0x00007f79bc4d398a in llvm::GVN::findLeader(llvm::BasicBlock const*, unsigned int) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#2  0x00007f79bc4d4279 in llvm::GVN::processInstruction(llvm::Instruction*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#3  0x00007f79bc4d5977 in llvm::GVN::processBlock(llvm::BasicBlock*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#4  0x00007f79bc4cbff0 in llvm::GVN::runImpl(llvm::Function&, llvm::AssumptionCache&, llvm::DominatorTree&, llvm::TargetLibraryInfo const&, llvm::AAResults&, llvm::MemoryDependenceResults*, llvm::LoopInfo*, llvm::OptimizationRemarkEmitter*) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#5  0x00007f79bc4cbbe6 in llvm::GVN::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#6  0x00007f79bdd1552d in llvm::detail::PassModel<llvm::Function, llvm::GVN, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#7  0x00007f79bb95abb3 in llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#8  0x00007f79bdd1817b in llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::CGSCCToFunctionPassAdaptor<llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>> >, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#9  0x00007f79bc8d85a4 in llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#10 0x00007f79bdd22000 in llvm::DevirtSCCRepeatedPass<llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&> >::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#11 0x00007f79bdd20f83 in llvm::detail::PassModel<llvm::Module, llvm::ModuleToPostOrderCGSCCPassAdaptor<llvm::DevirtSCCRepeatedPass<llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&> > >, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#12 0x00007f79bb958f6a in llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#13 0x00007f79bdd2820d in llvm::detail::PassModel<llvm::Module, llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#14 0x00007f79bb958f6a in llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/../lib/libLLVM-9-rust-1.44.0-nightly.so
#15 0x00007f79bf1fc2d1 in LLVMRustOptimizeWithNewPassManager () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#16 0x00007f79bf129c93 in rustc_codegen_llvm::back::write::optimize_with_new_llvm_pass_manager () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#17 0x00007f79bf12a616 in rustc_codegen_llvm::back::write::optimize () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#18 0x00007f79bf0eff17 in rustc_codegen_ssa::back::write::execute_work_item () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#19 0x00007f79bf1d780e in std::sys_common::backtrace::__rust_begin_short_backtrace () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#20 0x00007f79bf0b9eb5 in core::ops::function::FnOnce::call_once{{vtable-shim}} () from /home/jistone/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/../lib/librustc_driver-ebfe476c9299964b.so
#21 0x00007f79be69a2ff in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#22 0x00007f79be6cd813 in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once () at /rustc/537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae/src/liballoc/boxed.rs:1008
#23 std::sys_common::thread::start_thread () at src/libstd/sys_common/thread.rs:13
#24 std::sys::unix::thread::Thread::new::thread_start () at src/libstd/sys/unix/thread.rs:80
#25 0x00007f79be6044e2 in start_thread () from /lib64/libpthread.so.0
#26 0x00007f79be5216d3 in clone () from /lib64/libc.so.6

@cuviper
Copy link
Member Author

cuviper commented Apr 24, 2020

Since #70896 did land, removing the reproducer, here's a self-contained version:

#![crate_type = "lib"]
#![allow(unused)]

pub fn foo() -> Box<dyn Iterator<Item = u32>> {
    use std::iter::empty;

    Box::new(
        empty()
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty()) // 10th
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty())
            .my_chain(empty()), // 16th
    )
}

// The `Chain` implementation changed in #70896, which stopped reproducing the optimization hang,
// but here's a reduced copy of the old `Chain` for posterity.
struct Chain<A, B> {
    a: A,
    b: B,
    state: ChainState,
}

enum ChainState {
    Both,
    Front,
    Back,
}

impl<A, B> Iterator for Chain<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
{
    type Item = A::Item;

    #[inline]
    fn next(&mut self) -> Option<A::Item> {
        match self.state {
            ChainState::Both => match self.a.next() {
                elt @ Some(..) => elt,
                None => {
                    self.state = ChainState::Back;
                    self.b.next()
                }
            },
            ChainState::Front => self.a.next(),
            ChainState::Back => self.b.next(),
        }
    }
}

trait IteratorExt: Iterator {
    fn my_chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
    where
        Self: Sized,
        U: IntoIterator<Item = Self::Item>,
    {
        Chain {
            a: self,
            b: other.into_iter(),
            state: ChainState::Both,
        }
    }
}

impl<I: Iterator> IteratorExt for I {}

This compiles quickly (~150ms) in debug mode, but takes a very long time to optimize. I didn't wait to fully time it yet, but it's more than a minute, which is already unacceptable. (edit: 35m34s)

With -Znew-llvm-pass-manager it only takes 200ms, which is much better than I saw before, but I also didn't copy all of the old Chain methods here.

@tmiasko
Copy link
Contributor

tmiasko commented Jan 6, 2021

The performance bug can be triggered in original example by slightly increasing the LLVM inlining threshold (currently the issue starts at -Cinline-threshold=336 or above). This also came up in the past attempts to enable MIR inlining by default, e.g., in #68213 and #77307. The problem disappears with a single code generation unit.

The partitioning -Zprint-mono-items=lazy reveals a proximate cause. Implementation of iterator trait for chain is placed in one unit, implementation for empty in another. This makes a difference between large but completely trivial functions once empty is inlined, and large and complex when it isn't .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-hang Issue: The compiler never terminates, due to infinite loops, deadlock, livelock, etc. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants