diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -129,18 +129,46 @@ } void LLVMContextImpl::dropTriviallyDeadConstantArrays() { - SmallSetVector WorkList(ArrayConstants.begin(), - ArrayConstants.end()); + // If a ConstantArray is destroyed, its ConstantArray operands could be dead + // too. Use a work list to keep track of such operands. + SmallSetVector WorkList; + // ArrayConstants can contain C1 and C2 in sequence where C2 is one of C1's + // operands. After C1 is destroyed, C2 is added into the work list. Before + // processing the C2 in the worklist, C2 is destroyed. Use a set to track of + // ConstantArrays deleted when iterating ArrayConstants. + // + // If ArrayConstants are copied into the work list first, the above issue does + // not occur because SmallSetVector keeps elements unique. However, for a + // large application, such a copy can take 20% LTO time. In pratice, a very + // few operands of a destroyed ConstantArray is dead. Therefore, we first + // iterate ArrayConstants, and use WorkList for only operands of type + // ConstantArray. + // + // In practics, a very few ConstantArrays are destroyed from ArrayConstants in + // the initial pass. So the sizes of WorkList and Deleted are much smaller + // than the size of ArrayConstants. + SmallPtrSet Deleted; + + for (auto I = ArrayConstants.begin(), E = ArrayConstants.end(); I != E;) { + auto *C = *I++; + if (!C->use_empty()) + continue; + for (const Use &Op : C->operands()) + if (auto *COp = dyn_cast(Op)) + WorkList.insert(COp); + // This does not invalidate ArrayConstants's iterator. + C->destroyConstant(); + Deleted.insert(C); + } while (!WorkList.empty()) { ConstantArray *C = WorkList.pop_back_val(); - if (C->use_empty()) { - for (const Use &Op : C->operands()) { - if (auto *COp = dyn_cast(Op)) - WorkList.insert(COp); - } - C->destroyConstant(); - } + if (!C->use_empty() || Deleted.contains(C)) + continue; + for (const Use &Op : C->operands()) + if (auto *COp = dyn_cast(Op)) + WorkList.insert(COp); + C->destroyConstant(); } }