CIRCT  20.0.0git
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 
13 #include "EmitCEmissionPatterns.h"
14 #include "../EmissionPrinter.h"
15 #include "mlir/Dialect/EmitC/IR/EmitC.h"
16 #include "llvm/ADT/SmallString.h"
17 
18 using namespace mlir::emitc;
19 using namespace circt;
20 using namespace circt::ExportSystemC;
21 
22 //===----------------------------------------------------------------------===//
23 // Operation emission patterns.
24 //===----------------------------------------------------------------------===//
25 
26 namespace {
27 /// Emit emitc.include operations.
28 struct IncludeEmitter : OpEmissionPattern<IncludeOp> {
29  using OpEmissionPattern::OpEmissionPattern;
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.
38 struct ApplyOpEmitter : OpEmissionPattern<ApplyOp> {
39  using OpEmissionPattern::OpEmissionPattern;
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).
47  return Precedence::ADDRESS_OF;
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.
66 class CallOpEmitter : public OpEmissionPattern<CallOpaqueOp> {
67 public:
68  using OpEmissionPattern::OpEmissionPattern;
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())
74  return Precedence::FUNCTION_CALL;
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 
98 private:
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.
128 struct CastOpEmitter : OpEmissionPattern<CastOp> {
129  using OpEmissionPattern::OpEmissionPattern;
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.
148 struct ConstantEmitter : OpEmissionPattern<ConstantOp> {
149  using OpEmissionPattern::OpEmissionPattern;
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.
163 struct VariableEmitter : OpEmissionPattern<VariableOp> {
164  using OpEmissionPattern::OpEmissionPattern;
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 
197 namespace {
198 /// Emit an emitc.opaque type by just printing the contained string without
199 /// quotation marks.
200 struct OpaqueTypeEmitter : TypeEmissionPattern<OpaqueType> {
201  void emitType(OpaqueType type, EmissionPrinter &p) override {
202  p << type.getValue();
203  }
204 };
205 
206 /// Emit an emitc.ptr type.
207 struct 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.
215 struct LValueTypeEmitter : TypeEmissionPattern<LValueType> {
216  void emitType(LValueType type, EmissionPrinter &p) override {
217  p.emitType(type.getValueType());
218  }
219 };
220 } // namespace
221 
222 namespace {
223 
224 /// Emit an emitc.opaque attribute by just printing the contained string without
225 /// quotation marks.
226 struct 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 
251  patterns.add<OpaqueAttrEmitter>();
252 }
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.
Definition: DebugAnalysis.h:21
Emit a systemc.cpp.variable operation.
This is a convenience class providing default implementations for attribute emission patterns.
This is a convenience class providing default implementations for operation emission patterns.
This is a convenience class providing default implementations for type emission patterns.