diff --git a/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp b/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp index 14608bb8e8..8cb38c4a67 100644 --- a/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp +++ b/rocclr/compiler/lib/backends/common/v0_8/if_acl.cpp @@ -1113,7 +1113,7 @@ aclCompileInternal( if (error_code != ACL_SUCCESS) { goto internal_compile_failure; } - } else if (useLinker || useOpt || useCG) { + } else if (useLinker || useOpt) { // Load a temp frontend object to convert from string LLVM-IR to LLVM Module. ald = cl->feAPI.init(cl, bin, compile_callback, &error_code); module = cl->feAPI.toModule(ald, data, data_size, context, &error_code); @@ -1155,23 +1155,39 @@ aclCompileInternal( bHsailTextInput = true; if (bin && bin->options) { amd::option::Options* Opts = reinterpret_cast(bin->options); - // Verify that the internal (blit) kernel is not being compiled + // Verify that the internal (blit) kernel is not being compiled size_t ifind = Opts->origOptionStr.find("-cl-internal-kernel"); if (ifind != std::string::npos) bHsailTextInput = false; } } - if (!bHsailTextInput) - { - std::string* output = (std::string*) cl->cgAPI.codegen(ald, module, context, &error_code); - - if (error_code != ACL_SUCCESS) { - goto internal_compile_failure; - } - + if (!bHsailTextInput) { amdcl::HSAIL *acl = reinterpret_cast(ald); - if (acl == NULL || !acl->insertBRIG(*output)) { - assert(!"Inserting BRIG failed\n"); + assert(acl && "Inserting BRIG failed\n"); + // from ACL_TYPE_HSAIL_BINARY + if (!useFE && !useLinker && !useOpt) { + int result = 0; + HSAIL_ASM::BrigContainer c; + // BRIG is in aclSOURCE section + if (data) { + result = HSAIL_ASM::BrigStreamer::load(c, data, data_size); + // BRIG is in its corresponding BIF sections + } else { + if (!acl->extractBRIG(c)) { + error_code = ACL_CODEGEN_ERROR; + goto internal_compile_failure; + } + } + if (result != 0 || !acl->insertBRIG(c)) { + error_code = ACL_CODEGEN_ERROR; + goto internal_compile_failure; + } + } else { + std::string* output = (std::string*) cl->cgAPI.codegen(ald, module, context, &error_code); + if (error_code != ACL_SUCCESS || !acl->insertBRIG(*output)) { + error_code = ACL_CODEGEN_ERROR; + goto internal_compile_failure; + } } } else @@ -1371,17 +1387,32 @@ if_aclCompile(aclCompiler *cl, if ((from == ACL_TYPE_AMDIL_TEXT || from == ACL_TYPE_AMDIL_BINARY - || from == ACL_TYPE_HSAIL_TEXT - || from == ACL_TYPE_HSAIL_BINARY || from == ACL_TYPE_X86_TEXT || from == ACL_TYPE_X86_BINARY) && to != ACL_TYPE_ISA) { return ACL_INVALID_ARG; } + if ((from == ACL_TYPE_HSAIL_TEXT + || from == ACL_TYPE_HSAIL_BINARY) + && (to != ACL_TYPE_CG && to != ACL_TYPE_ISA)) { + return ACL_INVALID_ARG; + } + + if (from == ACL_TYPE_HSAIL_TEXT) { + amd::option::Options* Opts = reinterpret_cast(bin->options); + const char *kernel = Opts->oVariables->Kernel; + error_code = aclConvertType(cl, bin, kernel, from); + if (error_code != ACL_SUCCESS) + return error_code; + if (to == ACL_TYPE_CG) + return ACL_SUCCESS; + from = ACL_TYPE_CG; + } + bool stages[5] = {false}; uint8_t sectable[ACL_TYPE_LAST] = - { 0, 0, 1, 1, 1, 1, 0, 6, 0, 4, 4, 4, 4, 0, 5, 0, 1 }; + { 0, 0, 1, 1, 1, 1, 0, 6, 0, 3, 4, 4, 4, 0, 5, 0, 1 }; aclSections d_section[7] = { aclSOURCE, aclLLVMIR, aclSPIR, aclSOURCE, aclCODEGEN, aclTEXT, aclINTERNAL }; uint8_t start = sectable[from]; @@ -1411,6 +1442,14 @@ if_aclCompile(aclCompiler *cl, else if (from == ACL_TYPE_RSLLVMIR_BINARY) { data = cl->clAPI.extSec(cl, bin, &data_size, aclLLVMIR, &error_code); } + else if (from == ACL_TYPE_HSAIL_BINARY) { + data = cl->clAPI.extSec(cl, bin, &data_size, aclSOURCE, &error_code); + // if for ACL_TYPE_HSAIL_BINARY stage BRIG (data) is not presented in aclSOURCE (.source) section of BIF, + // then it should be in multiple corresponding .brig_ sections in BIF, so continue to compile + if (error_code == ACL_ELF_ERROR) { + error_code = ACL_SUCCESS; + } + } else { data = cl->clAPI.extSec(cl, bin, &data_size, d_section[start], &error_code); } @@ -1799,11 +1838,75 @@ if_aclConvertType(aclCompiler *cl, break; } case ACL_TYPE_HSAIL_TEXT: + { to = ACL_TYPE_HSAIL_BINARY; + const oclBIFSymbolStruct* symbol = findBIF30SymStruct(symHSAILText); + assert(symbol && "symbol not found"); + std::string symbolName = symbol->str[PRE] + std::string("main") + symbol->str[POST]; + from_data = cl->clAPI.extSym(cl, bin, &from_data_size, + symbol->sections[0], + symbolName.c_str(), &error_code); + // HSAIL was inserted into bif as section only without corresponding symbol + if (!from_data) { + from_data = cl->clAPI.extSec(cl, bin, &from_data_size, + symbol->sections[0], &error_code); + } break; + } case ACL_TYPE_HSAIL_BINARY: - to = ACL_TYPE_HSAIL_TEXT; + { +#if defined(WITH_TARGET_HSAIL) + // BRIG to HSAIL disassembling + if (isHSAILTarget(bin->target)) { + amdcl::HSAIL *acl = new amdcl::HSAIL(cl, bin, NULL); + if (acl == NULL) { + return ACL_OUT_OF_MEM; + } + std::string hsail = acl->disassembleBRIG(); + // If HSAIL was not disassembled from multiple .brig_ sections in BIF, then: + // 1. try to extract BRIG from aclSOURCE section + if (hsail.empty()) { + from_data = cl->clAPI.extSec(cl, bin, &from_data_size, aclSOURCE, &error_code); + HSAIL_ASM::BrigContainer c; + // 2. load BRIG in BrigContainer + int result = HSAIL_ASM::BrigStreamer::load(c, + reinterpret_cast(from_data), from_data_size); + if (result != 0) { + error_code = ACL_INVALID_BINARY; + delete acl; + return error_code; + } + // 3. insert BRIG into multiple .brig_ sections in BIF + + // insert matadata symbols for every kernel + if (!acl->insertBRIG(c)) { + assert(!"Inserting BRIG failed\n"); + error_code = ACL_INVALID_BINARY; + delete acl; + return error_code; + } + // 4. second attempt to disassemble BRIG + hsail = acl->disassembleBRIG(); + } + delete acl; + if (hsail.empty()) { + return ACL_ELF_ERROR; + } + const oclBIFSymbolStruct* symbol = findBIF30SymStruct(symHSAILText); + assert(symbol && "symbol not found"); + std::string symbolName = symbol->str[PRE] + std::string("main") + + symbol->str[POST]; + return cl->clAPI.insSym(cl, bin, hsail.data(), hsail.size(), + symbol->sections[0], symbolName.c_str()); + } else { + assert(!"Unsupported architecture, expect hsail."); + return ACL_SYS_ERROR; + } +#else + assert(!"Cannot go down this path without HSAIL support!"); + return ACL_SYS_ERROR; +#endif break; + } case ACL_TYPE_X86_TEXT: to = ACL_TYPE_X86_BINARY; break; @@ -1922,6 +2025,32 @@ if_aclConvertType(aclCompiler *cl, #else assert(!"Cannot go down this path without AMDIL support!"); return ACL_SYS_ERROR; +#endif + } + break; + case ACL_TYPE_HSAIL_BINARY: + { +#if defined(WITH_TARGET_HSAIL) + if (isHSAILTarget(bin->target)) { + amdcl::HSAIL *acl = new amdcl::HSAIL(cl, bin, NULL); + if (acl == NULL) { + return ACL_OUT_OF_MEM; + } + // while assembling BRIG insertion into BIF (bin) performs, + // so no need in any symbol/section insertion here + bool bRet = acl->assemble(std::string(reinterpret_cast(from_data))); + delete acl; + if (!bRet) { + return ACL_CODEGEN_ERROR; + } + return ACL_SUCCESS; + } else { + assert(!"Unsupported architecture, expect hsail."); + return ACL_SYS_ERROR; + } +#else + assert(!"Cannot go down this path without HSAIL support!"); + return ACL_SYS_ERROR; #endif } break; @@ -1963,7 +2092,7 @@ if_aclDisassemble(aclCompiler *cl, if (!hsail_be) { goto internal_disasm_failure; } - hsail_be->disassembleBRIG(cl, bin); + hsail_be->disassembleBRIG(); } } #endif diff --git a/rocclr/runtime/device/gpu/gpuprogram.cpp b/rocclr/runtime/device/gpu/gpuprogram.cpp index 4995236b64..26ea61b683 100644 --- a/rocclr/runtime/device/gpu/gpuprogram.cpp +++ b/rocclr/runtime/device/gpu/gpuprogram.cpp @@ -1893,11 +1893,14 @@ HSAILProgram::linkImpl( } aclType -HSAILProgram::getNextCompilationStageFromBinary() +HSAILProgram::getNextCompilationStageFromBinary(std::vector& complete_stages) { acl_error errorCode; size_t secSize = 0; + complete_stages.clear(); aclType from = ACL_TYPE_DEFAULT; + //@TODO_HSA: r=emankov: Should we also check here for + // ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT? // Checking llvmir in .llvmir section bool isLlvmirText = true; @@ -1906,7 +1909,6 @@ HSAILProgram::getNextCompilationStageFromBinary() if (errorCode != ACL_SUCCESS) { isLlvmirText = false; } - // Checking compile & link options in .comment section bool isOpts = true; const void* opts = aclExtractSection(dev().hsaCompiler(), @@ -1914,22 +1916,10 @@ HSAILProgram::getNextCompilationStageFromBinary() if (errorCode != ACL_SUCCESS) { isOpts = false; } - - if (isLlvmirText) { + if (isLlvmirText && isOpts) { + complete_stages.push_back(from); from = ACL_TYPE_LLVMIR_BINARY; } - else { - if (!isLlvmirText) { - buildLog_ +="Error while linking : \ - Invalid binary (Missing LLVMIR section)\n" ; - } - if (!isOpts) { - buildLog_ +="Warning while linking : \ - Invalid binary (Missing COMMENT section)\n" ; - } - return ACL_TYPE_DEFAULT; - } - bool isHsailText = true; // Checking HSAIL in .cg section const void *hsailText = aclExtractSection(dev().hsaCompiler(), @@ -1958,31 +1948,26 @@ HSAILProgram::getNextCompilationStageFromBinary() if (errorCode != ACL_SUCCESS) { isBrigOps = false; } - - if (isHsailText && isBrigStrtab && isBrigCode && isBrigOps) { + if (isBrigStrtab && isBrigCode && isBrigOps) { + complete_stages.push_back(from); from = ACL_TYPE_HSAIL_BINARY; + // Here we should check that CG stage was done. + // Right now there are 2 criterions to check it (besides BRIG itself): + // 1. matadata symbols symOpenclKernel for every kernel. + // 2. HSAIL text in aclCODEGEN section. + // Unfortunately there is no appropriate way in Compiler Lib to check 1. + // because kernel names are unknown here, therefore 2. + + //@TODO_HSA: r=emankov: Change the HSAIL section check, + // when the solution with kernel names appears in Compiler Lib. + if (isHsailText) { + complete_stages.push_back(from); + from = ACL_TYPE_CG; + } } - else if (!isHsailText && !isBrigStrtab && !isBrigCode && !isBrigOps) { - from = ACL_TYPE_LLVMIR_BINARY; - } - else { - if (!isHsailText) { - buildLog_ +="Error while linking : \ - Invalid binary (Missing CG section)\n" ; - } - if (!isBrigStrtab) { - buildLog_ +="Error while linking : \ - Invalid binary (Missing BRIG_STRTAB section)\n" ; - } - if (!isBrigCode) { - buildLog_ +="Error while linking : \ - Invalid binary (Missing BRIG_CODE section)\n" ; - } - if (!isBrigOps) { - buildLog_ +="Error while linking : \ - Invalid binary (Missing BRIG_OPERANDS section)\n" ; - } - return ACL_TYPE_DEFAULT; + else if (isHsailText) { + complete_stages.push_back(from); + from = ACL_TYPE_HSAIL_TEXT; } // Checking ISA in .text section bool isShaderIsa = true; @@ -1992,8 +1977,12 @@ HSAILProgram::getNextCompilationStageFromBinary() isShaderIsa = false; } if (isShaderIsa && from == ACL_TYPE_LLVMIR_BINARY) { + complete_stages.clear(); from = ACL_TYPE_DEFAULT; } + if (complete_stages.empty()) { + complete_stages.push_back(from); + } return from; } @@ -2002,64 +1991,80 @@ HSAILProgram::linkImpl(amd::option::Options* options) { acl_error errorCode; aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; - //If the binaryElf_ is not set then program must have been created - // using clCreateProgramWithBinary + // If !binaryElf_ then program must have been created using clCreateProgramWithBinary if (!binaryElf_) { binary_t binary = this->binary(); + // If the binary already exists if ((binary.first != NULL) && (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) { - buildLog_ += "Error while converting to BRIG: aclBinary init failure \n" ; - LogWarning("aclBinaryInit failed"); + buildLog_ += "Error while BRIG Codegen phase: aclReadFromMem failure \n" ; + LogWarning("aclReadFromMem failed"); return false; } - // Check that all needed section also exist in binaryElf_ + // Calculate the next stage to compile from, based on sections in binaryElf_; // No any validity checks here - continueCompileFrom = getNextCompilationStageFromBinary(); + std::vector complete_stages; + continueCompileFrom = getNextCompilationStageFromBinary(complete_stages); + //@TODO_HSA: r=emankov: Should we also check here for + // ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT to recompile from? if (ACL_TYPE_DEFAULT == continueCompileFrom) { + buildLog_ += "Error while BRIG Codegen phase: the binary is incomplete \n" ; return false; } if (ACL_TYPE_HSAIL_BINARY == continueCompileFrom) { - // Save binary in the interface class - // Also load compile & link options from binary into Program class members: - // compileOptions_ & linkOptions_ + // Saving binary in the interface class, + // which also load compile & link options from binary setBinary(static_cast(mem), binary.second); - // Compare options loaded from binary with current ones - // If they differ then recompile from ACL_TYPE_LLVMIR_BINARY - // @TODO It is needed to compare options taking into account that: - // 1. options are order independent; - // 2. (may be not trivial) compare only options that affect binary - std::string curOptions = options->origOptionStr + hsailOptions(); - if (compileOptions_ + linkOptions_ != curOptions) { - continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; + // Check the previous completed stage + if (ACL_TYPE_LLVMIR_BINARY == complete_stages.back()) { + // Compare options loaded from binary with current ones + // If they differ then recompile from ACL_TYPE_LLVMIR_BINARY + //@TODO_HSA: r=emankov: Should we need to check options at all? + std::string curOptions = options->origOptionStr + hsailOptions(); + if (compileOptions_ + linkOptions_ != curOptions) { + continueCompileFrom = ACL_TYPE_LLVMIR_BINARY; + } } } } } - - // 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 all brig sections, - // but the binary's compile & link options differ from current ones (recompilation); - if (ACL_TYPE_LLVMIR_BINARY == continueCompileFrom) { - std::string curOptions = options->origOptionStr + hsailOptions(); - errorCode = aclCompile(dev().hsaCompiler(), binaryElf_, - curOptions.c_str(), ACL_TYPE_LLVMIR_BINARY, ACL_TYPE_CG, NULL); + switch (continueCompileFrom) { + default: + break; + // 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 + hsailOptions(); + errorCode = aclCompile(dev().hsaCompiler(), binaryElf_, + curOptions.c_str(), continueCompileFrom, ACL_TYPE_CG, NULL); + break; + } } if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error while converting to BRIG: Compiling LLVMIR to BRIG \n" ; + buildLog_ += "Error while BRIG Codegen phase: compilation error \n" ; return false; } + if (!aclHsaLoader(dev().hsaCompiler(), binaryElf_, this, &AllocateGPUMemory, + &DmaMemoryCopy, &GetSamplerObjectParams, &InitializeSamplerObject)) { + buildLog_ += "Error while BRIG Codegen phase: loading BRIG globals in the ELF \n"; + return false; + } + // We need to pull out kernels' names for finalizing kernels + //@TODO_HSA: r=emankov: rewrite the below code, + // if another way to obtain kernel names appears in the compiler library size_t fsailSize; const oclBIFSymbolStruct* symbol = findBIF30SymStruct(symHSAILText); assert(symbol && "symbol not found"); @@ -2071,20 +2076,11 @@ HSAILProgram::linkImpl(amd::option::Options* options) symName.c_str(), &errorCode); if (errorCode != ACL_SUCCESS) { - buildLog_ += "Error while reading out the HSAIL from the ELF" ; + buildLog_ += "Error while reading out the HSAIL from the ELF \n" ; return false; } - - if (!aclHsaLoader(dev().hsaCompiler(), binaryElf_, this, &AllocateGPUMemory, - &DmaMemoryCopy, &GetSamplerObjectParams, &InitializeSamplerObject)) { - buildLog_ += "Error while loading BRIG globals in the ELF"; - return false; - } - std::string hsailProgram((char *)hsailText); HSAILProgram_ = hsailProgram; - // We pull out all the kernel names in a very ugly manner - //! \todo check if this has been fixed in the compiler library if (!HSAILProgram_.empty()) { bool dynamicParallelism = false; // Find out the name of the kernel. Works for multiple kernels diff --git a/rocclr/runtime/device/gpu/gpuprogram.hpp b/rocclr/runtime/device/gpu/gpuprogram.hpp index 9b6e0a8d6c..6cc151b353 100644 --- a/rocclr/runtime/device/gpu/gpuprogram.hpp +++ b/rocclr/runtime/device/gpu/gpuprogram.hpp @@ -419,7 +419,10 @@ protected: amd::option::Options* options //!< compile options's object ); - aclType getNextCompilationStageFromBinary(); + /* \brief Return the next stage to compile from, based on sections in binary, + * also return completed stages in vector, which contains at least ACL_TYPE_DEFAULT + */ + aclType getNextCompilationStageFromBinary(std::vector& complete_stages); /*! \brief Compiles LLVM binary to FSAIL code (compiler backend: link+opt+codegen) *