Unverified Commit 0ef1c2f9 authored by Jai Menon's avatar Jai Menon Committed by GitHub

Merge pull request #243 from NervanaSystems/bob/static_compiler

Bob/static compiler
parents 7b9b35d3 1ac8d820
......@@ -106,12 +106,14 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
set(SRC ${SRC}
codegen/code_writer.cpp
codegen/compiler.cpp
codegen/execution_engine.cpp
runtime/cpu/call_frame.cpp
runtime/cpu/cpu_backend.cpp
runtime/cpu/cpu_manager.cpp
runtime/cpu/cpu_kernels.cpp
runtime/cpu/emitter.cpp
runtime/cpu/external_function.cpp
runtime/cpu/memory_handler.cpp
runtime/cpu/tensor_view.cpp
)
# LLVM binary builds are typically built without RTTI
......
......@@ -45,13 +45,15 @@
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/util.hpp"
// TODO: Fix leaks
// #define USE_CACHE
using namespace clang;
using namespace llvm;
using namespace llvm::opt;
......@@ -59,26 +61,36 @@ using namespace std;
using namespace ngraph::codegen;
static std::string GetExecutablePath(const char* Argv0)
static HeaderCache s_header_cache;
static StaticCompiler s_static_compiler;
static std::mutex m_mutex;
Compiler::Compiler()
{
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
execution_state::execution_state()
: m_execution_engine{nullptr}
, precompiled_headers_enabled(false)
, debuginfo_enabled(false)
Compiler::~Compiler()
{
}
execution_state::~execution_state()
std::unique_ptr<llvm::Module> Compiler::compile(const std::string& source)
{
lock_guard<mutex> lock(m_mutex);
return s_static_compiler.compile(source);
}
std::unique_ptr<llvm::Module> execution_state::compile(const string& source, const string& name)
static std::string GetExecutablePath(const char* Argv0)
{
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
StaticCompiler::StaticCompiler()
: m_precompiled_headers_enabled(false)
, m_debuginfo_enabled(false)
, m_source_name("code.cpp")
{
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
......@@ -87,7 +99,7 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
// Prepare compilation arguments
vector<const char*> args;
args.push_back(name.c_str());
args.push_back(m_source_name.c_str());
// Prepare DiagnosticEngine
DiagnosticOptions DiagOpts;
......@@ -97,45 +109,76 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
new DiagnosticsEngine(pDiagIDs, &DiagOpts, textDiagPrinter);
// Create and initialize CompilerInstance
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
Clang->createDiagnostics();
m_compiler = std::unique_ptr<CompilerInstance>(new CompilerInstance());
m_compiler->createDiagnostics();
// Initialize CompilerInvocation
CompilerInvocation::CreateFromArgs(
Clang->getInvocation(), &args[0], &args[0] + args.size(), *pDiagnosticsEngine);
m_compiler->getInvocation(), &args[0], &args[0] + args.size(), *pDiagnosticsEngine);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
Clang->getHeaderSearchOpts().ResourceDir.empty())
if (m_compiler->getHeaderSearchOpts().UseBuiltinIncludes &&
m_compiler->getHeaderSearchOpts().ResourceDir.empty())
{
void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
auto path = CompilerInvocation::GetResourcesPath(args[0], MainAddr);
Clang->getHeaderSearchOpts().ResourceDir = path;
m_compiler->getHeaderSearchOpts().ResourceDir = path;
}
auto& HSO = Clang->getInvocation().getHeaderSearchOpts();
// Add base toolchain-supplied header paths
// Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h
// But that's a private header and isn't part of the public libclang API
// Instead of re-implementing all of that functionality in a custom toolchain
// just hardcode the paths relevant to frequently used build/test machines for now
HSO.AddPath(CLANG_BUILTIN_HEADERS_PATH, clang::frontend::System, false, false);
HSO.AddPath("/usr/include/x86_64-linux-gnu", clang::frontend::System, false, false);
HSO.AddPath("/usr/include", clang::frontend::System, false, false);
// Add C++ standard library headers
// Debian-like + GCC 4.8 libstdc++
HSO.AddPath("/usr/include/x86_64-linux-gnu/c++/4.8", clang::frontend::System, false, false);
HSO.AddPath("/usr/include/c++/4.8", clang::frontend::System, false, false);
// Debian-like + GCC 5 libstdc++
HSO.AddPath("/usr/include/x86_64-linux-gnu/c++/5", clang::frontend::System, false, false);
HSO.AddPath("/usr/include/c++/5", clang::frontend::System, false, false);
HSO.AddPath(EIGEN_HEADERS_PATH, clang::frontend::System, false, false);
HSO.AddPath(NGRAPH_HEADERS_PATH, clang::frontend::System, false, false);
if (s_header_cache.is_valid() == false)
{
// Add base toolchain-supplied header paths
// Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h
// But that's a private header and isn't part of the public libclang API
// Instead of re-implementing all of that functionality in a custom toolchain
// just hardcode the paths relevant to frequently used build/test machines for now
add_header_search_path(CLANG_BUILTIN_HEADERS_PATH);
add_header_search_path("/usr/include/x86_64-linux-gnu");
add_header_search_path("/usr/include");
// Search for headers in
// /usr/include/x86_64-linux-gnu/c++/N.N
// /usr/include/c++/N.N
// and add them to the header search path
file_util::iterate_files("/usr/include/x86_64-linux-gnu/c++/",
[&](const std::string& file, bool is_dir) {
if (is_dir)
{
string dir_name = file_util::get_file_name(file);
if (is_version_number(dir_name))
{
add_header_search_path(file);
}
}
});
file_util::iterate_files("/usr/include/c++/", [&](const std::string& file, bool is_dir) {
if (is_dir)
{
string dir_name = file_util::get_file_name(file);
if (is_version_number(dir_name))
{
add_header_search_path(file);
}
}
});
add_header_search_path(EIGEN_HEADERS_PATH);
add_header_search_path(NGRAPH_HEADERS_PATH);
#ifdef USE_CACHE
s_header_cache.set_valid();
#endif
}
#ifdef USE_CACHE
use_cached_files(m_compiler);
#endif
// Language options
// These are the C++ features needed to compile ngraph headers
// and any dependencies like Eigen
auto LO = Clang->getInvocation().getLangOpts();
auto LO = m_compiler->getInvocation().getLangOpts();
LO->CPlusPlus = 1;
LO->CPlusPlus11 = 1;
LO->Bool = 1;
......@@ -148,7 +191,7 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
LO->OpenMPUseTLS = 1;
// CodeGen options
auto& CGO = Clang->getInvocation().getCodeGenOpts();
auto& CGO = m_compiler->getInvocation().getCodeGenOpts();
CGO.OptimizationLevel = 3;
CGO.RelocationModel = "static";
CGO.ThreadModel = "posix";
......@@ -158,22 +201,22 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
CGO.VectorizeSLP = 1;
CGO.CXAAtExit = 0;
if (debuginfo_enabled)
if (m_debuginfo_enabled)
{
CGO.setDebugInfo(codegenoptions::FullDebugInfo);
}
if (precompiled_headers_enabled)
if (m_precompiled_headers_enabled)
{
// Preprocessor options
auto& PPO = Clang->getInvocation().getPreprocessorOpts();
auto& PPO = m_compiler->getInvocation().getPreprocessorOpts();
PPO.ImplicitPCHInclude = "ngcpu.pch";
PPO.DisablePCHValidation = 1;
}
// Enable various target features
// Most of these are for Eigen
auto& TO = Clang->getInvocation().getTargetOpts();
auto& TO = m_compiler->getInvocation().getTargetOpts();
// TODO: This needs to be configurable and selected carefully
TO.CPU = "broadwell";
TO.FeaturesAsWritten.emplace_back("+sse");
......@@ -185,62 +228,121 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
TO.FeaturesAsWritten.emplace_back("+avx");
TO.FeaturesAsWritten.emplace_back("+avx2");
TO.FeaturesAsWritten.emplace_back("+fma");
}
// Map code filename to a memoryBuffer
StringRef source_ref(source);
unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
Clang->getInvocation().getPreprocessorOpts().addRemappedFile(name, buffer.get());
// Create and execute action
CodeGenAction* compilerAction = new EmitCodeGenOnlyAction();
std::unique_ptr<llvm::Module> rc;
if (Clang->ExecuteAction(*compilerAction) == true)
{
rc = compilerAction->takeModule();
}
buffer.release();
return rc;
StaticCompiler::~StaticCompiler()
{
}
bool execution_state::add_module(std::unique_ptr<llvm::Module>& module)
bool StaticCompiler::is_version_number(const string& path)
{
if (module)
bool rc = true;
vector<string> tokens = ngraph::split(path, '.');
for (string s : tokens)
{
if (!m_execution_engine)
for (char c : s)
{
m_execution_engine = llvm::EngineBuilder(move(module))
.setEngineKind(llvm::EngineKind::JIT)
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setErrorStr(&jit_error)
.create();
if (!m_execution_engine)
if (!isdigit(c))
{
return false;
rc = false;
}
}
}
else
return rc;
}
void StaticCompiler::add_header_search_path(const string& path)
{
if (!contains(m_extra_search_path_list, path))
{
return false;
}
m_extra_search_path_list.push_back(path);
HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
#ifdef USE_CACHE
static vector<string> valid_ext = {".h", ".hpp", ".tcc", ""};
string mapped_path = file_util::path_join("/$BUILTIN", path);
mapped_path = path;
s_header_cache.add_path(mapped_path);
auto func = [&](const std::string& file, bool is_dir) {
if (!is_dir)
{
string ext = file_util::get_file_ext(file);
if (contains(valid_ext, ext))
{
// This is a header file
string relative_name = file.substr(path.size() + 1);
string mapped_name = file_util::path_join(mapped_path, relative_name);
ErrorOr<unique_ptr<MemoryBuffer>> code = MemoryBuffer::getFile(file);
if (error_code ec = code.getError())
{
// throw up
throw runtime_error("could not find file '" + file + "'");
}
return true;
s_header_cache.add_file(mapped_name, code.get());
}
}
};
file_util::iterate_files(path, func, true);
#else
hso.AddPath(path, clang::frontend::System, false, false);
#endif
}
}
void execution_state::finalize()
void StaticCompiler::use_cached_files()
{
if (m_execution_engine)
HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
for (const string& path : s_header_cache.get_include_paths())
{
m_execution_engine->finalizeObject();
m_execution_engine->runStaticConstructorsDestructors(false);
hso.AddPath(path, clang::frontend::System, false, false);
}
else
for (auto& header : s_header_cache.get_header_map())
{
throw std::runtime_error(
"Error in finalize: " +
(jit_error.empty() ? "Could not create an execution engine" : jit_error));
m_compiler->getPreprocessorOpts().addRemappedFile(header.first, header.second.get());
}
}
std::unique_ptr<llvm::Module> StaticCompiler::compile(const string& source)
{
// Map code filename to a memoryBuffer
StringRef source_ref(source);
unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());
// Create and execute action
CodeGenAction* compilerAction = new EmitCodeGenOnlyAction();
std::unique_ptr<llvm::Module> rc;
if (m_compiler->ExecuteAction(*compilerAction) == true)
{
rc = compilerAction->takeModule();
}
buffer.release();
m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();
return rc;
}
// std::unique_ptr<llvm::Module> StaticCompiler::generate_pch(const string& source)
// {
// // Map code filename to a memoryBuffer
// StringRef source_ref(source);
// unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
// m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());
// // Create and execute action
// CodeGenAction* compilerAction = new GeneratePCHAction();
// std::unique_ptr<llvm::Module> rc;
// if (m_compiler->ExecuteAction(*compilerAction) == true)
// {
// rc = compilerAction->takeModule();
// }
// buffer.release();
// m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();
// return rc;
// }
......@@ -27,10 +27,18 @@ namespace ngraph
namespace codegen
{
class module;
class execution_state;
class Compiler;
class StaticCompiler;
class HeaderCache;
}
}
namespace clang
{
class HeaderSearchOptions;
class CompilerInstance;
}
class ngraph::codegen::module
{
public:
......@@ -38,39 +46,57 @@ private:
std::unique_ptr<llvm::Module> m_module;
};
class ngraph::codegen::execution_state : public llvm::SectionMemoryManager
class ngraph::codegen::Compiler
{
public:
execution_state();
~execution_state();
void set_precompiled_headers_enabled(bool state) { precompiled_headers_enabled = state; }
bool is_precompiled_headers_enabled() { return precompiled_headers_enabled; }
void set_debuginfo_enabled(bool state) { debuginfo_enabled = state; }
bool is_debuginfo_enabled() { return debuginfo_enabled; }
std::unique_ptr<llvm::Module> compile(const std::string& source, const std::string& name = "");
bool add_module(std::unique_ptr<llvm::Module>&);
Compiler();
~Compiler();
std::unique_ptr<llvm::Module> compile(const std::string& source);
void finalize();
private:
};
template <typename ftype>
std::function<ftype> find_function(const std::string& func_name)
{
auto f = m_execution_engine->getPointerToNamedFunction(func_name);
class ngraph::codegen::StaticCompiler : public llvm::SectionMemoryManager
{
public:
StaticCompiler();
~StaticCompiler();
return f_cast<ftype>(f);
}
void set_precompiled_headers_enabled(bool state) { m_precompiled_headers_enabled = state; }
bool is_precompiled_headers_enabled() { return m_precompiled_headers_enabled; }
void set_debuginfo_enabled(bool state) { m_debuginfo_enabled = state; }
bool is_debuginfo_enabled() { return m_debuginfo_enabled; }
void add_header_search_path(const std::string& path);
std::unique_ptr<llvm::Module> compile(const std::string& source);
private:
llvm::ExecutionEngine* m_execution_engine;
std::string jit_error;
bool precompiled_headers_enabled;
bool debuginfo_enabled;
std::unique_ptr<clang::CompilerInstance> m_compiler;
bool m_precompiled_headers_enabled;
bool m_debuginfo_enabled;
std::string m_source_name;
std::vector<std::string> m_extra_search_path_list;
template <typename signature>
std::function<signature> f_cast(void* f)
bool is_version_number(const std::string& path);
void use_cached_files();
};
class ngraph::codegen::HeaderCache
{
public:
bool is_valid() const { return m_headers_valid; }
bool set_valid() { return m_headers_valid = true; }
void add_path(const std::string& path) { m_include_paths.push_back(path); }
void add_file(const std::string& path, std::unique_ptr<llvm::MemoryBuffer>& code)
{
m_headers.insert(std::make_pair(path, std::move(code)));
}
const std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>>& get_header_map() const
{
return static_cast<signature*>(reinterpret_cast<signature*>(f));
return m_headers;
}
const std::vector<std::string>& get_include_paths() const { return m_include_paths; }
private:
std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> m_headers;
std::vector<std::string> m_include_paths;
bool m_headers_valid;
};
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include "ngraph/codegen/execution_engine.hpp"
using namespace ngraph;
codegen::ExecutionEngine::ExecutionEngine()
: m_execution_engine{nullptr}
{
}
codegen::ExecutionEngine::~ExecutionEngine()
{
}
bool codegen::ExecutionEngine::add_module(std::unique_ptr<llvm::Module>& module)
{
if (module)
{
if (!m_execution_engine)
{
m_execution_engine = llvm::EngineBuilder(move(module))
.setEngineKind(llvm::EngineKind::JIT)
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setErrorStr(&m_jit_error)
.create();
if (!m_execution_engine)
{
return false;
}
}
}
else
{
return false;
}
return true;
}
void codegen::ExecutionEngine::finalize()
{
if (m_execution_engine)
{
m_execution_engine->finalizeObject();
m_execution_engine->runStaticConstructorsDestructors(false);
}
else
{
throw std::runtime_error(
"Error in finalize: " +
(m_jit_error.empty() ? "Could not create an execution engine" : m_jit_error));
}
}
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include <memory>
#include <llvm/ExecutionEngine/MCJIT.h> // forces JIT to link in
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Option/Arg.h>
namespace ngraph
{
namespace codegen
{
class ExecutionEngine;
}
}
class ngraph::codegen::ExecutionEngine
{
public:
ExecutionEngine();
~ExecutionEngine();
bool add_module(std::unique_ptr<llvm::Module>& module);
void finalize();
template <typename ftype>
std::function<ftype> find_function(const std::string& func_name)
{
auto f = m_execution_engine->getPointerToNamedFunction(func_name);
return f_cast<ftype>(f);
}
private:
llvm::ExecutionEngine* m_execution_engine;
std::string m_jit_error;
template <typename signature>
std::function<signature> f_cast(void* f)
{
return static_cast<signature*>(reinterpret_cast<signature*>(f));
}
};
/*
Copyright 2016 Nervana Systems Inc.
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.
*/
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include <cassert>
#include <dirent.h>
......@@ -29,10 +28,37 @@
#include <unistd.h>
#include <vector>
#include "file_util.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
using namespace std;
std::string ngraph::file_util::get_file_name(const std::string& s)
{
string rc = s;
auto pos = s.find_last_of('/');
if (pos != string::npos)
{
rc = s.substr(pos + 1);
}
return rc;
}
std::string ngraph::file_util::get_file_ext(const std::string& s)
{
string rc = get_file_name(s);
auto pos = rc.find_last_of('.');
if (pos != string::npos)
{
rc = rc.substr(pos);
}
else
{
rc = "";
}
return rc;
}
string ngraph::file_util::path_join(const string& s1, const string& s2)
{
string rc;
......@@ -79,20 +105,22 @@ size_t ngraph::file_util::get_file_size(const string& filename)
void ngraph::file_util::remove_directory(const string& dir)
{
struct stat status;
if (stat(dir.c_str(), &status) == -1)
if (stat(dir.c_str(), &status) != -1)
{
return;
iterate_files(dir,
[](const string& file, bool is_dir) {
if (is_dir)
{
rmdir(file.c_str());
}
else
{
remove(file.c_str());
}
},
true);
rmdir(dir.c_str());
}
file_util::iterate_files(dir,
[](const string& file, bool is_dir) {
if (is_dir)
rmdir(file.c_str());
else
remove(file.c_str());
},
true);
rmdir(dir.c_str());
}
void ngraph::file_util::remove_file(const string& file)
......@@ -117,7 +145,7 @@ bool ngraph::file_util::make_directory(const string& dir)
string ngraph::file_util::make_temp_directory(const string& path)
{
string fname = path.empty() ? file_util::get_temp_directory() : path;
string tmp_template = file_util::path_join(fname, "aeonXXXXXX");
string tmp_template = file_util::path_join(fname, "ngraph_XXXXXX");
char* tmpname = strdup(tmp_template.c_str());
mkdtemp(tmpname);
......@@ -129,7 +157,7 @@ string ngraph::file_util::make_temp_directory(const string& path)
std::string ngraph::file_util::get_temp_directory()
{
const vector<string> potential_tmps = {"NERVANA_AEON_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"};
const vector<string> potential_tmps = {"NGRAPH_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"};
const char* path = nullptr;
for (const string& var : potential_tmps)
......@@ -161,7 +189,7 @@ vector<char> ngraph::file_util::read_file_contents(const string& path)
char* p = data.data();
size_t remainder = file_size;
size_t offset = 0;
while (remainder > 0)
while (f && remainder > 0)
{
size_t rc = fread(&p[offset], 1, remainder, f);
offset += rc;
......@@ -197,12 +225,16 @@ void ngraph::file_util::iterate_files(const string& path,
else
files.push_back(file);
},
true);
recurse);
for (auto f : files)
{
func(f, false);
}
for (auto f : dirs)
{
func(f, true);
}
}
void ngraph::file_util::iterate_files_worker(
......@@ -218,18 +250,23 @@ void ngraph::file_util::iterate_files_worker(
switch (ent->d_type)
{
case DT_DIR:
if (recurse && name != "." && name != "..")
if (name != "." && name != "..")
{
string dir_path = file_util::path_join(path, name);
iterate_files(dir_path, func, recurse);
if (recurse)
{
iterate_files(dir_path, func, recurse);
}
func(dir_path, true);
}
break;
case DT_LNK: break;
case DT_REG:
name = file_util::path_join(path, name);
func(name, false);
{
string file_name = file_util::path_join(path, name);
func(file_name, false);
break;
}
default: break;
}
}
......
/*
Copyright 2016 Nervana Systems Inc.
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.
*/
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
......@@ -27,6 +26,8 @@ namespace ngraph
class ngraph::file_util
{
public:
static std::string get_file_name(const std::string&);
static std::string get_file_ext(const std::string&);
static std::string path_join(const std::string& s1, const std::string& s2);
static size_t get_file_size(const std::string& filename);
static void remove_directory(const std::string& dir);
......
......@@ -14,8 +14,8 @@
#pragma once
#include <cinttypes>
#include <cstddef>
#include <cstdint>
// CBLAS types and wrappers
......
......@@ -16,7 +16,7 @@
#include <memory>
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
#include "ngraph/runtime/manager.hpp"
namespace ngraph
......@@ -33,7 +33,7 @@ namespace ngraph
class CPUManager : public Manager
{
protected:
ngraph::codegen::execution_state exec_state;
ngraph::codegen::ExecutionEngine exec_state;
public:
virtual std::shared_ptr<Backend> allocate_backend() override;
......
......@@ -89,7 +89,7 @@ namespace ngraph
};
}
// ET element type
// T element type
// FMT array format (fmt::V for vector, etc.)
// BASE select array/matrix
template <typename T,
......@@ -128,4 +128,4 @@ namespace ngraph
}
}
}
}
\ No newline at end of file
}
......@@ -66,20 +66,12 @@ void Emitter::EmitAdd(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
string type = et.c_type_string();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << type << ">(" << outputs[0].get_tensor().get_name() << ", "
<< eigen_vector_format(outputs[0]) << ") =\n";
TU << emit_array1d(outputs[0]) << " = \n";
TU.indent++;
TU << "EigenArray1d<" << type << ">(" << inputs[0].get_tensor().get_name() << ", "
<< eigen_vector_format(inputs[0]) << ") +\n";
TU << "EigenArray1d<" << type << ">(" << inputs[1].get_tensor().get_name() << ", "
<< eigen_vector_format(inputs[1]) << ");\n";
TU << emit_array1d(inputs[0]) << " +\n ";
TU << emit_array1d(inputs[1]) << ";\n";
TU.indent -= 2;
TU << "}\n";
}
......@@ -111,11 +103,8 @@ void Emitter::EmitDot(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << arg0_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ")\n = " << first.get_tensor().get_name() << "[0]\n * EigenVector<"
<< arg0_element_type.c_type_string() << ">(" << second.get_tensor().get_name() << ", "
<< eigen_vector_format(second) << ");\n";
TU << "" << emit_vector(outputs[0]) << "\n = ";
TU << first.get_tensor().get_name() << "[0]\n * " << emit_vector(second) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -123,15 +112,9 @@ void Emitter::EmitDot(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << arg0_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") << \n"
<< " EigenVector<" << arg0_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ").dot("
<< "EigenVector<" << arg0_element_type.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", " << eigen_vector_format(inputs[1])
<< "));\n";
TU << "" << emit_vector(outputs[0]) << " << \n"
<< " " << emit_vector(inputs[0]) << ".dot("
<< "" << emit_vector(inputs[1]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -141,14 +124,9 @@ void Emitter::EmitDot(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << arg0_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") = \n"
<< " EigenMatrix<" << arg0_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides()) << ") * "
<< "EigenVector<" << arg0_element_type.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", " << eigen_vector_format(inputs[1]) << ");\n";
TU << "" << emit_vector(outputs[0]) << " = \n"
<< " " << emit_matrix(inputs[0]) << " * "
<< "" << emit_vector(inputs[1]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -179,18 +157,9 @@ void Emitter::EmitDot(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenMatrix<" << arg0_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides())
<< ") = \n"
<< " EigenMatrix<" << arg0_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ") * "
<< "EigenMatrix<" << arg0_element_type.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg1_layout->get_shape(), arg1_layout->get_strides())
<< ");\n";
TU << "" << emit_matrix(outputs[0]) << " = \n"
<< " " << emit_matrix(inputs[0]) << " * "
<< "" << emit_matrix(inputs[1]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -213,12 +182,9 @@ void Emitter::EmitMultiply(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << type << ">(" << outputs[0].get_tensor().get_name() << ", "
<< eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << type << ">(" << inputs[0].get_tensor().get_name() << ", "
<< eigen_vector_format(inputs[0]) << ") *\n"
<< " EigenArray1d<" << type << ">(" << inputs[1].get_tensor().get_name() << ", "
<< eigen_vector_format(inputs[1]) << ");\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << " *\n"
<< " " << emit_array1d(inputs[1]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -276,16 +242,10 @@ void Emitter::EmitAbs(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n";
TU << "Eigen::abs(EigenArray1d<" << et.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0]) << "));\n";
TU << emit_array1d(outputs[0]) << " =\n";
TU << "Eigen::abs(" << emit_array1d(inputs[0]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -299,24 +259,19 @@ void Emitter::EmitConcat(const ngraph::Node* n,
assert(result_tensor_type);
auto result_shape = result_tensor_type->get_shape();
auto& result_element_type = result_tensor_type->get_element_type();
if (result_shape.size() == 1)
{
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << result_element_type.c_type_string() << "> out_vector("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ");\n";
TU << "" << emit_vector(outputs[0], "out_vector") << ";\n";
size_t concat_pos = 0;
for (size_t i = 0; i < inputs.size(); i++)
{
TU << "out_vector.segment(" << concat_pos << ", "
<< inputs[i].get_tensor_view_layout()->get_shape().at(0) << ") << "
<< "EigenVector<" << result_element_type.c_type_string() << ">("
<< inputs[i].get_tensor().get_name() << ", " << eigen_vector_format(inputs[i])
<< ");\n";
<< "" << emit_vector(inputs[i]) << ";\n";
concat_pos += inputs[i].get_tensor_view_layout()->get_shape().at(0);
}
TU.indent--;
......@@ -329,9 +284,7 @@ void Emitter::EmitConcat(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenMatrix<" << result_element_type.c_type_string() << "> out_matrix("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides()) << ");\n";
TU << "" << emit_matrix(outputs[0], "out_matrix") << ";\n";
size_t concat_pos[2]{0, 0};
for (size_t i = 0; i < inputs.size(); i++)
......@@ -341,9 +294,7 @@ void Emitter::EmitConcat(const ngraph::Node* n,
TU << "out_matrix.block(" << concat_pos[0] << ", " << concat_pos[1] << ", "
<< arg_shape.at(0) << ", " << arg_shape.at(1) << ") << "
<< "EigenMatrix<" << result_element_type.c_type_string() << ">("
<< inputs[i].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg_layout->get_shape(), arg_layout->get_strides()) << ");\n";
<< "" << emit_matrix(inputs[i]) << ";\n";
concat_pos[axis] += arg_shape.at(axis);
}
......@@ -358,18 +309,11 @@ void Emitter::EmitDivide(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") /\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ");\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << " /\n"
<< " " << emit_array1d(inputs[1]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -379,18 +323,11 @@ void Emitter::EmitEqual(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") ==\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " ==\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -400,18 +337,11 @@ void Emitter::EmitGreater(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU << "{ // " << n->get_name() << " xxx\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") >\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " >\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -421,18 +351,11 @@ void Emitter::EmitGreaterEq(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") >=\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " >=\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -442,18 +365,11 @@ void Emitter::EmitLess(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") <\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " <\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -463,18 +379,11 @@ void Emitter::EmitLessEq(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") <=\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " <=\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -484,16 +393,10 @@ void Emitter::EmitLog(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " Eigen::log(EigenArray1d<" << et.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0]) << "));\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " Eigen::log(" << emit_array1d(inputs[0]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -503,18 +406,11 @@ void Emitter::EmitMaximum(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").max(\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << "));\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".max(\n"
<< " " << emit_array1d(inputs[1]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -524,18 +420,11 @@ void Emitter::EmitMinimum(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").min(\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << "));\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".min(\n"
<< " " << emit_array1d(inputs[1]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -545,16 +434,10 @@ void Emitter::EmitNegative(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " -EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ");\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " -" << emit_array1d(inputs[0]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -564,18 +447,11 @@ void Emitter::EmitNotEqual(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " (EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") !=\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ")).template cast<char>();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " (" << emit_array1d(inputs[0]) << " !=\n"
<< " " << emit_array1d(inputs[1]) << ").template cast<char>();\n";
TU.indent--;
TU << "}\n";
}
......@@ -585,20 +461,12 @@ void Emitter::EmitSelect(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(1)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << element::Bool::element_type().c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0]) << ")\n"
<< " .select(EigenArray1d<" << et.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0]) << "),\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[2].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << "));\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << "\n"
<< " .select(" << emit_array1d(inputs[1]) << ",\n"
<< " " << emit_array1d(inputs[2]) << ");\n";
TU.indent--;
TU << "}\n";
}
......@@ -608,18 +476,11 @@ void Emitter::EmitSubtract(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ") -\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[1].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[1]) << ");\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << " -\n"
<< " " << emit_array1d(inputs[1]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -808,7 +669,6 @@ void Emitter::EmitBroadcast(const ngraph::Node* n,
auto arg_shape = arg_tensor_type->get_shape();
auto result_shape = result_tensor_type->get_shape();
auto& result_element_type = result_tensor_type->get_element_type();
if (broadcast->get_broadcast_axes().empty())
{
......@@ -826,12 +686,8 @@ void Emitter::EmitBroadcast(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenArray1d<" << result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ")(0, 0);\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << "(0, 0);\n";
TU.indent--;
TU << "}\n";
}
......@@ -843,13 +699,8 @@ void Emitter::EmitBroadcast(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenMatrix<" << result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides())
<< ").colwise() =\n"
<< " EigenVector<" << result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ");\n";
TU << "" << emit_matrix(outputs[0]) << ".colwise() =\n"
<< " " << emit_vector(inputs[0]) << ";\n";
TU.indent--;
TU << "}\n";
}
......@@ -859,13 +710,8 @@ void Emitter::EmitBroadcast(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenMatrix<" << result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides())
<< ").rowwise() =\n"
<< " EigenVector<" << result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ").transpose();\n";
TU << "" << emit_matrix(outputs[0]) << ".rowwise() =\n"
<< " " << emit_vector(inputs[0]) << ".transpose();\n";
TU.indent--;
TU << "}\n";
}
......@@ -892,8 +738,6 @@ void Emitter::EmitConvert(const ngraph::Node* n,
auto arg_tensor_type = dynamic_pointer_cast<const TensorViewType>(arg->get_value_type());
assert(arg_tensor_type);
auto& arg_element_type = arg_tensor_type->get_element_type();
auto result_tensor_type = dynamic_pointer_cast<const TensorViewType>(n->get_value_type());
assert(result_tensor_type);
......@@ -901,10 +745,8 @@ void Emitter::EmitConvert(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << arg_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0]) << ")\n"
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << "\n"
<< " .template cast<" << result_element_type.c_type_string() << ">();\n";
TU.indent--;
TU << "}\n";
......@@ -961,7 +803,8 @@ void Emitter::EmitReshape(const ngraph::Node* n,
result_shape_product *= i;
}
// If there is no layout change or we are just going from 1^n to 1^m or a zero-size tensor, we can just copy.
// If there is no layout change or we are just going from 1^n to 1^m or a zero-size tensor,
// we can just copy.
if (same_layout || result_shape_product < 2)
{
TU << "{ // " << n->get_name() << " 1\n";
......@@ -1000,13 +843,8 @@ void Emitter::EmitReshape(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << " 3\n";
TU.indent++;
TU << "EigenMatrix<" << result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides()) << ") =\n"
<< " EigenMatrix<" << result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").transpose();\n";
TU << "" << emit_matrix(outputs[0]) << " =\n"
<< " " << emit_matrix(inputs[0]) << ".transpose();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1029,19 +867,7 @@ void Emitter::EmitFunctionCall(const ngraph::Node* n,
TU << "{ // Call " << function->get_name() << "\n";
TU.indent++;
TU << "std::vector<void*> inputs;\n";
for (const TensorViewInfo& input : inputs)
{
TU << "inputs.push_back(" << input.get_tensor().get_name() << ");\n";
}
TU << "\n";
TU << "std::vector<void*> outputs;\n";
for (const TensorViewInfo& output : outputs)
{
TU << "outputs.push_back(" << output.get_tensor().get_name() << ");\n";
}
TU << "\n";
TU << function->get_name() << "(inputs, outputs);\n";
generate_call(inputs, outputs, function);
TU.indent--;
TU << "}\n";
}
......@@ -1137,24 +963,18 @@ void Emitter::EmitReduce(const ngraph::Node* n,
TU << "{ // " << n->get_name() << " 3\n";
TU.indent++;
string type = f_result_element_type.c_type_string();
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << " {\n";
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << "\n{";
TU.indent++;
TU << "std::vector<void*> inputs;\n";
TU << "inputs.push_back(&x);\n";
TU << "inputs.push_back(&y);\n\n";
TU << "\n";
TU << type << " result;\n";
TU << "std::vector<void*> outputs;\n";
TU << "outputs.push_back(&result);\n";
TU << "std::vector<void*> inputs = {&x, &y};\n";
TU << "std::vector<void*> outputs = {&result};\n";
TU << reduction_function->get_name() << "(inputs, outputs);\n";
TU << "return result;\n";
TU.indent--;
TU << "};\n";
TU << "EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ").redux(f);\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".redux(f);\n";
TU.indent--;
TU << "}\n";
}
......@@ -1165,12 +985,8 @@ void Emitter::EmitReduce(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << " 4\n";
TU.indent++;
TU << "EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", " << eigen_vector_format(inputs[1])
<< ")(0, 0);\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[1]) << "(0, 0);\n";
TU.indent--;
TU << "}\n";
}
......@@ -1183,25 +999,18 @@ void Emitter::EmitReduce(const ngraph::Node* n,
TU << "{ // " << n->get_name() << " 5\n";
TU.indent++;
string type = f_result_element_type.c_type_string();
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << " {\n";
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << "\n{";
TU.indent++;
TU << "std::vector<void*> inputs;\n";
TU << "inputs.push_back(&x);\n";
TU << "inputs.push_back(&y);\n\n";
TU << "\n";
TU << type << " result;\n";
TU << "std::vector<void*> outputs;\n";
TU << "outputs.push_back(&result);\n";
TU << "std::vector<void*> inputs = {&x, &y};\n";
TU << "std::vector<void*> outputs = {&result};\n";
TU << reduction_function->get_name() << "(inputs, outputs);\n";
TU << "return result;\n";
TU.indent--;
TU << "};\n";
TU << "EigenVector<" << f_result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenMatrix<" << f_result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").rowwise().redux(f);\n";
TU << "" << emit_vector(outputs[0]) << " =\n"
<< " " << emit_matrix(inputs[0]) << ".rowwise().redux(f);\n";
TU.indent--;
TU << "}\n";
}
......@@ -1212,12 +1021,8 @@ void Emitter::EmitReduce(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << " 6\n";
TU.indent++;
TU << "EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenArray1d<" << f_result_element_type.c_type_string() << ">("
<< inputs[1].get_tensor().get_name() << ", " << eigen_vector_format(inputs[1])
<< ")(0, 0);\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[1]) << "(0, 0);\n";
TU.indent--;
TU << "}\n";
}
......@@ -1226,25 +1031,18 @@ void Emitter::EmitReduce(const ngraph::Node* n,
TU << "{ // " << n->get_name() << " 7\n";
TU.indent++;
string type = f_result_element_type.c_type_string();
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << " {\n";
TU << "auto f = [](" << type << " x, " << type << " y) -> " << type << "\n{";
TU.indent++;
TU << "std::vector<void*> inputs;\n";
TU << "inputs.push_back(&x);\n";
TU << "inputs.push_back(&y);\n\n";
TU << "\n";
TU << type << " result;\n";
TU << "std::vector<void*> outputs;\n";
TU << "outputs.push_back(&result);\n";
TU << "std::vector<void*> inputs = {&x, &y};\n";
TU << "std::vector<void*> outputs = {&result};\n";
TU << reduction_function->get_name() << "(inputs, outputs);\n";
TU << "return result;\n";
TU.indent--;
TU << "};\n";
TU << "EigenVector<" << f_result_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenMatrix<" << f_result_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").colwise().redux(f);\n";
TU << "" << emit_vector(outputs[0]) << " =\n"
<< " " << emit_matrix(inputs[0]) << ".colwise().redux(f);\n";
TU.indent--;
TU << "}\n";
}
......@@ -1260,16 +1058,10 @@ void Emitter::EmitSign(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").sign();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".sign();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1294,7 +1086,6 @@ void Emitter::EmitSlice(const ngraph::Node* n,
assert(arg_tensor_view_type);
auto arg_shape = arg_tensor_view_type->get_shape();
auto arg_rank = arg_shape.size();
auto& arg_element_type = arg_tensor_view_type->get_element_type();
auto& lower_bounds = slice->get_lower_bounds();
auto& upper_bounds = slice->get_upper_bounds();
......@@ -1316,12 +1107,8 @@ void Emitter::EmitSlice(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << " 2\n";
TU.indent++;
TU << "EigenVector<" << arg_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenVector<" << arg_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ").segment(\n"
TU << "" << emit_vector(outputs[0]) << " =\n"
<< " " << emit_vector(inputs[0]) << ".segment(\n"
<< " " << to_string(lower_bounds[0]) << ", "
<< to_string(upper_bounds[0] - lower_bounds[0]) << ");\n";
TU.indent--;
......@@ -1334,14 +1121,9 @@ void Emitter::EmitSlice(const ngraph::Node* n,
TU << "{ // " << n->get_name() << " 3\n";
TU.indent++;
TU << "EigenMatrix<" << arg_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(out_layout->get_shape(), out_layout->get_strides()) << ") = \n"
<< " EigenMatrix<" << arg_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").block(" << to_string(lower_bounds[0]) << ", " << to_string(lower_bounds[1])
<< ",\n"
TU << "" << emit_matrix(outputs[0]) << " = \n"
<< " " << emit_matrix(inputs[0]) << ".block(" << to_string(lower_bounds[0])
<< ", " << to_string(lower_bounds[1]) << ",\n"
<< " " << to_string(upper_bounds[0] - lower_bounds[0]) << ",\n"
<< " " << to_string(upper_bounds[1] - lower_bounds[1]) << ");\n";
TU.indent--;
......@@ -1362,7 +1144,6 @@ void Emitter::EmitSum(const ngraph::Node* n,
auto s = static_cast<const op::Sum*>(n);
auto s_tensor_view_type = dynamic_pointer_cast<const TensorViewType>(s->get_value_type());
assert(s_tensor_view_type);
auto& s_element_type = s_tensor_view_type->get_element_type();
auto s_shape = s_tensor_view_type->get_shape();
auto arg = s->get_arguments().at(0);
......@@ -1393,12 +1174,8 @@ void Emitter::EmitSum(const ngraph::Node* n,
{
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << s_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenArray1d<" << s_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", " << eigen_vector_format(inputs[0])
<< ").sum();\n";
TU << "" << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".sum();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1408,13 +1185,8 @@ void Emitter::EmitSum(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << s_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenMatrix<" << s_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").rowwise().sum();\n";
TU << "" << emit_vector(outputs[0]) << " =\n"
<< " " << emit_matrix(inputs[0]) << ".rowwise().sum();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1424,13 +1196,8 @@ void Emitter::EmitSum(const ngraph::Node* n,
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenVector<" << s_element_type.c_type_string() << ">("
<< outputs[0].get_tensor().get_name() << ", " << eigen_vector_format(outputs[0])
<< ") =\n"
<< " EigenMatrix<" << s_element_type.c_type_string() << ">("
<< inputs[0].get_tensor().get_name() << ", "
<< eigen_matrix_format(arg0_layout->get_shape(), arg0_layout->get_strides())
<< ").colwise().sum();\n";
TU << "" << emit_vector(outputs[0]) << " =\n"
<< " " << emit_matrix(inputs[0]) << ".colwise().sum();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1445,16 +1212,10 @@ void Emitter::EmitExp(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").exp();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".exp();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1464,16 +1225,10 @@ void Emitter::EmitSin(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").sin();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".sin();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1483,16 +1238,10 @@ void Emitter::EmitSinh(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").sinh();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".sinh();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1502,16 +1251,10 @@ void Emitter::EmitCos(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").cos();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".cos();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1521,16 +1264,10 @@ void Emitter::EmitCosh(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").cosh();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".cosh();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1540,16 +1277,10 @@ void Emitter::EmitTan(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").tan();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".tan();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1579,16 +1310,10 @@ void Emitter::EmitAsin(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").asin();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".asin();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1598,16 +1323,10 @@ void Emitter::EmitAcos(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").acos();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".acos();\n";
TU.indent--;
TU << "}\n";
}
......@@ -1617,16 +1336,89 @@ void Emitter::EmitAtan(const ngraph::Node* n,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)
{
const element::Type& et =
(dynamic_pointer_cast<const TensorViewType>(n->get_arguments().at(0)->get_value_type()))
->get_element_type();
TU << "{ // " << n->get_name() << "\n";
TU.indent++;
TU << "EigenArray1d<" << et.c_type_string() << ">(" << outputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(outputs[0]) << ") =\n"
<< " EigenArray1d<" << et.c_type_string() << ">(" << inputs[0].get_tensor().get_name()
<< ", " << eigen_vector_format(inputs[0]) << ").atan();\n";
TU << emit_array1d(outputs[0]) << " =\n"
<< " " << emit_array1d(inputs[0]) << ".atan();\n";
TU.indent--;
TU << "}\n";
}
//------------------------------------------------------------------------------------------------
// Utility methods
//------------------------------------------------------------------------------------------------
void Emitter::generate_call(const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs,
shared_ptr<Function> function)
{
vector<string> input_names;
vector<string> output_names;
for (const TensorViewInfo& input : inputs)
{
input_names.push_back(input.get_tensor().get_name());
}
for (const TensorViewInfo& output : outputs)
{
output_names.push_back(output.get_tensor().get_name());
}
TU << "std::vector<void*> inputs =\n{";
TU.indent++;
TU << "\n" << join(input_names, ",\n");
TU.indent--;
TU << "\n};\n";
TU << "std::vector<void*> outputs =\n{";
TU.indent++;
TU << "\n" << join(output_names, ",\n");
TU.indent--;
TU << "\n};\n";
TU << "\n";
TU << function->get_name() << "(inputs, outputs);\n";
}
static string format_name(const string& name)
{
string rc;
if (name.empty())
{
rc = " " + name;
}
return rc;
}
string Emitter::emit_vector(const TensorViewInfo& tvi, const string& name)
{
stringstream ss;
const element::Type& et = tvi.get_tensor_view()->get_value_type()->get_element_type();
ss << "EigenVector<" << et.c_type_string() << ">" << format_name(name) << "("
<< tvi.get_tensor().get_name() << ", " << eigen_vector_format(tvi) << ")";
return ss.str();
}
string Emitter::emit_array1d(const TensorViewInfo& tvi, const string& name)
{
stringstream ss;
const element::Type& et = tvi.get_tensor_view()->get_value_type()->get_element_type();
ss << "EigenArray1d<" << et.c_type_string() << ">" << format_name(name) << "("
<< tvi.get_tensor().get_name() << ", " << eigen_vector_format(tvi) << ")";
return ss.str();
}
string Emitter::emit_matrix(const TensorViewInfo& tvi, const string& name)
{
stringstream ss;
auto layout = tvi.get_layout<DenseTensorViewLayout>();
const element::Type& et = tvi.get_tensor_view()->get_value_type()->get_element_type();
ss << "EigenMatrix<" << et.c_type_string() << ">" << format_name(name) << "("
<< tvi.get_tensor().get_name() << ", "
<< eigen_matrix_format(layout->get_shape(), layout->get_strides()) << ")";
return ss.str();
}
......@@ -94,6 +94,15 @@ namespace ngraph
void EMITTER_DECL(EmitAsin);
void EMITTER_DECL(EmitAcos);
void EMITTER_DECL(EmitAtan);
private:
void generate_call(const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs,
std::shared_ptr<Function> function);
std::string emit_vector(const TensorViewInfo&, const std::string& name = "");
std::string emit_array1d(const TensorViewInfo&, const std::string& name = "");
std::string emit_matrix(const TensorViewInfo&, const std::string& name = "");
};
}
}
......
......@@ -22,6 +22,7 @@
#include "ngraph/codegen/code_writer.hpp"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
#include "ngraph/descriptor/input.hpp"
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/output.hpp"
......@@ -74,6 +75,7 @@
#include "ngraph/pass/memory_layout.hpp"
#include "ngraph/pass/topological_sort.hpp"
#include "ngraph/runtime/cpu/call_frame.hpp"
#include "ngraph/runtime/cpu/cpu_backend.hpp"
#include "ngraph/runtime/cpu/emitter.hpp"
#include "ngraph/runtime/cpu/external_function.hpp"
#include "ngraph/runtime/utils.hpp"
......@@ -81,26 +83,17 @@
using namespace std;
using namespace ngraph::runtime::cpu;
using ngraph::descriptor::layout::DenseTensorViewLayout;
static const std::string s_output_dir = "cpu_codegen";
extern "C" void
allocate_aligned_buffer(size_t size, size_t alignment, char** allocated, char** aligned_ptr)
class StaticInitializers
{
size_t allocation_size = size + alignment;
*allocated = static_cast<char*>(malloc(allocation_size));
*aligned_ptr = *allocated;
size_t mod = size_t(*aligned_ptr) % alignment;
public:
StaticInitializers() { ngraph::file_util::remove_directory(s_output_dir); }
};
if (mod != 0)
{
(*aligned_ptr) += (alignment - mod);
}
}
static StaticInitializers s_static_initializers;
extern "C" void free_aligned_buffer(void* allocated)
{
free(allocated);
}
using ngraph::descriptor::layout::DenseTensorViewLayout;
#define TI(x) type_index(typeid(x))
......@@ -192,37 +185,25 @@ void ExternalFunction::compile()
TU +=
R"(// Generated by the NGraph CPU backend
#include <algorithm>
#include <cmath>
#include <memory>
#include <vector>
#include <Eigen/Dense>
#include "ngraph/runtime/cpu/cpu_kernels.hpp"
#include "ngraph/runtime/cpu/eigen_utils.hpp"
#include "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph::runtime::cpu::eigen;
extern "C" void allocate_aligned_buffer(
size_t size,
size_t alignment,
char** allocated,
char** aligned_ptr);
extern "C" void free_aligned_buffer(void* allocated);
)";
TU << "// Declare any functions that are not main\n";
TU << "// Declare all functions\n";
for (shared_ptr<Function> f : pass_manager.get_state().get_functions())
{
if (f != m_function)
{
TU << "extern \"C\" void " << f->get_name() << "(\n";
TU << " const std::vector<void*>& inputs,\n";
TU << " const std::vector<void*>& outputs);\n";
}
TU << "extern \"C\" void " << f->get_name() << "(\n";
TU << " const std::vector<void*>& inputs,\n";
TU << " const std::vector<void*>& outputs);\n";
}
TU << "\n";
......@@ -232,27 +213,37 @@ extern "C" void free_aligned_buffer(void* allocated);
TU << " const std::vector<void*>& inputs,\n";
TU << " const std::vector<void*>& outputs)\n";
TU << "{\n";
TU.indent++;
TU << "// Allocate the memory pool\n";
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
TU << "char* allocated_buffer_pool;\n";
TU << "char* aligned_buffer_pool;\n";
TU << "allocate_aligned_buffer(" << temp_pool_size << ", 64"
<< ", &allocated_buffer_pool, &aligned_buffer_pool);\n";
TU << "\n";
TU << "// Define temporary tensors\n";
bool temporaries_used = false;
for (shared_ptr<Node> node : current_function->get_ordered_ops())
{
for (descriptor::Tensor* tensor : node->liveness_new_list)
if (node->liveness_new_list.size() > 0)
{
TU << tensor->get_element_type() << "* " << tensor->get_name() << " = ("
<< tensor->get_element_type() << "*)(aligned_buffer_pool + "
<< tensor->get_pool_offset() << ");\n";
temporaries_used = true;
break;
}
}
TU << "\n";
if (temporaries_used)
{
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
TU << "// Allocate the memory pool\n";
TU << "ngraph::runtime::cpu::MemoryHandler memory_handler(" << temp_pool_size << ", "
<< ngraph::runtime::cpu::alignment << ");\n";
TU << "\n";
TU << "// Define temporary tensors\n";
for (shared_ptr<Node> node : current_function->get_ordered_ops())
{
for (descriptor::Tensor* tensor : node->liveness_new_list)
{
TU << tensor->get_element_type() << "* " << tensor->get_name() << " = ("
<< tensor->get_element_type() << "*)(memory_handler.get_ptr("
<< tensor->get_pool_offset() << "));\n";
}
}
TU << "\n";
}
TU << "// Define inputs\n";
size_t arg_index = 0;
......@@ -283,13 +274,10 @@ extern "C" void free_aligned_buffer(void* allocated);
}
TU << "\n";
TU << "// Define tensor views\n";
TU << "\n";
for (shared_ptr<Node> node : current_function->get_ordered_ops())
{
auto& n = *node; // Work around a compiler warning (*node inside typeid may have effects
// with shared pointers, which is fine here but clang doesn't like it.)
// with shared pointers, which is fine here but clang doesn't like it.)
auto handler = dispatcher.find(type_index(typeid(n)));
if (handler == dispatcher.end())
{
......@@ -311,8 +299,6 @@ extern "C" void free_aligned_buffer(void* allocated);
handler->second(&emitter, node.get(), this, in, out);
}
TU << "\nfree_aligned_buffer(allocated_buffer_pool);\n";
TU.indent--;
// End TU
......@@ -321,34 +307,33 @@ extern "C" void free_aligned_buffer(void* allocated);
// TODO: Cleanup and make this a utility function
string output_dir = "cpu_codegen";
string function_name = m_function->get_name();
file_util::remove_directory(output_dir);
file_util::make_directory(output_dir);
string filename = file_util::path_join(output_dir, function_name + "_codegen.cpp");
file_util::make_directory(s_output_dir);
string filename = file_util::path_join(s_output_dir, function_name + "_codegen.cpp");
ofstream out(filename);
string code = TU.get_code();
out << code;
out.close();
ngraph::codegen::execution_state estate;
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
#if NGCPU_PCH
estate.set_precompiled_headers_enabled(true);
compiler.set_precompiled_headers_enabled(true);
#endif
#if NGCPU_DEBUGINFO
estate.set_debuginfo_enabled(true);
compiler.set_debuginfo_enabled(true);
#endif
auto llvm_module = estate.compile(code, function_name + "_codegen.cpp");
auto llvm_module = compiler.compile(code);
if (llvm_module == nullptr)
{
throw runtime_error("function failed to compile");
}
estate.add_module(llvm_module);
estate.finalize();
m_compiled_function = estate.find_function<EntryPoint_t>(function_name);
execution_engine.add_module(llvm_module);
execution_engine.finalize();
m_compiled_function = execution_engine.find_function<EntryPoint_t>(function_name);
assert(m_compiled_function);
m_is_compiled = true;
......
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph;
runtime::cpu::MemoryHandler::MemoryHandler(size_t byte_size, size_t alignment)
: m_allocated_buffer_pool(nullptr)
, m_aligned_buffer_pool(nullptr)
{
if (byte_size > 0)
{
size_t allocation_size = byte_size + alignment;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool;
size_t mod = size_t(m_aligned_buffer_pool) % alignment;
if (mod != 0)
{
m_aligned_buffer_pool += (alignment - mod);
}
}
}
runtime::cpu::MemoryHandler::~MemoryHandler()
{
if (m_allocated_buffer_pool != nullptr)
{
free(m_allocated_buffer_pool);
}
}
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include <cstddef>
#include <memory>
namespace ngraph
{
namespace runtime
{
namespace cpu
{
class MemoryHandler;
}
}
}
class ngraph::runtime::cpu::MemoryHandler
{
public:
MemoryHandler(size_t pool_size, size_t alignment);
~MemoryHandler();
void* get_ptr(size_t offset) const { return m_aligned_buffer_pool + offset; }
private:
char* m_allocated_buffer_pool;
char* m_aligned_buffer_pool;
};
......@@ -20,35 +20,47 @@
using namespace ngraph;
using namespace std;
extern "C" void
allocate_aligned_buffer(size_t size, size_t alignment, char** allocated, char** aligned_ptr);
extern "C" void free_aligned_buffer(void* allocated);
runtime::cpu::CPUTensorView::CPUTensorView(const ngraph::element::Type& element_type,
const Shape& shape)
: runtime::TensorView(std::make_shared<ngraph::descriptor::PrimaryTensorView>(
std::make_shared<ngraph::TensorViewType>(element_type, shape), "external", true, true))
, m_allocated_buffer_pool(nullptr)
, m_aligned_buffer_pool(nullptr)
{
m_descriptor->set_tensor_view_layout(
std::make_shared<ngraph::descriptor::layout::DenseTensorViewLayout>(*m_descriptor));
m_buffer_size = m_descriptor->get_tensor_view_layout()->get_size() * element_type.size();
allocate_aligned_buffer(m_buffer_size, runtime::cpu::alignment, &m_allocated, &m_buffer);
if (m_buffer_size > 0)
{
size_t allocation_size = m_buffer_size + runtime::cpu::alignment;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool;
size_t mod = size_t(m_aligned_buffer_pool) % alignment;
if (mod != 0)
{
m_aligned_buffer_pool += (alignment - mod);
}
}
}
runtime::cpu::CPUTensorView::~CPUTensorView()
{
free_aligned_buffer(m_allocated);
if (m_allocated_buffer_pool != nullptr)
{
free(m_allocated_buffer_pool);
}
}
char* runtime::cpu::CPUTensorView::get_data_ptr()
{
return m_buffer;
return m_aligned_buffer_pool;
}
const char* runtime::cpu::CPUTensorView::get_data_ptr() const
{
return m_buffer;
return m_aligned_buffer_pool;
}
void runtime::cpu::CPUTensorView::write(const void* source, size_t tensor_offset, size_t n)
......
......@@ -52,7 +52,7 @@ public:
void read(void* p, size_t tensor_offset, size_t n) const override;
private:
char* m_allocated;
char* m_buffer;
char* m_allocated_buffer_pool;
char* m_aligned_buffer_pool;
size_t m_buffer_size;
};
......@@ -19,23 +19,26 @@
#include "gtest/gtest.h"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
using namespace std;
using namespace ngraph;
TEST(codegen, simple_return)
{
constexpr auto name = "test.cpp";
constexpr auto source = R"(extern "C" int test() { return 2+5; })";
ngraph::codegen::execution_state estate;
auto module = estate.compile(source, name);
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
estate.add_module(module);
execution_engine.add_module(module);
estate.finalize();
execution_engine.finalize();
auto func = estate.find_function<int()>("test");
auto func = execution_engine.find_function<int()>("test");
ASSERT_NE(nullptr, func);
int result = func();
......@@ -44,18 +47,19 @@ TEST(codegen, simple_return)
TEST(codegen, pass_args)
{
constexpr auto name = "test.cpp";
constexpr auto source = R"(extern "C" int test(int a, int b) { return a+b; })";
ngraph::codegen::execution_state estate;
auto module = estate.compile(source, name);
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
estate.add_module(module);
execution_engine.add_module(module);
estate.finalize();
execution_engine.finalize();
auto func = estate.find_function<int(int, int)>("test");
auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func);
int result = func(20, 22);
......@@ -64,7 +68,6 @@ TEST(codegen, pass_args)
TEST(codegen, include)
{
constexpr auto name = "test.cpp";
constexpr auto source =
R"(
#include <cmath>
......@@ -74,15 +77,17 @@ TEST(codegen, include)
}
)";
ngraph::codegen::execution_state estate;
auto module = estate.compile(source, name);
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
estate.add_module(module);
execution_engine.add_module(module);
estate.finalize();
execution_engine.finalize();
auto func = estate.find_function<int(int, int)>("test");
auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func);
int result = func(20, 2);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment