CIRCT  19.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 } // namespace
162 
163 //===----------------------------------------------------------------------===//
164 // Type emission patterns.
165 //===----------------------------------------------------------------------===//
166 
167 namespace {
168 /// Emit an emitc.opaque type by just printing the contained string without
169 /// quotation marks.
170 struct OpaqueTypeEmitter : TypeEmissionPattern<OpaqueType> {
171  void emitType(OpaqueType type, EmissionPrinter &p) override {
172  p << type.getValue();
173  }
174 };
175 
176 /// Emit an emitc.ptr type.
177 struct PointerTypeEmitter : TypeEmissionPattern<PointerType> {
178  void emitType(PointerType type, EmissionPrinter &p) override {
179  p.emitType(type.getPointee());
180  p << "*";
181  }
182 };
183 } // namespace
184 
185 namespace {
186 
187 /// Emit an emitc.opaque attribute by just printing the contained string without
188 /// quotation marks.
189 struct OpaqueAttrEmitter : AttrEmissionPattern<OpaqueAttr> {
190  void emitAttr(OpaqueAttr attr, EmissionPrinter &p) override {
191  p << attr.getValue();
192  }
193 };
194 
195 } // namespace
196 
197 //===----------------------------------------------------------------------===//
198 // Register Operation and Type emission patterns.
199 //===----------------------------------------------------------------------===//
200 
202  OpEmissionPatternSet &patterns, MLIRContext *context) {
203  patterns.add<IncludeEmitter, ApplyOpEmitter, CallOpEmitter, CastOpEmitter,
204  ConstantEmitter>(context);
205 }
206 
209  patterns.add<OpaqueTypeEmitter, PointerTypeEmitter>();
210 }
211 
214  patterns.add<OpaqueAttrEmitter>();
215 }
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
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.