1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
/*
* Copyright (C) 2018-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/helpers/non_copyable_or_moveable.h"
#include "shared/source/utilities/arrayref.h"
#include "shared/source/utilities/spinlock.h"
#include "shared/source/utilities/stackvec.h"
#include "cif/common/cif_main.h"
#include "ocl_igc_interface/code_type.h"
#include "ocl_igc_interface/fcl_ocl_device_ctx.h"
#include "ocl_igc_interface/igc_ocl_device_ctx.h"
#include <map>
#include <unordered_map>
namespace NEO {
enum class SipKernelType : std::uint32_t;
class OsLibrary;
class CompilerCache;
class Device;
struct TargetDevice;
using specConstValuesMap = std::unordered_map<uint32_t, uint64_t>;
struct TranslationInput {
TranslationInput(IGC::CodeType::CodeType_t srcType, IGC::CodeType::CodeType_t outType, IGC::CodeType::CodeType_t preferredIntermediateType = IGC::CodeType::undefined)
: srcType(srcType), preferredIntermediateType(preferredIntermediateType), outType(outType) {
}
bool allowCaching = true;
ArrayRef<const char> src;
ArrayRef<const char> apiOptions;
ArrayRef<const char> internalOptions;
const char *tracingOptions = nullptr;
uint32_t tracingOptionsCount = 0;
IGC::CodeType::CodeType_t srcType = IGC::CodeType::invalid;
IGC::CodeType::CodeType_t preferredIntermediateType = IGC::CodeType::invalid;
IGC::CodeType::CodeType_t outType = IGC::CodeType::invalid;
void *gtPinInput = nullptr;
specConstValuesMap specializedValues;
};
struct TranslationOutput {
enum class ErrorCode {
success = 0,
compilerNotAvailable,
compilationFailure,
buildFailure,
linkFailure,
alreadyCompiled,
unknownError,
};
struct MemAndSize {
std::unique_ptr<char[]> mem;
size_t size = 0;
};
IGC::CodeType::CodeType_t intermediateCodeType = IGC::CodeType::invalid;
MemAndSize intermediateRepresentation;
MemAndSize finalizerInputRepresentation;
MemAndSize deviceBinary;
MemAndSize debugData;
std::string frontendCompilerLog;
std::string backendCompilerLog;
template <typename ContainerT>
static void makeCopy(ContainerT &dst, CIF::Builtins::BufferSimple *src) {
if ((nullptr == src) || (src->GetSizeRaw() == 0)) {
dst.clear();
return;
}
dst.assign(src->GetMemory<char>(), src->GetSize<char>());
}
template <typename ContainerT, typename SeparatorT>
static void append(ContainerT &dst, CIF::Builtins::BufferSimple *src, const SeparatorT *separator, size_t separatorLen) {
if ((nullptr == src) || (src->GetSizeRaw() == 0)) {
return;
}
if ((false == dst.empty()) && separator && (separatorLen > 0)) {
dst.append(separator, separatorLen);
}
dst.append(src->GetMemory<char>(), src->GetSize<char>());
}
template <typename ContainerT, typename SeparatorT>
static void append(ContainerT &dst, CIF::Builtins::BufferSimple *src, const SeparatorT *separator) {
append(dst, src, separator, 1);
}
static void makeCopy(MemAndSize &dst, CIF::Builtins::BufferSimple *src);
};
struct SpecConstantInfo {
CIF::RAII::UPtr_t<CIF::Builtins::BufferLatest> idsBuffer;
CIF::RAII::UPtr_t<CIF::Builtins::BufferLatest> sizesBuffer;
};
enum class CachingMode {
none,
direct,
preProcess
};
class CompilerInterface : NEO::NonCopyableAndNonMovableClass {
public:
CompilerInterface();
virtual ~CompilerInterface();
template <typename CompilerInterfaceT = CompilerInterface>
static CompilerInterfaceT *createInstance(std::unique_ptr<CompilerCache> &&cache, bool requireFcl) {
auto instance = new CompilerInterfaceT();
if (!instance->initialize(std::move(cache), requireFcl)) {
delete instance;
instance = nullptr;
}
return instance;
}
MOCKABLE_VIRTUAL TranslationOutput::ErrorCode build(const NEO::Device &device,
const TranslationInput &input,
TranslationOutput &output);
MOCKABLE_VIRTUAL TranslationOutput::ErrorCode compile(const NEO::Device &device,
const TranslationInput &input,
TranslationOutput &output);
MOCKABLE_VIRTUAL TranslationOutput::ErrorCode link(const NEO::Device &device,
const TranslationInput &input,
TranslationOutput &output);
MOCKABLE_VIRTUAL TranslationOutput::ErrorCode getSpecConstantsInfo(const NEO::Device &device,
ArrayRef<const char> srcSpirV, SpecConstantInfo &output);
TranslationOutput::ErrorCode createLibrary(NEO::Device &device,
const TranslationInput &input,
TranslationOutput &output);
MOCKABLE_VIRTUAL TranslationOutput::ErrorCode getSipKernelBinary(NEO::Device &device, SipKernelType type, std::vector<char> &retBinary,
std::vector<char> &stateSaveAreaHeader);
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::IgcFeaturesAndWorkaroundsTagOCL> getIgcFeaturesAndWorkarounds(const NEO::Device &device);
protected:
struct CompilerLibraryEntry {
std::string revision;
size_t libSize{};
time_t libMTime{};
std::unique_ptr<OsLibrary> library;
CIF::RAII::UPtr_t<CIF::CIFMain> entryPoint;
};
MOCKABLE_VIRTUAL bool initialize(std::unique_ptr<CompilerCache> &&cache, bool requireFcl);
MOCKABLE_VIRTUAL bool loadFcl();
MOCKABLE_VIRTUAL bool loadIgcBasedCompiler(CompilerLibraryEntry &entryPoint, const char *libName);
template <template <CIF::Version_t> class EntryPointT>
std::once_flag &getIcbeVersionCallOnceFlag();
static SpinLock spinlock;
[[nodiscard]] MOCKABLE_VIRTUAL std::unique_lock<SpinLock> lock() {
return std::unique_lock<SpinLock>{spinlock};
}
std::unique_ptr<CompilerCache> cache;
using igcDevCtxUptr = CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL>;
using finalizerDevCtxUptr = CIF::RAII::UPtr_t<IGC::IgcOclDeviceCtxTagOCL>;
using fclDevCtxUptr = CIF::RAII::UPtr_t<IGC::FclOclDeviceCtxTagOCL>;
CompilerLibraryEntry defaultIgc;
std::mutex customCompilerLibraryLoadMutex;
std::unordered_map<std::string, std::unique_ptr<CompilerLibraryEntry>> customCompilerLibraries;
std::unordered_map<const Device *, igcDevCtxUptr> igcDeviceContexts;
CompilerLibraryEntry fcl;
std::unordered_map<const Device *, fclDevCtxUptr> fclDeviceContexts;
CIF::RAII::UPtr_t<IGC::FclOclTranslationCtxTagOCL> fclBaseTranslationCtx;
std::unordered_map<const Device *, finalizerDevCtxUptr> finalizerDeviceContexts;
IGC::CodeType::CodeType_t finalizerInputType = IGC::CodeType::undefined;
MOCKABLE_VIRTUAL IGC::FclOclDeviceCtxTagOCL *getFclDeviceCtx(const Device &device);
MOCKABLE_VIRTUAL IGC::IgcOclDeviceCtxTagOCL *getIgcDeviceCtx(const Device &device);
MOCKABLE_VIRTUAL IGC::IgcOclDeviceCtxTagOCL *getFinalizerDeviceCtx(const Device &device);
MOCKABLE_VIRTUAL IGC::CodeType::CodeType_t getPreferredIntermediateRepresentation(const Device &device);
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::FclOclTranslationCtxTagOCL> createFclTranslationCtx(const Device &device,
IGC::CodeType::CodeType_t inType,
IGC::CodeType::CodeType_t outType);
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::IgcOclTranslationCtxTagOCL> createIgcTranslationCtx(const Device &device,
IGC::CodeType::CodeType_t inType,
IGC::CodeType::CodeType_t outType);
MOCKABLE_VIRTUAL CIF::RAII::UPtr_t<IGC::IgcOclTranslationCtxTagOCL> createFinalizerTranslationCtx(const Device &device,
IGC::CodeType::CodeType_t inType,
IGC::CodeType::CodeType_t outType);
bool isFclAvailable(const Device *device);
bool isIgcAvailable(const Device *device);
bool isFinalizerAvailable(const Device *device);
bool useIgcAsFcl(const Device *device);
const CompilerLibraryEntry *getCustomCompilerLibrary(const char *libName);
const CompilerLibraryEntry *getIgc(const char *libName) {
if (libName == nullptr) {
if (defaultIgc.entryPoint == nullptr) {
return nullptr;
}
return &defaultIgc;
}
return getCustomCompilerLibrary(libName);
}
const CompilerLibraryEntry *getIgc(const Device *device);
const CompilerLibraryEntry *getFinalizer(const char *libName) {
if (libName == nullptr) {
return nullptr;
}
return getCustomCompilerLibrary(libName);
}
const CompilerLibraryEntry *getFinalizer(const Device *device);
bool isCompilerAvailable(const Device *device, IGC::CodeType::CodeType_t translationSrc, IGC::CodeType::CodeType_t translationDst) {
bool requiresFcl = (IGC::CodeType::oclC == translationSrc);
bool requiresIgc = (IGC::CodeType::oclC != translationSrc) || ((IGC::CodeType::spirV != translationDst) && (IGC::CodeType::llvmBc != translationDst) && (IGC::CodeType::llvmLl != translationDst));
bool requiresFinalizer = (finalizerInputType != IGC::CodeType::undefined) && ((translationDst == IGC::CodeType::oclGenBin) || (translationSrc == finalizerInputType));
return (isFclAvailable(device) || (false == requiresFcl)) && (isIgcAvailable(device) || (false == requiresIgc)) && ((false == requiresFinalizer) || isFinalizerAvailable(device));
}
};
static_assert(NEO::NonCopyableAndNonMovable<CompilerInterface>);
class CompilerCacheHelper {
public:
static void packAndCacheBinary(CompilerCache &compilerCache, const std::string &kernelFileHash, const NEO::TargetDevice &targetDevice, const NEO::TranslationOutput &translationOutput);
static bool loadCacheAndSetOutput(CompilerCache &compilerCache, const std::string &kernelFileHash, NEO::TranslationOutput &output, const NEO::Device &device);
static CachingMode getCachingMode(CompilerCache *compilerCache, IGC::CodeType::CodeType_t srcCodeType, const ArrayRef<const char> source);
protected:
static bool processPackedCacheBinary(ArrayRef<const uint8_t> archive, TranslationOutput &output, const NEO::Device &device);
using WhitelistedIncludesVec = StackVec<std::string_view, 2>;
static bool validateIncludes(const ArrayRef<const char> source, const WhitelistedIncludesVec &whitelistedIncludes);
static WhitelistedIncludesVec whitelistedIncludes;
};
} // namespace NEO
|