diff --git a/rocclr/compiler/lib/loaders/elf/elf.hpp b/rocclr/compiler/lib/loaders/elf/elf.hpp index 552ca360f6..3964aa30bb 100644 --- a/rocclr/compiler/lib/loaders/elf/elf.hpp +++ b/rocclr/compiler/lib/loaders/elf/elf.hpp @@ -34,6 +34,9 @@ #ifndef EM_ATI_CALIMAGE_BINARY #define EM_ATI_CALIMAGE_BINARY 125 #endif +#ifndef EM_AMDGPU +#define EM_AMDGPU 224 +#endif #ifndef ELFOSABI_AMD_OPENCL #define ELFOSABI_AMD_OPENCL 201 #endif diff --git a/rocclr/compiler/lib/utils/OPTIONS.def b/rocclr/compiler/lib/utils/OPTIONS.def index b30fbb6657..196cb35852 100644 --- a/rocclr/compiler/lib/utils/OPTIONS.def +++ b/rocclr/compiler/lib/utils/OPTIONS.def @@ -499,7 +499,7 @@ OPTION(OT_BOOL, \ OA_RUNTIME|OVIS_INTERNAL|OVA_DISALLOWED|OFA_PREFIX_F, \ "bin-gpu64", NULL, \ EnableGpuElf64, \ - false, 0, 0, NULL, \ + IS_LIGHTNING ? true : false, 0, 0, NULL, \ "Generate 64-bit ELF binary for GPU (default: 32-bit)") // -fdebug-linker -fno-debug-linker diff --git a/rocclr/runtime/device/cpu/cpuprogram.cpp b/rocclr/runtime/device/cpu/cpuprogram.cpp index 179c483083..436b6ed956 100644 --- a/rocclr/runtime/device/cpu/cpuprogram.cpp +++ b/rocclr/runtime/device/cpu/cpuprogram.cpp @@ -919,7 +919,7 @@ bool Program::linkImpl(amd::option::Options* options) { // Load ISA // For elf format, setup elfIn() and this elfIn() will be released // at the end of build by finiBuild(). - if (!clBinary()->setElfIn(LP64_SWITCH(ELFCLASS32, ELFCLASS64))) { + if (!clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting up input OpenCL binary failed!\n"; LogError("Setting up input binary failed"); return false; @@ -1044,7 +1044,7 @@ bool Program::linkImpl(const std::vector& inputPrograms, // Load ISA // For elf format, setup elfIn() and this elfIn() will be released // at the end of build by finiBuild(). - if (!program->clBinary()->setElfIn(LP64_SWITCH(ELFCLASS32, ELFCLASS64))) { + if (!program->clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting up input OpenCL binary" " failed!\n"; diff --git a/rocclr/runtime/device/device.cpp b/rocclr/runtime/device/device.cpp index 64d49d35dd..b8c1d362d3 100644 --- a/rocclr/runtime/device/device.cpp +++ b/rocclr/runtime/device/device.cpp @@ -614,7 +614,7 @@ bool CacheCompilation::compileAndLinkExecutable(amd::opencl_driver::Compiler* C, return true; } -#endif +#endif // defined(WITH_LIGHTNING_COMPILER) } // namespace amd @@ -1088,7 +1088,7 @@ bool Program::getCompileOptionsAtLinking(const std::vector& inputProgr return true; } -bool Program::initClBinary(char* binaryIn, size_t size) { +bool Program::initClBinary(const char* binaryIn, size_t size) { if (!initClBinary()) { return false; } @@ -1096,7 +1096,7 @@ bool Program::initClBinary(char* binaryIn, size_t size) { // Save the original binary that isn't owned by ClBinary clBinary()->saveOrigBinary(binaryIn, size); - char* bin = binaryIn; + const char* bin = binaryIn; size_t sz = size; // unencrypted @@ -1130,7 +1130,7 @@ bool Program::initClBinary(char* binaryIn, size_t size) { return false; } if (info().arch_id == aclHSAIL || info().arch_id == aclHSAIL64) { - err = aclWriteToMem(aclbin_v30, reinterpret_cast(&bin), &sz); + err = aclWriteToMem(aclbin_v30, (void**)const_cast(&bin), &sz); if (err != ACL_SUCCESS) { LogWarning("aclWriteToMem failed"); aclBinaryFini(aclbin_v30); @@ -1139,7 +1139,7 @@ bool Program::initClBinary(char* binaryIn, size_t size) { aclBinaryFini(aclbin_v30); } else { aclBinary* aclbin_v21 = aclCreateFromBinary(aclbin_v30, aclBIFVersion21); - err = aclWriteToMem(aclbin_v21, reinterpret_cast(&bin), &sz); + err = aclWriteToMem(aclbin_v21, (void**)const_cast(&bin), &sz); if (err != ACL_SUCCESS) { LogWarning("aclWriteToMem failed"); aclBinaryFini(aclbin_v30); @@ -1150,7 +1150,7 @@ bool Program::initClBinary(char* binaryIn, size_t size) { aclBinaryFini(aclbin_v21); } } else -#endif // defined(WITH_LIGHTNING_COMPILER) +#endif // !defined(WITH_LIGHTNING_COMPILER) { size_t decryptedSize; if (!clBinary()->decryptElf(binaryIn, size, &decryptedBin, &decryptedSize, &encryptCode)) { @@ -1177,16 +1177,12 @@ bool Program::initClBinary(char* binaryIn, size_t size) { } -bool Program::setBinary(char* binaryIn, size_t size) { +bool Program::setBinary(const char* binaryIn, size_t size) { if (!initClBinary(binaryIn, size)) { return false; } -#if defined(WITH_LIGHTNING_COMPILER) - if (!clBinary()->setElfIn(ELFCLASS64)) { -#else // !defined(WITH_LIGHTNING_COMPILER) - if (!clBinary()->setElfIn(ELFCLASS32)) { -#endif // !defined(WITH_LIGHTNING_COMPILER) + if (!clBinary()->setElfIn()) { LogError("Setting input OCL binary failed"); return false; } @@ -1209,7 +1205,14 @@ bool Program::setBinary(char* binaryIn, size_t size) { break; } case ET_DYN: { - setType(TYPE_LIBRARY); + char* sect = NULL; + size_t sz = 0; + // FIXME: we should look for the e_machine to detect an HSACO. + if (clBinary()->elfIn()->getSection(amd::OclElf::TEXT, §, &sz) && sect && sz > 0) { + setType(TYPE_EXECUTABLE); + } else { + setType(TYPE_LIBRARY); + } break; } case ET_EXEC: { @@ -1223,35 +1226,12 @@ bool Program::setBinary(char* binaryIn, size_t size) { clBinary()->loadCompileOptions(compileOptions_); clBinary()->loadLinkOptions(linkOptions_); -#if defined(WITH_LIGHTNING_COMPILER) - // TODO: Remove this once BIF is no longer used as we should have a machinasm in - // place to get the binary type correctly from above. - // It is a workaround for executable build from the library. The code object - // binary does not have the type information. - char* sect = NULL; - size_t sz = 0; - if (clBinary()->elfIn()->getSection(amd::OclElf::TEXT, §, &sz) && sect && sz > 0) { - setType(TYPE_EXECUTABLE); - } - - sect = NULL; - sz = 0; - if (type != ET_DYN && // binary is not a library - (clBinary()->elfIn()->getSection(amd::OclElf::LLVMIR, §, &sz) && sect && sz > 0)) { - setType(TYPE_COMPILED); - } - -#endif clBinary()->resetElfIn(); return true; } bool Program::createBIFBinary(aclBinary* bin) { -#if defined(WITH_LIGHTNING_COMPILER) - assert(!"createBIFBinary() should not be called when using LC"); - return false; -#else // defined(WITH_LIGHTNING_COMPILER) acl_error err; char* binaryIn = NULL; size_t size; @@ -1263,7 +1243,6 @@ bool Program::createBIFBinary(aclBinary* bin) { clBinary()->saveBIFBinary(binaryIn, size); aclFreeMem(bin, binaryIn); return true; -#endif // defined(WITH_LIGHTNING_COMPILER) } ClBinary::ClBinary(const amd::Device& dev, BinaryImageFormat bifVer) @@ -1399,7 +1378,7 @@ void ClBinary::release() { } } -void ClBinary::saveBIFBinary(char* binaryIn, size_t size) { +void ClBinary::saveBIFBinary(const char* binaryIn, size_t size) { char* image = new char[size]; memcpy(image, binaryIn, size); @@ -1492,7 +1471,7 @@ bool ClBinary::createElfBinary(bool doencrypt, Program::type_t type) { Program::binary_t ClBinary::data() const { return std::make_pair(binary_, size_); } -bool ClBinary::setBinary(char* theBinary, size_t theBinarySize, bool allocated) { +bool ClBinary::setBinary(const char* theBinary, size_t theBinarySize, bool allocated) { release(); size_ = theBinarySize; @@ -1514,7 +1493,7 @@ void ClBinary::setFlags(int encryptCode) { } } -bool ClBinary::decryptElf(char* binaryIn, size_t size, char** decryptBin, size_t* decryptSize, +bool ClBinary::decryptElf(const char* binaryIn, size_t size, char** decryptBin, size_t* decryptSize, int* encryptCode) { *decryptBin = NULL; #if defined(HAVE_BLOWFISH_H) @@ -1540,13 +1519,13 @@ bool ClBinary::decryptElf(char* binaryIn, size_t size, char** decryptBin, size_t return true; } -bool ClBinary::setElfIn(unsigned char eclass) { +bool ClBinary::setElfIn() { if (elfIn_) return true; if (binary_ == NULL) { return false; } - elfIn_ = new amd::OclElf(eclass, binary_, size_, NULL, ELF_C_READ); + elfIn_ = new amd::OclElf(ELFCLASSNONE, binary_, size_, NULL, ELF_C_READ); if ((elfIn_ == NULL) || elfIn_->hasError()) { if (elfIn_) { delete elfIn_; diff --git a/rocclr/runtime/device/device.hpp b/rocclr/runtime/device/device.hpp index 1916ef12e5..7451547bdc 100644 --- a/rocclr/runtime/device/device.hpp +++ b/rocclr/runtime/device/device.hpp @@ -19,7 +19,7 @@ #if defined(WITH_LIGHTNING_COMPILER) #include "caching/cache.hpp" #include "driver/AmdCompiler.h" -#endif // defined(WITH_LIGHTNING_COMPILER) +#endif // defined(WITH_LIGHTNING_COMPILER) #include "acl.h" #include "hwdebug.hpp" @@ -1084,7 +1084,7 @@ class Program : public amd::HeapObject { ClBinary* clBinary() { return clBinary_; } const ClBinary* clBinary() const { return clBinary_; } - bool setBinary(char* binaryIn, size_t size); + bool setBinary(const char* binaryIn, size_t size); type_t type() const { return type_; } @@ -1116,7 +1116,7 @@ class Program : public amd::HeapObject { virtual bool createBIFBinary(aclBinary* bin); //! Initialize Binary (used only for clCreateProgramWithBinary()). - bool initClBinary(char* binaryIn, size_t size); + bool initClBinary(const char* binaryIn, size_t size); //! Initialize Binary virtual bool initClBinary() = 0; @@ -1165,10 +1165,10 @@ class ClBinary : public amd::HeapObject { /** called only in loading image routines, never called in storing routines */ - bool setBinary(char* theBinary, size_t theBinarySize, bool allocated = false); + bool setBinary(const char* theBinary, size_t theBinarySize, bool allocated = false); //! setin elfIn_ - bool setElfIn(unsigned char eclass); + bool setElfIn(); void resetElfIn(); //! set out elf @@ -1189,9 +1189,9 @@ class ClBinary : public amd::HeapObject { bool createElfBinary(bool doencrypt, Program::type_t type); // save BIF binary image - void saveBIFBinary(char* binaryIn, size_t size); + void saveBIFBinary(const char* binaryIn, size_t size); - bool decryptElf(char* binaryIn, size_t size, char** decryptBin, size_t* decryptSize, + bool decryptElf(const char* binaryIn, size_t size, char** decryptBin, size_t* decryptSize, int* encryptCode); //! Returns the binary pair for the abstraction layer @@ -1222,7 +1222,7 @@ class ClBinary : public amd::HeapObject { //! Check if the binary is recompilable bool isRecompilable(std::string& llvmBinary, amd::OclElf::oclElfPlatform thePlatform); - void saveOrigBinary(char* origBinary, size_t origSize) { + void saveOrigBinary(const char* origBinary, size_t origSize) { origBinary_ = origBinary; origSize_ = origSize; } @@ -1306,11 +1306,11 @@ class ClBinary : public amd::HeapObject { //! Releases the binary data store void release(); - char* binary_; //!< binary data + const char* binary_; //!< binary data size_t size_; //!< binary size uint flags_; //!< CL binary object flags - char* origBinary_; //!< original binary data + const char* origBinary_; //!< original binary data size_t origSize_; //!< original binary size int encryptCode_; //!< Encryption Code for input binary (0 for not encrypted) @@ -1468,11 +1468,7 @@ class SvmManager : public AllStatic { */ class Device : public RuntimeObject { protected: -#if defined(WITH_LIGHTNING_COMPILER) - typedef amd::opencl_driver::Compiler Compiler; -#else // !defined(WITH_LIGHTNING_COMPILER) typedef aclCompiler Compiler; -#endif // !defined(WITH_LIGHTNING_COMPILER) public: typedef std::list CommandQueues; @@ -1753,7 +1749,6 @@ struct KernelParameterDescriptor { }; #if defined(WITH_LIGHTNING_COMPILER) - //! Compilation process with cache support. class CacheCompilation : public amd::HeapObject { public: @@ -1790,8 +1785,7 @@ class CacheCompilation : public amd::HeapObject { StringCache codeCache_; //! Cached codes const bool isCodeCacheEnabled_; //! Code cache enable }; - -#endif +#endif // defined(WITH_LIGHTNING_COMPILER) /*! @} * @} diff --git a/rocclr/runtime/device/gpu/gpuprogram.cpp b/rocclr/runtime/device/gpu/gpuprogram.cpp index f29ab699ae..354cd1d9af 100644 --- a/rocclr/runtime/device/gpu/gpuprogram.cpp +++ b/rocclr/runtime/device/gpu/gpuprogram.cpp @@ -176,7 +176,7 @@ bool NullProgram::linkImpl(amd::option::Options* options) { if (ilProgram_.empty()) { // Setup elfIn() and try to load ISA from binary // This elfIn() will be released at the end of build by finiBuild(). - if (!clBinary()->setElfIn(ELFCLASS32)) { + if (!clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting input OCL binary failed!\n"; LogError("Setting input OCL binary failed"); return false; @@ -479,7 +479,7 @@ bool NullProgram::linkImpl(const std::vector& inputPrograms, // We are using CL binary directly. // Setup elfIn() and try to load llvmIR from binary // This elfIn() will be released at the end of build by finiBuild(). - if (!program->clBinary()->setElfIn(ELFCLASS32)) { + if (!program->clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting input OCL binary failed!\n"; LogError("Setting input OCL binary failed"); return false; diff --git a/rocclr/runtime/device/pal/palprogram.cpp b/rocclr/runtime/device/pal/palprogram.cpp index 695fa871cd..aa196c61df 100644 --- a/rocclr/runtime/device/pal/palprogram.cpp +++ b/rocclr/runtime/device/pal/palprogram.cpp @@ -1280,7 +1280,7 @@ bool LightningProgram::linkImpl(const std::vector& inputPrograms, // We are using CL binary directly. // Setup elfIn() and try to load llvmIR from binary // This elfIn() will be released at the end of build by finiBuild(). - if (!program->clBinary()->setElfIn(ELFCLASS64)) { + if (!program->clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting input OCL binary failed!\n"; return false; } diff --git a/rocclr/runtime/device/rocm/roccompiler.cpp b/rocclr/runtime/device/rocm/roccompiler.cpp index 1c167d3051..d66213945d 100644 --- a/rocclr/runtime/device/rocm/roccompiler.cpp +++ b/rocclr/runtime/device/rocm/roccompiler.cpp @@ -15,9 +15,7 @@ #if defined(WITH_LIGHTNING_COMPILER) #include "opencl1.2-c.amdgcn.inc" #include "opencl2.0-c.amdgcn.inc" -#else // !defined(WITH_LIGHTNING_COMPILER) -#include "roccompilerlib.hpp" -#endif // !defined(WITH_LIGHTNING_COMPILER) +#endif // defined(WITH_LIGHTNING_COMPILER) #include "utils/options.hpp" #include @@ -48,10 +46,125 @@ static void logFunction(const char* msg, size_t size) { static int programsCount = 0; +bool HSAILProgram::compileImpl(const std::string& sourceCode, + const std::vector& headers, + const char** headerIncludeNames, amd::option::Options* options) { + acl_error errorCode; + aclTargetInfo target; + + target = aclGetTargetInfo(LP64_SWITCH("hsail", "hsail64"), + dev().deviceInfo().complibTarget_, &errorCode); + + // end if asic info is ready + // We dump the source code for each program (param: headers) + // into their filenames (headerIncludeNames) into the TEMP + // folder specific to the OS and add the include path while + // compiling + + // Find the temp folder for the OS + std::string tempFolder = amd::Os::getEnvironment("TEMP"); + if (tempFolder.empty()) { + tempFolder = amd::Os::getEnvironment("TMP"); + if (tempFolder.empty()) { + tempFolder = WINDOWS_SWITCH(".", "/tmp"); + ; + } + } + // Iterate through each source code and dump it into tmp + std::fstream f; + std::vector headerFileNames(headers.size()); + std::vector newDirs; + for (size_t i = 0; i < headers.size(); ++i) { + std::string headerPath = tempFolder; + std::string headerIncludeName(headerIncludeNames[i]); + // replace / in path with current os's file separator + if (amd::Os::fileSeparator() != '/') { + for (std::string::iterator it = headerIncludeName.begin(), end = headerIncludeName.end(); + it != end; ++it) { + if (*it == '/') *it = amd::Os::fileSeparator(); + } + } + size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator()); + if (pos != std::string::npos) { + headerPath += amd::Os::fileSeparator(); + headerPath += headerIncludeName.substr(0, pos); + headerIncludeName = headerIncludeName.substr(pos + 1); + } + if (!amd::Os::pathExists(headerPath)) { + bool ret = amd::Os::createPath(headerPath); + assert(ret && "failed creating path!"); + newDirs.push_back(headerPath); + } + std::string headerFullName = headerPath + amd::Os::fileSeparator() + headerIncludeName; + headerFileNames[i] = headerFullName; + f.open(headerFullName.c_str(), std::fstream::out); + // Should we allow asserts + assert(!f.fail() && "failed creating header file!"); + f.write(headers[i]->c_str(), headers[i]->length()); + f.close(); + } + + // Create Binary + binaryElf_ = aclBinaryInit(sizeof(aclBinary), &target, &binOpts_, &errorCode); + + if (errorCode != ACL_SUCCESS) { + buildLog_ += + "Error while compiling opencl source:\ + aclBinary init failure \n"; + LogWarning("aclBinaryInit failed"); + return false; + } + + // Insert opencl into binary + errorCode = aclInsertSection(device().compiler(), binaryElf_, sourceCode.c_str(), + strlen(sourceCode.c_str()), aclSOURCE); + + if (errorCode != ACL_SUCCESS) { + buildLog_ += + "Error while converting to BRIG: \ + Inserting openCl Source \n"; + } + + // Set the options for the compiler + // Set the include path for the temp folder that contains the includes + if (!headers.empty()) { + this->compileOptions_.append(" -I"); + this->compileOptions_.append(tempFolder); + } + + // Add only for CL2.0 and later + if (options->oVariables->CLStd[2] >= '2') { + std::stringstream opts; + opts << " -D" + << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE=" << device().info().maxGlobalVariableSize_; + compileOptions_.append(opts.str()); + } + + // Compile source to IR + this->compileOptions_.append(preprocessorOptions(options)); + this->compileOptions_.append(codegenOptions(options)); + + errorCode = aclCompile(device().compiler(), binaryElf_, + //"-Wf,--support_all_extensions", + this->compileOptions_.c_str(), ACL_TYPE_OPENCL, + ACL_TYPE_LLVMIR_BINARY, logFunction); + buildLog_ += aclGetCompilerLog(device().compiler()); + if (errorCode != ACL_SUCCESS) { + LogWarning("aclCompile failed"); + buildLog_ += + "Error while compiling \ + opencl source: Compiling CL to IR"; + return false; + } + // Save the binary in the interface class + saveBinaryAndSetType(TYPE_COMPILED); + return true; +} + #if defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::compileImpl_LC(const std::string& sourceCode, - const std::vector& headers, - const char** headerIncludeNames, amd::option::Options* options) { +bool LightningProgram::compileImpl(const std::string& sourceCode, + const std::vector& headers, + const char** headerIncludeNames, amd::option::Options* options) { using namespace amd::opencl_driver; std::unique_ptr C(newCompilerInstance()); std::vector inputs; @@ -238,128 +351,7 @@ bool HSAILProgram::compileImpl_LC(const std::string& sourceCode, } return true; } -#endif // defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::compileImpl(const std::string& sourceCode, - const std::vector& headers, - const char** headerIncludeNames, amd::option::Options* options) { -#if defined(WITH_LIGHTNING_COMPILER) - return compileImpl_LC(sourceCode, headers, headerIncludeNames, options); -#else // !defined(WITH_LIGHTNING_COMPILER) - acl_error errorCode; - aclTargetInfo target; - - target = g_complibApi._aclGetTargetInfo(LP64_SWITCH("hsail", "hsail64"), - dev().deviceInfo().complibTarget_, &errorCode); - - // end if asic info is ready - // We dump the source code for each program (param: headers) - // into their filenames (headerIncludeNames) into the TEMP - // folder specific to the OS and add the include path while - // compiling - - // Find the temp folder for the OS - std::string tempFolder = amd::Os::getEnvironment("TEMP"); - if (tempFolder.empty()) { - tempFolder = amd::Os::getEnvironment("TMP"); - if (tempFolder.empty()) { - tempFolder = WINDOWS_SWITCH(".", "/tmp"); - ; - } - } - // Iterate through each source code and dump it into tmp - std::fstream f; - std::vector headerFileNames(headers.size()); - std::vector newDirs; - for (size_t i = 0; i < headers.size(); ++i) { - std::string headerPath = tempFolder; - std::string headerIncludeName(headerIncludeNames[i]); - // replace / in path with current os's file separator - if (amd::Os::fileSeparator() != '/') { - for (std::string::iterator it = headerIncludeName.begin(), end = headerIncludeName.end(); - it != end; ++it) { - if (*it == '/') *it = amd::Os::fileSeparator(); - } - } - size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator()); - if (pos != std::string::npos) { - headerPath += amd::Os::fileSeparator(); - headerPath += headerIncludeName.substr(0, pos); - headerIncludeName = headerIncludeName.substr(pos + 1); - } - if (!amd::Os::pathExists(headerPath)) { - bool ret = amd::Os::createPath(headerPath); - assert(ret && "failed creating path!"); - newDirs.push_back(headerPath); - } - std::string headerFullName = headerPath + amd::Os::fileSeparator() + headerIncludeName; - headerFileNames[i] = headerFullName; - f.open(headerFullName.c_str(), std::fstream::out); - // Should we allow asserts - assert(!f.fail() && "failed creating header file!"); - f.write(headers[i]->c_str(), headers[i]->length()); - f.close(); - } - - // Create Binary - binaryElf_ = g_complibApi._aclBinaryInit(sizeof(aclBinary), &target, &binOpts_, &errorCode); - - if (errorCode != ACL_SUCCESS) { - buildLog_ += - "Error while compiling opencl source:\ - aclBinary init failure \n"; - LogWarning("aclBinaryInit failed"); - return false; - } - - // Insert opencl into binary - errorCode = g_complibApi._aclInsertSection(device().compiler(), binaryElf_, sourceCode.c_str(), - strlen(sourceCode.c_str()), aclSOURCE); - - if (errorCode != ACL_SUCCESS) { - buildLog_ += - "Error while converting to BRIG: \ - Inserting openCl Source \n"; - } - - // Set the options for the compiler - // Set the include path for the temp folder that contains the includes - if (!headers.empty()) { - this->compileOptions_.append(" -I"); - this->compileOptions_.append(tempFolder); - } - - // Add only for CL2.0 and later - if (options->oVariables->CLStd[2] >= '2') { - std::stringstream opts; - opts << " -D" - << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE=" << device().info().maxGlobalVariableSize_; - compileOptions_.append(opts.str()); - } - - // Compile source to IR - this->compileOptions_.append(preprocessorOptions(options)); - this->compileOptions_.append(codegenOptions(options)); - - errorCode = g_complibApi._aclCompile(device().compiler(), binaryElf_, - //"-Wf,--support_all_extensions", - this->compileOptions_.c_str(), ACL_TYPE_OPENCL, - ACL_TYPE_LLVMIR_BINARY, logFunction); - buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler()); - if (errorCode != ACL_SUCCESS) { - LogWarning("aclCompile failed"); - buildLog_ += - "Error while compiling \ - opencl source: Compiling CL to IR"; - return false; - } - // Save the binary in the interface class - saveBinaryAndSetType(TYPE_COMPILED); - return true; -#endif // !defined(WITH_LIGHTNING_COMPILER) -} - -#if defined(WITH_LIGHTNING_COMPILER) #if defined(ATI_OS_LINUX) static pthread_once_t once = PTHREAD_ONCE_INIT; @@ -396,7 +388,7 @@ static void checkLLVM_BIN() { } #endif // defined(ATI_OS_LINUX) -amd::opencl_driver::Compiler* HSAILProgram::newCompilerInstance() { +amd::opencl_driver::Compiler* LightningProgram::newCompilerInstance() { #if defined(ATI_OS_LINUX) pthread_once(&once, checkLLVM_BIN); #endif // defined(ATI_OS_LINUX) diff --git a/rocclr/runtime/device/rocm/roccompilerlib.cpp b/rocclr/runtime/device/rocm/roccompilerlib.cpp deleted file mode 100644 index 6afc916f66..0000000000 --- a/rocclr/runtime/device/rocm/roccompilerlib.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "roccompilerlib.hpp" -#include "utils/flags.hpp" - -#include "acl.h" - -namespace roc { - -void* g_complibModule = nullptr; -struct CompLibApi g_complibApi; - -// -// g_complibModule is defined in LoadCompLib(). This macro must be used only in LoadCompLib() -// function. -// -#if defined(BUILD_HSA_TARGET) -#define LOADSYMBOL(api) \ - g_complibApi._##api = (pfn_##api)amd::Os::getSymbol(g_complibModule, #api); \ - if (g_complibApi._##api == nullptr) { \ - LogError("amd::Os::getSymbol() for exported func " #api " failed."); \ - amd::Os::unloadLibrary(g_complibModule); \ - return false; \ - } -#else // !defined(BUILD_HSA_TARGET) -#define LOADSYMBOL(api) g_complibApi._##api = (pfn_##api)&(api); -#endif // !defined(BUILD_HSA_TARGET) - -bool LoadCompLib(bool offline) { -#if defined(BUILD_HSA_TARGET) - g_complibModule = amd::Os::loadLibrary("amdhsacl" LP64_SWITCH(LINUX_SWITCH("32", ""), "64")); - if (g_complibModule == nullptr) { - if (!offline) { - LogError("amd::Os::loadLibrary() for loading of amdhsacl.dll failed."); - } - return false; - } -#endif // defined(BUILD_HSA_TARGET) - - LOADSYMBOL(aclCompilerInit) - LOADSYMBOL(aclGetTargetInfo) - LOADSYMBOL(aclBinaryInit) - LOADSYMBOL(aclInsertSection) - LOADSYMBOL(aclCompile) - LOADSYMBOL(aclCompilerFini) - LOADSYMBOL(aclBinaryFini) - LOADSYMBOL(aclWriteToMem) - LOADSYMBOL(aclQueryInfo) - LOADSYMBOL(aclExtractSymbol) - LOADSYMBOL(aclGetCompilerLog) - LOADSYMBOL(aclCreateFromBinary) - LOADSYMBOL(aclReadFromMem) - LOADSYMBOL(aclBinaryVersion) - LOADSYMBOL(aclLink) - - return true; -} - -void UnloadCompLib() { - if (g_complibModule) { - amd::Os::unloadLibrary(g_complibModule); - } -} - -} // namespace roc diff --git a/rocclr/runtime/device/rocm/roccompilerlib.hpp b/rocclr/runtime/device/rocm/roccompilerlib.hpp deleted file mode 100644 index 422713002c..0000000000 --- a/rocclr/runtime/device/rocm/roccompilerlib.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -// -// This file hsa the code for explicity loading amdoclcl.dll. -// Exported functions from amdoclcl.dll can be added for usage as need-basis. -// With explicit/dynamic loading roc will not have any linkage to amdoclcl.lib. -// - -#include "thread/thread.hpp" -#include "acl.h" -#include "utils/debug.hpp" - -#if defined(WITH_LIGHTNING_COMPILER) -#error Should not include this file -#endif // defined(WITH_LIGHTNING_COMPILER) - -using namespace amd; - -namespace roc { - -// -// To use any new exported function from amdhsacl.dll please add/make that function specific changes -// in typedef below, struct CompLibApi and in hsacompilerLib.cpp::LoadCompLib() function. -// - -// -// Convention: The typedefed function name must be prefixed with pfn_ -// -typedef aclCompiler*(ACL_API_ENTRY* pfn_aclCompilerInit)(aclCompilerOptions* opts, - acl_error* error_code); -typedef aclTargetInfo(ACL_API_ENTRY* pfn_aclGetTargetInfo)(const char*, const char*, acl_error*); -typedef aclBinary*(ACL_API_ENTRY* pfn_aclBinaryInit)(size_t, const aclTargetInfo*, - const aclBinaryOptions*, acl_error*); -typedef acl_error(ACL_API_ENTRY* pfn_aclInsertSection)(aclCompiler* cl, aclBinary* binary, - const void* data, size_t data_size, - aclSections id); -typedef acl_error(ACL_API_ENTRY* pfn_aclCompile)(aclCompiler* cl, aclBinary* bin, - const char* options, aclType from, aclType to, - aclLogFunction compile_callback); -typedef acl_error(ACL_API_ENTRY* pfn_aclCompilerFini)(aclCompiler* cl); -typedef acl_error(ACL_API_ENTRY* pfn_aclBinaryFini)(aclBinary* bin); -typedef acl_error(ACL_API_ENTRY* pfn_aclWriteToMem)(aclBinary* bin, void** mem, size_t* size); -typedef acl_error(ACL_API_ENTRY* pfn_aclQueryInfo)(aclCompiler* cl, const aclBinary* binary, - aclQueryType query, const char* kernel, - void* data_ptr, size_t* ptr_size); -typedef const void*(ACL_API_ENTRY* pfn_aclExtractSymbol)(aclCompiler* cl, const aclBinary* binary, - size_t* size, aclSections id, - const char* symbol, acl_error* error_code); -typedef aclBinary*(ACL_API_ENTRY* pfn_aclReadFromMem)(void* mem, size_t size, - acl_error* error_code); -typedef char*(ACL_API_ENTRY* pfn_aclGetCompilerLog)(aclCompiler* cl); -typedef aclBinary*(ACL_API_ENTRY* pfn_aclCreateFromBinary)(const aclBinary* binary, - aclBIFVersion version); -typedef aclBIFVersion(ACL_API_ENTRY* pfn_aclBinaryVersion)(const aclBinary* binary); -typedef acl_error(ACL_API_ENTRY* pfn_aclLink)(aclCompiler* cl, aclBinary* src_bin, - unsigned int num_libs, aclBinary** libs, - aclType link_mode, const char* options, - aclLogFunction link_callback); -// -// Convention: prefix struct member variable with with underscore '_' -// would be nice if there was no underscore prfix, but on Linux the token -// pasting in the macro is srtict and his is the workaround. -// -struct CompLibApi { - pfn_aclCompilerInit _aclCompilerInit; - pfn_aclGetTargetInfo _aclGetTargetInfo; - pfn_aclBinaryInit _aclBinaryInit; - pfn_aclInsertSection _aclInsertSection; - pfn_aclCompile _aclCompile; - pfn_aclCompilerFini _aclCompilerFini; - pfn_aclBinaryFini _aclBinaryFini; - pfn_aclWriteToMem _aclWriteToMem; - pfn_aclQueryInfo _aclQueryInfo; - pfn_aclExtractSymbol _aclExtractSymbol; - pfn_aclReadFromMem _aclReadFromMem; - pfn_aclGetCompilerLog _aclGetCompilerLog; - pfn_aclCreateFromBinary _aclCreateFromBinary; - pfn_aclBinaryVersion _aclBinaryVersion; - pfn_aclLink _aclLink; -}; - - -// -// Use g_ prefix for all global variables. -// -extern void* g_complibModule; -extern CompLibApi g_complibApi; - -// Note: initializes global variable g_complibApi. -// Not sure what error values we have, for now returning false on failure. -bool LoadCompLib(bool isOfflineDevice = false); -void UnloadCompLib(); - -} // namespace roc diff --git a/rocclr/runtime/device/rocm/rocdevice.cpp b/rocclr/runtime/device/rocm/rocdevice.cpp index a2c805e375..04a011d275 100644 --- a/rocclr/runtime/device/rocm/rocdevice.cpp +++ b/rocclr/runtime/device/rocm/rocdevice.cpp @@ -9,6 +9,7 @@ #include "os/os.hpp" #include "utils/debug.hpp" #include "utils/flags.hpp" +#include "utils/options.hpp" #include "utils/versions.hpp" #include "thread/monitor.hpp" #include "CL/cl_ext.h" @@ -20,9 +21,7 @@ #include "device/rocm/rocprogram.hpp" #if defined(WITH_LIGHTNING_COMPILER) #include "driver/AmdCompiler.h" -#else // !defined(WITH_LIGHTNING_COMPILER) -#include "device/rocm/roccompilerlib.hpp" -#endif // !defined(WITH_LIGHTNING_COMPILER) +#endif // defined(WITH_LIGHTNING_COMPILER) #include "device/rocm/rocmemory.hpp" #include "device/rocm/rocglinterop.hpp" #ifdef WITH_AMDGPU_PRO @@ -191,46 +190,34 @@ Device::~Device() { } } bool NullDevice::initCompiler(bool isOffline) { -#if !defined(WITH_LIGHTNING_COMPILER) - // Initializes g_complibModule and g_complibApi if they were not initialized - if (g_complibModule == nullptr) { - if (!LoadCompLib(isOffline)) { - if (!isOffline) { - LogError("Error - could not find the compiler library"); - } - return false; - } - } // Initialize the compiler handle if has already not been initialized // This is destroyed in Device::teardown acl_error error; if (!compilerHandle_) { - compilerHandle_ = g_complibApi._aclCompilerInit(nullptr, &error); + aclCompilerOptions opts = { + sizeof(aclCompilerOptions_0_8), + IF(IS_LIGHTNING, "libamdoclcl64.so", NULL), + NULL, NULL, NULL, NULL, NULL, NULL + }; + compilerHandle_ = aclCompilerInit(&opts, &error); if (error != ACL_SUCCESS) { +#if !defined(WITH_LIGHTNING_COMPILER) LogError("Error initializing the compiler handle"); return false; +#endif // !defined(WITH_LIGHTNING_COMPILER) } } -#endif // !defined(WITH_LIGHTNING_COMPILER) return true; } bool NullDevice::destroyCompiler() { -#if defined(WITH_LIGHTNING_COMPILER) - delete compilerHandle_; - compilerHandle_ = nullptr; -#else // !defined(WITH_LIGHTNING_COMPILER) if (compilerHandle_ != nullptr) { - acl_error error = g_complibApi._aclCompilerFini(compilerHandle_); + acl_error error = aclCompilerFini(compilerHandle_); if (error != ACL_SUCCESS) { LogError("Error closing the compiler"); return false; } } - if (g_complibModule != nullptr) { - UnloadCompLib(); - } -#endif // !defined(WITH_LIGHTNING_COMPILER) return true; } @@ -682,6 +669,11 @@ device::Program* NullDevice::createProgram(amd::option::Options* options) { } device::Program* Device::createProgram(amd::option::Options* options) { +#if defined(WITH_LIGHTNING_COMPILER) + if (!compilerHandle_ || !options->oVariables->Legacy) { + return new roc::LightningProgram(*this); + } +#endif // defined(WITH_LIGHTNING_COMPILER) return new roc::HSAILProgram(*this); } @@ -965,7 +957,9 @@ bool Device::populateOCLDeviceConstants() { return false; } std::stringstream ss; - ss << AMD_BUILD_STRING " (HSA" << major << "." << minor << "," IF(IS_LIGHTNING, "LC", "HSAIL") ")"; + ss << AMD_BUILD_STRING " (HSA" << major << "." << minor << "," IF(IS_LIGHTNING, "LC", "HSAIL"); + if (IS_LIGHTNING && compilerHandle_) ss << "*,HSAIL"; + ss << ")"; strcpy(info_.driverVersion_, ss.str().c_str()); info_.version_ = "OpenCL " /*OPENCL_VERSION_STR*/"1.2" " "; diff --git a/rocclr/runtime/device/rocm/rockernel.cpp b/rocclr/runtime/device/rocm/rockernel.cpp index 87702089b9..56fcf2e651 100644 --- a/rocclr/runtime/device/rocm/rockernel.cpp +++ b/rocclr/runtime/device/rocm/rockernel.cpp @@ -498,7 +498,7 @@ static inline cl_kernel_arg_type_qualifier GetOclTypeQual(const aclArgData* argI return rv; } -void Kernel::initArguments(const aclArgData* aclArg) { +void HSAILKernel::initArguments(const aclArgData* aclArg) { device::Kernel::parameters_t params; // Iterate through the arguments and insert into parameterList @@ -562,7 +562,7 @@ void Kernel::initArguments(const aclArgData* aclArg) { } #if defined(WITH_LIGHTNING_COMPILER) -void Kernel::initArguments_LC(const KernelMD& kernelMD) { +void LightningKernel::initArguments(const KernelMD& kernelMD) { device::Kernel::parameters_t params; size_t offset = 0; @@ -632,7 +632,7 @@ void Kernel::initArguments_LC(const KernelMD& kernelMD) { } #endif // defined(WITH_LIGHTNING_COMPILER) -Kernel::Kernel(std::string name, HSAILProgram* prog, const uint64_t& kernelCodeHandle, +Kernel::Kernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle, const uint32_t workgroupGroupSegmentByteSize, const uint32_t workitemPrivateSegmentByteSize, const uint32_t kernargSegmentByteSize, const uint32_t kernargSegmentAlignment) @@ -645,7 +645,6 @@ Kernel::Kernel(std::string name, HSAILProgram* prog, const uint64_t& kernelCodeH kernargSegmentAlignment_(kernargSegmentAlignment) {} #if defined(WITH_LIGHTNING_COMPILER) - static const KernelMD* FindKernelMetadata(const CodeObjectMD* programMD, const std::string& name) { for (const KernelMD& kernelMD : programMD->mKernels) { if (kernelMD.mName == name) { @@ -655,18 +654,18 @@ static const KernelMD* FindKernelMetadata(const CodeObjectMD* programMD, const s return nullptr; } -bool Kernel::init_LC() { +bool LightningKernel::init() { hsa_agent_t hsaDevice = program_->hsaDevice(); // Pull out metadata from the ELF - const CodeObjectMD* programMD = program_->metadata(); + const CodeObjectMD* programMD = static_cast(program_)->metadata(); assert(programMD != nullptr); const KernelMD* kernelMD = FindKernelMetadata(programMD, name()); if (kernelMD == nullptr) { return false; } - initArguments_LC(*kernelMD); + initArguments(*kernelMD); // Set the workgroup information for the kernel workGroupInfo_.availableLDSSize_ = program_->dev().info().localMemSizePerCU_; @@ -721,16 +720,13 @@ bool Kernel::init_LC() { return false; } - initPrintf_LC(programMD->mPrintf); + initPrintf(programMD->mPrintf); return true; } #endif // defined(WITH_LIGHTNING_COMPILER) -bool Kernel::init() { -#if defined(WITH_LIGHTNING_COMPILER) - return init_LC(); -#else // !defined(WITH_LIGHTNING_COMPILER) +bool HSAILKernel::init() { acl_error errorCode; // compile kernel down to ISA hsa_agent_t hsaDevice = program_->hsaDevice(); @@ -738,13 +734,13 @@ bool Kernel::init() { size_t sizeOfArgList; aclCompiler* compileHandle = program_->dev().compiler(); std::string openClKernelName("&__OpenCL_" + name() + "_kernel"); - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), RT_ARGUMENT_ARRAY, + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_ARGUMENT_ARRAY, openClKernelName.c_str(), nullptr, &sizeOfArgList); if (errorCode != ACL_SUCCESS) { return false; } std::unique_ptr argList(new char[sizeOfArgList]); - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), RT_ARGUMENT_ARRAY, + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_ARGUMENT_ARRAY, openClKernelName.c_str(), argList.get(), &sizeOfArgList); if (errorCode != ACL_SUCCESS) { return false; @@ -760,12 +756,12 @@ bool Kernel::init() { workGroupInfo_.availableSGPRs_ = 104; workGroupInfo_.availableVGPRs_ = 256; size_t sizeOfWorkGroupSize; - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), RT_WORK_GROUP_SIZE, + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_WORK_GROUP_SIZE, openClKernelName.c_str(), nullptr, &sizeOfWorkGroupSize); if (errorCode != ACL_SUCCESS) { return false; } - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), RT_WORK_GROUP_SIZE, + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_WORK_GROUP_SIZE, openClKernelName.c_str(), workGroupInfo_.compileSize_, &sizeOfWorkGroupSize); if (errorCode != ACL_SUCCESS) { @@ -810,7 +806,7 @@ bool Kernel::init() { // Pull out printf metadata from the ELF size_t sizeOfPrintfList; - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), RT_GPU_PRINTF_ARRAY, + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_GPU_PRINTF_ARRAY, openClKernelName.c_str(), nullptr, &sizeOfPrintfList); if (errorCode != ACL_SUCCESS) { return false; @@ -822,7 +818,7 @@ bool Kernel::init() { if (!aclPrintfList) { return false; } - errorCode = g_complibApi._aclQueryInfo(compileHandle, program_->binaryElf(), + errorCode = aclQueryInfo(compileHandle, program_->binaryElf(), RT_GPU_PRINTF_ARRAY, openClKernelName.c_str(), aclPrintfList.get(), &sizeOfPrintfList); if (errorCode != ACL_SUCCESS) { @@ -833,11 +829,10 @@ bool Kernel::init() { initPrintf(reinterpret_cast(aclPrintfList.get())); } return true; -#endif // !defined(WITH_LIGHTNING_COMPILER) } #if defined(WITH_LIGHTNING_COMPILER) -void Kernel::initPrintf_LC(const std::vector& printfInfoStrings) { +void LightningKernel::initPrintf(const std::vector& printfInfoStrings) { for (auto str : printfInfoStrings) { std::vector tokens; @@ -928,7 +923,7 @@ void Kernel::initPrintf_LC(const std::vector& printfInfoStrings) { } #endif // defined(WITH_LIGHTNING_COMPILER) -void Kernel::initPrintf(const aclPrintfFmt* aclPrintf) { +void HSAILKernel::initPrintf(const aclPrintfFmt* aclPrintf) { PrintfInfo info; uint index = 0; for (; aclPrintf->struct_size != 0; aclPrintf++) { diff --git a/rocclr/runtime/device/rocm/rockernel.hpp b/rocclr/runtime/device/rocm/rockernel.hpp index 954324a6d8..39f4be559b 100644 --- a/rocclr/runtime/device/rocm/rockernel.hpp +++ b/rocclr/runtime/device/rocm/rockernel.hpp @@ -85,7 +85,7 @@ class Kernel : public device::Kernel { ROC_ACCESS_TYPE access_; //!< Access type for the argument }; - Kernel(std::string name, HSAILProgram* prog, const uint64_t& kernelCodeHandle, + Kernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle, const uint32_t workgroupGroupSegmentByteSize, const uint32_t workitemPrivateSegmentByteSize, const uint32_t kernargSegmentByteSize, const uint32_t kernargSegmentAlignment); @@ -103,13 +103,9 @@ class Kernel : public device::Kernel { ~Kernel(); //! Initializes the metadata required for this kernel - bool init(); -#if defined(WITH_LIGHTNING_COMPILER) - //! Initializes the metadata required for this kernel - bool init_LC(); -#endif // defined(WITH_LIGHTNING_COMPILER) + virtual bool init() = 0; - const HSAILProgram* program() const { return static_cast(program_); } + const Program* program() const { return static_cast(program_); } //! Returns the kernel argument list const std::vector& hsailArgs() const { return hsailArgList_; } @@ -131,7 +127,7 @@ class Kernel : public device::Kernel { //! set internal kernel flag void setInternalKernelFlag(bool flag) { flags_.internalKernel_ = flag; } - private: + protected: union Flags { struct { uint internalKernel_ : 1; //!< Is a blit kernel? @@ -140,21 +136,8 @@ class Kernel : public device::Kernel { Flags() : value_(0) {} } flags_; - //! Populates hsailArgList_ - void initArguments(const aclArgData* aclArg); -#if defined(WITH_LIGHTNING_COMPILER) - //! Initializes Hsail Argument metadata and info for LC - void initArguments_LC(const KernelMD& kernelMD); -#endif // defined(WITH_LIGHTNING_COMPILER) - //! Initializes HSAIL Printf metadata and info - void initPrintf(const aclPrintfFmt* aclPrintf); -#if defined(WITH_LIGHTNING_COMPILER) - //! Initializes HSAIL Printf metadata and info for LC - void initPrintf_LC(const std::vector& printfInfoStrings); -#endif // defined(WITH_LIGHTNING_COMPILER) - - HSAILProgram* program_; //!< The roc::HSAILProgram context + Program* program_; //!< The roc::Program context std::vector hsailArgList_; //!< Vector list of HSAIL Arguments uint64_t kernelCodeHandle_; //!< Kernel code handle (aka amd_kernel_code_t) const uint32_t workgroupGroupSegmentByteSize_; @@ -165,6 +148,51 @@ class Kernel : public device::Kernel { std::vector printf_; }; +class HSAILKernel : public roc::Kernel { + public: + HSAILKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle, + const uint32_t workgroupGroupSegmentByteSize, + const uint32_t workitemPrivateSegmentByteSize, + const uint32_t kernargSegmentByteSize, + const uint32_t kernargSegmentAlignment) + : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize, + workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) { + } + + //! Initializes the metadata required for this kernel + virtual bool init() final; + + private: + //! Populates hsailArgList_ + void initArguments(const aclArgData* aclArg); + + //! Initializes HSAIL Printf metadata and info + void initPrintf(const aclPrintfFmt* aclPrintf); +}; + +#if defined(WITH_LIGHTNING_COMPILER) +class LightningKernel : public roc::Kernel { + public: + LightningKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle, + const uint32_t workgroupGroupSegmentByteSize, + const uint32_t workitemPrivateSegmentByteSize, + const uint32_t kernargSegmentByteSize, + const uint32_t kernargSegmentAlignment) + : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize, + workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) { + } + //! Initializes the metadata required for this kernel + virtual bool init() final; + +private: + //! Initializes Hsail Argument metadata and info for LC + void initArguments(const KernelMD& kernelMD); + + //! Initializes HSAIL Printf metadata and info for LC + void initPrintf(const std::vector& printfInfoStrings); +}; +#endif // defined(WITH_LIGHTNING_COMPILER) + } // namespace roc #endif // WITHOUT_HSA_BACKEND diff --git a/rocclr/runtime/device/rocm/rocprogram.cpp b/rocclr/runtime/device/rocm/rocprogram.cpp index a0d60b24e1..2218e3ae8c 100644 --- a/rocclr/runtime/device/rocm/rocprogram.cpp +++ b/rocclr/runtime/device/rocm/rocprogram.cpp @@ -13,9 +13,7 @@ #include #include "driver/AmdCompiler.h" #include "libraries.amdgcn.inc" -#else // !defined(WITH_LIGHTNING_COMPILER) -#include "roccompilerlib.hpp" -#endif // !defined(WITH_LIGHTNING_COMPILER) +#endif // defined(WITH_LIGHTNING_COMPILER) #include "utils/bif_section_labels.hpp" #include "amd_hsa_kernel_code.h" @@ -26,7 +24,6 @@ #include #include #include -#include #include namespace roc { @@ -58,17 +55,15 @@ static void logFunction(const char* msg, size_t size) { std::cout << "Compiler Library log :" << msg << std::endl; } -HSAILProgram::~HSAILProgram() { -#if !defined(WITH_LIGHTNING_COMPILER) - acl_error error; - // Free the elf binary - if (binaryElf_ != nullptr) { - error = g_complibApi._aclBinaryFini(binaryElf_); - if (error != ACL_SUCCESS) { - LogWarning("Error while destroying the acl binary \n"); - } +static inline const char* hsa_strerror(hsa_status_t status) { + const char* str = nullptr; + if (hsa_status_string(status, &str) == HSA_STATUS_SUCCESS) { + return str; } -#endif // !defined(WITH_LIGHTNING_COMPILER) + return "Unknown error"; +} + +Program::~Program() { // Destroy the executable. if (hsaExecutable_.handle != 0) { hsa_executable_destroy(hsaExecutable_); @@ -77,13 +72,9 @@ HSAILProgram::~HSAILProgram() { hsa_code_object_reader_destroy(hsaCodeObjectReader_); } releaseClBinary(); - -#if defined(WITH_LIGHTNING_COMPILER) - delete metadata_; -#endif // defined(WITH_LIGHTNING_COMPILER) } -HSAILProgram::HSAILProgram(roc::NullDevice& device) : Program(device), binaryElf_(nullptr) { +Program::Program(roc::NullDevice& device) : device::Program(device), binaryElf_(nullptr) { memset(&binOpts_, 0, sizeof(binOpts_)); binOpts_.struct_size = sizeof(binOpts_); // binOpts_.elfclass = LP64_SWITCH( ELFCLASS32, ELFCLASS64 ); @@ -98,13 +89,9 @@ HSAILProgram::HSAILProgram(roc::NullDevice& device) : Program(device), binaryElf hsaCodeObjectReader_.handle = 0; hasGlobalStores_ = false; - -#if defined(WITH_LIGHTNING_COMPILER) - metadata_ = nullptr; -#endif // defined(WITH_LIGHTNING_COMPILER) } -bool HSAILProgram::initClBinary(char* binaryIn, size_t size) { +bool Program::initClBinary(char* binaryIn, size_t size) { // Save the original binary that isn't owned by ClBinary clBinary()->saveOrigBinary(binaryIn, size); @@ -139,7 +126,7 @@ bool HSAILProgram::initClBinary(char* binaryIn, size_t size) { } -bool HSAILProgram::initBuild(amd::option::Options* options) { +bool Program::initBuild(amd::option::Options* options) { compileOptions_ = options->origOptionStr; if (!device::Program::initBuild(options)) { @@ -159,11 +146,7 @@ bool HSAILProgram::initBuild(amd::option::Options* options) { outFileName = options->getDumpFileName(".bin"); } -#if defined(WITH_LIGHTNING_COMPILER) - bool useELF64 = true; -#else // !defined(WITH_LIGHTNING_COMPILER) bool useELF64 = getCompilerOptions()->oVariables->EnableGpuElf64; -#endif // !defined(WITH_LIGHTNING_COMPILER) if (!clBinary()->setElfOut(useELF64 ? ELFCLASS64 : ELFCLASS32, (outFileName.size() > 0) ? outFileName.c_str() : nullptr)) { LogError("Setup elf out for gpu failed"); @@ -173,7 +156,7 @@ bool HSAILProgram::initBuild(amd::option::Options* options) { } // ! post-compile setup for GPU -bool HSAILProgram::finiBuild(bool isBuildGood) { +bool Program::finiBuild(bool isBuildGood) { clBinary()->resetElfOut(); clBinary()->resetElfIn(); @@ -185,137 +168,36 @@ bool HSAILProgram::finiBuild(bool isBuildGood) { return device::Program::finiBuild(isBuildGood); } -aclType HSAILProgram::getCompilationStagesFromBinary(std::vector& completeStages, - bool& needOptionsCheck) { - acl_error errorCode; - size_t secSize = 0; - completeStages.clear(); - aclType from = ACL_TYPE_DEFAULT; - needOptionsCheck = true; - size_t boolSize = sizeof(bool); - //! @todo Should we also check for ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT? - // Checking llvmir in .llvmir section - bool containsHsailText = false; - bool containsBrig = false; - bool containsLoaderMap = false; - bool containsLlvmirText = (type() == TYPE_COMPILED); - bool containsShaderIsa = (type() == TYPE_EXECUTABLE); - bool containsOpts = !(compileOptions_.empty() && linkOptions_.empty()); -#if !defined(WITH_LIGHTNING_COMPILER) // !defined(WITH_LIGHTNING_COMPILER) - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LLVMIR, - nullptr, &containsLlvmirText, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsLlvmirText = false; +bool Program::initClBinary() { + if (clBinary_ == nullptr) { + clBinary_ = new ClBinary(static_cast(device())); + if (clBinary_ == nullptr) { + return false; + } } - // Checking compile & link options in .comment section - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_OPTIONS, - nullptr, &containsOpts, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsOpts = false; - } - // Checking HSAIL in .cg section - containsHsailText = true; - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_HSAIL, - nullptr, &containsHsailText, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsHsailText = false; - } - // Checking BRIG sections - containsBrig = true; - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_BRIG, nullptr, - &containsBrig, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsBrig = false; - } - // Checking Loader Map symbol from CG section - containsLoaderMap = true; - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LOADER_MAP, - NULL, &containsLoaderMap, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsLoaderMap = false; - } - if (containsBrig) { - completeStages.push_back(from); - from = ACL_TYPE_HSAIL_BINARY; - } else if (containsHsailText) { - completeStages.push_back(from); - from = ACL_TYPE_HSAIL_TEXT; - } - if (containsLoaderMap) { - completeStages.push_back(from); - from = ACL_TYPE_CG; - } - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_ISA, nullptr, - &containsShaderIsa, &boolSize); - if (errorCode != ACL_SUCCESS) { - containsShaderIsa = false; - } -#endif // !defined(WITH_LIGHTNING_COMPILER) - - if (containsLlvmirText && containsOpts) { - completeStages.push_back(from); - from = ACL_TYPE_LLVMIR_BINARY; - } - if (containsShaderIsa) { - completeStages.push_back(from); - from = ACL_TYPE_ISA; - } - std::string sCurOptions = compileOptions_ + linkOptions_; - amd::option::Options curOptions; - if (!amd::option::parseAllOptions(sCurOptions, curOptions)) { - buildLog_ += curOptions.optionsLog(); - LogError("Parsing compile options failed."); - return ACL_TYPE_DEFAULT; - } - switch (from) { - // compile from HSAIL text, no matter prev. stages and options - case ACL_TYPE_HSAIL_TEXT: - needOptionsCheck = false; - break; - case ACL_TYPE_HSAIL_BINARY: - // do not check options, if LLVMIR is absent or might be absent or options are absent - if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) { - needOptionsCheck = false; - } - break; - case ACL_TYPE_CG: - case ACL_TYPE_ISA: - // do not check options, if LLVMIR is absent or might be absent or options are absent - if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) { - needOptionsCheck = false; - } -#if !defined(WITH_LIGHTNING_COMPILER) - // do not check options, if BRIG is absent or might be absent or LoaderMap is absent - if (!curOptions.oVariables->BinCG || !containsBrig || !containsLoaderMap) { - needOptionsCheck = false; - } -#endif - break; - // recompilation might be needed - case ACL_TYPE_LLVMIR_BINARY: - case ACL_TYPE_DEFAULT: - default: - break; - } - return from; + return true; } -aclType HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* options) { +void Program::releaseClBinary() { + if (clBinary_ != nullptr) { + delete clBinary_; + clBinary_ = nullptr; + } +} + +aclType Program::getNextCompilationStageFromBinary(amd::option::Options* options) { aclType continueCompileFrom = ACL_TYPE_DEFAULT; binary_t binary = this->binary(); // If the binary already exists if ((binary.first != nullptr) && (binary.second > 0)) { -#if defined(WITH_LIGHTNING_COMPILER) - void* mem = (void*)binary.first; -#else // !defined(WITH_LIGHTNING_COMPILER) - void* mem = const_cast(binary.first); - acl_error errorCode; - binaryElf_ = g_complibApi._aclReadFromMem(mem, binary.second, &errorCode); - if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error while BRIG Codegen phase: aclReadFromMem failure \n"; - return continueCompileFrom; + if (aclValidateBinaryImage(binary.first, binary.second, BINARY_TYPE_ELF)) { + acl_error errorCode; + binaryElf_ = aclReadFromMem(binary.first, binary.second, &errorCode); + if (errorCode != ACL_SUCCESS) { + buildLog_ += "Error while BRIG Codegen phase: aclReadFromMem failure \n"; + return continueCompileFrom; + } } -#endif // !defined(WITH_LIGHTNING_COMPILER) // save the current options std::string sCurCompileOptions = compileOptions_; @@ -324,7 +206,7 @@ aclType HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* op // Saving binary in the interface class, // which also load compile & link options from binary - setBinary(static_cast(mem), binary.second); + setBinary(static_cast(binary.first), binary.second); // Calculate the next stage to compile from, based on sections in binaryElf_; // No any validity checks here @@ -344,23 +226,25 @@ aclType HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* op // If compile options are absent in binary, do not compare and recompile if (compileOptions_.empty()) break; -#if defined(WITH_LIGHTNING_COMPILER) - std::string sBinOptions = compileOptions_ + linkOptions_; -#else // !defined(WITH_LIGHTNING_COMPILER) - const oclBIFSymbolStruct* symbol = findBIF30SymStruct(symOpenclCompilerOptions); - assert(symbol && "symbol not found"); - std::string symName = - std::string(symbol->str[bif::PRE]) + std::string(symbol->str[bif::POST]); - size_t symSize = 0; + std::string sBinOptions; + if (binaryElf_ != nullptr) { + const oclBIFSymbolStruct* symbol = findBIF30SymStruct(symOpenclCompilerOptions); + assert(symbol && "symbol not found"); + std::string symName = + std::string(symbol->str[bif::PRE]) + std::string(symbol->str[bif::POST]); + size_t symSize = 0; + acl_error errorCode; - const void* opts = g_complibApi._aclExtractSymbol(device().compiler(), binaryElf_, &symSize, - aclCOMMENT, symName.c_str(), &errorCode); - if (errorCode != ACL_SUCCESS) { - recompile = true; - break; + const void* opts = aclExtractSymbol(device().compiler(), binaryElf_, &symSize, + aclCOMMENT, symName.c_str(), &errorCode); + if (errorCode != ACL_SUCCESS) { + recompile = true; + break; + } + sBinOptions = std::string((char*)opts, symSize); + } else { + sBinOptions = sCurOptions; } - std::string sBinOptions = std::string((char*)opts, symSize); -#endif // !defined(WITH_LIGHTNING_COMPILER) compileOptions_ = sCurCompileOptions; linkOptions_ = sCurLinkOptions; @@ -398,25 +282,564 @@ aclType HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* op return continueCompileFrom; } -static hsa_status_t allocFunc(size_t size, hsa_callback_data_t data, void** address) { - if (!address || 0 == size) { - return HSA_STATUS_ERROR_INVALID_ARGUMENT; +std::string HSAILProgram::codegenOptions(amd::option::Options* options) { + std::string optionsStr; + + if (dev().deviceInfo().gfxipVersion_ < 900 || !dev().settings().singleFpDenorm_) { + optionsStr.append(" -cl-denorms-are-zero"); } - *address = (char*)malloc(size); - if (!*address) { - return HSA_STATUS_ERROR_OUT_OF_RESOURCES; - } + // check if the host is 64 bit or 32 bit + LP64_ONLY(optionsStr.append(" -m64")); - return HSA_STATUS_SUCCESS; + return optionsStr; +} + +std::string Program::preprocessorOptions(amd::option::Options* options) { + std::string optionsStr; + + // Set options for the standard device specific options + + optionsStr.append(" -D__AMD__=1"); + + optionsStr.append(" -D__").append(device().info().name_).append("__=1"); + optionsStr.append(" -D__").append(device().info().name_).append("=1"); + + int major, minor; + ::sscanf(device().info().version_, "OpenCL %d.%d ", &major, &minor); + + std::stringstream ss; + ss << " -D__OPENCL_VERSION__=" << (major * 100 + minor * 10); + optionsStr.append(ss.str()); + + if (device().info().imageSupport_ && options->oVariables->ImageSupport) { + optionsStr.append(" -D__IMAGE_SUPPORT__=1"); + } + + // This is just for legacy compiler code + // All our devices support these options now + if (options->oVariables->FastFMA) { + optionsStr.append(" -DFP_FAST_FMA=1"); + } + if (options->oVariables->FastFMAF) { + optionsStr.append(" -DFP_FAST_FMAF=1"); + } + + uint clcStd = + (options->oVariables->CLStd[2] - '0') * 100 + (options->oVariables->CLStd[4] - '0') * 10; + + if (clcStd >= 200) { + std::stringstream opts; + // Add only for CL2.0 and later + opts << " -D" + << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE=" << device().info().maxGlobalVariableSize_; + optionsStr.append(opts.str()); + } + + // Tokenize the extensions string into a vector of strings + std::istringstream istrstr(device().info().extensions_); + std::istream_iterator sit(istrstr), end; + std::vector extensions(sit, end); + + if (IS_LIGHTNING && !options->oVariables->Legacy) { + // FIXME_lmoriche: opencl-c.h defines 'cl_khr_depth_images', so + // remove it from the command line. Should we fix opencl-c.h? + auto found = std::find(extensions.begin(), extensions.end(), "cl_khr_depth_images"); + if (found != extensions.end()) { + extensions.erase(found); + } + + if (!extensions.empty()) { + std::ostringstream clext; + + clext << " -Xclang -cl-ext=+"; + std::copy(extensions.begin(), extensions.end() - 1, + std::ostream_iterator(clext, ",+")); + clext << extensions.back(); + + optionsStr.append(clext.str()); + } + } else { + for (auto e : extensions) { + optionsStr.append(" -D").append(e).append("=1"); + } + } + + return optionsStr; +} + +HSAILProgram::HSAILProgram(roc::NullDevice& device) : roc::Program(device) { +} + +HSAILProgram::~HSAILProgram() { + acl_error error; + // Free the elf binary + if (binaryElf_ != nullptr) { + error = aclBinaryFini(binaryElf_); + if (error != ACL_SUCCESS) { + LogWarning("Error while destroying the acl binary \n"); + } + } +} + +bool HSAILProgram::createBinary(amd::option::Options* options) { + return false; +} + +bool HSAILProgram::saveBinaryAndSetType(type_t type) { + void* rawBinary; + size_t size; + + // Write binary to memory + if (aclWriteToMem(binaryElf_, &rawBinary, &size) != ACL_SUCCESS) { + buildLog_ += "Failed to write binary to memory \n"; + return false; + } + clBinary()->saveBIFBinary((char*)rawBinary, size); + // Set the type of binary + setType(type); + +// Free memory containing rawBinary + binaryElf_->binOpts.dealloc(rawBinary); + return true; +} + +aclType HSAILProgram::getCompilationStagesFromBinary(std::vector& completeStages, + bool& needOptionsCheck) { + acl_error errorCode; + size_t secSize = 0; + completeStages.clear(); + aclType from = ACL_TYPE_DEFAULT; + needOptionsCheck = true; + size_t boolSize = sizeof(bool); + //! @todo Should we also check for ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT? + // Checking llvmir in .llvmir section + bool containsHsailText = false; + bool containsBrig = false; + bool containsLoaderMap = false; + bool containsLlvmirText = (type() == TYPE_COMPILED); + bool containsShaderIsa = (type() == TYPE_EXECUTABLE); + bool containsOpts = !(compileOptions_.empty() && linkOptions_.empty()); + + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LLVMIR, + nullptr, &containsLlvmirText, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsLlvmirText = false; + } + // Checking compile & link options in .comment section + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_OPTIONS, + nullptr, &containsOpts, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsOpts = false; + } + // Checking HSAIL in .cg section + containsHsailText = true; + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_HSAIL, + nullptr, &containsHsailText, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsHsailText = false; + } + // Checking BRIG sections + containsBrig = true; + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_BRIG, nullptr, + &containsBrig, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsBrig = false; + } + // Checking Loader Map symbol from CG section + containsLoaderMap = true; + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LOADER_MAP, + NULL, &containsLoaderMap, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsLoaderMap = false; + } + if (containsBrig) { + completeStages.push_back(from); + from = ACL_TYPE_HSAIL_BINARY; + } else if (containsHsailText) { + completeStages.push_back(from); + from = ACL_TYPE_HSAIL_TEXT; + } + if (containsLoaderMap) { + completeStages.push_back(from); + from = ACL_TYPE_CG; + } + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_ISA, nullptr, + &containsShaderIsa, &boolSize); + if (errorCode != ACL_SUCCESS) { + containsShaderIsa = false; + } + + if (containsLlvmirText && containsOpts) { + completeStages.push_back(from); + from = ACL_TYPE_LLVMIR_BINARY; + } + if (containsShaderIsa) { + completeStages.push_back(from); + from = ACL_TYPE_ISA; + } + std::string sCurOptions = compileOptions_ + linkOptions_; + amd::option::Options curOptions; + if (!amd::option::parseAllOptions(sCurOptions, curOptions)) { + buildLog_ += curOptions.optionsLog(); + LogError("Parsing compile options failed."); + return ACL_TYPE_DEFAULT; + } + switch (from) { + // compile from HSAIL text, no matter prev. stages and options + case ACL_TYPE_HSAIL_TEXT: + needOptionsCheck = false; + break; + case ACL_TYPE_HSAIL_BINARY: + // do not check options, if LLVMIR is absent or might be absent or options are absent + if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) { + needOptionsCheck = false; + } + break; + case ACL_TYPE_CG: + case ACL_TYPE_ISA: + // do not check options, if LLVMIR is absent or might be absent or options are absent + if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) { + needOptionsCheck = false; + } + // do not check options, if BRIG is absent or might be absent or LoaderMap is absent + if (!curOptions.oVariables->BinCG || !containsBrig || !containsLoaderMap) { + needOptionsCheck = false; + } + break; + // recompilation might be needed + case ACL_TYPE_LLVMIR_BINARY: + case ACL_TYPE_DEFAULT: + default: + break; + } + return from; +} + +bool HSAILProgram::linkImpl(const std::vector& inputPrograms, + amd::option::Options* options, bool createLibrary) { + std::vector::const_iterator it = inputPrograms.begin(); + std::vector::const_iterator itEnd = inputPrograms.end(); + acl_error errorCode; + + // For each program we need to extract the LLVMIR and create + // aclBinary for each + std::vector binaries_to_link; + + for (size_t i = 0; it != itEnd; ++it, ++i) { + Program* program = (Program*)*it; + // Check if the program was created with clCreateProgramWIthBinary + binary_t binary = program->binary(); + if ((binary.first != nullptr) && (binary.second > 0)) { + // Binary already exists -- we can also check if there is no + // opencl source code + // Need to check if LLVMIR exists in the binary + // If LLVMIR does not exist then is it valid + // We need to pull out all the compiled kernels + // We cannot do this at present because we need at least + // Hsail text to pull the kernels oout + void* mem = const_cast(binary.first); + binaryElf_ = aclReadFromMem(mem, binary.second, &errorCode); + + if (errorCode != ACL_SUCCESS) { + LogWarning("Error while linking : Could not read from raw binary"); + return false; + } + } + // At this stage each Program contains a valid binary_elf + // Check if LLVMIR is in the binary + size_t boolSize = sizeof(bool); + bool containsLLLVMIR = false; + errorCode = aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LLVMIR, + nullptr, &containsLLLVMIR, &boolSize); + if (errorCode != ACL_SUCCESS || !containsLLLVMIR) { + buildLog_ += "Error while linking : Invalid binary (Missing LLVMIR section)"; + return false; + } + // Create a new aclBinary for each LLVMIR and save it in a list + aclBIFVersion ver = aclBinaryVersion(binaryElf_); + aclBinary* bin = aclCreateFromBinary(binaryElf_, ver); + binaries_to_link.push_back(bin); + } + + // At this stage each Program in the list has an aclBinary initialized + // and contains LLVMIR + // We can now go ahead and link them. + if (binaries_to_link.size() > 1) { + errorCode = aclLink(device().compiler(), binaries_to_link[0], + binaries_to_link.size() - 1, &binaries_to_link[1], + ACL_TYPE_LLVMIR_BINARY, "-create-library", nullptr); + } else { + errorCode = aclLink(device().compiler(), binaries_to_link[0], 0, nullptr, + ACL_TYPE_LLVMIR_BINARY, "-create-library", nullptr); + } + if (errorCode != ACL_SUCCESS) { + buildLog_ += "Failed to link programs"; + return false; + } + // Store the newly linked aclBinary for this program. + binaryElf_ = binaries_to_link[0]; + // Free all the other aclBinaries + for (size_t i = 1; i < binaries_to_link.size(); i++) { + aclBinaryFini(binaries_to_link[i]); + } + if (createLibrary) { + saveBinaryAndSetType(TYPE_LIBRARY); + return true; + } + + // Now call linkImpl with the new options + return linkImpl(options); +} + +bool HSAILProgram::linkImpl(amd::option::Options* options) { + acl_error errorCode; + aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; + bool finalize = true; + // If !binaryElf_ then program must have been created using clCreateProgramWithBinary + if (!binaryElf_) { + continueCompileFrom = getNextCompilationStageFromBinary(options); + } + switch (continueCompileFrom) { + // Compilation from ACL_TYPE_LLVMIR_BINARY to ACL_TYPE_CG in cases: + // 1. if the program is not created with binary; + // 2. if the program is created with binary and contains only .llvmir & .comment + // 3. if the program is created with binary, contains .llvmir, .comment, brig sections, + // but the binary's compile & link options differ from current ones (recompilation); + case ACL_TYPE_LLVMIR_BINARY: + // Compilation from ACL_TYPE_HSAIL_BINARY to ACL_TYPE_CG in cases: + // 1. if the program is created with binary and contains only brig sections + case ACL_TYPE_HSAIL_BINARY: + // Compilation from ACL_TYPE_HSAIL_TEXT to ACL_TYPE_CG in cases: + // 1. if the program is created with binary and contains only hsail text + case ACL_TYPE_HSAIL_TEXT: { + std::string curOptions = + options->origOptionStr + preprocessorOptions(options) + codegenOptions(options); + errorCode = aclCompile(device().compiler(), binaryElf_, curOptions.c_str(), + continueCompileFrom, ACL_TYPE_CG, logFunction); + buildLog_ += aclGetCompilerLog(device().compiler()); + if (errorCode != ACL_SUCCESS) { + buildLog_ += "Error while BRIG Codegen phase: compilation error \n"; + return false; + } + break; + } + case ACL_TYPE_CG: + break; + case ACL_TYPE_ISA: { + finalize = false; + break; + } + default: + buildLog_ += "Error while BRIG Codegen phase: the binary is incomplete \n"; + return false; + } + // Stop compilation if it is an offline device - HSA runtime does not + // support ISA compiled offline + if (!dev().isOnline()) { + return true; + } + + if (finalize) { + std::string fin_options(options->origOptionStr); + // Append an option so that we can selectively enable a SCOption on CZ + // whenever IOMMUv2 is enabled. + if (dev().isFineGrainedSystem(true)) { + fin_options.append(" -sc-xnack-iommu"); + } + errorCode = aclCompile(device().compiler(), binaryElf_, fin_options.c_str(), ACL_TYPE_CG, + ACL_TYPE_ISA, logFunction); + buildLog_ += aclGetCompilerLog(device().compiler()); + if (errorCode != ACL_SUCCESS) { + buildLog_ += "Error: BRIG finalization to ISA failed.\n"; + return false; + } + } + size_t secSize; + void* data = + (void*)aclExtractSection(device().compiler(), binaryElf_, &secSize, aclTEXT, &errorCode); + if (errorCode != ACL_SUCCESS) { + buildLog_ += "Error: cannot extract ISA from compiled binary.\n"; + return false; + } + + // Create an executable. + hsa_status_t status = hsa_executable_create_alt( + HSA_PROFILE_FULL, HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT, nullptr, &hsaExecutable_); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to create executable: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + // Load the code object. + hsa_code_object_reader_t codeObjectReader; + status = hsa_code_object_reader_create_from_memory(data, secSize, &codeObjectReader); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: AMD HSA Code Object Reader create failed: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + hsa_agent_t hsaDevice = dev().getBackendDevice(); + status = hsa_executable_load_agent_code_object(hsaExecutable_, hsaDevice, codeObjectReader, + nullptr, nullptr); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: AMD HSA Code Object loading failed: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + hsa_code_object_reader_destroy(codeObjectReader); + + // Freeze the executable. + status = hsa_executable_freeze(hsaExecutable_, nullptr); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to freeze executable: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + // Get the list of kernels + std::vector kernelNameList; + status = hsa_executable_iterate_agent_symbols(hsaExecutable_, hsaDevice, GetKernelNamesCallback, + (void*)&kernelNameList); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get kernel names: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + for (auto& kernelName : kernelNameList) { + // Query symbol handle for this symbol. + hsa_executable_symbol_t kernelSymbol; + status = hsa_executable_get_symbol_by_name(hsaExecutable_, kernelName.c_str(), &hsaDevice, + &kernelSymbol); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get executable symbol: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + // Query code handle for this symbol. + uint64_t kernelCodeHandle; + status = hsa_executable_symbol_get_info(kernelSymbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, + &kernelCodeHandle); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get executable symbol info: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + std::string openclKernelName = kernelName; + // Strip the opencl and kernel name + kernelName = kernelName.substr(strlen("&__OpenCL_"), kernelName.size()); + kernelName = kernelName.substr(0, kernelName.size() - strlen("_kernel")); + aclMetadata md; + md.numHiddenKernelArgs = 0; + + size_t sizeOfnumHiddenKernelArgs = sizeof(md.numHiddenKernelArgs); + errorCode = aclQueryInfo(device().compiler(), binaryElf_, + RT_NUM_KERNEL_HIDDEN_ARGS, openclKernelName.c_str(), + &md.numHiddenKernelArgs, &sizeOfnumHiddenKernelArgs); + if (errorCode != ACL_SUCCESS) { + buildLog_ += + "Error while Finalization phase: Kernel extra arguments count querying from the ELF " + "failed\n"; + return false; + } + + uint32_t workgroupGroupSegmentByteSize; + status = hsa_executable_symbol_get_info(kernelSymbol, + HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_GROUP_SEGMENT_SIZE, + &workgroupGroupSegmentByteSize); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get group segment size info: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + uint32_t workitemPrivateSegmentByteSize; + status = hsa_executable_symbol_get_info(kernelSymbol, + HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE, + &workitemPrivateSegmentByteSize); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get private segment size info: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + uint32_t kernargSegmentByteSize; + status = hsa_executable_symbol_get_info(kernelSymbol, + HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_SIZE, + &kernargSegmentByteSize); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get kernarg segment size info: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + uint32_t kernargSegmentAlignment; + status = hsa_executable_symbol_get_info( + kernelSymbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_ALIGNMENT, + &kernargSegmentAlignment); + if (status != HSA_STATUS_SUCCESS) { + buildLog_ += "Error: Failed to get kernarg segment alignment info: "; + buildLog_ += hsa_strerror(status); + buildLog_ += "\n"; + return false; + } + + Kernel* aKernel = new roc::HSAILKernel(kernelName, this, kernelCodeHandle, + workgroupGroupSegmentByteSize, + workitemPrivateSegmentByteSize, + kernargSegmentByteSize, kernargSegmentAlignment); + if (!aKernel->init()) { + return false; + } + aKernel->setUniformWorkGroupSize(options->oVariables->UniformWorkGroupSize); + aKernel->setInternalKernelFlag(compileOptions_.find("-cl-internal-kernel") != + std::string::npos); + kernels()[kernelName] = aKernel; + } + saveBinaryAndSetType(TYPE_EXECUTABLE); + buildLog_ += aclGetCompilerLog(device().compiler()); + return true; } -bool HSAILProgram::saveBinaryAndSetType(type_t type, void* rawBinary, size_t size) { -// Write binary to memory #if defined(WITH_LIGHTNING_COMPILER) +LightningProgram::LightningProgram(roc::NullDevice& device) : roc::Program(device) { + metadata_ = nullptr; +} + +LightningProgram::~LightningProgram() { + delete metadata_; +} + +bool LightningProgram::createBinary(amd::option::Options* options) { + if (!clBinary()->createElfBinary(options->oVariables->BinEncrypt, type())) { + LogError("Failed to create ELF binary image!"); + return false; + } + return true; +} + +bool LightningProgram::saveBinaryAndSetType(type_t type, void* rawBinary, size_t size) { + // Write binary to memory if (type == TYPE_EXECUTABLE) { // handle code object binary assert(rawBinary != nullptr && size != 0 && "must pass in the binary"); - } else { // handle LLVM binary + } + else { // handle LLVM binary if (llvmBinary_.empty()) { buildLog_ += "ERROR: Tried to save emtpy LLVM binary \n"; return false; @@ -424,31 +847,63 @@ bool HSAILProgram::saveBinaryAndSetType(type_t type, void* rawBinary, size_t siz rawBinary = (void*)llvmBinary_.data(); size = llvmBinary_.size(); } -#else // !defined(WITH_LIGHTNING_COMPILER) - if (g_complibApi._aclWriteToMem(binaryElf_, &rawBinary, &size) != ACL_SUCCESS) { - buildLog_ += "Failed to write binary to memory \n"; - return false; - } -#endif // !defined(WITH_LIGHTNING_COMPILER) clBinary()->saveBIFBinary((char*)rawBinary, size); + // Set the type of binary setType(type); - -// Free memory containing rawBinary -#if !defined(WITH_LIGHTNING_COMPILER) - binaryElf_->binOpts.dealloc(rawBinary); -#endif return true; } -#if defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::linkImpl_LC(const std::vector& inputPrograms, - amd::option::Options* options, bool createLibrary) { +aclType LightningProgram::getCompilationStagesFromBinary(std::vector& completeStages, + bool& needOptionsCheck) { + completeStages.clear(); + aclType from = ACL_TYPE_DEFAULT; + needOptionsCheck = true; + //! @todo Should we also check for ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT? + // Checking llvmir in .llvmir section + bool containsLlvmirText = (type() == TYPE_COMPILED); + bool containsShaderIsa = (type() == TYPE_EXECUTABLE); + bool containsOpts = !(compileOptions_.empty() && linkOptions_.empty()); + + if (containsLlvmirText && containsOpts) { + completeStages.push_back(from); + from = ACL_TYPE_LLVMIR_BINARY; + } + if (containsShaderIsa) { + completeStages.push_back(from); + from = ACL_TYPE_ISA; + } + std::string sCurOptions = compileOptions_ + linkOptions_; + amd::option::Options curOptions; + if (!amd::option::parseAllOptions(sCurOptions, curOptions)) { + buildLog_ += curOptions.optionsLog(); + LogError("Parsing compile options failed."); + return ACL_TYPE_DEFAULT; + } + switch (from) { + case ACL_TYPE_CG: + case ACL_TYPE_ISA: + // do not check options, if LLVMIR is absent or might be absent or options are absent + if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) { + needOptionsCheck = false; + } + break; + // recompilation might be needed + case ACL_TYPE_LLVMIR_BINARY: + case ACL_TYPE_DEFAULT: + default: + break; + } + return from; +} + +bool LightningProgram::linkImpl(const std::vector& inputPrograms, + amd::option::Options* options, bool createLibrary) { using namespace amd::opencl_driver; std::unique_ptr C(newCompilerInstance()); std::vector inputs; - for (auto program : (const std::vector&)inputPrograms) { + for (auto program : (const std::vector&)inputPrograms) { if (program->llvmBinary_.empty()) { if (program->clBinary() == nullptr) { buildLog_ += "Internal error: Input program not compiled!\n"; @@ -458,7 +913,7 @@ bool HSAILProgram::linkImpl_LC(const std::vector& inputPrograms, // We are using CL binary directly. // Setup elfIn() and try to load llvmIR from binary // This elfIn() will be released at the end of build by finiBuild(). - if (!program->clBinary()->setElfIn(ELFCLASS64)) { + if (!program->clBinary()->setElfIn()) { buildLog_ += "Internal error: Setting input OCL binary failed!\n"; return false; } @@ -529,100 +984,37 @@ bool HSAILProgram::linkImpl_LC(const std::vector& inputPrograms, return true; } - return linkImpl_LC(options); + return linkImpl(options); } -#endif // defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::linkImpl(const std::vector& inputPrograms, - amd::option::Options* options, bool createLibrary) { -#if defined(WITH_LIGHTNING_COMPILER) - return linkImpl_LC(inputPrograms, options, createLibrary); -#else // !defined(WITH_LIGHTNING_COMPILER) - std::vector::const_iterator it = inputPrograms.begin(); - std::vector::const_iterator itEnd = inputPrograms.end(); +bool LightningProgram::linkImpl(amd::option::Options* options) { acl_error errorCode; + aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; - // For each program we need to extract the LLVMIR and create - // aclBinary for each - std::vector binaries_to_link; - - for (size_t i = 0; it != itEnd; ++it, ++i) { - HSAILProgram* program = (HSAILProgram*)*it; - // Check if the program was created with clCreateProgramWIthBinary - binary_t binary = program->binary(); - if ((binary.first != nullptr) && (binary.second > 0)) { - // Binary already exists -- we can also check if there is no - // opencl source code - // Need to check if LLVMIR exists in the binary - // If LLVMIR does not exist then is it valid - // We need to pull out all the compiled kernels - // We cannot do this at present because we need at least - // Hsail text to pull the kernels oout - void* mem = const_cast(binary.first); - binaryElf_ = g_complibApi._aclReadFromMem(mem, binary.second, &errorCode); - - if (errorCode != ACL_SUCCESS) { - LogWarning("Error while linking : Could not read from raw binary"); + if (llvmBinary_.empty()) { + continueCompileFrom = getNextCompilationStageFromBinary(options); + } + switch (continueCompileFrom) { + case ACL_TYPE_CG: + case ACL_TYPE_LLVMIR_BINARY: { + break; + } + break; + case ACL_TYPE_ISA: { + binary_t isaBinary = binary(); + if ((isaBinary.first != nullptr) && (isaBinary.second > 0)) { + return setKernels(options, (void*)isaBinary.first, isaBinary.second); + } else { + buildLog_ += "Error: code object is empty \n"; return false; } + break; } - // At this stage each HSAILProgram contains a valid binary_elf - // Check if LLVMIR is in the binary - size_t boolSize = sizeof(bool); - bool containsLLLVMIR = false; - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, RT_CONTAINS_LLVMIR, - nullptr, &containsLLLVMIR, &boolSize); - if (errorCode != ACL_SUCCESS || !containsLLLVMIR) { - buildLog_ += "Error while linking : Invalid binary (Missing LLVMIR section)"; + default: + buildLog_ += "Error while BRIG Codegen phase: the binary is incomplete \n"; return false; - } - // Create a new aclBinary for each LLVMIR and save it in a list - aclBIFVersion ver = g_complibApi._aclBinaryVersion(binaryElf_); - aclBinary* bin = g_complibApi._aclCreateFromBinary(binaryElf_, ver); - binaries_to_link.push_back(bin); } - // At this stage each HSAILProgram in the list has an aclBinary initialized - // and contains LLVMIR - // We can now go ahead and link them. - if (binaries_to_link.size() > 1) { - errorCode = g_complibApi._aclLink(device().compiler(), binaries_to_link[0], - binaries_to_link.size() - 1, &binaries_to_link[1], - ACL_TYPE_LLVMIR_BINARY, "-create-library", nullptr); - } else { - errorCode = g_complibApi._aclLink(device().compiler(), binaries_to_link[0], 0, nullptr, - ACL_TYPE_LLVMIR_BINARY, "-create-library", nullptr); - } - if (errorCode != ACL_SUCCESS) { - buildLog_ += "Failed to link programs"; - return false; - } - // Store the newly linked aclBinary for this program. - binaryElf_ = binaries_to_link[0]; - // Free all the other aclBinaries - for (size_t i = 1; i < binaries_to_link.size(); i++) { - g_complibApi._aclBinaryFini(binaries_to_link[i]); - } - if (createLibrary) { - saveBinaryAndSetType(TYPE_LIBRARY); - return true; - } - - // Now call linkImpl with the new options - return linkImpl(options); -#endif // !defined(WITH_LIGHTNING_COMPILER) -} - -static inline const char* hsa_strerror(hsa_status_t status) { - const char* str = nullptr; - if (hsa_status_string(status, &str) == HSA_STATUS_SUCCESS) { - return str; - } - return "Unknown error"; -} - -#if defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::linkImpl_LC(amd::option::Options* options) { using namespace amd::opencl_driver; std::unique_ptr C(newCompilerInstance()); @@ -791,10 +1183,10 @@ bool HSAILProgram::linkImpl_LC(amd::option::Options* options) { } } - return setKernels_LC(options, out_exec->Buf().data(), out_exec->Size()); + return setKernels(options, out_exec->Buf().data(), out_exec->Size()); } -bool HSAILProgram::setKernels_LC(amd::option::Options* options, void* binary, size_t binSize) { +bool LightningProgram::setKernels(amd::option::Options* options, void* binary, size_t binSize) { size_t progvarsTotalSize = 0; size_t dynamicSize = 0; size_t progvarsWriteSize = 0; @@ -1006,7 +1398,7 @@ bool HSAILProgram::setKernels_LC(amd::option::Options* options, void* binary, si // the worse case: 128byte aligned. kernargSegmentAlignment = std::max(kernargSegmentAlignment, 128u); - Kernel* aKernel = new roc::Kernel( + Kernel* aKernel = new roc::LightningKernel( kernelName, this, kernelCodeHandle, workgroupGroupSegmentByteSize, workitemPrivateSegmentByteSize, kernargSegmentByteSize, amd::alignUp(kernargSegmentAlignment, device().info().globalMemCacheLineSize_)); @@ -1023,369 +1415,6 @@ bool HSAILProgram::setKernels_LC(amd::option::Options* options, void* binary, si } #endif // defined(WITH_LIGHTNING_COMPILER) -bool HSAILProgram::linkImpl(amd::option::Options* options) { - acl_error errorCode; - aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; - bool finalize = true; -#if !defined(WITH_LIGHTNING_COMPILER) - // If !binaryElf_ then program must have been created using clCreateProgramWithBinary - if (!binaryElf_) -#else // defined(WITH_LIGHTNING_COMPILER) - if (llvmBinary_.empty()) -#endif // defined(WITH_LIGHTNING_COMPILER) - { - continueCompileFrom = getNextCompilationStageFromBinary(options); - } - switch (continueCompileFrom) { - // Compilation from ACL_TYPE_LLVMIR_BINARY to ACL_TYPE_CG in cases: - // 1. if the program is not created with binary; - // 2. if the program is created with binary and contains only .llvmir & .comment - // 3. if the program is created with binary, contains .llvmir, .comment, brig sections, - // but the binary's compile & link options differ from current ones (recompilation); - case ACL_TYPE_LLVMIR_BINARY: - // Compilation from ACL_TYPE_HSAIL_BINARY to ACL_TYPE_CG in cases: - // 1. if the program is created with binary and contains only brig sections - case ACL_TYPE_HSAIL_BINARY: - // Compilation from ACL_TYPE_HSAIL_TEXT to ACL_TYPE_CG in cases: - // 1. if the program is created with binary and contains only hsail text - case ACL_TYPE_HSAIL_TEXT: { -#if defined(WITH_LIGHTNING_COMPILER) - if (!linkImpl_LC(options)) { - return false; - } -#else // !defined(WITH_LIGHTNING_COMPILER) - std::string curOptions = - options->origOptionStr + preprocessorOptions(options) + codegenOptions(options); - errorCode = g_complibApi._aclCompile(device().compiler(), binaryElf_, curOptions.c_str(), - continueCompileFrom, ACL_TYPE_CG, logFunction); - buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler()); - if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error while BRIG Codegen phase: compilation error \n"; - return false; - } -#endif // !defined(WITH_LIGHTNING_COMPILER) - break; - } - case ACL_TYPE_CG: - break; - case ACL_TYPE_ISA: { -#if defined(WITH_LIGHTNING_COMPILER) - binary_t isaBinary = binary(); - if ((isaBinary.first != nullptr) && (isaBinary.second > 0)) { - return setKernels_LC(options, (void*)isaBinary.first, isaBinary.second); - } else { - buildLog_ += "Error: code object is empty \n"; - return false; - } -#endif // !defined(WITH_LIGHTNING_COMPILER) - finalize = false; - break; - } - default: - buildLog_ += "Error while BRIG Codegen phase: the binary is incomplete \n"; - return false; - } - // Stop compilation if it is an offline device - HSA runtime does not - // support ISA compiled offline - if (!dev().isOnline()) { - return true; - } - -#if !defined(WITH_LIGHTNING_COMPILER) - if (finalize) { - std::string fin_options(options->origOptionStr); - // Append an option so that we can selectively enable a SCOption on CZ - // whenever IOMMUv2 is enabled. - if (dev().isFineGrainedSystem(true)) { - fin_options.append(" -sc-xnack-iommu"); - } - errorCode = aclCompile(dev().compiler(), binaryElf_, fin_options.c_str(), ACL_TYPE_CG, - ACL_TYPE_ISA, logFunction); - buildLog_ += aclGetCompilerLog(dev().compiler()); - if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error: BRIG finalization to ISA failed.\n"; - return false; - } - } - size_t secSize; - void* data = - (void*)aclExtractSection(device().compiler(), binaryElf_, &secSize, aclTEXT, &errorCode); - if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error: cannot extract ISA from compiled binary.\n"; - return false; - } - - // Create an executable. - hsa_status_t status = hsa_executable_create_alt( - HSA_PROFILE_FULL, HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT, nullptr, &hsaExecutable_); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to create executable: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - // Load the code object. - hsa_code_object_reader_t codeObjectReader; - status = hsa_code_object_reader_create_from_memory(data, secSize, &codeObjectReader); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: AMD HSA Code Object Reader create failed: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - hsa_agent_t hsaDevice = dev().getBackendDevice(); - status = hsa_executable_load_agent_code_object(hsaExecutable_, hsaDevice, codeObjectReader, - nullptr, nullptr); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: AMD HSA Code Object loading failed: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - hsa_code_object_reader_destroy(codeObjectReader); - - // Freeze the executable. - status = hsa_executable_freeze(hsaExecutable_, nullptr); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to freeze executable: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - // Get the list of kernels - std::vector kernelNameList; - status = hsa_executable_iterate_agent_symbols(hsaExecutable_, hsaDevice, GetKernelNamesCallback, - (void*)&kernelNameList); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get kernel names: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - for (auto& kernelName : kernelNameList) { - // Query symbol handle for this symbol. - hsa_executable_symbol_t kernelSymbol; - status = hsa_executable_get_symbol_by_name(hsaExecutable_, kernelName.c_str(), &hsaDevice, - &kernelSymbol); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get executable symbol: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - // Query code handle for this symbol. - uint64_t kernelCodeHandle; - status = hsa_executable_symbol_get_info(kernelSymbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, - &kernelCodeHandle); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get executable symbol info: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - std::string openclKernelName = kernelName; - // Strip the opencl and kernel name - kernelName = kernelName.substr(strlen("&__OpenCL_"), kernelName.size()); - kernelName = kernelName.substr(0, kernelName.size() - strlen("_kernel")); - aclMetadata md; - md.numHiddenKernelArgs = 0; - - size_t sizeOfnumHiddenKernelArgs = sizeof(md.numHiddenKernelArgs); - errorCode = g_complibApi._aclQueryInfo(device().compiler(), binaryElf_, - RT_NUM_KERNEL_HIDDEN_ARGS, openclKernelName.c_str(), - &md.numHiddenKernelArgs, &sizeOfnumHiddenKernelArgs); - if (errorCode != ACL_SUCCESS) { - buildLog_ += - "Error while Finalization phase: Kernel extra arguments count querying from the ELF " - "failed\n"; - return false; - } - - uint32_t workgroupGroupSegmentByteSize; - status = hsa_executable_symbol_get_info(kernelSymbol, - HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_GROUP_SEGMENT_SIZE, - &workgroupGroupSegmentByteSize); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get group segment size info: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - uint32_t workitemPrivateSegmentByteSize; - status = hsa_executable_symbol_get_info(kernelSymbol, - HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE, - &workitemPrivateSegmentByteSize); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get private segment size info: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - uint32_t kernargSegmentByteSize; - status = hsa_executable_symbol_get_info(kernelSymbol, - HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_SIZE, - &kernargSegmentByteSize); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get kernarg segment size info: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - uint32_t kernargSegmentAlignment; - status = hsa_executable_symbol_get_info( - kernelSymbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_KERNARG_SEGMENT_ALIGNMENT, - &kernargSegmentAlignment); - if (status != HSA_STATUS_SUCCESS) { - buildLog_ += "Error: Failed to get kernarg segment alignment info: "; - buildLog_ += hsa_strerror(status); - buildLog_ += "\n"; - return false; - } - - Kernel* aKernel = new roc::Kernel(kernelName, this, kernelCodeHandle, - workgroupGroupSegmentByteSize, workitemPrivateSegmentByteSize, - kernargSegmentByteSize, kernargSegmentAlignment); - if (!aKernel->init()) { - return false; - } - aKernel->setUniformWorkGroupSize(options->oVariables->UniformWorkGroupSize); - aKernel->setInternalKernelFlag(compileOptions_.find("-cl-internal-kernel") != - std::string::npos); - kernels()[kernelName] = aKernel; - } - saveBinaryAndSetType(TYPE_EXECUTABLE); - buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler()); -#endif // !defined(WITH_LIGHTNING_COMPILER) - return true; -} - -bool HSAILProgram::createBinary(amd::option::Options* options) { -#if defined(WITH_LIGHTNING_COMPILER) - if (!clBinary()->createElfBinary(options->oVariables->BinEncrypt, type())) { - LogError("Failed to create ELF binary image!"); - return false; - } - return true; -#else // !defined(WITH_LIGHTNING_COMPILER) - return false; -#endif // !defined(WITH_LIGHTNING_COMPILER) -} - -bool HSAILProgram::initClBinary() { - if (clBinary_ == nullptr) { - clBinary_ = new ClBinary(static_cast(device())); - if (clBinary_ == nullptr) { - return false; - } - } - return true; -} - -void HSAILProgram::releaseClBinary() { - if (clBinary_ != nullptr) { - delete clBinary_; - clBinary_ = nullptr; - } -} - -std::string HSAILProgram::codegenOptions(amd::option::Options* options) { - std::string optionsStr; - -#if !defined(WITH_LIGHTNING_COMPILER) - if (dev().deviceInfo().gfxipVersion_ < 900 || !dev().settings().singleFpDenorm_) { - optionsStr.append(" -cl-denorms-are-zero"); - } -#endif // !defined(WITH_LIGHTNING_COMPILER) - - // check if the host is 64 bit or 32 bit - LP64_ONLY(optionsStr.append(" -m64")); - - return optionsStr; -} - -std::string HSAILProgram::preprocessorOptions(amd::option::Options* options) { - std::string optionsStr; - - // Set options for the standard device specific options - - optionsStr.append(" -D__AMD__=1"); - - optionsStr.append(" -D__").append(device().info().name_).append("__=1"); - optionsStr.append(" -D__").append(device().info().name_).append("=1"); - - int major, minor; - ::sscanf(device().info().version_, "OpenCL %d.%d ", &major, &minor); - - std::stringstream ss; - ss << " -D__OPENCL_VERSION__=" << (major * 100 + minor * 10); - optionsStr.append(ss.str()); - - if (device().info().imageSupport_ && options->oVariables->ImageSupport) { - optionsStr.append(" -D__IMAGE_SUPPORT__=1"); - } - - // This is just for legacy compiler code - // All our devices support these options now - if (options->oVariables->FastFMA) { - optionsStr.append(" -DFP_FAST_FMA=1"); - } - if (options->oVariables->FastFMAF) { - optionsStr.append(" -DFP_FAST_FMAF=1"); - } - - uint clcStd = - (options->oVariables->CLStd[2] - '0') * 100 + (options->oVariables->CLStd[4] - '0') * 10; - - if (clcStd >= 200) { - std::stringstream opts; - // Add only for CL2.0 and later - opts << " -D" - << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE=" << device().info().maxGlobalVariableSize_; - optionsStr.append(opts.str()); - } - - // Tokenize the extensions string into a vector of strings - std::istringstream istrstr(device().info().extensions_); - std::istream_iterator sit(istrstr), end; - std::vector extensions(sit, end); - -#if defined(WITH_LIGHTNING_COMPILER) - // FIXME_lmoriche: opencl-c.h defines 'cl_khr_depth_images', so - // remove it from the command line. Should we fix opencl-c.h? - auto found = std::find(extensions.begin(), extensions.end(), "cl_khr_depth_images"); - if (found != extensions.end()) { - extensions.erase(found); - } - - if (!extensions.empty()) { - std::ostringstream clext; - - clext << " -Xclang -cl-ext=+"; - std::copy(extensions.begin(), extensions.end() - 1, - std::ostream_iterator(clext, ",+")); - clext << extensions.back(); - - optionsStr.append(clext.str()); - } -#else // !defined(WITH_LIGHTNING_COMPILER) - for (auto e : extensions) { - optionsStr.append(" -D").append(e).append("=1"); - } -#endif // !defined(WITH_LIGHTNING_COMPILER) - - return optionsStr; -} - } // namespace roc #endif // WITHOUT_HSA_BACKEND diff --git a/rocclr/runtime/device/rocm/rocprogram.hpp b/rocclr/runtime/device/rocm/rocprogram.hpp index de25b29377..e1154014c3 100644 --- a/rocclr/runtime/device/rocm/rocprogram.hpp +++ b/rocclr/runtime/device/rocm/rocprogram.hpp @@ -6,9 +6,6 @@ #ifndef WITHOUT_HSA_BACKEND #include "rocbinary.hpp" -#if !defined(WITH_LIGHTNING_COMPILER) -#include "roccompilerlib.hpp" -#endif // !defined(WITH_LIGHTNING_COMPILER) #include "acl.h" #include #include @@ -29,15 +26,18 @@ typedef llvm::AMDGPU::HSAMD::Kernel::Arg::Metadata KernelArgMD; //! \namespace roc HSA Device Implementation namespace roc { +class HSAILProgram; +class LightningProgram; + //! \class empty program -class HSAILProgram : public device::Program { +class Program : public device::Program { friend class ClBinary; public: //! Default constructor - HSAILProgram(roc::NullDevice& device); + Program(roc::NullDevice& device); //! Default destructor - ~HSAILProgram(); + ~Program(); // Initialize Binary for GPU (used only for clCreateProgramWithBinary()). virtual bool initClBinary(char* binaryIn, size_t size); @@ -45,11 +45,6 @@ class HSAILProgram : public device::Program { //! Returns the aclBinary associated with the program const aclBinary* binaryElf() const { return static_cast(binaryElf_); } -#if defined(WITH_LIGHTNING_COMPILER) - //! Returns the program metadata. - const CodeObjectMD* metadata() const { return metadata_; } -#endif // defined(WITH_LIGHTNING_COMPILER) - //! Return a typecasted GPU device const NullDevice& dev() const { return static_cast(device()); } @@ -65,23 +60,6 @@ class HSAILProgram : public device::Program { //! post-compile setup for GPU virtual bool finiBuild(bool isBuildGood); - /*! \brief Compiles GPU CL program to LLVM binary (compiler frontend) - * - * \return True if we successfully compiled a GPU program - */ - virtual bool compileImpl(const std::string& sourceCode, //!< the program's source code - const std::vector& headers, - const char** headerIncludeNames, - amd::option::Options* options //!< compile options's object - ); -#if defined(WITH_LIGHTNING_COMPILER) - virtual bool compileImpl_LC(const std::string& sourceCode, //!< the program's source code - const std::vector& headers, - const char** headerIncludeNames, - amd::option::Options* options //!< compile options's object - ); -#endif // defined(WITH_LIGHTNING_COMPILER) - /*! \brief Compiles LLVM binary to HSAIL code (compiler backend: link+opt+codegen) * * \return The build error code @@ -89,22 +67,7 @@ class HSAILProgram : public device::Program { int compileBinaryToHSAIL(amd::option::Options* options //!< options for compilation ); - - virtual bool linkImpl(amd::option::Options* options); -#if defined(WITH_LIGHTNING_COMPILER) - virtual bool linkImpl_LC(amd::option::Options* options); - bool setKernels_LC(amd::option::Options* options, void* binary, size_t binSize); -#endif // defined(WITH_LIGHTNING_COMPILER) - - //! Link the device programs. - virtual bool linkImpl(const std::vector& inputPrograms, amd::option::Options* options, - bool createLibrary); -#if defined(WITH_LIGHTNING_COMPILER) - virtual bool linkImpl_LC(const std::vector& inputPrograms, - amd::option::Options* options, bool createLibrary); -#endif // defined(WITH_LIGHTNING_COMPILER) - - virtual bool createBinary(amd::option::Options* options); + virtual bool createBinary(amd::option::Options* options) = 0; //! Initialize Binary virtual bool initClBinary(); @@ -127,28 +90,27 @@ class HSAILProgram : public device::Program { return static_cast(device::Program::clBinary()); } - private: + protected: /* \brief Returns the next stage to compile from, based on sections in binary, * also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT, * sets needOptionsCheck to true if options check is needed to decide whether or not to recompile */ - aclType getCompilationStagesFromBinary(std::vector& completeStages, - bool& needOptionsCheck); + virtual aclType getCompilationStagesFromBinary(std::vector& completeStages, + bool& needOptionsCheck) = 0; /* \brief Returns the next stage to compile from, based on sections and options in binary */ aclType getNextCompilationStageFromBinary(amd::option::Options* options); - bool saveBinaryAndSetType(type_t type, void* binary = nullptr, size_t size = 0); //! Disable default copy constructor - HSAILProgram(const HSAILProgram&) = delete; + Program(const Program&) = delete; //! Disable operator= - HSAILProgram& operator=(const HSAILProgram&) = delete; + Program& operator=(const Program&) = delete; +protected: //! Returns all the options to be appended while passing to the // compiler std::string preprocessorOptions(amd::option::Options* options); - std::string codegenOptions(amd::option::Options* options); // aclBinary and aclCompiler - for the compiler library aclBinary* binaryElf_; //!< Binary for the new compiler library @@ -158,13 +120,72 @@ class HSAILProgram : public device::Program { /* HSA executable */ hsa_executable_t hsaExecutable_; //!< Handle to HSA executable hsa_code_object_reader_t hsaCodeObjectReader_; //!< Handle to HSA code reader +}; + +class HSAILProgram : public roc::Program { + public: + HSAILProgram(roc::NullDevice& device); + virtual ~HSAILProgram(); + + protected: + virtual bool compileImpl(const std::string& sourceCode, //!< the program's source code + const std::vector& headers, + const char** headerIncludeNames, + amd::option::Options* options //!< compile options's object + ) final; + + virtual bool linkImpl(amd::option::Options* options) final; + + virtual bool linkImpl(const std::vector& inputPrograms, + amd::option::Options* options, bool createLibrary) final; + + virtual bool createBinary(amd::option::Options* options) final; + +private: + std::string codegenOptions(amd::option::Options* options); + + virtual aclType getCompilationStagesFromBinary(std::vector& completeStages, + bool& needOptionsCheck) final; + + bool saveBinaryAndSetType(type_t type); +}; #if defined(WITH_LIGHTNING_COMPILER) +class LightningProgram : public roc::Program { +public: + LightningProgram(roc::NullDevice& device); + virtual ~LightningProgram(); + + //! Returns the program metadata. + const CodeObjectMD* metadata() const { return metadata_; } + +protected: + virtual bool compileImpl(const std::string& sourceCode, //!< the program's source code + const std::vector& headers, + const char** headerIncludeNames, + amd::option::Options* options //!< compile options's object + ) final; + + virtual bool linkImpl(amd::option::Options* options) final; + + virtual bool linkImpl(const std::vector& inputPrograms, + amd::option::Options* options, bool createLibrary) final; + + virtual bool createBinary(amd::option::Options* options) final; + +private: + bool saveBinaryAndSetType(type_t type, void* rawBinary, size_t size); + + virtual aclType getCompilationStagesFromBinary(std::vector& completeStages, + bool& needOptionsCheck) final; + + bool setKernels(amd::option::Options* options, void* binary, size_t binSize); + CodeObjectMD* metadata_; //!< Runtime metadata //! Return a new transient compiler instance. static amd::opencl_driver::Compiler* newCompilerInstance(); -#endif // defined(WITH_LIGHTNING_COMPILER) }; +#endif // defined(WITH_LIGHTNING_COMPILER) /*@}*/} // namespace roc diff --git a/rocclr/runtime/platform/program.cpp b/rocclr/runtime/platform/program.cpp index f9926a83bb..2c0b3c3039 100644 --- a/rocclr/runtime/platform/program.cpp +++ b/rocclr/runtime/platform/program.cpp @@ -49,18 +49,14 @@ const Symbol* Program::findSymbol(const char* kernelName) const { cl_int Program::addDeviceProgram(Device& device, const void* image, size_t length, amd::option::Options* options) { -#if defined(WITH_LIGHTNING_COMPILER) - // LC binary must be in ELF format - if (image != NULL && !amd::isElfMagic((const char*)image)) { + if (image != NULL && !amd::isElfMagic((const char*)image) +#if !defined(WITH_LIGHTNING_COMPILER) + && !aclValidateBinaryImage( + image, length, isSPIRV_ ? BINARY_TYPE_SPIRV : BINARY_TYPE_ELF | BINARY_TYPE_LLVM) +#endif // !defined(WITH_LIGHTNING_COMPILER) + ) { return CL_INVALID_BINARY; } -#else // !defined(WITH_LIGHTNING_COMPILER) - if (image != NULL && - !aclValidateBinaryImage(image, length, - isSPIRV_ ? BINARY_TYPE_SPIRV : BINARY_TYPE_ELF | BINARY_TYPE_LLVM)) { - return CL_INVALID_BINARY; - } -#endif // !defined(WITH_LIGHTNING_COMPILER) // Check if the device is already associated with this program if (deviceList_.find(&device) != deviceList_.end()) { @@ -80,7 +76,6 @@ cl_int Program::addDeviceProgram(Device& device, const void* image, size_t lengt emptyOptions = true; } -#if !defined(WITH_LIGHTNING_COMPILER) if (image != NULL && length != 0 && aclValidateBinaryImage(image, length, BINARY_TYPE_ELF)) { acl_error errorCode; aclBinary* binary = aclReadFromMem(image, length, &errorCode); @@ -102,10 +97,11 @@ cl_int Program::addDeviceProgram(Device& device, const void* image, size_t lengt return CL_INVALID_COMPILER_OPTIONS; } } - options->oVariables->Legacy = isAMDILTarget(*aclutGetTargetInfo(binary)); + options->oVariables->Legacy = !IS_LIGHTNING ? + isAMDILTarget(*aclutGetTargetInfo(binary)) : + isHSAILTarget(*aclutGetTargetInfo(binary)); aclBinaryFini(binary); } -#endif // !defined(WITH_LIGHTNING_COMPILER) options->oVariables->BinaryIsSpirv = isSPIRV_; device::Program* program = rootDev.createProgram(options); if (program == NULL) { @@ -133,7 +129,7 @@ cl_int Program::addDeviceProgram(Device& device, const void* image, size_t lengt return CL_INVALID_BINARY; } -#if defined(WITH_LIGHTNING_COMPILER) +#if 0 && defined(WITH_LIGHTNING_COMPILER) // load the compiler options from the binary if it is not provided std::string sBinOptions = program->compileOptions(); if (!sBinOptions.empty() && emptyOptions) { @@ -143,7 +139,7 @@ cl_int Program::addDeviceProgram(Device& device, const void* image, size_t lengt return CL_INVALID_COMPILER_OPTIONS; } } -#endif +#endif // defined(WITH_LIGHTNING_COMPILER) } devicePrograms_[&rootDev] = program; @@ -300,8 +296,8 @@ cl_int Program::link(const std::vector& devices, size_t numInputs, // Check the binary's target for the first found device program. // TODO: Revise these binary's target checks // and possibly remove them after switching to HSAIL by default. -#if !defined(WITH_LIGHTNING_COMPILER) - if (!found && binary.first != NULL && binary.second > 0) { + if (!found && binary.first != NULL && binary.second > 0 && + aclValidateBinaryImage(binary.first, binary.second, BINARY_TYPE_ELF)) { acl_error errorCode = ACL_SUCCESS; void* mem = const_cast(binary.first); aclBinary* aclBin = aclReadFromMem(mem, binary.second, &errorCode); @@ -311,12 +307,14 @@ cl_int Program::link(const std::vector& devices, size_t numInputs, } if (isHSAILTarget(*aclutGetTargetInfo(aclBin))) { parsedOptions.oVariables->Frontend = "clang"; +#if defined(WITH_LIGHTNING_COMPILER) + parsedOptions.oVariables->Legacy = true; +#endif // defined(WITH_LIGHTNING_COMPILER) } else if (isAMDILTarget(*aclutGetTargetInfo(aclBin))) { parsedOptions.oVariables->Frontend = "edg"; } aclBinaryFini(aclBin); } -#endif // !defined(WITH_LIGHTNING_COMPILER) found = true; } if (inputDevPrograms.size() == 0) {