MLIR  21.0.0git
TranslateToCpp.cpp
Go to the documentation of this file.
1 //===- TranslateToCpp.cpp - Translating to C++ calls ----------------------===//
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 
12 #include "mlir/IR/BuiltinOps.h"
13 #include "mlir/IR/BuiltinTypes.h"
14 #include "mlir/IR/Dialect.h"
15 #include "mlir/IR/Operation.h"
16 #include "mlir/IR/SymbolTable.h"
18 #include "mlir/Support/LLVM.h"
20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/ScopedHashTable.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/FormatVariadic.h"
27 #include <stack>
28 #include <utility>
29 
30 #define DEBUG_TYPE "translate-to-cpp"
31 
32 using namespace mlir;
33 using namespace mlir::emitc;
34 using llvm::formatv;
35 
36 /// Convenience functions to produce interleaved output with functions returning
37 /// a LogicalResult. This is different than those in STLExtras as functions used
38 /// on each element doesn't return a string.
39 template <typename ForwardIterator, typename UnaryFunctor,
40  typename NullaryFunctor>
41 inline LogicalResult
43  UnaryFunctor eachFn, NullaryFunctor betweenFn) {
44  if (begin == end)
45  return success();
46  if (failed(eachFn(*begin)))
47  return failure();
48  ++begin;
49  for (; begin != end; ++begin) {
50  betweenFn();
51  if (failed(eachFn(*begin)))
52  return failure();
53  }
54  return success();
55 }
56 
57 template <typename Container, typename UnaryFunctor, typename NullaryFunctor>
58 inline LogicalResult interleaveWithError(const Container &c,
59  UnaryFunctor eachFn,
60  NullaryFunctor betweenFn) {
61  return interleaveWithError(c.begin(), c.end(), eachFn, betweenFn);
62 }
63 
64 template <typename Container, typename UnaryFunctor>
65 inline LogicalResult interleaveCommaWithError(const Container &c,
66  raw_ostream &os,
67  UnaryFunctor eachFn) {
68  return interleaveWithError(c.begin(), c.end(), eachFn, [&]() { os << ", "; });
69 }
70 
71 /// Return the precedence of a operator as an integer, higher values
72 /// imply higher precedence.
73 static FailureOr<int> getOperatorPrecedence(Operation *operation) {
75  .Case<emitc::AddOp>([&](auto op) { return 12; })
76  .Case<emitc::ApplyOp>([&](auto op) { return 15; })
77  .Case<emitc::BitwiseAndOp>([&](auto op) { return 7; })
78  .Case<emitc::BitwiseLeftShiftOp>([&](auto op) { return 11; })
79  .Case<emitc::BitwiseNotOp>([&](auto op) { return 15; })
80  .Case<emitc::BitwiseOrOp>([&](auto op) { return 5; })
81  .Case<emitc::BitwiseRightShiftOp>([&](auto op) { return 11; })
82  .Case<emitc::BitwiseXorOp>([&](auto op) { return 6; })
83  .Case<emitc::CallOp>([&](auto op) { return 16; })
84  .Case<emitc::CallOpaqueOp>([&](auto op) { return 16; })
85  .Case<emitc::CastOp>([&](auto op) { return 15; })
86  .Case<emitc::CmpOp>([&](auto op) -> FailureOr<int> {
87  switch (op.getPredicate()) {
88  case emitc::CmpPredicate::eq:
89  case emitc::CmpPredicate::ne:
90  return 8;
91  case emitc::CmpPredicate::lt:
92  case emitc::CmpPredicate::le:
93  case emitc::CmpPredicate::gt:
94  case emitc::CmpPredicate::ge:
95  return 9;
96  case emitc::CmpPredicate::three_way:
97  return 10;
98  }
99  return op->emitError("unsupported cmp predicate");
100  })
101  .Case<emitc::ConditionalOp>([&](auto op) { return 2; })
102  .Case<emitc::DivOp>([&](auto op) { return 13; })
103  .Case<emitc::LoadOp>([&](auto op) { return 16; })
104  .Case<emitc::LogicalAndOp>([&](auto op) { return 4; })
105  .Case<emitc::LogicalNotOp>([&](auto op) { return 15; })
106  .Case<emitc::LogicalOrOp>([&](auto op) { return 3; })
107  .Case<emitc::MulOp>([&](auto op) { return 13; })
108  .Case<emitc::RemOp>([&](auto op) { return 13; })
109  .Case<emitc::SubOp>([&](auto op) { return 12; })
110  .Case<emitc::UnaryMinusOp>([&](auto op) { return 15; })
111  .Case<emitc::UnaryPlusOp>([&](auto op) { return 15; })
112  .Default([](auto op) { return op->emitError("unsupported operation"); });
113 }
114 
115 namespace {
116 /// Emitter that uses dialect specific emitters to emit C++ code.
117 struct CppEmitter {
118  explicit CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
119  StringRef fileId);
120 
121  /// Emits attribute or returns failure.
122  LogicalResult emitAttribute(Location loc, Attribute attr);
123 
124  /// Emits operation 'op' with/without training semicolon or returns failure.
125  ///
126  /// For operations that should never be followed by a semicolon, like ForOp,
127  /// the `trailingSemicolon` argument is ignored and a semicolon is not
128  /// emitted.
129  LogicalResult emitOperation(Operation &op, bool trailingSemicolon);
130 
131  /// Emits type 'type' or returns failure.
132  LogicalResult emitType(Location loc, Type type);
133 
134  /// Emits array of types as a std::tuple of the emitted types.
135  /// - emits void for an empty array;
136  /// - emits the type of the only element for arrays of size one;
137  /// - emits a std::tuple otherwise;
138  LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
139 
140  /// Emits array of types as a std::tuple of the emitted types independently of
141  /// the array size.
142  LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
143 
144  /// Emits an assignment for a variable which has been declared previously.
145  LogicalResult emitVariableAssignment(OpResult result);
146 
147  /// Emits a variable declaration for a result of an operation.
148  LogicalResult emitVariableDeclaration(OpResult result,
149  bool trailingSemicolon);
150 
151  /// Emits a declaration of a variable with the given type and name.
152  LogicalResult emitVariableDeclaration(Location loc, Type type,
153  StringRef name);
154 
155  /// Emits the variable declaration and assignment prefix for 'op'.
156  /// - emits separate variable followed by std::tie for multi-valued operation;
157  /// - emits single type followed by variable for single result;
158  /// - emits nothing if no value produced by op;
159  /// Emits final '=' operator where a type is produced. Returns failure if
160  /// any result type could not be converted.
161  LogicalResult emitAssignPrefix(Operation &op);
162 
163  /// Emits a global variable declaration or definition.
164  LogicalResult emitGlobalVariable(GlobalOp op);
165 
166  /// Emits a label for the block.
167  LogicalResult emitLabel(Block &block);
168 
169  /// Emits the operands and atttributes of the operation. All operands are
170  /// emitted first and then all attributes in alphabetical order.
171  LogicalResult emitOperandsAndAttributes(Operation &op,
172  ArrayRef<StringRef> exclude = {});
173 
174  /// Emits the operands of the operation. All operands are emitted in order.
175  LogicalResult emitOperands(Operation &op);
176 
177  /// Emits value as an operands of an operation
178  LogicalResult emitOperand(Value value);
179 
180  /// Emit an expression as a C expression.
181  LogicalResult emitExpression(ExpressionOp expressionOp);
182 
183  /// Insert the expression representing the operation into the value cache.
184  void cacheDeferredOpResult(Value value, StringRef str);
185 
186  /// Return the existing or a new name for a Value.
187  StringRef getOrCreateName(Value val);
188 
189  // Returns the textual representation of a subscript operation.
190  std::string getSubscriptName(emitc::SubscriptOp op);
191 
192  // Returns the textual representation of a member (of object) operation.
193  std::string createMemberAccess(emitc::MemberOp op);
194 
195  // Returns the textual representation of a member of pointer operation.
196  std::string createMemberAccess(emitc::MemberOfPtrOp op);
197 
198  /// Return the existing or a new label of a Block.
199  StringRef getOrCreateName(Block &block);
200 
201  /// Whether to map an mlir integer to a unsigned integer in C++.
202  bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
203 
204  /// RAII helper function to manage entering/exiting C++ scopes.
205  struct Scope {
206  Scope(CppEmitter &emitter)
207  : valueMapperScope(emitter.valueMapper),
208  blockMapperScope(emitter.blockMapper), emitter(emitter) {
209  emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
210  emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
211  }
212  ~Scope() {
213  emitter.valueInScopeCount.pop();
214  emitter.labelInScopeCount.pop();
215  }
216 
217  private:
218  llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
219  llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
220  CppEmitter &emitter;
221  };
222 
223  /// Returns wether the Value is assigned to a C++ variable in the scope.
224  bool hasValueInScope(Value val);
225 
226  // Returns whether a label is assigned to the block.
227  bool hasBlockLabel(Block &block);
228 
229  /// Returns the output stream.
230  raw_indented_ostream &ostream() { return os; };
231 
232  /// Returns if all variables for op results and basic block arguments need to
233  /// be declared at the beginning of a function.
234  bool shouldDeclareVariablesAtTop() { return declareVariablesAtTop; };
235 
236  /// Returns whether this file op should be emitted
237  bool shouldEmitFile(FileOp file) {
238  return !fileId.empty() && file.getId() == fileId;
239  }
240 
241  /// Get expression currently being emitted.
242  ExpressionOp getEmittedExpression() { return emittedExpression; }
243 
244  /// Determine whether given value is part of the expression potentially being
245  /// emitted.
246  bool isPartOfCurrentExpression(Value value) {
247  if (!emittedExpression)
248  return false;
249  Operation *def = value.getDefiningOp();
250  if (!def)
251  return false;
252  auto operandExpression = dyn_cast<ExpressionOp>(def->getParentOp());
253  return operandExpression == emittedExpression;
254  };
255 
256 private:
257  using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
258  using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
259 
260  /// Output stream to emit to.
262 
263  /// Boolean to enforce that all variables for op results and block
264  /// arguments are declared at the beginning of the function. This also
265  /// includes results from ops located in nested regions.
266  bool declareVariablesAtTop;
267 
268  /// Only emit file ops whos id matches this value.
269  std::string fileId;
270 
271  /// Map from value to name of C++ variable that contain the name.
272  ValueMapper valueMapper;
273 
274  /// Map from block to name of C++ label.
275  BlockMapper blockMapper;
276 
277  /// The number of values in the current scope. This is used to declare the
278  /// names of values in a scope.
279  std::stack<int64_t> valueInScopeCount;
280  std::stack<int64_t> labelInScopeCount;
281 
282  /// State of the current expression being emitted.
283  ExpressionOp emittedExpression;
284  SmallVector<int> emittedExpressionPrecedence;
285 
286  void pushExpressionPrecedence(int precedence) {
287  emittedExpressionPrecedence.push_back(precedence);
288  }
289  void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
290  static int lowestPrecedence() { return 0; }
291  int getExpressionPrecedence() {
292  if (emittedExpressionPrecedence.empty())
293  return lowestPrecedence();
294  return emittedExpressionPrecedence.back();
295  }
296 };
297 } // namespace
298 
299 /// Determine whether expression \p op should be emitted in a deferred way.
300 static bool hasDeferredEmission(Operation *op) {
301  return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
302  emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
303 }
304 
305 /// Determine whether expression \p expressionOp should be emitted inline, i.e.
306 /// as part of its user. This function recommends inlining of any expressions
307 /// that can be inlined unless it is used by another expression, under the
308 /// assumption that any expression fusion/re-materialization was taken care of
309 /// by transformations run by the backend.
310 static bool shouldBeInlined(ExpressionOp expressionOp) {
311  // Do not inline if expression is marked as such.
312  if (expressionOp.getDoNotInline())
313  return false;
314 
315  // Do not inline expressions with side effects to prevent side-effect
316  // reordering.
317  if (expressionOp.hasSideEffects())
318  return false;
319 
320  // Do not inline expressions with multiple uses.
321  Value result = expressionOp.getResult();
322  if (!result.hasOneUse())
323  return false;
324 
325  Operation *user = *result.getUsers().begin();
326 
327  // Do not inline expressions used by operations with deferred emission, since
328  // their translation requires the materialization of variables.
329  if (hasDeferredEmission(user))
330  return false;
331 
332  // Do not inline expressions used by ops with the CExpressionInterface. If
333  // this was intended, the user could have been merged into the expression op.
334  return !isa<emitc::CExpressionInterface>(*user);
335 }
336 
337 static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation,
338  Attribute value) {
339  OpResult result = operation->getResult(0);
340 
341  // Only emit an assignment as the variable was already declared when printing
342  // the FuncOp.
343  if (emitter.shouldDeclareVariablesAtTop()) {
344  // Skip the assignment if the emitc.constant has no value.
345  if (auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
346  if (oAttr.getValue().empty())
347  return success();
348  }
349 
350  if (failed(emitter.emitVariableAssignment(result)))
351  return failure();
352  return emitter.emitAttribute(operation->getLoc(), value);
353  }
354 
355  // Emit a variable declaration for an emitc.constant op without value.
356  if (auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
357  if (oAttr.getValue().empty())
358  // The semicolon gets printed by the emitOperation function.
359  return emitter.emitVariableDeclaration(result,
360  /*trailingSemicolon=*/false);
361  }
362 
363  // Emit a variable declaration.
364  if (failed(emitter.emitAssignPrefix(*operation)))
365  return failure();
366  return emitter.emitAttribute(operation->getLoc(), value);
367 }
368 
369 static LogicalResult printOperation(CppEmitter &emitter,
370  emitc::ConstantOp constantOp) {
371  Operation *operation = constantOp.getOperation();
372  Attribute value = constantOp.getValue();
373 
374  return printConstantOp(emitter, operation, value);
375 }
376 
377 static LogicalResult printOperation(CppEmitter &emitter,
378  emitc::VariableOp variableOp) {
379  Operation *operation = variableOp.getOperation();
380  Attribute value = variableOp.getValue();
381 
382  return printConstantOp(emitter, operation, value);
383 }
384 
385 static LogicalResult printOperation(CppEmitter &emitter,
386  emitc::GlobalOp globalOp) {
387 
388  return emitter.emitGlobalVariable(globalOp);
389 }
390 
391 static LogicalResult printOperation(CppEmitter &emitter,
392  emitc::AssignOp assignOp) {
393  OpResult result = assignOp.getVar().getDefiningOp()->getResult(0);
394 
395  if (failed(emitter.emitVariableAssignment(result)))
396  return failure();
397 
398  return emitter.emitOperand(assignOp.getValue());
399 }
400 
401 static LogicalResult printOperation(CppEmitter &emitter, emitc::LoadOp loadOp) {
402  if (failed(emitter.emitAssignPrefix(*loadOp)))
403  return failure();
404 
405  return emitter.emitOperand(loadOp.getOperand());
406 }
407 
408 static LogicalResult printBinaryOperation(CppEmitter &emitter,
409  Operation *operation,
410  StringRef binaryOperator) {
411  raw_ostream &os = emitter.ostream();
412 
413  if (failed(emitter.emitAssignPrefix(*operation)))
414  return failure();
415 
416  if (failed(emitter.emitOperand(operation->getOperand(0))))
417  return failure();
418 
419  os << " " << binaryOperator << " ";
420 
421  if (failed(emitter.emitOperand(operation->getOperand(1))))
422  return failure();
423 
424  return success();
425 }
426 
427 static LogicalResult printUnaryOperation(CppEmitter &emitter,
428  Operation *operation,
429  StringRef unaryOperator) {
430  raw_ostream &os = emitter.ostream();
431 
432  if (failed(emitter.emitAssignPrefix(*operation)))
433  return failure();
434 
435  os << unaryOperator;
436 
437  if (failed(emitter.emitOperand(operation->getOperand(0))))
438  return failure();
439 
440  return success();
441 }
442 
443 static LogicalResult printOperation(CppEmitter &emitter, emitc::AddOp addOp) {
444  Operation *operation = addOp.getOperation();
445 
446  return printBinaryOperation(emitter, operation, "+");
447 }
448 
449 static LogicalResult printOperation(CppEmitter &emitter, emitc::DivOp divOp) {
450  Operation *operation = divOp.getOperation();
451 
452  return printBinaryOperation(emitter, operation, "/");
453 }
454 
455 static LogicalResult printOperation(CppEmitter &emitter, emitc::MulOp mulOp) {
456  Operation *operation = mulOp.getOperation();
457 
458  return printBinaryOperation(emitter, operation, "*");
459 }
460 
461 static LogicalResult printOperation(CppEmitter &emitter, emitc::RemOp remOp) {
462  Operation *operation = remOp.getOperation();
463 
464  return printBinaryOperation(emitter, operation, "%");
465 }
466 
467 static LogicalResult printOperation(CppEmitter &emitter, emitc::SubOp subOp) {
468  Operation *operation = subOp.getOperation();
469 
470  return printBinaryOperation(emitter, operation, "-");
471 }
472 
473 static LogicalResult emitSwitchCase(CppEmitter &emitter,
474  raw_indented_ostream &os, Region &region) {
475  for (Region::OpIterator iteratorOp = region.op_begin(), end = region.op_end();
476  std::next(iteratorOp) != end; ++iteratorOp) {
477  if (failed(emitter.emitOperation(*iteratorOp, /*trailingSemicolon=*/true)))
478  return failure();
479  }
480  os << "break;\n";
481  return success();
482 }
483 
484 static LogicalResult printOperation(CppEmitter &emitter,
485  emitc::SwitchOp switchOp) {
486  raw_indented_ostream &os = emitter.ostream();
487 
488  os << "switch (";
489  if (failed(emitter.emitOperand(switchOp.getArg())))
490  return failure();
491  os << ") {";
492 
493  for (auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
494  os << "\ncase " << std::get<0>(pair) << ": {\n";
495  os.indent();
496 
497  if (failed(emitSwitchCase(emitter, os, std::get<1>(pair))))
498  return failure();
499 
500  os.unindent() << "}";
501  }
502 
503  os << "\ndefault: {\n";
504  os.indent();
505 
506  if (failed(emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
507  return failure();
508 
509  os.unindent() << "}\n}";
510  return success();
511 }
512 
513 static LogicalResult printOperation(CppEmitter &emitter, emitc::CmpOp cmpOp) {
514  Operation *operation = cmpOp.getOperation();
515 
516  StringRef binaryOperator;
517 
518  switch (cmpOp.getPredicate()) {
519  case emitc::CmpPredicate::eq:
520  binaryOperator = "==";
521  break;
522  case emitc::CmpPredicate::ne:
523  binaryOperator = "!=";
524  break;
525  case emitc::CmpPredicate::lt:
526  binaryOperator = "<";
527  break;
528  case emitc::CmpPredicate::le:
529  binaryOperator = "<=";
530  break;
531  case emitc::CmpPredicate::gt:
532  binaryOperator = ">";
533  break;
534  case emitc::CmpPredicate::ge:
535  binaryOperator = ">=";
536  break;
537  case emitc::CmpPredicate::three_way:
538  binaryOperator = "<=>";
539  break;
540  }
541 
542  return printBinaryOperation(emitter, operation, binaryOperator);
543 }
544 
545 static LogicalResult printOperation(CppEmitter &emitter,
546  emitc::ConditionalOp conditionalOp) {
547  raw_ostream &os = emitter.ostream();
548 
549  if (failed(emitter.emitAssignPrefix(*conditionalOp)))
550  return failure();
551 
552  if (failed(emitter.emitOperand(conditionalOp.getCondition())))
553  return failure();
554 
555  os << " ? ";
556 
557  if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
558  return failure();
559 
560  os << " : ";
561 
562  if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
563  return failure();
564 
565  return success();
566 }
567 
568 static LogicalResult printOperation(CppEmitter &emitter,
569  emitc::VerbatimOp verbatimOp) {
570  raw_ostream &os = emitter.ostream();
571 
572  FailureOr<SmallVector<ReplacementItem>> items =
573  verbatimOp.parseFormatString();
574  if (failed(items))
575  return failure();
576 
577  auto fmtArg = verbatimOp.getFmtArgs().begin();
578 
579  for (ReplacementItem &item : *items) {
580  if (auto *str = std::get_if<StringRef>(&item)) {
581  os << *str;
582  } else {
583  if (failed(emitter.emitOperand(*fmtArg++)))
584  return failure();
585  }
586  }
587 
588  return success();
589 }
590 
591 static LogicalResult printOperation(CppEmitter &emitter,
592  cf::BranchOp branchOp) {
593  raw_ostream &os = emitter.ostream();
594  Block &successor = *branchOp.getSuccessor();
595 
596  for (auto pair :
597  llvm::zip(branchOp.getOperands(), successor.getArguments())) {
598  Value &operand = std::get<0>(pair);
599  BlockArgument &argument = std::get<1>(pair);
600  os << emitter.getOrCreateName(argument) << " = "
601  << emitter.getOrCreateName(operand) << ";\n";
602  }
603 
604  os << "goto ";
605  if (!(emitter.hasBlockLabel(successor)))
606  return branchOp.emitOpError("unable to find label for successor block");
607  os << emitter.getOrCreateName(successor);
608  return success();
609 }
610 
611 static LogicalResult printOperation(CppEmitter &emitter,
612  cf::CondBranchOp condBranchOp) {
613  raw_indented_ostream &os = emitter.ostream();
614  Block &trueSuccessor = *condBranchOp.getTrueDest();
615  Block &falseSuccessor = *condBranchOp.getFalseDest();
616 
617  os << "if (";
618  if (failed(emitter.emitOperand(condBranchOp.getCondition())))
619  return failure();
620  os << ") {\n";
621 
622  os.indent();
623 
624  // If condition is true.
625  for (auto pair : llvm::zip(condBranchOp.getTrueOperands(),
626  trueSuccessor.getArguments())) {
627  Value &operand = std::get<0>(pair);
628  BlockArgument &argument = std::get<1>(pair);
629  os << emitter.getOrCreateName(argument) << " = "
630  << emitter.getOrCreateName(operand) << ";\n";
631  }
632 
633  os << "goto ";
634  if (!(emitter.hasBlockLabel(trueSuccessor))) {
635  return condBranchOp.emitOpError("unable to find label for successor block");
636  }
637  os << emitter.getOrCreateName(trueSuccessor) << ";\n";
638  os.unindent() << "} else {\n";
639  os.indent();
640  // If condition is false.
641  for (auto pair : llvm::zip(condBranchOp.getFalseOperands(),
642  falseSuccessor.getArguments())) {
643  Value &operand = std::get<0>(pair);
644  BlockArgument &argument = std::get<1>(pair);
645  os << emitter.getOrCreateName(argument) << " = "
646  << emitter.getOrCreateName(operand) << ";\n";
647  }
648 
649  os << "goto ";
650  if (!(emitter.hasBlockLabel(falseSuccessor))) {
651  return condBranchOp.emitOpError()
652  << "unable to find label for successor block";
653  }
654  os << emitter.getOrCreateName(falseSuccessor) << ";\n";
655  os.unindent() << "}";
656  return success();
657 }
658 
659 static LogicalResult printCallOperation(CppEmitter &emitter, Operation *callOp,
660  StringRef callee) {
661  if (failed(emitter.emitAssignPrefix(*callOp)))
662  return failure();
663 
664  raw_ostream &os = emitter.ostream();
665  os << callee << "(";
666  if (failed(emitter.emitOperands(*callOp)))
667  return failure();
668  os << ")";
669  return success();
670 }
671 
672 static LogicalResult printOperation(CppEmitter &emitter, func::CallOp callOp) {
673  Operation *operation = callOp.getOperation();
674  StringRef callee = callOp.getCallee();
675 
676  return printCallOperation(emitter, operation, callee);
677 }
678 
679 static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
680  Operation *operation = callOp.getOperation();
681  StringRef callee = callOp.getCallee();
682 
683  return printCallOperation(emitter, operation, callee);
684 }
685 
686 static LogicalResult printOperation(CppEmitter &emitter,
687  emitc::CallOpaqueOp callOpaqueOp) {
688  raw_ostream &os = emitter.ostream();
689  Operation &op = *callOpaqueOp.getOperation();
690 
691  if (failed(emitter.emitAssignPrefix(op)))
692  return failure();
693  os << callOpaqueOp.getCallee();
694 
695  // Template arguments can't refer to SSA values and as such the template
696  // arguments which are supplied in form of attributes can be emitted as is. We
697  // don't need to handle integer attributes specially like we do for arguments
698  // - see below.
699  auto emitTemplateArgs = [&](Attribute attr) -> LogicalResult {
700  return emitter.emitAttribute(op.getLoc(), attr);
701  };
702 
703  if (callOpaqueOp.getTemplateArgs()) {
704  os << "<";
705  if (failed(interleaveCommaWithError(*callOpaqueOp.getTemplateArgs(), os,
706  emitTemplateArgs)))
707  return failure();
708  os << ">";
709  }
710 
711  auto emitArgs = [&](Attribute attr) -> LogicalResult {
712  if (auto t = dyn_cast<IntegerAttr>(attr)) {
713  // Index attributes are treated specially as operand index.
714  if (t.getType().isIndex()) {
715  int64_t idx = t.getInt();
716  Value operand = op.getOperand(idx);
717  if (!emitter.hasValueInScope(operand))
718  return op.emitOpError("operand ")
719  << idx << "'s value not defined in scope";
720  os << emitter.getOrCreateName(operand);
721  return success();
722  }
723  }
724  if (failed(emitter.emitAttribute(op.getLoc(), attr)))
725  return failure();
726 
727  return success();
728  };
729 
730  os << "(";
731 
732  LogicalResult emittedArgs =
733  callOpaqueOp.getArgs()
734  ? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
735  : emitter.emitOperands(op);
736  if (failed(emittedArgs))
737  return failure();
738  os << ")";
739  return success();
740 }
741 
742 static LogicalResult printOperation(CppEmitter &emitter,
743  emitc::ApplyOp applyOp) {
744  raw_ostream &os = emitter.ostream();
745  Operation &op = *applyOp.getOperation();
746 
747  if (failed(emitter.emitAssignPrefix(op)))
748  return failure();
749  os << applyOp.getApplicableOperator();
750  os << emitter.getOrCreateName(applyOp.getOperand());
751 
752  return success();
753 }
754 
755 static LogicalResult printOperation(CppEmitter &emitter,
756  emitc::BitwiseAndOp bitwiseAndOp) {
757  Operation *operation = bitwiseAndOp.getOperation();
758  return printBinaryOperation(emitter, operation, "&");
759 }
760 
761 static LogicalResult
762 printOperation(CppEmitter &emitter,
763  emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
764  Operation *operation = bitwiseLeftShiftOp.getOperation();
765  return printBinaryOperation(emitter, operation, "<<");
766 }
767 
768 static LogicalResult printOperation(CppEmitter &emitter,
769  emitc::BitwiseNotOp bitwiseNotOp) {
770  Operation *operation = bitwiseNotOp.getOperation();
771  return printUnaryOperation(emitter, operation, "~");
772 }
773 
774 static LogicalResult printOperation(CppEmitter &emitter,
775  emitc::BitwiseOrOp bitwiseOrOp) {
776  Operation *operation = bitwiseOrOp.getOperation();
777  return printBinaryOperation(emitter, operation, "|");
778 }
779 
780 static LogicalResult
781 printOperation(CppEmitter &emitter,
782  emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
783  Operation *operation = bitwiseRightShiftOp.getOperation();
784  return printBinaryOperation(emitter, operation, ">>");
785 }
786 
787 static LogicalResult printOperation(CppEmitter &emitter,
788  emitc::BitwiseXorOp bitwiseXorOp) {
789  Operation *operation = bitwiseXorOp.getOperation();
790  return printBinaryOperation(emitter, operation, "^");
791 }
792 
793 static LogicalResult printOperation(CppEmitter &emitter,
794  emitc::UnaryPlusOp unaryPlusOp) {
795  Operation *operation = unaryPlusOp.getOperation();
796  return printUnaryOperation(emitter, operation, "+");
797 }
798 
799 static LogicalResult printOperation(CppEmitter &emitter,
800  emitc::UnaryMinusOp unaryMinusOp) {
801  Operation *operation = unaryMinusOp.getOperation();
802  return printUnaryOperation(emitter, operation, "-");
803 }
804 
805 static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) {
806  raw_ostream &os = emitter.ostream();
807  Operation &op = *castOp.getOperation();
808 
809  if (failed(emitter.emitAssignPrefix(op)))
810  return failure();
811  os << "(";
812  if (failed(emitter.emitType(op.getLoc(), op.getResult(0).getType())))
813  return failure();
814  os << ") ";
815  return emitter.emitOperand(castOp.getOperand());
816 }
817 
818 static LogicalResult printOperation(CppEmitter &emitter,
819  emitc::ExpressionOp expressionOp) {
820  if (shouldBeInlined(expressionOp))
821  return success();
822 
823  Operation &op = *expressionOp.getOperation();
824 
825  if (failed(emitter.emitAssignPrefix(op)))
826  return failure();
827 
828  return emitter.emitExpression(expressionOp);
829 }
830 
831 static LogicalResult printOperation(CppEmitter &emitter,
832  emitc::IncludeOp includeOp) {
833  raw_ostream &os = emitter.ostream();
834 
835  os << "#include ";
836  if (includeOp.getIsStandardInclude())
837  os << "<" << includeOp.getInclude() << ">";
838  else
839  os << "\"" << includeOp.getInclude() << "\"";
840 
841  return success();
842 }
843 
844 static LogicalResult printOperation(CppEmitter &emitter,
845  emitc::LogicalAndOp logicalAndOp) {
846  Operation *operation = logicalAndOp.getOperation();
847  return printBinaryOperation(emitter, operation, "&&");
848 }
849 
850 static LogicalResult printOperation(CppEmitter &emitter,
851  emitc::LogicalNotOp logicalNotOp) {
852  Operation *operation = logicalNotOp.getOperation();
853  return printUnaryOperation(emitter, operation, "!");
854 }
855 
856 static LogicalResult printOperation(CppEmitter &emitter,
857  emitc::LogicalOrOp logicalOrOp) {
858  Operation *operation = logicalOrOp.getOperation();
859  return printBinaryOperation(emitter, operation, "||");
860 }
861 
862 static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) {
863 
864  raw_indented_ostream &os = emitter.ostream();
865 
866  // Utility function to determine whether a value is an expression that will be
867  // inlined, and as such should be wrapped in parentheses in order to guarantee
868  // its precedence and associativity.
869  auto requiresParentheses = [&](Value value) {
870  auto expressionOp =
871  dyn_cast_if_present<ExpressionOp>(value.getDefiningOp());
872  if (!expressionOp)
873  return false;
874  return shouldBeInlined(expressionOp);
875  };
876 
877  os << "for (";
878  if (failed(
879  emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
880  return failure();
881  os << " ";
882  os << emitter.getOrCreateName(forOp.getInductionVar());
883  os << " = ";
884  if (failed(emitter.emitOperand(forOp.getLowerBound())))
885  return failure();
886  os << "; ";
887  os << emitter.getOrCreateName(forOp.getInductionVar());
888  os << " < ";
889  Value upperBound = forOp.getUpperBound();
890  bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
891  if (upperBoundRequiresParentheses)
892  os << "(";
893  if (failed(emitter.emitOperand(upperBound)))
894  return failure();
895  if (upperBoundRequiresParentheses)
896  os << ")";
897  os << "; ";
898  os << emitter.getOrCreateName(forOp.getInductionVar());
899  os << " += ";
900  if (failed(emitter.emitOperand(forOp.getStep())))
901  return failure();
902  os << ") {\n";
903  os.indent();
904 
905  Region &forRegion = forOp.getRegion();
906  auto regionOps = forRegion.getOps();
907 
908  // We skip the trailing yield op.
909  for (auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
910  if (failed(emitter.emitOperation(*it, /*trailingSemicolon=*/true)))
911  return failure();
912  }
913 
914  os.unindent() << "}";
915 
916  return success();
917 }
918 
919 static LogicalResult printOperation(CppEmitter &emitter, emitc::IfOp ifOp) {
920  raw_indented_ostream &os = emitter.ostream();
921 
922  // Helper function to emit all ops except the last one, expected to be
923  // emitc::yield.
924  auto emitAllExceptLast = [&emitter](Region &region) {
925  Region::OpIterator it = region.op_begin(), end = region.op_end();
926  for (; std::next(it) != end; ++it) {
927  if (failed(emitter.emitOperation(*it, /*trailingSemicolon=*/true)))
928  return failure();
929  }
930  assert(isa<emitc::YieldOp>(*it) &&
931  "Expected last operation in the region to be emitc::yield");
932  return success();
933  };
934 
935  os << "if (";
936  if (failed(emitter.emitOperand(ifOp.getCondition())))
937  return failure();
938  os << ") {\n";
939  os.indent();
940  if (failed(emitAllExceptLast(ifOp.getThenRegion())))
941  return failure();
942  os.unindent() << "}";
943 
944  Region &elseRegion = ifOp.getElseRegion();
945  if (!elseRegion.empty()) {
946  os << " else {\n";
947  os.indent();
948  if (failed(emitAllExceptLast(elseRegion)))
949  return failure();
950  os.unindent() << "}";
951  }
952 
953  return success();
954 }
955 
956 static LogicalResult printOperation(CppEmitter &emitter,
957  func::ReturnOp returnOp) {
958  raw_ostream &os = emitter.ostream();
959  os << "return";
960  switch (returnOp.getNumOperands()) {
961  case 0:
962  return success();
963  case 1:
964  os << " ";
965  if (failed(emitter.emitOperand(returnOp.getOperand(0))))
966  return failure();
967  return success();
968  default:
969  os << " std::make_tuple(";
970  if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
971  return failure();
972  os << ")";
973  return success();
974  }
975 }
976 
977 static LogicalResult printOperation(CppEmitter &emitter,
978  emitc::ReturnOp returnOp) {
979  raw_ostream &os = emitter.ostream();
980  os << "return";
981  if (returnOp.getNumOperands() == 0)
982  return success();
983 
984  os << " ";
985  if (failed(emitter.emitOperand(returnOp.getOperand())))
986  return failure();
987  return success();
988 }
989 
990 static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
991  CppEmitter::Scope scope(emitter);
992 
993  for (Operation &op : moduleOp) {
994  if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
995  return failure();
996  }
997  return success();
998 }
999 
1000 static LogicalResult printOperation(CppEmitter &emitter, FileOp file) {
1001  if (!emitter.shouldEmitFile(file))
1002  return success();
1003 
1004  CppEmitter::Scope scope(emitter);
1005 
1006  for (Operation &op : file) {
1007  if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
1008  return failure();
1009  }
1010  return success();
1011 }
1012 
1013 static LogicalResult printFunctionArgs(CppEmitter &emitter,
1014  Operation *functionOp,
1015  ArrayRef<Type> arguments) {
1016  raw_indented_ostream &os = emitter.ostream();
1017 
1018  return (
1019  interleaveCommaWithError(arguments, os, [&](Type arg) -> LogicalResult {
1020  return emitter.emitType(functionOp->getLoc(), arg);
1021  }));
1022 }
1023 
1024 static LogicalResult printFunctionArgs(CppEmitter &emitter,
1025  Operation *functionOp,
1026  Region::BlockArgListType arguments) {
1027  raw_indented_ostream &os = emitter.ostream();
1028 
1029  return (interleaveCommaWithError(
1030  arguments, os, [&](BlockArgument arg) -> LogicalResult {
1031  return emitter.emitVariableDeclaration(
1032  functionOp->getLoc(), arg.getType(), emitter.getOrCreateName(arg));
1033  }));
1034 }
1035 
1036 static LogicalResult printFunctionBody(CppEmitter &emitter,
1037  Operation *functionOp,
1038  Region::BlockListType &blocks) {
1039  raw_indented_ostream &os = emitter.ostream();
1040  os.indent();
1041 
1042  if (emitter.shouldDeclareVariablesAtTop()) {
1043  // Declare all variables that hold op results including those from nested
1044  // regions.
1045  WalkResult result =
1046  functionOp->walk<WalkOrder::PreOrder>([&](Operation *op) -> WalkResult {
1047  if (isa<emitc::ExpressionOp>(op->getParentOp()) ||
1048  (isa<emitc::ExpressionOp>(op) &&
1049  shouldBeInlined(cast<emitc::ExpressionOp>(op))))
1050  return WalkResult::skip();
1051  for (OpResult result : op->getResults()) {
1052  if (failed(emitter.emitVariableDeclaration(
1053  result, /*trailingSemicolon=*/true))) {
1054  return WalkResult(
1055  op->emitError("unable to declare result variable for op"));
1056  }
1057  }
1058  return WalkResult::advance();
1059  });
1060  if (result.wasInterrupted())
1061  return failure();
1062  }
1063 
1064  // Create label names for basic blocks.
1065  for (Block &block : blocks) {
1066  emitter.getOrCreateName(block);
1067  }
1068 
1069  // Declare variables for basic block arguments.
1070  for (Block &block : llvm::drop_begin(blocks)) {
1071  for (BlockArgument &arg : block.getArguments()) {
1072  if (emitter.hasValueInScope(arg))
1073  return functionOp->emitOpError(" block argument #")
1074  << arg.getArgNumber() << " is out of scope";
1075  if (isa<ArrayType, LValueType>(arg.getType()))
1076  return functionOp->emitOpError("cannot emit block argument #")
1077  << arg.getArgNumber() << " with type " << arg.getType();
1078  if (failed(
1079  emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1080  return failure();
1081  }
1082  os << " " << emitter.getOrCreateName(arg) << ";\n";
1083  }
1084  }
1085 
1086  for (Block &block : blocks) {
1087  // Only print a label if the block has predecessors.
1088  if (!block.hasNoPredecessors()) {
1089  if (failed(emitter.emitLabel(block)))
1090  return failure();
1091  }
1092  for (Operation &op : block.getOperations()) {
1093  if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/true)))
1094  return failure();
1095  }
1096  }
1097 
1098  os.unindent();
1099 
1100  return success();
1101 }
1102 
1103 static LogicalResult printOperation(CppEmitter &emitter,
1104  func::FuncOp functionOp) {
1105  // We need to declare variables at top if the function has multiple blocks.
1106  if (!emitter.shouldDeclareVariablesAtTop() &&
1107  functionOp.getBlocks().size() > 1) {
1108  return functionOp.emitOpError(
1109  "with multiple blocks needs variables declared at top");
1110  }
1111 
1112  if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1113  return functionOp.emitOpError()
1114  << "cannot emit lvalue type as argument type";
1115  }
1116 
1117  if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1118  return functionOp.emitOpError() << "cannot emit array type as result type";
1119  }
1120 
1121  CppEmitter::Scope scope(emitter);
1122  raw_indented_ostream &os = emitter.ostream();
1123  if (failed(emitter.emitTypes(functionOp.getLoc(),
1124  functionOp.getFunctionType().getResults())))
1125  return failure();
1126  os << " " << functionOp.getName();
1127 
1128  os << "(";
1129  Operation *operation = functionOp.getOperation();
1130  if (failed(printFunctionArgs(emitter, operation, functionOp.getArguments())))
1131  return failure();
1132  os << ") {\n";
1133  if (failed(printFunctionBody(emitter, operation, functionOp.getBlocks())))
1134  return failure();
1135  os << "}\n";
1136 
1137  return success();
1138 }
1139 
1140 static LogicalResult printOperation(CppEmitter &emitter,
1141  emitc::FuncOp functionOp) {
1142  // We need to declare variables at top if the function has multiple blocks.
1143  if (!emitter.shouldDeclareVariablesAtTop() &&
1144  functionOp.getBlocks().size() > 1) {
1145  return functionOp.emitOpError(
1146  "with multiple blocks needs variables declared at top");
1147  }
1148 
1149  CppEmitter::Scope scope(emitter);
1150  raw_indented_ostream &os = emitter.ostream();
1151  if (functionOp.getSpecifiers()) {
1152  for (Attribute specifier : functionOp.getSpecifiersAttr()) {
1153  os << cast<StringAttr>(specifier).str() << " ";
1154  }
1155  }
1156 
1157  if (failed(emitter.emitTypes(functionOp.getLoc(),
1158  functionOp.getFunctionType().getResults())))
1159  return failure();
1160  os << " " << functionOp.getName();
1161 
1162  os << "(";
1163  Operation *operation = functionOp.getOperation();
1164  if (functionOp.isExternal()) {
1165  if (failed(printFunctionArgs(emitter, operation,
1166  functionOp.getArgumentTypes())))
1167  return failure();
1168  os << ");";
1169  return success();
1170  }
1171  if (failed(printFunctionArgs(emitter, operation, functionOp.getArguments())))
1172  return failure();
1173  os << ") {\n";
1174  if (failed(printFunctionBody(emitter, operation, functionOp.getBlocks())))
1175  return failure();
1176  os << "}\n";
1177 
1178  return success();
1179 }
1180 
1181 static LogicalResult printOperation(CppEmitter &emitter,
1182  DeclareFuncOp declareFuncOp) {
1183  CppEmitter::Scope scope(emitter);
1184  raw_indented_ostream &os = emitter.ostream();
1185 
1186  auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1187  declareFuncOp, declareFuncOp.getSymNameAttr());
1188 
1189  if (!functionOp)
1190  return failure();
1191 
1192  if (functionOp.getSpecifiers()) {
1193  for (Attribute specifier : functionOp.getSpecifiersAttr()) {
1194  os << cast<StringAttr>(specifier).str() << " ";
1195  }
1196  }
1197 
1198  if (failed(emitter.emitTypes(functionOp.getLoc(),
1199  functionOp.getFunctionType().getResults())))
1200  return failure();
1201  os << " " << functionOp.getName();
1202 
1203  os << "(";
1204  Operation *operation = functionOp.getOperation();
1205  if (failed(printFunctionArgs(emitter, operation, functionOp.getArguments())))
1206  return failure();
1207  os << ");";
1208 
1209  return success();
1210 }
1211 
1212 CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
1213  StringRef fileId)
1214  : os(os), declareVariablesAtTop(declareVariablesAtTop),
1215  fileId(fileId.str()) {
1216  valueInScopeCount.push(0);
1217  labelInScopeCount.push(0);
1218 }
1219 
1220 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1221  std::string out;
1222  llvm::raw_string_ostream ss(out);
1223  ss << getOrCreateName(op.getValue());
1224  for (auto index : op.getIndices()) {
1225  ss << "[" << getOrCreateName(index) << "]";
1226  }
1227  return out;
1228 }
1229 
1230 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1231  std::string out;
1232  llvm::raw_string_ostream ss(out);
1233  ss << getOrCreateName(op.getOperand());
1234  ss << "." << op.getMember();
1235  return out;
1236 }
1237 
1238 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1239  std::string out;
1240  llvm::raw_string_ostream ss(out);
1241  ss << getOrCreateName(op.getOperand());
1242  ss << "->" << op.getMember();
1243  return out;
1244 }
1245 
1246 void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) {
1247  if (!valueMapper.count(value))
1248  valueMapper.insert(value, str.str());
1249 }
1250 
1251 /// Return the existing or a new name for a Value.
1252 StringRef CppEmitter::getOrCreateName(Value val) {
1253  if (!valueMapper.count(val)) {
1254  assert(!hasDeferredEmission(val.getDefiningOp()) &&
1255  "cacheDeferredOpResult should have been called on this value, "
1256  "update the emitOperation function.");
1257  valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top()));
1258  }
1259  return *valueMapper.begin(val);
1260 }
1261 
1262 /// Return the existing or a new label for a Block.
1263 StringRef CppEmitter::getOrCreateName(Block &block) {
1264  if (!blockMapper.count(&block))
1265  blockMapper.insert(&block, formatv("label{0}", ++labelInScopeCount.top()));
1266  return *blockMapper.begin(&block);
1267 }
1268 
1269 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1270  switch (val) {
1271  case IntegerType::Signless:
1272  return false;
1273  case IntegerType::Signed:
1274  return false;
1275  case IntegerType::Unsigned:
1276  return true;
1277  }
1278  llvm_unreachable("Unexpected IntegerType::SignednessSemantics");
1279 }
1280 
1281 bool CppEmitter::hasValueInScope(Value val) { return valueMapper.count(val); }
1282 
1283 bool CppEmitter::hasBlockLabel(Block &block) {
1284  return blockMapper.count(&block);
1285 }
1286 
1287 LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) {
1288  auto printInt = [&](const APInt &val, bool isUnsigned) {
1289  if (val.getBitWidth() == 1) {
1290  if (val.getBoolValue())
1291  os << "true";
1292  else
1293  os << "false";
1294  } else {
1295  SmallString<128> strValue;
1296  val.toString(strValue, 10, !isUnsigned, false);
1297  os << strValue;
1298  }
1299  };
1300 
1301  auto printFloat = [&](const APFloat &val) {
1302  if (val.isFinite()) {
1303  SmallString<128> strValue;
1304  // Use default values of toString except don't truncate zeros.
1305  val.toString(strValue, 0, 0, false);
1306  os << strValue;
1307  switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1308  case llvm::APFloatBase::S_IEEEhalf:
1309  os << "f16";
1310  break;
1311  case llvm::APFloatBase::S_BFloat:
1312  os << "bf16";
1313  break;
1314  case llvm::APFloatBase::S_IEEEsingle:
1315  os << "f";
1316  break;
1317  case llvm::APFloatBase::S_IEEEdouble:
1318  break;
1319  default:
1320  llvm_unreachable("unsupported floating point type");
1321  };
1322  } else if (val.isNaN()) {
1323  os << "NAN";
1324  } else if (val.isInfinity()) {
1325  if (val.isNegative())
1326  os << "-";
1327  os << "INFINITY";
1328  }
1329  };
1330 
1331  // Print floating point attributes.
1332  if (auto fAttr = dyn_cast<FloatAttr>(attr)) {
1333  if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1334  fAttr.getType())) {
1335  return emitError(
1336  loc, "expected floating point attribute to be f16, bf16, f32 or f64");
1337  }
1338  printFloat(fAttr.getValue());
1339  return success();
1340  }
1341  if (auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1342  if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1343  dense.getElementType())) {
1344  return emitError(
1345  loc, "expected floating point attribute to be f16, bf16, f32 or f64");
1346  }
1347  os << '{';
1348  interleaveComma(dense, os, [&](const APFloat &val) { printFloat(val); });
1349  os << '}';
1350  return success();
1351  }
1352 
1353  // Print integer attributes.
1354  if (auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1355  if (auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1356  printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1357  return success();
1358  }
1359  if (auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1360  printInt(iAttr.getValue(), false);
1361  return success();
1362  }
1363  }
1364  if (auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1365  if (auto iType = dyn_cast<IntegerType>(
1366  cast<TensorType>(dense.getType()).getElementType())) {
1367  os << '{';
1368  interleaveComma(dense, os, [&](const APInt &val) {
1369  printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1370  });
1371  os << '}';
1372  return success();
1373  }
1374  if (auto iType = dyn_cast<IndexType>(
1375  cast<TensorType>(dense.getType()).getElementType())) {
1376  os << '{';
1377  interleaveComma(dense, os,
1378  [&](const APInt &val) { printInt(val, false); });
1379  os << '}';
1380  return success();
1381  }
1382  }
1383 
1384  // Print opaque attributes.
1385  if (auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1386  os << oAttr.getValue();
1387  return success();
1388  }
1389 
1390  // Print symbolic reference attributes.
1391  if (auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1392  if (sAttr.getNestedReferences().size() > 1)
1393  return emitError(loc, "attribute has more than 1 nested reference");
1394  os << sAttr.getRootReference().getValue();
1395  return success();
1396  }
1397 
1398  // Print type attributes.
1399  if (auto type = dyn_cast<TypeAttr>(attr))
1400  return emitType(loc, type.getValue());
1401 
1402  return emitError(loc, "cannot emit attribute: ") << attr;
1403 }
1404 
1405 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1406  assert(emittedExpressionPrecedence.empty() &&
1407  "Expected precedence stack to be empty");
1408  Operation *rootOp = expressionOp.getRootOp();
1409 
1410  emittedExpression = expressionOp;
1411  FailureOr<int> precedence = getOperatorPrecedence(rootOp);
1412  if (failed(precedence))
1413  return failure();
1414  pushExpressionPrecedence(precedence.value());
1415 
1416  if (failed(emitOperation(*rootOp, /*trailingSemicolon=*/false)))
1417  return failure();
1418 
1419  popExpressionPrecedence();
1420  assert(emittedExpressionPrecedence.empty() &&
1421  "Expected precedence stack to be empty");
1422  emittedExpression = nullptr;
1423 
1424  return success();
1425 }
1426 
1427 LogicalResult CppEmitter::emitOperand(Value value) {
1428  if (isPartOfCurrentExpression(value)) {
1429  Operation *def = value.getDefiningOp();
1430  assert(def && "Expected operand to be defined by an operation");
1431  FailureOr<int> precedence = getOperatorPrecedence(def);
1432  if (failed(precedence))
1433  return failure();
1434 
1435  // Sub-expressions with equal or lower precedence need to be parenthesized,
1436  // as they might be evaluated in the wrong order depending on the shape of
1437  // the expression tree.
1438  bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1439  if (encloseInParenthesis)
1440  os << "(";
1441  pushExpressionPrecedence(precedence.value());
1442 
1443  if (failed(emitOperation(*def, /*trailingSemicolon=*/false)))
1444  return failure();
1445 
1446  if (encloseInParenthesis)
1447  os << ")";
1448 
1449  popExpressionPrecedence();
1450  return success();
1451  }
1452 
1453  auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.getDefiningOp());
1454  if (expressionOp && shouldBeInlined(expressionOp))
1455  return emitExpression(expressionOp);
1456 
1457  os << getOrCreateName(value);
1458  return success();
1459 }
1460 
1461 LogicalResult CppEmitter::emitOperands(Operation &op) {
1462  return interleaveCommaWithError(op.getOperands(), os, [&](Value operand) {
1463  // If an expression is being emitted, push lowest precedence as these
1464  // operands are either wrapped by parenthesis.
1465  if (getEmittedExpression())
1466  pushExpressionPrecedence(lowestPrecedence());
1467  if (failed(emitOperand(operand)))
1468  return failure();
1469  if (getEmittedExpression())
1470  popExpressionPrecedence();
1471  return success();
1472  });
1473 }
1474 
1475 LogicalResult
1476 CppEmitter::emitOperandsAndAttributes(Operation &op,
1477  ArrayRef<StringRef> exclude) {
1478  if (failed(emitOperands(op)))
1479  return failure();
1480  // Insert comma in between operands and non-filtered attributes if needed.
1481  if (op.getNumOperands() > 0) {
1482  for (NamedAttribute attr : op.getAttrs()) {
1483  if (!llvm::is_contained(exclude, attr.getName().strref())) {
1484  os << ", ";
1485  break;
1486  }
1487  }
1488  }
1489  // Emit attributes.
1490  auto emitNamedAttribute = [&](NamedAttribute attr) -> LogicalResult {
1491  if (llvm::is_contained(exclude, attr.getName().strref()))
1492  return success();
1493  os << "/* " << attr.getName().getValue() << " */";
1494  if (failed(emitAttribute(op.getLoc(), attr.getValue())))
1495  return failure();
1496  return success();
1497  };
1498  return interleaveCommaWithError(op.getAttrs(), os, emitNamedAttribute);
1499 }
1500 
1501 LogicalResult CppEmitter::emitVariableAssignment(OpResult result) {
1502  if (!hasValueInScope(result)) {
1503  return result.getDefiningOp()->emitOpError(
1504  "result variable for the operation has not been declared");
1505  }
1506  os << getOrCreateName(result) << " = ";
1507  return success();
1508 }
1509 
1510 LogicalResult CppEmitter::emitVariableDeclaration(OpResult result,
1511  bool trailingSemicolon) {
1512  if (hasDeferredEmission(result.getDefiningOp()))
1513  return success();
1514  if (hasValueInScope(result)) {
1515  return result.getDefiningOp()->emitError(
1516  "result variable for the operation already declared");
1517  }
1518  if (failed(emitVariableDeclaration(result.getOwner()->getLoc(),
1519  result.getType(),
1520  getOrCreateName(result))))
1521  return failure();
1522  if (trailingSemicolon)
1523  os << ";\n";
1524  return success();
1525 }
1526 
1527 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1528  if (op.getExternSpecifier())
1529  os << "extern ";
1530  else if (op.getStaticSpecifier())
1531  os << "static ";
1532  if (op.getConstSpecifier())
1533  os << "const ";
1534 
1535  if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1536  op.getSymName()))) {
1537  return failure();
1538  }
1539 
1540  std::optional<Attribute> initialValue = op.getInitialValue();
1541  if (initialValue) {
1542  os << " = ";
1543  if (failed(emitAttribute(op->getLoc(), *initialValue)))
1544  return failure();
1545  }
1546 
1547  os << ";";
1548  return success();
1549 }
1550 
1551 LogicalResult CppEmitter::emitAssignPrefix(Operation &op) {
1552  // If op is being emitted as part of an expression, bail out.
1553  if (getEmittedExpression())
1554  return success();
1555 
1556  switch (op.getNumResults()) {
1557  case 0:
1558  break;
1559  case 1: {
1560  OpResult result = op.getResult(0);
1561  if (shouldDeclareVariablesAtTop()) {
1562  if (failed(emitVariableAssignment(result)))
1563  return failure();
1564  } else {
1565  if (failed(emitVariableDeclaration(result, /*trailingSemicolon=*/false)))
1566  return failure();
1567  os << " = ";
1568  }
1569  break;
1570  }
1571  default:
1572  if (!shouldDeclareVariablesAtTop()) {
1573  for (OpResult result : op.getResults()) {
1574  if (failed(emitVariableDeclaration(result, /*trailingSemicolon=*/true)))
1575  return failure();
1576  }
1577  }
1578  os << "std::tie(";
1579  interleaveComma(op.getResults(), os,
1580  [&](Value result) { os << getOrCreateName(result); });
1581  os << ") = ";
1582  }
1583  return success();
1584 }
1585 
1586 LogicalResult CppEmitter::emitLabel(Block &block) {
1587  if (!hasBlockLabel(block))
1588  return block.getParentOp()->emitError("label for block not found");
1589  // FIXME: Add feature in `raw_indented_ostream` to ignore indent for block
1590  // label instead of using `getOStream`.
1591  os.getOStream() << getOrCreateName(block) << ":\n";
1592  return success();
1593 }
1594 
1595 LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
1596  LogicalResult status =
1598  // Builtin ops.
1599  .Case<ModuleOp>([&](auto op) { return printOperation(*this, op); })
1600  // CF ops.
1601  .Case<cf::BranchOp, cf::CondBranchOp>(
1602  [&](auto op) { return printOperation(*this, op); })
1603  // EmitC ops.
1604  .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1605  emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1606  emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1607  emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1608  emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1609  emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1610  emitc::DivOp, emitc::ExpressionOp, emitc::FileOp, emitc::ForOp,
1611  emitc::FuncOp, emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp,
1612  emitc::LoadOp, emitc::LogicalAndOp, emitc::LogicalNotOp,
1613  emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp,
1614  emitc::SubOp, emitc::SwitchOp, emitc::UnaryMinusOp,
1615  emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>(
1616 
1617  [&](auto op) { return printOperation(*this, op); })
1618  // Func ops.
1619  .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1620  [&](auto op) { return printOperation(*this, op); })
1621  .Case<emitc::GetGlobalOp>([&](auto op) {
1622  cacheDeferredOpResult(op.getResult(), op.getName());
1623  return success();
1624  })
1625  .Case<emitc::LiteralOp>([&](auto op) {
1626  cacheDeferredOpResult(op.getResult(), op.getValue());
1627  return success();
1628  })
1629  .Case<emitc::MemberOp>([&](auto op) {
1630  cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
1631  return success();
1632  })
1633  .Case<emitc::MemberOfPtrOp>([&](auto op) {
1634  cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
1635  return success();
1636  })
1637  .Case<emitc::SubscriptOp>([&](auto op) {
1638  cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
1639  return success();
1640  })
1641  .Default([&](Operation *) {
1642  return op.emitOpError("unable to find printer for op");
1643  });
1644 
1645  if (failed(status))
1646  return failure();
1647 
1648  if (hasDeferredEmission(&op))
1649  return success();
1650 
1651  if (getEmittedExpression() ||
1652  (isa<emitc::ExpressionOp>(op) &&
1653  shouldBeInlined(cast<emitc::ExpressionOp>(op))))
1654  return success();
1655 
1656  // Never emit a semicolon for some operations, especially if endening with
1657  // `}`.
1658  trailingSemicolon &=
1659  !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
1660  emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(
1661  op);
1662 
1663  os << (trailingSemicolon ? ";\n" : "\n");
1664 
1665  return success();
1666 }
1667 
1668 LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
1669  StringRef name) {
1670  if (auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1671  if (failed(emitType(loc, arrType.getElementType())))
1672  return failure();
1673  os << " " << name;
1674  for (auto dim : arrType.getShape()) {
1675  os << "[" << dim << "]";
1676  }
1677  return success();
1678  }
1679  if (failed(emitType(loc, type)))
1680  return failure();
1681  os << " " << name;
1682  return success();
1683 }
1684 
1685 LogicalResult CppEmitter::emitType(Location loc, Type type) {
1686  if (auto iType = dyn_cast<IntegerType>(type)) {
1687  switch (iType.getWidth()) {
1688  case 1:
1689  return (os << "bool"), success();
1690  case 8:
1691  case 16:
1692  case 32:
1693  case 64:
1694  if (shouldMapToUnsigned(iType.getSignedness()))
1695  return (os << "uint" << iType.getWidth() << "_t"), success();
1696  else
1697  return (os << "int" << iType.getWidth() << "_t"), success();
1698  default:
1699  return emitError(loc, "cannot emit integer type ") << type;
1700  }
1701  }
1702  if (auto fType = dyn_cast<FloatType>(type)) {
1703  switch (fType.getWidth()) {
1704  case 16: {
1705  if (llvm::isa<Float16Type>(type))
1706  return (os << "_Float16"), success();
1707  else if (llvm::isa<BFloat16Type>(type))
1708  return (os << "__bf16"), success();
1709  else
1710  return emitError(loc, "cannot emit float type ") << type;
1711  }
1712  case 32:
1713  return (os << "float"), success();
1714  case 64:
1715  return (os << "double"), success();
1716  default:
1717  return emitError(loc, "cannot emit float type ") << type;
1718  }
1719  }
1720  if (auto iType = dyn_cast<IndexType>(type))
1721  return (os << "size_t"), success();
1722  if (auto sType = dyn_cast<emitc::SizeTType>(type))
1723  return (os << "size_t"), success();
1724  if (auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1725  return (os << "ssize_t"), success();
1726  if (auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1727  return (os << "ptrdiff_t"), success();
1728  if (auto tType = dyn_cast<TensorType>(type)) {
1729  if (!tType.hasRank())
1730  return emitError(loc, "cannot emit unranked tensor type");
1731  if (!tType.hasStaticShape())
1732  return emitError(loc, "cannot emit tensor type with non static shape");
1733  os << "Tensor<";
1734  if (isa<ArrayType>(tType.getElementType()))
1735  return emitError(loc, "cannot emit tensor of array type ") << type;
1736  if (failed(emitType(loc, tType.getElementType())))
1737  return failure();
1738  auto shape = tType.getShape();
1739  for (auto dimSize : shape) {
1740  os << ", ";
1741  os << dimSize;
1742  }
1743  os << ">";
1744  return success();
1745  }
1746  if (auto tType = dyn_cast<TupleType>(type))
1747  return emitTupleType(loc, tType.getTypes());
1748  if (auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1749  os << oType.getValue();
1750  return success();
1751  }
1752  if (auto aType = dyn_cast<emitc::ArrayType>(type)) {
1753  if (failed(emitType(loc, aType.getElementType())))
1754  return failure();
1755  for (auto dim : aType.getShape())
1756  os << "[" << dim << "]";
1757  return success();
1758  }
1759  if (auto lType = dyn_cast<emitc::LValueType>(type))
1760  return emitType(loc, lType.getValueType());
1761  if (auto pType = dyn_cast<emitc::PointerType>(type)) {
1762  if (isa<ArrayType>(pType.getPointee()))
1763  return emitError(loc, "cannot emit pointer to array type ") << type;
1764  if (failed(emitType(loc, pType.getPointee())))
1765  return failure();
1766  os << "*";
1767  return success();
1768  }
1769  return emitError(loc, "cannot emit type ") << type;
1770 }
1771 
1772 LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
1773  switch (types.size()) {
1774  case 0:
1775  os << "void";
1776  return success();
1777  case 1:
1778  return emitType(loc, types.front());
1779  default:
1780  return emitTupleType(loc, types);
1781  }
1782 }
1783 
1784 LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
1785  if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1786  return emitError(loc, "cannot emit tuple of array type");
1787  }
1788  os << "std::tuple<";
1789  if (failed(interleaveCommaWithError(
1790  types, os, [&](Type type) { return emitType(loc, type); })))
1791  return failure();
1792  os << ">";
1793  return success();
1794 }
1795 
1796 LogicalResult emitc::translateToCpp(Operation *op, raw_ostream &os,
1797  bool declareVariablesAtTop,
1798  StringRef fileId) {
1799  CppEmitter emitter(os, declareVariablesAtTop, fileId);
1800  return emitter.emitOperation(*op, /*trailingSemicolon=*/false);
1801 }
static LogicalResult printCallOperation(CppEmitter &emitter, Operation *callOp, StringRef callee)
static bool shouldBeInlined(ExpressionOp expressionOp)
Determine whether expression expressionOp should be emitted inline, i.e.
LogicalResult interleaveCommaWithError(const Container &c, raw_ostream &os, UnaryFunctor eachFn)
static FailureOr< int > getOperatorPrecedence(Operation *operation)
Return the precedence of a operator as an integer, higher values imply higher precedence.
static LogicalResult printFunctionArgs(CppEmitter &emitter, Operation *functionOp, ArrayRef< Type > arguments)
static LogicalResult printFunctionBody(CppEmitter &emitter, Operation *functionOp, Region::BlockListType &blocks)
static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation, Attribute value)
static LogicalResult emitSwitchCase(CppEmitter &emitter, raw_indented_ostream &os, Region &region)
LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator)
static LogicalResult printOperation(CppEmitter &emitter, emitc::ConstantOp constantOp)
static LogicalResult printUnaryOperation(CppEmitter &emitter, Operation *operation, StringRef unaryOperator)
static bool hasDeferredEmission(Operation *op)
Determine whether expression op should be emitted in a deferred way.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class represents an argument of a Block.
Definition: Value.h:309
Block represents an ordered list of Operations.
Definition: Block.h:33
BlockArgListType getArguments()
Definition: Block.h:87
Block * getSuccessor(unsigned i)
Definition: Block.cpp:261
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:33
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:164
This is a value defined by a result of an operation.
Definition: Value.h:447
Operation * getOwner() const
Returns the operation that owns this result.
Definition: Value.h:456
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Value getOperand(unsigned idx)
Definition: Operation.h:350
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:407
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Definition: Operation.h:797
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
unsigned getNumOperands()
Definition: Operation.h:346
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Definition: Operation.h:512
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:378
result_range getResults()
Definition: Operation.h:415
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:673
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:404
This class provides iteration over the held operations of blocks directly within a region.
Definition: Region.h:134
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
iterator_range< OpIterator > getOps()
Definition: Region.h:172
llvm::iplist< Block > BlockListType
Definition: Region.h:44
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
Definition: Region.h:170
bool empty()
Definition: Region.h:60
MutableArrayRef< BlockArgument > BlockArgListType
Definition: Region.h:80
OpIterator op_end()
Definition: Region.h:171
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:105
user_range getUsers() const
Definition: Value.h:218
bool hasOneUse() const
Returns true if this value has exactly one use.
Definition: Value.h:197
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:33
static WalkResult skip()
Definition: Visitors.h:52
static WalkResult advance()
Definition: Visitors.h:51
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & unindent()
Decreases the indent and returning this raw_indented_ostream.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
LogicalResult translateToCpp(Operation *op, raw_ostream &os, bool declareVariablesAtTop=false, StringRef fileId={})
Translates the given operation to C++ code.
std::variant< StringRef, Placeholder > ReplacementItem
Definition: EmitC.h:54
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This iterator enumerates the elements in "forward" order.
Definition: Visitors.h:65