CIRCT 23.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.address_of operations.
38struct AddressOfOpEmitter : OpEmissionPattern<AddressOfOp> {
40
41 MatchResult matchInlinable(Value value) override {
42 if (value.getDefiningOp<AddressOfOp>())
44 return {};
45 }
46
47 void emitInlined(Value value, EmissionPrinter &p) override {
48 auto addressOfOp = value.getDefiningOp<AddressOfOp>();
49 p << "&";
50 p.getInlinable(addressOfOp.getReference())
51 .emitWithParensOnLowerPrecedence(Precedence::ADDRESS_OF);
52 }
53};
54
55/// Emit emitc.dereference operations.
56struct DereferenceOpEmitter : OpEmissionPattern<DereferenceOp> {
58
59 MatchResult matchInlinable(Value value) override {
60 // `dereference` has the same precedence as `address_of`.
61 if (value.getDefiningOp<DereferenceOp>())
63 return {};
64 }
65
66 void emitInlined(Value value, EmissionPrinter &p) override {
67 auto dereferenceOp = value.getDefiningOp<DereferenceOp>();
68 p << "*";
69 p.getInlinable(dereferenceOp.getPointer())
70 .emitWithParensOnLowerPrecedence(Precedence::ADDRESS_OF);
71 }
72};
73
74/// Emit emitc.call operations. Only calls with 0 or 1 results are supported.
75/// Calls with no result are emitted as statements whereas calls with exactly
76/// one result are always inlined no matter whether it is a pure function or has
77/// side effects. To make sure that calls with side effects are not reordered
78/// with interferring operations, a pre-pass has to emit VariableOp operations
79/// with the result of the call as initial value.
80class CallOpEmitter : public OpEmissionPattern<CallOpaqueOp> {
81public:
83
84 MatchResult matchInlinable(Value value) override {
85 if (auto callOp = value.getDefiningOp<CallOpaqueOp>()) {
86 // TODO: template arguments not supported for now.
87 if (callOp->getNumResults() == 1 && !callOp.getTemplateArgs())
89 }
90 return {};
91 }
92
93 void emitInlined(Value value, EmissionPrinter &p) override {
94 printCallOp(value.getDefiningOp<CallOpaqueOp>(), p);
95 }
96
97 bool matchStatement(Operation *op) override {
98 // TODO: template arguments not supported for now.
99 if (auto callOp = dyn_cast<CallOpaqueOp>(op))
100 return callOp->getNumResults() <= 1 && !callOp.getTemplateArgs();
101 return false;
102 }
103
104 void emitStatement(CallOpaqueOp callOp, EmissionPrinter &p) override {
105 if (callOp->getNumResults() != 0)
106 return;
107
108 printCallOp(callOp, p);
109 p << ";\n";
110 }
111
112private:
113 void printCallOp(CallOpaqueOp callOp, EmissionPrinter &p) {
114 p << callOp.getCallee();
115
116 p << "(";
117
118 if (!callOp.getArgs()) {
119 llvm::interleaveComma(callOp.getOperands(), p, [&](Value operand) {
120 p.getInlinable(operand).emitWithParensOnLowerPrecedence(
121 Precedence::COMMA);
122 });
123 } else {
124 llvm::interleaveComma(callOp.getArgs().value(), p, [&](Attribute attr) {
125 if (auto idx = dyn_cast<IntegerAttr>(attr)) {
126 if (isa<IndexType>(idx.getType())) {
127 p.getInlinable(callOp.getOperands()[idx.getInt()])
128 .emitWithParensOnLowerPrecedence(Precedence::COMMA);
129 return;
130 }
131 }
132
133 p.emitAttr(attr);
134 });
135 }
136
137 p << ")";
138 }
139};
140
141/// Emit emitc.cast operations.
142struct CastOpEmitter : OpEmissionPattern<CastOp> {
144
145 MatchResult matchInlinable(Value value) override {
146 if (value.getDefiningOp<CastOp>())
147 return Precedence::CAST;
148 return {};
149 }
150
151 void emitInlined(Value value, EmissionPrinter &p) override {
152 auto castOp = value.getDefiningOp<CastOp>();
153 p << "(";
154 p.emitType(castOp.getDest().getType());
155 p << ") ";
156 p.getInlinable(castOp.getSource())
157 .emitWithParensOnLowerPrecedence(Precedence::CAST);
158 }
159};
160
161/// Emit emitc.constant operations.
162struct ConstantEmitter : OpEmissionPattern<ConstantOp> {
164
165 MatchResult matchInlinable(Value value) override {
166 if (value.getDefiningOp<ConstantOp>())
167 return Precedence::LIT;
168 return {};
169 }
170
171 void emitInlined(Value value, EmissionPrinter &p) override {
172 p.emitAttr(value.getDefiningOp<ConstantOp>().getValue());
173 }
174};
175
176/// Emit an emitc.variable operation.
177struct VariableEmitter : OpEmissionPattern<VariableOp> {
179
180 MatchResult matchInlinable(Value value) override {
181 if (auto varOp = value.getDefiningOp<VariableOp>()) {
182 if (!varOp->getAttrOfType<StringAttr>("name"))
183 return {};
184 return Precedence::VAR;
185 }
186 return {};
187 }
188
189 void emitInlined(Value value, EmissionPrinter &p) override {
190 p << value.getDefiningOp()->getAttrOfType<StringAttr>("name").getValue();
191 }
192
193 void emitStatement(VariableOp op, EmissionPrinter &p) override {
194 p.emitType(op.getResult().getType());
195 p << " " << op->getAttrOfType<StringAttr>("name").getValue();
196
197 if (op.getValue()) {
198 p << " = ";
199 p.emitAttr(op.getValue());
200 }
201
202 p << ";\n";
203 }
204};
205} // namespace
206
207//===----------------------------------------------------------------------===//
208// Type emission patterns.
209//===----------------------------------------------------------------------===//
210
211namespace {
212/// Emit an emitc.opaque type by just printing the contained string without
213/// quotation marks.
214struct OpaqueTypeEmitter : TypeEmissionPattern<OpaqueType> {
215 void emitType(OpaqueType type, EmissionPrinter &p) override {
216 p << type.getValue();
217 }
218};
219
220/// Emit an emitc.ptr type.
221struct PointerTypeEmitter : TypeEmissionPattern<PointerType> {
222 void emitType(PointerType type, EmissionPrinter &p) override {
223 p.emitType(type.getPointee());
224 p << "*";
225 }
226};
227
228/// Emit an emitc.ptr type.
229struct LValueTypeEmitter : TypeEmissionPattern<LValueType> {
230 void emitType(LValueType type, EmissionPrinter &p) override {
231 p.emitType(type.getValueType());
232 }
233};
234} // namespace
235
236namespace {
237
238/// Emit an emitc.opaque attribute by just printing the contained string without
239/// quotation marks.
240struct OpaqueAttrEmitter : AttrEmissionPattern<OpaqueAttr> {
241 void emitAttr(OpaqueAttr attr, EmissionPrinter &p) override {
242 p << attr.getValue();
243 }
244};
245
246} // namespace
247
248//===----------------------------------------------------------------------===//
249// Register Operation and Type emission patterns.
250//===----------------------------------------------------------------------===//
251
253 OpEmissionPatternSet &patterns, MLIRContext *context) {
254 patterns.add<IncludeEmitter, AddressOfOpEmitter, DereferenceOpEmitter,
255 CallOpEmitter, CastOpEmitter, ConstantEmitter, VariableEmitter>(
256 context);
257}
258
261 patterns.add<OpaqueTypeEmitter, PointerTypeEmitter, LValueTypeEmitter>();
262}
263
static std::unique_ptr< Context > context
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.