diff --git a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp --- a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp +++ b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp @@ -176,6 +176,27 @@ for (const auto *Succ : successors(BB)) Worklist.push_back(Succ); } + + // There could be successors that were reached before but now are only + // reachable from elsewhere in the CFG. + // Suppose the following diamond CFG (lines are arrows pointing down): + // A + // / \ + // B C + // \ / + // D + // There's a call site in C that is inlined. Upon doing that, it turns out + // it expands to + // call void @llvm.trap() + // unreachable + // D isn't reachable from C anymore, but we did discount it when we set up + // FunctionPropertiesUpdater, so we need to re-include it here. + for (const auto *Succ : Successors) { + if (!ReIncluded.contains(Succ) && !pred_empty(Succ)) { + FPI.reIncludeBB(*Succ, LI); + ReIncluded.insert(Succ); + } + } FPI.updateAggregateStats(Caller, LI); assert(FPI == FunctionPropertiesInfo::getFunctionPropertiesInfo(Caller, LI)); } diff --git a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp --- a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp +++ b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp @@ -610,4 +610,64 @@ EXPECT_EQ(FPI, ExpectedFinal); } +TEST_F(FunctionPropertiesAnalysisTest, Unreachable) { + LLVMContext C; + std::unique_ptr M = makeLLVMModule(C, + R"IR( +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux-gnu" + +define i64 @f1(i32 noundef %value) { +entry: + br i1 true, label %cond.true, label %cond.false + +cond.true: ; preds = %entry + %conv2 = sext i32 %value to i64 + br label %cond.end + +cond.false: ; preds = %entry + %call3 = call noundef i64 @f2() + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %cond.false ] + ret i64 %cond +} + +define i64 @f2() { +entry: + tail call void @llvm.trap() + unreachable +} + +declare void @llvm.trap() +)IR"); + + Function *F1 = M->getFunction("f1"); + CallBase *CB = findCall(*F1); + EXPECT_NE(CB, nullptr); + + FunctionPropertiesInfo ExpectedInitial; + ExpectedInitial.BasicBlockCount = 4; + ExpectedInitial.TotalInstructionCount = 7; + ExpectedInitial.BlocksReachedFromConditionalInstruction = 2; + ExpectedInitial.Uses = 1; + ExpectedInitial.DirectCallsToDefinedFunctions = 1; + + FunctionPropertiesInfo ExpectedFinal = ExpectedInitial; + ExpectedFinal.BasicBlockCount = 4; + ExpectedFinal.DirectCallsToDefinedFunctions = 0; + ExpectedFinal.TotalInstructionCount = 7; + + auto FPI = buildFPI(*F1); + EXPECT_EQ(FPI, ExpectedInitial); + + FunctionPropertiesUpdater FPU(FPI, *CB); + InlineFunctionInfo IFI; + auto IR = llvm::InlineFunction(*CB, IFI); + EXPECT_TRUE(IR.isSuccess()); + FPU.finish(*LI); + EXPECT_EQ(FPI, ExpectedFinal); +} + } // end anonymous namespace