compiler.hpp 7.5 KB
Newer Older
1
//*****************************************************************************
nmostafa's avatar
nmostafa committed
2
// Copyright 2017-2019 Intel Corporation
3 4 5 6 7 8 9 10 11 12 13 14 15
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
16

17 18
// NOTE: This file follows nGraph format style.
// Follows nGraph naming convention for public APIs only, else MLIR naming convention.
19

20 21
#pragma once

Nagy Mostafa's avatar
Nagy Mostafa committed
22
#include "memory_manager.hpp"
23 24
#include "ngraph/node.hpp"

25
#include <mlir/ExecutionEngine/ExecutionEngine.h>
26
#include <mlir/ExecutionEngine/MemRefUtils.h>
27 28 29 30
#include <mlir/IR/Builders.h>
#include <mlir/IR/Module.h>
#include <mlir/IR/Types.h>

31 32 33
#include <typeindex>
#include <unordered_map>
#include <vector>
Nagy Mostafa's avatar
Nagy Mostafa committed
34

35 36 37 38 39
namespace llvm
{
    class TargetMachine;
}

40 41
namespace ngraph
{
42 43 44 45 46 47 48 49
    namespace descriptor
    {
        class Tensor;
    }
    namespace element
    {
        class Type;
    }
50 51 52 53
    namespace op
    {
        class CompiledKernel;
    }
54 55
    namespace runtime
    {
56
        namespace ngmlir
57
        {
58 59 60
            /// This class is the entry point to MLIR from nGraph. It drives the conversion of
            /// nGraph sub-graphs, represented with CompiledKernel nodes, to MLIR nGraph dialect
            /// and its lowering, optimization and execution using LLVM-based MLIR execution engine.
61 62
            class MLIRCompiler
            {
Nagy Mostafa's avatar
Nagy Mostafa committed
63
            public:
64
                /// Initializes MLIR environment. It must be called only once per execution.
Nagy Mostafa's avatar
Nagy Mostafa committed
65 66
                static void init_mlir();

67 68 69 70
            public:
                using TensorList = std::vector<descriptor::Tensor*>;
                using TypeList = llvm::SmallVector<mlir::Type, 4>;

71
                MLIRCompiler(const ngraph::op::CompiledKernel* compiled_kernel)
72
                    : m_compiledKernel(compiled_kernel)
nmostafa's avatar
nmostafa committed
73 74
                {
                }
75

76 77
                /// Compiles a subgraph with MLIR
                void compile();
nmostafa's avatar
nmostafa committed
78

79
                /// Executes a pre-compiled subgraph
80
                void run(std::vector<void*>& externalTensors);
81 82 83 84

            private:
                struct TensorInfo
                {
85 86
                    // MLIR values this tensor maps to.
                    mlir::Value* m_value;
87 88 89
                };

            private:
90 91
                void buildNgDialectModule();
                void lowerNgDialect();
92
                void optimizeNgDialect();
nmostafa's avatar
nmostafa committed
93
                void optimize();
94
                void bindArguments(std::vector<void*>& externalTensors);
95 96 97
                void execute();
                void cleanup();

98 99 100
                mlir::Type getMlirType(const descriptor::Tensor* tensor);
                mlir::Type getMlirType(const element::Type& type);
                mlir::Type getMlirType(const ngraph::Node* node);
101

102 103
                TensorInfo getTensorValue(descriptor::Tensor* tensor);
                void updateTensorValue(descriptor::Tensor* tensor, mlir::Value* value);
Nagy Mostafa's avatar
Nagy Mostafa committed
104

105
                void buildNgDialect();
106

nmostafa's avatar
nmostafa committed
107
                template <typename Op>
108
                static mlir::Operation* createOp(MLIRCompiler& compiler, const ngraph::Node* ngNode)
109
                {
110
                    throw std::runtime_error("Unimplemented op '" + ngNode->description() +
111 112 113
                                             "' in MLIR Compiler");
                }

nmostafa's avatar
nmostafa committed
114 115
                // Generic op lowerer to ng dialect.
                // Simply maps ngraph tensors to values and generate an OP. No op-specific logic.
nmostafa's avatar
nmostafa committed
116
                template <typename Op>
117
                mlir::Operation* createGenericOp(const ngraph::Node* ngNode);
Adam Procter's avatar
Adam Procter committed
118

119
                template <typename RedOp>
120
                mlir::Operation* createIndexReduction(const ngraph::Node* ngNode);
nmostafa's avatar
nmostafa committed
121

122
                void createReturn();
123

Nagy Mostafa's avatar
Nagy Mostafa committed
124
                /// Helper to create memref arguments for MLIR function signature
125
                llvm::SmallVector<void*, 8> allocateMemrefArgs();
Nagy Mostafa's avatar
Nagy Mostafa committed
126 127

                /// Helper to allocate a mem ref object. Handles static shapes only for now.
128
                mlir::StaticFloatMemRef* allocateMemrefDescriptor();
Nagy Mostafa's avatar
Nagy Mostafa committed
129

130
                /// Helper to dump MLIR module into llvm::dbgs prepended by the message \p msg.
131
                void dumpMlirModule(const std::string msg);
132

133 134
                /// Converts nGraph shape-like types \p ng_shape to MLIR shape \p mlir_shape.
                template <typename T>
135
                void getMlirShape(T ngShape, llvm::SmallVectorImpl<int64_t>& mlirShape);
136 137 138

                /// Converts an ngraph shape to an I64 array attribute
                template <typename T>
139
                mlir::ArrayAttr getShapeAsAttr(T ngShape);
140

141
            private:
142
                // Sub-graph to be compiled and executed with MLIR.
143
                const ngraph::op::CompiledKernel* m_compiledKernel;
144 145

                // Pointers to externally allocated memory for sub-graph's input and output tensors.
146
                std::vector<void*>* m_externalTensors;
147 148

                // Arguments for the MLIR function generated for the nGraph sub-graph.
149
                llvm::SmallVector<void*, 8> m_invokeArgs;
150 151 152

                // MLIR context that holds all the MLIR information related to the sub-graph
                // compilation.
153
                mlir::MLIRContext m_context;
154

155
                mlir::OwningModuleRef m_module;
156
                std::unique_ptr<mlir::OpBuilder> m_builder;
157
                std::unique_ptr<mlir::ExecutionEngine> m_engine;
158 159 160 161

                using TensorToInfo = std::pair<descriptor::Tensor*, TensorInfo>;
                using TensorToInfoMap = std::unordered_map<descriptor::Tensor*, TensorInfo>;
                using MLIRCompOpFunction =
162
                    std::function<mlir::Operation*(MLIRCompiler& compiler, const ngraph::Node*)>;
163 164 165 166
                using MLIRCompOpMap = std::unordered_map<std::type_index, MLIRCompOpFunction>;

                // Maps tensor to the value it represents in the IR
                // use for MLIR dialect gen
167 168
                TensorToInfoMap m_tensorToValueMap;
                static const MLIRCompOpMap opDispatcher;
Nagy Mostafa's avatar
Nagy Mostafa committed
169

170 171 172 173 174 175 176 177 178
                // Optimization level used by MLIR and LLVM compilers. It's based on LLVM CG
                // optimization levels:
                // enum Level {
                //   None,        // -O0
                //   Less,        // -O1
                //   Default,     // -O2, -Os
                //   Aggressive   // -O3
                // };
                static llvm::CodeGenOpt::Level mlirOptLevel;
179 180 181 182 183 184 185 186 187

                // LLVM target machine to be used by this MLIR compiler instance to retrieve
                // information about target features.
                // TODO: Note that, unfortunatelly, MLIR/OrcJIT execution engine creates its own
                // target machine for compilation internally. This target machine is for non-JIT
                // related stuff. We should change OrcJIT API so that we can pass an external target
                // machine or configuration flags.
                // TODO: Move target machine to external nGraph backend when multiple backends start
                // to use MLIR.
188
                static std::unique_ptr<llvm::TargetMachine> targetMachine;
189 190 191 192
            };
        }
    }
}