From 5262e04facf01c7165ecfc604350691cc8a3efab Mon Sep 17 00:00:00 2001 From: Luo Date: Fri, 6 Jun 2014 14:17:31 +0800 Subject: [PATCH] remove the code of saving the llvm bitcode to file, replace it with llvm::Module Save the global LLVMContext and module pointer to GenProgram, delete the module pointer in the destructor. Signed-off-by: Luo Reviewed-by: "Song, Ruiling" --- backend/src/backend/gen_program.cpp | 33 +++++++++++-- backend/src/backend/gen_program.hpp | 4 +- backend/src/backend/program.cpp | 95 ++++++++++++++++++++----------------- backend/src/backend/program.h | 3 +- backend/src/backend/program.hpp | 2 +- backend/src/llvm/llvm_to_gen.cpp | 16 ++++--- backend/src/llvm/llvm_to_gen.hpp | 2 +- src/cl_program.c | 2 +- 8 files changed, 100 insertions(+), 57 deletions(-) diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index bd12f15..9fca8fa 100644 --- a/backend/src/backend/gen_program.cpp +++ b/backend/src/backend/gen_program.cpp @@ -22,6 +22,17 @@ * \author Benjamin Segovia */ +#include "llvm/Config/config.h" +#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2 +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/DataLayout.h" +#else +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/DataLayout.h" +#endif /* LLVM_VERSION_MINOR <= 2 */ + #include "backend/program.h" #include "backend/gen_program.h" #include "backend/gen_program.hpp" @@ -33,6 +44,8 @@ #include "ir/unit.hpp" #include "llvm/llvm_to_gen.hpp" +#include + #include #include #include @@ -74,7 +87,19 @@ namespace gbe { #endif } - GenProgram::~GenProgram(void) {} + GenProgram::~GenProgram(void){ +#ifdef GBE_COMPILER_AVAILABLE + if(module){ + delete (llvm::Module*)module; + module = NULL; + } + + if(llvm_ctx){ + delete (llvm::LLVMContext*)llvm_ctx; + llvm_ctx = NULL; + } +#endif + } /*! We must avoid spilling at all cost with Gen */ static const struct CodeGenStrategy { @@ -182,17 +207,19 @@ namespace gbe { static gbe_program genProgramNewFromLLVM(uint32_t deviceID, const char *fileName, + const void* module, + const void* llvm_ctx, size_t stringSize, char *err, size_t *errSize, int optLevel) { using namespace gbe; - GenProgram *program = GBE_NEW(GenProgram, deviceID); + GenProgram *program = GBE_NEW(GenProgram, deviceID, module, llvm_ctx); #ifdef GBE_COMPILER_AVAILABLE std::string error; // Try to compile the program - if (program->buildFromLLVMFile(fileName, error, optLevel) == false) { + if (program->buildFromLLVMFile(fileName, module, error, optLevel) == false) { if (err != NULL && errSize != NULL && stringSize > 0u) { const size_t msgSize = std::min(error.size(), stringSize-1u); std::memcpy(err, error.c_str(), msgSize); diff --git a/backend/src/backend/gen_program.hpp b/backend/src/backend/gen_program.hpp index da96aa0..d308212 100644 --- a/backend/src/backend/gen_program.hpp +++ b/backend/src/backend/gen_program.hpp @@ -59,7 +59,7 @@ namespace gbe { public: /*! Create an empty program */ - GenProgram(uint32_t deviceID) : deviceID(deviceID) {} + GenProgram(uint32_t deviceID, const void* mod = NULL, const void* ctx = NULL) : deviceID(deviceID),module((void*)mod), llvm_ctx((void*)ctx) {} /*! Current device ID*/ uint32_t deviceID; /*! Destroy the program */ @@ -70,6 +70,8 @@ namespace gbe virtual Kernel *allocateKernel(const std::string &name) { return GBE_NEW(GenKernel, name, deviceID); } + void* module; + void* llvm_ctx; /*! Use custom allocators */ GBE_CLASS(GenProgram); }; diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp index 949aeb4..6e50761 100644 --- a/backend/src/backend/program.cpp +++ b/backend/src/backend/program.cpp @@ -34,6 +34,8 @@ #include "llvm/Config/config.h" #include "llvm/Support/Threading.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/IR/LLVMContext.h" #include #include #include @@ -103,9 +105,13 @@ namespace gbe { #ifdef GBE_COMPILER_AVAILABLE BVAR(OCL_OUTPUT_GEN_IR, false); - bool Program::buildFromLLVMFile(const char *fileName, std::string &error, int optLevel) { + bool Program::buildFromLLVMFile(const char *fileName, const void* module, std::string &error, int optLevel) { ir::Unit *unit = new ir::Unit(); - if (llvmToGen(*unit, fileName, optLevel) == false) { + llvm::Module * cloned_module = NULL; + if(module){ + cloned_module = llvm::CloneModule((llvm::Module*)module); + } + if (llvmToGen(*unit, fileName, module, optLevel) == false) { error = std::string(fileName) + " not found"; return false; } @@ -114,11 +120,18 @@ namespace gbe { if(!unit->getValid()) { delete unit; //clear unit unit = new ir::Unit(); - llvmToGen(*unit, fileName, 0); //suppose file exists and llvmToGen will not return false. + if(cloned_module){ + llvmToGen(*unit, fileName, cloned_module, 0); //suppose file exists and llvmToGen will not return false. + }else{ + llvmToGen(*unit, fileName, module, 0); //suppose file exists and llvmToGen will not return false. + } } assert(unit->getValid()); this->buildFromUnit(*unit, error); delete unit; + if(cloned_module){ + delete (llvm::Module*) cloned_module; + } return true; } @@ -518,7 +531,7 @@ namespace gbe { SVAR(OCL_PCH_PATH, PCH_OBJECT_DIR); SVAR(OCL_PCM_PATH, PCM_OBJECT_DIR); - static bool buildModuleFromSource(const char* input, const char* output, std::string options, + static bool buildModuleFromSource(const char* input, llvm::Module** out_module, llvm::LLVMContext* llvm_ctx, std::string options, size_t stringSize, char *err, size_t *errSize) { // Arguments to pass to the clang frontend vector args; @@ -634,7 +647,7 @@ namespace gbe { } // Create an action and make the compiler instance carry it out - llvm::OwningPtr Act(new clang::EmitLLVMOnlyAction()); + llvm::OwningPtr Act(new clang::EmitLLVMOnlyAction(llvm_ctx)); std::string dirs = OCL_PCM_PATH; std::string pcmFileName; @@ -669,50 +682,23 @@ namespace gbe { llvm::Module *module = Act->takeModule(); -#if (LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 3) - auto mode = llvm::sys::fs::F_Binary; -#else - auto mode = llvm::raw_fd_ostream::F_Binary; -#endif - llvm::raw_fd_ostream OS(output, ErrorString, mode); - //still write to temp file for code simply, otherwise need add another function. - //because gbe_program_new_from_llvm also be used by cl_program_create_from_llvm, can't be removed - //TODO: Pass module to llvmToGen, if use module, should return Act and use OwningPtr out of this funciton - llvm::WriteBitcodeToFile(module, OS); - if (err != NULL && *errSize < stringSize - 1 && ErrorString.size() > 0) { - size_t errLen; - errLen = ErrorString.copy(err + *errSize, stringSize - *errSize - 1, 0); - *errSize += errLen; - } - - if (err == NULL || OCL_OUTPUT_BUILD_LOG) { - // flush the error messages to the errs() if there is no - // error string buffer. - llvm::errs() << ErrorString; - } - OS.close(); + *out_module = module; return true; } extern std::string ocl_stdlib_str; BVAR(OCL_USE_PCH, true); - static gbe_program programNewFromSource(uint32_t deviceID, - const char *source, - size_t stringSize, - const char *options, - char *err, - size_t *errSize) + static void processSourceAndOption(const char *source, + const char *options, + const char *temp_header_path, + std::string& clOpt, + std::string& clName, + int& optLevel) { char clStr[] = "/tmp/XXXXXX.cl"; - char llStr[] = "/tmp/XXXXXX.ll"; int clFd = mkstemps(clStr, 3); - int llFd = mkstemps(llStr, 3); - close(llFd); - const std::string clName = std::string(clStr); - const std::string llName = std::string(llStr); - std::string clOpt; - int optLevel = 1; + clName = std::string(clStr); FILE *clFile = fdopen(clFd, "w"); FATAL_IF(clFile == NULL, "Failed to open temporary file"); @@ -812,6 +798,13 @@ namespace gbe { } else fwrite(ocl_stdlib_str.c_str(), strlen(ocl_stdlib_str.c_str()), 1, clFile); + //for clCompilerProgram usage. + if(temp_header_path){ + clOpt += " -I "; + clOpt += temp_header_path; + clOpt += " "; + } + if (!OCL_STRICT_CONFORMANCE) { fwrite(ocl_mathfunc_fastpath_str.c_str(), strlen(ocl_mathfunc_fastpath_str.c_str()), 1, clFile); } @@ -823,9 +816,25 @@ namespace gbe { // Write the source to the cl file fwrite(source, strlen(source), 1, clFile); fclose(clFile); + } + + static gbe_program programNewFromSource(uint32_t deviceID, + const char *source, + size_t stringSize, + const char *options, + char *err, + size_t *errSize) + { + int optLevel = 1; + std::string clOpt; + std::string clName; + processSourceAndOption(source, options, NULL, clOpt, clName, optLevel); gbe_program p; - if (buildModuleFromSource(clName.c_str(), llName.c_str(), clOpt.c_str(), + // will delete the module and act in the destructor of GenProgram. + llvm::Module * out_module; + llvm::LLVMContext* llvm_ctx = new llvm::LLVMContext; + if (buildModuleFromSource(clName.c_str(), &out_module, llvm_ctx, clOpt.c_str(), stringSize, err, errSize)) { // Now build the program from llvm static std::mutex gbe_mutex; @@ -837,14 +846,14 @@ namespace gbe { err += *errSize; clangErrSize = *errSize; } - p = gbe_program_new_from_llvm(deviceID, llName.c_str(), stringSize, + + p = gbe_program_new_from_llvm(deviceID, NULL, out_module, llvm_ctx, stringSize, err, errSize, optLevel); if (err != NULL) *errSize += clangErrSize; gbe_mutex.unlock(); if (OCL_OUTPUT_BUILD_LOG && options) llvm::errs() << options; - remove(llName.c_str()); } else p = NULL; remove(clName.c_str()); diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h index 8727966..5c72964 100644 --- a/backend/src/backend/program.h +++ b/backend/src/backend/program.h @@ -120,7 +120,6 @@ typedef gbe_program (gbe_program_new_from_source_cb)(uint32_t deviceID, char *err, size_t *err_size); extern gbe_program_new_from_source_cb *gbe_program_new_from_source; - /*! Create a new program from the given blob */ typedef gbe_program (gbe_program_new_from_binary_cb)(uint32_t deviceID, const char *binary, size_t size); extern gbe_program_new_from_binary_cb *gbe_program_new_from_binary; @@ -132,6 +131,8 @@ extern gbe_program_serialize_to_binary_cb *gbe_program_serialize_to_binary; /*! Create a new program from the given LLVM file */ typedef gbe_program (gbe_program_new_from_llvm_cb)(uint32_t deviceID, const char *fileName, + const void *module, + const void *llvm_ctx, size_t string_size, char *err, size_t *err_size, diff --git a/backend/src/backend/program.hpp b/backend/src/backend/program.hpp index 6bb1529..1235d51 100644 --- a/backend/src/backend/program.hpp +++ b/backend/src/backend/program.hpp @@ -234,7 +234,7 @@ namespace gbe { /*! Build a program from a ir::Unit */ bool buildFromUnit(const ir::Unit &unit, std::string &error); /*! Buils a program from a LLVM source code */ - bool buildFromLLVMFile(const char *fileName, std::string &error, int optLevel); + bool buildFromLLVMFile(const char *fileName, const void* module, std::string &error, int optLevel); /*! Buils a program from a OCL string */ bool buildFromSource(const char *source, std::string &error); /*! Get size of the global constant arrays */ diff --git a/backend/src/llvm/llvm_to_gen.cpp b/backend/src/llvm/llvm_to_gen.cpp index 9282b3f..2bb9da1 100644 --- a/backend/src/llvm/llvm_to_gen.cpp +++ b/backend/src/llvm/llvm_to_gen.cpp @@ -61,6 +61,8 @@ #include "sys/cvar.hpp" #include "sys/platform.hpp" +#include + #include #include #include @@ -163,10 +165,8 @@ namespace gbe MPM.run(mod); } - bool llvmToGen(ir::Unit &unit, const char *fileName, int optLevel) + bool llvmToGen(ir::Unit &unit, const char *fileName,const void* module, int optLevel) { - // Get the global LLVM context - llvm::LLVMContext& c = llvm::getGlobalContext(); std::string errInfo; std::unique_ptr o = NULL; if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS || OCL_OUTPUT_LLVM) @@ -175,9 +175,13 @@ namespace gbe // Get the module from its file llvm::SMDiagnostic Err; std::auto_ptr M; - M.reset(ParseIRFile(fileName, Err, c)); - if (M.get() == 0) return false; - Module &mod = *M.get(); + if(fileName){ + // only when module is null, Get the global LLVM context + llvm::LLVMContext& c = llvm::getGlobalContext(); + M.reset(ParseIRFile(fileName, Err, c)); + if (M.get() == 0) return false; + } + Module &mod = (module!=NULL)?*(llvm::Module*)module:*M.get(); Triple TargetTriple(mod.getTargetTriple()); TargetLibraryInfo *libraryInfo = new TargetLibraryInfo(TargetTriple); diff --git a/backend/src/llvm/llvm_to_gen.hpp b/backend/src/llvm/llvm_to_gen.hpp index 50ea267..41e3477 100644 --- a/backend/src/llvm/llvm_to_gen.hpp +++ b/backend/src/llvm/llvm_to_gen.hpp @@ -32,7 +32,7 @@ namespace gbe { /*! Convert the LLVM IR code to a GEN IR code, optLevel 0 equal to clang -O1 and 1 equal to clang -O2*/ - bool llvmToGen(ir::Unit &unit, const char *fileName, int optLevel); + bool llvmToGen(ir::Unit &unit, const char *fileName, const void* module, int optLevel); } /* namespace gbe */ diff --git a/src/cl_program.c b/src/cl_program.c index af9d21e..42058e8 100644 --- a/src/cl_program.c +++ b/src/cl_program.c @@ -226,7 +226,7 @@ cl_program_create_from_llvm(cl_context ctx, INVALID_VALUE_IF (file_name == NULL); program = cl_program_new(ctx); - program->opaque = compiler_program_new_from_llvm(ctx->device->vendor_id, file_name, program->build_log_max_sz, program->build_log, &program->build_log_sz, 1); + program->opaque = compiler_program_new_from_llvm(ctx->device->vendor_id, file_name, NULL, NULL, program->build_log_max_sz, program->build_log, &program->build_log_sz, 1); if (UNLIKELY(program->opaque == NULL)) { err = CL_INVALID_PROGRAM; goto error; -- 2.7.4