/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/SourceMgr.h"
#include "sys/cvar.hpp"
#include "src/GBEConfig.h"
#include "llvm/llvm_gen_backend.hpp"
#if LLVM_VERSION_MINOR >= 5
#include "llvm/Linker/Linker.h"
#else
#include "llvm/Linker.h"
#endif
using namespace llvm;
SVAR(OCL_BITCODE_LIB_PATH, OCL_BITCODE_BIN);
namespace gbe
{
static Module* createOclBitCodeModule(LLVMContext& ctx, bool strictMath)
{
std::string bitCodeFiles = OCL_BITCODE_LIB_PATH;
std::istringstream bitCodeFilePath(bitCodeFiles);
std::string FilePath;
bool findBC = false;
Module* oclLib = NULL;
SMDiagnostic Err;
while (std::getline(bitCodeFilePath, FilePath, ':')) {
if(access(FilePath.c_str(), R_OK) == 0) {
findBC = true;
break;
}
}
assert(findBC);
oclLib = getLazyIRFileModule(FilePath, Err, ctx);
if (!oclLib) {
printf("Fatal Error: ocl lib can not be opened\n");
return NULL;
}
if (strictMath) {
llvm::GlobalVariable* mathFastFlag = oclLib->getGlobalVariable("__ocl_math_fastpath_flag");
assert(mathFastFlag);
Type* intTy = IntegerType::get(ctx, 32);
mathFastFlag->setInitializer(ConstantInt::get(intTy, 0));
}
return oclLib;
}
static bool materializedFuncCall(Module& src, Module& lib, llvm::Function &KF, std::set& MFS)
{
bool fromSrc = false;
for (llvm::Function::iterator B = KF.begin(), BE = KF.end(); B != BE; B++) {
for (BasicBlock::iterator instI = B->begin(),
instE = B->end(); instI != instE; ++instI) {
llvm::CallInst* call = dyn_cast(instI);
if (!call) {
continue;
}
if (call->getCalledFunction() &&
call->getCalledFunction()->getIntrinsicID() != 0)
continue;
Value *Callee = call->getCalledValue();
const std::string fnName = Callee->getName();
if (!MFS.insert(fnName).second) {
continue;
}
fromSrc = false;
llvm::Function *newMF = lib.getFunction(fnName);
if (!newMF) {
newMF = src.getFunction(fnName);
if (!newMF) {
printf("Can not find the lib: %s\n", fnName.c_str());
return false;
}
fromSrc = true;
}
std::string ErrInfo;// = "Not Materializable";
if (!fromSrc && newMF->isMaterializable()) {
if (newMF->Materialize(&ErrInfo)) {
printf("Can not materialize the function: %s, because %s\n", fnName.c_str(), ErrInfo.c_str());
return false;
}
}
if (!materializedFuncCall(src, lib, *newMF, MFS))
return false;
}
}
return true;
}
Module* runBitCodeLinker(Module *mod, bool strictMath)
{
LLVMContext& ctx = mod->getContext();
std::set materializedFuncs;
Module* clonedLib = createOclBitCodeModule(ctx, strictMath);
assert(clonedLib && "Can not create the beignet bitcode\n");
std::vector kernels;
std::vector builtinFuncs;
/* Add the memset and memcpy functions here. */
builtinFuncs.push_back("__gen_memcpy_gg");
builtinFuncs.push_back("__gen_memcpy_gp");
builtinFuncs.push_back("__gen_memcpy_gl");
builtinFuncs.push_back("__gen_memcpy_pg");
builtinFuncs.push_back("__gen_memcpy_pp");
builtinFuncs.push_back("__gen_memcpy_pl");
builtinFuncs.push_back("__gen_memcpy_lg");
builtinFuncs.push_back("__gen_memcpy_lp");
builtinFuncs.push_back("__gen_memcpy_ll");
builtinFuncs.push_back("__gen_memset_p");
builtinFuncs.push_back("__gen_memset_g");
builtinFuncs.push_back("__gen_memset_l");
builtinFuncs.push_back("__gen_memcpy_gg_align");
builtinFuncs.push_back("__gen_memcpy_gp_align");
builtinFuncs.push_back("__gen_memcpy_gl_align");
builtinFuncs.push_back("__gen_memcpy_pg_align");
builtinFuncs.push_back("__gen_memcpy_pp_align");
builtinFuncs.push_back("__gen_memcpy_pl_align");
builtinFuncs.push_back("__gen_memcpy_lg_align");
builtinFuncs.push_back("__gen_memcpy_lp_align");
builtinFuncs.push_back("__gen_memcpy_ll_align");
builtinFuncs.push_back("__gen_memset_p_align");
builtinFuncs.push_back("__gen_memset_g_align");
builtinFuncs.push_back("__gen_memset_l_align");
builtinFuncs.push_back("__gen_memcpy_pc");
builtinFuncs.push_back("__gen_memcpy_gc");
builtinFuncs.push_back("__gen_memcpy_lc");
builtinFuncs.push_back("__gen_memcpy_pc_align");
builtinFuncs.push_back("__gen_memcpy_gc_align");
builtinFuncs.push_back("__gen_memcpy_lc_align");
for (Module::iterator SF = mod->begin(), E = mod->end(); SF != E; ++SF) {
if (SF->isDeclaration()) continue;
if (!isKernelFunction(*SF)) continue;
kernels.push_back(SF->getName().data());
if (!materializedFuncCall(*mod, *clonedLib, *SF, materializedFuncs)) {
delete clonedLib;
return NULL;
}
}
if (kernels.empty()) {
printf("One module without kernel function!\n");
delete clonedLib;
return NULL;
}
for (auto &f : builtinFuncs) {
const std::string fnName(f);
if (!materializedFuncs.insert(fnName).second) {
continue;
}
llvm::Function *newMF = clonedLib->getFunction(fnName);
if (!newMF) {
printf("Can not find the function: %s\n", fnName.c_str());
delete clonedLib;
return NULL;
}
std::string ErrInfo;// = "Not Materializable";
if (newMF->isMaterializable()) {
if (newMF->Materialize(&ErrInfo)) {
printf("Can not materialize the function: %s, because %s\n", fnName.c_str(), ErrInfo.c_str());
delete clonedLib;
return NULL;
}
}
if (!materializedFuncCall(*mod, *clonedLib, *newMF, materializedFuncs)) {
delete clonedLib;
return NULL;
}
kernels.push_back(f);
}
/* We use beignet's bitcode as dst because it will have a lot of
lazy functions which will not be loaded. */
std::string errorMsg;
if(Linker::LinkModules(clonedLib, mod, Linker::DestroySource, &errorMsg)) {
delete clonedLib;
printf("Fatal Error: link the bitcode error:\n%s\n", errorMsg.c_str());
return NULL;
}
llvm::PassManager passes;
passes.add(createInternalizePass(kernels));
passes.add(createGlobalDCEPass());
passes.run(*clonedLib);
return clonedLib;
}
} // end namespace