CIRCT 23.0.0git
Loading...
Searching...
No Matches
SimplifyRefs.cpp
Go to the documentation of this file.
1//===- SimplifyRefs.cpp - moore.concat_ref and queue reference lowering -- ===//
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 defines the SimplifyRefs pass.
10// It has two purposes:
11// - To disassemble the moore.concat_ref. Which is tricky to lower
12// directly. For example, disassemble "{a, b} = c" onto "a = c[7:3]"
13// and "b = c[2:0]".
14// - To eliminate moore.dyn_queue_ref_element in the case where the reference
15// immediately has a value assigned via blocking assignment, replacing it with
16// moore.queue.set. Queue element references are tricky to lower into LLHD,
17// so it's best to get rid of them.
18//
19//===----------------------------------------------------------------------===//
20
23#include "mlir/Transforms/DialectConversion.h"
24
25namespace circt {
26namespace moore {
27#define GEN_PASS_DEF_SIMPLIFYREFS
28#include "circt/Dialect/Moore/MoorePasses.h.inc"
29} // namespace moore
30} // namespace circt
31
32using namespace circt;
33using namespace moore;
34using namespace mlir;
35
36namespace {
37
38// A helper function for collecting the non-concatRef operands of concatRef.
39static void collectOperands(Value operand, SmallVectorImpl<Value> &operands,
40 ConversionPatternRewriter &rewriter) {
41 if (auto concatRefOp = operand.getDefiningOp<ConcatRefOp>()) {
42 // Assuming the assignment is the only user, erase the op now.
43 if (std::distance(concatRefOp->getUsers().begin(),
44 concatRefOp->getUsers().end()) == 1) {
45 rewriter.eraseOp(concatRefOp);
46 }
47 for (auto nestedOperand : concatRefOp.getValues())
48 collectOperands(nestedOperand, operands, rewriter);
49
50 } else
51 operands.push_back(operand);
52}
53
54template <typename OpTy>
55struct ConcatRefLowering : public OpConversionPattern<OpTy> {
57 using OpAdaptor = typename OpTy::Adaptor;
58
59 LogicalResult
60 matchAndRewrite(OpTy op, OpAdaptor adaptor,
61 ConversionPatternRewriter &rewriter) const override {
62 // Use to collect the operands of concatRef.
63 SmallVector<Value, 4> operands;
64 collectOperands(op.getDst(), operands, rewriter);
65 auto srcWidth =
66 cast<UnpackedType>(op.getSrc().getType()).getBitSize().value();
67
68 // Disassemble assignments with the LHS is concatRef. And create new
69 // corresponding assignments using non-concatRef LHS.
70 for (auto operand : operands) {
71 auto type = cast<RefType>(operand.getType()).getNestedType();
72 auto width = type.getBitSize().value();
73
74 rewriter.setInsertionPoint(op);
75 // FIXME: Need to estimate whether the bits range is from large to
76 // small or vice versa. Like "logic [7:0] or [0:7]".
77
78 // Only able to correctly handle the situation like "[7:0]" now.
79 auto extract = ExtractOp::create(rewriter, op.getLoc(), type, op.getSrc(),
80 srcWidth - width);
81
82 // Update the real bit width of RHS of assignment. Like "c" the above
83 // description mentioned.
84 srcWidth = srcWidth - width;
85
86 OpTy::create(rewriter, op.getLoc(), operand, extract);
87 }
88 rewriter.eraseOp(op);
89 return success();
90 }
91};
92
93struct QueueRefLowering : public OpConversionPattern<DynQueueRefElementOp> {
94 using OpConversionPattern<DynQueueRefElementOp>::OpConversionPattern;
95
96 LogicalResult
97 matchAndRewrite(DynQueueRefElementOp op, OpAdaptor adaptor,
98 ConversionPatternRewriter &rewriter) const override {
99 // For now, we only support using a queue reference in the LHS of a blocking
100 // assignment op.
101 for (auto *consumer : op->getUsers()) {
102 if (isa<BlockingAssignOp>(consumer)) {
103
104 auto assignOp = cast<BlockingAssignOp>(consumer);
105 // Replace BlockingAssignOp with a queue.set operation to the index.
106 rewriter.setInsertionPoint(consumer);
107 moore::QueueSetOp::create(rewriter, op->getLoc(), op.getInput(),
108 op.getIndex(), assignOp.getSrc());
109
110 rewriter.eraseOp(assignOp);
111 } else {
112 return mlir::emitError(op.getLoc())
113 << "Queue element reference couldn't be reduced to setting the "
114 "value at an index: consuming op "
115 << consumer << " is not supported";
116 }
117 }
118
119 rewriter.eraseOp(op);
120
121 return success();
122 }
123};
124
125struct SimplifyRefsPass
126 : public circt::moore::impl::SimplifyRefsBase<SimplifyRefsPass> {
127 void runOnOperation() override;
128};
129
130} // namespace
131
132std::unique_ptr<mlir::Pass> circt::moore::createSimplifyRefsPass() {
133 return std::make_unique<SimplifyRefsPass>();
134}
135
136void SimplifyRefsPass::runOnOperation() {
137 MLIRContext &context = getContext();
138 ConversionTarget target(context);
139
140 target.addDynamicallyLegalOp<ContinuousAssignOp, BlockingAssignOp,
141 NonBlockingAssignOp>([](auto op) {
142 return !op->getOperand(0).template getDefiningOp<ConcatRefOp>();
143 });
144
145 target.addLegalDialect<MooreDialect>();
146 RewritePatternSet concatRefPatterns(&context);
147 concatRefPatterns.add<ConcatRefLowering<ContinuousAssignOp>,
148 ConcatRefLowering<BlockingAssignOp>,
149 ConcatRefLowering<NonBlockingAssignOp>>(&context);
150
151 if (failed(applyPartialConversion(getOperation(), target,
152 std::move(concatRefPatterns)))) {
153 signalPassFailure();
154 return;
155 }
156
157 // Once we have removed ConcatRefOps, attempt to rewrite any queue element
158 // references to queue.set
159 RewritePatternSet queueRefPatterns(&context);
160 target.addIllegalOp<DynQueueRefElementOp>();
161 queueRefPatterns.add<QueueRefLowering>(&context);
162 if (failed(applyPartialConversion(getOperation(), target,
163 std::move(queueRefPatterns))))
164 signalPassFailure();
165}
static std::unique_ptr< Context > context
std::unique_ptr< mlir::Pass > createSimplifyRefsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.