diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp --- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -520,8 +520,14 @@ for (const BasicBlock &BB : F) { // If we have any returns of `musttail` results - the signature can't // change - if (BB.getTerminatingMustTailCall() != nullptr) + if (const auto *TC = BB.getTerminatingMustTailCall()) { HasMustTailCalls = true; + // In addition, if the called function is virtual, we can't change + // the return type. + if (!TC->getCalledFunction()) + for (unsigned Ri = 0; Ri < RetCount; ++Ri) + RetValLiveness[Ri] = Live; + } } if (HasMustTailCalls) { diff --git a/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll b/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DeadArgElim/musttail-indirect.ll @@ -0,0 +1,9 @@ +; RUN: opt -passes=deadargelim,verify -S < %s 2>&1 | FileCheck %s +define internal i32 @test(ptr %fptr, i32 %a, i32 %b) { + %r = musttail call i32 %fptr(ptr %fptr, i32 %a, i32 0) + ret i32 %r +} + +; CHECK-NOT: cannot guarantee tail call due to mismatched parameter counts +; CHECK: define internal i32 @test +; CHECK-NEXT: %r = musttail call i32 %fptr