1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #pragma once
10 
11 #include "ocl_igc_interface/igc_ocl_translation_ctx.h"
12 #include "ocl_igc_interface/impl/igc_ocl_device_ctx_impl.h"
13 
14 #include <memory>
15 #include <iomanip>
16 
17 #include "cif/builtins/memory/buffer/impl/buffer_impl.h"
18 #include "cif/helpers/error.h"
19 #include "cif/export/pimpl_base.h"
20 
21 #include "ocl_igc_interface/impl/ocl_translation_output_impl.h"
22 
23 #include "AdaptorOCL/OCL/TB/igc_tb.h"
24 #include "common/debug/Debug.hpp"
25 
26 #include "cif/macros/enable.h"
27 #include <spirv-tools/libspirv.h>
28 
29 namespace TC{
30 
31 // Taken from dllInterfaceCompute
32 extern bool ProcessElfInput(
33   STB_TranslateInputArgs &InputArgs,
34   STB_TranslateOutputArgs &OutputArgs,
35   IGC::OpenCLProgramContext &Context,
36   PLATFORM &platform, bool isOutputLlvmBinary);
37 
38 extern bool ParseInput(
39   llvm::Module*& pKernelModule,
40   const STB_TranslateInputArgs* pInputArgs,
41   STB_TranslateOutputArgs* pOutputArgs,
42   IGC::OpenCLProgramContext &oclContext,
43   TB_DATA_FORMAT inputDataFormatTemp);
44 
45 bool TranslateBuild(
46   const STB_TranslateInputArgs* pInputArgs,
47   STB_TranslateOutputArgs* pOutputArgs,
48   TB_DATA_FORMAT inputDataFormatTemp,
49   const IGC::CPlatform &platform,
50   float profilingTimerResolution);
51 
52 bool TranslateBuildSPMD(
53   const STB_TranslateInputArgs* pInputArgs,
54   STB_TranslateOutputArgs* pOutputArgs,
55   TB_DATA_FORMAT inputDataFormatTemp,
56   const IGC::CPlatform &platform,
57   float profilingTimerResolution,
58   const ShaderHash& inputShHash);
59 
60 bool TranslateBuildVC(
61   const STB_TranslateInputArgs* pInputArgs,
62   STB_TranslateOutputArgs* pOutputArgs,
63   TB_DATA_FORMAT inputDataFormatTemp,
64   const IGC::CPlatform &platform,
65   float profilingTimerResolution,
66   const ShaderHash& inputShHash);
67 
68 bool ReadSpecConstantsFromSPIRV(
69     std::istream &IS,
70     std::vector<std::pair<uint32_t, uint32_t>> &OutSCInfo);
71 
72 void DumpShaderFile(
73     const std::string& dstDir,
74     const char* pBuffer,
75     const UINT bufferSize,
76     const QWORD hash,
77     const std::string& ext,
78     std::string* fileName);
79 
80 spv_result_t DisassembleSPIRV(
81     const char* pBuffer,
82     UINT bufferSize,
83     spv_text* outSpirvAsm);
84 }
85 
86 bool enableSrcLine(void*);
87 
88 namespace IGC {
89 
toLegacyFormat(CodeType::CodeType_t format)90 inline TC::TB_DATA_FORMAT toLegacyFormat(CodeType::CodeType_t format){
91     switch(format){
92         case CodeType::elf : return TC::TB_DATA_FORMAT_ELF; break;
93         case CodeType::llvmBc : return TC::TB_DATA_FORMAT_LLVM_BINARY; break;
94         case CodeType::llvmLl : return TC::TB_DATA_FORMAT_LLVM_TEXT; break;
95         case CodeType::oclC : return TC::TB_DATA_FORMAT_OCL_TEXT; break;
96         case CodeType::oclGenBin : return TC::TB_DATA_FORMAT_DEVICE_BINARY; break;
97         case CodeType::spirV : return TC::TB_DATA_FORMAT_SPIR_V; break;
98         default:
99             return TC::TB_DATA_FORMAT_UNKNOWN;
100     }
101 }
102 
103 struct IGC_State {
104 protected:
105     bool isAlive;
106 public:
IGC_StateIGC_State107     IGC_State() {
108         isAlive = true;
109     }
~IGC_StateIGC_State110     ~IGC_State() {
111         isAlive = false;
112     }
isDestructedIGC_State113     static const bool isDestructed() {
114         static const IGC_State obj;
115         return !obj.isAlive;
116     }
117 };
118 
CIF_DECLARE_INTERFACE_PIMPL(IgcOclTranslationCtx)119 CIF_DECLARE_INTERFACE_PIMPL(IgcOclTranslationCtx) : CIF::PimplBase
120 {
121     CIF_PIMPL_DECLARE_CONSTRUCTOR(CIF::Version_t version, CIF_PIMPL(IgcOclDeviceCtx) *globalState,
122                                   CodeType::CodeType_t inType, CodeType::CodeType_t outType)
123         : globalState(CIF::Sanity::ToReferenceOrAbort(globalState)), inType(inType), outType(outType)
124     {
125     }
126 
127     static bool SupportsTranslation(CodeType::CodeType_t inType, CodeType::CodeType_t outType){
128         static std::pair<CodeType::CodeType_t, CodeType::CodeType_t> supportedTranslations[] =
129             {
130                   // from                 // to
131                 { CodeType::elf,      CodeType::llvmBc },
132                 { CodeType::llvmLl,   CodeType::oclGenBin },
133                 { CodeType::llvmBc,   CodeType::oclGenBin },
134                 { CodeType::spirV,    CodeType::oclGenBin },
135             };
136         for(const auto & st : supportedTranslations){
137             if((inType == st.first) && (outType == st.second)){
138                 return true;
139             }
140         }
141         return false;
142     }
143 
144     bool GetSpecConstantsInfo(CIF::Builtins::BufferSimple *src,
145                               CIF::Builtins::BufferSimple *outSpecConstantsIds,
146                               CIF::Builtins::BufferSimple *outSpecConstantsSizes)
147     {
148         if (IGC_State::isDestructed()) {
149             return false;
150         }
151         bool success = false;
152         const char* pInput = src->GetMemory<char>();
153         uint32_t inputSize = static_cast<uint32_t>(src->GetSizeRaw());
154 
155         if(this->inType == CodeType::spirV){
156             // load registry keys to make sure that flags can be read correctly
157             LoadRegistryKeys();
158             if (IGC_IS_FLAG_ENABLED(ShaderDumpEnable))
159             {
160                 // dump SPIRV input if flag is enabled
161                 const char* pOutputFolder = Debug::GetShaderOutputFolder();
162                 QWORD hash = Debug::ShaderHashOCL(reinterpret_cast<const UINT*>(pInput), inputSize / 4).getAsmHash();
163 
164                 TC::DumpShaderFile(pOutputFolder, pInput, inputSize, hash, ".spv", nullptr);
165 #if defined(IGC_SPIRV_TOOLS_ENABLED)
166                 spv_text spirvAsm = nullptr;
167                 if (TC::DisassembleSPIRV(pInput, inputSize, &spirvAsm) == SPV_SUCCESS)
168                 {
169                     TC::DumpShaderFile(pOutputFolder, spirvAsm->str, spirvAsm->length, hash, ".spvasm", nullptr);
170                 }
171                 spvTextDestroy(spirvAsm);
172 #endif // defined(IGC_SPIRV_TOOLS_ENABLED)
173             }
174             llvm::StringRef strInput = llvm::StringRef(pInput, inputSize);
175             std::istringstream IS(strInput.str());
176 
177             // vector of pairs [spec_id, spec_size]
178             std::vector<std::pair<uint32_t, uint32_t>> SCInfo;
179             success = TC::ReadSpecConstantsFromSPIRV(IS, SCInfo);
180 
181             outSpecConstantsIds->Resize(sizeof(uint32_t) * SCInfo.size());
182             outSpecConstantsSizes->Resize(sizeof(uint32_t) * SCInfo.size());
183 
184             uint32_t* specConstantsIds = outSpecConstantsIds->GetMemoryWriteable<uint32_t>();
185             uint32_t* specConstantsSizes = outSpecConstantsSizes->GetMemoryWriteable<uint32_t>();
186 
187             for(uint32_t i = 0; i < SCInfo.size(); ++i){
188                 specConstantsIds[i] = SCInfo.at(i).first;
189                 specConstantsSizes[i] = SCInfo.at(i).second;
190             }
191         }
192         else{
193             success = false;
194         }
195 
196         return success;
197     }
198 
199     OclTranslationOutputBase *Translate(CIF::Version_t outVersion,
200                                         CIF::Builtins::BufferSimple *src,
201                                         CIF::Builtins::BufferSimple *specConstantsIds,
202                                         CIF::Builtins::BufferSimple *specConstantsValues,
203                                         CIF::Builtins::BufferSimple *options,
204                                         CIF::Builtins::BufferSimple *internalOptions,
205                                         CIF::Builtins::BufferSimple *tracingOptions,
206                                         uint32_t tracingOptionsCount,
207                                         void *gtPinInput) const{
208         // Create interface for return data
209         auto outputInterface = CIF::RAII::UPtr(CIF::InterfaceCreator<OclTranslationOutput>::CreateInterfaceVer(outVersion, this->outType));
210         if(outputInterface == nullptr){
211             return nullptr; // OOM
212         }
213         if (IGC_State::isDestructed()) {
214             outputInterface->GetImpl()->SetError(TranslationErrorType::UnhandledInput, "IGC is destructed");
215             return outputInterface.release();
216         }
217 
218         TC::STB_TranslateInputArgs inputArgs;
219         if(src != nullptr){
220             if (gtPinInput)
221             {
222                 bool srcLine = enableSrcLine(gtPinInput);
223                 if (srcLine)
224                 {
225                     const char* arg = " -gline-tables-only";
226                     src->PushBackRawBytes(arg, strlen(arg));
227                 }
228             }
229             inputArgs.pInput = src->GetMemoryWriteable<char>();
230             inputArgs.InputSize = static_cast<uint32_t>(src->GetSizeRaw());
231         }
232         if(options != nullptr){
233             inputArgs.pOptions = options->GetMemory<char>();
234             inputArgs.OptionsSize = static_cast<uint32_t>(options->GetSizeRaw());
235         }
236         if(internalOptions != nullptr){
237             inputArgs.pInternalOptions =  internalOptions->GetMemory<char>();
238             inputArgs.InternalOptionsSize = static_cast<uint32_t>(internalOptions->GetSizeRaw());
239         }
240         if(tracingOptions != nullptr){
241             inputArgs.pTracingOptions = tracingOptions->GetMemoryRawWriteable();
242         }
243         inputArgs.TracingOptionsCount = tracingOptionsCount;
244         if(specConstantsIds != nullptr && specConstantsValues != nullptr){
245             inputArgs.pSpecConstantsIds = specConstantsIds->GetMemory<uint32_t>();
246             inputArgs.SpecConstantsSize = static_cast<uint32_t>(specConstantsIds->GetSizeRaw() / sizeof(uint32_t));
247             inputArgs.pSpecConstantsValues = specConstantsValues->GetMemory<uint64_t>();
248         }
249         inputArgs.GTPinInput = gtPinInput;
250 
251         CIF::Sanity::NotNullOrAbort(this->globalState.GetPlatformImpl());
252         auto platform = this->globalState.GetPlatformImpl()->p;
253 
254         USC::SShaderStageBTLayout zeroLayout = USC::g_cZeroShaderStageBTLayout;
255         IGC::COCLBTILayout oclLayout(&zeroLayout);
256 
257         TC::STB_TranslateOutputArgs output;
258         CIF::SafeZeroOut(output);
259 
260         std::string RegKeysFlagsFromOptions;
261         if (inputArgs.pOptions != nullptr)
262         {
263             const std::string optionsWithFlags = inputArgs.pOptions;
264             std::size_t found = optionsWithFlags.find("-igc_opts");
265             if (found != std::string::npos)
266             {
267                 std::size_t foundFirstSingleQuote = optionsWithFlags.find('\'', found);
268                 std::size_t foundSecondSingleQuote = optionsWithFlags.find('\'', foundFirstSingleQuote + 1);
269                 if (foundFirstSingleQuote != std::string::npos && foundSecondSingleQuote)
270                 {
271                     RegKeysFlagsFromOptions = optionsWithFlags.substr(foundFirstSingleQuote + 1, (foundSecondSingleQuote - foundFirstSingleQuote - 1));
272                     RegKeysFlagsFromOptions = RegKeysFlagsFromOptions + ',';
273                 }
274             }
275         }
276         bool RegFlagNameError = 0;
277         LoadRegistryKeys(RegKeysFlagsFromOptions, &RegFlagNameError);
278         if(RegFlagNameError) outputInterface->GetImpl()->SetError(TranslationErrorType::Unused, "Invalid registry flag name in -igc_opts, at least one flag has been ignored");
279 
280         IGC::CPlatform igcPlatform = this->globalState.GetIgcCPlatform();
281 
282         // extra ocl options set from regkey
283         const char *extraOptions = IGC_GET_REGKEYSTRING(ExtraOCLOptions);
284         std::string combinedOptions;
285         if (extraOptions[0] != '\0')
286         {
287             if (inputArgs.pOptions != nullptr)
288             {
289                 combinedOptions = std::string(inputArgs.pOptions) + ' ';
290             }
291             combinedOptions += extraOptions;
292             inputArgs.pOptions = combinedOptions.c_str();
293             inputArgs.OptionsSize = combinedOptions.size();
294         }
295 
296         // extra ocl internal options set from regkey
297         const char *extraInternlOptions = IGC_GET_REGKEYSTRING(ExtraOCLInternalOptions);
298         std::string combinedInternalOptions;
299         if (extraInternlOptions[0] != '\0')
300         {
301             if (inputArgs.pInternalOptions != nullptr)
302             {
303                 combinedInternalOptions = std::string(inputArgs.pInternalOptions) + ' ';
304             }
305             combinedInternalOptions += extraInternlOptions;
306             inputArgs.pInternalOptions = combinedInternalOptions.c_str();
307             inputArgs.InternalOptionsSize = combinedInternalOptions.size();
308         }
309 
310         bool success = false;
311         if (this->inType == CodeType::elf)
312         {
313             // Handle TB_DATA_FORMAT_ELF input as a result of a call to
314             // clLinkLibrary(). There are two possible scenarios, link input
315             // to form a new library (BC module) or link input to form an
316             // executable.
317 
318             // First, link input modules together
319             CDriverInfo dummyDriverInfo;
320             IGC::OpenCLProgramContext oclContextTemp(oclLayout, igcPlatform, &inputArgs, dummyDriverInfo, nullptr, false);
321             IGC::Debug::RegisterComputeErrHandlers(*oclContextTemp.getLLVMContext());
322             success = TC::ProcessElfInput(inputArgs, output, oclContextTemp, platform, this->outType == CodeType::llvmBc);
323         }else
324         {
325             if ((this->inType == CodeType::llvmLl) ||
326                 (this->inType == CodeType::spirV) ||
327                 (this->inType == CodeType::llvmBc))
328             {
329                 TC::TB_DATA_FORMAT inFormatLegacy = toLegacyFormat(this->inType);
330                 success = TC::TranslateBuild(
331                     &inputArgs,
332                     &output,
333                     inFormatLegacy,
334                     igcPlatform,
335                     this->globalState.MiscOptions.ProfilingTimerResolution);
336             }
337             else
338             {
339                 outputInterface->GetImpl()->SetError(TranslationErrorType::UnhandledInput, "Unhandled inType");
340                 success = false;
341             }
342         }
343 
344         auto outputData = std::unique_ptr<char[]>(output.pOutput);
345         auto errorString = std::unique_ptr<char[]>(output.pErrorString);
346         auto debugData = std::unique_ptr<char[]>(output.pDebugData);
347 
348         bool dataCopiedSuccessfuly = true;
349         if(success){
350             dataCopiedSuccessfuly &= outputInterface->GetImpl()->AddWarning(output.pErrorString, output.ErrorStringSize);
351             dataCopiedSuccessfuly &= outputInterface->GetImpl()->CloneDebugData(output.pDebugData, output.DebugDataSize);
352             dataCopiedSuccessfuly &= outputInterface->GetImpl()->SetSuccessfulAndCloneOutput(output.pOutput, output.OutputSize);
353         }else{
354             dataCopiedSuccessfuly &= outputInterface->GetImpl()->SetError(TranslationErrorType::FailedCompilation, output.pErrorString);
355         }
356 
357         if(dataCopiedSuccessfuly == false){
358             return nullptr; // OOM
359         }
360 
361         return outputInterface.release();
362     }
363 
364 protected:
365     CIF_PIMPL(IgcOclDeviceCtx) &globalState;
366     CodeType::CodeType_t inType;
367     CodeType::CodeType_t outType;
368 };
369 
370 CIF_DEFINE_INTERFACE_TO_PIMPL_FORWARDING_CTOR_DTOR(IgcOclTranslationCtx);
371 
372 }
373 
374 #include "cif/macros/disable.h"
375