llvm.org GIT mirror llvm / 2565675
Query the StringMap only once when creating MDString (NFC) Summary: Loading IR with debug info improves MDString::get() from 19ms to 10ms. This is a rework of D16597 with adding an "emplace" method on the StringMap to avoid requiring the MDString move ctor to be public. Reviewers: dexonsmith Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D17920 From: Mehdi Amini <mehdi.amini@apple.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264386 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
4 changed file(s) with 76 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
142142
143143 StringRef first() const { return StringRef(getKeyData(), getKeyLength()); }
144144
145 /// Create - Create a StringMapEntry for the specified key and default
146 /// construct the value.
147 template
145 /// Create a StringMapEntry for the specified key construct the value using
146 /// \p InitiVals.
147 template
148148 static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator,
149 InitType &&InitVal) {
149 InitTypes &&... InitVals) {
150150 unsigned KeyLength = Key.size();
151151
152152 // Allocate a new item with space for the string at the end and a null
158158 StringMapEntry *NewItem =
159159 static_cast(Allocator.Allocate(AllocSize,Alignment));
160160
161 // Default construct the value.
162 new (NewItem) StringMapEntry(KeyLength, std::forward(InitVal));
161 // Construct the value.
162 new (NewItem)
163 StringMapEntry(KeyLength, std::forward(InitVals)...);
163164
164165 // Copy the string information.
165166 char *StrBuffer = const_cast(NewItem->getKeyData());
167168 memcpy(StrBuffer, Key.data(), KeyLength);
168169 StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
169170 return NewItem;
170 }
171
172 template
173 static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator) {
174 return Create(Key, Allocator, ValueTy());
175171 }
176172
177173 /// Create - Create a StringMapEntry with normal malloc/free.
295291 return ValueTy();
296292 }
297293
294 /// Lookup the ValueTy for the \p Key, or create a default constructed value
295 /// if the key is not in the map.
298296 ValueTy &operator[](StringRef Key) {
299 return insert(std::make_pair(Key, ValueTy())).first->second;
297 return emplace_second(Key).first->second;
300298 }
301299
302300 /// count - Return 1 if the element is in the map, 0 otherwise.
328326 /// if and only if the insertion takes place, and the iterator component of
329327 /// the pair points to the element with key equivalent to the key of the pair.
330328 std::pair insert(std::pair KV) {
331 unsigned BucketNo = LookupBucketFor(KV.first);
329 return emplace_second(KV.first, std::move(KV.second));
330 }
331
332 /// Emplace a new element for the specified key into the map if the key isn't
333 /// already in the map. The bool component of the returned pair is true
334 /// if and only if the insertion takes place, and the iterator component of
335 /// the pair points to the element with key equivalent to the key of the pair.
336 template
337 std::pair emplace_second(StringRef Key, ArgsTy &&... Args) {
338 unsigned BucketNo = LookupBucketFor(Key);
332339 StringMapEntryBase *&Bucket = TheTable[BucketNo];
333340 if (Bucket && Bucket != getTombstoneVal())
334341 return std::make_pair(iterator(TheTable + BucketNo, false),
336343
337344 if (Bucket == getTombstoneVal())
338345 --NumTombstones;
339 Bucket =
340 MapEntryTy::Create(KV.first, Allocator, std::move(KV.second));
346 Bucket = MapEntryTy::Create(Key, Allocator, std::forward(Args)...);
341347 ++NumItems;
342348 assert(NumItems + NumTombstones <= NumBuckets);
343349
591591
592592 StringMapEntry *Entry;
593593 MDString() : Metadata(MDStringKind, Uniqued), Entry(nullptr) {}
594 MDString(MDString &&) : Metadata(MDStringKind, Uniqued) {}
595594
596595 public:
597596 static MDString *get(LLVMContext &Context, StringRef Str);
396396
397397 MDString *MDString::get(LLVMContext &Context, StringRef Str) {
398398 auto &Store = Context.pImpl->MDStringCache;
399 auto I = Store.find(Str);
400 if (I != Store.end())
401 return &I->second;
402
403 auto *Entry =
404 StringMapEntry::Create(Str, Store.getAllocator(), MDString());
405 bool WasInserted = Store.insert(Entry);
406 (void)WasInserted;
407 assert(WasInserted && "Expected entry to be inserted");
408 Entry->second.Entry = Entry;
409 return &Entry->second;
399 auto I = Store.emplace_second(Str);
400 auto &MapEntry = I.first->getValue();
401 if (!I.second)
402 return &MapEntry;
403 MapEntry.Entry = &*I.first;
404 return &MapEntry;
410405 }
411406
412407 StringRef MDString::getString() const {
357357
358358 namespace {
359359 // Simple class that counts how many moves and copy happens when growing a map
360 struct CountCopyAndMove {
360 struct CountCtorCopyAndMove {
361 static unsigned Ctor;
361362 static unsigned Move;
362363 static unsigned Copy;
363 CountCopyAndMove() {}
364
365 CountCopyAndMove(const CountCopyAndMove &) { Copy++; }
366 CountCopyAndMove &operator=(const CountCopyAndMove &) {
364 int Data = 0;
365 CountCtorCopyAndMove(int Data) : Data(Data) { Ctor++; }
366 CountCtorCopyAndMove() { Ctor++; }
367
368 CountCtorCopyAndMove(const CountCtorCopyAndMove &) { Copy++; }
369 CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &) {
367370 Copy++;
368371 return *this;
369372 }
370 CountCopyAndMove(CountCopyAndMove &&) { Move++; }
371 CountCopyAndMove &operator=(const CountCopyAndMove &&) {
373 CountCtorCopyAndMove(CountCtorCopyAndMove &&) { Move++; }
374 CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &&) {
372375 Move++;
373376 return *this;
374377 }
375378 };
376 unsigned CountCopyAndMove::Copy = 0;
377 unsigned CountCopyAndMove::Move = 0;
379 unsigned CountCtorCopyAndMove::Copy = 0;
380 unsigned CountCtorCopyAndMove::Move = 0;
381 unsigned CountCtorCopyAndMove::Ctor = 0;
378382
379383 } // anonymous namespace
380384
384388 // 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an
385389 // arbitrary prime, picked without any good reason.
386390 for (auto Size : {1, 32, 67}) {
387 StringMap Map(Size);
388 CountCopyAndMove::Copy = 0;
389 CountCopyAndMove::Move = 0;
391 StringMap Map(Size);
392 CountCtorCopyAndMove::Move = 0;
393 CountCtorCopyAndMove::Copy = 0;
390394 for (int i = 0; i < Size; ++i)
391 Map.insert(std::make_pair(Twine(i).str(), CountCopyAndMove()));
392 EXPECT_EQ((unsigned)Size * 3, CountCopyAndMove::Move);
393 EXPECT_EQ(0u, CountCopyAndMove::Copy);
394 }
395 Map.insert(std::make_pair(Twine(i).str(), CountCtorCopyAndMove()));
396 EXPECT_EQ((unsigned)Size * 3, CountCtorCopyAndMove::Move);
397 EXPECT_EQ(0u, CountCtorCopyAndMove::Copy);
398 }
399 }
400
401 TEST(StringMapCustomTest, BracketOperatorCtor) {
402 StringMap Map;
403 CountCtorCopyAndMove::Ctor = 0;
404 Map["abcd"];
405 EXPECT_EQ(1u, CountCtorCopyAndMove::Ctor);
406 // Test that operator[] does not create a value when it is already in the map
407 CountCtorCopyAndMove::Ctor = 0;
408 Map["abcd"];
409 EXPECT_EQ(0u, CountCtorCopyAndMove::Ctor);
410 }
411
412 namespace {
413 struct NonMoveableNonCopyableType {
414 int Data = 0;
415 NonMoveableNonCopyableType() = default;
416 NonMoveableNonCopyableType(int Data) : Data(Data) {}
417 NonMoveableNonCopyableType(const NonMoveableNonCopyableType &) = delete;
418 NonMoveableNonCopyableType(NonMoveableNonCopyableType &&) = delete;
419 };
420 }
421
422 // Test that we can "emplace" an element in the map without involving map/move
423 TEST(StringMapCustomTest, EmplaceTest) {
424 StringMap Map;
425 Map.emplace_second("abcd", 42);
426 EXPECT_EQ(1u, Map.count("abcd"));
427 EXPECT_EQ(42, Map["abcd"].Data);
395428 }
396429
397430 } // end anonymous namespace