P4 to Git Change 1329974 by lmoriche@lmoriche_opencl_dev on 2016/10/21 13:09:44

SWDEV-105604 - OpenCL program manager for LC on PAL (Initial check-in)
	- Created LightningProgram and LightningKernel classes
	- Implemented LightningProgram::compileImpl and LightningProgram::linkImpl using LC
	- Implemented LightningKernel::init (to set up args using the LC metadata)
	Tests: Passes clinfo and HelloWorld.
	Pre-checkin: http://ocltc.amd.com:8111/viewModification.html?modId=77957&personal=true&buildTypeId=&tab=vcsModificationBuilds&show_all_builds=true

Affected files ...

... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/build/Makefile.api#141 edit
... //depot/stg/opencl/drivers/opencl/compiler/Makefile#67 edit
... //depot/stg/opencl/drivers/opencl/compiler/sclibdefs.opencl#11 edit
... //depot/stg/opencl/drivers/opencl/library/build/Makefile.library#57 edit
... //depot/stg/opencl/drivers/opencl/make/llvm.git/lib/Target/Makefile#2 edit
... //depot/stg/opencl/drivers/opencl/make/llvm.git/llvmdefs#3 edit
... //depot/stg/opencl/drivers/opencl/make/llvm.git/llvmlibs#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/build/Makefile.pal#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palcompiler.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldefs.hpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldevice.cpp#26 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldevice.hpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palkernel.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palkernel.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.hpp#8 edit
このコミットが含まれているのは:
foreman
2016-10-21 13:18:35 -04:00
コミット cd17800734
8個のファイルの変更、1355行の追加、52行の削除
+457 -29
ファイルの表示
@@ -18,6 +18,12 @@
#include "hsa.h"
#include "hsa_ext_image.h"
#include "amd_hsa_loader.hpp"
#if defined(WITH_LIGHTNING_COMPILER)
#include "libamdhsacode/amdgpu_metadata.hpp"
#include "driver/AmdCompiler.h"
#include "libraries.amdgcn.inc"
#include "gelf.h"
#endif // !defined(WITH_LIGHTNING_COMPILER)
namespace pal {
@@ -67,6 +73,7 @@ HSAILProgram::~HSAILProgram()
for (auto& it : staticSamplers_) {
delete it;
}
#if !defined(WITH_LIGHTNING_COMPILER)
if (rawBinary_ != nullptr) {
aclFreeMem(binaryElf_, rawBinary_);
}
@@ -78,6 +85,7 @@ HSAILProgram::~HSAILProgram()
LogWarning( "Error while destroying the acl binary \n" );
}
}
#endif // !defined(WITH_LIGHTNING_COMPILER)
releaseClBinary();
if (executable_ != nullptr) {
loader_->DestroyExecutable(executable_);
@@ -135,6 +143,10 @@ HSAILProgram::linkImpl(
amd::option::Options *options,
bool createLibrary)
{
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
return false;
#else // !defined(WITH_LIGHTNING_COMPILER)
std::vector<device::Program *>::const_iterator it
= inputPrograms.begin();
std::vector<device::Program *>::const_iterator itEnd
@@ -222,11 +234,16 @@ HSAILProgram::linkImpl(
}
// Now call linkImpl with the new options
return linkImpl(options);
#endif // !defined(WITH_LIGHTNING_COMPILER)
}
aclType
HSAILProgram::getCompilationStagesFromBinary(std::vector<aclType>& completeStages, bool& needOptionsCheck)
{
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
return ACL_TYPE_DEFAULT;
#else // !defined(WITH_LIGHTNING_COMPILER)
acl_error errorCode;
size_t secSize = 0;
completeStages.clear();
@@ -343,10 +360,15 @@ HSAILProgram::getCompilationStagesFromBinary(std::vector<aclType>& completeStage
break;
}
return from;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}
aclType
HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* options) {
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
return ACL_TYPE_DEFAULT;
#else // !defined(WITH_LIGHTNING_COMPILER)
aclType continueCompileFrom = ACL_TYPE_DEFAULT;
binary_t binary = this->binary();
// If the binary already exists
@@ -423,6 +445,7 @@ HSAILProgram::getNextCompilationStageFromBinary(amd::option::Options* options) {
}
}
return continueCompileFrom;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}
inline static std::vector<std::string>
@@ -438,6 +461,10 @@ splitSpaceSeparatedString(char *str)
bool
HSAILProgram::linkImpl(amd::option::Options* options)
{
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
return false;
#else // !defined(WITH_LIGHTNING_COMPILER)
acl_error errorCode;
aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY;
bool finalize = true;
@@ -580,6 +607,7 @@ HSAILProgram::linkImpl(amd::option::Options* options)
saveBinaryAndSetType(TYPE_EXECUTABLE);
buildLog_ += aclGetCompilerLog(dev().compiler());
return true;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}
bool
@@ -621,9 +649,11 @@ HSAILProgram::hsailOptions()
if (dev().settings().reportFMA_) {
hsailOptions.append(" -DFP_FAST_FMA=1");
}
#if !defined(WITH_LIGHTNING_COMPILER)
if (!dev().settings().singleFpDenorm_) {
hsailOptions.append(" -cl-denorms-are-zero");
}
#endif // !defined(WITH_LIGHTNING_COMPILER)
// Check if the host is 64 bit or 32 bit
LP64_ONLY(hsailOptions.append(" -m64"));
@@ -677,7 +707,11 @@ HSAILProgram::fillResListWithKernels(
}
const aclTargetInfo &
HSAILProgram::info(const char * str) {
HSAILProgram::info(const char * str)
{
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
#else // !defined(WITH_LIGHTNING_COMPILER)
acl_error err;
std::string arch = "hsail";
if (dev().settings().use64BitPtr_) {
@@ -688,12 +722,16 @@ HSAILProgram::info(const char * str) {
if (err != ACL_SUCCESS) {
LogWarning("aclGetTargetInfo failed");
}
#endif // !defined(WITH_LIGHTNING_COMPILER)
return info_;
}
bool
HSAILProgram::saveBinaryAndSetType(type_t type)
{
#if defined(WITH_LIGHTNING_COMPILER)
assert(!"Should not reach here");
#else // !defined(WITH_LIGHTNING_COMPILER)
//Write binary to memory
if (rawBinary_ != nullptr) {
//Free memory containing rawBinary
@@ -708,6 +746,7 @@ HSAILProgram::saveBinaryAndSetType(type_t type)
setBinary(static_cast<char*>(rawBinary_), size);
//Set the type of binary
setType(type);
#endif // !defined(WITH_LIGHTNING_COMPILER)
return true;
}
@@ -729,38 +768,21 @@ bool ORCAHSALoaderContext::IsaSupportedByAgent(hsa_agent_t agent, hsa_isa_t isa)
default:
LogError("Unsupported gfxip version");
return false;
case gfx700:
case gfx701:
case gfx702:
case gfx700: case gfx701: case gfx702:
// gfx701 only differs from gfx700 by faster fp operations and can be loaded on either device.
return isa.handle == gfx700 || isa.handle == gfx701;
case gfx800:
switch (program_->dev().asicRevision()) {
case Pal::AsicRevision::Iceland:
case Pal::AsicRevision::Tonga:
return isa.handle == gfx800;
case Pal::AsicRevision::Carrizo:
return isa.handle == gfx801;
case Pal::AsicRevision::Fiji:
case Pal::AsicRevision::Ellesmere:
case Pal::AsicRevision::Baffin:
// gfx800 ISA has only sgrps limited and can be loaded.
// gfx801 ISA has XNACK limitations and can be loaded.
return isa.handle == gfx800 || isa.handle == gfx801 || isa.handle == gfx804;
case Pal::AsicRevision::Stoney:
return isa.handle == gfx800;
case gfx801:
return isa.handle == gfx801;
case gfx804:
// gfx800 ISA has only sgrps limited and can be loaded.
// gfx801 ISA has XNACK limitations and can be loaded.
return isa.handle == gfx800 || isa.handle == gfx801 || isa.handle == gfx804;
case gfx810:
return isa.handle == gfx810;
default:
assert(0 && "Unknown asic!");
return false;
}
case gfx900:
switch (program_->dev().ipLevel()) {
case Pal::GfxIpLevel::GfxIp9:
return isa.handle == gfx900 || isa.handle == gfx901;
default:
assert(0 && "Unknown asic!");
return false;
}
case gfx900: case gfx901:
return isa.handle == gfx900 || isa.handle == gfx901;
}
}
@@ -960,4 +982,410 @@ void ORCAHSALoaderContext::GpuMemFree(void *ptr, size_t size)
}
}
#if defined(WITH_LIGHTNING_COMPILER)
static hsa_status_t
GetKernelNamesCallback(
hsa_executable_t hExec,
hsa_executable_symbol_t hSymbol,
void *data)
{
auto symbol = Symbol::Object(hSymbol);
auto symbolNameList = reinterpret_cast<std::vector<std::string>*>(data);
hsa_symbol_kind_t type;
if (!symbol->GetInfo(HSA_EXECUTABLE_SYMBOL_INFO_TYPE, &type)) {
return HSA_STATUS_ERROR;
}
if (type == HSA_SYMBOL_KIND_KERNEL) {
uint32_t length;
if (!symbol->GetInfo(HSA_EXECUTABLE_SYMBOL_INFO_NAME_LENGTH, &length)) {
return HSA_STATUS_ERROR;
}
char* name = (char*) alloca(length+1);
if (!symbol->GetInfo(HSA_EXECUTABLE_SYMBOL_INFO_NAME, name)) {
return HSA_STATUS_ERROR;
}
name[length] = '\0';
symbolNameList->push_back(std::string(name));
}
return HSA_STATUS_SUCCESS;
}
bool
LightningProgram::linkImpl(amd::option::Options *options)
{
using namespace amd::opencl_driver;
internal_ = (compileOptions_.find("-cl-internal-kernel") !=
std::string::npos) ? true : false;
aclType continueCompileFrom = llvmBinary_.empty()
? getNextCompilationStageFromBinary(options)
: ACL_TYPE_LLVMIR_BINARY;
if (continueCompileFrom == ACL_TYPE_ISA) {
binary_t isa = binary();
if ((isa.first != NULL) && (isa.second > 0)) {
return setKernels(options, (void*) isa.first, isa.second );
}
else {
buildLog_ += "Error: code object is empty \n" ;
return false;
}
return true;
}
if (continueCompileFrom != ACL_TYPE_LLVMIR_BINARY) {
buildLog_ += "Error while Codegen phase: the binary is incomplete \n" ;
return false;
}
std::auto_ptr<Compiler> C(newCompilerInstance());
// call LinkLLVMBitcode
std::vector<Data*> inputs;
// open the input IR source
Data* input = C->NewBufferReference(
DT_LLVM_BC, llvmBinary_.data(), llvmBinary_.size());
if (!input) {
buildLog_ += "Error: Failed to open the compiled program.\n";
return false;
}
inputs.push_back(input); //< must be the first input
// open the bitcode libraries
Data* opencl_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) opencl_amdgcn, opencl_amdgcn_size);
Data* ocml_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) ocml_amdgcn, ocml_amdgcn_size);
Data* ockl_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) ockl_amdgcn, ockl_amdgcn_size);
Data* irif_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) irif_amdgcn, irif_amdgcn_size);
if (!opencl_bc || !ocml_bc || !ockl_bc || !irif_bc) {
buildLog_ += "Error: Failed to open the bitcode library.\n";
return false;
}
inputs.push_back(opencl_bc); // depends on oclm & ockl
inputs.push_back(ockl_bc); // depends on irif
inputs.push_back(ocml_bc); // depends on irif
inputs.push_back(irif_bc);
// open the control functions
std::pair<const void*, size_t> isa_version;
switch (dev().hwInfo()->gfxipVersion_) {
case 700: isa_version = std::make_pair(
oclc_isa_version_700_amdgcn, oclc_isa_version_700_amdgcn_size);
break;
case 701: isa_version = std::make_pair(
oclc_isa_version_701_amdgcn, oclc_isa_version_701_amdgcn_size);
break;
case 800: isa_version = std::make_pair(
oclc_isa_version_800_amdgcn, oclc_isa_version_800_amdgcn_size);
break;
case 801: isa_version = std::make_pair(
oclc_isa_version_801_amdgcn, oclc_isa_version_801_amdgcn_size);
break;
case 802: isa_version = std::make_pair(
oclc_isa_version_802_amdgcn, oclc_isa_version_802_amdgcn_size);
break;
case 803: case 804: isa_version = std::make_pair(
oclc_isa_version_803_amdgcn, oclc_isa_version_803_amdgcn_size);
break;
case 810: isa_version = std::make_pair(
oclc_isa_version_810_amdgcn, oclc_isa_version_810_amdgcn_size);
break;
default:
buildLog_ += "Error: Linking for this device is not supported\n";
return false;
}
Data* isa_version_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) isa_version.first, isa_version.second);
if (!isa_version_bc) {
buildLog_ += "Error: Failed to open the control functions.\n";
return false;
}
inputs.push_back(isa_version_bc);
auto correctly_rounded_sqrt = (options->oVariables->FP32RoundDivideSqrt)
? std::make_pair(
oclc_correctly_rounded_sqrt_on_amdgcn,
oclc_correctly_rounded_sqrt_on_amdgcn_size)
: std::make_pair(
oclc_correctly_rounded_sqrt_off_amdgcn,
oclc_correctly_rounded_sqrt_off_amdgcn_size);
auto daz_opt = (dev().hwInfo()->gfxipVersion_ < 900
|| options->oVariables->DenormsAreZero)
? std::make_pair(
oclc_daz_opt_on_amdgcn,
oclc_daz_opt_on_amdgcn_size)
: std::make_pair(
oclc_daz_opt_off_amdgcn,
oclc_daz_opt_off_amdgcn_size);
auto finite_only = (options->oVariables->FiniteMathOnly
|| options->oVariables->FastRelaxedMath)
? std::make_pair(
oclc_finite_only_on_amdgcn,
oclc_finite_only_on_amdgcn_size)
: std::make_pair(
oclc_finite_only_off_amdgcn,
oclc_finite_only_off_amdgcn_size);
auto unsafe_math = (options->oVariables->UnsafeMathOpt
|| options->oVariables->FastRelaxedMath)
? std::make_pair(
oclc_unsafe_math_on_amdgcn,
oclc_unsafe_math_on_amdgcn_size)
: std::make_pair(
oclc_unsafe_math_off_amdgcn,
oclc_unsafe_math_off_amdgcn_size);
Data* correctly_rounded_sqrt_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) correctly_rounded_sqrt.first, correctly_rounded_sqrt.second);
Data* daz_opt_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) daz_opt.first, daz_opt.second);
Data* finite_only_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) finite_only.first, finite_only.second);
Data* unsafe_math_bc = C->NewBufferReference(DT_LLVM_BC,
(const char*) unsafe_math.first, unsafe_math.second);
if (!correctly_rounded_sqrt_bc || !daz_opt_bc || !finite_only_bc || !unsafe_math_bc) {
buildLog_ += "Error: Failed to open the control functions.\n";
return false;
}
inputs.push_back(correctly_rounded_sqrt_bc);
inputs.push_back(daz_opt_bc);
inputs.push_back(finite_only_bc);
inputs.push_back(unsafe_math_bc);
// open the linked output
std::vector<std::string> linkOptions;
amd::opencl_driver::Buffer* linked_bc = C->NewBuffer(DT_LLVM_BC);
if (!linked_bc) {
buildLog_ += "Error: Failed to open the linked program.\n";
return false;
}
bool ret = C->LinkLLVMBitcode(inputs, linked_bc, linkOptions);
buildLog_ += C->Output();
if (!ret) {
buildLog_ += "Error: Linking bitcode failed: linking source & IR libraries.\n";
return false;
}
if (options->isDumpFlagSet(amd::option::DUMP_BC_LINKED)) {
std::ofstream f(options->getDumpFileName("_linked.bc").c_str(), std::ios::trunc);
if(f.is_open()) {
f.write(linked_bc->Buf().data(), linked_bc->Size());
} else {
buildLog_ +=
"Warning: opening the file to dump the linked IR failed.\n";
}
}
inputs.clear();
inputs.push_back(linked_bc);
amd::opencl_driver::Buffer* out_exec = C->NewBuffer(DT_EXECUTABLE);
if (!out_exec) {
buildLog_ += "Error: Failed to create the linked executable.\n";
return false;
}
std::string codegenOptions(options->llvmOptions);
// Set the machine target
std::ostringstream mCPU;
mCPU << " -mcpu=gfx" << dev().hwInfo()->gfxipVersion_;
codegenOptions.append(mCPU.str());
// Set the -O#
std::ostringstream optLevel;
optLevel << "-O" << options->oVariables->OptLevel;
codegenOptions.append(" ").append(optLevel.str());
// Tokenize the options string into a vector of strings
std::istringstream strstr(codegenOptions);
std::istream_iterator<std::string> sit(strstr), end;
std::vector<std::string> params(sit, end);
ret = C->CompileAndLinkExecutable(inputs, out_exec, params);
buildLog_ += C->Output();
if (!ret) {
buildLog_ += "Error: Creating the executable failed: Compiling LLVM IRs to exe.\n";
return false;
}
if (options->isDumpFlagSet(amd::option::DUMP_O)) {
std::ofstream f(options->getDumpFileName(".so").c_str(), std::ios::trunc);
if(f.is_open()) {
f.write(out_exec->Buf().data(), out_exec->Size());
} else {
buildLog_ +=
"Warning: opening the file to dump the code object failed.\n";
}
}
return setKernels(options, out_exec->Buf().data(), out_exec->Size());
}
bool
LightningProgram::setKernels(
amd::option::Options *options,
void* binary,
size_t size
)
{
hsa_agent_t agent;
agent.handle = 1;
executable_ = loader_->CreateExecutable(HSA_PROFILE_FULL, NULL);
if (executable_ == nullptr) {
buildLog_ += "Error: Executable for AMD HSA Code Object isn't created.\n";
return false;
}
hsa_code_object_t code_object;
code_object.handle = reinterpret_cast<uint64_t>(binary);
hsa_status_t status = executable_->LoadCodeObject(agent, code_object, nullptr);
if (status != HSA_STATUS_SUCCESS) {
buildLog_ += "Error: AMD HSA Code Object loading failed.\n";
return false;
}
/* FIXME_lmoriche: We need to call this!
status = executable_->Freeze(nullptr);
if (status != HSA_STATUS_SUCCESS) {
buildLog_ += "Error: Freezing the executable failed: ";
return false;
}*/
size_t progvarsTotalSize = 0;
// Begin the Elf image from memory
Elf* e = elf_memory((char*) binary, size, NULL);
if (elf_kind(e) != ELF_K_ELF) {
buildLog_ += "Error while reading the ELF program binary\n";
return false;
}
size_t shstrndx;
if (elf_getshdrstrndx(e, &shstrndx) != 0) {
buildLog_ += "Error while reading the ELF program binary\n";
return false;
}
// Iterate over the sections
for (Elf_Scn* scn = elf_nextscn(e, 0); scn; scn = elf_nextscn(e, scn)) {
GElf_Shdr shdr;
if (gelf_getshdr(scn, &shdr) != &shdr) {
continue;
}
// Skip non-program sections
if (shdr.sh_type != SHT_PROGBITS) {
continue;
}
// Accumulate the size of A & !X sections
if ((shdr.sh_flags & SHF_ALLOC) && !(shdr.sh_flags & SHF_EXECINSTR)) {
progvarsTotalSize += shdr.sh_size;
}
// Check if this is the metadata section
const char* name = elf_strptr(e, shstrndx , shdr.sh_name);
if (name && !strcmp(name, ".AMDGPU.runtime_metadata")) {
// Assume a single Elf_Data, the parser will fail if it isn't
Elf_Data* data = elf_getdata(scn, NULL);
if (!data) {
buildLog_ += "Error while reading ELF program binary " \
"runtime metadata section\n";
return false;
}
metadata_ = new amd::hsa::code::Program::Metadata();
if (!metadata_ || !metadata_->ReadFrom(data->d_buf, data->d_size)) {
buildLog_ += "Error while parsing ELF program binary " \
"runtime metadata section\n";
return false;
}
}
}
elf_end(e);
if (!metadata_) {
buildLog_ += "Error: runtime metadata section not present in " \
"ELF program binary\n";
return false;
}
setGlobalVariableTotalSize(progvarsTotalSize);
// Get the list of kernels
std::vector<std::string> kernelNameList;
status = executable_->IterateSymbols(GetKernelNamesCallback,
(void *) &kernelNameList );
if (status != HSA_STATUS_SUCCESS) {
buildLog_ += "Error: Failed to get kernel names\n";
return false;
}
for (auto &kernelName : kernelNameList) {
auto kernel = new LightningKernel(
kernelName, this, options->origOptionStr + hsailOptions());
kernels()[kernelName] = kernel;
auto symbol = executable_->GetSymbol("", kernelName.c_str(), agent, 0);
if (!symbol) {
buildLog_ += "Error: Getting kernel symbol '" + kernelName
+ "' from AMD HSA Code Object failed. " \
"Kernel initialization failed.\n";
return false;
}
if (!kernel->init(symbol)) {
buildLog_ += "Error: Kernel '" + kernelName
+ "' initialization failed.\n";
return false;
}
buildLog_ += kernel->buildLog();
kernel->setUniformWorkGroupSize(options->oVariables->UniformWorkGroupSize);
// Find max scratch regs used in the program. It's used for scratch buffer preallocation
// with dynamic parallelism, since runtime doesn't know which child kernel will be called
maxScratchRegs_ = std::max(static_cast<uint>(kernel->workGroupInfo()->scratchRegs_), maxScratchRegs_);
}
// Allocate kernel table for device enqueuing
if (!isNull() && false/*dynamicParallelism*/ && !allocKernelTable()) {
return false;
}
// Save the binary and type
clBinary()->saveBIFBinary((char*)binary, size);
setType(TYPE_EXECUTABLE);
return true;
}
LightningProgram::~LightningProgram()
{
delete metadata_;
}
#endif // defined(WITH_LIGHTNING_COMPILER)
} // namespace pal