Index: llvm/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -716,7 +716,88 @@ Assume->eraseFromParent(); resetIteratorIfInvalidatedWhileCalling(&BB, [&]() { - RecursivelyDeleteTriviallyDeadInstructions(Operand, TLInfo, nullptr); + auto *OperandInst = dyn_cast(Operand); + if (!OperandInst || + !wouldInstructionBeTriviallyDead(OperandInst, TLInfo)) + return; + // Instructions marked for removal. + SmallPtrSet ToRemove; + // Keeps the operands of already marked to remove instructions. + // Contains only instructions would be trivial dead if no uses. + SmallPtrSet Candidates; + + // For a given instruction, add its operands to Candidate set if + // it is an instruction and would be trivially dead if no uses. + // Also removes operands from instruction itself. + auto AddToCandidates = [&](Instruction *I) { + assert(ToRemove.count(I) && "Should be already marked!"); + for (Use &OpU : I->operands()) { + if (Value *OpV = OpU.get()) { + OpU.set(nullptr); + if (auto *OpI = dyn_cast(OpV)) + if (!ToRemove.count(OpI) && + wouldInstructionBeTriviallyDead(OpI, TLInfo)) + Candidates.insert(OpI); + } + } + }; + + // For instruction I, find transitive closure of users and if + // all of them would be trivially dead or other llvm.assume then + // mark them for removal and populate Candidate with new instructions. + auto ProcessCandidate = [&](Instruction *I) { + assert(wouldInstructionBeTriviallyDead(I, TLInfo) && + "expect trivially dead"); + // Simple Case. no users. + if (I->use_empty()) { + ToRemove.insert(I); + AddToCandidates(I); + return; + } + // Find a cycle of dead instructions. + SmallPtrSet Visited; + SmallVector Worklist; + Visited.insert(I); + Worklist.push_back(I); + while (!Worklist.empty()) { + Instruction *Curr = Worklist.pop_back_val(); + for (auto *U : Curr->users()) { + auto *UI = dyn_cast(U); + if (!UI) + return; + if (!Visited.insert(UI).second) + continue; + if (isa(UI) || + wouldInstructionBeTriviallyDead(UI, TLInfo)) + Worklist.push_back(UI); + else + return; + } + } + // We found a cycle. Add all walked instructions to remove set. + ToRemove.insert(Visited.begin(), Visited.end()); + for (auto *V : Visited) + AddToCandidates(V); + }; + + if (OperandInst->use_empty()) { + ToRemove.insert(OperandInst); + AddToCandidates(OperandInst); + } else + Candidates.insert(OperandInst); + + // Process candidates now. + while (!Candidates.empty()) { + Instruction *Cand = *Candidates.begin(); + Candidates.erase(Cand); + ProcessCandidate(Cand); + } + // Now, remove everything we found. + for (auto *TR : ToRemove) { + assert(TR->use_empty() && "Expected no uses!"); + salvageDebugInfo(*TR); + TR->eraseFromParent(); + } }); } } Index: llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll +++ llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll @@ -32,9 +32,7 @@ ; CHECK-NEXT: br label [[HEADER:%.*]] ; CHECK: header: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[HEADER]] ] -; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[HEADER]] ] ; CHECK-NEXT: [[IV_INC]] = add i32 [[IV]], 1 -; CHECK-NEXT: [[IV2_INC]] = add i32 [[IV2]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[IV]], [[N:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[HEADER]] ; CHECK: exit: @@ -63,9 +61,7 @@ ; CHECK-NEXT: br label [[HEADER:%.*]] ; CHECK: header: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[HEADER]] ] -; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[HEADER]] ] ; CHECK-NEXT: [[IV_INC]] = add i32 [[IV]], 1 -; CHECK-NEXT: [[IV2_INC]] = add i32 [[IV2]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[IV]], [[N:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[HEADER]] ; CHECK: exit: