Skip to content

DO NOT MERGE: Identify places that need reserve. #136543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ reverse_children::reverse_children(Stmt *S, ASTContext &Ctx) {
}

// Default case for all other statements.
auto R = S->children();
childrenBuf.reserve(childrenBuf.size() + std::distance(R.begin(), R.end()));
llvm::append_range(childrenBuf, S->children());

// This needs to be done *after* childrenBuf has been populated.
Expand Down
51 changes: 51 additions & 0 deletions llvm/include/llvm/ADT/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -2113,12 +2113,63 @@ void erase(Container &C, ValueType V) {
C.erase(std::remove(C.begin(), C.end(), V), C.end());
}

namespace detail {
template <typename Range>
using check_has_member_iterator_category_t =
typename decltype(std::declval<Range &>().begin())::iterator_category;

template <typename Range>
static constexpr bool HasMemberIteratorCategory =
is_detected<check_has_member_iterator_category_t, Range>::value;
Comment on lines +2118 to +2123
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iterator_traits should already handle plain pointers, so I think we'd want to use that instead of looking for iterator_category?


template <typename Container>
using check_has_member_capacity_t =
decltype(std::declval<Container &>().capacity());

template <typename Container>
static constexpr bool HasMemberCapacity =
is_detected<check_has_member_capacity_t, Container>::value;

template <typename Container>
using check_has_member_reserve_t =
decltype(std::declval<Container &>().reserve(1U));

template <typename Container>
static constexpr bool HasMemberReserve =
is_detected<check_has_member_reserve_t, Container>::value;
} // namespace detail

/// Wrapper function to append range `R` to container `C`.
///
/// C.insert(C.end(), R.begin(), R.end());
template <typename Container, typename Range>
void append_range(Container &C, Range &&R) {
size_t Before = 0;
size_t After = 0;

if constexpr (detail::HasMemberReserve<Container>) {
using IteratorType = decltype(adl_begin(R));
if constexpr (std::is_pointer<IteratorType>::value) {
C.reserve(C.size() + std::distance(adl_begin(R), adl_end(R)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to check that the type either has .size() (which we assume to be fast) or that llvm::size is detected (which already requires random access iterators)

} else if constexpr (detail::HasMemberIteratorCategory<Range>) {
if constexpr (std::is_convertible<
typename IteratorType::iterator_category,
std::random_access_iterator_tag>::value) {
C.reserve(C.size() + std::distance(adl_begin(R), adl_end(R)));
}
}
}

if constexpr (detail::HasMemberCapacity<Container>)
Before = C.capacity();

C.insert(C.end(), adl_begin(R), adl_end(R));

if constexpr (detail::HasMemberCapacity<Container>)
After = C.capacity();

if (Before != After)
llvm_unreachable("capacity changed");
Comment on lines +2168 to +2172
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a cool idea for verifying that it reserved as intended!

}

/// Appends all `Values` to container `C`.
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/SplitKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ void SplitEditor::computeRedundantBackCopies(
}
if (!DominatedVNIs.empty()) {
forceRecompute(0, *ParentVNI);
BackCopies.reserve(BackCopies.size() + DominatedVNIs.size());
append_range(BackCopies, DominatedVNIs);
DominatedVNIs.clear();
}
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,11 @@ static void forEachUser(const Value *User,
const Value *Cur = WorkList.pop_back_val();
if (!Visited.insert(Cur).second)
continue;
if (Callback(Cur))
if (Callback(Cur)) {
auto R = Cur->materialized_users();
WorkList.reserve(WorkList.size() + std::distance(R.begin(), R.end()));
append_range(WorkList, Cur->materialized_users());
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,8 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
Value *V = Worklist.pop_back_val();
if (isa<GetElementPtrInst>(V)) {
DeadInsts.push_back(cast<Instruction>(V));
auto R = V->users();
Worklist.reserve(Worklist.size() + std::distance(R.begin(), R.end()));
append_range(Worklist, V->users());
continue;
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/IPO/FunctionAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,7 @@ static bool inferInitializes(Argument &A, Function &F) {
if (UPB != UsesPerBlock.end()) {
// Sort uses in this block by instruction order.
SmallVector<std::pair<Instruction *, ArgumentAccessInfo>, 2> Insts;
Insts.reserve(UPB->second.Insts.size());
append_range(Insts, UPB->second.Insts);
sort(Insts, [](std::pair<Instruction *, ArgumentAccessInfo> &LHS,
std::pair<Instruction *, ArgumentAccessInfo> &RHS) {
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Transforms/IPO/GlobalOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,11 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
append_range(WorkList, BO->users());
if (auto *ASC = dyn_cast<AddrSpaceCastOperator>(U))
append_range(WorkList, ASC->users());
else if (auto *GEP = dyn_cast<GEPOperator>(U))
else if (auto *GEP = dyn_cast<GEPOperator>(U)) {
auto R = GEP->users();
WorkList.reserve(WorkList.size() + std::distance(R.begin(), R.end()));
append_range(WorkList, GEP->users());
else if (auto *LI = dyn_cast<LoadInst>(U)) {
} else if (auto *LI = dyn_cast<LoadInst>(U)) {
// A load from a uniform value is always the same, regardless of any
// applied offset.
Type *Ty = LI->getType();
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Transforms/Utils/LoopSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,12 @@ static void addBlockAndPredsToSet(BasicBlock *InputBB, BasicBlock *StopBlock,
Worklist.push_back(InputBB);
do {
BasicBlock *BB = Worklist.pop_back_val();
if (Blocks.insert(BB).second && BB != StopBlock)
if (Blocks.insert(BB).second && BB != StopBlock) {
// If BB is not already processed and it is not a stop block then
// insert its predecessor in the work list
Worklist.reserve(Worklist.size() + pred_size(BB));
append_range(Worklist, predecessors(BB));
}
} while (!Worklist.empty());
}

Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Transforms/Utils/SSAUpdater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,12 @@ class SSAUpdaterTraits<SSAUpdater> {
// We can get our predecessor info by walking the pred_iterator list,
// but it is relatively slow. If we already have PHI nodes in this
// block, walk one of them to get the predecessor list instead.
if (PHINode *SomePhi = dyn_cast<PHINode>(BB->begin()))
if (PHINode *SomePhi = dyn_cast<PHINode>(BB->begin())) {
append_range(*Preds, SomePhi->blocks());
else
} else {
Preds->reserve(pred_size(BB));
append_range(*Preds, predecessors(BB));
}
}

/// GetPoisonVal - Get a poison value of the same type as the value
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6433,6 +6433,7 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(ElementCount VF) {

// Add all instructions used to generate the addresses.
SmallVector<Instruction *, 4> Worklist;
Worklist.reserve(AddrDefs.size());
append_range(Worklist, AddrDefs);
while (!Worklist.empty()) {
Instruction *I = Worklist.pop_back_val();
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/TableGen/Common/CodeGenRegisters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@ void CodeGenRegisterClass::extendSuperRegClasses(CodeGenSubRegIndex *SubIdx) {
return;

SmallVector<CodeGenRegisterClass *> MidRCs;
MidRCs.reserve(It->second.size());
llvm::append_range(MidRCs, It->second);

for (CodeGenRegisterClass *MidRC : MidRCs) {
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/TableGen/GlobalISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Create a table containing the LLT objects needed by the matcher and an enum
// for the matcher to reference them with.
std::vector<LLTCodeGen> TypeObjects;
TypeObjects.reserve(KnownTypes.size());
append_range(TypeObjects, KnownTypes);
llvm::sort(TypeObjects);

Expand Down
Loading