1 //===- BufferUtils.h - Buffer optimization utilities ------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides utilities for passes optimizing code that has already
10 // been converted to buffers.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_BUFFERUTILS_H
15 #define MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_BUFFERUTILS_H
16
17 #include "mlir/Analysis/Liveness.h"
18 #include "mlir/Dialect/Arith/IR/Arith.h"
19 #include "mlir/Dialect/Bufferization/Transforms/BufferViewFlowAnalysis.h"
20 #include "mlir/IR/Builders.h"
21 #include "mlir/IR/BuiltinOps.h"
22 #include "mlir/IR/Dominance.h"
23 #include "mlir/IR/Operation.h"
24 #include "mlir/Transforms/DialectConversion.h"
25
26 namespace mlir {
27 namespace memref {
28 class GlobalOp;
29 } // namespace memref
30
31 namespace bufferization {
32
33 /// A simple analysis that detects allocation operations.
34 class BufferPlacementAllocs {
35 public:
36 /// Represents a tuple of allocValue and deallocOperation.
37 using AllocEntry = std::tuple<Value, Operation *>;
38
39 /// Represents a list containing all alloc entries.
40 using AllocEntryList = SmallVector<AllocEntry, 8>;
41
42 /// Get the start operation to place the given alloc value within the
43 /// specified placement block.
44 static Operation *getStartOperation(Value allocValue, Block *placementBlock,
45 const Liveness &liveness);
46
47 public:
48 /// Initializes the internal list by discovering all supported allocation
49 /// nodes.
50 BufferPlacementAllocs(Operation *op);
51
52 /// Returns the begin iterator to iterate over all allocations.
begin()53 AllocEntryList::const_iterator begin() const { return allocs.begin(); }
54
55 /// Returns the end iterator that can be used in combination with begin.
end()56 AllocEntryList::const_iterator end() const { return allocs.end(); }
57
58 /// Returns the begin iterator to iterate over all allocations.
begin()59 AllocEntryList::iterator begin() { return allocs.begin(); }
60
61 /// Returns the end iterator that can be used in combination with begin.
end()62 AllocEntryList::iterator end() { return allocs.end(); }
63
64 /// Registers a new allocation entry.
registerAlloc(const AllocEntry & entry)65 void registerAlloc(const AllocEntry &entry) { allocs.push_back(entry); }
66
67 private:
68 /// Searches for and registers all supported allocation entries.
69 void build(Operation *op);
70
71 private:
72 /// Maps allocation nodes to their associated blocks.
73 AllocEntryList allocs;
74 };
75
76 /// Finds a common dominator for the given value while taking the positions
77 /// of the values in the value set into account. It supports dominator and
78 /// post-dominator analyses via template arguments. If no common dominator
79 /// can be found, this function will return "nullptr".
80 template <typename DominatorT>
findCommonDominator(Value value,const BufferViewFlowAnalysis::ValueSetT & values,const DominatorT & doms)81 Block *findCommonDominator(Value value,
82 const BufferViewFlowAnalysis::ValueSetT &values,
83 const DominatorT &doms) {
84 // Store blocks in a set before querying `DominanceInfo` to filter out
85 // duplicate blocks (for performance reasons).
86 llvm::SmallPtrSet<Block *, 16> blocks;
87 // Start with the current block the value is defined in.
88 blocks.insert(value.getParentBlock());
89 for (Value childValue : values) {
90 for (Operation *user : childValue.getUsers()) {
91 // Find an appropriate dominator block that takes the current use into
92 // account.
93 blocks.insert(user->getBlock());
94 }
95 // Take values without any users into account.
96 blocks.insert(childValue.getParentBlock());
97 }
98 return doms.findNearestCommonDominator(blocks);
99 }
100
101 /// The base class for all BufferPlacement transformations.
102 class BufferPlacementTransformationBase {
103 public:
104 using ValueSetT = BufferViewFlowAnalysis::ValueSetT;
105
106 /// Constructs a new operation base using the given root operation.
107 BufferPlacementTransformationBase(Operation *op);
108
109 protected:
110 /// Alias information that can be updated during the insertion of copies.
111 BufferViewFlowAnalysis aliases;
112
113 /// Stores all internally managed allocations.
114 BufferPlacementAllocs allocs;
115
116 /// The underlying liveness analysis to compute fine grained information
117 /// about alloc and dealloc positions.
118 Liveness liveness;
119 };
120
121 // Create a global op for the given tensor-valued constant in the program.
122 // Globals are created lazily at the top of the enclosing ModuleOp with pretty
123 // names. Duplicates are avoided.
124 FailureOr<memref::GlobalOp> getGlobalFor(arith::ConstantOp constantOp,
125 uint64_t alignment,
126 Attribute memorySpace = {});
127
128 } // namespace bufferization
129 } // namespace mlir
130
131 #endif // MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_BUFFERUTILS_H
132