2022-02-03 18:28:56 -05:00
|
|
|
/* Copyright (c) 2008 - 2022 Advanced Micro Devices, Inc.
|
2020-02-04 09:26:14 -08:00
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
THE SOFTWARE. */
|
|
|
|
|
|
2021-12-01 08:17:44 -08:00
|
|
|
#include "platform/command.hpp"
|
|
|
|
|
#include "platform/commandqueue.hpp"
|
2018-09-18 18:53:08 -04:00
|
|
|
#include "platform/runtime.hpp"
|
|
|
|
|
#include "platform/program.hpp"
|
|
|
|
|
#include "platform/ndrange.hpp"
|
|
|
|
|
#include "devprogram.hpp"
|
|
|
|
|
#include "devkernel.hpp"
|
|
|
|
|
#include "utils/macros.hpp"
|
|
|
|
|
#include "utils/options.hpp"
|
2019-06-06 11:45:30 -04:00
|
|
|
#include "comgrctx.hpp"
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2019-11-26 12:30:05 -06:00
|
|
|
#include <algorithm>
|
2020-08-28 21:38:05 -07:00
|
|
|
#include <atomic>
|
2018-09-19 17:06:20 -04:00
|
|
|
#include <cstdio>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <iostream>
|
2020-12-03 16:36:58 +03:00
|
|
|
#include <iomanip>
|
2018-09-18 18:53:08 -04:00
|
|
|
#include <string>
|
|
|
|
|
#include <sstream>
|
2018-09-19 17:06:20 -04:00
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
|
|
#if defined(ATI_OS_LINUX)
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <libgen.h>
|
|
|
|
|
#endif // defined(ATI_OS_LINUX)
|
|
|
|
|
|
2024-06-06 18:40:49 +01:00
|
|
|
namespace amd::device {
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2019-07-09 16:10:34 -04:00
|
|
|
inline static std::vector<std::string> splitSpaceSeparatedString(const char* str) {
|
|
|
|
|
std::string s(str);
|
|
|
|
|
std::stringstream ss(s);
|
|
|
|
|
std::istream_iterator<std::string> beg(ss), end;
|
|
|
|
|
std::vector<std::string> vec(beg, end);
|
|
|
|
|
return vec;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
// ================================================================================================
|
2019-08-11 18:53:11 -04:00
|
|
|
Program::Program(amd::Device& device, amd::Program& owner)
|
2018-09-18 18:53:08 -04:00
|
|
|
: device_(device),
|
2019-08-11 18:53:11 -04:00
|
|
|
owner_(owner),
|
2018-09-18 18:53:08 -04:00
|
|
|
type_(TYPE_NONE),
|
2025-08-05 14:02:05 -07:00
|
|
|
initKernels_(),
|
|
|
|
|
finiKernels_(),
|
2018-09-18 18:53:08 -04:00
|
|
|
flags_(0),
|
|
|
|
|
clBinary_(nullptr),
|
|
|
|
|
llvmBinary_(),
|
2020-07-29 09:41:02 -04:00
|
|
|
elfSectionType_(amd::Elf::LLVMIR),
|
2018-09-18 18:53:08 -04:00
|
|
|
compileOptions_(),
|
|
|
|
|
linkOptions_(),
|
|
|
|
|
lastBuildOptionsArg_(),
|
|
|
|
|
buildStatus_(CL_BUILD_NONE),
|
|
|
|
|
buildError_(CL_SUCCESS),
|
|
|
|
|
globalVariableTotalSize_(0),
|
2025-10-23 11:21:49 -07:00
|
|
|
programOptions_(nullptr) {}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
|
|
|
|
// ================================================================================================
|
2018-09-25 17:47:26 -04:00
|
|
|
Program::~Program() {
|
|
|
|
|
clear();
|
2025-10-23 11:21:49 -07:00
|
|
|
for (auto const& kernelMeta : kernelMetadataMap_) {
|
|
|
|
|
amd::Comgr::destroy_metadata(kernelMeta.second);
|
2019-10-28 18:13:35 -04:00
|
|
|
}
|
2025-10-23 11:21:49 -07:00
|
|
|
amd::Comgr::destroy_metadata(metadata_);
|
2018-09-25 17:47:26 -04:00
|
|
|
}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
|
|
|
void Program::clear() {
|
2025-08-05 14:02:05 -07:00
|
|
|
initKernels_.clear();
|
|
|
|
|
finiKernels_.clear();
|
2018-09-18 18:53:08 -04:00
|
|
|
// Destroy all device kernels
|
|
|
|
|
for (const auto& it : kernels_) {
|
|
|
|
|
delete it.second;
|
|
|
|
|
}
|
|
|
|
|
kernels_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-19 17:06:20 -04:00
|
|
|
// ================================================================================================
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2019-03-14 17:09:48 -04:00
|
|
|
// If buildLog is not null, and dataSet contains a log object, extract the
|
|
|
|
|
// first log data object from dataSet and process it with
|
|
|
|
|
// extractByteCodeBinary.
|
2019-07-01 16:23:41 -04:00
|
|
|
void Program::extractBuildLog(amd_comgr_data_set_t dataSet) {
|
2019-03-14 17:09:48 -04:00
|
|
|
amd_comgr_status_t status = AMD_COMGR_STATUS_SUCCESS;
|
2019-07-01 16:23:41 -04:00
|
|
|
size_t count;
|
|
|
|
|
status = amd::Comgr::action_data_count(dataSet, AMD_COMGR_DATA_KIND_LOG, &count);
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS && count > 0) {
|
|
|
|
|
char* logData = nullptr;
|
|
|
|
|
size_t logSize;
|
|
|
|
|
status = extractByteCodeBinary(dataSet, AMD_COMGR_DATA_KIND_LOG, "", &logData, &logSize);
|
|
|
|
|
buildLog_ += logData;
|
2019-10-24 16:29:54 -04:00
|
|
|
delete[] logData;
|
2019-03-14 17:09:48 -04:00
|
|
|
}
|
2019-03-22 20:13:50 -04:00
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "Warning: extracting build log failed.\n";
|
|
|
|
|
}
|
2019-03-14 17:09:48 -04:00
|
|
|
}
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
// Extract the byte code binary from the data set. The binary will be saved to an output
|
|
|
|
|
// file if the file name is provided. If buffer pointer, outBinary, is provided, the
|
|
|
|
|
// binary will be passed back to the caller.
|
|
|
|
|
//
|
2019-02-15 12:26:57 -05:00
|
|
|
amd_comgr_status_t Program::extractByteCodeBinary(const amd_comgr_data_set_t inDataSet,
|
|
|
|
|
const amd_comgr_data_kind_t dataKind,
|
|
|
|
|
const std::string& outFileName, char* outBinary[],
|
|
|
|
|
size_t* outSize) {
|
2018-11-05 14:24:49 -05:00
|
|
|
amd_comgr_data_t binaryData;
|
|
|
|
|
|
2019-10-25 18:17:54 -04:00
|
|
|
amd_comgr_status_t status = amd::Comgr::action_data_get_data(inDataSet, dataKind, 0, &binaryData);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-11-22 14:04:51 -05:00
|
|
|
size_t binarySize = 0;
|
2018-11-05 14:24:49 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::get_data(binaryData, &binarySize, NULL);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-15 12:26:57 -05:00
|
|
|
size_t bufSize = (dataKind == AMD_COMGR_DATA_KIND_LOG) ? binarySize + 1 : binarySize;
|
|
|
|
|
|
2019-10-24 16:29:54 -04:00
|
|
|
char* binary = new char[bufSize];
|
2018-11-05 14:24:49 -05:00
|
|
|
if (binary == nullptr) {
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::release_data(binaryData);
|
2019-02-15 12:26:57 -05:00
|
|
|
return AMD_COMGR_STATUS_ERROR;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::get_data(binaryData, &binarySize, binary);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-15 12:26:57 -05:00
|
|
|
if (dataKind == AMD_COMGR_DATA_KIND_LOG) {
|
|
|
|
|
binary[binarySize] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::release_data(binaryData);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
2019-10-24 16:29:54 -04:00
|
|
|
delete[] binary;
|
2019-02-15 12:26:57 -05:00
|
|
|
return status;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save the binary to the file as output file name is specified
|
|
|
|
|
if (!outFileName.empty()) {
|
2019-08-14 12:37:39 -04:00
|
|
|
std::ofstream f(outFileName.c_str(), std::ios::trunc | std::ios::binary);
|
2019-05-31 10:55:14 -04:00
|
|
|
if (f.is_open()) {
|
|
|
|
|
f.write(binary, binarySize);
|
|
|
|
|
f.close();
|
|
|
|
|
} else {
|
|
|
|
|
buildLog_ += "Warning: opening the file to dump the code failed.\n";
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outBinary != nullptr) {
|
|
|
|
|
// Pass the dump binary and its size back to the caller
|
|
|
|
|
*outBinary = binary;
|
|
|
|
|
*outSize = binarySize;
|
|
|
|
|
} else {
|
2019-10-24 16:29:54 -04:00
|
|
|
delete[] binary;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
2019-02-15 12:26:57 -05:00
|
|
|
return AMD_COMGR_STATUS_SUCCESS;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amd_comgr_status_t Program::addCodeObjData(const char* source, const size_t size,
|
|
|
|
|
const amd_comgr_data_kind_t type, const char* name,
|
|
|
|
|
amd_comgr_data_set_t* dataSet) {
|
|
|
|
|
amd_comgr_data_t data;
|
|
|
|
|
amd_comgr_status_t status;
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::create_data(type, &data);
|
2018-11-05 14:24:49 -05:00
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::set_data(data, size, source);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if ((name != nullptr) && (status == AMD_COMGR_STATUS_SUCCESS)) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::set_data_name(data, name);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((dataSet != nullptr) && (status == AMD_COMGR_STATUS_SUCCESS)) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::data_set_add(*dataSet, data);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::release_data(data);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-14 18:01:05 +01:00
|
|
|
static amd_comgr_language_t getCOMGRLanguage(bool isHIP, const amd::option::Options& amdOptions) {
|
|
|
|
|
if (isHIP) {
|
|
|
|
|
return AMD_COMGR_LANGUAGE_HIP;
|
2019-11-25 17:55:47 -06:00
|
|
|
} else {
|
2023-03-14 18:01:05 +01:00
|
|
|
const char* clStd = amdOptions.oVariables->CLStd;
|
2019-11-25 17:55:47 -06:00
|
|
|
uint clcStd = (clStd[2] - '0') * 100 + (clStd[4] - '0') * 10;
|
|
|
|
|
|
2023-03-14 18:01:05 +01:00
|
|
|
switch (clcStd) {
|
|
|
|
|
case 100:
|
|
|
|
|
case 110:
|
|
|
|
|
case 120:
|
|
|
|
|
return AMD_COMGR_LANGUAGE_OPENCL_1_2;
|
|
|
|
|
case 200:
|
|
|
|
|
return AMD_COMGR_LANGUAGE_OPENCL_2_0;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
2023-03-14 18:01:05 +01:00
|
|
|
|
|
|
|
|
DevLogPrintfError("Cannot set Language version for %s \n", amdOptions.oVariables->CLStd);
|
|
|
|
|
return AMD_COMGR_LANGUAGE_NONE;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
amd_comgr_status_t Program::createAction(const amd_comgr_language_t oclver,
|
2019-06-14 07:15:00 -04:00
|
|
|
const std::vector<std::string>& options,
|
2018-12-13 20:36:31 -05:00
|
|
|
amd_comgr_action_info_t* action, bool* hasAction) {
|
|
|
|
|
*hasAction = false;
|
2018-12-13 15:22:06 -05:00
|
|
|
amd_comgr_status_t status = amd::Comgr::create_action_info(action);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
*hasAction = true;
|
|
|
|
|
if (oclver != AMD_COMGR_LANGUAGE_NONE) {
|
|
|
|
|
status = amd::Comgr::action_info_set_language(*action, oclver);
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2020-07-15 11:17:11 -04:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2021-01-10 12:17:06 +00:00
|
|
|
status = amd::Comgr::action_info_set_isa_name(*action, device().isa().isaName().c_str());
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-06-14 07:15:00 -04:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
std::vector<const char*> optionsArgv;
|
|
|
|
|
optionsArgv.reserve(options.size());
|
|
|
|
|
for (auto& option : options) {
|
|
|
|
|
optionsArgv.push_back(option.c_str());
|
|
|
|
|
}
|
|
|
|
|
status =
|
|
|
|
|
amd::Comgr::action_info_set_option_list(*action, optionsArgv.data(), optionsArgv.size());
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-07-01 16:23:41 -04:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
status = amd::Comgr::action_info_set_logging(*action, true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Program::linkLLVMBitcode(const amd_comgr_data_set_t inputs,
|
2023-01-12 17:46:39 +01:00
|
|
|
const std::vector<std::string>& options,
|
2018-11-05 14:24:49 -05:00
|
|
|
amd::option::Options* amdOptions, amd_comgr_data_set_t* output,
|
2023-11-09 13:17:06 -08:00
|
|
|
char* binaryData[], size_t* binarySize) {
|
2023-03-14 18:01:05 +01:00
|
|
|
amd_comgr_language_t langver = getCOMGRLanguage(isHIP(), *amdOptions);
|
2019-11-25 17:55:47 -06:00
|
|
|
if (langver == AMD_COMGR_LANGUAGE_NONE) {
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the action for linking
|
|
|
|
|
amd_comgr_action_info_t action;
|
2018-12-13 20:36:31 -05:00
|
|
|
bool hasAction = false;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2020-07-15 11:17:11 -04:00
|
|
|
amd_comgr_status_t status = createAction(langver, options, &action, &hasAction);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2023-09-06 17:40:14 -04:00
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_LINK_BC_TO_BC, action, inputs, *output);
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(*output);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
std::string dumpFileName;
|
2023-01-12 17:46:39 +01:00
|
|
|
if (amdOptions->isDumpFlagSet(amd::option::DUMP_BC_LINKED)) {
|
2018-11-05 14:24:49 -05:00
|
|
|
dumpFileName = amdOptions->getDumpFileName("_linked.bc");
|
|
|
|
|
}
|
2019-02-15 12:26:57 -05:00
|
|
|
status = extractByteCodeBinary(*output, AMD_COMGR_DATA_KIND_BC, dumpFileName, binaryData,
|
|
|
|
|
binarySize);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
if (hasAction) {
|
|
|
|
|
amd::Comgr::destroy_action_info(action);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
return (status == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
bool Program::compileToLLVMBitcode(const amd_comgr_data_set_t compileInputs,
|
2020-07-15 11:17:11 -04:00
|
|
|
const std::vector<std::string>& options,
|
|
|
|
|
amd::option::Options* amdOptions, char* binaryData[],
|
2023-11-09 13:17:06 -08:00
|
|
|
size_t* binarySize, const bool link_dev_libs) {
|
2023-03-14 18:01:05 +01:00
|
|
|
amd_comgr_language_t langver = getCOMGRLanguage(isHIP(), *amdOptions);
|
2019-11-25 17:55:47 -06:00
|
|
|
if (langver == AMD_COMGR_LANGUAGE_NONE) {
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the output data set
|
2021-05-14 15:00:53 -04:00
|
|
|
amd_comgr_action_info_t action{};
|
|
|
|
|
amd_comgr_data_set_t output{};
|
|
|
|
|
amd_comgr_data_set_t dataSetPCH{};
|
2019-11-25 17:55:47 -06:00
|
|
|
amd_comgr_data_set_t input = compileInputs;
|
|
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
bool hasAction = false;
|
2019-03-22 20:13:50 -04:00
|
|
|
bool hasOutput = false;
|
|
|
|
|
bool hasDataSetPCH = false;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2020-07-15 11:17:11 -04:00
|
|
|
amd_comgr_status_t status = createAction(langver, options, &action, &hasAction);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::create_data_set(&output);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Adding Precompiled Headers
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2019-03-22 20:13:50 -04:00
|
|
|
hasOutput = true;
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::create_data_set(&dataSetPCH);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
// Preprocess the source
|
|
|
|
|
// FIXME: This must happen before the precompiled headers are added, as they
|
|
|
|
|
// do not embed the source text of the header, and so reference paths in the
|
|
|
|
|
// filesystem which do not exist at runtime.
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
hasDataSetPCH = true;
|
|
|
|
|
|
|
|
|
|
if (amdOptions->isDumpFlagSet(amd::option::DUMP_I)) {
|
|
|
|
|
amd_comgr_data_set_t dataSetPreprocessor;
|
|
|
|
|
bool hasDataSetPreprocessor = false;
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::create_data_set(&dataSetPreprocessor);
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
hasDataSetPreprocessor = true;
|
|
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_SOURCE_TO_PREPROCESSOR, action, input,
|
2019-11-25 17:55:47 -06:00
|
|
|
dataSetPreprocessor);
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(dataSetPreprocessor);
|
2019-03-22 20:13:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
std::string outFileName = amdOptions->getDumpFileName(".i");
|
|
|
|
|
status =
|
|
|
|
|
extractByteCodeBinary(dataSetPreprocessor, AMD_COMGR_DATA_KIND_SOURCE, outFileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasDataSetPreprocessor) {
|
|
|
|
|
amd::Comgr::destroy_data_set(dataSetPreprocessor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
if (!isHIP()) {
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_ADD_PRECOMPILED_HEADERS, action, input,
|
|
|
|
|
dataSetPCH);
|
|
|
|
|
extractBuildLog(dataSetPCH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set input for the next stage
|
|
|
|
|
input = dataSetPCH;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
// Compiling the source codes with precompiled headers or directly compileInputs
|
2018-11-05 14:24:49 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2023-11-09 13:17:06 -08:00
|
|
|
if (link_dev_libs) {
|
|
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_COMPILE_SOURCE_WITH_DEVICE_LIBS_TO_BC, action,
|
|
|
|
|
input, output);
|
|
|
|
|
} else {
|
|
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_COMPILE_SOURCE_TO_BC, action, input, output);
|
|
|
|
|
}
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(output);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
std::string outFileName;
|
2022-10-21 14:04:47 +00:00
|
|
|
if (amdOptions->isDumpFlagSet(amd::option::DUMP_BC_OPTIMIZED)) {
|
|
|
|
|
outFileName = amdOptions->getDumpFileName("_optimized.bc");
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
2019-02-15 12:26:57 -05:00
|
|
|
status =
|
|
|
|
|
extractByteCodeBinary(output, AMD_COMGR_DATA_KIND_BC, outFileName, binaryData, binarySize);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
if (hasAction) {
|
|
|
|
|
amd::Comgr::destroy_action_info(action);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
if (hasDataSetPCH) {
|
2018-12-13 20:36:31 -05:00
|
|
|
amd::Comgr::destroy_data_set(dataSetPCH);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
if (hasOutput) {
|
2018-12-13 20:36:31 -05:00
|
|
|
amd::Comgr::destroy_data_set(output);
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
return (status == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create an executable from an input data set. To generate the executable,
|
|
|
|
|
// the input data set is converted to relocatable code, then executable binary.
|
|
|
|
|
// If assembly code is required, the input data set is converted to assembly.
|
|
|
|
|
bool Program::compileAndLinkExecutable(const amd_comgr_data_set_t inputs,
|
2020-07-15 11:17:11 -04:00
|
|
|
const std::vector<std::string>& options,
|
|
|
|
|
amd::option::Options* amdOptions, char* executable[],
|
2023-09-11 15:22:51 -04:00
|
|
|
size_t* executableSize, file_type_t continueCompileFrom) {
|
2018-11-05 14:24:49 -05:00
|
|
|
// create the linked output
|
|
|
|
|
amd_comgr_action_info_t action;
|
|
|
|
|
amd_comgr_data_set_t output;
|
|
|
|
|
amd_comgr_data_set_t relocatableData;
|
2018-12-13 20:36:31 -05:00
|
|
|
bool hasAction = false;
|
2019-03-22 20:13:50 -04:00
|
|
|
bool hasOutput = false;
|
|
|
|
|
bool hasRelocatableData = false;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2020-07-15 11:17:11 -04:00
|
|
|
amd_comgr_status_t status = createAction(AMD_COMGR_LANGUAGE_NONE, options, &action, &hasAction);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::create_data_set(&output);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2019-03-22 20:13:50 -04:00
|
|
|
hasOutput = true;
|
2018-12-13 20:36:31 -05:00
|
|
|
|
2021-08-12 05:48:07 -07:00
|
|
|
if ((amdOptions->isDumpFlagSet(amd::option::DUMP_ISA)) ||
|
|
|
|
|
(isHIP() && amdOptions->origOptionStr.find("-save-temps") != std::string::npos)) {
|
2018-12-13 20:36:31 -05:00
|
|
|
// create the assembly data set
|
|
|
|
|
amd_comgr_data_set_t assemblyData;
|
2019-03-22 20:13:50 -04:00
|
|
|
bool hasAssemblyData = false;
|
2018-12-13 20:36:31 -05:00
|
|
|
|
|
|
|
|
status = amd::Comgr::create_data_set(&assemblyData);
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2019-03-22 20:13:50 -04:00
|
|
|
hasAssemblyData = true;
|
2018-12-13 20:36:31 -05:00
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_CODEGEN_BC_TO_ASSEMBLY, action, inputs,
|
|
|
|
|
assemblyData);
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(assemblyData);
|
2018-12-13 20:36:31 -05:00
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
// dump the ISA
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
std::string dumpIsaName = amdOptions->getDumpFileName(".s");
|
2019-02-15 12:26:57 -05:00
|
|
|
status = extractByteCodeBinary(assemblyData, AMD_COMGR_DATA_KIND_SOURCE, dumpIsaName);
|
2018-12-13 20:36:31 -05:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
if (hasAssemblyData) {
|
2018-12-13 20:36:31 -05:00
|
|
|
amd::Comgr::destroy_data_set(assemblyData);
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-10 00:07:13 +00:00
|
|
|
// Create the relocatable data set
|
2018-11-05 14:24:49 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2018-12-13 15:22:06 -05:00
|
|
|
status = amd::Comgr::create_data_set(&relocatableData);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2019-03-22 20:13:50 -04:00
|
|
|
hasRelocatableData = true;
|
2023-09-11 15:22:51 -04:00
|
|
|
amd_comgr_action_kind_t kind = (continueCompileFrom == FILE_TYPE_ASM_TEXT)
|
|
|
|
|
? AMD_COMGR_ACTION_ASSEMBLE_SOURCE_TO_RELOCATABLE
|
|
|
|
|
: AMD_COMGR_ACTION_CODEGEN_BC_TO_RELOCATABLE;
|
|
|
|
|
status = amd::Comgr::do_action(kind, action, inputs, relocatableData);
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(relocatableData);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create executable from the relocatable data set
|
2020-02-12 17:34:20 -05:00
|
|
|
amd::Comgr::action_info_set_option_list(action, nullptr, 0);
|
2018-11-05 14:24:49 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2023-09-11 15:22:51 -04:00
|
|
|
status = amd::Comgr::do_action(AMD_COMGR_ACTION_LINK_RELOCATABLE_TO_EXECUTABLE, action,
|
|
|
|
|
relocatableData, output);
|
2019-07-01 16:23:41 -04:00
|
|
|
extractBuildLog(output);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
// Extract the executable binary
|
|
|
|
|
std::string outFileName;
|
|
|
|
|
if (amdOptions->isDumpFlagSet(amd::option::DUMP_O)) {
|
|
|
|
|
outFileName = amdOptions->getDumpFileName(".so");
|
|
|
|
|
}
|
2019-02-15 12:26:57 -05:00
|
|
|
status = extractByteCodeBinary(output, AMD_COMGR_DATA_KIND_EXECUTABLE, outFileName, executable,
|
|
|
|
|
executableSize);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 20:36:31 -05:00
|
|
|
if (hasAction) {
|
|
|
|
|
amd::Comgr::destroy_action_info(action);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
if (hasRelocatableData) {
|
2018-12-13 20:36:31 -05:00
|
|
|
amd::Comgr::destroy_data_set(relocatableData);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 20:13:50 -04:00
|
|
|
if (hasOutput) {
|
2018-12-13 20:36:31 -05:00
|
|
|
amd::Comgr::destroy_data_set(output);
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
return (status == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 16:36:58 +03:00
|
|
|
static std::size_t getOCLSourceHash(const std::string& sourceCode) {
|
|
|
|
|
return std::hash<std::string>()(sourceCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::size_t getOCLOptionsHash(const amd::option::Options& options) {
|
|
|
|
|
std::string opts;
|
|
|
|
|
for (const std::string& S : options.clangOptions) opts.append(S);
|
|
|
|
|
return std::hash<std::string>()(opts);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
bool Program::compileImpl(const std::string& sourceCode,
|
|
|
|
|
const std::vector<const std::string*>& headers,
|
|
|
|
|
const char** headerIncludeNames, amd::option::Options* options) {
|
2018-11-05 14:24:49 -05:00
|
|
|
const char* xLang = options->oVariables->XLang;
|
|
|
|
|
if (xLang != nullptr) {
|
|
|
|
|
if (strcmp(xLang, "asm") == 0) {
|
2020-07-29 09:41:02 -04:00
|
|
|
clBinary()->elfOut()->addSection(amd::Elf::SOURCE, sourceCode.data(), sourceCode.size());
|
2018-11-05 14:24:49 -05:00
|
|
|
return true;
|
|
|
|
|
} else if (!strcmp(xLang, "cl")) {
|
|
|
|
|
buildLog_ += "Unsupported language: \"" + std::string(xLang) + "\".\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add CL source to input data set
|
|
|
|
|
amd_comgr_data_set_t inputs;
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
if (amd::Comgr::create_data_set(&inputs) != AMD_COMGR_STATUS_SUCCESS) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: COMGR fails to create output buffer for LLVM bitcode.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (addCodeObjData(sourceCode.c_str(), sourceCode.length(), AMD_COMGR_DATA_KIND_SOURCE,
|
2019-11-25 17:55:47 -06:00
|
|
|
"CompileSource", &inputs) != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "Error: COMGR fails to create data from source.\n";
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
std::vector<std::string> driverOptions;
|
2018-11-05 14:24:49 -05:00
|
|
|
// Set the -O#
|
|
|
|
|
std::ostringstream optLevel;
|
2019-06-14 07:15:00 -04:00
|
|
|
optLevel << "-O" << options->oVariables->OptLevel;
|
|
|
|
|
driverOptions.push_back(optLevel.str());
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
if (!isHIP()) {
|
|
|
|
|
driverOptions.insert(driverOptions.end(), options->clangOptions.begin(),
|
|
|
|
|
options->clangOptions.end());
|
|
|
|
|
// TODO: Can this be fixed at the source? options->llvmOptions is a flat
|
|
|
|
|
// string, but should really be a vector of strings.
|
|
|
|
|
std::vector<std::string> splitLlvmOptions =
|
|
|
|
|
splitSpaceSeparatedString(options->llvmOptions.c_str());
|
|
|
|
|
driverOptions.insert(driverOptions.end(), splitLlvmOptions.begin(), splitLlvmOptions.end());
|
|
|
|
|
}
|
2019-06-14 07:15:00 -04:00
|
|
|
|
|
|
|
|
std::vector<std::string> processedOptions = ProcessOptions(options);
|
|
|
|
|
driverOptions.insert(driverOptions.end(), processedOptions.begin(), processedOptions.end());
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
// Set whole program mode
|
2023-06-09 13:33:57 -04:00
|
|
|
driverOptions.push_back("-mllvm");
|
|
|
|
|
driverOptions.push_back("-amdgpu-prelink");
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2019-01-07 18:02:10 -05:00
|
|
|
if (!device().settings().enableWgpMode_) {
|
2019-06-14 07:15:00 -04:00
|
|
|
driverOptions.push_back("-mcumode");
|
2019-01-07 18:02:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device().settings().lcWavefrontSize64_) {
|
2019-06-14 07:15:00 -04:00
|
|
|
driverOptions.push_back("-mwavefrontsize64");
|
2019-01-07 18:02:10 -05:00
|
|
|
}
|
2022-04-11 10:50:02 -04:00
|
|
|
driverOptions.push_back("-mcode-object-version=" +
|
|
|
|
|
std::to_string(options->oVariables->LCCodeObjectVersion));
|
2023-11-30 21:54:34 +00:00
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
// Iterate through each source code and dump it into tmp
|
|
|
|
|
std::fstream f;
|
|
|
|
|
std::vector<std::string> headerFileNames(headers.size());
|
|
|
|
|
|
|
|
|
|
if (!headers.empty()) {
|
|
|
|
|
for (size_t i = 0; i < headers.size(); ++i) {
|
2018-12-17 14:02:16 -05:00
|
|
|
std::string headerIncludeName(headerIncludeNames[i]);
|
|
|
|
|
// replace / in path with current os's file separator
|
|
|
|
|
if (amd::Os::fileSeparator() != '/') {
|
|
|
|
|
for (auto& it : headerIncludeName) {
|
|
|
|
|
if (it == '/') it = amd::Os::fileSeparator();
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
if (addCodeObjData(headers[i]->c_str(), headers[i]->length(), AMD_COMGR_DATA_KIND_INCLUDE,
|
2018-12-17 14:02:16 -05:00
|
|
|
headerIncludeName.c_str(), &inputs) != AMD_COMGR_STATUS_SUCCESS) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: COMGR fails to add headers into inputs.\n";
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
if (!isHIP() && options->isDumpFlagSet(amd::option::DUMP_CL)) {
|
2019-06-14 07:15:00 -04:00
|
|
|
std::ostringstream driverOptionsOStrStr;
|
|
|
|
|
std::copy(driverOptions.begin(), driverOptions.end(),
|
|
|
|
|
std::ostream_iterator<std::string>(driverOptionsOStrStr, " "));
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
std::ofstream f(options->getDumpFileName(".cl").c_str(), std::ios::trunc);
|
|
|
|
|
if (f.is_open()) {
|
2020-12-03 16:36:58 +03:00
|
|
|
auto srcHash = getOCLSourceHash(sourceCode);
|
|
|
|
|
auto optHash = getOCLOptionsHash(*options);
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
f << "/* Compiler options:\n"
|
|
|
|
|
"-c -emit-llvm -target amdgcn-amd-amdhsa -x cl "
|
2019-06-14 07:15:00 -04:00
|
|
|
<< driverOptionsOStrStr.str() << " -include opencl-c.h "
|
2020-12-03 16:36:58 +03:00
|
|
|
<< "\nHash to override:"
|
|
|
|
|
<< "\n Source: 0x" << std::setbase(16) << srcHash << "\n Source + clang options: 0x"
|
|
|
|
|
<< (srcHash ^ optHash) << "\n*/\n\n"
|
2018-11-05 14:24:49 -05:00
|
|
|
<< sourceCode;
|
|
|
|
|
f.close();
|
|
|
|
|
} else {
|
|
|
|
|
buildLog_ += "Warning: opening the file to dump the OpenCL source failed.\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 08:21:10 -05:00
|
|
|
// Append Options provided by user to driver options
|
|
|
|
|
if (isHIP()) {
|
|
|
|
|
if (options->origOptionStr.size()) {
|
|
|
|
|
std::istringstream userOptions{options->origOptionStr};
|
|
|
|
|
std::copy(std::istream_iterator<std::string>(userOptions),
|
|
|
|
|
std::istream_iterator<std::string>(), std::back_inserter(driverOptions));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
// Compile source to IR
|
|
|
|
|
char* binaryData = nullptr;
|
|
|
|
|
size_t binarySize = 0;
|
|
|
|
|
bool ret = compileToLLVMBitcode(inputs, driverOptions, options, &binaryData, &binarySize);
|
|
|
|
|
if (ret) {
|
|
|
|
|
llvmBinary_.assign(binaryData, binarySize);
|
2019-10-24 16:29:54 -04:00
|
|
|
// Destroy the original LLVM binary, received after compilation
|
|
|
|
|
delete[] binaryData;
|
|
|
|
|
|
2020-07-29 09:41:02 -04:00
|
|
|
elfSectionType_ = amd::Elf::LLVMIR;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (clBinary()->saveSOURCE()) {
|
2020-07-29 09:41:02 -04:00
|
|
|
clBinary()->elfOut()->addSection(amd::Elf::SOURCE, sourceCode.data(), sourceCode.size());
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
if (clBinary()->saveLLVMIR()) {
|
2020-07-29 09:41:02 -04:00
|
|
|
clBinary()->elfOut()->addSection(amd::Elf::LLVMIR, llvmBinary_.data(), llvmBinary_.size());
|
2025-10-23 11:21:49 -07:00
|
|
|
compileOptions_.clear();
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
} else {
|
2021-08-19 11:22:55 -07:00
|
|
|
buildLog_ += "Error: Failed to compile source (from CL or HIP source to LLVM IR).\n";
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return ret;
|
2018-09-27 13:10:59 -04:00
|
|
|
}
|
|
|
|
|
|
2018-09-27 18:15:24 -04:00
|
|
|
// ================================================================================================
|
2025-10-23 11:21:49 -07:00
|
|
|
bool Program::linkImpl(const std::vector<Program*>& inputPrograms, amd::option::Options* options,
|
|
|
|
|
bool createLibrary) {
|
2018-11-05 14:24:49 -05:00
|
|
|
amd_comgr_data_set_t inputs;
|
|
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
if (amd::Comgr::create_data_set(&inputs) != AMD_COMGR_STATUS_SUCCESS) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: COMGR fails to create data set.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t idx = 0;
|
|
|
|
|
for (auto program : inputPrograms) {
|
|
|
|
|
bool result = true;
|
|
|
|
|
if (program->llvmBinary_.empty()) {
|
|
|
|
|
result = (program->clBinary() != nullptr);
|
|
|
|
|
if (result) {
|
|
|
|
|
// 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().
|
|
|
|
|
result = program->clBinary()->setElfIn();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
|
result =
|
|
|
|
|
program->clBinary()->loadLlvmBinary(program->llvmBinary_, program->elfSectionType_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result) {
|
2020-07-29 09:41:02 -04:00
|
|
|
result = (program->elfSectionType_ == amd::Elf::LLVMIR);
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result) {
|
2019-01-02 14:22:04 -05:00
|
|
|
std::string llvmName = "LLVM Binary " + std::to_string(idx);
|
2018-11-05 14:24:49 -05:00
|
|
|
result = (addCodeObjData(program->llvmBinary_.data(), program->llvmBinary_.size(),
|
2019-01-02 14:22:04 -05:00
|
|
|
AMD_COMGR_DATA_KIND_BC, llvmName.c_str(),
|
2018-11-05 14:24:49 -05:00
|
|
|
&inputs) == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result) {
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: Linking bitcode failed: failing to generate LLVM binary.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
|
|
|
|
|
|
// release elfIn() for the program
|
|
|
|
|
program->clBinary()->resetElfIn();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the linked output
|
|
|
|
|
amd_comgr_data_set_t output;
|
2018-12-13 15:22:06 -05:00
|
|
|
if (amd::Comgr::create_data_set(&output) != AMD_COMGR_STATUS_SUCCESS) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: COMGR fails to create output buffer for LLVM bitcode.\n";
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: The options parameter is also used to identy cached code object.
|
|
|
|
|
// This parameter should not contain any dyanamically generated filename.
|
|
|
|
|
char* binaryData = nullptr;
|
|
|
|
|
size_t binarySize = 0;
|
2019-06-14 07:15:00 -04:00
|
|
|
std::vector<std::string> linkOptions;
|
2023-01-12 17:46:39 +01:00
|
|
|
bool ret = linkLLVMBitcode(inputs, linkOptions, options, &output, &binaryData, &binarySize);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(output);
|
|
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
|
buildLog_ += "Error: Linking bitcode failed: linking source & IR libraries.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvmBinary_.assign(binaryData, binarySize);
|
2019-10-24 16:29:54 -04:00
|
|
|
|
|
|
|
|
// Destroy llvm binary, received after compilation
|
|
|
|
|
delete[] binaryData;
|
|
|
|
|
|
2020-07-29 09:41:02 -04:00
|
|
|
elfSectionType_ = amd::Elf::LLVMIR;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (clBinary()->saveLLVMIR()) {
|
2020-07-29 09:41:02 -04:00
|
|
|
clBinary()->elfOut()->addSection(amd::Elf::LLVMIR, llvmBinary_.data(), llvmBinary_.size());
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
2018-09-27 13:10:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2019-05-27 20:11:08 -04:00
|
|
|
static void dumpCodeObject(const std::string& image) {
|
|
|
|
|
char fname[30];
|
|
|
|
|
static std::atomic<int> index;
|
|
|
|
|
sprintf(fname, "_code_object%04d.o", index++);
|
2025-09-04 10:08:41 -07:00
|
|
|
ClPrint(amd::LOG_DETAIL_DEBUG, amd::LOG_CODE, "Code object saved in %s\n", fname);
|
2019-05-27 20:11:08 -04:00
|
|
|
std::ofstream ofs;
|
|
|
|
|
ofs.open(fname, std::ios::binary);
|
|
|
|
|
ofs << image;
|
|
|
|
|
ofs.close();
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-27 18:15:24 -04:00
|
|
|
// ================================================================================================
|
2025-10-23 11:21:49 -07:00
|
|
|
bool Program::linkImpl(amd::option::Options* options) {
|
2021-04-12 14:55:06 -04:00
|
|
|
file_type_t continueCompileFrom = FILE_TYPE_LLVMIR_BINARY;
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-11-22 14:04:51 -05:00
|
|
|
internal_ = (compileOptions_.find("-cl-internal-kernel") != std::string::npos) ? true : false;
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
amd_comgr_data_set_t inputs;
|
2018-12-13 15:22:06 -05:00
|
|
|
if (amd::Comgr::create_data_set(&inputs) != AMD_COMGR_STATUS_SUCCESS) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: COMGR fails to create data set for linking.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-06 17:40:14 -04:00
|
|
|
bool bLinkLLVMBitcode = true;
|
2018-11-05 14:24:49 -05:00
|
|
|
if (llvmBinary_.empty()) {
|
|
|
|
|
continueCompileFrom = getNextCompilationStageFromBinary(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (continueCompileFrom) {
|
2021-04-12 14:55:06 -04:00
|
|
|
case FILE_TYPE_CG:
|
|
|
|
|
case FILE_TYPE_LLVMIR_BINARY: {
|
2018-11-05 14:24:49 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2021-04-12 14:55:06 -04:00
|
|
|
case FILE_TYPE_ASM_TEXT: {
|
2018-11-05 14:24:49 -05:00
|
|
|
char* section;
|
|
|
|
|
size_t sz;
|
2020-07-29 09:41:02 -04:00
|
|
|
clBinary()->elfOut()->getSection(amd::Elf::SOURCE, §ion, &sz);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (addCodeObjData(section, sz, AMD_COMGR_DATA_KIND_BC, "Assembly Text", &inputs) !=
|
|
|
|
|
AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "Error: COMGR fails to create assembly input.\n";
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-06 17:40:14 -04:00
|
|
|
bLinkLLVMBitcode = false;
|
2018-11-05 14:24:49 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2021-04-12 14:55:06 -04:00
|
|
|
case FILE_TYPE_ISA: {
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
binary_t isaBinary = binary();
|
2019-08-13 16:58:45 -04:00
|
|
|
if (GPU_DUMP_CODE_OBJECT) {
|
2019-05-27 20:11:08 -04:00
|
|
|
dumpCodeObject(std::string{(const char*)isaBinary.first, isaBinary.second});
|
|
|
|
|
}
|
2021-03-26 15:29:05 -04:00
|
|
|
|
|
|
|
|
if (!createKernels(const_cast<void*>(isaBinary.first), isaBinary.second,
|
|
|
|
|
options->oVariables->UniformWorkGroupSize, internal_)) {
|
|
|
|
|
buildLog_ += "Error: Cannot create kernels.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2018-11-05 14:24:49 -05:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
buildLog_ += "Error while Codegen phase: the binary is incomplete \n";
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-06 17:40:14 -04:00
|
|
|
// call LinkLLVMBitcode
|
|
|
|
|
if (bLinkLLVMBitcode) {
|
|
|
|
|
// open the bitcode libraries
|
|
|
|
|
std::vector<std::string> linkOptions;
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->FP32RoundDivideSqrt) {
|
|
|
|
|
linkOptions.push_back("correctly_rounded_sqrt");
|
|
|
|
|
}
|
|
|
|
|
if (options->oVariables->FiniteMathOnly || options->oVariables->FastRelaxedMath) {
|
|
|
|
|
linkOptions.push_back("finite_only");
|
|
|
|
|
}
|
|
|
|
|
if (options->oVariables->UnsafeMathOpt || options->oVariables->FastRelaxedMath) {
|
|
|
|
|
linkOptions.push_back("unsafe_math");
|
|
|
|
|
}
|
|
|
|
|
if (device().settings().lcWavefrontSize64_) {
|
|
|
|
|
linkOptions.push_back("wavefrontsize64");
|
|
|
|
|
}
|
|
|
|
|
linkOptions.push_back("code_object_v" +
|
|
|
|
|
std::to_string(options->oVariables->LCCodeObjectVersion));
|
|
|
|
|
|
|
|
|
|
amd_comgr_status_t status = addCodeObjData(llvmBinary_.data(), llvmBinary_.size(),
|
|
|
|
|
AMD_COMGR_DATA_KIND_BC, "LLVM Binary", &inputs);
|
|
|
|
|
|
|
|
|
|
amd_comgr_data_set_t linked_bc;
|
|
|
|
|
bool hasLinkedBC = false;
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
status = amd::Comgr::create_data_set(&linked_bc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ret = (status == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
if (ret) {
|
|
|
|
|
hasLinkedBC = true;
|
|
|
|
|
ret = linkLLVMBitcode(inputs, linkOptions, options, &linked_bc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
|
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
|
if (hasLinkedBC) {
|
|
|
|
|
amd::Comgr::destroy_data_set(linked_bc);
|
|
|
|
|
}
|
|
|
|
|
buildLog_ += "Error: Linking bitcode failed: linking source & IR libraries.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inputs = linked_bc;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 07:15:00 -04:00
|
|
|
std::vector<std::string> codegenOptions;
|
|
|
|
|
|
2019-07-09 16:10:34 -04:00
|
|
|
// TODO: Can this be fixed at the source? options->llvmOptions is a flat
|
|
|
|
|
// string, but should really be a vector of strings.
|
|
|
|
|
std::vector<std::string> splitLlvmOptions =
|
|
|
|
|
splitSpaceSeparatedString(options->llvmOptions.c_str());
|
|
|
|
|
codegenOptions.insert(codegenOptions.end(), splitLlvmOptions.begin(), splitLlvmOptions.end());
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
// Set the -O#
|
|
|
|
|
std::ostringstream optLevel;
|
|
|
|
|
optLevel << "-O" << options->oVariables->OptLevel;
|
2019-06-14 07:15:00 -04:00
|
|
|
codegenOptions.push_back(optLevel.str());
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
// Pass clang options
|
2025-01-14 15:59:21 -05:00
|
|
|
if (continueCompileFrom != FILE_TYPE_ASM_TEXT) {
|
|
|
|
|
std::copy_if(options->clangOptions.begin(), options->clangOptions.end(),
|
|
|
|
|
std::back_inserter(codegenOptions),
|
|
|
|
|
[](const std::string& opt) { return opt.rfind("-I", 0) != 0; });
|
|
|
|
|
} else {
|
|
|
|
|
codegenOptions.insert(codegenOptions.end(), options->clangOptions.begin(),
|
|
|
|
|
options->clangOptions.end());
|
|
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2018-11-23 15:11:58 -05:00
|
|
|
// Set whole program mode
|
2019-06-14 07:15:00 -04:00
|
|
|
codegenOptions.push_back("-mllvm");
|
|
|
|
|
codegenOptions.push_back("-amdgpu-internalize-symbols");
|
2018-11-05 14:24:49 -05:00
|
|
|
|
2019-01-07 18:02:10 -05:00
|
|
|
if (!device().settings().enableWgpMode_) {
|
2019-06-14 07:15:00 -04:00
|
|
|
codegenOptions.push_back("-mcumode");
|
2019-01-07 18:02:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device().settings().lcWavefrontSize64_) {
|
2019-06-14 07:15:00 -04:00
|
|
|
codegenOptions.push_back("-mwavefrontsize64");
|
2019-01-07 18:02:10 -05:00
|
|
|
}
|
2022-04-11 10:50:02 -04:00
|
|
|
codegenOptions.push_back("-mcode-object-version=" +
|
|
|
|
|
std::to_string(options->oVariables->LCCodeObjectVersion));
|
2019-01-07 18:02:10 -05:00
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
// NOTE: The params is also used to identy cached code object. This parameter
|
|
|
|
|
// should not contain any dyanamically generated filename.
|
|
|
|
|
char* executable = nullptr;
|
|
|
|
|
size_t executableSize = 0;
|
|
|
|
|
bool ret = compileAndLinkExecutable(inputs, codegenOptions, options, &executable, &executableSize,
|
2023-09-11 15:22:51 -04:00
|
|
|
continueCompileFrom);
|
2018-12-13 15:22:06 -05:00
|
|
|
amd::Comgr::destroy_data_set(inputs);
|
2018-11-05 14:24:49 -05:00
|
|
|
|
|
|
|
|
if (!ret) {
|
2021-04-12 14:55:06 -04:00
|
|
|
if (continueCompileFrom == FILE_TYPE_ASM_TEXT) {
|
2018-11-05 14:24:49 -05:00
|
|
|
buildLog_ += "Error: Creating the executable from ISA assembly text failed.\n";
|
|
|
|
|
} else {
|
|
|
|
|
buildLog_ += "Error: Creating the executable from LLVM IRs failed.\n";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the binary and type
|
2019-10-24 16:29:54 -04:00
|
|
|
clBinary()->saveBIFBinary(executable, executableSize);
|
|
|
|
|
|
|
|
|
|
// Destroy original memory with executable after compilation
|
|
|
|
|
delete[] executable;
|
|
|
|
|
|
2021-03-26 15:29:05 -04:00
|
|
|
if (!createKernels(const_cast<void*>(clBinary()->data().first), clBinary()->data().second,
|
|
|
|
|
options->oVariables->UniformWorkGroupSize, internal_)) {
|
|
|
|
|
buildLog_ += "Error: Cannot create kernels.\n";
|
2019-10-29 12:23:34 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 14:24:49 -05:00
|
|
|
setType(TYPE_EXECUTABLE);
|
|
|
|
|
|
|
|
|
|
return true;
|
2018-09-27 18:15:24 -04:00
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
// ================================================================================================
|
|
|
|
|
bool Program::initClBinary() {
|
|
|
|
|
if (clBinary_ == nullptr) {
|
|
|
|
|
clBinary_ = new ClBinary(device());
|
|
|
|
|
if (clBinary_ == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
|
|
|
void Program::releaseClBinary() {
|
2021-09-06 17:55:09 -04:00
|
|
|
delete clBinary_;
|
|
|
|
|
clBinary_ = nullptr;
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
|
|
|
bool Program::initBuild(amd::option::Options* options) {
|
2018-10-02 11:52:23 -04:00
|
|
|
compileOptions_ = options->origOptionStr;
|
2018-09-18 18:53:08 -04:00
|
|
|
programOptions_ = options;
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->DumpFlags > 0) {
|
2020-08-28 21:38:05 -07:00
|
|
|
static std::atomic<uint> build_num{0};
|
2018-09-18 18:53:08 -04:00
|
|
|
options->setBuildNo(build_num++);
|
|
|
|
|
}
|
|
|
|
|
buildLog_.clear();
|
|
|
|
|
if (!initClBinary()) {
|
2020-04-13 22:41:44 -04:00
|
|
|
DevLogError("Init CL Binary failed \n");
|
2018-09-18 18:53:08 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-10-02 11:52:23 -04:00
|
|
|
|
2024-12-10 20:13:30 +00:00
|
|
|
if (!amd::IS_HIP) {
|
|
|
|
|
std::string targetID = device().isa().targetId();
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
// Replace special charaters that are not supported by Windows FS.
|
|
|
|
|
std::replace(targetID.begin(), targetID.end(), ':', '@');
|
|
|
|
|
#endif
|
|
|
|
|
options->setPerBuildInfo(targetID.c_str(), clBinary()->getEncryptCode(), true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-02 11:52:23 -04:00
|
|
|
// Elf Binary setup
|
|
|
|
|
std::string outFileName;
|
2020-11-13 14:39:10 -05:00
|
|
|
bool tempFile = false;
|
2018-10-02 11:52:23 -04:00
|
|
|
|
|
|
|
|
// true means hsail required
|
2021-03-24 12:23:48 -04:00
|
|
|
clBinary()->init(options);
|
2018-10-02 11:52:23 -04:00
|
|
|
if (options->isDumpFlagSet(amd::option::DUMP_BIF)) {
|
|
|
|
|
outFileName = options->getDumpFileName(".bin");
|
2020-11-13 14:39:10 -05:00
|
|
|
} else {
|
|
|
|
|
// elf lib needs a writable temp file
|
|
|
|
|
outFileName = amd::Os::getTempFileName();
|
|
|
|
|
tempFile = true;
|
2018-10-02 11:52:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!clBinary()->setElfOut(LP64_SWITCH(ELFCLASS32, ELFCLASS64),
|
2020-11-13 14:39:10 -05:00
|
|
|
(outFileName.size() > 0) ? outFileName.c_str() : nullptr, tempFile)) {
|
2018-10-02 11:52:23 -04:00
|
|
|
LogError("Setup elf out for gpu failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2018-10-02 11:52:23 -04:00
|
|
|
bool Program::finiBuild(bool isBuildGood) {
|
|
|
|
|
clBinary()->resetElfOut();
|
|
|
|
|
clBinary()->resetElfIn();
|
|
|
|
|
|
|
|
|
|
if (!isBuildGood) {
|
|
|
|
|
// Prevent the encrypted binary form leaking out
|
|
|
|
|
clBinary()->setBinary(nullptr, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
|
|
|
|
// ================================================================================================
|
2020-02-12 13:16:06 -08:00
|
|
|
int32_t Program::compile(const std::string& sourceCode,
|
2018-09-18 18:53:08 -04:00
|
|
|
const std::vector<const std::string*>& headers,
|
|
|
|
|
const char** headerIncludeNames, const char* origOptions,
|
|
|
|
|
amd::option::Options* options) {
|
|
|
|
|
uint64_t start_time = 0;
|
|
|
|
|
if (options->oVariables->EnableBuildTiming) {
|
|
|
|
|
buildLog_ = "\nStart timing major build components.....\n\n";
|
|
|
|
|
start_time = amd::Os::timeNanos();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastBuildOptionsArg_ = origOptions ? origOptions : "";
|
|
|
|
|
if (options) {
|
|
|
|
|
compileOptions_ = options->origOptionStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildStatus_ = CL_BUILD_IN_PROGRESS;
|
|
|
|
|
if (!initBuild(options)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation init failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->FP32RoundDivideSqrt &&
|
|
|
|
|
!(device().info().singleFPConfig_ & CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
buildLog_ +=
|
|
|
|
|
"Error: -cl-fp32-correctly-rounded-divide-sqrt "
|
|
|
|
|
"specified without device support";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compile the source code if any
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !sourceCode.empty() &&
|
2025-03-28 10:36:19 +01:00
|
|
|
!compileImpl(sourceCode, headers, headerIncludeNames, options)) {
|
2018-09-18 18:53:08 -04:00
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setType(TYPE_COMPILED);
|
|
|
|
|
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !createBinary(options)) {
|
|
|
|
|
buildLog_ += "Internal Error: creating OpenCL binary failed!\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!finiBuild(buildStatus_ == CL_BUILD_IN_PROGRESS)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation fini failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buildStatus_ == CL_BUILD_IN_PROGRESS) {
|
|
|
|
|
buildStatus_ = CL_BUILD_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
buildError_ = CL_COMPILE_PROGRAM_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->EnableBuildTiming) {
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
tmp_ss << "\nTotal Compile Time: " << (amd::Os::timeNanos() - start_time) / 1000ULL << " us\n";
|
|
|
|
|
buildLog_ += tmp_ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->BuildLog && !buildLog_.empty()) {
|
|
|
|
|
if (strcmp(options->oVariables->BuildLog, "stderr") == 0) {
|
|
|
|
|
fprintf(stderr, "%s\n", options->optionsLog().c_str());
|
|
|
|
|
fprintf(stderr, "%s\n", buildLog_.c_str());
|
|
|
|
|
} else if (strcmp(options->oVariables->BuildLog, "stdout") == 0) {
|
|
|
|
|
printf("%s\n", options->optionsLog().c_str());
|
|
|
|
|
printf("%s\n", buildLog_.c_str());
|
|
|
|
|
} else {
|
|
|
|
|
std::fstream f;
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
std::string logs = options->optionsLog() + buildLog_;
|
|
|
|
|
tmp_ss << options->oVariables->BuildLog << "." << options->getBuildNo();
|
|
|
|
|
f.open(tmp_ss.str().c_str(), (std::fstream::out | std::fstream::binary));
|
|
|
|
|
f.write(logs.data(), logs.size());
|
|
|
|
|
f.close();
|
|
|
|
|
}
|
|
|
|
|
LogError(buildLog_.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2020-02-12 13:16:06 -08:00
|
|
|
int32_t Program::link(const std::vector<Program*>& inputPrograms, const char* origLinkOptions,
|
2018-09-18 18:53:08 -04:00
|
|
|
amd::option::Options* linkOptions) {
|
|
|
|
|
lastBuildOptionsArg_ = origLinkOptions ? origLinkOptions : "";
|
|
|
|
|
if (linkOptions) {
|
|
|
|
|
linkOptions_ = linkOptions->origOptionStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildStatus_ = CL_BUILD_IN_PROGRESS;
|
|
|
|
|
|
|
|
|
|
amd::option::Options options;
|
|
|
|
|
if (!getCompileOptionsAtLinking(inputPrograms, linkOptions)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ += "Internal error: Get compile options failed.";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-10-23 11:21:49 -07:00
|
|
|
if (!amd::option::parseAllOptions(compileOptions_, options, false)) {
|
2018-09-18 18:53:08 -04:00
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
buildLog_ += options.optionsLog();
|
|
|
|
|
LogError("Parsing compile options failed.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t start_time = 0;
|
|
|
|
|
if (options.oVariables->EnableBuildTiming) {
|
|
|
|
|
buildLog_ = "\nStart timing major build components.....\n\n";
|
|
|
|
|
start_time = amd::Os::timeNanos();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initBuild() will clear buildLog_, so store it in a temporary variable
|
|
|
|
|
std::string tmpBuildLog = buildLog_;
|
|
|
|
|
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !initBuild(&options)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ += "Internal error: Compilation init failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildLog_ += tmpBuildLog;
|
|
|
|
|
|
|
|
|
|
if (options.oVariables->FP32RoundDivideSqrt &&
|
|
|
|
|
!(device().info().singleFPConfig_ & CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
buildLog_ +=
|
|
|
|
|
"Error: -cl-fp32-correctly-rounded-divide-sqrt "
|
|
|
|
|
"specified without device support";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool createLibrary = linkOptions ? linkOptions->oVariables->clCreateLibrary : false;
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !linkImpl(inputPrograms, &options, createLibrary)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ += "Internal error: Link failed.\n";
|
|
|
|
|
buildLog_ += "Make sure the system setup is correct.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!finiBuild(buildStatus_ == CL_BUILD_IN_PROGRESS)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation fini failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buildStatus_ == CL_BUILD_IN_PROGRESS) {
|
|
|
|
|
buildStatus_ = CL_BUILD_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
buildError_ = CL_LINK_PROGRAM_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options.oVariables->EnableBuildTiming) {
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
tmp_ss << "\nTotal Link Time: " << (amd::Os::timeNanos() - start_time) / 1000ULL << " us\n";
|
|
|
|
|
buildLog_ += tmp_ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options.oVariables->BuildLog && !buildLog_.empty()) {
|
|
|
|
|
if (strcmp(options.oVariables->BuildLog, "stderr") == 0) {
|
|
|
|
|
fprintf(stderr, "%s\n", options.optionsLog().c_str());
|
|
|
|
|
fprintf(stderr, "%s\n", buildLog_.c_str());
|
|
|
|
|
} else if (strcmp(options.oVariables->BuildLog, "stdout") == 0) {
|
|
|
|
|
printf("%s\n", options.optionsLog().c_str());
|
|
|
|
|
printf("%s\n", buildLog_.c_str());
|
|
|
|
|
} else {
|
|
|
|
|
std::fstream f;
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
std::string logs = options.optionsLog() + buildLog_;
|
|
|
|
|
tmp_ss << options.oVariables->BuildLog << "." << options.getBuildNo();
|
|
|
|
|
f.open(tmp_ss.str().c_str(), (std::fstream::out | std::fstream::binary));
|
|
|
|
|
f.write(logs.data(), logs.size());
|
|
|
|
|
f.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!buildLog_.empty()) {
|
|
|
|
|
LogError(buildLog_.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2020-12-03 16:36:58 +03:00
|
|
|
static std::pair<std::string, size_t> getSubstBinFileName(const char* SubstCfgFile, size_t srcHash,
|
|
|
|
|
size_t optHash) {
|
|
|
|
|
using namespace std;
|
|
|
|
|
const size_t srcAndOptHash = srcHash ^ optHash;
|
|
|
|
|
ifstream cfgFile(SubstCfgFile);
|
|
|
|
|
if (cfgFile.good()) {
|
|
|
|
|
string line;
|
|
|
|
|
while (getline(cfgFile, line)) {
|
|
|
|
|
istringstream ss(line);
|
|
|
|
|
size_t hash;
|
|
|
|
|
ss >> setbase(16) >> hash;
|
|
|
|
|
if (ss.fail() || !isspace(ss.peek())) continue;
|
|
|
|
|
|
|
|
|
|
if (hash == srcAndOptHash || hash == srcHash) {
|
|
|
|
|
ss >> ws;
|
|
|
|
|
string objFileName;
|
|
|
|
|
getline(ss, objFileName); // get the rest of line with spaces
|
|
|
|
|
return make_pair(objFileName, hash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
return make_pair(string(), (size_t)1);
|
|
|
|
|
return make_pair(string(), (size_t)0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Program::trySubstObjFile(const char* SubstCfgFile, const std::string& sourceCode,
|
|
|
|
|
const amd::option::Options* options) {
|
|
|
|
|
std::string buffer;
|
|
|
|
|
std::ostringstream str(buffer);
|
|
|
|
|
|
|
|
|
|
size_t srcHash = getOCLSourceHash(sourceCode);
|
|
|
|
|
size_t optHash = getOCLOptionsHash(*options);
|
|
|
|
|
auto substRes = getSubstBinFileName(SubstCfgFile, srcHash, optHash);
|
|
|
|
|
if (substRes.first.empty()) {
|
|
|
|
|
switch (substRes.second) {
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
str << "Subst failure: cannot open config file " << SubstCfgFile << std::endl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
buildLog_ += str.str();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* binary = nullptr;
|
|
|
|
|
size_t binSize = 0;
|
|
|
|
|
std::ifstream binFile(substRes.first, std::ios::binary | std::ios::ate);
|
|
|
|
|
if (binFile.good()) {
|
|
|
|
|
binSize = binFile.tellg();
|
|
|
|
|
binFile.seekg(0, std::ios::beg);
|
|
|
|
|
binary = new (std::nothrow) uint8_t[binSize];
|
|
|
|
|
if (binary && !binFile.read(reinterpret_cast<char*>(binary), binSize)) {
|
|
|
|
|
delete[] binary;
|
|
|
|
|
binary = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!binary) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
buildError_ = CL_BUILD_PROGRAM_FAILURE;
|
|
|
|
|
str << "Subst failure: cannot read binary file " << substRes.first << '\n';
|
|
|
|
|
} else {
|
2022-07-27 06:00:30 +00:00
|
|
|
if (setKernels(binary, binSize)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_SUCCESS;
|
|
|
|
|
buildError_ = 0;
|
|
|
|
|
str << "Substituted program hash 0x" << std::setbase(16) << substRes.second << " with "
|
|
|
|
|
<< substRes.first << '\n';
|
|
|
|
|
}
|
2020-12-03 16:36:58 +03:00
|
|
|
}
|
|
|
|
|
buildLog_ += str.str();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-12 13:16:06 -08:00
|
|
|
int32_t Program::build(const std::string& sourceCode, const char* origOptions,
|
2025-03-28 10:36:19 +01:00
|
|
|
amd::option::Options* options) {
|
2020-12-03 16:36:58 +03:00
|
|
|
if (AMD_OCL_SUBST_OBJFILE != NULL &&
|
|
|
|
|
trySubstObjFile(AMD_OCL_SUBST_OBJFILE, sourceCode, options)) {
|
|
|
|
|
return buildError();
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
uint64_t start_time = 0;
|
|
|
|
|
if (options->oVariables->EnableBuildTiming) {
|
|
|
|
|
buildLog_ = "\nStart timing major build components.....\n\n";
|
|
|
|
|
start_time = amd::Os::timeNanos();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastBuildOptionsArg_ = origOptions ? origOptions : "";
|
|
|
|
|
if (options) {
|
|
|
|
|
compileOptions_ = options->origOptionStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildStatus_ = CL_BUILD_IN_PROGRESS;
|
|
|
|
|
if (!initBuild(options)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation init failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->FP32RoundDivideSqrt &&
|
|
|
|
|
!(device().info().singleFPConfig_ & CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
buildLog_ +=
|
|
|
|
|
"Error: -cl-fp32-correctly-rounded-divide-sqrt "
|
|
|
|
|
"specified without device support";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<const std::string*> headers;
|
2020-10-05 04:25:18 -04:00
|
|
|
std::vector<const char*> headerIncludeNames;
|
|
|
|
|
const std::vector<std::string>& tmpHeaderNames = owner()->headerNames();
|
|
|
|
|
const std::vector<std::string>& tmpHeaders = owner()->headers();
|
|
|
|
|
for (size_t i = 0; i < tmpHeaders.size(); ++i) {
|
|
|
|
|
headers.push_back(&tmpHeaders[i]);
|
|
|
|
|
headerIncludeNames.push_back(tmpHeaderNames[i].c_str());
|
|
|
|
|
}
|
|
|
|
|
// Compile the source code if any
|
2020-10-13 01:16:59 -04:00
|
|
|
bool compileStatus = true;
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !sourceCode.empty()) {
|
|
|
|
|
if (!headerIncludeNames.empty()) {
|
2025-03-28 10:36:19 +01:00
|
|
|
compileStatus = compileImpl(sourceCode, headers, &headerIncludeNames[0], options);
|
2020-10-13 01:16:59 -04:00
|
|
|
} else {
|
2025-03-28 10:36:19 +01:00
|
|
|
compileStatus = compileImpl(sourceCode, headers, nullptr, options);
|
2020-10-13 01:16:59 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!compileStatus) {
|
2018-09-18 18:53:08 -04:00
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((buildStatus_ == CL_BUILD_IN_PROGRESS) && !linkImpl(options)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ += "Internal error: Link failed.\n";
|
|
|
|
|
buildLog_ += "Make sure the system setup is correct.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!finiBuild(buildStatus_ == CL_BUILD_IN_PROGRESS)) {
|
|
|
|
|
buildStatus_ = CL_BUILD_ERROR;
|
|
|
|
|
if (buildLog_.empty()) {
|
|
|
|
|
buildLog_ = "Internal error: Compilation fini failed.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buildStatus_ == CL_BUILD_IN_PROGRESS) {
|
|
|
|
|
buildStatus_ = CL_BUILD_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
buildError_ = CL_BUILD_PROGRAM_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->EnableBuildTiming) {
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
tmp_ss << "\nTotal Build Time: " << (amd::Os::timeNanos() - start_time) / 1000ULL << " us\n";
|
|
|
|
|
buildLog_ += tmp_ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->oVariables->BuildLog && !buildLog_.empty()) {
|
|
|
|
|
if (strcmp(options->oVariables->BuildLog, "stderr") == 0) {
|
|
|
|
|
fprintf(stderr, "%s\n", options->optionsLog().c_str());
|
|
|
|
|
fprintf(stderr, "%s\n", buildLog_.c_str());
|
|
|
|
|
} else if (strcmp(options->oVariables->BuildLog, "stdout") == 0) {
|
|
|
|
|
printf("%s\n", options->optionsLog().c_str());
|
|
|
|
|
printf("%s\n", buildLog_.c_str());
|
|
|
|
|
} else {
|
|
|
|
|
std::fstream f;
|
|
|
|
|
std::stringstream tmp_ss;
|
|
|
|
|
std::string logs = options->optionsLog() + buildLog_;
|
|
|
|
|
tmp_ss << options->oVariables->BuildLog << "." << options->getBuildNo();
|
|
|
|
|
f.open(tmp_ss.str().c_str(), (std::fstream::out | std::fstream::binary));
|
|
|
|
|
f.write(logs.data(), logs.size());
|
|
|
|
|
f.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!buildLog_.empty()) {
|
|
|
|
|
LogError(buildLog_.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildError();
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 15:29:05 -04:00
|
|
|
// ================================================================================================
|
|
|
|
|
bool Program::load() {
|
2025-10-23 11:21:49 -07:00
|
|
|
coLoaded_ = setKernels(const_cast<void*>(binary().first), binary().second, BinaryFd().first,
|
|
|
|
|
BinaryFd().second, BinaryURI());
|
|
|
|
|
return coLoaded_;
|
2021-03-26 15:29:05 -04:00
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
// ================================================================================================
|
2019-06-14 07:15:00 -04:00
|
|
|
std::vector<std::string> Program::ProcessOptions(amd::option::Options* options) {
|
|
|
|
|
std::vector<std::string> optionsVec;
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
if (!isHIP()) {
|
|
|
|
|
int major, minor;
|
|
|
|
|
::sscanf(device().info().version_, "OpenCL %d.%d ", &major, &minor);
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "-D__OPENCL_VERSION__=" << (major * 100 + minor * 10);
|
|
|
|
|
optionsVec.push_back(ss.str());
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
if (!isHIP()) {
|
|
|
|
|
if (device().info().imageSupport_ && options->oVariables->ImageSupport) {
|
|
|
|
|
optionsVec.push_back("-D__IMAGE_SUPPORT__=1");
|
2018-10-02 18:50:36 -04:00
|
|
|
}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
uint clcStd =
|
|
|
|
|
(options->oVariables->CLStd[2] - '0') * 100 + (options->oVariables->CLStd[4] - '0') * 10;
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
if (clcStd >= 200) {
|
|
|
|
|
std::stringstream opts;
|
|
|
|
|
// Add only for CL2.0 and later
|
|
|
|
|
opts << "-D"
|
|
|
|
|
<< "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE=" << device().info().maxGlobalVariableSize_;
|
|
|
|
|
optionsVec.push_back(opts.str());
|
2022-12-22 16:05:12 -05:00
|
|
|
} else {
|
|
|
|
|
options->oVariables->UniformWorkGroupSize = true;
|
2019-11-25 17:55:47 -06:00
|
|
|
}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2019-11-25 17:55:47 -06:00
|
|
|
// Tokenize the extensions string into a vector of strings
|
|
|
|
|
std::istringstream istrstr(device().info().extensions_);
|
|
|
|
|
std::istream_iterator<std::string> sit(istrstr), end;
|
|
|
|
|
std::vector<std::string> extensions(sit, end);
|
2018-09-18 18:53:08 -04:00
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
if (!extensions.empty()) {
|
|
|
|
|
std::ostringstream clext;
|
2019-11-25 17:55:47 -06:00
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
clext << "-cl-ext=+";
|
|
|
|
|
std::copy(extensions.begin(), extensions.end() - 1,
|
|
|
|
|
std::ostream_iterator<std::string>(clext, ",+"));
|
|
|
|
|
clext << extensions.back();
|
2019-11-25 17:55:47 -06:00
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
optionsVec.push_back("-Xclang");
|
|
|
|
|
optionsVec.push_back(clext.str());
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 07:15:00 -04:00
|
|
|
return optionsVec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Program::ProcessOptionsFlattened(amd::option::Options* options) {
|
|
|
|
|
std::vector<std::string> processOptions = ProcessOptions(options);
|
|
|
|
|
std::ostringstream processOptionsOStrStr;
|
|
|
|
|
processOptionsOStrStr << " ";
|
|
|
|
|
std::copy(processOptions.begin(), processOptions.end(),
|
|
|
|
|
std::ostream_iterator<std::string>(processOptionsOStrStr, " "));
|
|
|
|
|
return processOptionsOStrStr.str();
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
|
|
|
bool Program::getCompileOptionsAtLinking(const std::vector<Program*>& inputPrograms,
|
|
|
|
|
const amd::option::Options* linkOptions) {
|
|
|
|
|
amd::option::Options compileOptions;
|
|
|
|
|
auto it = inputPrograms.cbegin();
|
|
|
|
|
const auto itEnd = inputPrograms.cend();
|
|
|
|
|
for (size_t i = 0; it != itEnd; ++it, ++i) {
|
|
|
|
|
Program* program = *it;
|
|
|
|
|
|
|
|
|
|
amd::option::Options compileOptions2;
|
|
|
|
|
amd::option::Options* thisCompileOptions = i == 0 ? &compileOptions : &compileOptions2;
|
2025-10-23 11:21:49 -07:00
|
|
|
if (!amd::option::parseAllOptions(program->compileOptions_, *thisCompileOptions, false)) {
|
2018-09-18 18:53:08 -04:00
|
|
|
buildLog_ += thisCompileOptions->optionsLog();
|
|
|
|
|
LogError("Parsing compile options failed.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == 0) compileOptions_ = program->compileOptions_;
|
|
|
|
|
|
|
|
|
|
// if we are linking a program executable, and if "program" is a
|
|
|
|
|
// compiled module or a library created with "-enable-link-options",
|
|
|
|
|
// we can overwrite "program"'s compile options with linking options
|
|
|
|
|
if (!linkOptions_.empty() && !linkOptions->oVariables->clCreateLibrary) {
|
|
|
|
|
bool linkOptsCanOverwrite = false;
|
|
|
|
|
if (program->type() != TYPE_LIBRARY) {
|
|
|
|
|
linkOptsCanOverwrite = true;
|
|
|
|
|
} else {
|
|
|
|
|
amd::option::Options thisLinkOptions;
|
2025-10-23 11:21:49 -07:00
|
|
|
if (!amd::option::parseLinkOptions(program->linkOptions_, thisLinkOptions)) {
|
2018-09-18 18:53:08 -04:00
|
|
|
buildLog_ += thisLinkOptions.optionsLog();
|
|
|
|
|
LogError("Parsing link options failed.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (thisLinkOptions.oVariables->clEnableLinkOptions) linkOptsCanOverwrite = true;
|
|
|
|
|
}
|
|
|
|
|
if (linkOptsCanOverwrite) {
|
|
|
|
|
if (!thisCompileOptions->setOptionVariablesAs(*linkOptions)) {
|
|
|
|
|
buildLog_ += thisCompileOptions->optionsLog();
|
|
|
|
|
LogError("Setting link options failed.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == 0) compileOptions_ += " " + linkOptions_;
|
|
|
|
|
}
|
|
|
|
|
// warn if input modules have inconsistent compile options
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
if (!compileOptions.equals(*thisCompileOptions, true /*ignore clc options*/)) {
|
|
|
|
|
buildLog_ +=
|
|
|
|
|
"Warning: Input OpenCL binaries has inconsistent"
|
|
|
|
|
" compile options. Using compile options from"
|
|
|
|
|
" the first input binary!\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2020-08-03 11:21:37 -04:00
|
|
|
bool Program::initClBinary(const char* binaryIn, size_t size, amd::Os::FileDesc fdesc,
|
|
|
|
|
size_t foffset, std::string uri) {
|
2018-09-18 18:53:08 -04:00
|
|
|
if (!initClBinary()) {
|
2020-04-13 22:41:44 -04:00
|
|
|
DevLogError("Init CL Binary failed \n");
|
2018-09-18 18:53:08 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the original binary that isn't owned by ClBinary
|
|
|
|
|
clBinary()->saveOrigBinary(binaryIn, size);
|
|
|
|
|
|
|
|
|
|
const char* bin = binaryIn;
|
|
|
|
|
size_t sz = size;
|
|
|
|
|
|
|
|
|
|
// unencrypted
|
|
|
|
|
int encryptCode = 0;
|
|
|
|
|
char* decryptedBin = nullptr;
|
|
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
size_t decryptedSize;
|
|
|
|
|
if (!clBinary()->decryptElf(binaryIn, size, &decryptedBin, &decryptedSize, &encryptCode)) {
|
|
|
|
|
DevLogError("Cannot Decrypt Elf \n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (decryptedBin != nullptr) {
|
|
|
|
|
// It is decrypted binary.
|
|
|
|
|
bin = decryptedBin;
|
|
|
|
|
sz = decryptedSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isElf(bin)) {
|
|
|
|
|
// Invalid binary.
|
|
|
|
|
delete[] decryptedBin;
|
|
|
|
|
DevLogError("Bin is not ELF \n");
|
|
|
|
|
return false;
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clBinary()->setFlags(encryptCode);
|
|
|
|
|
|
2020-08-03 11:21:37 -04:00
|
|
|
return clBinary()->setBinary(bin, sz, (decryptedBin != nullptr), fdesc, foffset, uri);
|
2018-09-18 18:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
// ================================================================================================
|
|
|
|
|
void Program::addKernel(Kernel* k) {
|
|
|
|
|
kernels_[k->name()] = k;
|
|
|
|
|
if (k->isInitKernel()) {
|
|
|
|
|
initKernels_.push_back(k);
|
|
|
|
|
} else if (k->isFiniKernel()) {
|
|
|
|
|
finiKernels_.push_back(k);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 18:53:08 -04:00
|
|
|
// ================================================================================================
|
2020-08-03 11:21:37 -04:00
|
|
|
bool Program::setBinary(const char* binaryIn, size_t size, const device::Program* same_dev_prog,
|
|
|
|
|
amd::Os::FileDesc fdesc, size_t foffset, std::string uri) {
|
|
|
|
|
if (!initClBinary(binaryIn, size, fdesc, foffset, uri)) {
|
2020-04-13 22:41:44 -04:00
|
|
|
DevLogError("Init CL Binary failed \n");
|
2018-09-18 18:53:08 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!clBinary()->setElfIn()) {
|
|
|
|
|
LogError("Setting input OCL binary failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
uint16_t type;
|
|
|
|
|
if (!clBinary()->elfIn()->getType(type)) {
|
|
|
|
|
LogError("Bad OCL Binary: error loading ELF type!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
switch (type) {
|
|
|
|
|
case ET_NONE: {
|
|
|
|
|
setType(TYPE_NONE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ET_REL: {
|
|
|
|
|
if (clBinary()->isSPIR() || clBinary()->isSPIRV()) {
|
|
|
|
|
setType(TYPE_INTERMEDIATE);
|
|
|
|
|
} else {
|
|
|
|
|
setType(TYPE_COMPILED);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ET_DYN: {
|
|
|
|
|
char* sect = nullptr;
|
|
|
|
|
size_t sz = 0;
|
2019-10-03 17:12:38 -04:00
|
|
|
if (clBinary()->elfIn()->isHsaCo()) {
|
2018-09-18 18:53:08 -04:00
|
|
|
setType(TYPE_EXECUTABLE);
|
|
|
|
|
} else {
|
|
|
|
|
setType(TYPE_LIBRARY);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ET_EXEC: {
|
|
|
|
|
setType(TYPE_EXECUTABLE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
LogError("Bad OCL Binary: bad ELF type!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-06 19:26:40 -04:00
|
|
|
if (same_dev_prog != nullptr) {
|
|
|
|
|
compileOptions_ = same_dev_prog->compileOptions();
|
|
|
|
|
linkOptions_ = same_dev_prog->linkOptions();
|
2020-08-13 02:26:39 -04:00
|
|
|
} else if (!amd::IS_HIP) {
|
2025-10-23 11:21:49 -07:00
|
|
|
compileOptions_.clear();
|
|
|
|
|
linkOptions_.clear();
|
2020-07-06 19:26:40 -04:00
|
|
|
}
|
2018-09-18 18:53:08 -04:00
|
|
|
|
|
|
|
|
clBinary()->resetElfIn();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-24 18:21:56 -04:00
|
|
|
// ================================================================================================
|
2021-04-12 14:55:06 -04:00
|
|
|
Program::file_type_t Program::getCompilationStagesFromBinary(
|
|
|
|
|
std::vector<Program::file_type_t>& completeStages, bool& needOptionsCheck) {
|
|
|
|
|
Program::file_type_t from = FILE_TYPE_DEFAULT;
|
2025-10-23 11:21:49 -07:00
|
|
|
completeStages.clear();
|
|
|
|
|
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 = FILE_TYPE_LLVMIR_BINARY;
|
|
|
|
|
}
|
|
|
|
|
if (containsShaderIsa) {
|
|
|
|
|
completeStages.push_back(from);
|
|
|
|
|
from = FILE_TYPE_ISA;
|
|
|
|
|
}
|
|
|
|
|
std::string sCurOptions = compileOptions_ + linkOptions_;
|
|
|
|
|
amd::option::Options curOptions;
|
|
|
|
|
if (!amd::option::parseAllOptions(sCurOptions, curOptions, false)) {
|
|
|
|
|
buildLog_ += curOptions.optionsLog();
|
|
|
|
|
LogError("Parsing compile options failed.");
|
|
|
|
|
return FILE_TYPE_DEFAULT;
|
|
|
|
|
}
|
|
|
|
|
switch (from) {
|
|
|
|
|
case FILE_TYPE_CG:
|
|
|
|
|
case FILE_TYPE_ISA:
|
|
|
|
|
// do not check options, if LLVMIR is absent or might be absent or options are absent
|
|
|
|
|
if (!curOptions.oVariables->BinLLVMIR || !containsLlvmirText || !containsOpts) {
|
2018-09-24 18:21:56 -04:00
|
|
|
needOptionsCheck = false;
|
2025-10-23 11:21:49 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// recompilation might be needed
|
|
|
|
|
case FILE_TYPE_LLVMIR_BINARY:
|
|
|
|
|
case FILE_TYPE_DEFAULT:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2018-09-24 18:21:56 -04:00
|
|
|
}
|
2018-11-05 14:24:49 -05:00
|
|
|
return from;
|
2018-09-24 18:21:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
2021-04-12 14:55:06 -04:00
|
|
|
Program::file_type_t Program::getNextCompilationStageFromBinary(amd::option::Options* options) {
|
|
|
|
|
Program::file_type_t continueCompileFrom = FILE_TYPE_DEFAULT;
|
2018-09-24 18:21:56 -04:00
|
|
|
binary_t binary = this->binary();
|
2020-08-03 11:21:37 -04:00
|
|
|
finfo_t finfo = this->BinaryFd();
|
|
|
|
|
std::string uri = this->BinaryURI();
|
2018-09-24 18:21:56 -04:00
|
|
|
// If the binary already exists
|
|
|
|
|
if ((binary.first != nullptr) && (binary.second > 0)) {
|
|
|
|
|
// 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
|
2020-08-03 11:21:37 -04:00
|
|
|
setBinary(static_cast<const char*>(binary.first), binary.second, nullptr, finfo.first,
|
|
|
|
|
finfo.second, uri);
|
2018-09-24 18:21:56 -04:00
|
|
|
|
|
|
|
|
// Calculate the next stage to compile from, based on sections in binaryElf_;
|
|
|
|
|
// No any validity checks here
|
2021-04-12 14:55:06 -04:00
|
|
|
std::vector<file_type_t> completeStages;
|
2018-09-24 18:21:56 -04:00
|
|
|
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) {
|
2021-04-12 14:55:06 -04:00
|
|
|
case FILE_TYPE_HSAIL_BINARY:
|
|
|
|
|
case FILE_TYPE_CG:
|
|
|
|
|
case FILE_TYPE_ISA: {
|
2018-09-24 18:21:56 -04:00
|
|
|
// 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;
|
2025-08-20 16:28:06 +02:00
|
|
|
|
2018-09-24 18:21:56 -04:00
|
|
|
compileOptions_ = sCurCompileOptions;
|
|
|
|
|
linkOptions_ = sCurLinkOptions;
|
|
|
|
|
|
2025-10-23 11:21:49 -07:00
|
|
|
amd::option::Options curOptions;
|
|
|
|
|
if (!amd::option::parseAllOptions(sCurOptions, curOptions, false)) {
|
2018-09-24 18:21:56 -04:00
|
|
|
buildLog_ += curOptions.optionsLog();
|
|
|
|
|
LogError("Parsing compile options failed.");
|
2021-04-12 14:55:06 -04:00
|
|
|
return FILE_TYPE_DEFAULT;
|
2018-09-24 18:21:56 -04:00
|
|
|
}
|
2025-08-20 16:28:06 +02:00
|
|
|
break;
|
2018-09-24 18:21:56 -04:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (recompile) {
|
|
|
|
|
while (!completeStages.empty()) {
|
|
|
|
|
continueCompileFrom = completeStages.back();
|
2021-04-12 14:55:06 -04:00
|
|
|
if (continueCompileFrom == FILE_TYPE_SPIRV_BINARY ||
|
|
|
|
|
continueCompileFrom == FILE_TYPE_LLVMIR_BINARY ||
|
|
|
|
|
continueCompileFrom == FILE_TYPE_SPIR_BINARY ||
|
|
|
|
|
continueCompileFrom == FILE_TYPE_DEFAULT) {
|
2018-09-24 18:21:56 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
completeStages.pop_back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const char* xLang = options->oVariables->XLang;
|
|
|
|
|
if (xLang != nullptr && strcmp(xLang, "asm") == 0) {
|
2021-04-12 14:55:06 -04:00
|
|
|
continueCompileFrom = FILE_TYPE_ASM_TEXT;
|
2018-09-24 18:21:56 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return continueCompileFrom;
|
|
|
|
|
}
|
2018-09-25 17:47:26 -04:00
|
|
|
|
|
|
|
|
// ================================================================================================
|
2021-08-23 10:13:31 -04:00
|
|
|
bool ComgrBinaryData::create(amd_comgr_data_kind_t kind, void* binary, size_t binSize) {
|
2021-08-04 10:38:39 -04:00
|
|
|
amd_comgr_status_t status = amd::Comgr::create_data(kind, &binaryData_);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
created_ = true;
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::set_data(binaryData_, binSize, reinterpret_cast<const char*>(binary));
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 10:13:31 -04:00
|
|
|
amd_comgr_data_t& ComgrBinaryData::data() {
|
2021-08-04 10:38:39 -04:00
|
|
|
assert(created_);
|
|
|
|
|
return binaryData_;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 10:13:31 -04:00
|
|
|
ComgrBinaryData::~ComgrBinaryData() {
|
2021-08-04 10:38:39 -04:00
|
|
|
if (created_) {
|
|
|
|
|
amd::Comgr::release_data(binaryData_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Program::createKernelMetadataMap(void* binary, size_t binSize) {
|
2021-08-23 10:13:31 -04:00
|
|
|
ComgrBinaryData binaryData;
|
2021-08-04 10:38:39 -04:00
|
|
|
if (!binaryData.create(AMD_COMGR_DATA_KIND_EXECUTABLE, binary, binSize)) {
|
|
|
|
|
buildLog_ += "Error: COMGR failed to create code object data object.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-01-04 15:06:29 -05:00
|
|
|
|
|
|
|
|
amd_comgr_status_t status;
|
2021-09-23 16:03:01 -04:00
|
|
|
if (device().isOnline()) {
|
|
|
|
|
size_t requiredSize = 0;
|
|
|
|
|
status = amd::Comgr::get_data_isa_name(binaryData.data(), &requiredSize, nullptr);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "Error: COMGR failed to get code object ISA name.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-04 10:38:39 -04:00
|
|
|
|
2021-09-23 16:03:01 -04:00
|
|
|
std::vector<char> binaryIsaName(requiredSize);
|
|
|
|
|
status = amd::Comgr::get_data_isa_name(binaryData.data(), &requiredSize, binaryIsaName.data());
|
|
|
|
|
if ((status != AMD_COMGR_STATUS_SUCCESS) || (requiredSize != binaryIsaName.size())) {
|
|
|
|
|
buildLog_ += "Error: COMGR failed to get code object ISA name.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-04 10:38:39 -04:00
|
|
|
|
2021-09-23 16:03:01 -04:00
|
|
|
const amd::Isa* binaryIsa = amd::Isa::findIsa(binaryIsaName.data());
|
|
|
|
|
if (!binaryIsa) {
|
2023-04-13 16:02:46 -07:00
|
|
|
buildLog_ +=
|
|
|
|
|
"Error: Could not find the program ISA " + std::string(binaryIsaName.data()) + "\n";
|
2021-09-23 16:03:01 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-04 10:38:39 -04:00
|
|
|
|
2021-09-23 16:03:01 -04:00
|
|
|
if (!amd::Isa::isCompatible(*binaryIsa, device().isa())) {
|
|
|
|
|
buildLog_ += "Error: The program ISA " + std::string(binaryIsaName.data());
|
2023-04-13 16:02:46 -07:00
|
|
|
buildLog_ += " is not compatible with the device ISA " + device().isa().isaName() + "\n";
|
2021-09-23 16:03:01 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-04 10:38:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::get_data_metadata(binaryData.data(), &metadata_);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "Error: COMGR failed to get the metadata.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:06:29 -05:00
|
|
|
amd_comgr_metadata_node_t kernelsMD;
|
|
|
|
|
bool hasKernelMD = false;
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
|
2019-10-28 18:13:35 -04:00
|
|
|
status = amd::Comgr::metadata_lookup(metadata_, "Kernels", &kernelsMD);
|
2019-01-04 15:06:29 -05:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
2025-09-04 10:08:41 -07:00
|
|
|
ClPrint(amd::LOG_DETAIL_DEBUG, amd::LOG_CODE, "Using Code Object V2.");
|
2019-01-04 15:06:29 -05:00
|
|
|
hasKernelMD = true;
|
2019-04-09 23:24:10 -04:00
|
|
|
codeObjectVer_ = 2;
|
|
|
|
|
} else {
|
2020-12-05 11:27:13 -05:00
|
|
|
amd_comgr_metadata_node_t versionMD, versionNode;
|
|
|
|
|
char major_version, minor_version;
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::metadata_lookup(metadata_, "amdhsa.version", &versionMD);
|
|
|
|
|
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "No amdhsa.version metadata found.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::index_list_metadata(versionMD, 0, &versionNode);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "Cannot get code object metadata major version node.");
|
|
|
|
|
amd::Comgr::destroy_metadata(versionMD);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = 1;
|
|
|
|
|
status = amd::Comgr::get_metadata_string(versionNode, &size, &major_version);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "Cannot get code object metadata major version.");
|
|
|
|
|
amd::Comgr::destroy_metadata(versionNode);
|
|
|
|
|
amd::Comgr::destroy_metadata(versionMD);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
amd::Comgr::destroy_metadata(versionNode);
|
|
|
|
|
|
|
|
|
|
status = amd::Comgr::index_list_metadata(versionMD, 1, &versionNode);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "Cannot get code object metadata minor version node.");
|
|
|
|
|
amd::Comgr::destroy_metadata(versionMD);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = 1;
|
|
|
|
|
status = amd::Comgr::get_metadata_string(versionNode, &size, &minor_version);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "Cannot get code object metadata minor version.");
|
|
|
|
|
amd::Comgr::destroy_metadata(versionNode);
|
|
|
|
|
amd::Comgr::destroy_metadata(versionMD);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
amd::Comgr::destroy_metadata(versionNode);
|
|
|
|
|
|
|
|
|
|
amd::Comgr::destroy_metadata(versionMD);
|
|
|
|
|
|
|
|
|
|
if (major_version == '1') {
|
|
|
|
|
if (minor_version == '0') {
|
2025-09-04 10:08:41 -07:00
|
|
|
ClPrint(amd::LOG_DETAIL_DEBUG, amd::LOG_CODE, "Using Code Object V3.");
|
2020-12-05 11:27:13 -05:00
|
|
|
codeObjectVer_ = 3;
|
|
|
|
|
} else if (minor_version == '1') {
|
2025-09-04 10:08:41 -07:00
|
|
|
ClPrint(amd::LOG_DETAIL_DEBUG, amd::LOG_CODE, "Using Code Object V4.");
|
2020-12-05 11:27:13 -05:00
|
|
|
codeObjectVer_ = 4;
|
2022-02-03 18:28:56 -05:00
|
|
|
} else if (minor_version == '2') {
|
2025-09-04 10:08:41 -07:00
|
|
|
ClPrint(amd::LOG_DETAIL_DEBUG, amd::LOG_CODE, "Using Code Object V5.");
|
2022-02-03 18:28:56 -05:00
|
|
|
codeObjectVer_ = 5;
|
2020-12-05 11:27:13 -05:00
|
|
|
} else {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE,
|
|
|
|
|
"Unknown code object metadata minor version [%s.%s].", major_version,
|
|
|
|
|
minor_version);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ClPrint(amd::LOG_ERROR, amd::LOG_CODE, "Unknown code object metadata major version [%s.%s].",
|
|
|
|
|
major_version, minor_version);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-28 18:13:35 -04:00
|
|
|
status = amd::Comgr::metadata_lookup(metadata_, "amdhsa.kernels", &kernelsMD);
|
2019-04-09 23:24:10 -04:00
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
hasKernelMD = true;
|
|
|
|
|
}
|
2019-01-04 15:06:29 -05:00
|
|
|
}
|
|
|
|
|
|
2019-04-11 11:13:22 -04:00
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
status = amd::Comgr::get_metadata_list_size(kernelsMD, &size);
|
2019-10-03 17:12:38 -04:00
|
|
|
} else if (amd::IS_HIP) {
|
|
|
|
|
// Assume an empty binary. HIP may have binaries with just global variables
|
|
|
|
|
return true;
|
2019-04-11 11:13:22 -04:00
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:06:29 -05:00
|
|
|
for (size_t i = 0; i < size && status == AMD_COMGR_STATUS_SUCCESS; i++) {
|
|
|
|
|
amd_comgr_metadata_node_t nameMeta;
|
|
|
|
|
bool hasNameMeta = false;
|
|
|
|
|
bool hasKernelNode = false;
|
|
|
|
|
|
|
|
|
|
amd_comgr_metadata_node_t kernelNode;
|
|
|
|
|
|
|
|
|
|
std::string kernelName;
|
|
|
|
|
status = amd::Comgr::index_list_metadata(kernelsMD, i, &kernelNode);
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
hasKernelNode = true;
|
2019-04-09 23:24:10 -04:00
|
|
|
status = amd::Comgr::metadata_lookup(kernelNode, (codeObjectVer() == 2) ? "Name" : ".name",
|
|
|
|
|
&nameMeta);
|
2019-01-04 15:06:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
hasNameMeta = true;
|
|
|
|
|
status = getMetaBuf(nameMeta, &kernelName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
kernelMetadataMap_[kernelName] = kernelNode;
|
|
|
|
|
} else {
|
|
|
|
|
if (hasKernelNode) {
|
|
|
|
|
amd::Comgr::destroy_metadata(kernelNode);
|
|
|
|
|
}
|
|
|
|
|
for (auto const& kernelMeta : kernelMetadataMap_) {
|
|
|
|
|
amd::Comgr::destroy_metadata(kernelMeta.second);
|
|
|
|
|
}
|
|
|
|
|
kernelMetadataMap_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasNameMeta) {
|
|
|
|
|
amd::Comgr::destroy_metadata(nameMeta);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasKernelMD) {
|
|
|
|
|
amd::Comgr::destroy_metadata(kernelsMD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (status == AMD_COMGR_STATUS_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-25 17:47:26 -04:00
|
|
|
bool Program::FindGlobalVarSize(void* binary, size_t binSize) {
|
2022-02-23 21:18:35 -05:00
|
|
|
// HIP doesn't need information about global variable size.
|
|
|
|
|
// Hence runtime can skip expensive Elf object creation for parsing
|
|
|
|
|
if (!amd::IS_HIP) {
|
|
|
|
|
size_t progvarsTotalSize = 0;
|
|
|
|
|
size_t dynamicSize = 0;
|
|
|
|
|
size_t progvarsWriteSize = 0;
|
|
|
|
|
|
|
|
|
|
amd::Elf elfIn(ELFCLASSNONE, reinterpret_cast<const char*>(binary), binSize, nullptr,
|
|
|
|
|
amd::Elf::ELF_C_READ);
|
|
|
|
|
|
|
|
|
|
if (!elfIn.isSuccessful()) {
|
|
|
|
|
buildLog_ += "Creating input amd::Elf object failed\n";
|
|
|
|
|
return false;
|
2018-09-25 17:47:26 -04:00
|
|
|
}
|
2021-08-04 10:38:39 -04:00
|
|
|
|
2022-02-23 21:18:35 -05:00
|
|
|
auto numpHdrs = elfIn.getSegmentNum();
|
|
|
|
|
for (unsigned int i = 0; i < numpHdrs; ++i) {
|
|
|
|
|
amd::ELFIO::segment* seg = nullptr;
|
|
|
|
|
if (!elfIn.getSegment(i, seg)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Accumulate the size of R & !X loadable segments
|
|
|
|
|
if (seg->get_type() == PT_LOAD && !(seg->get_flags() & PF_X)) {
|
|
|
|
|
if (seg->get_flags() & PF_R) {
|
|
|
|
|
progvarsTotalSize += seg->get_memory_size();
|
|
|
|
|
}
|
|
|
|
|
if (seg->get_flags() & PF_W) {
|
|
|
|
|
progvarsWriteSize += seg->get_memory_size();
|
|
|
|
|
}
|
|
|
|
|
} else if (seg->get_type() == PT_DYNAMIC) {
|
|
|
|
|
dynamicSize += seg->get_memory_size();
|
2018-09-25 17:47:26 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-02-23 21:18:35 -05:00
|
|
|
|
|
|
|
|
progvarsTotalSize -= dynamicSize;
|
|
|
|
|
setGlobalVariableTotalSize(progvarsTotalSize);
|
|
|
|
|
|
|
|
|
|
if (progvarsWriteSize != dynamicSize) {
|
|
|
|
|
hasGlobalStores_ = true;
|
2018-09-25 17:47:26 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 10:38:39 -04:00
|
|
|
if (!createKernelMetadataMap(binary, binSize)) {
|
2020-07-30 17:50:49 -04:00
|
|
|
buildLog_ += "Error: create kernel metadata map using COMgr\n";
|
2019-01-04 15:06:29 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-09-25 17:47:26 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-07-23 20:09:59 -04:00
|
|
|
|
|
|
|
|
amd_comgr_status_t getSymbolFromModule(amd_comgr_symbol_t symbol, void* userData) {
|
2019-08-11 18:53:11 -04:00
|
|
|
size_t nlen = 0;
|
|
|
|
|
size_t* userDataInfo = nullptr;
|
2019-07-23 20:09:59 -04:00
|
|
|
amd_comgr_status_t status;
|
|
|
|
|
amd_comgr_symbol_type_t type;
|
2019-08-11 18:53:11 -04:00
|
|
|
std::vector<std::string>* var_names = nullptr;
|
|
|
|
|
|
|
|
|
|
/* Unpack the user data */
|
|
|
|
|
SymbolInfo* sym_info = reinterpret_cast<SymbolInfo*>(userData);
|
|
|
|
|
|
|
|
|
|
if (!sym_info) {
|
|
|
|
|
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
|
|
|
|
|
}
|
2019-07-23 20:09:59 -04:00
|
|
|
|
|
|
|
|
/* Retrieve the symbol info */
|
|
|
|
|
status = amd::Comgr::symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_NAME_LENGTH, &nlen);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve the symbol name */
|
|
|
|
|
char* name = new char[nlen + 1];
|
|
|
|
|
status = amd::Comgr::symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_NAME, name);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve the symbol type*/
|
|
|
|
|
status = amd::Comgr::symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_TYPE, &type);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If symbol type is object(Variable) add it to vector */
|
2019-08-11 18:53:11 -04:00
|
|
|
if ((std::strcmp(name, "") != 0) && (type == sym_info->sym_type)) {
|
|
|
|
|
sym_info->var_names->push_back(std::string(name));
|
2019-07-23 20:09:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[] name;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-11 18:53:11 -04:00
|
|
|
bool Program::getSymbolsFromCodeObj(std::vector<std::string>* var_names,
|
|
|
|
|
amd_comgr_symbol_type_t sym_type) const {
|
2019-07-23 20:09:59 -04:00
|
|
|
amd_comgr_status_t status = AMD_COMGR_STATUS_SUCCESS;
|
|
|
|
|
amd_comgr_data_t dataObject;
|
2019-08-11 18:53:11 -04:00
|
|
|
SymbolInfo sym_info;
|
|
|
|
|
bool ret_val = true;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
/* Create comgr data */
|
|
|
|
|
status = amd::Comgr::create_data(AMD_COMGR_DATA_KIND_EXECUTABLE, &dataObject);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "COMGR: Cannot create comgr data \n";
|
|
|
|
|
ret_val = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-07-23 20:09:59 -04:00
|
|
|
|
2019-08-11 18:53:11 -04:00
|
|
|
/* Set the binary as a dataObject */
|
|
|
|
|
status = amd::Comgr::set_data(dataObject, static_cast<size_t>(clBinary_->data().second),
|
|
|
|
|
reinterpret_cast<const char*>(clBinary_->data().first));
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "COMGR: Cannot set comgr data \n";
|
|
|
|
|
ret_val = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-07-23 20:09:59 -04:00
|
|
|
|
2019-08-11 18:53:11 -04:00
|
|
|
/* Pack the user data */
|
|
|
|
|
sym_info.sym_type = sym_type;
|
|
|
|
|
sym_info.var_names = var_names;
|
2019-07-23 20:09:59 -04:00
|
|
|
|
2020-07-30 17:50:49 -04:00
|
|
|
/* Iterate through list of symbols */
|
2019-08-11 18:53:11 -04:00
|
|
|
status = amd::Comgr::iterate_symbols(dataObject, getSymbolFromModule, &sym_info);
|
|
|
|
|
if (status != AMD_COMGR_STATUS_SUCCESS) {
|
|
|
|
|
buildLog_ += "COMGR: Cannot iterate comgr symbols \n";
|
|
|
|
|
ret_val = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-09 06:47:55 -04:00
|
|
|
amd::Comgr::release_data(dataObject);
|
2019-08-11 18:53:11 -04:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
}
|
2019-07-23 20:09:59 -04:00
|
|
|
|
2019-12-04 14:22:03 -05:00
|
|
|
const bool Program::getLoweredNames(std::vector<std::string>* mangledNames) const {
|
|
|
|
|
/* Iterate thru kernel names first */
|
|
|
|
|
for (auto const& kernelMeta : kernelMetadataMap_) {
|
|
|
|
|
mangledNames->emplace_back(kernelMeta.first);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Itrate thru global vars */
|
|
|
|
|
if (!getSymbolsFromCodeObj(mangledNames, AMD_COMGR_SYMBOL_TYPE_OBJECT)) {
|
2020-04-13 22:41:44 -04:00
|
|
|
DevLogError("Cannot get Symbols from Code Obj \n");
|
2019-12-04 14:22:03 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-03-18 12:44:24 -04:00
|
|
|
|
2021-08-31 12:20:52 -07:00
|
|
|
bool Program::getDemangledName(const std::string& mangledName, std::string& demangledName) const {
|
|
|
|
|
amd_comgr_data_t mangled_data;
|
|
|
|
|
amd_comgr_data_t demangled_data;
|
|
|
|
|
|
|
|
|
|
if (AMD_COMGR_STATUS_SUCCESS != amd::Comgr::create_data(AMD_COMGR_DATA_KIND_BYTES, &mangled_data))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (AMD_COMGR_STATUS_SUCCESS !=
|
|
|
|
|
amd::Comgr::set_data(mangled_data, mangledName.size(), mangledName.c_str())) {
|
|
|
|
|
amd::Comgr::release_data(mangled_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (AMD_COMGR_STATUS_SUCCESS != amd::Comgr::demangle_symbol_name(mangled_data, &demangled_data)) {
|
|
|
|
|
amd::Comgr::release_data(mangled_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t demangled_size = 0;
|
|
|
|
|
if (AMD_COMGR_STATUS_SUCCESS != amd::Comgr::get_data(demangled_data, &demangled_size, NULL)) {
|
|
|
|
|
amd::Comgr::release_data(mangled_data);
|
|
|
|
|
amd::Comgr::release_data(demangled_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
demangledName.resize(demangled_size);
|
|
|
|
|
|
|
|
|
|
if (AMD_COMGR_STATUS_SUCCESS != amd::Comgr::get_data(demangled_data, &demangled_size,
|
|
|
|
|
const_cast<char*>(demangledName.data()))) {
|
|
|
|
|
amd::Comgr::release_data(mangled_data);
|
|
|
|
|
amd::Comgr::release_data(demangled_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amd::Comgr::release_data(mangled_data);
|
|
|
|
|
amd::Comgr::release_data(demangled_data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 12:44:24 -04:00
|
|
|
bool Program::getGlobalFuncFromCodeObj(std::vector<std::string>* func_names) const {
|
|
|
|
|
return getSymbolsFromCodeObj(func_names, AMD_COMGR_SYMBOL_TYPE_FUNC);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-11 18:53:11 -04:00
|
|
|
bool Program::getGlobalVarFromCodeObj(std::vector<std::string>* var_names) const {
|
|
|
|
|
return getSymbolsFromCodeObj(var_names, AMD_COMGR_SYMBOL_TYPE_OBJECT);
|
2019-07-23 20:09:59 -04:00
|
|
|
}
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2024-08-07 18:10:41 -04:00
|
|
|
// Init Fini Launch Lock
|
|
|
|
|
amd::Monitor Program::initFiniLock_(true);
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
bool Program::runInitFiniKernel(const std::vector<const Kernel*>& kernels) const {
|
2021-12-01 08:17:44 -08:00
|
|
|
amd::HostQueue* queue = nullptr;
|
|
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
for (const auto& kernel : kernels) {
|
|
|
|
|
amd::ScopedLock sl(initFiniLock_);
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
if (queue == nullptr) {
|
|
|
|
|
queue = new amd::HostQueue(device_().context(), device_(), 0);
|
2021-12-01 08:17:44 -08:00
|
|
|
if (queue == nullptr) {
|
2025-08-05 14:02:05 -07:00
|
|
|
LogError("Unable to create queue");
|
|
|
|
|
return false;
|
2021-12-01 08:17:44 -08:00
|
|
|
}
|
2025-08-05 14:02:05 -07:00
|
|
|
queue->create();
|
|
|
|
|
}
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
LogPrintfInfo("%s is marked init/fini", kernel->name().c_str());
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
size_t globalWorkOffset[3] = {0};
|
|
|
|
|
size_t globalWorkSize[3] = {1, 1, 1};
|
|
|
|
|
size_t localWorkSize[3] = {1, 1, 1};
|
|
|
|
|
amd::NDRangeContainer ndrange(3, globalWorkOffset, globalWorkSize, localWorkSize);
|
|
|
|
|
amd::Command::EventWaitList waitList;
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
auto symbol = owner_.findSymbol(kernel->name().c_str());
|
|
|
|
|
amd::Kernel* k = new amd::Kernel(owner_, *symbol, kernel->name().c_str());
|
|
|
|
|
if (!k) {
|
|
|
|
|
queue->release();
|
|
|
|
|
LogError("Unable to create kernel");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
amd::NDRangeKernelCommand* kernelCommand =
|
|
|
|
|
new amd::NDRangeKernelCommand(*queue, waitList, *k, ndrange);
|
|
|
|
|
if (!kernelCommand) {
|
|
|
|
|
LogError("Unale to allocate memory to launch kernel");
|
2021-12-01 08:17:44 -08:00
|
|
|
k->release();
|
2025-08-05 14:02:05 -07:00
|
|
|
queue->release();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (CL_SUCCESS != kernelCommand->captureAndValidate()) {
|
|
|
|
|
LogError("Kernel Capture and Validate failed");
|
2021-12-01 08:17:44 -08:00
|
|
|
kernelCommand->release();
|
2025-08-05 14:02:05 -07:00
|
|
|
k->release();
|
|
|
|
|
queue->release();
|
|
|
|
|
return false;
|
2021-12-01 08:17:44 -08:00
|
|
|
}
|
2025-08-05 14:02:05 -07:00
|
|
|
kernelCommand->enqueue();
|
|
|
|
|
queue->finish();
|
|
|
|
|
k->release();
|
|
|
|
|
kernelCommand->release();
|
2021-12-01 08:17:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (queue != nullptr) {
|
|
|
|
|
queue->release();
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
bool Program::runInitKernels() { return runInitFiniKernel(initKernels_); }
|
2021-12-01 08:17:44 -08:00
|
|
|
|
2025-08-05 14:02:05 -07:00
|
|
|
bool Program::runFiniKernels() { return runInitFiniKernel(finiKernels_); }
|
2024-06-06 18:40:49 +01:00
|
|
|
} /* namespace amd::device*/
|