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