1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
|
/* Copyright (c) 2008 - 2021 Advanced Micro Devices, Inc.
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. */
#pragma once
#if defined(WITH_COMPILER_LIB)
#include "aclTypes.h"
#endif
#include "platform/context.hpp"
#include "platform/object.hpp"
#include "platform/memory.hpp"
#if defined(USE_COMGR_LIBRARY)
#include "amd_comgr/amd_comgr.h"
#endif // defined(USE_COMGR_LIBRARY)
namespace amd {
namespace hsa {
namespace loader {
class Symbol;
} // loader
namespace code {
namespace Kernel {
class Metadata;
} // Kernel
} // code
} // hsa
} // amd
namespace amd {
class Device;
class Program;
namespace option {
class Options;
} // option
}
namespace amd::device {
class ClBinary;
class Kernel;
struct SymbolInfo {
int sym_type;
std::vector<std::string>* var_names;
};
struct SymbolLoweredName {
const char* name_expression;
std::string* loweredName;
};
//! A program object for a specific device.
class Program : public amd::HeapObject {
public:
typedef std::pair<const void* /* binary_image */, size_t /* binary size */> binary_t;
typedef std::pair<amd::Os::FileDesc /* file_desc */, size_t /* file_offset */> finfo_t;
typedef std::unordered_map<std::string, Kernel*> kernels_t;
// type of the program
typedef enum {
TYPE_NONE = 0, // uncompiled
TYPE_COMPILED, // compiled
TYPE_LIBRARY, // linked library
TYPE_EXECUTABLE, // linked executable
TYPE_INTERMEDIATE // intermediate
} type_t;
//! type of the input file
typedef enum {
FILE_TYPE_DEFAULT = 0,
FILE_TYPE_OPENCL = 1,
FILE_TYPE_LLVMIR_TEXT = 2,
FILE_TYPE_LLVMIR_BINARY = 3,
FILE_TYPE_SPIR_TEXT = 4,
FILE_TYPE_SPIR_BINARY = 5,
FILE_TYPE_AMDIL_TEXT = 6,
FILE_TYPE_AMDIL_BINARY = 7,
FILE_TYPE_HSAIL_TEXT = 8,
FILE_TYPE_HSAIL_BINARY = 9,
FILE_TYPE_X86_TEXT = 10,
FILE_TYPE_X86_BINARY = 11,
FILE_TYPE_CG = 12,
FILE_TYPE_SOURCE = 13,
FILE_TYPE_ISA = 14,
FILE_TYPE_HEADER = 15,
FILE_TYPE_RSLLVMIR_BINARY = 16,
FILE_TYPE_SPIRV_BINARY = 17,
FILE_TYPE_ASM_TEXT = 18,
FILE_TYPE_LAST = 19
} file_type_t;
private:
//! The device target for this binary.
amd::SharedReference<amd::Device> device_;
amd::Program& owner_; //!< owner of this program
kernels_t kernels_; //!< The kernel entry points this binary.
type_t type_; //!< type of this program
typedef enum { InitKernel = 0, FiniKernel } kernel_kind_t; //!< Kernel kind
bool runInitFiniKernel(kernel_kind_t) const;
#if defined(WITH_COMPILER_LIB)
static amd::Monitor buildLock_; //!< Global build lock for HSAIL which isn't thread-safe
#endif
protected:
union {
struct {
uint32_t isNull_ : 1; //!< Null program no memory allocations
uint32_t internal_ : 1; //!< Internal blit program
uint32_t isLC_ : 1; //!< LC was used for the program compilation
uint32_t hasGlobalStores_ : 1; //!< Program has writable program scope variables
uint32_t isHIP_ : 1; //!< Determine if the program is for HIP
uint32_t coLoaded_ : 1; //!< Has the code objected been loaded
uint32_t trapHandler_ : 1; //!< It is a trap handler for debugger
};
uint32_t flags_; //!< Program flags
};
ClBinary* clBinary_; //!< The CL program binary file
std::string llvmBinary_; //!< LLVM IR binary code
amd::Elf::ElfSections elfSectionType_; //!< LLVM IR binary code is in SPIR format
std::string compileOptions_; //!< compile/build options.
std::string linkOptions_; //!< link options.
//!< the option arg passed in to clCompileProgram(), clLinkProgram(),
//! or clBuildProgram(), whichever is called last
#if defined(WITH_COMPILER_LIB)
aclBinaryOptions binOpts_; //!< Binary options to create aclBinary
aclBinary* binaryElf_; //!< Binary for the new compiler library
#endif
std::string lastBuildOptionsArg_;
mutable std::string buildLog_; //!< build log.
int32_t buildStatus_; //!< build status.
int32_t buildError_; //!< build error
#if defined(WITH_COMPILER_LIB)
aclTargetInfo info_; //!< The info target for this binary.
#endif
size_t globalVariableTotalSize_;
amd::option::Options* programOptions_;
#if defined(USE_COMGR_LIBRARY)
amd_comgr_metadata_node_t metadata_ = {}; //!< COMgr metadata
uint32_t codeObjectVer_; //!< version of code object
std::map<std::string, amd_comgr_metadata_node_t> kernelMetadataMap_; //!< Map of kernel metadata
#endif
//! Sanitizer lock - lock when launching init/fini kernels
static amd::Monitor initFiniLock_;
public:
//! Construct a section.
Program(amd::Device& device, amd::Program& owner);
//! Destroy this binary image.
virtual ~Program();
//! Destroy all the kernels
void clear();
amd::Program* owner() const { return &owner_; }
//! Return the compiler options passed to build this program
amd::option::Options* getCompilerOptions() const { return programOptions_; }
//! Compile the device program.
int32_t compile(const std::string& sourceCode, const std::vector<const std::string*>& headers,
const char** headerIncludeNames, const char* origOptions,
amd::option::Options* options);
//! Link the device program.
int32_t link(const std::vector<Program*>& inputPrograms, const char* origLinkOptions,
amd::option::Options* linkOptions);
//! Build the device program.
int32_t build(const std::string& sourceCode, const char* origOptions,
amd::option::Options* options, const std::vector<std::string>& preCompiledHeaders);
//! Load the device program.
bool load();
//! Return the device object, associated with this program.
const amd::Device& device() const { return device_(); }
//! Return the compiler options used to build the program.
const std::string& compileOptions() const { return compileOptions_; }
const std::string& linkOptions() const { return linkOptions_; }
//! Return the option arg passed in to clCompileProgram(), clLinkProgram(),
//! or clBuildProgram(), whichever is called last
const std::string lastBuildOptionsArg() const { return lastBuildOptionsArg_; }
//! Return the build log.
const std::string& buildLog() const { return buildLog_; }
//! Return the build status.
cl_build_status buildStatus() const { return buildStatus_; }
//! Return the build error.
int32_t buildError() const { return buildError_; }
//! Return the symbols vector.
const kernels_t& kernels() const { return kernels_; }
kernels_t& kernels() { return kernels_; }
//! Return the binary image.
inline const binary_t binary() const;
inline binary_t binary();
inline finfo_t BinaryFd() const;
inline std::string BinaryURI() const;
//! Returns the CL program binary file
ClBinary* clBinary() { return clBinary_; }
const ClBinary* clBinary() const { return clBinary_; }
bool setBinary(const char* binaryIn, size_t size, const device::Program* same_dev_prog = nullptr,
amd::Os::FileDesc fdesc = amd::Os::FDescInit(), size_t foffset = 0,
std::string uri = std::string());
type_t type() const { return type_; }
void setGlobalVariableTotalSize(size_t size) { globalVariableTotalSize_ = size; }
size_t globalVariableTotalSize() const { return globalVariableTotalSize_; }
#if defined(WITH_COMPILER_LIB)
//! Returns the aclBinary associated with the program
aclBinary* binaryElf() const { return static_cast<aclBinary*>(binaryElf_); }
#endif
//! Returns TRUE if the program just compiled
bool isNull() const { return isNull_; }
//! Returns TRUE if the program used internally by runtime
bool isInternal() const { return internal_; }
//! Returns TRUE if Lightning compiler was used for this program
bool isLC() const { return isLC_; }
//! Global variables are a part of the code segment
bool hasGlobalStores() const { return hasGlobalStores_; }
//! Return TRUE if the program has been loaded
bool isCodeObjectLoaded() const { return coLoaded_; }
//! Returns TRUE if the program is a trap handler for debugger support
bool isTrapHandler() const { return trapHandler_; }
#if defined(USE_COMGR_LIBRARY)
amd_comgr_metadata_node_t metadata() const { return metadata_; }
//! Get the kernel metadata
const bool getKernelMetadata(const std::string name, amd_comgr_metadata_node_t* meta) const {
auto it = kernelMetadataMap_.find(name);
if (it != kernelMetadataMap_.end()) {
*meta = it->second;
return true;
}
return false;
}
const uint32_t codeObjectVer() const { return codeObjectVer_; }
#endif
//! Check if program is HIP based
const bool isHIP() const { return (isHIP_ == 1); }
//! Get mangled name of a name expresion
const bool getLoweredNames(std::vector<std::string>* mangledNames) const;
//! Get demangled names
bool getDemangledName(const std::string& mangledNames, std::string& demangledNames) const;
bool getGlobalFuncFromCodeObj(std::vector<std::string>* func_names) const;
bool getGlobalVarFromCodeObj(std::vector<std::string>* var_names) const;
bool getUndefinedVarFromCodeObj(std::vector<std::string>* var_names) const;
virtual bool createGlobalVarObj(amd::Memory** amd_mem_obj, void** dptr,
size_t* bytes, const char* globalName) const {
ShouldNotReachHere();
return false;
}
//! Run kernels marked with "init" kind metadata
bool runInitKernels();
//! Run kernels marked with "fini" kind metadata
bool runFiniKernels();
protected:
//! pre-compile setup
bool initBuild(amd::option::Options* options);
//! post-compile cleanup
bool finiBuild(bool isBuildGood);
/*! \brief Compiles GPU CL program to LLVM binary (compiler frontend)
*
* \return True if we successefully compiled a GPU program
*/
virtual bool compileImpl(
const std::string& sourceCode, //!< the program's source code
const std::vector<const std::string*>& headers, const char** headerIncludeNames,
amd::option::Options* options, //!< compile options's object
const std::vector<std::string>& preCompiledHeaders //!< precompiled headers
);
//! Link the device program.
virtual bool linkImpl(amd::option::Options* options);
//! Link the device programs.
virtual bool linkImpl(const std::vector<Program*>& inputPrograms, amd::option::Options* options,
bool createLibrary);
virtual bool createBinary(amd::option::Options* options) = 0;
//! Initialize Binary (used only for clCreateProgramWithBinary()).
bool initClBinary(const char* binaryIn, size_t size,
amd::Os::FileDesc fdesc = amd::Os::FDescInit(),
size_t foffset = 0, std::string uri = std::string());
//! Initialize Binary
virtual bool initClBinary();
virtual bool saveBinaryAndSetType(type_t type) = 0;
//! Release the Binary
void releaseClBinary();
#if defined(WITH_COMPILER_LIB)
//! return target info
virtual const aclTargetInfo& info() = 0;
#endif
virtual bool createKernels(void* binary, size_t binSize, bool useUniformWorkGroupSize,
bool internalKernel) { return true; }
virtual bool setKernels(
void* binary, size_t binSize,
amd::Os::FileDesc fdesc = amd::Os::FDescInit(), size_t foffset = 0,
std::string uri = std::string()) { return true; }
//! Returns all the options to be appended while passing to the compiler library
std::vector<std::string> ProcessOptions(amd::option::Options* options);
//! Returns all the options to be appended while passing to the compiler library,
//! flattened into one string.
std::string ProcessOptionsFlattened(amd::option::Options* options);
//! At linking time, get the set of compile options to be used from
//! the set of input program, warn if they have inconsisten compile options.
bool getCompileOptionsAtLinking(const std::vector<Program*>& inputPrograms,
const amd::option::Options* linkOptions);
void setType(type_t newType) { type_ = newType; }
/* \brief Returns the next stage to compile from, based on sections in binary,
* also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT,
* sets needOptionsCheck to true if options check is needed to decide whether or not to recompile
*/
file_type_t getCompilationStagesFromBinary(
std::vector<file_type_t>& completeStages,
bool& needOptionsCheck);
/* \brief Returns the next stage to compile from, based on sections and options in binary
*/
file_type_t getNextCompilationStageFromBinary(amd::option::Options* options);
//! Finds the total size of all global variables in the program
bool FindGlobalVarSize(void* binary, size_t binSize);
bool isElf(const char* bin) const { return amd::Elf::isElfMagic(bin); }
virtual bool defineGlobalVar(const char* name, void* dptr) {
ShouldNotReachHere();
return false;
}
#if defined(USE_COMGR_LIBRARY)
bool getSymbolsFromCodeObj(std::vector<std::string>* var_names, amd_comgr_symbol_type_t sym_type) const;
#endif
bool getUndefinedVarInfo(std::string var_name, void** var_addr, size_t* var_size);
bool defineUndefinedVars();
private:
//! Compile the device program with LC path
bool compileImplLC(const std::string& sourceCode, const std::vector<const std::string*>& headers,
const char** headerIncludeNames, amd::option::Options* options,
const std::vector<std::string>& preCompiledHeaders);
//! Compile the device program with HSAIL path
bool compileImplHSAIL(const std::string& sourceCode,
const std::vector<const std::string*>& headers,
const char** headerIncludeNames, amd::option::Options* options);
//! Link the device programs with LC path
bool linkImplLC(const std::vector<Program*>& inputPrograms,
amd::option::Options* options, bool createLibrary);
//! Link the device programs with HSAIL path
bool linkImplHSAIL(const std::vector<Program*>& inputPrograms,
amd::option::Options* options, bool createLibrary);
//! Link the device program with LC path
bool linkImplLC(amd::option::Options* options);
//! Link the device program with HSAIL path
bool linkImplHSAIL(amd::option::Options* options);
//! Load the device program with LC path
bool loadLC();
//! Load the device program with HSAIL path
bool loadHSAIL();
#if defined(USE_COMGR_LIBRARY)
//! Dump the log data object to the build log, if a log data object is present
void extractBuildLog(amd_comgr_data_set_t dataSet);
//! Dump the code object data
amd_comgr_status_t extractByteCodeBinary(const amd_comgr_data_set_t inDataSet,
const amd_comgr_data_kind_t dataKind, const std::string& outFileName,
char* outBinary[] = nullptr, size_t* outSize = nullptr);
//! Create code object and add it into the data set
amd_comgr_status_t addCodeObjData(const char *source,
const size_t size, const amd_comgr_data_kind_t type,
const char* name, amd_comgr_data_set_t* dataSet);
//! Add precompiled headers to the data set
amd_comgr_status_t addPreCompiledHeader(amd_comgr_data_set_t* dataSet,
const std::vector<std::string>& preCompiledHeaders);
//! Create action for the specified language, target and options
amd_comgr_status_t createAction(const amd_comgr_language_t oclver,
const std::vector<std::string>& options, amd_comgr_action_info_t* action,
bool* hasAction);
//! Create the bitcode of the linked input dataset
bool linkLLVMBitcode(const amd_comgr_data_set_t inputs,
const std::vector<std::string>& options,
amd::option::Options* amdOptions, amd_comgr_data_set_t* output,
char* binaryData[] = nullptr, size_t* binarySize = nullptr);
//! Create the bitcode of the compiled input dataset
bool compileToLLVMBitcode(const amd_comgr_data_set_t compileInputs,
const std::vector<std::string>& options, amd::option::Options* amdOptions,
char* binaryData[], size_t* binarySize,
const bool link_dev_libs = true);
//! Compile and create the excutable of the input dataset
bool compileAndLinkExecutable(const amd_comgr_data_set_t inputs,
const std::vector<std::string>& options, amd::option::Options* amdOptions, char* executable[],
size_t* executableSize, file_type_t continueCompileFrom);
//! Create the map for the kernel name and its metadata for fast access
bool createKernelMetadataMap(void* binary, size_t binSize);
#endif
bool trySubstObjFile(const char *SubstCfgFile,
const std::string& sourceCode,
const amd::option::Options* options);
//! Disable default copy constructor
Program(const Program&);
//! Disable operator=
Program& operator=(const Program&);
};
#if defined(USE_COMGR_LIBRARY)
class ComgrBinaryData {
public:
ComgrBinaryData() : binaryData_({0}), created_(false) {}
~ComgrBinaryData();
bool create(amd_comgr_data_kind_t kind, void* binary, size_t binSize);
amd_comgr_data_t& data();
private:
amd_comgr_data_t binaryData_;
bool created_;
};
#endif
} // namespace amd::device
|