Skip to content
Permalink
Browse files

Move the re-usable pieces of the CPUBackend into a dedicated LLVMIRCo…

…deGen library

- Move the re-usable pieces of the CPUBackend into a dedicated `LLVMIRCodeGen` library

- Introduce `LLVMBackend`, `LLVMCompiledFunction` and `LLVMIRGen` types that can be used as superclasses for different LLVM-based backends

  Concrete backends can derive from those classes and override specific parts of their logic to implement target-specific code generation.

- Each LLVM-based backend can have its own backend-specific libjit now

  The backend should just override `getLibjitBitcode` to achieve that.

- Re-factor the `CPUBackend` to use this new `LLVMIRCodeGen` library
  • Loading branch information...
opti-mix committed Feb 28, 2019
1 parent 1dfc1e4 commit 43106fcbd2d9f0e75a3cf27be52e99310ed0864c
Showing with 902 additions and 546 deletions.
  1. +8 −0 CMakeLists.txt
  2. +3 −3 {lib/Backends/CPU → include/glow/LLVMIRCodeGen}/GlowJIT.h
  3. +95 −0 include/glow/LLVMIRCodeGen/LLVMBackend.h
  4. +58 −0 include/glow/LLVMIRCodeGen/LLVMCompiledFunction.h
  5. +39 −19 {lib/Backends/CPU → include/glow/LLVMIRCodeGen}/LLVMIRGen.h
  6. +10 −40 lib/Backends/CPU/CMakeLists.txt
  7. +27 −140 lib/Backends/CPU/CPUBackend.cpp
  8. +17 −33 lib/Backends/CPU/CPUBackend.h
  9. +2 −95 lib/Backends/CPU/CPUFunction.cpp
  10. +4 −21 lib/Backends/CPU/CPUFunction.h
  11. +167 −0 lib/Backends/CPU/CPULLVMIRGen.cpp
  12. +51 −0 lib/Backends/CPU/CPULLVMIRGen.h
  13. +3 −0 lib/CMakeLists.txt
  14. 0 lib/{Backends/CPU → LLVMIRCodeGen}/AllocationsInfo.cpp
  15. +3 −3 lib/{Backends/CPU → LLVMIRCodeGen}/AllocationsInfo.h
  16. +38 −37 lib/{Backends/CPU → LLVMIRCodeGen}/BundleSaver.cpp
  17. +7 −6 lib/{Backends/CPU → LLVMIRCodeGen}/BundleSaver.h
  18. +45 −0 lib/LLVMIRCodeGen/CMakeLists.txt
  19. +1 −1 lib/{Backends/CPU → LLVMIRCodeGen}/CommandLine.cpp
  20. +4 −4 lib/{Backends/CPU → LLVMIRCodeGen}/CommandLine.h
  21. +2 −2 lib/{Backends/CPU → LLVMIRCodeGen}/DebugInfo.cpp
  22. +3 −3 lib/{Backends/CPU → LLVMIRCodeGen}/FunctionSpecializer.cpp
  23. +2 −2 lib/{Backends/CPU → LLVMIRCodeGen}/GlowJIT.cpp
  24. +167 −0 lib/LLVMIRCodeGen/LLVMBackend.cpp
  25. +122 −0 lib/LLVMIRCodeGen/LLVMCompiledFunction.cpp
  26. +19 −132 lib/{Backends/CPU → LLVMIRCodeGen}/LLVMIRGen.cpp
  27. +2 −2 lib/{Backends/CPU → LLVMIRCodeGen}/Pipeline.cpp
  28. +3 −3 tests/unittests/LLVMIRGenTest.cpp
@@ -6,6 +6,7 @@ project(Glow C CXX)
enable_testing()

