CIRCT 23.0.0git
Loading...
Searching...
No Matches
ESIFolds.cpp
Go to the documentation of this file.
1//===- ESIFolds.cpp - ESI op folders ----------------------------*- 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
10#include "circt/Support/LLVM.h"
11
12#include "mlir/IR/BuiltinAttributes.h"
13#include "mlir/IR/PatternMatch.h"
14
15using namespace circt;
16using namespace circt::esi;
17
18LogicalResult WrapValidReadyOp::canonicalize(WrapValidReadyOp op,
19 PatternRewriter &rewriter) {
20 // If the channel has no consumers but the ready signal does, replace ready
21 // with a constant true (always ready to accept data).
22 if (op.getChanOutput().use_empty() && !op.getReady().use_empty()) {
23 auto trueConst =
24 hw::ConstantOp::create(rewriter, op.getLoc(), rewriter.getI1Type(), 1);
25 rewriter.replaceAllUsesWith(op.getReady(), trueConst);
26 rewriter.eraseOp(op);
27 return success();
28 }
29
30 // If the wrap has no users at all, just erase it.
31 if (op->use_empty()) {
32 rewriter.eraseOp(op);
33 return success();
34 }
35
36 // If the sole consumer is an unwrap, merge and erase.
37 if (!op.getChanOutput().hasOneUse())
38 return rewriter.notifyMatchFailure(
39 op, "channel output doesn't have exactly one use");
40 auto unwrap = dyn_cast_or_null<UnwrapValidReadyOp>(
41 op.getChanOutput().getUses().begin()->getOwner());
42 if (succeeded(UnwrapValidReadyOp::mergeAndErase(unwrap, op, rewriter)))
43 return success();
44 return rewriter.notifyMatchFailure(
45 op, "could not find corresponding unwrap for wrap");
46}
47
48LogicalResult UnwrapValidReadyOp::mergeAndErase(UnwrapValidReadyOp unwrap,
49 WrapValidReadyOp wrap,
50 PatternRewriter &rewriter) {
51 // Only merge when the wrap's channel feeds nothing but this unwrap. Otherwise
52 // erasing the channel value (replacing it with null below) would corrupt the
53 // other users (e.g. a snoop op observing the same channel).
54 if (unwrap && wrap && wrap.getChanOutput().hasOneUse()) {
55 // Capture the ready operand before replacing `unwrap`, which erases it.
56 Value ready = unwrap.getReady();
57 rewriter.replaceOp(unwrap, {wrap.getRawInput(), wrap.getValid()});
58 rewriter.replaceOp(wrap, {{}, ready});
59 return success();
60 }
61 return failure();
62}
63
64LogicalResult UnwrapValidReadyOp::canonicalize(UnwrapValidReadyOp op,
65 PatternRewriter &rewriter) {
66 auto wrap =
67 dyn_cast_or_null<WrapValidReadyOp>(op.getChanInput().getDefiningOp());
68 if (succeeded(UnwrapValidReadyOp::mergeAndErase(op, wrap, rewriter)))
69 return success();
70 return failure();
71}
72
73LogicalResult UnwrapFIFOOp::mergeAndErase(UnwrapFIFOOp unwrap, WrapFIFOOp wrap,
74 PatternRewriter &rewriter) {
75 // Only merge when the wrap's channel feeds nothing but this unwrap.
76 if (unwrap && wrap && wrap.getChanOutput().hasOneUse()) {
77 // Capture the rden operand before replacing `unwrap`, which erases it.
78 Value rden = unwrap.getRden();
79 rewriter.replaceOp(unwrap, {wrap.getData(), wrap.getEmpty()});
80 rewriter.replaceOp(wrap, {{}, rden});
81 return success();
82 }
83 return failure();
84}
85LogicalResult UnwrapFIFOOp::canonicalize(UnwrapFIFOOp op,
86 PatternRewriter &rewriter) {
87 auto wrap = dyn_cast_or_null<WrapFIFOOp>(op.getChanInput().getDefiningOp());
88 if (succeeded(UnwrapFIFOOp::mergeAndErase(op, wrap, rewriter)))
89 return success();
90 return failure();
91}
92
93LogicalResult WrapFIFOOp::canonicalize(WrapFIFOOp op,
94 PatternRewriter &rewriter) {
95 // If the channel has no consumers but the rden signal does, replace rden
96 // with a constant false (not reading since there's no consumer).
97 if (op.getChanOutput().use_empty() && !op.getRden().use_empty()) {
98 auto falseConst =
99 hw::ConstantOp::create(rewriter, op.getLoc(), rewriter.getI1Type(), 0);
100 rewriter.replaceAllUsesWith(op.getRden(), falseConst);
101 rewriter.eraseOp(op);
102 return success();
103 }
104
105 // If the wrap has no users at all, just erase it.
106 if (op->use_empty()) {
107 rewriter.eraseOp(op);
108 return success();
109 }
110
111 // Existing wrap-unwrap canonicalization logic
112 if (!op.getChanOutput().hasOneUse())
113 return rewriter.notifyMatchFailure(
114 op, "channel output doesn't have exactly one use");
115 auto unwrap = dyn_cast_or_null<UnwrapFIFOOp>(
116 op.getChanOutput().getUses().begin()->getOwner());
117 if (succeeded(UnwrapFIFOOp::mergeAndErase(unwrap, op, rewriter)))
118 return success();
119 return rewriter.notifyMatchFailure(
120 op, "could not find corresponding unwrap for wrap");
121}
122
123//===----------------------------------------------------------------------===//
124// ValidOnly wrap / unwrap canonicalization.
125//===----------------------------------------------------------------------===//
126
127LogicalResult UnwrapValidOnlyOp::mergeAndErase(UnwrapValidOnlyOp unwrap,
128 WrapValidOnlyOp wrap,
129 PatternRewriter &rewriter) {
130 // Only merge when the wrap's channel feeds nothing but this unwrap.
131 if (unwrap && wrap && wrap.getChanOutput().hasOneUse()) {
132 rewriter.replaceOp(unwrap, {wrap.getRawInput(), wrap.getValid()});
133 rewriter.eraseOp(wrap);
134 return success();
135 }
136 return failure();
137}
138
139LogicalResult UnwrapValidOnlyOp::canonicalize(UnwrapValidOnlyOp op,
140 PatternRewriter &rewriter) {
141 auto wrap =
142 dyn_cast_or_null<WrapValidOnlyOp>(op.getChanInput().getDefiningOp());
143 if (succeeded(UnwrapValidOnlyOp::mergeAndErase(op, wrap, rewriter)))
144 return success();
145 return failure();
146}
147
148LogicalResult WrapValidOnlyOp::canonicalize(WrapValidOnlyOp op,
149 PatternRewriter &rewriter) {
150 // If the channel has no users, just erase.
151 if (op.getChanOutput().use_empty()) {
152 rewriter.eraseOp(op);
153 return success();
154 }
155
156 // If the sole consumer is an unwrap, merge and erase.
157 if (!op.getChanOutput().hasOneUse())
158 return rewriter.notifyMatchFailure(
159 op, "channel output doesn't have exactly one use");
160 auto unwrap = dyn_cast_or_null<UnwrapValidOnlyOp>(
161 op.getChanOutput().getUses().begin()->getOwner());
162 if (succeeded(UnwrapValidOnlyOp::mergeAndErase(unwrap, op, rewriter)))
163 return success();
164 return rewriter.notifyMatchFailure(
165 op, "could not find corresponding unwrap for wrap");
166}
167
168OpFoldResult WrapWindow::fold(FoldAdaptor) {
169 if (auto unwrap = dyn_cast_or_null<UnwrapWindow>(getFrame().getDefiningOp()))
170 return unwrap.getWindow();
171 return {};
172}
173LogicalResult WrapWindow::canonicalize(WrapWindow op,
174 PatternRewriter &rewriter) {
175 // Loop over all users and replace the frame of all UnwrapWindow users. Delete
176 // op if no users remain.
177 bool edited = false;
178 bool allUsersAreUnwraps = true;
179 for (auto &use : llvm::make_early_inc_range(op.getWindow().getUses())) {
180 if (auto unwrap = dyn_cast<UnwrapWindow>(use.getOwner())) {
181 rewriter.replaceOp(unwrap, op.getFrame());
182 edited = true;
183 } else {
184 allUsersAreUnwraps = false;
185 }
186 }
187 if (allUsersAreUnwraps || op.getWindow().getUses().empty()) {
188 rewriter.eraseOp(op);
189 edited = true;
190 }
191 return success(edited);
192}
193OpFoldResult UnwrapWindow::fold(FoldAdaptor) {
194 if (auto wrap = dyn_cast_or_null<WrapWindow>(getWindow().getDefiningOp()))
195 return wrap.getFrame();
196 return {};
197}
198
199LogicalResult PackBundleOp::canonicalize(PackBundleOp pack,
200 PatternRewriter &rewriter) {
201 Value bundle = pack.getBundle();
202 // This condition should be caught by the verifier, but we don't want to
203 // crash if we assume it since canonicalize can get run on IR in a broken
204 // state.
205 if (!bundle.hasOneUse())
206 return rewriter.notifyMatchFailure(pack,
207 "bundle has zero or more than one user");
208
209 // unpack(pack(x)) -> x
210 auto unpack = dyn_cast<UnpackBundleOp>(*bundle.getUsers().begin());
211 if (unpack) {
212 for (auto [a, b] :
213 llvm::zip_equal(pack.getToChannels(), unpack.getToChannels()))
214 rewriter.replaceAllUsesWith(b, a);
215 for (auto [a, b] :
216 llvm::zip_equal(unpack.getFromChannels(), pack.getFromChannels()))
217 rewriter.replaceAllUsesWith(b, a);
218 rewriter.eraseOp(unpack);
219 rewriter.eraseOp(pack);
220 return success();
221 }
222 return rewriter.notifyMatchFailure(pack,
223 "could not find corresponding unpack");
224}
225
226LogicalResult UnpackBundleOp::canonicalize(UnpackBundleOp unpack,
227 PatternRewriter &rewriter) {
228 Value bundle = unpack.getBundle();
229 // This condition should be caught by the verifier, but we don't want to
230 // crash if we assume it since canonicalize can get run on IR in a broken
231 // state.
232 if (!bundle.hasOneUse())
233 return rewriter.notifyMatchFailure(unpack,
234 "bundle has zero or more than one user");
235
236 // Reuse pack's canonicalizer.
237 auto pack = dyn_cast_or_null<PackBundleOp>(bundle.getDefiningOp());
238 if (pack)
239 return PackBundleOp::canonicalize(pack, rewriter);
240 return rewriter.notifyMatchFailure(unpack,
241 "could not find corresponding pack");
242}
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Definition OM.cpp:111
create(data_type, value)
Definition hw.py:433
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.