From 6d277ef77ea8aedfcbd86d93c132ceeb78ac64ad Mon Sep 17 00:00:00 2001
From: foreman
Date: Thu, 3 Nov 2016 18:56:31 -0400
Subject: [PATCH] P4 to Git Change 1336353 by lmoriche@lmoriche_opencl_dev on
2016/11/03 18:47:50
SWDEV-105604 - [OCL-LC-PAL] OpenCL program manager for LC on PAL
- Finish the implementation of the program manager to support separare compilation and binary loading.
Affected files ...
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.cpp#22 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.hpp#13 edit
[ROCm/clr commit: 065133bbc0eb86522b4bbf7c5490d01354e26d26]
---
.../rocclr/runtime/device/pal/palprogram.cpp | 223 ++++++++++++++++++
.../rocclr/runtime/device/pal/palprogram.hpp | 17 ++
2 files changed, 240 insertions(+)
diff --git a/projects/clr/rocclr/runtime/device/pal/palprogram.cpp b/projects/clr/rocclr/runtime/device/pal/palprogram.cpp
index 7193825b1d..a358971aa7 100644
--- a/projects/clr/rocclr/runtime/device/pal/palprogram.cpp
+++ b/projects/clr/rocclr/runtime/device/pal/palprogram.cpp
@@ -1063,6 +1063,229 @@ GetKernelNamesCallback(
return HSA_STATUS_SUCCESS;
}
+aclType
+LightningProgram::getCompilationStagesFromBinary(
+ std::vector& completeStages,
+ bool& needOptionsCheck
+ )
+{
+ completeStages.clear();
+ aclType from = ACL_TYPE_DEFAULT;
+ needOptionsCheck = true;
+
+ 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_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;
+}
+
+
+aclType
+LightningProgram::getNextCompilationStageFromBinary(amd::option::Options* options)
+{
+ aclType continueCompileFrom = ACL_TYPE_DEFAULT;
+ binary_t binary = this->binary();
+
+ // If the binary already exists
+ if ((binary.first != NULL) && (binary.second > 0)) {
+ void *mem = const_cast(binary.first);
+
+ // save the current options
+ std::string sCurCompileOptions = compileOptions_;
+ std::string sCurLinkOptions = linkOptions_;
+ std::string sCurOptions = compileOptions_ + linkOptions_;
+
+ // Saving binary in the interface class,
+ // which also load compile & link options from binary
+ setBinary(static_cast(mem), binary.second);
+
+ // Calculate the next stage to compile from, based on sections in binaryElf_;
+ // No any validity checks here
+ std::vector completeStages;
+ bool needOptionsCheck = true;
+ continueCompileFrom = getCompilationStagesFromBinary(completeStages, needOptionsCheck);
+ if (!options || !needOptionsCheck) {
+ return continueCompileFrom;
+ }
+ bool recompile = false;
+ //! @todo Should we also check for ACL_TYPE_OPENCL & ACL_TYPE_LLVMIR_TEXT?
+ switch (continueCompileFrom) {
+ case ACL_TYPE_ISA: {
+ // Compare options loaded from binary with current ones, recompile if differ;
+ // If compile options are absent in binary, do not compare and recompile
+ if (compileOptions_.empty())
+ break;
+
+ std::string sBinOptions = compileOptions_ + linkOptions_;
+
+ compileOptions_ = sCurCompileOptions;
+ linkOptions_ = sCurLinkOptions;
+
+ amd::option::Options curOptions, binOptions;
+ if (!amd::option::parseAllOptions(sBinOptions, binOptions)) {
+ buildLog_ += binOptions.optionsLog();
+ LogError("Parsing compile options from binary failed.");
+ return ACL_TYPE_DEFAULT;
+ }
+ if (!amd::option::parseAllOptions(sCurOptions, curOptions)) {
+ buildLog_ += curOptions.optionsLog();
+ LogError("Parsing compile options failed.");
+ return ACL_TYPE_DEFAULT;
+ }
+ if (!curOptions.equals(binOptions)) {
+ recompile = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (recompile) {
+ while (!completeStages.empty()) {
+ continueCompileFrom = completeStages.back();
+ if (continueCompileFrom == ACL_TYPE_LLVMIR_BINARY ||
+ continueCompileFrom == ACL_TYPE_DEFAULT) {
+ break;
+ }
+ completeStages.pop_back();
+ }
+ }
+ }
+ return continueCompileFrom;
+}
+
+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::linkImpl(
+ const std::vector &inputPrograms,
+ amd::option::Options *options,
+ bool createLibrary)
+{
+ using namespace amd::opencl_driver;
+ std::auto_ptr C(newCompilerInstance());
+
+ std::vector inputs;
+ for (auto program : (const std::vector&)inputPrograms) {
+ if (program->llvmBinary_.empty()) {
+ if (program->clBinary() == NULL) {
+ buildLog_ += "Internal error: Input program not compiled!\n";
+ return false;
+ }
+
+ // 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)) {
+ buildLog_ += "Internal error: Setting input OCL binary failed!\n";
+ return false;
+ }
+ if (!program->clBinary()->loadLlvmBinary(program->llvmBinary_,
+ program->elfSectionType_)) {
+ buildLog_ += "Internal error: Failed loading compiled binary!\n";
+ return false;
+ }
+ }
+
+ if (program->elfSectionType_ != amd::OclElf::LLVMIR) {
+ buildLog_ += "Error: Input binary format is not supported\n.";
+ return false;
+ }
+
+ Data* input = C->NewBufferReference(DT_LLVM_BC,
+ (const char*) program->llvmBinary_.data(),
+ program->llvmBinary_.size());
+
+ if (!input) {
+ buildLog_ += "Internal error: Failed to open the compiled programs.\n";
+ return false;
+ }
+
+ // release elfIn() for the program
+ program->clBinary()->resetElfIn();
+
+ inputs.push_back(input);
+ }
+
+ // open the linked output
+ amd::opencl_driver::Buffer* output = C->NewBuffer(DT_LLVM_BC);
+
+ if (!output) {
+ buildLog_ += "Error: Failed to open the linked program.\n";
+ return false;
+ }
+
+ std::vector linkOptions;
+ bool ret = C->LinkLLVMBitcode(inputs, output, linkOptions);
+ buildLog_ += C->Output();
+ if (!ret) {
+ buildLog_ += "Error: Linking bitcode failed: linking source & IR libraries.\n";
+ return false;
+ }
+
+ llvmBinary_.assign(output->Buf().data(), output->Size());
+ elfSectionType_ = amd::OclElf::LLVMIR;
+
+
+ if (clBinary()->saveLLVMIR()) {
+ clBinary()->elfOut()->addSection(
+ amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
+ // store the original link options
+ clBinary()->storeLinkOptions(linkOptions_);
+ // store the original compile options
+ clBinary()->storeCompileOptions(compileOptions_);
+ }
+
+ // skip the rest if we are building an opencl library
+ if (createLibrary) {
+ setType(TYPE_LIBRARY);
+ if (!createBinary(options)) {
+ buildLog_ += "Internal error: creating OpenCL binary failed\n";
+ return false;
+ }
+ return true;
+ }
+
+ return linkImpl(options);
+}
+
bool
LightningProgram::linkImpl(amd::option::Options *options)
{
diff --git a/projects/clr/rocclr/runtime/device/pal/palprogram.hpp b/projects/clr/rocclr/runtime/device/pal/palprogram.hpp
index 160b222602..427275df40 100644
--- a/projects/clr/rocclr/runtime/device/pal/palprogram.hpp
+++ b/projects/clr/rocclr/runtime/device/pal/palprogram.hpp
@@ -302,6 +302,16 @@ public:
private:
virtual ~LightningProgram();
+ /* \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);
+
+ /* \brief Returns the next stage to compile from, based on sections and options in binary
+ */
+ aclType getNextCompilationStageFromBinary(amd::option::Options* options);
+
protected:
virtual bool compileImpl(
const std::string& sourceCode, //!< the program's source code
@@ -312,8 +322,15 @@ protected:
virtual bool linkImpl(amd::option::Options* options) override;
+ //! Link the device programs.
+ virtual bool linkImpl (const std::vector& inputPrograms,
+ amd::option::Options* options,
+ bool createLibrary) override;
+
bool setKernels(amd::option::Options *options, void* binary, size_t size);
+ virtual bool createBinary(amd::option::Options* options) override;
+
//! Return a new transient compiler instance.
static std::auto_ptr newCompilerInstance();