[Mlir-commits] [mlir] Moving CppEmitter to header file. (PR #106201)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Aug 27 02:03:09 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: None (ddubov100)

<details>
<summary>Changes</summary>

In projects lowering MLIR, there might be project-specific translators that support the translation of custom dialects. For projects targeting code from the C family, it would be advantageous to use as many EmitC dialect operations as possible. If they want to benefit from EmitC dialect translation, they have two options:

1. Reimplement TranslateToCpp in their translators.
2. Lower everything to the EmitC dialect, though it might take a lot of time for the EmitC dialect to support all required features.

It might be beneficial for such projects to use CppEmitter as a standalone class with a clear API to translate EmitC dialect operations, allowing for custom translation of unsupported operations.

This PR moves CppEmitter to a header file to enable this functionality.

---
Full diff: https://github.com/llvm/llvm-project/pull/106201.diff


2 Files Affected:

- (modified) mlir/include/mlir/Target/Cpp/CppEmitter.h (+155) 
- (modified) mlir/lib/Target/Cpp/TranslateToCpp.cpp (+38-171) 


``````````diff
diff --git a/mlir/include/mlir/Target/Cpp/CppEmitter.h b/mlir/include/mlir/Target/Cpp/CppEmitter.h
index 99d8696cc8e077..72fba26a0f054a 100644
--- a/mlir/include/mlir/Target/Cpp/CppEmitter.h
+++ b/mlir/include/mlir/Target/Cpp/CppEmitter.h
@@ -13,12 +13,167 @@
 #ifndef MLIR_TARGET_CPP_CPPEMITTER_H
 #define MLIR_TARGET_CPP_CPPEMITTER_H
 
+#include "mlir/Dialect/EmitC/IR/EmitC.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/Support/IndentedOstream.h"
+
 #include "mlir/Support/LLVM.h"
+#include "llvm/ADT/ScopedHashTable.h"
+#include "llvm/Support/raw_ostream.h"
+#include <stack>
 
 namespace mlir {
 class Operation;
 namespace emitc {
 
+/// Emitter that uses dialect specific emitters to emit C++ code.
+struct CppEmitter {
+  explicit CppEmitter(raw_ostream &os, bool declareVariablesAtTop);
+
+  /// Emits attribute or returns failure.
+  LogicalResult emitAttribute(Location loc, Attribute attr);
+
+  /// Emits operation 'op' with/without training semicolon or returns failure.
+  LogicalResult emitOperation(Operation &op, bool trailingSemicolon);
+
+  /// Emits type 'type' or returns failure.
+  LogicalResult emitType(Location loc, Type type);
+
+  /// Emits array of types as a std::tuple of the emitted types.
+  /// - emits void for an empty array;
+  /// - emits the type of the only element for arrays of size one;
+  /// - emits a std::tuple otherwise;
+  LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
+
+  /// Emits array of types as a std::tuple of the emitted types independently of
+  /// the array size.
+  LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
+
+  /// Emits an assignment for a variable which has been declared previously.
+  LogicalResult emitVariableAssignment(OpResult result);
+
+  /// Emits a variable declaration for a result of an operation.
+  LogicalResult emitVariableDeclaration(OpResult result,
+                                        bool trailingSemicolon);
+
+  /// Emits a declaration of a variable with the given type and name.
+  LogicalResult emitVariableDeclaration(Location loc, Type type,
+                                        StringRef name);
+
+  /// Emits the variable declaration and assignment prefix for 'op'.
+  /// - emits separate variable followed by std::tie for multi-valued operation;
+  /// - emits single type followed by variable for single result;
+  /// - emits nothing if no value produced by op;
+  /// Emits final '=' operator where a type is produced. Returns failure if
+  /// any result type could not be converted.
+  LogicalResult emitAssignPrefix(Operation &op);
+
+  /// Emits a global variable declaration or definition.
+  LogicalResult emitGlobalVariable(GlobalOp op);
+
+  /// Emits a label for the block.
+  LogicalResult emitLabel(Block &block);
+
+  /// Emits the operands and atttributes of the operation. All operands are
+  /// emitted first and then all attributes in alphabetical order.
+  LogicalResult emitOperandsAndAttributes(Operation &op,
+                                          ArrayRef<StringRef> exclude = {});
+
+  /// Emits the operands of the operation. All operands are emitted in order.
+  LogicalResult emitOperands(Operation &op);
+
+  /// Emits value as an operands of an operation
+  LogicalResult emitOperand(Value value);
+
+  /// Emit an expression as a C expression.
+  LogicalResult emitExpression(ExpressionOp expressionOp);
+
+  /// Insert the expression representing the operation into the value cache.
+  void cacheDeferredOpResult(Value value, StringRef str);
+
+  /// Return the existing or a new name for a Value.
+  StringRef getOrCreateName(Value val);
+
+  // Returns the textual representation of a subscript operation.
+  std::string getSubscriptName(emitc::SubscriptOp op);
+
+  // Returns the textual representation of a member (of object) operation.
+  std::string createMemberAccess(emitc::MemberOp op);
+
+  // Returns the textual representation of a member of pointer operation.
+  std::string createMemberAccess(emitc::MemberOfPtrOp op);
+
+  /// Return the existing or a new label of a Block.
+  StringRef getOrCreateName(Block &block);
+
+  /// Whether to map an mlir integer to a unsigned integer in C++.
+  bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
+
+  /// RAII helper function to manage entering/exiting C++ scopes.
+  struct Scope {
+    Scope(CppEmitter &emitter);
+    ~Scope();
+
+  private:
+    llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
+    llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
+    CppEmitter &emitter;
+  };
+
+  /// Returns wether the Value is assigned to a C++ variable in the scope.
+  bool hasValueInScope(Value val);
+
+  // Returns whether a label is assigned to the block.
+  bool hasBlockLabel(Block &block);
+
+  /// Returns the output stream.
+  raw_indented_ostream &ostream() { return os; };
+
+  /// Returns if all variables for op results and basic block arguments need to
+  /// be declared at the beginning of a function.
+  bool shouldDeclareVariablesAtTop() { return declareVariablesAtTop; };
+
+  /// Get expression currently being emitted.
+  ExpressionOp getEmittedExpression() { return emittedExpression; }
+
+  /// Determine whether given value is part of the expression potentially being
+  /// emitted.
+  bool isPartOfCurrentExpression(Value value);
+
+private:
+  using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
+  using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
+
+  /// Output stream to emit to.
+  raw_indented_ostream os;
+
+  /// Boolean to enforce that all variables for op results and block
+  /// arguments are declared at the beginning of the function. This also
+  /// includes results from ops located in nested regions.
+  bool declareVariablesAtTop;
+
+  /// Map from value to name of C++ variable that contain the name.
+  ValueMapper valueMapper;
+
+  /// Map from block to name of C++ label.
+  BlockMapper blockMapper;
+
+  /// The number of values in the current scope. This is used to declare the
+  /// names of values in a scope.
+  std::stack<int64_t> valueInScopeCount;
+  std::stack<int64_t> labelInScopeCount;
+
+  /// State of the current expression being emitted.
+  ExpressionOp emittedExpression;
+  SmallVector<int> emittedExpressionPrecedence;
+
+  void pushExpressionPrecedence(int precedence);
+  void popExpressionPrecedence();
+  static int lowestPrecedence();
+  int getExpressionPrecedence();
+};
+
 /// Translates the given operation to C++ code. The operation or operations in
 /// the region of 'op' need almost all be in EmitC dialect. The parameter
 /// 'declareVariablesAtTop' enforces that all variables for op results and block
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 1dadb9dd691e70..e9045548730c96 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -33,6 +33,44 @@ using namespace mlir;
 using namespace mlir::emitc;
 using llvm::formatv;
 
+CppEmitter::Scope::Scope(CppEmitter &emitter)
+    : valueMapperScope(emitter.valueMapper),
+      blockMapperScope(emitter.blockMapper), emitter(emitter) {
+  emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
+  emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
+}
+
+CppEmitter::Scope::~Scope() {
+  emitter.valueInScopeCount.pop();
+  emitter.labelInScopeCount.pop();
+}
+
+bool CppEmitter::isPartOfCurrentExpression(Value value) {
+  if (!emittedExpression)
+    return false;
+  Operation *def = value.getDefiningOp();
+  if (!def)
+    return false;
+  auto operandExpression = dyn_cast<ExpressionOp>(def->getParentOp());
+  return operandExpression == emittedExpression;
+}
+
+void CppEmitter::pushExpressionPrecedence(int precedence) {
+  emittedExpressionPrecedence.push_back(precedence);
+}
+
+void CppEmitter::popExpressionPrecedence() {
+  emittedExpressionPrecedence.pop_back();
+}
+
+int CppEmitter::lowestPrecedence() { return 0; }
+
+int CppEmitter::getExpressionPrecedence() {
+  if (emittedExpressionPrecedence.empty())
+    return lowestPrecedence();
+  return emittedExpressionPrecedence.back();
+}
+
 /// Convenience functions to produce interleaved output with functions returning
 /// a LogicalResult. This is different than those in STLExtras as functions used
 /// on each element doesn't return a string.
@@ -111,177 +149,6 @@ static FailureOr<int> getOperatorPrecedence(Operation *operation) {
       .Default([](auto op) { return op->emitError("unsupported operation"); });
 }
 
-namespace {
-/// Emitter that uses dialect specific emitters to emit C++ code.
-struct CppEmitter {
-  explicit CppEmitter(raw_ostream &os, bool declareVariablesAtTop);
-
-  /// Emits attribute or returns failure.
-  LogicalResult emitAttribute(Location loc, Attribute attr);
-
-  /// Emits operation 'op' with/without training semicolon or returns failure.
-  LogicalResult emitOperation(Operation &op, bool trailingSemicolon);
-
-  /// Emits type 'type' or returns failure.
-  LogicalResult emitType(Location loc, Type type);
-
-  /// Emits array of types as a std::tuple of the emitted types.
-  /// - emits void for an empty array;
-  /// - emits the type of the only element for arrays of size one;
-  /// - emits a std::tuple otherwise;
-  LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
-
-  /// Emits array of types as a std::tuple of the emitted types independently of
-  /// the array size.
-  LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
-
-  /// Emits an assignment for a variable which has been declared previously.
-  LogicalResult emitVariableAssignment(OpResult result);
-
-  /// Emits a variable declaration for a result of an operation.
-  LogicalResult emitVariableDeclaration(OpResult result,
-                                        bool trailingSemicolon);
-
-  /// Emits a declaration of a variable with the given type and name.
-  LogicalResult emitVariableDeclaration(Location loc, Type type,
-                                        StringRef name);
-
-  /// Emits the variable declaration and assignment prefix for 'op'.
-  /// - emits separate variable followed by std::tie for multi-valued operation;
-  /// - emits single type followed by variable for single result;
-  /// - emits nothing if no value produced by op;
-  /// Emits final '=' operator where a type is produced. Returns failure if
-  /// any result type could not be converted.
-  LogicalResult emitAssignPrefix(Operation &op);
-
-  /// Emits a global variable declaration or definition.
-  LogicalResult emitGlobalVariable(GlobalOp op);
-
-  /// Emits a label for the block.
-  LogicalResult emitLabel(Block &block);
-
-  /// Emits the operands and atttributes of the operation. All operands are
-  /// emitted first and then all attributes in alphabetical order.
-  LogicalResult emitOperandsAndAttributes(Operation &op,
-                                          ArrayRef<StringRef> exclude = {});
-
-  /// Emits the operands of the operation. All operands are emitted in order.
-  LogicalResult emitOperands(Operation &op);
-
-  /// Emits value as an operands of an operation
-  LogicalResult emitOperand(Value value);
-
-  /// Emit an expression as a C expression.
-  LogicalResult emitExpression(ExpressionOp expressionOp);
-
-  /// Insert the expression representing the operation into the value cache.
-  void cacheDeferredOpResult(Value value, StringRef str);
-
-  /// Return the existing or a new name for a Value.
-  StringRef getOrCreateName(Value val);
-
-  // Returns the textual representation of a subscript operation.
-  std::string getSubscriptName(emitc::SubscriptOp op);
-
-  // Returns the textual representation of a member (of object) operation.
-  std::string createMemberAccess(emitc::MemberOp op);
-
-  // Returns the textual representation of a member of pointer operation.
-  std::string createMemberAccess(emitc::MemberOfPtrOp op);
-
-  /// Return the existing or a new label of a Block.
-  StringRef getOrCreateName(Block &block);
-
-  /// Whether to map an mlir integer to a unsigned integer in C++.
-  bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
-
-  /// RAII helper function to manage entering/exiting C++ scopes.
-  struct Scope {
-    Scope(CppEmitter &emitter)
-        : valueMapperScope(emitter.valueMapper),
-          blockMapperScope(emitter.blockMapper), emitter(emitter) {
-      emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
-      emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
-    }
-    ~Scope() {
-      emitter.valueInScopeCount.pop();
-      emitter.labelInScopeCount.pop();
-    }
-
-  private:
-    llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
-    llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
-    CppEmitter &emitter;
-  };
-
-  /// Returns wether the Value is assigned to a C++ variable in the scope.
-  bool hasValueInScope(Value val);
-
-  // Returns whether a label is assigned to the block.
-  bool hasBlockLabel(Block &block);
-
-  /// Returns the output stream.
-  raw_indented_ostream &ostream() { return os; };
-
-  /// Returns if all variables for op results and basic block arguments need to
-  /// be declared at the beginning of a function.
-  bool shouldDeclareVariablesAtTop() { return declareVariablesAtTop; };
-
-  /// Get expression currently being emitted.
-  ExpressionOp getEmittedExpression() { return emittedExpression; }
-
-  /// Determine whether given value is part of the expression potentially being
-  /// emitted.
-  bool isPartOfCurrentExpression(Value value) {
-    if (!emittedExpression)
-      return false;
-    Operation *def = value.getDefiningOp();
-    if (!def)
-      return false;
-    auto operandExpression = dyn_cast<ExpressionOp>(def->getParentOp());
-    return operandExpression == emittedExpression;
-  };
-
-private:
-  using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
-  using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
-
-  /// Output stream to emit to.
-  raw_indented_ostream os;
-
-  /// Boolean to enforce that all variables for op results and block
-  /// arguments are declared at the beginning of the function. This also
-  /// includes results from ops located in nested regions.
-  bool declareVariablesAtTop;
-
-  /// Map from value to name of C++ variable that contain the name.
-  ValueMapper valueMapper;
-
-  /// Map from block to name of C++ label.
-  BlockMapper blockMapper;
-
-  /// The number of values in the current scope. This is used to declare the
-  /// names of values in a scope.
-  std::stack<int64_t> valueInScopeCount;
-  std::stack<int64_t> labelInScopeCount;
-
-  /// State of the current expression being emitted.
-  ExpressionOp emittedExpression;
-  SmallVector<int> emittedExpressionPrecedence;
-
-  void pushExpressionPrecedence(int precedence) {
-    emittedExpressionPrecedence.push_back(precedence);
-  }
-  void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
-  static int lowestPrecedence() { return 0; }
-  int getExpressionPrecedence() {
-    if (emittedExpressionPrecedence.empty())
-      return lowestPrecedence();
-    return emittedExpressionPrecedence.back();
-  }
-};
-} // namespace
-
 /// Determine whether expression \p op should be emitted in a deferred way.
 static bool hasDeferredEmission(Operation *op) {
   return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,

``````````

</details>


https://github.com/llvm/llvm-project/pull/106201


More information about the Mlir-commits mailing list