1 /*
2 * Copyright (C) 2018-2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8 #include "offline_compiler.h"
9
10 #include "shared/offline_compiler/source/queries.h"
11 #include "shared/offline_compiler/source/utilities/get_git_version_info.h"
12 #include "shared/source/compiler_interface/intermediate_representations.h"
13 #include "shared/source/debug_settings/debug_settings_manager.h"
14 #include "shared/source/device_binary_format/device_binary_formats.h"
15 #include "shared/source/device_binary_format/elf/elf_encoder.h"
16 #include "shared/source/device_binary_format/elf/ocl_elf.h"
17 #include "shared/source/helpers/compiler_hw_info_config.h"
18 #include "shared/source/helpers/compiler_options_parser.h"
19 #include "shared/source/helpers/debug_helpers.h"
20 #include "shared/source/helpers/file_io.h"
21 #include "shared/source/helpers/hw_helper.h"
22 #include "shared/source/helpers/hw_info.h"
23 #include "shared/source/helpers/string.h"
24 #include "shared/source/helpers/validators.h"
25 #include "shared/source/os_interface/os_inc_base.h"
26 #include "shared/source/os_interface/os_library.h"
27
28 #include "cif/common/cif_main.h"
29 #include "cif/helpers/error.h"
30 #include "cif/import/library_api.h"
31 #include "compiler_options.h"
32 #include "igfxfmid.h"
33 #include "ocl_igc_interface/code_type.h"
34 #include "ocl_igc_interface/fcl_ocl_device_ctx.h"
35 #include "ocl_igc_interface/igc_ocl_device_ctx.h"
36 #include "ocl_igc_interface/platform_helper.h"
37
38 #include <algorithm>
39 #include <iomanip>
40 #include <iostream>
41 #include <list>
42
43 #ifdef _WIN32
44 #include <direct.h>
45 #define MakeDirectory _mkdir
46 #define GetCurrentWorkingDirectory _getcwd
47 #else
48 #include <sys/stat.h>
49 #define MakeDirectory(dir) mkdir(dir, 0777)
50 #define GetCurrentWorkingDirectory getcwd
51 #endif
52
53 namespace NEO {
54
55 CIF::CIFMain *createMainNoSanitize(CIF::CreateCIFMainFunc_t createFunc);
56
convertToPascalCase(const std::string & inString)57 std::string convertToPascalCase(const std::string &inString) {
58 std::string outString;
59 bool capitalize = true;
60
61 for (unsigned int i = 0; i < inString.length(); i++) {
62 if (isalpha(inString[i]) && capitalize == true) {
63 outString += toupper(inString[i]);
64 capitalize = false;
65 } else if (inString[i] == '_') {
66 capitalize = true;
67 } else {
68 outString += inString[i];
69 }
70 }
71 return outString;
72 }
73
74 OfflineCompiler::OfflineCompiler() = default;
~OfflineCompiler()75 OfflineCompiler::~OfflineCompiler() {
76 pBuildInfo.reset();
77 delete[] irBinary;
78 delete[] genBinary;
79 delete[] debugDataBinary;
80 }
81
create(size_t numArgs,const std::vector<std::string> & allArgs,bool dumpFiles,int & retVal,OclocArgHelper * helper)82 OfflineCompiler *OfflineCompiler::create(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles, int &retVal, OclocArgHelper *helper) {
83 retVal = SUCCESS;
84 auto pOffCompiler = new OfflineCompiler();
85
86 if (pOffCompiler) {
87 pOffCompiler->argHelper = helper;
88 retVal = pOffCompiler->initialize(numArgs, allArgs, dumpFiles);
89 }
90
91 if (retVal != SUCCESS) {
92 delete pOffCompiler;
93 pOffCompiler = nullptr;
94 }
95
96 return pOffCompiler;
97 }
98
printQueryHelp(OclocArgHelper * helper)99 void printQueryHelp(OclocArgHelper *helper) {
100 helper->printf(OfflineCompiler::queryHelp.data());
101 }
102
query(size_t numArgs,const std::vector<std::string> & allArgs,OclocArgHelper * helper)103 int OfflineCompiler::query(size_t numArgs, const std::vector<std::string> &allArgs, OclocArgHelper *helper) {
104 if (allArgs.size() != 3) {
105 helper->printf("Error: Invalid command line. Expected ocloc query <argument>");
106 return INVALID_COMMAND_LINE;
107 }
108
109 auto retVal = SUCCESS;
110 auto &arg = allArgs[2];
111
112 if (Queries::queryNeoRevision == arg) {
113 auto revision = NEO::getRevision();
114 helper->saveOutput(Queries::queryNeoRevision.data(), revision.c_str(), revision.size() + 1);
115 } else if (Queries::queryOCLDriverVersion == arg) {
116 auto driverVersion = NEO::getOclDriverVersion();
117 helper->saveOutput(Queries::queryOCLDriverVersion.data(), driverVersion.c_str(), driverVersion.size() + 1);
118 } else if ("--help" == arg) {
119 printQueryHelp(helper);
120 } else {
121 helper->printf("Error: Invalid command line. Uknown argument %s.", arg.c_str());
122 retVal = INVALID_COMMAND_LINE;
123 }
124
125 return retVal;
126 }
127
128 struct OfflineCompiler::buildInfo {
129 std::unique_ptr<CIF::Builtins::BufferLatest, CIF::RAII::ReleaseHelper<CIF::Builtins::BufferLatest>> fclOptions;
130 std::unique_ptr<CIF::Builtins::BufferLatest, CIF::RAII::ReleaseHelper<CIF::Builtins::BufferLatest>> fclInternalOptions;
131 std::unique_ptr<IGC::OclTranslationOutputTagOCL, CIF::RAII::ReleaseHelper<IGC::OclTranslationOutputTagOCL>> fclOutput;
132 IGC::CodeType::CodeType_t intermediateRepresentation;
133 };
134
buildIrBinary()135 int OfflineCompiler::buildIrBinary() {
136 int retVal = SUCCESS;
137 UNRECOVERABLE_IF(fclDeviceCtx == nullptr);
138 pBuildInfo->intermediateRepresentation = useLlvmText ? IGC::CodeType::llvmLl
139 : (useLlvmBc ? IGC::CodeType::llvmBc : preferredIntermediateRepresentation);
140
141 //sourceCode.size() returns the number of characters without null terminated char
142 CIF::RAII::UPtr_t<CIF::Builtins::BufferLatest> fclSrc = nullptr;
143 pBuildInfo->fclOptions = CIF::Builtins::CreateConstBuffer(fclMain.get(), options.c_str(), options.size());
144 pBuildInfo->fclInternalOptions = CIF::Builtins::CreateConstBuffer(fclMain.get(), internalOptions.c_str(), internalOptions.size());
145 auto err = CIF::Builtins::CreateConstBuffer(fclMain.get(), nullptr, 0);
146
147 auto srcType = IGC::CodeType::undefined;
148 std::vector<uint8_t> tempSrcStorage;
149 if (this->argHelper->hasHeaders()) {
150 srcType = IGC::CodeType::elf;
151
152 NEO::Elf::ElfEncoder<> elfEncoder(true, true, 1U);
153 elfEncoder.getElfFileHeader().type = NEO::Elf::ET_OPENCL_SOURCE;
154 elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_SOURCE, "CLMain", sourceCode);
155
156 for (const auto &header : this->argHelper->getHeaders()) {
157 ArrayRef<const uint8_t> headerData(header.data, header.length);
158 ConstStringRef headerName = header.name;
159
160 elfEncoder.appendSection(NEO::Elf::SHT_OPENCL_HEADER, headerName, headerData);
161 }
162 tempSrcStorage = elfEncoder.encode();
163 fclSrc = CIF::Builtins::CreateConstBuffer(fclMain.get(), tempSrcStorage.data(), tempSrcStorage.size());
164 } else {
165 srcType = IGC::CodeType::oclC;
166 fclSrc = CIF::Builtins::CreateConstBuffer(fclMain.get(), sourceCode.c_str(), sourceCode.size() + 1);
167 }
168
169 auto fclTranslationCtx = fclDeviceCtx->CreateTranslationCtx(srcType, pBuildInfo->intermediateRepresentation, err.get());
170
171 if (true == NEO::areNotNullptr(err->GetMemory<char>())) {
172 updateBuildLog(err->GetMemory<char>(), err->GetSizeRaw());
173 retVal = BUILD_PROGRAM_FAILURE;
174 return retVal;
175 }
176
177 if (false == NEO::areNotNullptr(fclSrc.get(), pBuildInfo->fclOptions.get(), pBuildInfo->fclInternalOptions.get(),
178 fclTranslationCtx.get())) {
179 retVal = OUT_OF_HOST_MEMORY;
180 return retVal;
181 }
182
183 pBuildInfo->fclOutput = fclTranslationCtx->Translate(fclSrc.get(), pBuildInfo->fclOptions.get(),
184 pBuildInfo->fclInternalOptions.get(), nullptr, 0);
185
186 if (pBuildInfo->fclOutput == nullptr) {
187 retVal = OUT_OF_HOST_MEMORY;
188 return retVal;
189 }
190
191 UNRECOVERABLE_IF(pBuildInfo->fclOutput->GetBuildLog() == nullptr);
192 UNRECOVERABLE_IF(pBuildInfo->fclOutput->GetOutput() == nullptr);
193
194 if (pBuildInfo->fclOutput->Successful() == false) {
195 updateBuildLog(pBuildInfo->fclOutput->GetBuildLog()->GetMemory<char>(), pBuildInfo->fclOutput->GetBuildLog()->GetSizeRaw());
196 retVal = BUILD_PROGRAM_FAILURE;
197 return retVal;
198 }
199
200 storeBinary(irBinary, irBinarySize, pBuildInfo->fclOutput->GetOutput()->GetMemory<char>(), pBuildInfo->fclOutput->GetOutput()->GetSizeRaw());
201 isSpirV = pBuildInfo->intermediateRepresentation == IGC::CodeType::spirV;
202
203 updateBuildLog(pBuildInfo->fclOutput->GetBuildLog()->GetMemory<char>(), pBuildInfo->fclOutput->GetBuildLog()->GetSizeRaw());
204
205 return retVal;
206 }
207
validateInputType(const std::string & input,bool isLlvm,bool isSpirv)208 std::string OfflineCompiler::validateInputType(const std::string &input, bool isLlvm, bool isSpirv) {
209 auto asBitcode = ArrayRef<const uint8_t>::fromAny(input.data(), input.size());
210 if (isSpirv) {
211 if (NEO::isSpirVBitcode(asBitcode)) {
212 return "";
213 }
214 return "Warning : file does not look like spirv bitcode (wrong magic numbers)";
215 }
216
217 if (isLlvm) {
218 if (NEO::isLlvmBitcode(asBitcode)) {
219 return "";
220 }
221 return "Warning : file does not look like llvm bitcode (wrong magic numbers)";
222 }
223
224 if (NEO::isSpirVBitcode(asBitcode)) {
225 return "Warning : file looks like spirv bitcode (based on magic numbers) - please make sure proper CLI flags are present";
226 }
227
228 if (NEO::isLlvmBitcode(asBitcode)) {
229 return "Warning : file looks like llvm bitcode (based on magic numbers) - please make sure proper CLI flags are present";
230 }
231
232 return "";
233 }
234
buildSourceCode()235 int OfflineCompiler::buildSourceCode() {
236 int retVal = SUCCESS;
237
238 do {
239 if (sourceCode.empty()) {
240 retVal = INVALID_PROGRAM;
241 break;
242 }
243 UNRECOVERABLE_IF(igcDeviceCtx == nullptr);
244 auto inputTypeWarnings = validateInputType(sourceCode, inputFileLlvm, inputFileSpirV);
245 this->argHelper->printf(inputTypeWarnings.c_str());
246
247 CIF::RAII::UPtr_t<IGC::OclTranslationOutputTagOCL> igcOutput;
248 bool inputIsIntermediateRepresentation = inputFileLlvm || inputFileSpirV;
249 if (false == inputIsIntermediateRepresentation) {
250 retVal = buildIrBinary();
251 if (retVal != SUCCESS)
252 break;
253
254 auto igcTranslationCtx = igcDeviceCtx->CreateTranslationCtx(pBuildInfo->intermediateRepresentation, IGC::CodeType::oclGenBin);
255 igcOutput = igcTranslationCtx->Translate(pBuildInfo->fclOutput->GetOutput(), pBuildInfo->fclOptions.get(),
256 pBuildInfo->fclInternalOptions.get(),
257 nullptr, 0);
258
259 } else {
260 storeBinary(irBinary, irBinarySize, sourceCode.c_str(), sourceCode.size());
261 isSpirV = inputFileSpirV;
262 auto igcSrc = CIF::Builtins::CreateConstBuffer(igcMain.get(), sourceCode.c_str(), sourceCode.size());
263 auto igcOptions = CIF::Builtins::CreateConstBuffer(igcMain.get(), options.c_str(), options.size());
264 auto igcInternalOptions = CIF::Builtins::CreateConstBuffer(igcMain.get(), internalOptions.c_str(), internalOptions.size());
265 auto igcTranslationCtx = igcDeviceCtx->CreateTranslationCtx(inputFileSpirV ? IGC::CodeType::spirV : IGC::CodeType::llvmBc, IGC::CodeType::oclGenBin);
266 igcOutput = igcTranslationCtx->Translate(igcSrc.get(), igcOptions.get(), igcInternalOptions.get(), nullptr, 0);
267 }
268 if (igcOutput == nullptr) {
269 retVal = OUT_OF_HOST_MEMORY;
270 break;
271 }
272 UNRECOVERABLE_IF(igcOutput->GetBuildLog() == nullptr);
273 UNRECOVERABLE_IF(igcOutput->GetOutput() == nullptr);
274 updateBuildLog(igcOutput->GetBuildLog()->GetMemory<char>(), igcOutput->GetBuildLog()->GetSizeRaw());
275
276 if (igcOutput->GetOutput()->GetSizeRaw() != 0) {
277 storeBinary(genBinary, genBinarySize, igcOutput->GetOutput()->GetMemory<char>(), igcOutput->GetOutput()->GetSizeRaw());
278 }
279 if (igcOutput->GetDebugData()->GetSizeRaw() != 0) {
280 storeBinary(debugDataBinary, debugDataBinarySize, igcOutput->GetDebugData()->GetMemory<char>(), igcOutput->GetDebugData()->GetSizeRaw());
281 }
282 retVal = igcOutput->Successful() ? SUCCESS : BUILD_PROGRAM_FAILURE;
283 } while (0);
284
285 return retVal;
286 }
287
build()288 int OfflineCompiler::build() {
289 int retVal = SUCCESS;
290 if (isOnlySpirV()) {
291 retVal = buildIrBinary();
292 } else {
293 retVal = buildSourceCode();
294 }
295 generateElfBinary();
296 if (dumpFiles) {
297 writeOutAllFiles();
298 }
299
300 return retVal;
301 }
302
updateBuildLog(const char * pErrorString,const size_t errorStringSize)303 void OfflineCompiler::updateBuildLog(const char *pErrorString, const size_t errorStringSize) {
304 std::string errorString = (errorStringSize && pErrorString) ? std::string(pErrorString, pErrorString + errorStringSize) : "";
305 if (errorString[0] != '\0') {
306 if (buildLog.empty()) {
307 buildLog.assign(errorString.c_str());
308 } else {
309 buildLog.append("\n");
310 buildLog.append(errorString.c_str());
311 }
312 }
313 }
314
getBuildLog()315 std::string &OfflineCompiler::getBuildLog() {
316 return buildLog;
317 }
318
setFamilyType()319 void OfflineCompiler::setFamilyType() {
320 familyNameWithType.clear();
321 familyNameWithType.append(familyName[hwInfo.platform.eRenderCoreFamily]);
322 familyNameWithType.append(hwInfo.capabilityTable.platformType);
323 }
324
initHardwareInfo(std::string deviceName)325 int OfflineCompiler::initHardwareInfo(std::string deviceName) {
326 int retVal = INVALID_DEVICE;
327
328 if (deviceName.empty()) {
329 return retVal;
330 }
331
332 if (argHelper->isFatbinary()) {
333 argHelper->setHwInfoForFatbinaryTarget(hwInfo);
334 setFamilyType();
335 retVal = SUCCESS;
336 return retVal;
337 }
338
339 overridePlatformName(deviceName);
340 std::transform(deviceName.begin(), deviceName.end(), deviceName.begin(), ::tolower);
341 const char hexPrefix = 2;
342 std::string product("");
343
344 auto numeration = argHelper->getMajorMinorRevision(deviceName);
345 if (!numeration.empty()) {
346 uint32_t productConfig = argHelper->getProductConfig(numeration);
347
348 if (argHelper->getHwInfoForProductConfig(productConfig, hwInfo)) {
349 deviceConfig = static_cast<PRODUCT_CONFIG>(productConfig);
350 setFamilyType();
351 retVal = SUCCESS;
352 return retVal;
353 }
354 argHelper->printf("Could not determine target based on product config: %s\n", deviceName.c_str());
355 return retVal;
356 } else if (deviceName.find(".") != std::string::npos) {
357 argHelper->printf("Could not determine target based on product config: %s\n", deviceName.c_str());
358 return retVal;
359 }
360
361 if (deviceName.substr(0, hexPrefix) == "0x" && std::all_of(deviceName.begin() + hexPrefix, deviceName.end(), (::isxdigit))) {
362 product = argHelper->returnProductNameForDevice(stoi(deviceName, 0, 16));
363 if (!product.empty()) {
364 argHelper->printf("Auto-detected target based on %s device id: %s\n", deviceName.c_str(), product.c_str());
365 deviceName = product;
366 } else {
367 argHelper->printf("Could not determine target based on device id: %s\n", deviceName.c_str());
368 return retVal;
369 }
370 }
371
372 for (unsigned int productId = 0; productId < IGFX_MAX_PRODUCT; ++productId) {
373 if (hardwarePrefix[productId] && (0 == strcmp(deviceName.c_str(), hardwarePrefix[productId]))) {
374 if (hardwareInfoTable[productId]) {
375 hwInfo = *hardwareInfoTable[productId];
376 if (revisionId != -1) {
377 hwInfo.platform.usRevId = revisionId;
378 }
379
380 auto hwInfoConfig = defaultHardwareInfoConfigTable[hwInfo.platform.eProductFamily];
381 setHwInfoValuesFromConfig(hwInfoConfig, hwInfo);
382 hardwareInfoSetup[hwInfo.platform.eProductFamily](&hwInfo, true, hwInfoConfig);
383 setFamilyType();
384 retVal = SUCCESS;
385 break;
386 }
387 }
388 }
389
390 return retVal;
391 }
392
getStringWithinDelimiters(const std::string & src)393 std::string OfflineCompiler::getStringWithinDelimiters(const std::string &src) {
394 size_t start = src.find("R\"===(");
395 size_t stop = src.find(")===\"");
396
397 DEBUG_BREAK_IF(std::string::npos == start);
398 DEBUG_BREAK_IF(std::string::npos == stop);
399
400 start += strlen("R\"===(");
401 size_t size = stop - start;
402
403 std::string dst(src, start, size + 1);
404 dst[size] = '\0'; // put null char at the end
405
406 return dst;
407 }
408
initialize(size_t numArgs,const std::vector<std::string> & allArgs,bool dumpFiles)409 int OfflineCompiler::initialize(size_t numArgs, const std::vector<std::string> &allArgs, bool dumpFiles) {
410 this->dumpFiles = dumpFiles;
411 int retVal = SUCCESS;
412 const char *source = nullptr;
413 std::unique_ptr<char[]> sourceFromFile;
414 size_t sourceFromFileSize = 0;
415 this->pBuildInfo = std::make_unique<buildInfo>();
416 retVal = parseCommandLine(numArgs, allArgs);
417 if (showHelp) {
418 printUsage();
419 return retVal;
420 } else if (retVal != SUCCESS) {
421 return retVal;
422 }
423
424 if (options.empty()) {
425 // try to read options from file if not provided by commandline
426 size_t ext_start = inputFile.find_last_of(".");
427 if (ext_start != std::string::npos) {
428 std::string oclocOptionsFileName = inputFile.substr(0, ext_start);
429 oclocOptionsFileName.append("_ocloc_options.txt");
430
431 std::string oclocOptionsFromFile;
432 bool oclocOptionsRead = readOptionsFromFile(oclocOptionsFromFile, oclocOptionsFileName, argHelper);
433 if (oclocOptionsRead && !isQuiet()) {
434 argHelper->printf("Building with ocloc options:\n%s\n", oclocOptionsFromFile.c_str());
435 }
436
437 if (oclocOptionsRead) {
438 std::istringstream iss(allArgs[0] + " " + oclocOptionsFromFile);
439 std::vector<std::string> tokens{
440 std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
441
442 retVal = parseCommandLine(tokens.size(), tokens);
443 if (retVal != SUCCESS) {
444 return retVal;
445 }
446 }
447
448 std::string optionsFileName = inputFile.substr(0, ext_start);
449 optionsFileName.append("_options.txt");
450
451 bool optionsRead = readOptionsFromFile(options, optionsFileName, argHelper);
452 if (optionsRead && !isQuiet()) {
453 argHelper->printf("Building with options:\n%s\n", options.c_str());
454 }
455
456 std::string internalOptionsFileName = inputFile.substr(0, ext_start);
457 internalOptionsFileName.append("_internal_options.txt");
458
459 std::string internalOptionsFromFile;
460 bool internalOptionsRead = readOptionsFromFile(internalOptionsFromFile, internalOptionsFileName, argHelper);
461 if (internalOptionsRead && !isQuiet()) {
462 argHelper->printf("Building with internal options:\n%s\n", internalOptionsFromFile.c_str());
463 }
464 CompilerOptions::concatenateAppend(internalOptions, internalOptionsFromFile);
465 }
466 }
467
468 retVal = deviceName.empty() ? SUCCESS : initHardwareInfo(deviceName.c_str());
469 if (retVal != SUCCESS) {
470 argHelper->printf("Error: Cannot get HW Info for device %s.\n", deviceName.c_str());
471 return retVal;
472 }
473
474 if (CompilerOptions::contains(options, CompilerOptions::generateDebugInfo.str())) {
475 if (hwInfo.platform.eRenderCoreFamily >= IGFX_GEN9_CORE) {
476 internalOptions = CompilerOptions::concatenate(internalOptions, CompilerOptions::debugKernelEnable);
477 }
478 }
479
480 if (deviceName.empty()) {
481 internalOptions = CompilerOptions::concatenate("-ocl-version=300 -cl-ext=-all,+cl_khr_3d_image_writes", internalOptions);
482 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::enableImageSupport);
483 } else {
484 appendExtensionsToInternalOptions(hwInfo, options, internalOptions);
485 appendExtraInternalOptions(hwInfo, internalOptions);
486 }
487
488 parseDebugSettings();
489
490 // set up the device inside the program
491 sourceFromFile = argHelper->loadDataFromFile(inputFile, sourceFromFileSize);
492 if (sourceFromFileSize == 0) {
493 retVal = INVALID_FILE;
494 return retVal;
495 }
496
497 if (inputFileLlvm || inputFileSpirV) {
498 // use the binary input "as is"
499 sourceCode.assign(sourceFromFile.get(), sourceFromFileSize);
500 } else {
501 // for text input, we also accept files used as runtime builtins
502 source = strstr((const char *)sourceFromFile.get(), "R\"===(");
503 sourceCode = (source != nullptr) ? getStringWithinDelimiters(sourceFromFile.get()) : sourceFromFile.get();
504 }
505
506 if ((inputFileSpirV == false) && (inputFileLlvm == false)) {
507 auto fclLibFile = OsLibrary::load(Os::frontEndDllName);
508
509 if (fclLibFile == nullptr) {
510 argHelper->printf("Error: Failed to load %s\n", Os::frontEndDllName);
511 return OUT_OF_HOST_MEMORY;
512 }
513
514 this->fclLib.reset(fclLibFile);
515 if (this->fclLib == nullptr) {
516 return OUT_OF_HOST_MEMORY;
517 }
518
519 auto fclCreateMain = reinterpret_cast<CIF::CreateCIFMainFunc_t>(this->fclLib->getProcAddress(CIF::CreateCIFMainFuncName));
520 if (fclCreateMain == nullptr) {
521 return OUT_OF_HOST_MEMORY;
522 }
523
524 this->fclMain = CIF::RAII::UPtr(createMainNoSanitize(fclCreateMain));
525 if (this->fclMain == nullptr) {
526 return OUT_OF_HOST_MEMORY;
527 }
528
529 if (false == this->fclMain->IsCompatible<IGC::FclOclDeviceCtx>()) {
530 argHelper->printf("Incompatible interface in FCL : %s\n", CIF::InterfaceIdCoder::Dec(this->fclMain->FindIncompatible<IGC::FclOclDeviceCtx>()).c_str());
531 DEBUG_BREAK_IF(true);
532 return OUT_OF_HOST_MEMORY;
533 }
534
535 this->fclDeviceCtx = this->fclMain->CreateInterface<IGC::FclOclDeviceCtxTagOCL>();
536 if (this->fclDeviceCtx == nullptr) {
537 return OUT_OF_HOST_MEMORY;
538 }
539
540 fclDeviceCtx->SetOclApiVersion(hwInfo.capabilityTable.clVersionSupport * 10);
541 preferredIntermediateRepresentation = fclDeviceCtx->GetPreferredIntermediateRepresentation();
542 if (this->fclDeviceCtx->GetUnderlyingVersion() > 4U) {
543 auto igcPlatform = fclDeviceCtx->GetPlatformHandle();
544 if (nullptr == igcPlatform) {
545 return OUT_OF_HOST_MEMORY;
546 }
547 IGC::PlatformHelper::PopulateInterfaceWith(*igcPlatform, hwInfo.platform);
548 }
549 } else {
550 if (!isQuiet()) {
551 argHelper->printf("Compilation from IR - skipping loading of FCL\n");
552 }
553 preferredIntermediateRepresentation = IGC::CodeType::spirV;
554 }
555
556 this->igcLib.reset(OsLibrary::load(Os::igcDllName));
557 if (this->igcLib == nullptr) {
558 return OUT_OF_HOST_MEMORY;
559 }
560
561 auto igcCreateMain = reinterpret_cast<CIF::CreateCIFMainFunc_t>(this->igcLib->getProcAddress(CIF::CreateCIFMainFuncName));
562 if (igcCreateMain == nullptr) {
563 return OUT_OF_HOST_MEMORY;
564 }
565
566 this->igcMain = CIF::RAII::UPtr(createMainNoSanitize(igcCreateMain));
567 if (this->igcMain == nullptr) {
568 return OUT_OF_HOST_MEMORY;
569 }
570
571 std::vector<CIF::InterfaceId_t> interfacesToIgnore = {IGC::OclGenBinaryBase::GetInterfaceId()};
572 if (false == this->igcMain->IsCompatible<IGC::IgcOclDeviceCtx>(&interfacesToIgnore)) {
573 argHelper->printf("Incompatible interface in IGC : %s\n", CIF::InterfaceIdCoder::Dec(this->igcMain->FindIncompatible<IGC::IgcOclDeviceCtx>(&interfacesToIgnore)).c_str());
574 DEBUG_BREAK_IF(true);
575 return OUT_OF_HOST_MEMORY;
576 }
577
578 CIF::Version_t verMin = 0, verMax = 0;
579 if (false == this->igcMain->FindSupportedVersions<IGC::IgcOclDeviceCtx>(IGC::OclGenBinaryBase::GetInterfaceId(), verMin, verMax)) {
580 argHelper->printf("Patchtoken interface is missing");
581 return OUT_OF_HOST_MEMORY;
582 }
583
584 this->igcDeviceCtx = this->igcMain->CreateInterface<IGC::IgcOclDeviceCtxTagOCL>();
585 if (this->igcDeviceCtx == nullptr) {
586 return OUT_OF_HOST_MEMORY;
587 }
588 this->igcDeviceCtx->SetProfilingTimerResolution(static_cast<float>(hwInfo.capabilityTable.defaultProfilingTimerResolution));
589 auto igcPlatform = this->igcDeviceCtx->GetPlatformHandle();
590 auto igcGtSystemInfo = this->igcDeviceCtx->GetGTSystemInfoHandle();
591 auto igcFeWa = this->igcDeviceCtx->GetIgcFeaturesAndWorkaroundsHandle();
592 if ((igcPlatform == nullptr) || (igcGtSystemInfo == nullptr) || (igcFeWa == nullptr)) {
593 return OUT_OF_HOST_MEMORY;
594 }
595 IGC::PlatformHelper::PopulateInterfaceWith(*igcPlatform.get(), hwInfo.platform);
596 IGC::GtSysInfoHelper::PopulateInterfaceWith(*igcGtSystemInfo.get(), hwInfo.gtSystemInfo);
597 // populate with features
598
599 igcFeWa.get()->SetFtrDesktop(hwInfo.featureTable.flags.ftrDesktop);
600 igcFeWa.get()->SetFtrChannelSwizzlingXOREnabled(hwInfo.featureTable.flags.ftrChannelSwizzlingXOREnabled);
601
602 igcFeWa.get()->SetFtrGtBigDie(hwInfo.featureTable.flags.ftrGtBigDie);
603 igcFeWa.get()->SetFtrGtMediumDie(hwInfo.featureTable.flags.ftrGtMediumDie);
604 igcFeWa.get()->SetFtrGtSmallDie(hwInfo.featureTable.flags.ftrGtSmallDie);
605
606 igcFeWa.get()->SetFtrGT1(hwInfo.featureTable.flags.ftrGT1);
607 igcFeWa.get()->SetFtrGT1_5(hwInfo.featureTable.flags.ftrGT1_5);
608 igcFeWa.get()->SetFtrGT2(hwInfo.featureTable.flags.ftrGT2);
609 igcFeWa.get()->SetFtrGT3(hwInfo.featureTable.flags.ftrGT3);
610 igcFeWa.get()->SetFtrGT4(hwInfo.featureTable.flags.ftrGT4);
611
612 igcFeWa.get()->SetFtrIVBM0M1Platform(hwInfo.featureTable.flags.ftrIVBM0M1Platform);
613 igcFeWa.get()->SetFtrGTL(hwInfo.featureTable.flags.ftrGT1);
614 igcFeWa.get()->SetFtrGTM(hwInfo.featureTable.flags.ftrGT2);
615 igcFeWa.get()->SetFtrGTH(hwInfo.featureTable.flags.ftrGT3);
616
617 igcFeWa.get()->SetFtrSGTPVSKUStrapPresent(hwInfo.featureTable.flags.ftrSGTPVSKUStrapPresent);
618 igcFeWa.get()->SetFtrGTA(hwInfo.featureTable.flags.ftrGTA);
619 igcFeWa.get()->SetFtrGTC(hwInfo.featureTable.flags.ftrGTC);
620 igcFeWa.get()->SetFtrGTX(hwInfo.featureTable.flags.ftrGTX);
621 igcFeWa.get()->SetFtr5Slice(hwInfo.featureTable.flags.ftr5Slice);
622
623 auto compilerHwInfoConfig = CompilerHwInfoConfig::get(hwInfo.platform.eProductFamily);
624 if (compilerHwInfoConfig) {
625 igcFeWa.get()->SetFtrGpGpuMidThreadLevelPreempt(compilerHwInfoConfig->isMidThreadPreemptionSupported(hwInfo));
626 }
627 igcFeWa.get()->SetFtrIoMmuPageFaulting(hwInfo.featureTable.flags.ftrIoMmuPageFaulting);
628 igcFeWa.get()->SetFtrWddm2Svm(hwInfo.featureTable.flags.ftrWddm2Svm);
629 igcFeWa.get()->SetFtrPooledEuEnabled(hwInfo.featureTable.flags.ftrPooledEuEnabled);
630
631 igcFeWa.get()->SetFtrResourceStreamer(hwInfo.featureTable.flags.ftrResourceStreamer);
632
633 return retVal;
634 }
635
parseCommandLine(size_t numArgs,const std::vector<std::string> & argv)636 int OfflineCompiler::parseCommandLine(size_t numArgs, const std::vector<std::string> &argv) {
637 int retVal = SUCCESS;
638 bool compile32 = false;
639 bool compile64 = false;
640
641 if (numArgs < 2) {
642 showHelp = true;
643 return INVALID_COMMAND_LINE;
644 }
645
646 for (uint32_t argIndex = 1; argIndex < numArgs; argIndex++) {
647 const auto &currArg = argv[argIndex];
648 const bool hasMoreArgs = (argIndex + 1 < numArgs);
649 if ("compile" == currArg) {
650 //skip it
651 } else if (("-file" == currArg) && hasMoreArgs) {
652 inputFile = argv[argIndex + 1];
653 argIndex++;
654 } else if (("-output" == currArg) && hasMoreArgs) {
655 outputFile = argv[argIndex + 1];
656 argIndex++;
657 } else if ((CompilerOptions::arch32bit == currArg) || ("-32" == currArg)) {
658 compile32 = true;
659 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::arch32bit);
660 } else if ((CompilerOptions::arch64bit == currArg) || ("-64" == currArg)) {
661 compile64 = true;
662 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::arch64bit);
663 } else if (CompilerOptions::greaterThan4gbBuffersRequired == currArg) {
664 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::greaterThan4gbBuffersRequired);
665 } else if (("-device" == currArg) && hasMoreArgs) {
666 deviceName = argv[argIndex + 1];
667 argIndex++;
668 } else if ("-llvm_text" == currArg) {
669 useLlvmText = true;
670 } else if ("-llvm_bc" == currArg) {
671 useLlvmBc = true;
672 } else if ("-llvm_input" == currArg) {
673 inputFileLlvm = true;
674 } else if ("-spirv_input" == currArg) {
675 inputFileSpirV = true;
676 } else if ("-cpp_file" == currArg) {
677 useCppFile = true;
678 } else if (("-options" == currArg) && hasMoreArgs) {
679 options = argv[argIndex + 1];
680 argIndex++;
681 } else if (("-internal_options" == currArg) && hasMoreArgs) {
682 CompilerOptions::concatenateAppend(internalOptions, argv[argIndex + 1]);
683 argIndex++;
684 } else if ("-options_name" == currArg) {
685 useOptionsSuffix = true;
686 } else if ("-force_stos_opt" == currArg) {
687 forceStatelessToStatefulOptimization = true;
688 } else if (("-out_dir" == currArg) && hasMoreArgs) {
689 outputDirectory = argv[argIndex + 1];
690 argIndex++;
691 } else if ("-q" == currArg) {
692 argHelper->getPrinterRef() = MessagePrinter(true);
693 quiet = true;
694 } else if ("-spv_only" == currArg) {
695 onlySpirV = true;
696 } else if ("-output_no_suffix" == currArg) {
697 outputNoSuffix = true;
698 } else if ("--help" == currArg) {
699 showHelp = true;
700 return SUCCESS;
701 } else if (("-revision_id" == currArg) && hasMoreArgs) {
702 revisionId = std::stoi(argv[argIndex + 1], nullptr, 0);
703 argIndex++;
704 } else if ("-exclude_ir" == currArg) {
705 excludeIr = true;
706 } else {
707 argHelper->printf("Invalid option (arg %d): %s\n", argIndex, argv[argIndex].c_str());
708 retVal = INVALID_COMMAND_LINE;
709 break;
710 }
711 }
712
713 unifyExcludeIrFlags();
714
715 if (DebugManager.flags.OverrideRevision.get() != -1) {
716 revisionId = static_cast<unsigned short>(DebugManager.flags.OverrideRevision.get());
717 }
718
719 if (retVal == SUCCESS) {
720 if (compile32 && compile64) {
721 argHelper->printf("Error: Cannot compile for 32-bit and 64-bit, please choose one.\n");
722 retVal |= INVALID_COMMAND_LINE;
723 }
724
725 if (deviceName.empty() && (false == onlySpirV)) {
726 argHelper->printf("Error: Device name missing.\n");
727 retVal = INVALID_COMMAND_LINE;
728 }
729
730 if (inputFile.empty()) {
731 argHelper->printf("Error: Input file name missing.\n");
732 retVal = INVALID_COMMAND_LINE;
733 } else if (!argHelper->fileExists(inputFile)) {
734 argHelper->printf("Error: Input file %s missing.\n", inputFile.c_str());
735 retVal = INVALID_FILE;
736 }
737 }
738
739 return retVal;
740 }
741
unifyExcludeIrFlags()742 void OfflineCompiler::unifyExcludeIrFlags() {
743 const auto excludeIrFromZebin{internalOptions.find(CompilerOptions::excludeIrFromZebin.data()) != std::string::npos};
744 if (!excludeIr && excludeIrFromZebin) {
745 excludeIr = true;
746 } else if (excludeIr && !excludeIrFromZebin) {
747 const std::string prefix{"-ze"};
748 CompilerOptions::concatenateAppend(internalOptions, prefix + CompilerOptions::excludeIrFromZebin.data());
749 }
750 }
751
setStatelessToStatefullBufferOffsetFlag()752 void OfflineCompiler::setStatelessToStatefullBufferOffsetFlag() {
753 bool isStatelessToStatefulBufferOffsetSupported = true;
754 if (!deviceName.empty()) {
755 const auto &compilerHwInfoConfig = *CompilerHwInfoConfig::get(hwInfo.platform.eProductFamily);
756 isStatelessToStatefulBufferOffsetSupported = compilerHwInfoConfig.isStatelessToStatefulBufferOffsetSupported();
757 }
758 if (DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.get() != -1) {
759 isStatelessToStatefulBufferOffsetSupported = DebugManager.flags.EnableStatelessToStatefulBufferOffsetOpt.get() != 0;
760 }
761 if (isStatelessToStatefulBufferOffsetSupported) {
762 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::hasBufferOffsetArg);
763 }
764 }
765
appendExtraInternalOptions(const HardwareInfo & hwInfo,std::string & internalOptions)766 void OfflineCompiler::appendExtraInternalOptions(const HardwareInfo &hwInfo, std::string &internalOptions) {
767 const auto &compilerHwInfoConfig = *CompilerHwInfoConfig::get(hwInfo.platform.eProductFamily);
768 auto sharedSystemMemCapabilitiesSupported = (hwInfo.capabilityTable.sharedSystemMemCapabilities > 0);
769 if (sharedSystemMemCapabilitiesSupported && !forceStatelessToStatefulOptimization) {
770 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::greaterThan4gbBuffersRequired);
771 }
772 if (compilerHwInfoConfig.isForceEmuInt32DivRemSPRequired()) {
773 CompilerOptions::concatenateAppend(internalOptions, CompilerOptions::forceEmuInt32DivRemSP);
774 }
775 }
776
parseDebugSettings()777 void OfflineCompiler::parseDebugSettings() {
778 setStatelessToStatefullBufferOffsetFlag();
779 }
780
parseBinAsCharArray(uint8_t * binary,size_t size,std::string & fileName)781 std::string OfflineCompiler::parseBinAsCharArray(uint8_t *binary, size_t size, std::string &fileName) {
782 std::string builtinName = convertToPascalCase(fileName);
783 std::ostringstream out;
784
785 // Convert binary to cpp
786 out << "#include <cstddef>\n";
787 out << "#include <cstdint>\n\n";
788 out << "size_t " << builtinName << "BinarySize_" << familyNameWithType << " = " << size << ";\n";
789 out << "uint32_t " << builtinName << "Binary_" << familyNameWithType << "[" << (size + 3) / 4 << "] = {"
790 << std::endl
791 << " ";
792
793 uint32_t *binaryUint = (uint32_t *)binary;
794 for (size_t i = 0; i < (size + 3) / 4; i++) {
795 if (i != 0) {
796 out << ", ";
797 if (i % 8 == 0) {
798 out << std::endl
799 << " ";
800 }
801 }
802 if (i < size / 4) {
803 out << "0x" << std::hex << std::setw(8) << std::setfill('0') << binaryUint[i];
804 } else {
805 uint32_t lastBytes = size & 0x3;
806 uint32_t lastUint = 0;
807 uint8_t *pLastUint = (uint8_t *)&lastUint;
808 for (uint32_t j = 0; j < lastBytes; j++) {
809 pLastUint[sizeof(uint32_t) - 1 - j] = binary[i * 4 + j];
810 }
811 out << "0x" << std::hex << std::setw(8) << std::setfill('0') << lastUint;
812 }
813 }
814 out << "};" << std::endl;
815
816 out << std::endl
817 << "#include \"shared/source/built_ins/registry/built_ins_registry.h\"\n"
818 << std::endl;
819 out << "namespace NEO {" << std::endl;
820 out << "static RegisterEmbeddedResource register" << builtinName << "Bin(" << std::endl;
821 out << " \"" << familyNameWithType << "_0_" << fileName.c_str() << ".builtin_kernel.bin\"," << std::endl;
822 out << " (const char *)" << builtinName << "Binary_" << familyNameWithType << "," << std::endl;
823 out << " " << builtinName << "BinarySize_" << familyNameWithType << ");" << std::endl;
824 out << "}" << std::endl;
825
826 return out.str();
827 }
828
getFileNameTrunk(std::string & filePath)829 std::string OfflineCompiler::getFileNameTrunk(std::string &filePath) {
830 size_t slashPos = filePath.find_last_of("\\/", filePath.size()) + 1;
831 size_t extPos = filePath.find_last_of(".", filePath.size());
832 if (extPos == std::string::npos) {
833 extPos = filePath.size();
834 }
835
836 std::string fileTrunk = filePath.substr(slashPos, (extPos - slashPos));
837
838 return fileTrunk;
839 }
840
getDevicesTypes()841 std::string getDevicesTypes() {
842 std::list<std::string> prefixes;
843 for (int j = 0; j < IGFX_MAX_PRODUCT; j++) {
844 if (hardwarePrefix[j] == nullptr)
845 continue;
846 prefixes.push_back(hardwarePrefix[j]);
847 }
848
849 std::ostringstream os;
850 for (auto it = prefixes.begin(); it != prefixes.end(); it++) {
851 if (it != prefixes.begin())
852 os << ", ";
853 os << *it;
854 }
855
856 return os.str();
857 }
858
getDevicesFamilies()859 std::string getDevicesFamilies() {
860 std::list<std::string> prefixes;
861 for (unsigned int i = 0; i < IGFX_MAX_CORE; ++i) {
862 if (familyName[i] == nullptr)
863 continue;
864 prefixes.push_back(familyName[i]);
865 }
866
867 std::ostringstream os;
868 for (auto it = prefixes.begin(); it != prefixes.end(); it++) {
869 if (it != prefixes.begin())
870 os << ", ";
871 os << *it;
872 }
873
874 return os.str();
875 }
876
getDevicesConfigs()877 std::string OfflineCompiler::getDevicesConfigs() {
878 std::list<std::string> configNum;
879 auto allSupportedConfigs = argHelper->getAllSupportedProductConfigs();
880
881 for (auto &config : allSupportedConfigs) {
882 auto numeration = argHelper->parseProductConfigFromValue(config);
883 configNum.push_back(numeration);
884 }
885
886 std::ostringstream os;
887 for (auto it = configNum.begin(); it != configNum.end(); it++) {
888 if (it != configNum.begin())
889 os << ", ";
890 os << *it;
891 }
892
893 return os.str();
894 }
895
printUsage()896 void OfflineCompiler::printUsage() {
897 argHelper->printf(R"===(Compiles input file to Intel Compute GPU device binary (*.bin).
898 Additionally, outputs intermediate representation (e.g. spirV).
899 Different input and intermediate file formats are available.
900
901 Usage: ocloc [compile] -file <filename> -device <device_type> [-output <filename>] [-out_dir <output_dir>] [-options <options>] [-32|-64] [-internal_options <options>] [-llvm_text|-llvm_input|-spirv_input] [-options_name] [-q] [-cpp_file] [-output_no_suffix] [--help]
902
903 -file <filename> The input file to be compiled
904 (by default input source format is
905 OpenCL C kernel language).
906
907 -device <device_type> Target device.
908 <device_type> can be: %s, %s or hexadecimal value with 0x prefix - can be single or multiple target devices.
909 The <major>[<minor>[.<revision>]] numbers:
910 <major> - family of graphics products,
911 <minor> - can be omitted, then ocloc will
912 compile for all of the <major> matching devices.
913 <revision> - can be omitted, then ocloc will
914 compile for all of the <major>.<minor> matching
915 devices.
916 The hexadecimal value represents device ID.
917 If such value is provided, ocloc will try to
918 match it with corresponding device type.
919 For example, 0xFF20 device ID will be translated
920 to tgllp.
921 If multiple target devices are provided, ocloc
922 will compile for each of these targets and will
923 create a fatbinary archive that contains all of
924 device binaries produced this way.
925 Supported -device patterns examples:
926 -device 0xFF20 ; will compile 1 target (tgllp)
927 -device 12.0.7 ; will compile 1 target (dg1)
928 -device 11 ; will compile the architecture
929 (gen11)
930 -device 9.0,11.0 ; will compile 2 targets
931 (skl & icllp)
932 -device 9.0-11.0 ; will compile all targets
933 in range (inclusive)
934 -device 9.0- ; will compile all targets
935 newer/same as provided
936 -device -9.0 ; will compile all targets
937 older/same as provided
938 -device * ; will compile all targets
939 known to ocloc
940
941 Deprecated notation that is still supported:
942 <device_type> can be: %s
943 - can be single or multiple target devices.
944 Supported -device patterns examples:
945 -device skl ; will compile 1 target
946 -device skl,icllp ; will compile 2 targets
947 -device skl-icllp ; will compile all targets
948 in range (inclusive)
949 -device skl- ; will compile all targets
950 newer/same as provided
951 -device -skl ; will compile all targets
952 older/same as provided
953 -device gen9 ; will compile all targets
954 matching the same gen
955 -device gen9-gen11 ; will compile all targets
956 in range (inclusive)
957 -device gen9- ; will compile all targets
958 newer/same as provided
959 -device -gen9 ; will compile all targets
960 older/same as provided
961
962 -output <filename> Optional output file base name.
963 Default is input file's base name.
964 This base name will be used for all output
965 files. Proper sufixes (describing file formats)
966 will be added automatically.
967
968 -out_dir <output_dir> Optional output directory.
969 Default is current working directory.
970
971 -options <options> Optional OpenCL C compilation options
972 as defined by OpenCL specification.
973 Special options for Vector Compute:
974 -vc-codegen <vc options> compile from SPIRV
975 -cmc <cm-options> compile from CM sources
976
977 -32 Forces target architecture to 32-bit pointers.
978 Default pointer size is inherited from
979 ocloc's pointer size.
980 This option is exclusive with -64.
981
982 -64 Forces target architecture to 64-bit pointers.
983 Default pointer size is inherited from
984 ocloc's pointer size.
985 This option is exclusive with -32.
986
987 -internal_options <options> Optional compiler internal options
988 as defined by compilers used underneath.
989 Check intel-graphics-compiler (IGC) project
990 for details on available internal options.
991 You also may provide explicit --help to inquire
992 information about option, mentioned in -options
993
994 -llvm_text Forces intermediate representation (IR) format
995 to human-readable LLVM IR (.ll).
996 This option affects only output files
997 and should not be used in combination with
998 '-llvm_input' option.
999 Default IR is spirV.
1000 This option is exclusive with -spirv_input.
1001 This option is exclusive with -llvm_input.
1002
1003 -llvm_input Indicates that input file is an llvm binary.
1004 Default is OpenCL C kernel language.
1005 This option is exclusive with -spirv_input.
1006 This option is exclusive with -llvm_text.
1007
1008 -spirv_input Indicates that input file is a spirV binary.
1009 Default is OpenCL C kernel language format.
1010 This option is exclusive with -llvm_input.
1011 This option is exclusive with -llvm_text.
1012
1013 -options_name Will add suffix to output files.
1014 This suffix will be generated based on input
1015 options (useful when rebuilding with different
1016 set of options so that results won't get
1017 overwritten).
1018 This suffix is added always as the last part
1019 of the filename (even after file's extension).
1020 It does not affect '--output' parameter and can
1021 be used along with it ('--output' parameter
1022 defines the base name - i.e. prefix).
1023
1024 -force_stos_opt Will forcibly enable stateless to stateful optimization,
1025 i.e. skip "-cl-intel-greater-than-4GB-buffer-required".
1026
1027 -q Will silence most of output messages.
1028
1029 -spv_only Will generate only spirV file.
1030
1031 -cpp_file Will generate c++ file with C-array
1032 containing Intel Compute device binary.
1033
1034 -output_no_suffix Prevents ocloc from adding family name suffix.
1035
1036 --help Print this usage message.
1037
1038 -revision_id <revision_id> Target stepping. Can be decimal or hexadecimal value.
1039
1040 -exclude_ir Excludes IR from the output binary file.
1041
1042 Examples :
1043 Compile file to Intel Compute GPU device binary (out = source_file_Gen9core.bin)
1044 ocloc -file source_file.cl -device skl
1045 )===",
1046 getDevicesConfigs().c_str(),
1047 NEO::getDevicesFamilies().c_str(),
1048 NEO::getDevicesTypes().c_str());
1049 }
1050
storeBinary(char * & pDst,size_t & dstSize,const void * pSrc,const size_t srcSize)1051 void OfflineCompiler::storeBinary(
1052 char *&pDst,
1053 size_t &dstSize,
1054 const void *pSrc,
1055 const size_t srcSize) {
1056 dstSize = 0;
1057
1058 DEBUG_BREAK_IF(!(pSrc && srcSize > 0));
1059
1060 delete[] pDst;
1061 pDst = new char[srcSize];
1062
1063 dstSize = static_cast<uint32_t>(srcSize);
1064 memcpy_s(pDst, dstSize, pSrc, srcSize);
1065 }
1066
generateElfBinary()1067 bool OfflineCompiler::generateElfBinary() {
1068 if (!genBinary || !genBinarySize) {
1069 return false;
1070 }
1071
1072 // return "as is" if zebin format
1073 if (isDeviceBinaryFormat<DeviceBinaryFormat::Zebin>(ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(genBinary), genBinarySize))) {
1074 this->elfBinary = std::vector<uint8_t>(genBinary, genBinary + genBinarySize);
1075 return true;
1076 }
1077
1078 SingleDeviceBinary binary = {};
1079 binary.buildOptions = this->options;
1080 binary.intermediateRepresentation = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->irBinary), this->irBinarySize);
1081 binary.deviceBinary = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->genBinary), this->genBinarySize);
1082 binary.debugData = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(this->debugDataBinary), this->debugDataBinarySize);
1083 std::string packErrors;
1084 std::string packWarnings;
1085
1086 using namespace NEO::Elf;
1087 ElfEncoder<EI_CLASS_64> ElfEncoder;
1088 ElfEncoder.getElfFileHeader().type = ET_OPENCL_EXECUTABLE;
1089 if (binary.buildOptions.empty() == false) {
1090 ElfEncoder.appendSection(SHT_OPENCL_OPTIONS, SectionNamesOpenCl::buildOptions,
1091 ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.buildOptions.data()), binary.buildOptions.size()));
1092 }
1093
1094 if (!binary.intermediateRepresentation.empty() && !excludeIr) {
1095 if (isSpirV) {
1096 ElfEncoder.appendSection(SHT_OPENCL_SPIRV, SectionNamesOpenCl::spirvObject, binary.intermediateRepresentation);
1097 } else {
1098 ElfEncoder.appendSection(SHT_OPENCL_LLVM_BINARY, SectionNamesOpenCl::llvmObject, binary.intermediateRepresentation);
1099 }
1100 }
1101
1102 if (binary.debugData.empty() == false) {
1103 ElfEncoder.appendSection(SHT_OPENCL_DEV_DEBUG, SectionNamesOpenCl::deviceDebug, binary.debugData);
1104 }
1105
1106 if (binary.deviceBinary.empty() == false) {
1107 ElfEncoder.appendSection(SHT_OPENCL_DEV_BINARY, SectionNamesOpenCl::deviceBinary, binary.deviceBinary);
1108 }
1109
1110 this->elfBinary = ElfEncoder.encode();
1111
1112 return true;
1113 }
1114
writeOutAllFiles()1115 void OfflineCompiler::writeOutAllFiles() {
1116 std::string fileBase;
1117 std::string fileTrunk = getFileNameTrunk(inputFile);
1118 if (outputNoSuffix) {
1119 if (outputFile.empty()) {
1120 fileBase = fileTrunk;
1121 } else {
1122 fileBase = outputFile;
1123 }
1124 } else {
1125 if (outputFile.empty()) {
1126 fileBase = fileTrunk + "_" + familyNameWithType;
1127 } else {
1128 fileBase = outputFile + "_" + familyNameWithType;
1129 }
1130 }
1131
1132 if (outputDirectory != "") {
1133 std::list<std::string> dirList;
1134 std::string tmp = outputDirectory;
1135 size_t pos = outputDirectory.size() + 1;
1136
1137 do {
1138 dirList.push_back(tmp);
1139 pos = tmp.find_last_of("/\\", pos);
1140 tmp = tmp.substr(0, pos);
1141 } while (pos != std::string::npos);
1142
1143 while (!dirList.empty()) {
1144 MakeDirectory(dirList.back().c_str());
1145 dirList.pop_back();
1146 }
1147 }
1148
1149 if (irBinary && !inputFileSpirV) {
1150 std::string irOutputFileName = generateFilePathForIr(fileBase) + generateOptsSuffix();
1151
1152 argHelper->saveOutput(irOutputFileName, irBinary, irBinarySize);
1153 }
1154
1155 if (genBinary) {
1156 std::string genOutputFile = generateFilePath(outputDirectory, fileBase, ".gen") + generateOptsSuffix();
1157
1158 argHelper->saveOutput(genOutputFile, genBinary, genBinarySize);
1159
1160 if (useCppFile) {
1161 std::string cppOutputFile = generateFilePath(outputDirectory, fileBase, ".cpp");
1162 std::string cpp = parseBinAsCharArray((uint8_t *)genBinary, genBinarySize, fileTrunk);
1163 argHelper->saveOutput(cppOutputFile, cpp.c_str(), cpp.size());
1164 }
1165 }
1166
1167 if (!elfBinary.empty()) {
1168 std::string elfOutputFile;
1169 if (outputNoSuffix) {
1170 elfOutputFile = generateFilePath(outputDirectory, fileBase, "");
1171 } else {
1172 elfOutputFile = generateFilePath(outputDirectory, fileBase, ".bin") + generateOptsSuffix();
1173 }
1174 argHelper->saveOutput(
1175 elfOutputFile,
1176 elfBinary.data(),
1177 elfBinary.size());
1178 }
1179
1180 if (debugDataBinary) {
1181 std::string debugOutputFile = generateFilePath(outputDirectory, fileBase, ".dbg") + generateOptsSuffix();
1182
1183 argHelper->saveOutput(
1184 debugOutputFile,
1185 debugDataBinary,
1186 debugDataBinarySize);
1187 }
1188 }
1189
readOptionsFromFile(std::string & options,const std::string & file,OclocArgHelper * helper)1190 bool OfflineCompiler::readOptionsFromFile(std::string &options, const std::string &file, OclocArgHelper *helper) {
1191 if (!helper->fileExists(file)) {
1192 return false;
1193 }
1194 size_t optionsSize = 0U;
1195 auto optionsFromFile = helper->loadDataFromFile(file, optionsSize);
1196 if (optionsSize > 0) {
1197 // Remove comment containing copyright header
1198 options = optionsFromFile.get();
1199 size_t commentBegin = options.find("/*");
1200 size_t commentEnd = options.rfind("*/");
1201 if (commentBegin != std::string::npos && commentEnd != std::string::npos) {
1202 auto sizeToReplace = commentEnd - commentBegin + 2;
1203 options = options.replace(commentBegin, sizeToReplace, "");
1204 size_t optionsBegin = options.find_first_not_of(" \t\n\r");
1205 if (optionsBegin != std::string::npos) {
1206 options = options.substr(optionsBegin, options.length());
1207 }
1208 }
1209 auto trimPos = options.find_last_not_of(" \n\r");
1210 options = options.substr(0, trimPos + 1);
1211 }
1212 return true;
1213 }
1214
generateFilePath(const std::string & directory,const std::string & fileNameBase,const char * extension)1215 std::string generateFilePath(const std::string &directory, const std::string &fileNameBase, const char *extension) {
1216 UNRECOVERABLE_IF(extension == nullptr);
1217
1218 if (directory.empty()) {
1219 return fileNameBase + extension;
1220 }
1221
1222 bool hasTrailingSlash = (*directory.rbegin() == '/');
1223 std::string ret;
1224 ret.reserve(directory.size() + (hasTrailingSlash ? 0 : 1) + fileNameBase.size() + strlen(extension) + 1);
1225 ret.append(directory);
1226 if (false == hasTrailingSlash) {
1227 ret.append("/", 1);
1228 }
1229 ret.append(fileNameBase);
1230 ret.append(extension);
1231
1232 return ret;
1233 }
1234
1235 } // namespace NEO
1236