|
19 | 19 | #include "mlir/IR/BuiltinTypes.h" |
20 | 20 | #include "mlir/IR/IntegerSet.h" |
21 | 21 | #include "mlir/IR/MLIRContext.h" |
22 | | -#include "mlir/Support/StorageUniquer.h" |
23 | | -#include "mlir/Support/ThreadLocalCache.h" |
24 | 22 | #include "llvm/ADT/APFloat.h" |
25 | 23 | #include "llvm/Support/Allocator.h" |
26 | | -#include <atomic> |
27 | | -#include <cstdint> |
28 | 24 | #include <mutex> |
29 | 25 |
|
30 | 26 | namespace mlir { |
@@ -398,112 +394,30 @@ class DistinctAttributeUniquer { |
398 | 394 | Attribute referencedAttr); |
399 | 395 | }; |
400 | 396 |
|
401 | | -/// An allocator for distinct attribute storage instances. It uses thread-local |
402 | | -/// bump pointer allocators stored in a thread-local cache to ensure the storage |
403 | | -/// is freed after the destruction of the distinct attribute allocator. The way |
404 | | -/// in which storage is allocated may be changed from a thread-local allocator |
405 | | -/// to a shared, locked allocator. This can be used to prevent use-after-free |
406 | | -/// errors if storage is allocated on a thread that has a lifetime less than the |
407 | | -/// lifetime of the storage. |
| 397 | +/// An allocator for distinct attribute storage instances. Uses a synchronized |
| 398 | +/// BumpPtrAllocator to ensure allocated storage is deleted when the |
| 399 | +/// DistinctAttributeAllocator is destroyed |
408 | 400 | class DistinctAttributeAllocator final { |
409 | 401 | public: |
410 | | - /// The allocation strategy for DistinctAttribute storage. |
411 | | - enum class AllocationMode : uint8_t { |
412 | | - /// Use a thread-local allocator. Lock-free, but storage lifetime is tied to |
413 | | - /// a thread, which may have shorter lifetime than the storage allocated |
414 | | - /// here. |
415 | | - ThreadLocal, |
416 | | - /// Use a single, shared allocator protected by a mutex. Slower due to |
417 | | - /// locking, but storage persists for the lifetime of the MLIR context. |
418 | | - SharedLocked, |
419 | | - }; |
420 | | - |
421 | | - DistinctAttributeAllocator() { |
422 | | - setAllocationMode(AllocationMode::ThreadLocal); |
423 | | - }; |
424 | | - |
| 402 | + DistinctAttributeAllocator() = default; |
425 | 403 | DistinctAttributeAllocator(DistinctAttributeAllocator &&) = delete; |
426 | 404 | DistinctAttributeAllocator(const DistinctAttributeAllocator &) = delete; |
427 | 405 | DistinctAttributeAllocator & |
428 | 406 | operator=(const DistinctAttributeAllocator &) = delete; |
429 | 407 |
|
430 | | - /// Allocates a distinct attribute storage. In most cases this will be |
431 | | - /// using a thread-local allocator for synchronization free parallel accesses, |
432 | | - /// however if the PassManager's crash recovery is enabled this will incur |
433 | | - /// synchronization cost in exchange for persisting the storage. |
434 | 408 | DistinctAttrStorage *allocate(Attribute referencedAttr) { |
435 | | - return std::invoke(allocatorFn.load(), *this, referencedAttr); |
436 | | - } |
437 | | - |
438 | | - /// Sets the allocation mode. This is used by the MLIRContext to switch |
439 | | - /// allocation strategies, for example, during crash recovery. |
440 | | - void setAllocationMode(AllocationMode mode) { |
441 | | - switch (mode) { |
442 | | - case AllocationMode::ThreadLocal: |
443 | | - allocatorFn.store(&DistinctAttributeAllocator::allocateThreadLocalWrapper, |
444 | | - std::memory_order_release); |
445 | | - break; |
446 | | - case AllocationMode::SharedLocked: |
447 | | - allocatorFn.store( |
448 | | - &DistinctAttributeAllocator::allocateLockedSharedWrapper, |
449 | | - std::memory_order_release); |
450 | | - break; |
451 | | - } |
452 | | - } |
453 | | - |
454 | | -private: |
455 | | - // Define some static wrappers for allocating using either the thread-local |
456 | | - // allocator or the shared locked allocator. We use these static wrappers to |
457 | | - // ensure that the width of the function pointer to these functions is the |
458 | | - // size of regular pointer on the platform (which is not always the case for |
459 | | - // pointer-to-member-function), and so should be handled by atomic |
460 | | - // instructions. |
461 | | - static DistinctAttrStorage * |
462 | | - allocateThreadLocalWrapper(DistinctAttributeAllocator &self, |
463 | | - Attribute referencedAttr) { |
464 | | - return self.allocateUsingThreadLocal(referencedAttr); |
465 | | - } |
466 | | - |
467 | | - static DistinctAttrStorage * |
468 | | - allocateLockedSharedWrapper(DistinctAttributeAllocator &self, |
469 | | - Attribute referencedAttr) { |
470 | | - return self.allocateUsingLockedShared(referencedAttr); |
471 | | - } |
472 | | - |
473 | | - DistinctAttrStorage *allocateUsingLockedShared(Attribute referencedAttr) { |
474 | | - std::scoped_lock<std::mutex> guard(sharedAllocatorMutex); |
475 | | - return doAllocate(sharedAllocator, referencedAttr); |
476 | | - } |
477 | | - |
478 | | - DistinctAttrStorage *allocateUsingThreadLocal(Attribute referencedAttr) { |
479 | | - return doAllocate(allocatorCache.get(), referencedAttr); |
480 | | - }; |
481 | | - |
482 | | - DistinctAttrStorage *doAllocate(llvm::BumpPtrAllocator &allocator, |
483 | | - Attribute referencedAttr) { |
| 409 | + std::scoped_lock<std::mutex> guard(allocatorMutex); |
484 | 410 | return new (allocator.Allocate<DistinctAttrStorage>()) |
485 | 411 | DistinctAttrStorage(referencedAttr); |
486 | 412 | }; |
487 | 413 |
|
488 | | - /// Used to allocate Distinct Attribute storage without synchronization |
489 | | - ThreadLocalCache<llvm::BumpPtrAllocator> allocatorCache; |
490 | | - |
491 | | - /// Used to allocate Distict Attribute storage with synchronization, |
492 | | - /// but without bounding the lifetime of the allocated memory to the |
493 | | - /// lifetime of a thread. |
494 | | - llvm::BumpPtrAllocator sharedAllocator; |
495 | | - |
496 | | - /// Used to lock access to the shared allocator |
497 | | - std::mutex sharedAllocatorMutex; |
498 | | - |
499 | | - using AllocatorFuncPtr = |
500 | | - DistinctAttrStorage *(*)(DistinctAttributeAllocator &, Attribute); |
| 414 | +private: |
| 415 | + /// Used to allocate Distict Attribute storage. When this allocator destroyed |
| 416 | + /// in till also dealllocate any storage instances |
| 417 | + llvm::BumpPtrAllocator allocator; |
501 | 418 |
|
502 | | - /// Atomic function pointer for the allocation strategy. Using a pointer to a |
503 | | - /// static member function as opposed to a non-static one should guarantee |
504 | | - /// that the function pointer fits into a standard pointer size, and so will |
505 | | - /// atomic instruction support for the corresponding width. |
506 | | - std::atomic<AllocatorFuncPtr> allocatorFn; |
| 419 | + /// Used to lock access to the allocator |
| 420 | + std::mutex allocatorMutex; |
507 | 421 | }; |
508 | 422 | } // namespace detail |
509 | 423 | } // namespace mlir |
|
0 commit comments