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