1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2020-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include "vc/igcdeps/TranslationInterface.h"
10
11 #include "vc/igcdeps/ShaderDump.h"
12 #include "vc/igcdeps/ShaderOverride.h"
13 #include "vc/igcdeps/cmc.h"
14
15 #include "vc/BiF/Wrapper.h"
16 #include "vc/Driver/Driver.h"
17 #include "vc/Support/Status.h"
18
19 #include <llvm/ADT/ArrayRef.h>
20 #include <llvm/ADT/ScopeExit.h>
21 #include <llvm/ADT/StringRef.h>
22 #include <llvm/Support/CommandLine.h>
23 #include <llvm/Support/Error.h>
24 #include <llvm/Support/MemoryBuffer.h>
25 #include <llvm/Support/Process.h>
26
27 #include <AdaptorOCL/OCL/BuiltinResource.h>
28 #include <AdaptorOCL/OCL/LoadBuffer.h>
29 #include <AdaptorOCL/OCL/TB/igc_tb.h>
30 #include <common/igc_regkeys.hpp>
31 #include <iStdLib/utility.h>
32 #include <inc/common/secure_mem.h>
33
34 #include <algorithm>
35 #include <memory>
36 #include <sstream>
37 #include <system_error>
38
39 #include <cstring>
40
41 namespace {
42 struct VcPayloadInfo {
43 bool IsValid = false;
44 size_t IRSize = 0;
45 llvm::StringRef VCApiOpts;
46 llvm::StringRef VCInternalOpts;
47 };
48
49 class BuildDiag {
50 public:
addWarning(const std::string & Str)51 void addWarning(const std::string &Str) {
52 BuildLog << "warning: " << Str << "\n";
53 }
getLog() const54 std::string getLog() const { return BuildLog.str(); }
55
56 private:
57 // for now, we don't differentiate between warnings and errors
58 // the expectation is that a marker indicating an error shall be
59 // reported by other means
60 std::ostringstream BuildLog;
61 };
62
63 } // namespace
64
tryExtractPayload(const char * Input,size_t InputSize)65 static VcPayloadInfo tryExtractPayload(const char *Input, size_t InputSize) {
66 // Payload format:
67 // |-vc-payload|api opts|internal opts|i64(IR size)|i64(Payload size)|-vc-payload|
68 // NOTE: <api/internal opts> are c-strings.
69 //
70 // Should be in sync with:
71 // Source/IGC/AdaptorOCL/ocl_igc_interface/impl/fcl_ocl_translation_ctx_impl.cpp
72
73 // Check for availability of "-vc-payload" marker at the end.
74 const char *PayloadMarker = "-vc-payload";
75 const size_t PayloadMarkerSize = strlen(PayloadMarker);
76 // Make sure that we also have a room for 2 i64 size items.
77 if (InputSize < (PayloadMarkerSize + 2 * sizeof(uint64_t)))
78 return {};
79 const char *const InputEnd = Input + InputSize;
80 if (std::memcmp(InputEnd - PayloadMarkerSize, PayloadMarker,
81 PayloadMarkerSize) != 0)
82 return {};
83
84 // Read IR and Payload sizes. We already ensured that we have the room.
85 uint64_t IrSize;
86 uint64_t PayloadSize;
87 const char *IrSizeBuff =
88 InputEnd - PayloadMarkerSize - 2 * sizeof(uint64_t);
89 const char *PayloadSizeBuff =
90 InputEnd - PayloadMarkerSize - 1 * sizeof(uint64_t);
91 memcpy_s(&IrSize, sizeof(IrSize), IrSizeBuff, sizeof(IrSize));
92 memcpy_s(&PayloadSize, sizeof(PayloadSize), PayloadSizeBuff,
93 sizeof(PayloadSize));
94 if (InputSize != (PayloadSize + IrSize))
95 return {};
96
97 // Search for the start of payload, it should start with "-vc-codegen" marker.
98 const char *const IREnd = InputEnd - PayloadSize;
99 if (std::memcmp(IREnd, PayloadMarker, PayloadMarkerSize) != 0)
100 return {};
101
102 // Make sure that we have a zero-terminated c-string (vc-options are encoded
103 // as such).
104 auto ApiOptsStart = IREnd + PayloadMarkerSize;
105 auto ApiOptsEnd = std::find(ApiOptsStart, InputEnd, 0);
106 if (ApiOptsEnd == InputEnd)
107 return {};
108 auto IntOptStart = ApiOptsEnd + 1;
109 auto IntOptEnd = std::find(IntOptStart, InputEnd, 0);
110 // Consistency check, see the Payload format.
111 if ((IntOptEnd + 1) != IrSizeBuff)
112 return {};
113
114 VcPayloadInfo Result;
115 Result.VCApiOpts = llvm::StringRef(ApiOptsStart);
116 Result.VCInternalOpts = llvm::StringRef(IntOptStart);
117 Result.IRSize = IrSize;
118 Result.IsValid = true;
119
120 return Result;
121 }
122
123 static std::unique_ptr<llvm::MemoryBuffer>
getGenericModuleBuffer(int ResourceID)124 getGenericModuleBuffer(int ResourceID) {
125 std::ostringstream SS;
126 SS << '#' << ResourceID;
127 return std::unique_ptr<llvm::MemoryBuffer>{
128 llvm::LoadBufferFromResource(SS.str().c_str(), "BC")};
129 }
130
131 template <enum vc::bif::RawKind Kind>
getVCModuleBuffer()132 std::unique_ptr<llvm::MemoryBuffer> getVCModuleBuffer() {
133 return llvm::MemoryBuffer::getMemBuffer(vc::bif::getRawData<Kind>(), "",
134 false /* RequiresNullTerminator */);
135 }
136
adjustPlatform(const IGC::CPlatform & IGCPlatform,vc::CompileOptions & Opts)137 static void adjustPlatform(const IGC::CPlatform &IGCPlatform,
138 vc::CompileOptions &Opts) {
139 auto &PlatformInfo = IGCPlatform.getPlatformInfo();
140 unsigned RevId = PlatformInfo.usRevId;
141 Opts.CPUStr = cmc::getPlatformStr(PlatformInfo, /* inout */ RevId);
142 Opts.RevId = RevId;
143 Opts.HasL1ReadOnlyCache = IGCPlatform.hasL1ReadOnlyCache();
144 Opts.HasLocalMemFenceSupress = IGCPlatform.localMemFenceSupress();
145 Opts.WATable = &IGCPlatform.getWATable();
146 }
147
adjustFileType(TC::TB_DATA_FORMAT DataFormat,vc::CompileOptions & Opts)148 static void adjustFileType(TC::TB_DATA_FORMAT DataFormat,
149 vc::CompileOptions &Opts) {
150 switch (DataFormat) {
151 case TC::TB_DATA_FORMAT::TB_DATA_FORMAT_LLVM_TEXT:
152 Opts.FType = vc::FileType::LLVM_TEXT;
153 return;
154 case TC::TB_DATA_FORMAT::TB_DATA_FORMAT_LLVM_BINARY:
155 Opts.FType = vc::FileType::LLVM_BINARY;
156 return;
157 case TC::TB_DATA_FORMAT::TB_DATA_FORMAT_SPIR_V:
158 Opts.FType = vc::FileType::SPIRV;
159 return;
160 default:
161 llvm_unreachable("Data format is not supported yet");
162 }
163 }
164
adjustOptLevel(vc::CompileOptions & Opts)165 static void adjustOptLevel(vc::CompileOptions &Opts) {
166 if (IGC_IS_FLAG_ENABLED(VCOptimizeNone))
167 Opts.OptLevel = vc::OptimizerLevel::None;
168 }
169
adjustStackCalls(vc::CompileOptions & Opts,BuildDiag & Diag)170 static void adjustStackCalls(vc::CompileOptions &Opts, BuildDiag &Diag) {
171 int FCtrlFlag = IGC_GET_FLAG_VALUE(FunctionControl);
172 switch (FCtrlFlag) {
173 default:
174 Opts.FCtrl = FunctionControl::Default;
175 break;
176 case FLAG_FCALL_FORCE_INLINE:
177 Diag.addWarning("VC does not support always inline");
178 break;
179 case FLAG_FCALL_FORCE_SUBROUTINE:
180 Diag.addWarning("VC does not support always subroutine");
181 break;
182 case FLAG_FCALL_FORCE_STACKCALL:
183 Opts.FCtrl = FunctionControl::StackCall;
184 break;
185 case FLAG_FCALL_FORCE_INDIRECTCALL:
186 Diag.addWarning("VC does not support always indirect calls");
187 break;
188 }
189 }
190
191 // Overwrite binary format option for backward compatibility with
192 // environment variable approach.
adjustBinaryFormat(vc::BinaryKind & Binary)193 static void adjustBinaryFormat(vc::BinaryKind &Binary) {
194 if (Binary == vc::BinaryKind::OpenCL && IGC_IS_FLAG_ENABLED(EnableZEBinary))
195 Binary = vc::BinaryKind::ZE;
196 }
197
deriveDefaultableFlagValue(int Flag)198 template <typename T> T deriveDefaultableFlagValue(int Flag) {
199 switch (Flag) {
200 default:
201 return T::Default;
202 case DEFAULTABLE_FLAG_ENABLE:
203 return T::Enable;
204 case DEFAULTABLE_FLAG_DISABLE:
205 return T::Disable;
206 }
207 }
208
adjustTransformationsAndOptimizations(vc::CompileOptions & Opts)209 static void adjustTransformationsAndOptimizations(vc::CompileOptions &Opts) {
210 if (IGC_IS_FLAG_ENABLED(VCLocalizeAccUsage))
211 Opts.ForceLiveRangesLocalizationForAccUsage = true;
212 if (IGC_IS_FLAG_ENABLED(VCDisableNonOverlappingRegionOpt))
213 Opts.ForceDisableNonOverlappingRegionOpt = true;
214 if (IGC_IS_FLAG_ENABLED(VCSaveStackCallLinkage))
215 Opts.SaveStackCallLinkage = true;
216 if (IGC_IS_FLAG_ENABLED(DebugInfoValidation))
217 Opts.ForceDebugInfoValidation = true;
218 Opts.NoOptFinalizerMode =
219 deriveDefaultableFlagValue<vc::NoOptFinalizerControl>(
220 IGC_GET_FLAG_VALUE(VCNoOptFinalizerControl));
221 Opts.DisableLRCoalescingMode =
222 deriveDefaultableFlagValue<vc::DisableLRCoalescingControl>(
223 IGC_GET_FLAG_VALUE(VCDisableLRCoalescingControl));
224 }
225
adjustDumpOptions(vc::CompileOptions & Opts)226 static void adjustDumpOptions(vc::CompileOptions &Opts) {
227 if (IGC_IS_FLAG_ENABLED(ShaderDumpEnable)) {
228 Opts.DumpIR = true;
229 Opts.DumpIsa = true;
230 Opts.DumpAsm = true;
231 Opts.DumpDebugInfo = true;
232 }
233 }
234
adjustOptions(const IGC::CPlatform & IGCPlatform,TC::TB_DATA_FORMAT DataFormat,vc::CompileOptions & Opts,BuildDiag & Diag)235 static void adjustOptions(const IGC::CPlatform &IGCPlatform,
236 TC::TB_DATA_FORMAT DataFormat,
237 vc::CompileOptions &Opts, BuildDiag &Diag) {
238 adjustPlatform(IGCPlatform, Opts);
239 adjustFileType(DataFormat, Opts);
240 adjustOptLevel(Opts);
241 adjustBinaryFormat(Opts.Binary);
242 adjustDumpOptions(Opts);
243 adjustStackCalls(Opts, Diag);
244
245 adjustTransformationsAndOptimizations(Opts);
246 }
247
setErrorMessage(const std::string & ErrorMessage,TC::STB_TranslateOutputArgs & pOutputArgs)248 static void setErrorMessage(const std::string &ErrorMessage,
249 TC::STB_TranslateOutputArgs &pOutputArgs) {
250 pOutputArgs.pErrorString = new char[ErrorMessage.size() + 1];
251 memcpy_s(pOutputArgs.pErrorString, ErrorMessage.size() + 1,
252 ErrorMessage.c_str(), ErrorMessage.size() + 1);
253 pOutputArgs.ErrorStringSize = ErrorMessage.size() + 1;
254 }
255
getError(llvm::Error Err,TC::STB_TranslateOutputArgs * OutputArgs)256 static std::error_code getError(llvm::Error Err,
257 TC::STB_TranslateOutputArgs *OutputArgs) {
258 std::error_code Status;
259 llvm::handleAllErrors(
260 std::move(Err), [&Status, OutputArgs](const llvm::ErrorInfoBase &EI) {
261 Status = EI.convertToErrorCode();
262 setErrorMessage(EI.message(), *OutputArgs);
263 });
264 return Status;
265 }
266
getError(std::error_code Err,TC::STB_TranslateOutputArgs * OutputArgs)267 static std::error_code getError(std::error_code Err,
268 TC::STB_TranslateOutputArgs *OutputArgs) {
269 setErrorMessage(Err.message(), *OutputArgs);
270 return Err;
271 }
272
outputBinary(llvm::StringRef Binary,llvm::StringRef DebugInfo,const BuildDiag & Diag,TC::STB_TranslateOutputArgs * OutputArgs)273 static void outputBinary(llvm::StringRef Binary, llvm::StringRef DebugInfo,
274 const BuildDiag &Diag,
275 TC::STB_TranslateOutputArgs *OutputArgs) {
276 size_t BinarySize = Binary.size();
277 char *BinaryOutput = new char[BinarySize];
278 memcpy_s(BinaryOutput, BinarySize, Binary.data(), BinarySize);
279 OutputArgs->OutputSize = static_cast<uint32_t>(BinarySize);
280 OutputArgs->pOutput = BinaryOutput;
281 if (DebugInfo.size()) {
282 char *DebugInfoOutput = new char[DebugInfo.size()];
283 memcpy_s(DebugInfoOutput, DebugInfo.size(), DebugInfo.data(),
284 DebugInfo.size());
285 OutputArgs->pDebugData = DebugInfoOutput;
286 OutputArgs->DebugDataSize = DebugInfo.size();
287 }
288 const std::string &BuildLog = Diag.getLog();
289 if (!BuildLog.empty()) {
290 // Currently, if warnings are reported, we expected that there was no
291 // error string set.
292 IGC_ASSERT(OutputArgs->pErrorString == nullptr);
293 #ifndef NDEBUG
294 llvm::errs() << BuildLog;
295 #endif
296 setErrorMessage(BuildLog, *OutputArgs);
297 }
298 }
299
300 // Similar to ShaderHashOCL though reinterpretation is hidden inside
301 // iStdLib so probably it will be safer (to use more specialized things).
getShaderHash(llvm::ArrayRef<char> Input)302 static ShaderHash getShaderHash(llvm::ArrayRef<char> Input) {
303 ShaderHash Hash;
304 Hash.asmHash = iSTD::HashFromBuffer(Input.data(), Input.size());
305 return Hash;
306 }
307
dumpInputData(vc::ShaderDumper & Dumper,llvm::StringRef ApiOptions,llvm::StringRef InternalOptions,llvm::ArrayRef<char> Input,bool IsRaw)308 static void dumpInputData(vc::ShaderDumper &Dumper, llvm::StringRef ApiOptions,
309 llvm::StringRef InternalOptions,
310 llvm::ArrayRef<char> Input, bool IsRaw) {
311 if (!IGC_IS_FLAG_ENABLED(ShaderDumpEnable))
312 return;
313
314 Dumper.dumpText(ApiOptions, IsRaw ? "options_raw.txt" : "options.txt");
315 Dumper.dumpText(InternalOptions,
316 IsRaw ? "internal_options_raw.txt" : "internal_options.txt");
317 Dumper.dumpBinary(Input, IsRaw ? "igc_input_raw.spv" : "igc_input.spv");
318 }
319
tryAddAuxiliaryOptions(llvm::StringRef AuxOpt,llvm::StringRef InOpt,std::string & Storage)320 static bool tryAddAuxiliaryOptions(llvm::StringRef AuxOpt,
321 llvm::StringRef InOpt,
322 std::string &Storage) {
323 if (AuxOpt.empty())
324 return false;
325
326 Storage.clear();
327 Storage.append(InOpt.data(), InOpt.size())
328 .append(" ")
329 .append(AuxOpt.data(), AuxOpt.size());
330 return true;
331 }
332
333 // Parse initial options dumping all needed data.
334 // Return structure that describes compilation setup (CompileOptions).
335 // FIXME: payload decoding requires modification of input data so make
336 // it reference until the problem with option passing from FE to BE is
337 // solved in more elegant way.
338 static llvm::Expected<vc::CompileOptions>
parseOptions(vc::ShaderDumper & Dumper,llvm::StringRef ApiOptions,llvm::StringRef InternalOptions,llvm::ArrayRef<char> & Input)339 parseOptions(vc::ShaderDumper &Dumper, llvm::StringRef ApiOptions,
340 llvm::StringRef InternalOptions, llvm::ArrayRef<char> &Input) {
341 auto RawInputDumper = llvm::make_scope_exit([=, &Dumper]() {
342 dumpInputData(Dumper, ApiOptions, InternalOptions, Input, /*IsRaw=*/true);
343 });
344
345 std::string ApiOptionsHolder;
346 std::string InternalOptionsHolder;
347 auto LegacyPayload = tryExtractPayload(Input.data(), Input.size());
348 if (LegacyPayload.IsValid) {
349 ApiOptionsHolder = "-vc-codegen";
350 ApiOptionsHolder.append(" ");
351 ApiOptionsHolder.append(LegacyPayload.VCApiOpts.str());
352 ApiOptions = ApiOptionsHolder;
353
354 InternalOptionsHolder = InternalOptions.str();
355 InternalOptionsHolder.append(" ");
356 InternalOptionsHolder.append(LegacyPayload.VCInternalOpts.str());
357 InternalOptions = InternalOptionsHolder;
358
359 Input = Input.take_front(static_cast<size_t>(LegacyPayload.IRSize));
360 }
361
362 std::string AuxApiOptions;
363 std::string AuxInternalOptions;
364 if (tryAddAuxiliaryOptions(IGC_GET_REGKEYSTRING(VCApiOptions), ApiOptions,
365 AuxApiOptions))
366 ApiOptions = {AuxApiOptions.data(), AuxApiOptions.size()};
367 if (tryAddAuxiliaryOptions(IGC_GET_REGKEYSTRING(VCInternalOptions),
368 InternalOptions, AuxInternalOptions))
369 InternalOptions = {AuxInternalOptions.data(), AuxInternalOptions.size()};
370
371 auto InputDumper = llvm::make_scope_exit([=, &Dumper]() {
372 dumpInputData(Dumper, ApiOptions, InternalOptions, Input, /*IsRaw=*/false);
373 });
374
375 const bool IsStrictParser = IGC_GET_FLAG_VALUE(VCStrictOptionParser);
376 auto ExpOptions =
377 vc::ParseOptions(ApiOptions, InternalOptions, IsStrictParser);
378 if (ExpOptions.errorIsA<vc::NotVCError>()) {
379 RawInputDumper.release();
380 InputDumper.release();
381 }
382 return std::move(ExpOptions);
383 }
384
385 // Returns whether the modules were successfully obtained.
386 template <enum vc::bif::RawKind Printf32, enum vc::bif::RawKind Printf64>
fillPrintfData(vc::ExternalData & ExtData)387 bool fillPrintfData(vc::ExternalData &ExtData) {
388 ExtData.VCPrintf32BIFModule = getVCModuleBuffer<Printf32>();
389 if (!ExtData.VCPrintf32BIFModule)
390 return false;
391 ExtData.VCPrintf64BIFModule = getVCModuleBuffer<Printf64>();
392 return static_cast<bool>(ExtData.VCPrintf64BIFModule);
393 }
394
395 static llvm::Optional<vc::ExternalData>
fillExternalData(vc::BinaryKind Binary)396 fillExternalData(vc::BinaryKind Binary) {
397 vc::ExternalData ExtData;
398 ExtData.OCLGenericBIFModule =
399 getGenericModuleBuffer(OCL_BC);
400 if (!ExtData.OCLGenericBIFModule)
401 return {};
402 switch (Binary) {
403 case vc::BinaryKind::CM:
404 if (!fillPrintfData<vc::bif::RawKind::PrintfCM32,
405 vc::bif::RawKind::PrintfCM64>(ExtData))
406 return {};
407 break;
408 case vc::BinaryKind::OpenCL:
409 if (!fillPrintfData<vc::bif::RawKind::PrintfOCL32,
410 vc::bif::RawKind::PrintfOCL64>(ExtData))
411 return {};
412 break;
413 case vc::BinaryKind::ZE:
414 if (!fillPrintfData<vc::bif::RawKind::PrintfZE32,
415 vc::bif::RawKind::PrintfZE64>(ExtData))
416 return {};
417 break;
418 }
419 ExtData.VCEmulationBIFModule =
420 getVCModuleBuffer<vc::bif::RawKind::Emulation>();
421 if (!ExtData.VCEmulationBIFModule)
422 return {};
423 ExtData.VCSPIRVBuiltinsBIFModule =
424 getVCModuleBuffer<vc::bif::RawKind::SPIRVBuiltins>();
425 if (!ExtData.VCSPIRVBuiltinsBIFModule)
426 return {};
427 return std::move(ExtData);
428 }
429
dumpPlatform(const vc::CompileOptions & Opts,PLATFORM Platform,vc::ShaderDumper & Dumper)430 static void dumpPlatform(const vc::CompileOptions &Opts, PLATFORM Platform,
431 vc::ShaderDumper &Dumper) {
432 #if defined(_DEBUG) || defined(_INTERNAL)
433 if (!IGC_IS_FLAG_ENABLED(ShaderDumpEnable))
434 return;
435
436 std::ostringstream Os;
437 auto Core = Platform.eDisplayCoreFamily;
438 auto RenderCore = Platform.eRenderCoreFamily;
439 auto Product = Platform.eProductFamily;
440 auto RevId = Platform.usRevId;
441
442 Os << "NEO passed: DisplayCore = " << Core << ", RenderCore = " << RenderCore
443 << ", Product = " << Product << ", Revision = " << RevId << "\n";
444 Os << "IGC translated into: " << Opts.CPUStr << ", " << Opts.RevId << "\n";
445
446 Dumper.dumpText(Os.str(), "platform.be.txt");
447 #endif
448 }
449
validateCMProgramForOCLBin(const vc::CGen8CMProgram & CMProgram)450 static void validateCMProgramForOCLBin(const vc::CGen8CMProgram &CMProgram) {
451 IGC_ASSERT_MESSAGE(
452 CMProgram.m_programInfo->m_GlobalPointerAddressRelocAnnotation.globalReloc
453 .empty(),
454 "global section relocations aren't supported for oclbin");
455 IGC_ASSERT_MESSAGE(
456 CMProgram.m_programInfo->m_GlobalPointerAddressRelocAnnotation
457 .globalConstReloc.empty(),
458 "constant section relocations aren't supported for oclbin");
459 }
460
translateBuild(const TC::STB_TranslateInputArgs * InputArgs,TC::STB_TranslateOutputArgs * OutputArgs,TC::TB_DATA_FORMAT InputDataFormatTemp,const IGC::CPlatform & IGCPlatform,float ProfilingTimerResolution)461 std::error_code vc::translateBuild(const TC::STB_TranslateInputArgs *InputArgs,
462 TC::STB_TranslateOutputArgs *OutputArgs,
463 TC::TB_DATA_FORMAT InputDataFormatTemp,
464 const IGC::CPlatform &IGCPlatform,
465 float ProfilingTimerResolution) {
466 llvm::StringRef ApiOptions{InputArgs->pOptions, InputArgs->OptionsSize};
467 llvm::StringRef InternalOptions{InputArgs->pInternalOptions,
468 InputArgs->InternalOptionsSize};
469
470 llvm::ArrayRef<char> Input{InputArgs->pInput, InputArgs->InputSize};
471
472 const ShaderHash Hash = getShaderHash(Input);
473 std::unique_ptr<vc::ShaderDumper> Dumper;
474 if (IGC_IS_FLAG_ENABLED(ShaderDumpEnable)) {
475 Dumper = vc::createVC_IGCFileDumper(Hash);
476 } else {
477 Dumper = vc::createDefaultShaderDumper();
478 }
479
480 auto ExpOptions = parseOptions(*Dumper, ApiOptions, InternalOptions, Input);
481 // If vc was not called, then observable state should not be changed.
482 if (ExpOptions.errorIsA<vc::NotVCError>()) {
483 llvm::consumeError(ExpOptions.takeError());
484 return vc::errc::not_vc_codegen;
485 }
486 // Other errors are VC related and should be reported.
487 if (!ExpOptions)
488 return getError(ExpOptions.takeError(), OutputArgs);
489
490 BuildDiag Diag;
491 vc::CompileOptions &Opts = ExpOptions.get();
492 adjustOptions(IGCPlatform, InputDataFormatTemp, Opts, Diag);
493
494 // here we have Opts set and can dump what we got from runtime and how
495 // we understood it
496 dumpPlatform(Opts, IGCPlatform.getPlatformInfo(), *Dumper);
497
498 if (IGC_IS_FLAG_ENABLED(ShaderOverride))
499 Opts.ShaderOverrider =
500 vc::createVC_IGCShaderOverrider(Hash, IGCPlatform.getPlatformInfo());
501
502 Opts.Dumper = std::move(Dumper);
503
504 auto ExtData = fillExternalData(Opts.Binary);
505 if (!ExtData)
506 return getError(vc::make_error_code(vc::errc::bif_load_fail),
507 OutputArgs);
508 llvm::ArrayRef<uint32_t> SpecConstIds{InputArgs->pSpecConstantsIds,
509 InputArgs->SpecConstantsSize};
510 llvm::ArrayRef<uint64_t> SpecConstValues{InputArgs->pSpecConstantsValues,
511 InputArgs->SpecConstantsSize};
512 auto ExpOutput = vc::Compile(Input, Opts, ExtData.getValue(), SpecConstIds,
513 SpecConstValues);
514 if (!ExpOutput)
515 return getError(ExpOutput.takeError(), OutputArgs);
516 vc::CompileOutput &Res = ExpOutput.get();
517
518 switch (Opts.Binary) {
519 case vc::BinaryKind::CM: {
520 auto &CompileResult = std::get<vc::cm::CompileOutput>(Res);
521 outputBinary(CompileResult.IsaBinary, llvm::StringRef(), Diag, OutputArgs);
522 break;
523 }
524 case vc::BinaryKind::OpenCL: {
525 auto &CompileResult = std::get<vc::ocl::CompileOutput>(Res);
526 vc::CGen8CMProgram CMProgram{IGCPlatform.getPlatformInfo(), IGCPlatform.getWATable()};
527 vc::createBinary(CMProgram, CompileResult);
528 validateCMProgramForOCLBin(CMProgram);
529 CMProgram.CreateKernelBinaries(Opts);
530 Util::BinaryStream ProgramBinary;
531 CMProgram.GetProgramBinary(ProgramBinary, CompileResult.PointerSizeInBytes);
532 llvm::StringRef BinaryRef{ProgramBinary.GetLinearPointer(),
533 static_cast<std::size_t>(ProgramBinary.Size())};
534
535 Util::BinaryStream ProgramDebugData;
536 CMProgram.GetProgramDebugData(ProgramDebugData);
537 llvm::StringRef DebugInfoRef{
538 ProgramDebugData.GetLinearPointer(),
539 static_cast<std::size_t>(ProgramDebugData.Size())};
540
541 if (CMProgram.HasErrors())
542 return getError(CMProgram.GetError(), OutputArgs);
543
544 outputBinary(BinaryRef, DebugInfoRef, Diag, OutputArgs);
545 break;
546 }
547 case vc::BinaryKind::ZE: {
548 auto &CompileResult = std::get<vc::ocl::CompileOutput>(Res);
549 vc::CGen8CMProgram CMProgram{IGCPlatform.getPlatformInfo(), IGCPlatform.getWATable()};
550 vc::createBinary(CMProgram, CompileResult);
551 llvm::SmallVector<char, 0> ProgramBinary;
552 llvm::raw_svector_ostream ProgramBinaryOS{ProgramBinary};
553 CMProgram.GetZEBinary(ProgramBinaryOS, CompileResult.PointerSizeInBytes);
554
555 if (CMProgram.HasErrors())
556 return getError(CMProgram.GetError(), OutputArgs);
557
558 llvm::StringRef BinaryRef{ProgramBinary.data(), ProgramBinary.size()};
559 outputBinary(BinaryRef, {}, Diag, OutputArgs);
560 break;
561 }
562 }
563
564 return {};
565 }
566