diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -1923,10 +1923,13 @@ // We no longer need the assumes or the type test. for (auto Assume : Assumes) Assume->eraseFromParent(); + // We may run into multiple type tests feeding into a phi. In that case + // RAUW true and leave the assume. + if (!CI->use_empty()) + CI->replaceAllUsesWith(ConstantInt::getTrue(M.getContext())); // We can't use RecursivelyDeleteTriviallyDeadInstructions here because we // may use the vtable argument later. - if (CI->use_empty()) - CI->eraseFromParent(); + CI->eraseFromParent(); }; // At this point we could remove all type test assume sequences, as they diff --git a/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-assume-phi.ll b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-assume-phi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-assume-phi.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s 2>&1 | FileCheck %s + +define void @call(ptr %obj, i1 %i) { +; CHECK-LABEL: @call( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[I:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[OBJ:%.*]], align 8 +; CHECK-NEXT: [[FPTR:%.*]] = load ptr, ptr [[VTABLE]], align 8 +; CHECK-NEXT: call void [[FPTR]](ptr [[OBJ]]) +; CHECK-NEXT: br label [[FIN:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[VTABLE2:%.*]] = load ptr, ptr [[OBJ]], align 8 +; CHECK-NEXT: [[FPTR2:%.*]] = load ptr, ptr [[VTABLE2]], align 8 +; CHECK-NEXT: call void [[FPTR2]](ptr [[OBJ]]) +; CHECK-NEXT: br label [[FIN]] +; CHECK: fin: +; CHECK-NEXT: [[PN:%.*]] = phi i1 [ true, [[BB1]] ], [ true, [[BB2]] ] +; CHECK-NEXT: call void @llvm.assume(i1 [[PN]]) +; CHECK-NEXT: ret void +; +entry: + br i1 %i, label %bb1, label %bb2 +bb1: + %vtable = load ptr, ptr %obj + %fptr = load ptr, ptr %vtable + call void %fptr(ptr %obj) + %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid") + br label %fin +bb2: + %vtable2 = load ptr, ptr %obj + %fptr2 = load ptr, ptr %vtable2 + call void %fptr2(ptr %obj) + %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !"typeid") + br label %fin +fin: + %pn = phi i1 [ %p, %bb1 ], [ %p2, %bb2 ] + call void @llvm.assume(i1 %pn) + ret void +} + +declare i1 @llvm.type.test(ptr, metadata) +declare void @llvm.assume(i1) + +!0 = !{i32 0, !"typeid"}