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 return failure();
36}
37
38LogicalResult UnwrapFIFOOp::mergeAndErase(UnwrapFIFOOp unwrap, WrapFIFOOp wrap,
39 PatternRewriter &rewriter) {
40 if (unwrap && wrap) {
41 rewriter.replaceOp(unwrap, {wrap.getData(), wrap.getEmpty()});
42 rewriter.replaceOp(wrap, {{}, unwrap.getRden()});
43 return success();
44 }
45 return failure();
46}
47LogicalResult UnwrapFIFOOp::canonicalize(UnwrapFIFOOp op,
48 PatternRewriter &rewriter) {
49 auto wrap = dyn_cast_or_null<WrapFIFOOp>(op.getChanInput().getDefiningOp());
50 if (succeeded(UnwrapFIFOOp::mergeAndErase(op, wrap, rewriter)))
51 return success();
52 return failure();
53}
54
55LogicalResult WrapFIFOOp::canonicalize(WrapFIFOOp op,
56 PatternRewriter &rewriter) {
57 // If the channel has no consumers but the rden signal does, replace rden
58 // with a constant false (not reading since there's no consumer).
59 if (op.getChanOutput().use_empty() && !op.getRden().use_empty()) {
60 auto falseConst =
61 hw::ConstantOp::create(rewriter, op.getLoc(), rewriter.getI1Type(), 0);
62 rewriter.replaceAllUsesWith(op.getRden(), falseConst);
63 rewriter.eraseOp(op);
64 return success();
65 }
66
67 // If the wrap has no users at all, just erase it.
68 if (op->use_empty()) {
69 rewriter.eraseOp(op);
70 return success();
71 }
72
73 // Existing wrap-unwrap canonicalization logic
74 if (!op.getChanOutput().hasOneUse())
75 return rewriter.notifyMatchFailure(
76 op, "channel output doesn't have exactly one use");
77 auto unwrap = dyn_cast_or_null<UnwrapFIFOOp>(
78 op.getChanOutput().getUses().begin()->getOwner());
79 if (succeeded(UnwrapFIFOOp::mergeAndErase(unwrap, op, rewriter)))
80 return success();
81 return rewriter.notifyMatchFailure(
82 op, "could not find corresponding unwrap for wrap");
83}
84
85//===----------------------------------------------------------------------===//
86// ValidOnly wrap / unwrap canonicalization.
87//===----------------------------------------------------------------------===//
88
89LogicalResult UnwrapValidOnlyOp::mergeAndErase(UnwrapValidOnlyOp unwrap,
90 WrapValidOnlyOp wrap,
91 PatternRewriter &rewriter) {
92 if (unwrap && wrap) {
93 rewriter.replaceOp(unwrap, {wrap.getRawInput(), wrap.getValid()});
94 rewriter.eraseOp(wrap);
95 return success();
96 }
97 return failure();
98}
99
100LogicalResult UnwrapValidOnlyOp::canonicalize(UnwrapValidOnlyOp op,
101 PatternRewriter &rewriter) {
102 auto wrap =
103 dyn_cast_or_null<WrapValidOnlyOp>(op.getChanInput().getDefiningOp());
104 if (succeeded(UnwrapValidOnlyOp::mergeAndErase(op, wrap, rewriter)))
105 return success();
106 return failure();
107}
108
109LogicalResult WrapValidOnlyOp::canonicalize(WrapValidOnlyOp op,
110 PatternRewriter &rewriter) {
111 // If the channel has no users, just erase.
112 if (op.getChanOutput().use_empty()) {
113 rewriter.eraseOp(op);
114 return success();
115 }
116
117 // If the sole consumer is an unwrap, merge and erase.
118 if (!op.getChanOutput().hasOneUse())
119 return rewriter.notifyMatchFailure(
120 op, "channel output doesn't have exactly one use");
121 auto unwrap = dyn_cast_or_null<UnwrapValidOnlyOp>(
122 op.getChanOutput().getUses().begin()->getOwner());
123 if (succeeded(UnwrapValidOnlyOp::mergeAndErase(unwrap, op, rewriter)))
124 return success();
125 return rewriter.notifyMatchFailure(
126 op, "could not find corresponding unwrap for wrap");
127}
128
129OpFoldResult WrapWindow::fold(FoldAdaptor) {
130 if (auto unwrap = dyn_cast_or_null<UnwrapWindow>(getFrame().getDefiningOp()))
131 return unwrap.getWindow();
132 return {};
133}
134LogicalResult WrapWindow::canonicalize(WrapWindow op,
135 PatternRewriter &rewriter) {
136 // Loop over all users and replace the frame of all UnwrapWindow users. Delete
137 // op if no users remain.
138 bool edited = false;
139 bool allUsersAreUnwraps = true;
140 for (auto &use : llvm::make_early_inc_range(op.getWindow().getUses())) {
141 if (auto unwrap = dyn_cast<UnwrapWindow>(use.getOwner())) {
142 rewriter.replaceOp(unwrap, op.getFrame());
143 edited = true;
144 } else {
145 allUsersAreUnwraps = false;
146 }
147 }
148 if (allUsersAreUnwraps || op.getWindow().getUses().empty()) {
149 rewriter.eraseOp(op);
150 edited = true;
151 }
152 return success(edited);
153}
154OpFoldResult UnwrapWindow::fold(FoldAdaptor) {
155 if (auto wrap = dyn_cast_or_null<WrapWindow>(getWindow().getDefiningOp()))
156 return wrap.getFrame();
157 return {};
158}
159
160LogicalResult PackBundleOp::canonicalize(PackBundleOp pack,
161 PatternRewriter &rewriter) {
162 Value bundle = pack.getBundle();
163 // This condition should be caught by the verifier, but we don't want to
164 // crash if we assume it since canonicalize can get run on IR in a broken
165 // state.
166 if (!bundle.hasOneUse())
167 return rewriter.notifyMatchFailure(pack,
168 "bundle has zero or more than one user");
169
170 // unpack(pack(x)) -> x
171 auto unpack = dyn_cast<UnpackBundleOp>(*bundle.getUsers().begin());
172 if (unpack) {
173 for (auto [a, b] :
174 llvm::zip_equal(pack.getToChannels(), unpack.getToChannels()))
175 rewriter.replaceAllUsesWith(b, a);
176 for (auto [a, b] :
177 llvm::zip_equal(unpack.getFromChannels(), pack.getFromChannels()))
178 rewriter.replaceAllUsesWith(b, a);
179 rewriter.eraseOp(unpack);
180 rewriter.eraseOp(pack);
181 return success();
182 }
183 return rewriter.notifyMatchFailure(pack,
184 "could not find corresponding unpack");
185}
186
187LogicalResult UnpackBundleOp::canonicalize(UnpackBundleOp unpack,
188 PatternRewriter &rewriter) {
189 Value bundle = unpack.getBundle();
190 // This condition should be caught by the verifier, but we don't want to
191 // crash if we assume it since canonicalize can get run on IR in a broken
192 // state.
193 if (!bundle.hasOneUse())
194 return rewriter.notifyMatchFailure(unpack,
195 "bundle has zero or more than one user");
196
197 // Reuse pack's canonicalizer.
198 auto pack = dyn_cast_or_null<PackBundleOp>(bundle.getDefiningOp());
199 if (pack)
200 return PackBundleOp::canonicalize(pack, rewriter);
201 return rewriter.notifyMatchFailure(unpack,
202 "could not find corresponding pack");
203}
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.