From 0b315633ca0e2aa732fefea2875c0b008f0638d3 Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Mon, 19 Jul 2021 13:20:57 -0700 Subject: [PATCH] [NewPM] Bail out of devirtualization wrapper if the current SCC is invalidated The specific case that triggered this was when inlining a recursive internal function into itself caused the recursion to go away, allowing the inliner to mark the function as dead. The inliner marks the SCC as invalidated but does not provide a new SCC to continue with. This matches the implementations of ModuleToPostOrderCGSCCPassAdaptor and CGSCCPassManager. Fixes PR50363. Reviewed By: asbirlea Differential Revision: https://reviews.llvm.org/D106306 --- lib/Analysis/CGSCCPassManager.cpp | 9 +++++++-- test/Other/devirt-invalidated.ll | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test/Other/devirt-invalidated.ll diff --git a/lib/Analysis/CGSCCPassManager.cpp b/lib/Analysis/CGSCCPassManager.cpp index 8043cc7fc74..253cc0b0a57 100644 --- a/lib/Analysis/CGSCCPassManager.cpp +++ b/lib/Analysis/CGSCCPassManager.cpp @@ -432,8 +432,13 @@ PreservedAnalyses DevirtSCCRepeatedPass::run(LazyCallGraph::SCC &InitialC, break; } - // Check that we didn't miss any update scenario. - assert(!UR.InvalidatedSCCs.count(C) && "Processing an invalid SCC!"); + // If the CGSCC pass wasn't able to provide a valid updated SCC, the + // current SCC may simply need to be skipped if invalid. + if (UR.InvalidatedSCCs.count(C)) { + LLVM_DEBUG(dbgs() << "Skipping invalidated root or island SCC!\n"); + break; + } + assert(C->begin() != C->end() && "Cannot have an empty SCC!"); // Check whether any of the handles were devirtualized. diff --git a/test/Other/devirt-invalidated.ll b/test/Other/devirt-invalidated.ll new file mode 100644 index 00000000000..c3ed5e53b3b --- /dev/null +++ b/test/Other/devirt-invalidated.ll @@ -0,0 +1,30 @@ +; RUN: opt -passes='devirt<0>(inline)' < %s -S | FileCheck %s + +; CHECK-NOT: internal +; CHECK: define void @e() +; CHECK-NOT: internal + +define void @e() { +entry: + call void @b() + ret void +} + +define internal void @b() { +entry: + call void @d() + call void @c() + ret void +} + +define internal void @d() { +entry: + unreachable +} + +define internal void @c() { +entry: + call void @b() + call void @e() + ret void +}