option(GLOW_WITH_CPU "Build the LLVM-based JIT CPU backend" ON)
option(GLOW_WITH_LLVMIRCODEGEN "Build the LLVM-based code generation library" ON)
option(GLOW_WITH_OPENCL "Build the OpenCL backend" ON)
option(GLOW_BUILD_EXAMPLES "Build the examples" ON)
option(GLOW_BUILD_TESTS "Build the tests" ON)
@@ -58,7 +59,14 @@ if(PNG_FOUND)
add_definitions(-DWITH_PNG)
endif()

if(GLOW_WITH_LLVMIRCODEGEN)
add_definitions(-DGLOW_WITH_LLVMIRCODEGEN=1)
endif()

if(GLOW_WITH_CPU)
if(NOT GLOW_WITH_LLVMIRCODEGEN)
message(FATAL_ERROR "Cannot use -DGLOW_WITH_CPU without -DGLOW_WITH_LLVMIRCODEGEN")
endif ()
add_definitions(-DGLOW_WITH_CPU=1)
endif ()

@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLOW_BACKENDS_CPU_GLOWJIT_H
#define GLOW_BACKENDS_CPU_GLOWJIT_H
#ifndef GLOW_LLVMIRCODEGEN_GLOWJIT_H
#define GLOW_LLVMIRCODEGEN_GLOWJIT_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
@@ -78,4 +78,4 @@ class GlowJIT {
} // end namespace orc
} // end namespace llvm

#endif // GLOW_BACKENDS_CPU_GLOWJIT_H
#endif // GLOW_LLVMIRCODEGEN_GLOWJIT_H
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2017-present, Facebook, 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.
*/
#ifndef GLOW_LLVMIRCODEGEN_LLVMBACKEND_H
#define GLOW_LLVMIRCODEGEN_LLVMBACKEND_H

#include "glow/Backends/Backend.h"
#include "glow/Backends/CompiledFunction.h"
#include "glow/Base/Tensor.h"
#include "glow/LLVMIRCodeGen/GlowJIT.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/IRBuilder.h"

namespace glow {

struct AllocationsInfo;
class Context;
class LLVMIRGen;

/// Helper function to create a new CallInst, with the specified \p builder, \p
/// callee, and \p args. Verifies that the function signature is correct,
/// and then creates and \returns the CallInst.
/// \param builder the IR builder to be used for creating the Call instruction.
/// \param callee the function to be called.
/// \param args arguments to be passed in this call.
/// \returns generated Call instruction.
llvm::CallInst *createCall(llvm::IRBuilder<> &builder, llvm::Function *callee,
llvm::ArrayRef<llvm::Value *> args);

class LLVMBackend : public BackendUsingGlowIR {
public:
LLVMBackend() = default;

/// @name Backend methods.
/// This is the implementation of the Backend interface.
///@{
virtual ~LLVMBackend() override = default;

virtual std::unique_ptr<CompiledFunction>
compileIR(std::unique_ptr<IRFunction> IR) const override;

virtual std::unique_ptr<CompiledFunction>
compileIRWithoutConstants(IRFunction *IR) const;

virtual std::unique_ptr<CompiledFunction>
compile(Function *F, const CompilationOptions &opts) const override;

virtual void save(Function *F, llvm::StringRef outputDir,
llvm::StringRef networkName) const override;
/// @}

/// \returns the size of metrics collected for a single TraceEvent.
virtual size_t getTraceEventDataSize() const override {
return sizeof(uint64_t);
}

/// Method that creates the LLVM IR generator. This gives the possibility to
/// create a backend that inherits from the CPU backend, while providing
/// a specific version of the LLVM IR generator derived from LLVMIRGen.
/// \param IR the IRFunction function to be converted into the LLVM IR.
/// \param allocationsInfo information about allocation of weights and
/// activations.
/// \returns backend-specific LLVMIRGen instance.
virtual std::unique_ptr<LLVMIRGen>
createIRGen(const IRFunction *IR, AllocationsInfo &allocationsInfo) const = 0;

protected:
/// Method that creates a CompiledFunction.
/// \param JIT GlowJIT to be used.
/// \param runtimeBundle bundle to be used for compiling the function.
/// \returns created CompiledFunction.
virtual std::unique_ptr<CompiledFunction>
createCompiledFunction(std::unique_ptr<llvm::orc::GlowJIT> JIT,
const runtime::RuntimeBundle &runtimeBundle) const = 0;

/// \returns libjit bitcode for the current backend.
virtual llvm::StringRef getLibjitBitcode() const = 0;
};

} // namespace glow

