P4 to Git Change 1273413 by smekhano@stas-nova-hsa on 2016/05/26 12:52:54
SWDEV-85602 - HSA HLC: serialize linking
Since we do not have build referenced symbol map now during linking we do not have to keep all library modules
in memory during the whole link process. This change serializes linking to save some memory.
Testing: smoke, precheckin
Reviewed by Evgeny Mankov
Affected files ...
... //depot/stg/opencl/drivers/opencl/compiler/lib/backends/common/linker.cpp#145 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/linker/include/AMDResolveLinker.h#5 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/linker/lib/AMDResolveLinker.cpp#5 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/linker/tools/opencl-link/opencl-link.cpp#7 edit
[ROCm/clr commit: 1161118bc3]
Этот коммит содержится в:
@@ -563,15 +563,6 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
}
|
||||
|
||||
if (Options()->isDumpFlagSet(amd::option::DUMP_BC_ORIGINAL)) {
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
std::string MyErrorInfo;
|
||||
std::string fileName = Options()->getDumpFileName("_original.bc");
|
||||
llvm::raw_fd_ostream outs(fileName.c_str(), MyErrorInfo, llvm::raw_fd_ostream::F_Binary);
|
||||
if (MyErrorInfo.empty())
|
||||
WriteBitcodeToFile(LLVMBinary(), outs);
|
||||
else
|
||||
printf(MyErrorInfo.c_str());
|
||||
#else
|
||||
std::string fileName = Options()->getDumpFileName("_original.bc");
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream outs(fileName.c_str(), EC, llvm::sys::fs::F_None);
|
||||
@@ -579,7 +570,6 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
WriteBitcodeToFile(LLVMBinary(), outs);
|
||||
else
|
||||
printf(EC.message().c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAS_SPIRV
|
||||
@@ -598,89 +588,6 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<llvm::Module*> LibMs;
|
||||
|
||||
// The AMDIL GPU libraries include 32 bit specific, 64 bit specific and common
|
||||
// libraries. The common libraries do not have target triple. A search is
|
||||
// performed to find the first library containing non-empty target triple
|
||||
// and use it for translating SPIR.
|
||||
amd::LibraryDescriptor LibDescs[
|
||||
amd::LibraryDescriptor::MAX_NUM_LIBRARY_DESCS];
|
||||
int sz;
|
||||
std::string LibTargetTriple;
|
||||
std::string LibDataLayout;
|
||||
if (amd::getLibDescs(Options()->libraryType_, LibDescs, sz) != 0) {
|
||||
// FIXME: If we error here, we don't clean up, so we crash in debug build
|
||||
// on compilerfini().
|
||||
BuildLog() += "Internal Error: finding libraries failed!\n";
|
||||
return 1;
|
||||
}
|
||||
for (int i=0; i < sz; i++) {
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
llvm::MemoryBuffer* Buffer = 0;
|
||||
llvm::Module* Library = amd::LoadLibrary(LibDescs[i].start, LibDescs[i].size, Context(), &Buffer);
|
||||
#else
|
||||
llvm::Module *Library = amd::LoadLibrary(LibDescs[i].start, LibDescs[i].size, Context());
|
||||
#endif
|
||||
DEBUG(llvm::dbgs() << "Loaded library " << i << "\n");
|
||||
if ( !Library ) {
|
||||
BuildLog() += "Internal Error: cannot load library!\n";
|
||||
delete LLVMBinary();
|
||||
for (int j = 0; j < i; ++j) {
|
||||
delete LibMs[j];
|
||||
}
|
||||
LibMs.clear();
|
||||
return 1;
|
||||
#ifndef NDEBUG
|
||||
} else {
|
||||
if ( llvm::verifyModule( *Library ) ) {
|
||||
BuildLog() += "Internal Error: library verification failed!\n";
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
DEBUG_WITH_TYPE("linkTriple", llvm::dbgs() << "Library[" << i << "] " <<
|
||||
Library->getTargetTriple() << ' ' << Library->getDataLayout() << '\n');
|
||||
// Find the first library whose target triple is not empty.
|
||||
if (LibTargetTriple.empty() && !Library->getTargetTriple().empty()) {
|
||||
LibTargetTriple = Library->getTargetTriple();
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
LibDataLayout = Library->getDataLayout();
|
||||
#else
|
||||
LibDataLayout = Library->getDataLayoutStr();
|
||||
#endif
|
||||
}
|
||||
LibMs.push_back(Library);
|
||||
}
|
||||
|
||||
// Check consistency of target and data layout
|
||||
assert (!LibTargetTriple.empty() && "At least one library should have triple");
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 0, e = LibMs.size(); i < e; ++i) {
|
||||
if (LibMs[i]->getTargetTriple().empty())
|
||||
continue;
|
||||
assert (LibMs[i]->getTargetTriple() == LibTargetTriple &&
|
||||
"Library target triple should match");
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
assert (LibMs[i]->getDataLayout() == LibDataLayout &&
|
||||
"Library data layout should match");
|
||||
#else
|
||||
assert (LibMs[i]->getDataLayoutStr() == LibDataLayout &&
|
||||
"Library data layout should match");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
AMDSpir::replaceTrivialFunc(*LLVMBinary());
|
||||
|
||||
if (!llvm::fixupKernelModule(LLVMBinary(), LibTargetTriple, LibDataLayout))
|
||||
return 1;
|
||||
|
||||
// Before doing anything else, quickly optimize Module
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_prelinkopt = amd::Os::timeNanos();
|
||||
}
|
||||
llvm::StringRef chip(aclGetChip(Elf()->target));
|
||||
setGPU(IsGPUTarget);
|
||||
setFiniteMathOnly(Options()->oVariables->FiniteMathOnly);
|
||||
@@ -693,10 +600,8 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
setFP32RoundDivideSqrt(Options()->oVariables->FP32RoundDivideSqrt);
|
||||
setUseNative(Options()->oVariables->OptUseNative);
|
||||
setDenormsAreZero(Options()->oVariables->DenormsAreZero);
|
||||
#if !defined(LEGACY_COMPLIB)
|
||||
llvm::HLC_FlushF32Denorms = Options()->oVariables->DenormsAreZero;
|
||||
llvm::HLC_Max_WG_Size = 2048; // Maximum HW supported workgroup size
|
||||
#endif
|
||||
setUniformWorkGroupSize(Options()->oVariables->UniformWorkGroupSize);
|
||||
setHaveFastFMA32(chip == "Cypress"
|
||||
|| chip == "Cayman"
|
||||
@@ -707,44 +612,111 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
setISAVersion(getIsaType(aclutGetTargetInfo(Elf())));
|
||||
LLVMBinary()->getContext().setAMDLLVMContextHook(&hookup_);
|
||||
|
||||
std::string clp_errmsg;
|
||||
llvm::Module *OnFlyLib = AMDPrelink(LLVMBinary(), clp_errmsg);
|
||||
|
||||
if (!clp_errmsg.empty()) {
|
||||
delete LLVMBinary();
|
||||
for (unsigned int i = 0; i < LibMs.size(); ++ i) {
|
||||
delete LibMs[i];
|
||||
}
|
||||
LibMs.clear();
|
||||
BuildLog() += clp_errmsg;
|
||||
BuildLog() += "Internal Error: on-fly library generation failed\n";
|
||||
amd::LibraryDescriptor LibDescs[
|
||||
amd::LibraryDescriptor::MAX_NUM_LIBRARY_DESCS];
|
||||
int sz;
|
||||
std::string LibTargetTriple;
|
||||
std::string LibDataLayout;
|
||||
if (amd::getLibDescs(Options()->libraryType_, LibDescs, sz) != 0) {
|
||||
// FIXME: If we error here, we don't clean up, so we crash in debug build
|
||||
// on compilerfini().
|
||||
BuildLog() += "Internal Error: finding libraries failed!\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (OnFlyLib) {
|
||||
// OnFlyLib must be the first!
|
||||
LibMs.insert(LibMs.begin(), OnFlyLib);
|
||||
}
|
||||
AMDSpir::replaceTrivialFunc(*LLVMBinary());
|
||||
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_prelinkopt = amd::Os::timeNanos() - time_prelinkopt;
|
||||
}
|
||||
// Now, do linking by extracting from the builtins library only those
|
||||
// functions that are used in the kernel(s).
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_link = amd::Os::timeNanos();
|
||||
}
|
||||
for (int i=0; i < sz; i++) {
|
||||
std::unique_ptr<llvm::Module> Library(
|
||||
amd::LoadLibrary(LibDescs[i].start, LibDescs[i].size, Context()));
|
||||
|
||||
std::string ErrorMessage;
|
||||
// Link libraries to get every functions that are referenced.
|
||||
std::string ErrorMsg;
|
||||
if (resolveLink(LLVMBinary(), LibMs, &ErrorMsg)) {
|
||||
BuildLog() += ErrorMsg;
|
||||
BuildLog() += "\nInternal Error: linking libraries failed!\n";
|
||||
DEBUG(llvm::dbgs() << "Loaded library " << i << "\n");
|
||||
if ( !Library.get() ) {
|
||||
BuildLog() += "Internal Error: cannot load library!\n";
|
||||
delete LLVMBinary();
|
||||
return 1;
|
||||
}
|
||||
LibMs.clear();
|
||||
#ifndef NDEBUG
|
||||
} else {
|
||||
if ( llvm::verifyModule( *Library.get() ) ) {
|
||||
BuildLog() += "Internal Error: library verification failed!\n";
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (LibTargetTriple.empty()) {
|
||||
// The first member in the list of libraries is assumed to be
|
||||
// representative of the target device.
|
||||
LibTargetTriple = Library->getTargetTriple();
|
||||
LibDataLayout = Library->getDataLayoutStr();
|
||||
DEBUG_WITH_TYPE("linkTriple", llvm::dbgs() << "Library[" << i << "] " <<
|
||||
LibTargetTriple << ' ' << LibDataLayout << '\n');
|
||||
assert(!LibTargetTriple.empty() && !LibDataLayout.empty() &&
|
||||
"First library should have triple and datalayout");
|
||||
|
||||
if (!llvm::fixupKernelModule(LLVMBinary(), LibTargetTriple, LibDataLayout))
|
||||
return 1;
|
||||
|
||||
// Before doing anything else, quickly optimize Module
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_prelinkopt = amd::Os::timeNanos();
|
||||
}
|
||||
|
||||
std::string clp_errmsg;
|
||||
llvm::Module *OnFlyLib = AMDPrelink(LLVMBinary(), clp_errmsg);
|
||||
|
||||
if (!clp_errmsg.empty()) {
|
||||
delete LLVMBinary();
|
||||
BuildLog() += clp_errmsg;
|
||||
BuildLog() += "Internal Error: on-fly library generation failed\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (OnFlyLib) {
|
||||
// OnFlyLib must be the first!
|
||||
std::string ErrorMsg;
|
||||
if (resolveLink(LLVMBinary(), OnFlyLib, &ErrorMsg)) {
|
||||
delete OnFlyLib;
|
||||
BuildLog() += ErrorMsg;
|
||||
BuildLog() += "\nInternal Error: linking libraries failed!\n";
|
||||
return 1;
|
||||
}
|
||||
delete OnFlyLib;
|
||||
}
|
||||
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_prelinkopt = amd::Os::timeNanos() - time_prelinkopt;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check consistency of target and data layout
|
||||
if (!Library->getTargetTriple().empty()) {
|
||||
assert (Library->getTargetTriple() == LibTargetTriple &&
|
||||
"Library target triple should match");
|
||||
assert (Library->getDataLayoutStr() == LibDataLayout &&
|
||||
"Library data layout should match");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now, do linking by extracting from the builtins library only those
|
||||
// functions that are used in the kernel(s).
|
||||
uint64_t tm = Options()->oVariables->EnableBuildTiming ? amd::Os::timeNanos() : 0ULL;
|
||||
|
||||
// Link libraries to get every functions that are referenced.
|
||||
std::string ErrorMsg;
|
||||
if (resolveLink(LLVMBinary(), Library.get(), &ErrorMsg)) {
|
||||
BuildLog() += ErrorMsg;
|
||||
BuildLog() += "\nInternal Error: linking libraries failed!\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_link += amd::Os::timeNanos() - tm;
|
||||
}
|
||||
}
|
||||
|
||||
CreateOptControlFunctions(LLVMBinary());
|
||||
|
||||
if (Options()->oVariables->EnableBuildTiming) {
|
||||
time_link = amd::Os::timeNanos() - time_link;
|
||||
@@ -753,45 +725,13 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
<< (amd::Os::timeNanos() - start_time)/1000ULL
|
||||
<< " us\n"
|
||||
<< " prelinkopt: " << time_prelinkopt/1000ULL << " us\n"
|
||||
<< " link: " << time_link/1000ULL << " us\n"
|
||||
;
|
||||
<< " link: " << time_link/1000ULL << " us\n";
|
||||
appendLogToCL(CL(), tmp_ss.str());
|
||||
}
|
||||
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
// Disable outline macro for mem2reg=0 unless -fdebug-call
|
||||
// is on.
|
||||
if (!Options()->oVariables->OptMem2reg && !Options()->oVariables->DebugCall)
|
||||
Options()->oVariables->UseMacroForCall = false;
|
||||
|
||||
if (isAMDILTarget(Elf()->target) &&
|
||||
getFamilyEnum(&Elf()->target) >= FAMILY_SI &&
|
||||
!Options()->oVariables->clInternalKernel &&
|
||||
(Options()->oVariables->OptMem2reg ||
|
||||
Options()->oVariables->DebugCall)) {
|
||||
auto OV = Options()->oVariables;
|
||||
AMDILFuncSupport::PostLinkProcForFuncSupport(
|
||||
OV->AddUserNoInline,
|
||||
OV->AddLibNoInline,
|
||||
OV->InlineCostThreshold,
|
||||
OV->InlineSizeThreshold,
|
||||
OV->InlineKernelSizeThreshold,
|
||||
OV->AllowMultiLevelCall && OV->UseMacroForCall,
|
||||
LLVMBinary(), LibMs);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Options()->isDumpFlagSet(amd::option::DUMP_BC_LINKED)) {
|
||||
std::string MyErrorInfo;
|
||||
std::string fileName = Options()->getDumpFileName("_linked.bc");
|
||||
#if defined(LEGACY_COMPLIB)
|
||||
llvm::raw_fd_ostream outs(fileName.c_str(), MyErrorInfo, llvm::raw_fd_ostream::F_Binary);
|
||||
// FIXME: Need to add this to the elf binary!
|
||||
if (MyErrorInfo.empty())
|
||||
WriteBitcodeToFile(LLVMBinary(), outs);
|
||||
else
|
||||
printf(MyErrorInfo.c_str());
|
||||
#else
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream outs(fileName.c_str(), EC, llvm::sys::fs::F_None);
|
||||
// FIXME: Need to add this to the elf binary!
|
||||
@@ -799,7 +739,6 @@ amdcl::OCLLinker::link(llvm::Module* input, std::vector<llvm::Module*> &libs)
|
||||
WriteBitcodeToFile(LLVMBinary(), outs);
|
||||
else
|
||||
printf(EC.message().c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check if kernels containing local arrays are called by other kernels.
|
||||
|
||||
Ссылка в новой задаче
Block a user