CIRCT 20.0.0git
Loading...
Searching...
No Matches
EmitCEmissionPatterns.cpp
Go to the documentation of this file.
1//===- EmitCEmissionPatterns.cpp - EmitC Dialect Emission Patterns --------===//
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 implements the emission patterns for the emitc dialect.
10//
11//===----------------------------------------------------------------------===//
12
14#include "../EmissionPrinter.h"
15#include "mlir/Dialect/EmitC/IR/EmitC.h"
16#include "llvm/ADT/SmallString.h"
17
18using namespace mlir::emitc;
19using namespace circt;
20using namespace circt::ExportSystemC;
21
22//===----------------------------------------------------------------------===//
23// Operation emission patterns.
24//===----------------------------------------------------------------------===//
25
26namespace {
27/// Emit emitc.include operations.
28struct IncludeEmitter : OpEmissionPattern<IncludeOp> {
30
31 void emitStatement(IncludeOp op, EmissionPrinter &p) override {
32 p << "#include " << (op.getIsStandardInclude() ? "<" : "\"")
33 << op.getInclude() << (op.getIsStandardInclude() ? ">" : "\"") << "\n";
34 }
35};
36
37/// Emit emitc.apply operations.
38struct ApplyOpEmitter : OpEmissionPattern<ApplyOp> {
40
41 MatchResult matchInlinable(Value value) override {
42 if (value.getDefiningOp<ApplyOp>()) {
43 // We would need to check the 'applicableOperator' to select the
44 // precedence to return. However, since the dereference and address_of
45 // operators have the same precedence, we can omit that (for better
46 // performance).
48 }
49 return {};
50 }
51
52 void emitInlined(Value value, EmissionPrinter &p) override {
53 auto applyOp = value.getDefiningOp<ApplyOp>();
54 p << applyOp.getApplicableOperator();
55 p.getInlinable(applyOp.getOperand())
56 .emitWithParensOnLowerPrecedence(Precedence::ADDRESS_OF);
57 }
58};
59
60/// Emit emitc.call operations. Only calls with 0 or 1 results are supported.
61/// Calls with no result are emitted as statements whereas calls with exactly
62/// one result are always inlined no matter whether it is a pure function or has
63/// side effects. To make sure that calls with side effects are not reordered
64/// with interferring operations, a pre-pass has to emit VariableOp operations
65/// with the result of the call as initial value.
66class CallOpEmitter : public OpEmissionPattern<CallOpaqueOp> {
67public:
69
70 MatchResult matchInlinable(Value value) override {
71 if (auto callOp = value.getDefiningOp<CallOpaqueOp>()) {
72 // TODO: template arguments not supported for now.
73 if (callOp->getNumResults() == 1 && !callOp.getTemplateArgs())
75 }
76 return {};
77 }
78
79 void emitInlined(Value value, EmissionPrinter &p) override {
80 printCallOp(value.getDefiningOp<CallOpaqueOp>(), p);
81 }
82
83 bool matchStatement(Operation *op) override {
84 // TODO: template arguments not supported for now.
85 if (auto callOp = dyn_cast<CallOpaqueOp>(op))
86 return callOp->getNumResults() <= 1 && !callOp.getTemplateArgs();
87 return false;
88 }
89
90 void emitStatement(CallOpaqueOp callOp, EmissionPrinter &p) override {
91 if (callOp->getNumResults() != 0)
92 return;
93
94 printCallOp(callOp, p);
95 p << ";\n";
96 }
97
98private:
99 void printCallOp(CallOpaqueOp callOp, EmissionPrinter &p) {
100 p << callOp.getCallee();
101
102 p << "(";
103
104 if (!callOp.getArgs()) {
105 llvm::interleaveComma(callOp.getOperands(), p, [&](Value operand) {
106 p.getInlinable(operand).emitWithParensOnLowerPrecedence(
107 Precedence::COMMA);
108 });
109 } else {
110 llvm::interleaveComma(callOp.getArgs().value(), p, [&](Attribute attr) {
111 if (auto idx = dyn_cast<IntegerAttr>(attr)) {
112 if (isa<IndexType>(idx.getType())) {
113 p.getInlinable(callOp.getOperands()[idx.getInt()])
114 .emitWithParensOnLowerPrecedence(Precedence::COMMA);
115 return;
116 }
117 }
118
119 p.emitAttr(attr);
120 });
121 }
122
123 p << ")";
124 }
125};
126
127/// Emit emitc.cast operations.
128struct CastOpEmitter : OpEmissionPattern<CastOp> {
130
131 MatchResult matchInlinable(Value value) override {
132 if (value.getDefiningOp<CastOp>())
133 return Precedence::CAST;
134 return {};
135 }
136
137 void emitInlined(Value value, EmissionPrinter &p) override {
138 auto castOp = value.getDefiningOp<CastOp>();
139 p << "(";
140 p.emitType(castOp.getDest().getType());
141 p << ") ";
142 p.getInlinable(castOp.getSource())
143 .emitWithParensOnLowerPrecedence(Precedence::CAST);
144 }
145};
146
147/// Emit emitc.constant operations.
148struct ConstantEmitter : OpEmissionPattern<ConstantOp> {
150
151 MatchResult matchInlinable(Value value) override {
152 if (value.getDefiningOp<ConstantOp>())
153 return Precedence::LIT;
154 return {};
155 }
156
157 void emitInlined(Value value, EmissionPrinter &p) override {
158 p.emitAttr(value.getDefiningOp<ConstantOp>().getValue());
159 }
160};
161
162/// Emit an emitc.variable operation.
163struct VariableEmitter : OpEmissionPattern<VariableOp> {
165
166 MatchResult matchInlinable(Value value) override {
167 if (auto varOp = value.getDefiningOp<VariableOp>()) {
168 if (!varOp->getAttrOfType<StringAttr>("name"))
169 return {};
170 return Precedence::VAR;
171 }
172 return {};
173 }
174
175 void emitInlined(Value value, EmissionPrinter &p) override {
176 p << value.getDefiningOp()->getAttrOfType<StringAttr>("name").getValue();
177 }
178
179 void emitStatement(VariableOp op, EmissionPrinter &p) override {
180 p.emitType(op.getResult().getType());
181 p << " " << op->getAttrOfType<StringAttr>("name").getValue();
182
183 if (op.getValue()) {
184 p << " = ";
185 p.emitAttr(op.getValue());
186 }
187
188 p << ";\n";
189 }
190};
191} // namespace
192
193//===----------------------------------------------------------------------===//
194// Type emission patterns.
195//===----------------------------------------------------------------------===//
196
197namespace {
198/// Emit an emitc.opaque type by just printing the contained string without
199/// quotation marks.
200struct OpaqueTypeEmitter : TypeEmissionPattern<OpaqueType> {
201 void emitType(OpaqueType type, EmissionPrinter &p) override {
202 p << type.getValue();
203 }
204};
205
206/// Emit an emitc.ptr type.
207struct PointerTypeEmitter : TypeEmissionPattern<PointerType> {
208 void emitType(PointerType type, EmissionPrinter &p) override {
209 p.emitType(type.getPointee());
210 p << "*";
211 }
212};
213
214/// Emit an emitc.ptr type.
215struct LValueTypeEmitter : TypeEmissionPattern<LValueType> {
216 void emitType(LValueType type, EmissionPrinter &p) override {
217 p.emitType(type.getValueType());
218 }
219};
220} // namespace
221
222namespace {
223
224/// Emit an emitc.opaque attribute by just printing the contained string without
225/// quotation marks.
226struct OpaqueAttrEmitter : AttrEmissionPattern<OpaqueAttr> {
227 void emitAttr(OpaqueAttr attr, EmissionPrinter &p) override {
228 p << attr.getValue();
229 }
230};
231
232} // namespace
233
234//===----------------------------------------------------------------------===//
235// Register Operation and Type emission patterns.
236//===----------------------------------------------------------------------===//
237
239 OpEmissionPatternSet &patterns, MLIRContext *context) {
240 patterns.add<IncludeEmitter, ApplyOpEmitter, CallOpEmitter, CastOpEmitter,
241 ConstantEmitter, VariableEmitter>(context);
242}
243
246 patterns.add<OpaqueTypeEmitter, PointerTypeEmitter, LValueTypeEmitter>();
247}
248
This class collects a set of emission patterns with base type 'PatternTy'.
This is intended to be the driving class for all pattern-based IR emission.
InlineEmitter getInlinable(Value value)
Emit the expression represented by the given value to the ostream associated with this printer accord...
void emitAttr(Attribute attr)
Emit the given attribute to the ostream associated with this printer according to the emission patter...
void emitType(Type type)
Emit the given type to the ostream associated with this printer according to the emission patterns re...
This class allows a pattern's match function for inlining to pass its result's precedence to the patt...
void populateEmitCOpEmitters(OpEmissionPatternSet &patterns, MLIRContext *context)
Register EmitC operation emission patterns.
void populateEmitCTypeEmitters(TypeEmissionPatternSet &patterns)
Register EmitC type emission patterns.
void populateEmitCAttrEmitters(AttrEmissionPatternSet &patterns)
Register EmitC attribute emission patterns.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Emit a systemc.cpp.variable operation.
This is a convenience class providing default implementations for attribute emission patterns.
void emitAttr(Attribute attr, EmissionPrinter &p) final
Emit the given attribute to the emission printer.
This is a convenience class providing default implementations for operation emission patterns.
void emitInlined(mlir::Value value, EmissionPrinter &p) override
Emit the expression for the given value.
bool matchStatement(mlir::Operation *op) override
Checks if this pattern is applicable to the given operation for statement emission.
void emitStatement(mlir::Operation *op, EmissionPrinter &p) final
Emit zero or more statements for the given operation.
MatchResult matchInlinable(Value value) override
Checks if this pattern is applicable to the given value to emit an inlinable expression.
This is a convenience class providing default implementations for type emission patterns.
void emitType(Type type, EmissionPrinter &p) final
Emit the given type to the emission printer.