#endif // GLOW_LLVMIRCODEGEN_LLVMBACKEND_H
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2017-present, Facebook, 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.
*/
#ifndef GLOW_LLVMIRCODEGEN_LLVMCOMPILEDFUNCTION_H
#define GLOW_LLVMIRCODEGEN_LLVMCOMPILEDFUNCTION_H

#include "glow/LLVMIRCodeGen/GlowJIT.h"

#include "glow/Backends/BackendUtils.h"
#include "glow/Backends/CompiledFunction.h"

namespace glow {
/// A Glow IR function compiled using LLVM.
class LLVMCompiledFunction : public CompiledFunction {
public:
LLVMCompiledFunction(std::unique_ptr<llvm::orc::GlowJIT> JIT,
const runtime::RuntimeBundle &runtimeBundle);

/// \name CompiledFunction interface
///@{
virtual ~LLVMCompiledFunction() override;
virtual void execute(Context *ctx) override;

virtual void collectConstants(Module *module) override;

/// Read trace events out of this func and write them into /p ctx
virtual void translateTraceEvents(Context *ctx) const override;
///@}
//

protected:
/// Load constant tensors from \p ctx into \p weightsAddress, as defined by
/// the RuntimeBundle (pre-run).
virtual void loadPlaceholders(Context *ctx, uint8_t *weightsAddress);

/// Load weights from \p weightsAddress into applicable backing tensors in
/// \p ctx, as defined by the RuntimeBundle (post-run).
virtual void updatePlaceholders(Context *ctx, uint8_t *weightsAddress);

/// The LLVM JIT engine. The jit must be initialized after the ctor
/// initializes the LLVM backends.
std::unique_ptr<llvm::orc::GlowJIT> JIT_;
};
} // end namespace glow

#endif // GLOW_LLVMIRCODEGEN_LLVMCOMPILEDFUNCTION_H
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLOW_BACKENDS_CPU_LLVMIRGEN_H
#define GLOW_BACKENDS_CPU_LLVMIRGEN_H
#ifndef GLOW_LLVMIRCODEGEN_LLVMIRGEN_H
#define GLOW_LLVMIRCODEGEN_LLVMIRGEN_H

#include "AllocationsInfo.h"
#include "glow/Base/Tensor.h"
#include "glow/IR/IR.h"

