diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp --- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp +++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp @@ -511,6 +511,9 @@ if (!DirectCallee) return false; // No function pointer found. + if (!isLegalToPromote(CS, DirectCallee)) + return false; + // Success. promoteCall(CS, DirectCallee); return true; diff --git a/llvm/unittests/Transforms/Utils/CallPromotionUtilsTest.cpp b/llvm/unittests/Transforms/Utils/CallPromotionUtilsTest.cpp --- a/llvm/unittests/Transforms/Utils/CallPromotionUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/CallPromotionUtilsTest.cpp @@ -330,3 +330,50 @@ F = dyn_cast(GV); EXPECT_EQ(F, CS2.getCalledFunction()); } + +// Check that it isn't crashing due to missing promotion legality. +TEST(CallPromotionUtilsTest, TryPromoteCall_Legality) { + LLVMContext C; + std::unique_ptr M = parseIR(C, + R"IR( +%struct1 = type <{ i32, i64 }> +%struct2 = type <{ i32, i64 }> + +%class.Impl = type <{ %class.Interface, i32, [4 x i8] }> +%class.Interface = type { i32 (...)** } + +@_ZTV4Impl = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* null, i8* bitcast (%struct2 (%class.Impl*)* @_ZN4Impl3RunEv to i8*)] } + +define %struct1 @f() { +entry: + %o = alloca %class.Impl + %base = getelementptr %class.Impl, %class.Impl* %o, i64 0, i32 0, i32 0 + store i32 (...)** bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV4Impl, i64 0, inrange i32 0, i64 2) to i32 (...)**), i32 (...)*** %base + %f = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 1 + store i32 3, i32* %f + %base.i = getelementptr inbounds %class.Impl, %class.Impl* %o, i64 0, i32 0 + %c = bitcast %class.Interface* %base.i to %struct1 (%class.Interface*)*** + %vtable.i = load %struct1 (%class.Interface*)**, %struct1 (%class.Interface*)*** %c + %fp = load %struct1 (%class.Interface*)*, %struct1 (%class.Interface*)** %vtable.i + %rv = call %struct1 %fp(%class.Interface* nonnull %base.i) + ret %struct1 %rv +} + +declare %struct2 @_ZN4Impl3RunEv(%class.Impl* %this) +)IR"); + + auto *GV = M->getNamedValue("f"); + ASSERT_TRUE(GV); + auto *F = dyn_cast(GV); + ASSERT_TRUE(F); + Instruction *Inst = &F->front().front(); + auto *AI = dyn_cast(Inst); + ASSERT_TRUE(AI); + Inst = &*++F->front().rbegin(); + auto *CI = dyn_cast(Inst); + ASSERT_TRUE(CI); + CallSite CS(CI); + ASSERT_FALSE(CS.getCalledFunction()); + bool IsPromoted = tryPromoteCall(CS); + EXPECT_FALSE(IsPromoted); +}