Skip to content

Commit e9e207d

Browse files
authored
SWDEV-517941 - use device bitcode before spirv (#95)
Also add flag: HIP_FORCE_SPIRV_CODEOBJECT to allow override to force use SPIRV. * use cache for already compiled code objects * address review comments and use the two spirv isa names [ROCm/clr commit: 07e57a1]
1 parent b389f97 commit e9e207d

File tree

2 files changed

+69
-41
lines changed

2 files changed

+69
-41
lines changed

projects/clr/hipamd/src/hip_fatbin.cpp

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,15 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi
317317
std::string device_name = device->devices()[0]->isa().isaName();
318318
unique_isa_names.insert({device_name, std::make_pair<size_t, size_t>(0, 0)});
319319
}
320-
// Add the spirv target
321-
const std::string spirv_isa_name = "spirv64-amd-amdhsa--amdgcnspirv";
322-
unique_isa_names.insert({spirv_isa_name, std::make_pair<size_t, size_t>(0, 0)});
320+
321+
// there are two spirv targets, spirv64-amd-amdhsa--amdgcnspirv and
322+
// spirv64-amd-amdhsa-unknown-amdgcnspirv.
323+
// eventually we will remove spirv64-amd-amdhsa--amdgcnspirv
324+
const std::vector<std::string> spirv_isa_names = {"spirv64-amd-amdhsa--amdgcnspirv",
325+
"spirv64-amd-amdhsa-unknown-amdgcnspirv"};
326+
for (const auto& spirv_isa_name : spirv_isa_names) {
327+
unique_isa_names.insert({spirv_isa_name, std::make_pair<size_t, size_t>(0, 0)});
328+
}
323329

324330
// Create a query list using COMGR info for unique ISAs.
325331
std::vector<amd_comgr_code_object_info_t> query_list_array;
@@ -347,45 +353,36 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi
347353
static_cast<size_t>(item.offset));
348354
}
349355

350-
// if we have SPIRV isa, we will use Comgr to create isa for all devices.
351-
auto spirv_isa_handle = unique_isa_names.find(spirv_isa_name);
352-
bool spirv_isa_found = spirv_isa_handle->second.first != 0;
353-
354-
if (!spirv_isa_found) {
355-
for (auto device : devices) {
356-
std::string device_name = device->devices()[0]->isa().isaName();
357-
auto dev_it = unique_isa_names.find(device_name);
358-
// If the size is 0, then Comgr API could not find the CO for this GPU device/ISA
359-
if (dev_it->second.first == 0) {
360-
LogPrintfError("Cannot find CO in the bundle %s for ISA: %s", fname_.c_str(),
361-
device_name.c_str());
362-
hip_status = hipErrorNoBinaryForGpu;
363-
ListAllDeviceWithNoCOFromBundle(unique_isa_names);
364-
break;
365-
}
366-
guarantee(unique_isa_names.cend() != dev_it,
367-
"Cannot find the device name in the unique device name");
368-
fatbin_dev_info_[device->deviceId()] = new FatBinaryDeviceInfo(
369-
reinterpret_cast<address>(const_cast<void*>(image_)) + dev_it->second.second,
370-
dev_it->second.first, dev_it->second.second);
371-
fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext()));
356+
bool spirv_isa_found = false;
357+
decltype(unique_isa_names.begin()) spirv_isa_handle;
358+
for (const auto& spirv_isa_name : spirv_isa_names) {
359+
auto iter = unique_isa_names.find(spirv_isa_name);
360+
if (iter->second.first != 0) {
361+
spirv_isa_found = true;
362+
spirv_isa_handle = iter;
372363
}
373-
} else {
374-
LogPrintfDebug("%s", "SPIRV isa found");
364+
}
365+
366+
bool compile_spv_bitcode_res = false;
367+
std::once_flag spirv_to_bc_flag;
375368

376-
comgr_helper::ComgrDataSetUniqueHandle spirv_data_set, bc_data_set;
369+
comgr_helper::ComgrDataSetUniqueHandle bc_data_set;
370+
std::unordered_map<std::string, std::pair<char*, size_t>> compiled_co; // code object cache
371+
372+
auto compile_spv_bitcode = [&]() {
373+
comgr_helper::ComgrDataSetUniqueHandle spirv_data_set;
377374
comgr_helper::ComgrDataUniqueHandle spirv_data;
378375
comgr_helper::ComgrActionInfoUniqueHandle action;
379376

380377
if (comgr_status = spirv_data_set.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) {
381378
LogError("Failed to create SPIRV Data set");
382-
break;
379+
return;
383380
}
384381

385382
if (comgr_status = spirv_data.Create(AMD_COMGR_DATA_KIND_SPIRV);
386383
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
387384
LogError("Failed to create SPIRV Data");
388-
break;
385+
return;
389386
}
390387

391388
if (comgr_status =
@@ -394,43 +391,64 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi
394391
spirv_isa_handle->second.second /* buffer */);
395392
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
396393
LogError("Failed to assign data in comgr");
397-
break;
394+
return;
398395
}
399396