@@ -80,16 +79,22 @@ struct DebugInfo {
/// This is a class containing a common logic for the generation of the LLVM IR
/// from an IRFunction. The primary clients of this class are JITs and bundlers.
class LLVMIRGen {
private:
protected:
/// Implementation of emitDataParallelKernel where we bound the number of
/// inputs to 64.
void emitDataParallelKernelImpl(llvm::IRBuilder<> &builder,
llvm::ArrayRef<const Instruction *> bundle,
llvm::ArrayRef<llvm::Type *> argTypes,
llvm::DenseMap<Value *, int> &bufferToArgNum,
llvm::ArrayRef<llvm::Value *> buffers);
/// \param builder IRBuilder to be used for the LLVM IR code emission.
/// \param bundle set of instructions to be emitted as a data-parallel kernel.
/// \param argType types of arguments for the data-parallel kernel.
/// \bufferToArgNum mapping from a buffer to its argument number in the
/// data-parallel kernel.
/// \param buffers buffers used by the data-parallel kernel.
virtual void
emitDataParallelKernelImpl(llvm::IRBuilder<> &builder,
llvm::ArrayRef<const Instruction *> bundle,
llvm::ArrayRef<llvm::Type *> argTypes,
llvm::DenseMap<Value *, int> &bufferToArgNum,
llvm::ArrayRef<llvm::Value *> buffers);

protected:
/// The IR to generate code for.
const IRFunction *F_;
/// The LLVM context.
@@ -129,10 +134,19 @@ class LLVMIRGen {
/// specializer not to specialize.
llvm::DenseSet<llvm::Value *> dontSpecializeArgsSet_;

/// Bitcode of the libjit. Containts the starting address and the length of
/// the bitcode.
llvm::StringRef libjitBC_;

/// Generates LLVM IR that computes the address of \p val using \p builder.
/// The address type is specified by \p ptrTy.
llvm::Value *emitValueAddress(llvm::IRBuilder<> &builder,
const glow::Value *val);
/// Emit the address of the buffer \p v inside a data-parallel kernel \p
/// kernel using the mapping provided by \p bufferToArgNum.
llvm::Value *emitBufferAddress(llvm::IRBuilder<> &builder, Value *val,
llvm::Function *kernel,
llvm::DenseMap<Value *, int> &bufferToArgNum);
/// Generates LLVM IR that computes the size of the tensor of \p val using
/// \p builder. The size type is native to the machine (size_t).
llvm::Value *emitValueSize(llvm::IRBuilder<> &builder,
@@ -177,7 +191,9 @@ class LLVMIRGen {
/// stacked \p kernel. The current loop count is described by \p loopCount.
/// The \p bufferToArgNum map can be used to find the required buffers, which
/// are provided as arguments to the stacked \p kernel.
void generateLLVMIRForDataParallelInstr(
/// Derived classes may want to override this function to implement a
/// backend-specific LLVM IR generation logic for some intructions.
virtual void generateLLVMIRForDataParallelInstr(
llvm::IRBuilder<> &builder, const glow::Instruction *I,
llvm::Function *kernel, llvm::DenseMap<Value *, int> &bufferToArgNum,
llvm::Value *loopCount);
@@ -212,13 +228,22 @@ class LLVMIRGen {
/// Destructor
virtual ~LLVMIRGen() {}
/// Ctor.
/// \param M IRFunction to be converted into LLVM IR.
/// \param allocationsInfo information about allocation of weights and
/// activations.
/// \param mainEntryName Name of the main entry.
/// \param libjitBC bitcode of the backend's libjit library.
explicit LLVMIRGen(const IRFunction *M, AllocationsInfo &allocationsInfo,
std::string mainEntryName);
std::string mainEntryName, llvm::StringRef libjitBC);

/// Init the TargetMachine using a given target and code model.
void initTargetMachine(llvm::StringRef T, llvm::CodeModel::Model CM);
virtual void initTargetMachine(llvm::StringRef T, llvm::CodeModel::Model CM);

/// Emit LLVM-IR for the instruction \p I, using the builder \p builder.
/// Derived classes may want to override this function to implement a
/// backend-specific LLVM IR generation logic for some intructions.
/// \param builder IRBuilder to be used to emit LLVM IR code.
/// \param I IR instruction which should be compiled into LLVM IR.
virtual void generateLLVMIRForInstr(llvm::IRBuilder<> &builder,
const glow::Instruction *I);
/// Emit LLVM-IR for the whole IRFunction.
@@ -227,11 +252,6 @@ class LLVMIRGen {
llvm::Function *getFunction(const std::string &name);
/// \returns a libjit API function by name and tensor element type.
llvm::Function *getFunction(const std::string &name, glow::ElemKind elemTy);
/// Creates global variables for the base addresses of different memory areas
/// and invokes a library function to set their values.
void
createGlobalVariables(llvm::IRBuilder<> &builder,
llvm::ArrayRef<llvm::Value *> initFunctionCallArgs);
/// Optimize the function \p F and the module that owns it. Use the target
/// information from the \p TM target machine.
void optimizeLLVMModule(llvm::Function *F, llvm::TargetMachine &TM);
@@ -279,4 +299,4 @@ class LLVMIRGen {

} // namespace glow

#endif // GLOW_BACKENDS_CPU_LLVMIRGEN_H
#endif // GLOW_LLVMIRCODEGEN_LLVMIRGEN_H
@@ -44,19 +44,19 @@ foreach(libjit_src_file ${libjit_files})
endforeach()

add_custom_command(
OUTPUT ${GLOW_BINARY_DIR}/libjit.bc
COMMAND ${LLVM_LINK_BIN} -o ${GLOW_BINARY_DIR}/libjit.bc ${CPURuntime_OBJS}
OUTPUT ${GLOW_BINARY_DIR}/CPU/libjit.bc
COMMAND ${LLVM_LINK_BIN} -o ${GLOW_BINARY_DIR}/CPU/libjit.bc ${CPURuntime_OBJS}
DEPENDS ${CPURuntime_OBJS} ${CPURuntime_SRCS}
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")

add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/glow/libjit_bc.inc
COMMAND include-bin "${CMAKE_BINARY_DIR}/libjit.bc" "${CMAKE_BINARY_DIR}/glow/libjit_bc.inc"
DEPENDS ${GLOW_BINARY_DIR}/libjit.bc
OUTPUT ${CMAKE_BINARY_DIR}/glow/CPU/libjit_bc.inc
COMMAND include-bin "${CMAKE_BINARY_DIR}/CPU/libjit.bc" "${CMAKE_BINARY_DIR}/glow/CPU/libjit_bc.inc"
DEPENDS ${GLOW_BINARY_DIR}/CPU/libjit.bc
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")

add_custom_target(CPURuntime
DEPENDS ${CMAKE_BINARY_DIR}/glow/libjit_bc.inc
DEPENDS ${CMAKE_BINARY_DIR}/glow/CPU/libjit_bc.inc
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}")

if (NOT MSVC)
@@ -67,20 +67,12 @@ if (NOT MSVC)
endif(NOT MSVC)

add_library(CPUBackend
"${CMAKE_BINARY_DIR}/glow/libjit_bc.inc"
AllocationsInfo.cpp
BundleSaver.cpp
CommandLine.cpp
"${CMAKE_BINARY_DIR}/glow/CPU/libjit_bc.inc"
CPUFunction.cpp
DebugInfo.cpp
FunctionSpecializer.cpp
GlowJIT.cpp
Pipeline.cpp
Transforms.cpp
LLVMIRGen.cpp
CPUBackend.cpp)
CPUBackend.cpp
CPULLVMIRGen.cpp)

llvm_map_components_to_libnames(LLVM_TARGET_LIBRARIES ${LLVM_TARGETS_TO_BUILD})
target_link_libraries(CPUBackend
PUBLIC
Backend
@@ -90,29 +82,7 @@ target_link_libraries(CPUBackend
IR
Optimizer
QuantizationBase
${LLVM_TARGET_LIBRARIES}
LLVMAnalysis
LLVMBitWriter
LLVMCodeGen
LLVMCore
LLVMExecutionEngine
LLVMIRReader
LLVMInstCombine
LLVMInterpreter
LLVMMC
LLVMObject
LLVMPasses
LLVMScalarOpts
LLVMSupport
LLVMTarget
LLVMTransformUtils
LLVMVectorize
LLVMipo)
if(LLVM_VERSION_MAJOR VERSION_GREATER 6)
target_link_libraries(CPUBackend
PRIVATE
LLVMOrcJIT)
endif()
LLVMIRCodeGen)
add_dependencies(CPUBackend CPURuntime)

add_library(CPUDeviceManager
Oops, something went wrong.

0 comments on commit 43106fc

Please sign in to comment.
You can’t perform that action at this time.