CIRCT 20.0.0git
Loading...
Searching...
No Matches
SystemCEmissionPatterns.cpp
Go to the documentation of this file.
1//===- SystemCEmissionPatterns.cpp - SystemC 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 systemc dialect.
10//
11//===----------------------------------------------------------------------===//
12
14#include "../EmissionPrinter.h"
16
17using namespace circt;
18using namespace circt::systemc;
19using namespace circt::ExportSystemC;
20
21//===----------------------------------------------------------------------===//
22// Operation emission patterns.
23//===----------------------------------------------------------------------===//
24
25namespace {
26/// Emit a SystemC module using the SC_MODULE macro and emit all ports as fields
27/// of the module. Users of the ports request an expression to be inlined and we
28/// simply return the name of the port.
29struct SCModuleEmitter : OpEmissionPattern<SCModuleOp> {
31 MatchResult matchInlinable(Value value) override {
32 if (isa<BlockArgument>(value) &&
33 value.getParentRegion()->getParentOfType<SCModuleOp>())
34 return Precedence::VAR;
35 return {};
36 }
37
38 void emitInlined(Value value, EmissionPrinter &p) override {
39 auto module = value.getParentRegion()->getParentOfType<SCModuleOp>();
40 for (size_t i = 0, e = module.getNumArguments(); i < e; ++i) {
41 if (module.getArgument(i) == value) {
42 p << cast<StringAttr>(module.getPortNames()[i]).getValue();
43 return;
44 }
45 }
46 }
47
48 void emitStatement(SCModuleOp module, EmissionPrinter &p) override {
49 // Emit a newline at the start to ensure an empty line before the module for
50 // better readability.
51 p << "\nSC_MODULE(" << module.getModuleName() << ") ";
52 auto scope = p.getOstream().scope("{\n", "};\n");
53 for (size_t i = 0, e = module.getNumArguments(); i < e; ++i) {
54 p.emitType(module.getArgument(i).getType());
55
56 auto portName = cast<StringAttr>(module.getPortNames()[i]).getValue();
57 p << " " << portName << ";\n";
58 }
59
60 p.emitRegion(module.getRegion(), scope);
61 }
62};
63
64/// Emit a systemc.signal.write operation by using the explicit 'write' member
65/// function of the signal and port classes.
66struct SignalWriteEmitter : OpEmissionPattern<SignalWriteOp> {
68
69 void emitStatement(SignalWriteOp op, EmissionPrinter &p) override {
70 p.getInlinable(op.getDest()).emit();
71 p << ".write(";
72 p.getInlinable(op.getSrc()).emit();
73 p << ");\n";
74 }
75};
76
77/// Emit a systemc.signal.read operation by using the explicit 'read' member
78/// function of the signal and port classes.
79struct SignalReadEmitter : OpEmissionPattern<SignalReadOp> {
81
82 MatchResult matchInlinable(Value value) override {
83 if (value.getDefiningOp<SignalReadOp>())
85 return {};
86 }
87
88 void emitInlined(Value value, EmissionPrinter &p) override {
89 p.getInlinable(value.getDefiningOp<SignalReadOp>().getInput()).emit();
90 p << ".read()";
91 }
92};
93
94/// Emit a systemc.cpp.new operation.
95struct NewEmitter : OpEmissionPattern<NewOp> {
97
98 MatchResult matchInlinable(Value value) override {
99 if (value.getDefiningOp<NewOp>())
100 return Precedence::NEW;
101 return {};
102 }
103
104 void emitInlined(Value value, EmissionPrinter &p) override {
105 p << "new ";
106 p.emitType(cast<mlir::emitc::PointerType>(value.getType()).getPointee());
107
108 auto newOp = value.getDefiningOp<NewOp>();
109 if (newOp.getArgs().empty())
110 return;
111
112 p << "(";
113 llvm::interleaveComma(newOp.getArgs(), p, [&](Value arg) {
114 p.getInlinable(arg).emitWithParensOnLowerPrecedence(Precedence::COMMA);
115 });
116 p << ")";
117 }
118};
119
120/// Emit a systemc.ctor operation by using the SC_CTOR macro.
121struct CtorEmitter : OpEmissionPattern<CtorOp> {
123
124 void emitStatement(CtorOp op, EmissionPrinter &p) override {
125 // Emit a new line before the SC_CTOR to ensure an empty line for better
126 // readability.
127 p << "\nSC_CTOR(" << op->getParentOfType<SCModuleOp>().getModuleName()
128 << ") ";
129 p.emitRegion(op.getBody());
130 }
131};
132
133/// Emit a systemc.cpp.destructor operation.
134struct DestructorEmitter : OpEmissionPattern<DestructorOp> {
136
137 void emitStatement(DestructorOp op, EmissionPrinter &p) override {
138 // Emit a new line before the destructor to ensure an empty line for better
139 // readability.
140 // TODO: the 'override' keyword is hardcoded here because the destructor can
141 // only be inside a class inheriting from 'sc_module', if we ever support
142 // custom classes the override should probably be a unitAttr on the
143 // destructor operation.
144 p << "\n~" << op->getParentOfType<SCModuleOp>().getModuleName()
145 << "() override ";
146 p.emitRegion(op.getBody());
147 }
148};
149
150/// Emit a systemc.func operation.
151struct SCFuncEmitter : OpEmissionPattern<SCFuncOp> {
153
154 MatchResult matchInlinable(Value value) override {
155 if (value.getDefiningOp<SCFuncOp>())
156 return Precedence::VAR;
157 return {};
158 }
159
160 void emitInlined(Value value, EmissionPrinter &p) override {
161 p << value.getDefiningOp<SCFuncOp>().getName();
162 }
163
164 void emitStatement(SCFuncOp op, EmissionPrinter &p) override {
165 // Emit a new line before the member function to ensure an empty line for
166 // better readability.
167 p << "\nvoid " << op.getName() << "() ";
168 p.emitRegion(op.getBody());
169 }
170};
171
172/// Emit a systemc.method operation by using the SC_METHOD macro.
173struct MethodEmitter : OpEmissionPattern<MethodOp> {
175
176 void emitStatement(MethodOp op, EmissionPrinter &p) override {
177 p << "SC_METHOD(";
178 p.getInlinable(op.getFuncHandle()).emit();
179 p << ");\n";
180 }
181};
182
183/// Emit a systemc.sensitive operation by using the 'sensitive' data member;
184struct SensitiveEmitter : OpEmissionPattern<SensitiveOp> {
186
187 void emitStatement(SensitiveOp op, EmissionPrinter &p) override {
188 if (op.getSensitivities().empty())
189 return;
190
191 p << "sensitive << ";
192 llvm::interleave(
193 op.getSensitivities(), p,
194 [&](Value sensitive) {
195 p.getInlinable(sensitive).emitWithParensOnLowerPrecedence(
196 Precedence::SHL);
197 },
198 " << ");
199 p << ";\n";
200 }
201};
202
203/// Emit a systemc.thread operation by using the SC_THREAD macro.
204struct ThreadEmitter : OpEmissionPattern<ThreadOp> {
206
207 void emitStatement(ThreadOp op, EmissionPrinter &p) override {
208 p << "SC_THREAD(";
209 p.getInlinable(op.getFuncHandle()).emit();
210 p << ");\n";
211 }
212};
213
214/// Emit a systemc.cpp.delete operation.
215struct DeleteEmitter : OpEmissionPattern<DeleteOp> {
217
218 void emitStatement(DeleteOp op, EmissionPrinter &p) override {
219 p << "delete ";
220 p.getInlinable(op.getPointer())
221 .emitWithParensOnLowerPrecedence(Precedence::DELETE);
222 p << ";\n";
223 }
224};
225
226/// Emit a systemc.signal operation.
227struct SignalEmitter : OpEmissionPattern<SignalOp> {
229
230 MatchResult matchInlinable(Value value) override {
231 if (llvm::isa_and_nonnull<SignalOp>(value.getDefiningOp()))
232 return Precedence::VAR;
233 return {};
234 }
235
236 void emitInlined(Value value, EmissionPrinter &p) override {
237 p << value.getDefiningOp<SignalOp>().getName();
238 }
239
240 void emitStatement(SignalOp op, EmissionPrinter &p) override {
241 p.emitType(op.getSignal().getType());
242 p << " ";
243
244 if (op.getNamed()) {
245 // This style of emitting SC_NAMED requires the printed code to be
246 // compiled with at least C++11.
247 p << "SC_NAMED(" << op.getName() << ");\n";
248 return;
249 }
250
251 p << op.getName() << ";\n";
252 }
253};
254
255/// Emit a systemc.instance.decl operation.
256struct InstanceDeclEmitter : OpEmissionPattern<InstanceDeclOp> {
258
259 MatchResult matchInlinable(Value value) override {
260 if (value.getDefiningOp<InstanceDeclOp>())
261 return Precedence::VAR;
262 return {};
263 }
264
265 void emitInlined(Value value, EmissionPrinter &p) override {
266 p << value.getDefiningOp<InstanceDeclOp>().getName();
267 }
268
269 void emitStatement(InstanceDeclOp op, EmissionPrinter &p) override {
270 p.emitType(op.getInstanceType());
271 p << " " << op.getName() << ";\n";
272 }
273};
274} // namespace
275
276/// Emit a systemc.instance.bind_port operation using the operator() rather than
277/// .bind() variant.
278struct BindPortEmitter : OpEmissionPattern<BindPortOp> {
280
281 void emitStatement(BindPortOp op, EmissionPrinter &p) override {
282 p.getInlinable(op.getInstance())
283 .emitWithParensOnLowerPrecedence(Precedence::MEMBER_ACCESS);
284
285 p << "." << op.getPortName() << "(";
286 p.getInlinable(op.getChannel()).emit();
287 p << ");\n";
288 }
289};
290
291/// Emit a systemc.cpp.member_access operation.
292struct MemberAccessEmitter : OpEmissionPattern<MemberAccessOp> {
294
295 MatchResult matchInlinable(Value value) override {
296 if (value.getDefiningOp<MemberAccessOp>())
297 return Precedence::MEMBER_ACCESS;
298 return {};
299 }
300
301 void emitInlined(Value value, EmissionPrinter &p) override {
302 auto op = value.getDefiningOp<MemberAccessOp>();
303 p.getInlinable(op.getObject())
304 .emitWithParensOnLowerPrecedence(Precedence::MEMBER_ACCESS);
305
306 if (op.getAccessKind() == MemberAccessKind::Arrow)
307 p << "->";
308 else if (op.getAccessKind() == MemberAccessKind::Dot)
309 p << ".";
310 else
311 p.emitError(op, "member access kind not implemented");
312
313 p << op.getMemberName();
314 }
315};
316
317/// Emit a systemc.cpp.assign operation.
320
321 void emitStatement(AssignOp op, EmissionPrinter &p) override {
322 p.getInlinable(op.getDest())
323 .emitWithParensOnLowerPrecedence(Precedence::ASSIGN);
324 p << " = ";
325 p.getInlinable(op.getSource())
326 .emitWithParensOnLowerPrecedence(Precedence::ASSIGN);
327 p << ";\n";
328 }
329};
330
331/// Emit a systemc.cpp.variable operation.
332struct VariableEmitter : OpEmissionPattern<VariableOp> {
334
335 MatchResult matchInlinable(Value value) override {
336 if (value.getDefiningOp<VariableOp>())
337 return Precedence::VAR;
338 return {};
339 }
340
341 void emitInlined(Value value, EmissionPrinter &p) override {
342 p << value.getDefiningOp<VariableOp>().getName();
343 }
344
345 void emitStatement(VariableOp op, EmissionPrinter &p) override {
346 p.emitType(op.getVariable().getType());
347 p << " " << op.getName();
348
349 if (op.getInit()) {
350 p << " = ";
351 p.getInlinable(op.getInit())
352 .emitWithParensOnLowerPrecedence(Precedence::ASSIGN);
353 }
354
355 p << ";\n";
356 }
357};
358
359/// Emit a systemc.cpp.func function. Users of the function arguments request an
360/// expression to be inlined and we simply return the name of the argument. This
361/// name has to be passed to this emission pattern via an array of strings
362/// attribute called 'argNames' because the emitter cannot do any name uniquing
363/// as it just emits the IR statement by statement. However, relying on an
364/// attribute for the argument names also has the advantage that the names
365/// can be preserved 1-1 during a lowering pipeline and upstream passes have
366/// more control on how the arguments should be named (e.g. when they create a
367/// function and have some context to assign better names).
370 MatchResult matchInlinable(Value value) override {
371 // Note that the verifier of systemc::FuncOp guarantees that whenever the
372 // function has a body, argNames is present and of the correct length
373 if (isa<BlockArgument>(value) &&
374 value.getParentRegion()->getParentOfType<FuncOp>())
375 return Precedence::VAR;
376
377 return {};
378 }
379
380 void emitInlined(Value value, EmissionPrinter &p) override {
381 auto func = value.getParentRegion()->getParentOfType<FuncOp>();
382 for (auto [arg, name] :
383 llvm::zip(func.getArguments(), func.getArgNames())) {
384 if (arg == value) {
385 p << cast<StringAttr>(name).getValue();
386 return;
387 }
388 }
389 }
390
391 void emitStatement(FuncOp func, EmissionPrinter &p) override {
392 // Emit a newline at the start to ensure an empty line before the function
393 // for better readability.
394 p << "\n";
395
396 if (func.getExternC())
397 p << "extern \"C\" ";
398
399 // Emit return type.
400 if (func.getFunctionType().getNumResults() == 0)
401 p << "void";
402 else
403 p.emitType(func.getFunctionType().getResult(0));
404
405 p << " " << func.getSymName() << "(";
406
407 // Emit the argument list. When the function is a declaration, it is not
408 // required to have argument names, in that case just print the types.
409 if (func.isDeclaration() && func.getArgNames().empty())
410 llvm::interleaveComma(func.getFunctionType().getInputs(), p,
411 [&](Type ty) { p.emitType(ty); });
412 else
413 llvm::interleaveComma(
414 llvm::zip(func.getFunctionType().getInputs(), func.getArgNames()), p,
415 [&](std::tuple<Type, Attribute> arg) {
416 p.emitType(std::get<0>(arg));
417 p << " " << cast<StringAttr>(std::get<1>(arg)).getValue();
418 });
419
420 p << ")";
421
422 // Emit body when present.
423 if (func.isDeclaration()) {
424 p << ";\n";
425 } else {
426 p << " ";
427 p.emitRegion(func.getRegion());
428 }
429 }
430};
431
432/// Emit a systemc.cpp.call operation. If it has no result, it is treated as a
433/// statement, otherwise as an expression that will always be inlined. That
434/// means, an emission preparation pass has to insert a VariableOp to bind the
435/// call result to such that reordering of the call cannot lead to incorrectness
436/// due to interference of side-effects.
437class CallEmitter : public OpEmissionPattern<CallOp> {
439
440 MatchResult matchInlinable(Value value) override {
441 if (value.getDefiningOp<CallOp>())
442 return Precedence::FUNCTION_CALL;
443 return {};
444 }
445
446 void emitInlined(Value value, EmissionPrinter &p) override {
447 printCall(value.getDefiningOp<CallOp>(), p);
448 }
449
450 void emitStatement(CallOp op, EmissionPrinter &p) override {
451 // If the call returns values, then it is treated as an expression rather
452 // than a statement.
453 if (op.getNumResults() > 0)
454 return;
455
456 printCall(op, p);
457 p << ";\n";
458 }
459
460private:
461 void printCall(CallOp op, EmissionPrinter &p) {
462 p << op.getCallee() << "(";
463 llvm::interleaveComma(op.getOperands(), p, [&](auto arg) {
464 p.getInlinable(arg).emitWithParensOnLowerPrecedence(Precedence::COMMA);
465 });
466 p << ")";
467 }
468};
469
470/// Emit a systemc.cpp.call_indirect operation. If it has no result, it is
471/// treated as a statement, otherwise as an expression that will always be
472/// inlined. That means, an emission preparation pass has to insert a VariableOp
473/// to bind the call result to such that reordering of the call cannot lead to
474/// incorrectness due to interference of side-effects.
475class CallIndirectEmitter : public OpEmissionPattern<CallIndirectOp> {
477
478 MatchResult matchInlinable(Value value) override {
479 if (value.getDefiningOp<CallIndirectOp>())
480 return Precedence::FUNCTION_CALL;
481
482 return {};
483 }
484
485 void emitInlined(Value value, EmissionPrinter &p) override {
486 printCall(value.getDefiningOp<CallIndirectOp>(), p);
487 }
488
489 void emitStatement(CallIndirectOp op, EmissionPrinter &p) override {
490 // If the call returns values, then it is treated as an expression rather
491 // than a statement.
492 if (op.getNumResults() > 0)
493 return;
494
495 printCall(op, p);
496 p << ";\n";
497 }
498
499private:
500 void printCall(CallIndirectOp op, EmissionPrinter &p) {
501 p.getInlinable(op.getCallee())
502 .emitWithParensOnLowerPrecedence(Precedence::FUNCTION_CALL);
503 p << "(";
504 llvm::interleaveComma(op.getCalleeOperands(), p, [&](auto arg) {
505 p.getInlinable(arg).emitWithParensOnLowerPrecedence(Precedence::COMMA);
506 });
507 p << ")";
508 }
509};
510
511/// Emit a systemc.cpp.return operation.
514
515 bool matchStatement(Operation *op) override {
516 return isa<ReturnOp>(op) && cast<ReturnOp>(op)->getNumOperands() <= 1;
517 }
518
519 void emitStatement(ReturnOp op, EmissionPrinter &p) override {
520 p << "return";
521 if (!op.getReturnValues().empty()) {
522 p << " ";
523 p.getInlinable(op.getReturnValues()[0]).emit();
524 }
525 p << ";\n";
526 }
527};
528
529//===----------------------------------------------------------------------===//
530// Type emission patterns.
531//===----------------------------------------------------------------------===//
532
533namespace {
534/// Emit SystemC signal and port types according to the specification listed in
535/// their ODS description.
536template <typename Ty, const char Mn[]>
537struct SignalTypeEmitter : public TypeEmissionPattern<Ty> {
538 void emitType(Ty type, EmissionPrinter &p) override {
539 p << Mn << "<";
540 p.emitType(type.getBaseType());
541 p << ">";
542 }
543};
544
545/// Emit a systemc::ModuleType by just printing the module name as we are
546/// dealing with a nominal type system.
547struct ModuleTypeEmitter : public TypeEmissionPattern<ModuleType> {
548 void emitType(ModuleType type, EmissionPrinter &p) override {
549 p << type.getModuleName().getValue();
550 }
551};
552
553/// Emit SystemC integer and bit-vector types with known-at-compile-time
554/// bit-width according to the specification listed in their class description.
555template <typename Ty>
556struct IntegerTypeEmitter : public TypeEmissionPattern<Ty> {
557 void emitType(Ty type, EmissionPrinter &p) override {
558 p << "sc_" << Ty::getMnemonic() << "<" << type.getWidth() << ">";
559 }
560};
561
562/// Emit SystemC integer and bit-vector types without known bit-width according
563/// to the specification listed in their class description.
564template <typename Ty>
565struct DynIntegerTypeEmitter : public TypeEmissionPattern<Ty> {
566 void emitType(Ty type, EmissionPrinter &p) override {
567 p << "sc_" << Ty::getMnemonic();
568 }
569};
570} // namespace
571
572//===----------------------------------------------------------------------===//
573// Register Operation and Type emission patterns.
574//===----------------------------------------------------------------------===//
575
577 OpEmissionPatternSet &patterns, MLIRContext *context) {
578 patterns.add<
579 SCModuleEmitter, CtorEmitter, SCFuncEmitter, MethodEmitter, ThreadEmitter,
580 // Signal and port related emitters
581 SignalWriteEmitter, SignalReadEmitter, SignalEmitter, SensitiveEmitter,
582 // Instance-related emitters
583 InstanceDeclEmitter, BindPortEmitter,
584 // CPP-level operation emitters
585 AssignEmitter, VariableEmitter, NewEmitter, DestructorEmitter,
586 DeleteEmitter, MemberAccessEmitter,
587 // Function related emitters
589}
590
593 static constexpr const char in[] = "sc_in";
594 static constexpr const char inout[] = "sc_inout";
595 static constexpr const char out[] = "sc_out";
596 static constexpr const char signal[] = "sc_signal";
597
598 patterns.add<
599 // Port and signal types
600 SignalTypeEmitter<InputType, in>, SignalTypeEmitter<InOutType, inout>,
601 SignalTypeEmitter<OutputType, out>, SignalTypeEmitter<SignalType, signal>,
602 // SystemC integers with statically known bit-width
603 IntegerTypeEmitter<IntType>, IntegerTypeEmitter<UIntType>,
604 IntegerTypeEmitter<BigIntType>, IntegerTypeEmitter<BigUIntType>,
605 // SystemC integers without statically known bit-width
606 DynIntegerTypeEmitter<IntBaseType>, DynIntegerTypeEmitter<UIntBaseType>,
607 DynIntegerTypeEmitter<SignedType>, DynIntegerTypeEmitter<UnsignedType>,
608 // Vector types with statically known bit-width
609 IntegerTypeEmitter<BitVectorType>, IntegerTypeEmitter<LogicVectorType>,
610 // Vector types without statically known bit-width
611 DynIntegerTypeEmitter<BitVectorBaseType>,
612 DynIntegerTypeEmitter<LogicVectorBaseType>,
613 // Misc types
614 DynIntegerTypeEmitter<LogicType>, ModuleTypeEmitter>();
615}
Emit a systemc.cpp.call operation.
void printCall(CallOp op, EmissionPrinter &p)
MatchResult matchInlinable(Value value) override
Checks if this pattern is applicable to the given value to emit an inlinable expression.
void emitInlined(Value value, EmissionPrinter &p) override
void emitStatement(CallOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
Emit a systemc.cpp.call_indirect operation.
MatchResult matchInlinable(Value value) override
Checks if this pattern is applicable to the given value to emit an inlinable expression.
void printCall(CallIndirectOp op, EmissionPrinter &p)
void emitInlined(Value value, EmissionPrinter &p) override
void emitStatement(CallIndirectOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
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.
void emitRegion(Region &region)
Emit the given region to the ostream associated with this printer.
mlir::raw_indented_ostream & getOstream() const
InlineEmitter getInlinable(Value value)
Emit the expression represented by the given value to the ostream associated with this printer accord...
void emitType(Type type)
Emit the given type to the ostream associated with this printer according to the emission patterns re...
InFlightDiagnostic emitError(Operation *op, const Twine &message)
Emit an error on the operation and fail emission.
void emitWithParensOnLowerPrecedence(Precedence prec, StringRef lParen="(", StringRef rParen=")") const
This class allows a pattern's match function for inlining to pass its result's precedence to the patt...
void populateSystemCOpEmitters(OpEmissionPatternSet &patterns, MLIRContext *context)
Register SystemC operation emission patterns.
void populateSystemCTypeEmitters(TypeEmissionPatternSet &patterns)
Register SystemC type emission patterns.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Emit a systemc.cpp.assign operation.
void emitStatement(AssignOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
Emit a systemc.instance.bind_port operation using the operator() rather than .bind() variant.
void emitStatement(BindPortOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
Emit a systemc.cpp.func function.
void emitInlined(Value value, EmissionPrinter &p) override
void emitStatement(FuncOp func, EmissionPrinter &p) override
Emit zero (default) 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.
Emit a systemc.cpp.member_access operation.
void emitInlined(Value value, EmissionPrinter &p) override
MatchResult matchInlinable(Value value) override
Checks if this pattern is applicable to the given value to emit an inlinable expression.
Emit a systemc.cpp.return operation.
void emitStatement(ReturnOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
bool matchStatement(Operation *op) override
Emit a systemc.cpp.variable operation.
void emitStatement(VariableOp op, EmissionPrinter &p) override
Emit zero (default) or more statements for the given operation.
void emitInlined(Value value, EmissionPrinter &p) override
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 operation emission patterns.
void emitInlined(mlir::Value value, EmissionPrinter &p) override
Emit the expression for the given value.
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.