| //===- CppEmitter.h - Helpers to create C++ emitter -------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines helpers to emit C++ code using the EmitC dialect. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef EMITC_TARGET_CPP_CPPEMITTER_H |
| #define EMITC_TARGET_CPP_CPPEMITTER_H |
| |
| #include "mlir/IR/BuiltinTypes.h" |
| #include "mlir/IR/Value.h" |
| #include "mlir/Support/IndentedOstream.h" |
| #include "llvm/ADT/ScopedHashTable.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <stack> |
| |
| namespace mlir { |
| namespace emitc { |
| |
| /// Convenience functions to produce interleaved output with functions returning |
| /// a LogicalResult. This is different than those in STL as functions used on |
| /// each element doesn't return a string. |
| template <typename ForwardIterator, typename UnaryFunctor, |
| typename NullaryFunctor> |
| inline LogicalResult |
| interleaveWithError(ForwardIterator begin, ForwardIterator end, |
| UnaryFunctor eachFn, NullaryFunctor betweenFn) { |
| if (begin == end) |
| return success(); |
| if (failed(eachFn(*begin))) |
| return failure(); |
| ++begin; |
| for (; begin != end; ++begin) { |
| betweenFn(); |
| if (failed(eachFn(*begin))) |
| return failure(); |
| } |
| return success(); |
| } |
| |
| template <typename Container, typename UnaryFunctor, typename NullaryFunctor> |
| inline LogicalResult interleaveWithError(const Container &c, |
| UnaryFunctor eachFn, |
| NullaryFunctor betweenFn) { |
| return interleaveWithError(c.begin(), c.end(), eachFn, betweenFn); |
| } |
| |
| template <typename Container, typename UnaryFunctor> |
| inline LogicalResult interleaveCommaWithError(const Container &c, |
| raw_ostream &os, |
| UnaryFunctor eachFn) { |
| return interleaveWithError(c.begin(), c.end(), eachFn, [&]() { os << ", "; }); |
| } |
| |
| /// 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(Operation &op, 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(Operation &op, 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(Operation &op, ArrayRef<Type> types); |
| |
| /// Emits array of types as a std::tuple of the emitted types independently of |
| /// the array size. |
| LogicalResult emitTupleType(Operation &op, 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 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 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); |
| |
| /// Return the existing or a new name for a Value. |
| StringRef getOrCreateName(Value val); |
| |
| /// Return the existing or a new label of a Block. |
| StringRef getOrCreateName(Block &block); |
| |
| /// Whether to map an mlir integer to a signed integer in C++. |
| bool shouldMapToSigned(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; }; |
| |
| 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; |
| }; |
| |
| /// 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 |
| /// arguments are declared at the beginning of the function. |
| LogicalResult translateToCpp(Operation *op, raw_ostream &os, |
| bool declareVariablesAtTop = false); |
| } // namespace emitc |
| } // namespace mlir |
| |
| #endif // EMITC_TARGET_CPP_CPPEMITTER_H |