1 /*
2  * Copyright (C) 2018-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #pragma once
9 #include "shared/source/built_ins/sip.h"
10 #include "shared/source/compiler_interface/compiler_cache.h"
11 #include "shared/source/helpers/string.h"
12 #include "shared/source/os_interface/os_library.h"
13 #include "shared/source/utilities/arrayref.h"
14 #include "shared/source/utilities/spinlock.h"
15 
16 #include "cif/common/cif_main.h"
17 #include "ocl_igc_interface/code_type.h"
18 #include "ocl_igc_interface/fcl_ocl_device_ctx.h"
19 #include "ocl_igc_interface/igc_ocl_device_ctx.h"
20 
21 #include <map>
22 #include <unordered_map>
23 
24 namespace NEO {
25 class Device;
26 
27 using specConstValuesMap = std::unordered_map<uint32_t, uint64_t>;
28 
29 struct TranslationInput {
30     TranslationInput(IGC::CodeType::CodeType_t srcType, IGC::CodeType::CodeType_t outType, IGC::CodeType::CodeType_t preferredIntermediateType = IGC::CodeType::undefined)
srcTypeTranslationInput31         : srcType(srcType), preferredIntermediateType(preferredIntermediateType), outType(outType) {
32     }
33 
34     bool allowCaching = false;
35 
36     ArrayRef<const char> src;
37     ArrayRef<const char> apiOptions;
38     ArrayRef<const char> internalOptions;
39     const char *tracingOptions = nullptr;
40     uint32_t tracingOptionsCount = 0;
41     IGC::CodeType::CodeType_t srcType = IGC::CodeType::invalid;
42     IGC::CodeType::CodeType_t preferredIntermediateType = IGC::CodeType::invalid;
43     IGC::CodeType::CodeType_t outType = IGC::CodeType::invalid;
44     void *GTPinInput = nullptr;
45 
46     specConstValuesMap specializedValues;
47 };
48 
49 struct TranslationOutput {
50     enum class ErrorCode {
51         Success = 0,
52         CompilerNotAvailable,
53         CompilationFailure,
54         BuildFailure,
55         LinkFailure,
56         AlreadyCompiled,
57         UnknownError,
58     };
59 
60     struct MemAndSize {
61         std::unique_ptr<char[]> mem;
62         size_t size = 0;
63     };
64 
65     IGC::CodeType::CodeType_t intermediateCodeType = IGC::CodeType::invalid;
66     MemAndSize intermediateRepresentation;
67     MemAndSize deviceBinary;
68     MemAndSize debugData;
69     std::string frontendCompilerLog;
70     std::string backendCompilerLog;
71 
72     template <typename ContainerT>
makeCopyTranslationOutput73     static void makeCopy(ContainerT &dst, CIF::Builtins::BufferSimple *src) {
74         if ((nullptr == src) || (src->GetSizeRaw() == 0)) {
75             dst.clear();
76             return;
77         }
78         dst.assign(src->GetMemory<char>(), src->GetSize<char>());
79     }
80 
makeCopyTranslationOutput81     static void makeCopy(MemAndSize &dst, CIF::Builtins::BufferSimple *src) {
82         if ((nullptr == src) || (src->GetSizeRaw() == 0)) {
83             dst.mem.reset();
84             dst.size = 0U;
85             return;
86         }
87 
88         dst.size = src->GetSize<char>();
89         dst.mem = ::makeCopy(src->GetMemory<void>(), src->GetSize<char>());
90     }
91 };
92 
93 struct SpecConstantInfo {
94     CIF::RAII::UPtr_t<CIF::Builtins::BufferLatest> idsBuffer;
95     CIF::RAII::UPtr_t<CIF::Builtins::BufferLatest> sizesBuffer;
96 };
97 
98 class CompilerInterface {
99   public:
100     CompilerInterface();
101     CompilerInterface(const CompilerInterface &) = delete;
102     CompilerInterface &operator=(const CompilerInterface &) = delete;
103     CompilerInterface(CompilerInterface &&) = delete;
104     CompilerInterface &operator=(CompilerInterface &&) = delete;
105     virtual ~CompilerInterface();
106 
107     template <typename CompilerInterfaceT = CompilerInterface>
createInstance(std::unique_ptr<CompilerCache> && cache,bool requireFcl)108     static CompilerInterfaceT *createInstance(std::unique_ptr<CompilerCache> &&cache, bool requireFcl) {
109         auto instance = new CompilerInterfaceT();
110         if (!instance->initialize(std::move(cache), requireFcl)) {
111             delete instance;
112             instance = nullptr;
113         }
114         return instance;
115     }
116 
117     MOCKABLE_VIRTUAL TranslationOutput::ErrorCode build(const NEO::Device &device,
118                                                         const TranslationInput &input,
119                                                         TranslationOutput &output);
120 
121     MOCKABLE_VIRTUAL TranslationOutput::ErrorCode compile(const NEO::Device &device,
122                                                           const TranslationInput &input,
123                                                           TranslationOutput &output);
124 
125     MOCKABLE_VIRTUAL TranslationOutput::ErrorCode link(const NEO::Device &device,
126                                                        const TranslationInput &input,
127                                                        TranslationOutput &output);
128 
129     MOCKABLE_VIRTUAL TranslationOutput::ErrorCode getSpecConstantsInfo(const NEO::Device &device,
130                                                                        ArrayRef<const char> srcSpirV, SpecConstantInfo &output);
131 
132     TranslationOutput::ErrorCode createLibrary(NEO::Device &device,
133                                                const TranslationInput &input,
134                                                TranslationOutput &output);
135 
136     MOCKABLE_VIRTUAL TranslationOutput::ErrorCode getSipKernelBinary(NEO::Device &device, SipKernelType type, std::vector<char> &retBinary,
137                                                                      std::vector<char> &stateSaveAreaHeader);
138 
139   protected:
140     MOCKABLE_VIRTUAL bool initialize(std::unique_ptr<CompilerCache> &&cache, bool requireFcl);
141     MOCKABLE_VIRTUAL bool loadFcl();
142     MOCKABLE_VIRTUAL bool loadIgc();
143 
144     static SpinLock spinlock;
lock()145     MOCKABLE_VIRTUAL std::unique_lock<SpinLock> lock() {
146         return std::unique_lock<SpinLock>{spinlock};
147     }
148     std::unique_ptr<CompilerCache> cache = nullptr;
149 
150     using igcDevCtxUptr = CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL>;
151     using fclDevCtxUptr = CIF::RAII::UPtr_t<IGC::FclOclDeviceCtxTagOCL>;
152 
153     std::unique_ptr<OsLibrary> igcLib;
154     CIF::RAII::UPtr_t<CIF::CIFMain> igcMain = nullptr;
155     std::map<const Device *, igcDevCtxUptr> igcDeviceContexts;
156 
157     std::unique_ptr<OsLibrary> fclLib;
158     CIF::RAII::UPtr_t<CIF::CIFMain> fclMain = nullptr;
159     std::map<const Device *, fclDevCtxUptr> fclDeviceContexts;
160     CIF::RAII::UPtr_t<IGC::FclOclTranslationCtxTagOCL> fclBaseTranslationCtx = nullptr;
161 
162     MOCKABLE_VIRTUAL IGC::FclOclDeviceCtxTagOCL *getFclDeviceCtx(const Device &device);
163     MOCKABLE_VIRTUAL IGC::IgcOclDeviceCtxTagOCL *getIgcDeviceCtx(const Device &device);
164     MOCKABLE_VIRTUAL IGC::CodeType::CodeType_t getPreferredIntermediateRepresentation(const Device &device);
165 
166     MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::FclOclTranslationCtxTagOCL> createFclTranslationCtx(const Device &device,
167                                                                                                 IGC::CodeType::CodeType_t inType,
168                                                                                                 IGC::CodeType::CodeType_t outType);
169     MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::IgcOclTranslationCtxTagOCL> createIgcTranslationCtx(const Device &device,
170                                                                                                 IGC::CodeType::CodeType_t inType,
171                                                                                                 IGC::CodeType::CodeType_t outType);
172 
isFclAvailable()173     bool isFclAvailable() const {
174         return (fclMain != nullptr);
175     }
176 
isIgcAvailable()177     bool isIgcAvailable() const {
178         return (igcMain != nullptr);
179     }
180 
isCompilerAvailable(IGC::CodeType::CodeType_t translationSrc,IGC::CodeType::CodeType_t translationDst)181     bool isCompilerAvailable(IGC::CodeType::CodeType_t translationSrc, IGC::CodeType::CodeType_t translationDst) const {
182         bool requiresFcl = (IGC::CodeType::oclC == translationSrc);
183         bool requiresIgc = (IGC::CodeType::oclC != translationSrc) || ((IGC::CodeType::spirV != translationDst) && (IGC::CodeType::llvmBc != translationDst) && (IGC::CodeType::llvmLl != translationDst));
184         return (isFclAvailable() || (false == requiresFcl)) && (isIgcAvailable() || (false == requiresIgc));
185     }
186 };
187 } // namespace NEO
188