|
11 | 11 |
|
12 | 12 | #include "mlir/IR/Dominance.h"
|
13 | 13 | #include "mlir/IR/OpDefinition.h"
|
14 |
| -#include "mlir/Interfaces/Mem2RegInterfaces.h" |
| 14 | +#include "mlir/Interfaces/MemorySlotInterfaces.h" |
15 | 15 |
|
16 | 16 | namespace mlir {
|
17 | 17 |
|
| 18 | +/// Information computed during promotion analysis used to perform actual |
| 19 | +/// promotion. |
| 20 | +struct MemorySlotPromotionInfo { |
| 21 | + /// Blocks for which at least two definitions of the slot values clash. |
| 22 | + SmallPtrSet<Block *, 8> mergePoints; |
| 23 | + /// Contains, for each operation, which uses must be eliminated by promotion. |
| 24 | + /// This is a DAG structure because if an operation must eliminate some of |
| 25 | + /// its uses, it is because the defining ops of the blocking uses requested |
| 26 | + /// it. The defining ops therefore must also have blocking uses or be the |
| 27 | + /// starting point of the bloccking uses. |
| 28 | + DenseMap<Operation *, SmallPtrSet<OpOperand *, 4>> userToBlockingUses; |
| 29 | +}; |
| 30 | + |
| 31 | +/// Computes information for basic slot promotion. This will check that direct |
| 32 | +/// slot promotion can be performed, and provide the information to execute the |
| 33 | +/// promotion. This does not mutate IR. |
| 34 | +class MemorySlotPromotionAnalyzer { |
| 35 | +public: |
| 36 | + MemorySlotPromotionAnalyzer(MemorySlot slot, DominanceInfo &dominance) |
| 37 | + : slot(slot), dominance(dominance) {} |
| 38 | + |
| 39 | + /// Computes the information for slot promotion if promotion is possible, |
| 40 | + /// returns nothing otherwise. |
| 41 | + std::optional<MemorySlotPromotionInfo> computeInfo(); |
| 42 | + |
| 43 | +private: |
| 44 | + /// Computes the transitive uses of the slot that block promotion. This finds |
| 45 | + /// uses that would block the promotion, checks that the operation has a |
| 46 | + /// solution to remove the blocking use, and potentially forwards the analysis |
| 47 | + /// if the operation needs further blocking uses resolved to resolve its own |
| 48 | + /// uses (typically, removing its users because it will delete itself to |
| 49 | + /// resolve its own blocking uses). This will fail if one of the transitive |
| 50 | + /// users cannot remove a requested use, and should prevent promotion. |
| 51 | + LogicalResult computeBlockingUses( |
| 52 | + DenseMap<Operation *, SmallPtrSet<OpOperand *, 4>> &userToBlockingUses); |
| 53 | + |
| 54 | + /// Computes in which blocks the value stored in the slot is actually used, |
| 55 | + /// meaning blocks leading to a load. This method uses `definingBlocks`, the |
| 56 | + /// set of blocks containing a store to the slot (defining the value of the |
| 57 | + /// slot). |
| 58 | + SmallPtrSet<Block *, 16> |
| 59 | + computeSlotLiveIn(SmallPtrSetImpl<Block *> &definingBlocks); |
| 60 | + |
| 61 | + /// Computes the points in which multiple re-definitions of the slot's value |
| 62 | + /// (stores) may conflict. |
| 63 | + void computeMergePoints(SmallPtrSetImpl<Block *> &mergePoints); |
| 64 | + |
| 65 | + /// Ensures predecessors of merge points can properly provide their current |
| 66 | + /// definition of the value stored in the slot to the merge point. This can |
| 67 | + /// notably be an issue if the terminator used does not have the ability to |
| 68 | + /// forward values through block operands. |
| 69 | + bool areMergePointsUsable(SmallPtrSetImpl<Block *> &mergePoints); |
| 70 | + |
| 71 | + MemorySlot slot; |
| 72 | + DominanceInfo &dominance; |
| 73 | +}; |
| 74 | + |
| 75 | +/// The MemorySlotPromoter handles the state of promoting a memory slot. It |
| 76 | +/// wraps a slot and its associated allocator. This will perform the mutation of |
| 77 | +/// IR. |
| 78 | +class MemorySlotPromoter { |
| 79 | +public: |
| 80 | + MemorySlotPromoter(MemorySlot slot, PromotableAllocationOpInterface allocator, |
| 81 | + OpBuilder &builder, DominanceInfo &dominance, |
| 82 | + MemorySlotPromotionInfo info); |
| 83 | + |
| 84 | + /// Actually promotes the slot by mutating IR. Promoting a slot does not |
| 85 | + /// invalidate the MemorySlotPromotionInfo of other slots. |
| 86 | + void promoteSlot(); |
| 87 | + |
| 88 | +private: |
| 89 | + /// Computes the reaching definition for all the operations that require |
| 90 | + /// promotion. `reachingDef` is the value the slot should contain at the |
| 91 | + /// beginning of the block. This method returns the reached definition at the |
| 92 | + /// end of the block. |
| 93 | + Value computeReachingDefInBlock(Block *block, Value reachingDef); |
| 94 | + |
| 95 | + /// Computes the reaching definition for all the operations that require |
| 96 | + /// promotion. `reachingDef` corresponds to the initial value the |
| 97 | + /// slot will contain before any write, typically a poison value. |
| 98 | + void computeReachingDefInRegion(Region *region, Value reachingDef); |
| 99 | + |
| 100 | + /// Removes the blocking uses of the slot, in topological order. |
| 101 | + void removeBlockingUses(); |
| 102 | + |
| 103 | + /// Lazily-constructed default value representing the content of the slot when |
| 104 | + /// no store has been executed. This function may mutate IR. |
| 105 | + Value getLazyDefaultValue(); |
| 106 | + |
| 107 | + MemorySlot slot; |
| 108 | + PromotableAllocationOpInterface allocator; |
| 109 | + OpBuilder &builder; |
| 110 | + /// Potentially non-initialized default value. Use `getLazyDefaultValue` to |
| 111 | + /// initialize it on demand. |
| 112 | + Value defaultValue; |
| 113 | + /// Contains the reaching definition at this operation. Reaching definitions |
| 114 | + /// are only computed for promotable memory operations with blocking uses. |
| 115 | + DenseMap<PromotableMemOpInterface, Value> reachingDefs; |
| 116 | + DominanceInfo &dominance; |
| 117 | + MemorySlotPromotionInfo info; |
| 118 | +}; |
| 119 | + |
18 | 120 | /// Attempts to promote the memory slots of the provided allocators. Succeeds if
|
19 | 121 | /// at least one memory slot was promoted.
|
20 | 122 | LogicalResult
|
|
0 commit comments