400397
if (comgr_status = amd::Comgr::set_data_name(spirv_data.get(), "hip_code_object.spv");
401398
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
402399
LogError("Failed to set data name");
403-
break;
400+
return;
404401
}
405402

406403
if (comgr_status = amd::Comgr::data_set_add(spirv_data_set.get(), spirv_data.get());
407404
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
408405
LogError("Failed to add spir data");
409-
break;
406+
return;
410407
}
411408

412409
if (comgr_status = action.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) {
413410
LogError("Failed to create action");
414-
break;
411+
return;
415412
}
416413

417414
if (comgr_status = bc_data_set.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) {
418415
LogError("Failed to create bitcode data set");
419-
break;
416+
return;
420417
}
421418

422419
if (comgr_status = amd::Comgr::do_action(AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC, action.get(),
423420
spirv_data_set.get(), bc_data_set.get());
424421
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
425422
LogError("Failed to compile to ll");
426-
break;
423+
return;
427424
}
425+
compile_spv_bitcode_res = true;
426+
};
428427

429-
// System might report multiple devices of same name, we do not want to recompile for all
430-
// these. store code objects after compiling them to reuse.
431-
std::unordered_map<std::string, std::pair<char*, size_t>> compiled_co;
428+
LogPrintfInfo("Searching for code objects, HIP_FORCE_SPIRV_CODEOBJECT: %d",
429+
HIP_FORCE_SPIRV_CODEOBJECT);
430+
431+
for (auto device : devices) {
432+
std::string device_name = device->devices()[0]->isa().isaName();
433+
auto dev_it = unique_isa_names.find(device_name);
434+
// If the size is not 0, that means we found the native isa code object
435+
if (dev_it->second.first != 0 && !HIP_FORCE_SPIRV_CODEOBJECT) {
436+
LogPrintfInfo("Using Native code object: %s", device->devices()[0]->isa().targetId());
437+
guarantee(unique_isa_names.cend() != dev_it,
438+
"Cannot find the device name in the unique device name");
439+
fatbin_dev_info_[device->deviceId()] = new FatBinaryDeviceInfo(
440+
reinterpret_cast<address>(const_cast<void*>(image_)) + dev_it->second.second,
441+
dev_it->second.first, dev_it->second.second);
442+
fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext()));
443+
} else if (spirv_isa_found) {
444+
// Compile to bitcode once
445+
std::call_once(spirv_to_bc_flag, compile_spv_bitcode);
446+
447+
if(!compile_spv_bitcode_res) {
448+
hip_status = hipErrorInvalidValue;
449+
break;
450+
}
432451

433-
for (auto device : devices) {
434452
std::string target_id = device->devices()[0]->isa().targetId();
435453
if (auto code_iter = compiled_co.find(target_id); code_iter != compiled_co.end()) {
436454
// We have already compiled for it, lets reuse the code object
@@ -451,7 +469,6 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi
451469
break;
452470
}
453471

454-
// TODO: do this for all devices
455472
if (comgr_status = amd::Comgr::action_info_set_isa_name(reloc_action.get(), isa.c_str());
456473
comgr_status != AMD_COMGR_STATUS_SUCCESS) {
457474
LogError("Failed to set ISA name");
@@ -540,13 +557,22 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi
540557
auto elf_size = CodeObject::ElfSize(co);
541558
fatbin_dev_info_[device->deviceId()] = new FatBinaryDeviceInfo(co, elf_size, 0);
542559
fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext()));
560+
543561
// Save the compiled code object
544562
compiled_co[target_id] = std::make_pair(co, elf_size);
563+
} else {
564+
// We found neither a compatible code object nor SPIRV
565+
LogPrintfError(
566+
"No compatible code objects found for: %s, value of HIP_FORCE_SPIRV_CODEOBJECT: %d",
567+
device->devices()[0]->isa().targetId(), HIP_FORCE_SPIRV_CODEOBJECT);
568+
hip_status = hipErrorInvalidValue;
569+
break;
545570
}
546571
}
547572
} while (0);
548573

549574
if (comgr_status != AMD_COMGR_STATUS_SUCCESS) {
575+
LogError("comgr API call failed");
550576
hip_status = hipErrorInvalidValue;
551577
}
552578

projects/clr/rocclr/utils/flags.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ release(bool, DEBUG_HIP_DYNAMIC_QUEUES, true, \
278278
release(uint, DEBUG_HIP_7_PREVIEW, 0, \
279279
"Enables specific backward incompatible changes support before 7.0," \
280280
"using the mask. By default the changes are disabled and is set to 0")\
281+
release(bool, HIP_FORCE_SPIRV_CODEOBJECT, false, \
282+
"Force use of SPIRV instead of device specific code object.") \
281283

282284
namespace amd {
283285

0 commit comments

Comments
 (0)