CIRCT 20.0.0git
Loading...
Searching...
No Matches
CFToHandshake.h
Go to the documentation of this file.
1//===- CFToHandshake.h ------------------------------------------*- 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 declares passes which together will lower the Standard dialect to
10// Handshake dialect.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef CIRCT_CONVERSION_CFTOHANDSHAKE_H_
15#define CIRCT_CONVERSION_CFTOHANDSHAKE_H_
16
20#include "mlir/Transforms/DialectConversion.h"
21
22#include <memory>
23
24namespace mlir {
25class ModuleOp;
26template <typename T>
28} // namespace mlir
29
30namespace circt {
31
32#define GEN_PASS_DECL_CFTOHANDSHAKE
33#define GEN_PASS_DECL_HANDSHAKEREMOVEBLOCK
34#include "circt/Conversion/Passes.h.inc"
35
36namespace handshake {
37
38// ============================================================================
39// Partial lowering infrastructure
40// ============================================================================
41
43 llvm::function_ref<LogicalResult(Region &, ConversionPatternRewriter &)>;
44// Convenience function for executing a PartialLowerRegion with a provided
45// partial lowering function.
46LogicalResult partiallyLowerRegion(const RegionLoweringFunc &loweringFunc,
47 MLIRContext *ctx, Region &r);
48
49// Holds the shared state of the different transformations required to transform
50// Standard to Handshake operations. The transformations are expressed as member
51// functions to simplify access to the state.
52//
53// This class' member functions expect a rewriter that matched on the parent
54// operation of the encapsulated region.
56public:
57 struct MergeOpInfo {
58 Operation *op;
59 Value val;
60 SmallVector<Backedge> dataEdges;
61 std::optional<Backedge> indexEdge{};
62 };
63
64 using BlockValues = DenseMap<Block *, std::vector<Value>>;
65 using BlockOps = DenseMap<Block *, std::vector<MergeOpInfo>>;
66 using ValueMap = DenseMap<Value, Value>;
68 llvm::MapVector<Value, std::vector<Operation *>>;
69
70 explicit HandshakeLowering(Region &r) : r(r) {}
71
72 LogicalResult addMergeOps(ConversionPatternRewriter &rewriter);
73 LogicalResult addBranchOps(ConversionPatternRewriter &rewriter);
74 LogicalResult replaceCallOps(ConversionPatternRewriter &rewriter);
75
76 template <typename TSrcTerm, typename TDstTerm>
77 LogicalResult setControlOnlyPath(ConversionPatternRewriter &rewriter,
78 Value entryCtrl) {
79 assert(isa<NoneType>(entryCtrl.getType()) &&
80 "Expected NoneType for entry control value");
81 // Creates start and end points of the control-only path
82 Block *entryBlock = &r.front();
83 setBlockEntryControl(entryBlock, entryCtrl);
84
85 // Replace original return ops with new returns with additional control
86 // input
87 for (auto retOp : llvm::make_early_inc_range(r.getOps<TSrcTerm>())) {
88 rewriter.setInsertionPoint(retOp);
89 SmallVector<Value, 8> operands(retOp->getOperands());
90 operands.push_back(entryCtrl);
91 rewriter.replaceOpWithNewOp<TDstTerm>(retOp, operands);
92 }
93
94 // Store the number of block arguments in each block
95 DenseMap<Block *, unsigned> numArgsPerBlock;
96 for (auto &block : r.getBlocks())
97 numArgsPerBlock[&block] = block.getNumArguments();
98
99 // Apply SSA maximization on the newly added entry block argument to
100 // propagate it explicitly between the start-point of the control-only
101 // network and the function's terminators
102 if (failed(runSSAMaximization(rewriter, entryCtrl)))
103 return failure();
104
105 // Identify all block arguments belonging to the control-only network
106 // (needed to later insert control merges after those values). These are the
107 // last arguments to blocks that got a new argument during SSA maximization
108 for (auto &[block, numArgs] : numArgsPerBlock)
109 if (block->getNumArguments() != numArgs)
110 setBlockEntryControl(block, block->getArguments().back());
111
112 return success();
113 }
114
115 LogicalResult connectConstantsToControl(ConversionPatternRewriter &rewriter,
116 bool sourceConstants);
117
118 LogicalResult feedForwardRewriting(ConversionPatternRewriter &rewriter);
119 LogicalResult loopNetworkRewriting(ConversionPatternRewriter &rewriter);
120
121 BlockOps insertMergeOps(ValueMap &mergePairs, BackedgeBuilder &edgeBuilder,
122 ConversionPatternRewriter &rewriter);
123
124 // Insert appropriate type of Merge CMerge for control-only path,
125 // Merge for single-successor blocks, Mux otherwise
126 MergeOpInfo insertMerge(Block *block, Value val, BackedgeBuilder &edgeBuilder,
127 ConversionPatternRewriter &rewriter);
128
129 // Replaces standard memory ops with their handshake version (i.e.,
130 // ops which connect to memory/LSQ). Returns a map with an ordered
131 // list of new ops corresponding to each memref. Later, we instantiate
132 // a memory node for each memref and connect it to its load/store ops
133 LogicalResult replaceMemoryOps(ConversionPatternRewriter &rewriter,
134 MemRefToMemoryAccessOp &memRefOps);
135
136 LogicalResult connectToMemory(ConversionPatternRewriter &rewriter,
137 MemRefToMemoryAccessOp memRefOps, bool lsq);
138 void setMemOpControlInputs(ConversionPatternRewriter &rewriter,
139 ArrayRef<Operation *> memOps, Operation *memOp,
140 int offset, ArrayRef<int> cntrlInd);
141
142 // Returns the entry control value for operations contained within this
143 // block.
144 Value getBlockEntryControl(Block *block) const;
145
146 void setBlockEntryControl(Block *block, Value v);
147
148 Region &getRegion() { return r; }
149 MLIRContext *getContext() { return r.getContext(); }
150
151protected:
152 // SSA maximization dispatch, to avoid an inclusion of
153 // "circt/Transforms/Passes.h" in this header file (which itself is in the
154 // Converisons library). Instead, move this dependency to CFToHandshake.cpp.
155 LogicalResult runSSAMaximization(ConversionPatternRewriter &rewriter,
156 Value entryCtrl);
157
158 Region &r;
159
160 /// Start point of the control-only network
161 BlockArgument startCtrl;
162
163private:
164 DenseMap<Block *, Value> blockEntryControlMap;
165};
166
167// Driver for the HandshakeLowering class.
168// Note: using two different vararg template names due to potantial references
169// that would cause a type mismatch
170template <typename T, typename... TArgs, typename... TArgs2>
171LogicalResult runPartialLowering(
172 T &instance,
173 LogicalResult (T::*memberFunc)(ConversionPatternRewriter &, TArgs2...),
174 TArgs &...args) {
176 [&](Region &, ConversionPatternRewriter &rewriter) -> LogicalResult {
177 return (instance.*memberFunc)(rewriter, args...);
178 },
179 instance.getContext(), instance.getRegion());
180}
181
182/// Remove basic blocks inside the given region. This allows the result to be
183/// a valid graph region, since multi-basic block regions are not allowed to
184/// be graph regions currently.
185void removeBasicBlocks(Region &r);
186
187// Helper to check the validity of the dataflow conversion
188// Driver that applies the partial lowerings expressed in HandshakeLowering to
189// the region encapsulated in it. The region is assumed to have a terminator of
190// type TSrcTerm, and will replace it with TDstTerm. See HandshakeLowering for
191// the different lowering steps.
192template <typename TSrcTerm, typename TDstTerm>
193LogicalResult lowerRegion(HandshakeLowering &hl, bool sourceConstants,
194 bool disableTaskPipelining, Value entryCtrl) {
195 // Perform initial dataflow conversion. This process allows for the use of
196 // non-deterministic merge-like operations.
198
199 if (failed(
201 return failure();
202 if (failed(runPartialLowering(
203 hl, &HandshakeLowering::setControlOnlyPath<TSrcTerm, TDstTerm>,
204 entryCtrl)))
205 return failure();
207 return failure();
209 return failure();
211 return failure();
212
213 // The following passes modifies the dataflow graph to being safe for task
214 // pipelining. In doing so, non-deterministic merge structures are replaced
215 // for deterministic structures.
216 if (!disableTaskPipelining) {
217 if (failed(
219 return failure();
220 if (failed(
222 return failure();
223 }
224
225 if (failed(runPartialLowering(
226 hl, &HandshakeLowering::connectConstantsToControl, sourceConstants)))
227 return failure();
228
229 bool lsq = false;
231 lsq)))
232 return failure();
233
234 // Legalize the resulting regions, removing basic blocks and performing
235 // any simple conversions.
237
238 return success();
239}
240
241/// Lowers the mlir operations into handshake that are not part of the dataflow
242/// conversion.
243LogicalResult postDataflowConvert(Operation *op);
244
245} // namespace handshake
246
247std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>>
249
250std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>>
251createCFToHandshakePass(bool sourceConstants = false,
252 bool disableTaskPipelining = false);
253
254std::unique_ptr<mlir::OperationPass<handshake::FuncOp>>
256
257std::unique_ptr<mlir::OperationPass<handshake::FuncOp>>
259
260/// Insert additional blocks that serve as counterparts to the blocks that
261/// diverged the control flow.
262/// The resulting merge block tree is guaranteed to be a binary tree.
263///
264/// This transformation does treat loops like a single block and thus does not
265/// affect them.
266mlir::LogicalResult
267insertMergeBlocks(mlir::Region &r, mlir::ConversionPatternRewriter &rewriter);
268
269std::unique_ptr<mlir::Pass> createInsertMergeBlocksPass();
270
271} // namespace circt
272
273#endif // CIRCT_CONVERSION_CFTOHANDSHAKE_H_
assert(baseType &&"element must be base type")
llvm::ScopedHashTable< mlir::Value, std::string > ValueMap
Instantiate one of these and use it to build typed backedges.
BlockOps insertMergeOps(ValueMap &mergePairs, BackedgeBuilder &edgeBuilder, ConversionPatternRewriter &rewriter)
MergeOpInfo insertMerge(Block *block, Value val, BackedgeBuilder &edgeBuilder, ConversionPatternRewriter &rewriter)
LogicalResult loopNetworkRewriting(ConversionPatternRewriter &rewriter)
BlockArgument startCtrl
Start point of the control-only network.
DenseMap< Block *, std::vector< MergeOpInfo > > BlockOps
LogicalResult feedForwardRewriting(ConversionPatternRewriter &rewriter)
LogicalResult replaceCallOps(ConversionPatternRewriter &rewriter)
void setMemOpControlInputs(ConversionPatternRewriter &rewriter, ArrayRef< Operation * > memOps, Operation *memOp, int offset, ArrayRef< int > cntrlInd)
LogicalResult addMergeOps(ConversionPatternRewriter &rewriter)
LogicalResult replaceMemoryOps(ConversionPatternRewriter &rewriter, MemRefToMemoryAccessOp &memRefOps)
DenseMap< Block *, std::vector< Value > > BlockValues
LogicalResult connectConstantsToControl(ConversionPatternRewriter &rewriter, bool sourceConstants)
llvm::MapVector< Value, std::vector< Operation * > > MemRefToMemoryAccessOp
LogicalResult runSSAMaximization(ConversionPatternRewriter &rewriter, Value entryCtrl)
DenseMap< Block *, Value > blockEntryControlMap
LogicalResult setControlOnlyPath(ConversionPatternRewriter &rewriter, Value entryCtrl)
DenseMap< Value, Value > ValueMap
Value getBlockEntryControl(Block *block) const
void setBlockEntryControl(Block *block, Value v)
LogicalResult connectToMemory(ConversionPatternRewriter &rewriter, MemRefToMemoryAccessOp memRefOps, bool lsq)
LogicalResult addBranchOps(ConversionPatternRewriter &rewriter)
LogicalResult runPartialLowering(T &instance, LogicalResult(T::*memberFunc)(ConversionPatternRewriter &, TArgs2...), TArgs &...args)
LogicalResult postDataflowConvert(Operation *op)
Lowers the mlir operations into handshake that are not part of the dataflow conversion.
LogicalResult lowerRegion(HandshakeLowering &hl, bool sourceConstants, bool disableTaskPipelining, Value entryCtrl)
llvm::function_ref< LogicalResult(Region &, ConversionPatternRewriter &)> RegionLoweringFunc
void removeBasicBlocks(Region &r)
Remove basic blocks inside the given region.
LogicalResult partiallyLowerRegion(const RegionLoweringFunc &loweringFunc, MLIRContext *ctx, Region &r)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createInsertMergeBlocksPass()
std::unique_ptr< mlir::OperationPass< handshake::FuncOp > > createHandshakeCanonicalizePass()
mlir::LogicalResult insertMergeBlocks(mlir::Region &r, mlir::ConversionPatternRewriter &rewriter)
Insert additional blocks that serve as counterparts to the blocks that diverged the control flow.
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createCFToHandshakePass(bool sourceConstants=false, bool disableTaskPipelining=false)
std::unique_ptr< mlir::OperationPass< handshake::FuncOp > > createHandshakeRemoveBlockPass()
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createHandshakeAnalysisPass()