mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-24 21:18:24 +08:00
Zebin: set kernel barriers based on ext funcs
This change allows for modifying kernel's barrier count based on called external functions metadata passed via zeInfo section in zebin. Added parsing external functions metadata. Added resolving external functions call graph. Added updating kernel barriers based on called external functions. Added support for L0 dynamic link. Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
bae9e6f5b5
commit
0ccce5a6d7
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2019-2021 Intel Corporation
|
||||
# Copyright (C) 2019-2022 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
@@ -13,6 +13,8 @@ set(NEO_CORE_COMPILER_INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compiler_interface.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/create_main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/default_cache_config.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external_functions.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external_functions.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/intermediate_representations.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linker.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/linker.inl
|
||||
|
||||
116
shared/source/compiler_interface/external_functions.cpp
Normal file
116
shared/source/compiler_interface/external_functions.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/compiler_interface/external_functions.h"
|
||||
|
||||
#include "shared/source/helpers/debug_helpers.h"
|
||||
#include "shared/source/kernel/kernel_descriptor.h"
|
||||
|
||||
#include <algorithm>
|
||||
namespace NEO {
|
||||
|
||||
uint32_t resolveBarrierCount(ExternalFunctionInfosT externalFunctionInfos, KernelDependenciesT kernelDependencies,
|
||||
FunctionDependenciesT funcDependencies, KernelDescriptorMapT &nameToKernelDescriptor) {
|
||||
FuncNameToIdMapT funcNameToId;
|
||||
for (size_t i = 0U; i < externalFunctionInfos.size(); i++) {
|
||||
auto &extFuncInfo = externalFunctionInfos[i];
|
||||
funcNameToId[extFuncInfo->functionName] = i;
|
||||
}
|
||||
|
||||
auto error = resolveExtFuncDependencies(externalFunctionInfos, funcNameToId, funcDependencies);
|
||||
if (error != RESOLVE_SUCCESS) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = resolveKernelDependencies(externalFunctionInfos, funcNameToId, kernelDependencies, nameToKernelDescriptor);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t getExtFuncDependencies(FuncNameToIdMapT &funcNameToId, FunctionDependenciesT funcDependencies, size_t numExternalFuncs,
|
||||
DependenciesT &outDependencies, CalledByT &outCalledBy) {
|
||||
outDependencies.resize(numExternalFuncs);
|
||||
outCalledBy.resize(numExternalFuncs);
|
||||
for (size_t i = 0; i < funcDependencies.size(); i++) {
|
||||
auto funcDep = funcDependencies[i];
|
||||
if (funcNameToId.count(funcDep->callerFuncName) == 0 ||
|
||||
funcNameToId.count(funcDep->usedFuncName) == 0) {
|
||||
return ERROR_EXTERNAL_FUNCTION_INFO_MISSING;
|
||||
}
|
||||
size_t callerId = funcNameToId[funcDep->callerFuncName];
|
||||
size_t calleeId = funcNameToId[funcDep->usedFuncName];
|
||||
|
||||
outDependencies[callerId].push_back(calleeId);
|
||||
outCalledBy[calleeId].push_back(callerId);
|
||||
}
|
||||
|
||||
return RESOLVE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t resolveExtFuncDependencies(ExternalFunctionInfosT externalFunctionInfos, FuncNameToIdMapT &funcNameToId, FunctionDependenciesT funcDependencies) {
|
||||
DependenciesT dependencies;
|
||||
CalledByT calledBy;
|
||||
auto error = getExtFuncDependencies(funcNameToId, funcDependencies, externalFunctionInfos.size(), dependencies, calledBy);
|
||||
if (error != RESOLVE_SUCCESS) {
|
||||
return error;
|
||||
}
|
||||
|
||||
DependencyResolver depResolver(dependencies);
|
||||
auto resolved = depResolver.resolveDependencies();
|
||||
if (depResolver.hasLoop()) {
|
||||
return ERROR_LOOP_DETECKTED;
|
||||
}
|
||||
for (auto calleeId : resolved) {
|
||||
const auto callee = externalFunctionInfos[calleeId];
|
||||
for (auto callerId : calledBy[calleeId]) {
|
||||
auto caller = externalFunctionInfos[callerId];
|
||||
caller->barrierCount = std::max(caller->barrierCount, callee->barrierCount);
|
||||
}
|
||||
}
|
||||
return RESOLVE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t resolveKernelDependencies(ExternalFunctionInfosT externalFunctionInfos, FuncNameToIdMapT &funcNameToId, KernelDependenciesT kernelDependencies, KernelDescriptorMapT &nameToKernelDescriptor) {
|
||||
for (size_t i = 0; i < kernelDependencies.size(); i++) {
|
||||
auto kernelDep = kernelDependencies[i];
|
||||
if (funcNameToId.count(kernelDep->usedFuncName) == 0) {
|
||||
return ERROR_EXTERNAL_FUNCTION_INFO_MISSING;
|
||||
} else if (nameToKernelDescriptor.count(kernelDep->kernelName) == 0) {
|
||||
return ERROR_KERNEL_DESCRIPTOR_MISSING;
|
||||
}
|
||||
const auto functionBarrierCount = externalFunctionInfos[funcNameToId[kernelDep->usedFuncName]]->barrierCount;
|
||||
auto &kernelBarrierCount = nameToKernelDescriptor[kernelDep->kernelName]->kernelAttributes.barrierCount;
|
||||
kernelBarrierCount = std::max(kernelBarrierCount, functionBarrierCount);
|
||||
}
|
||||
return RESOLVE_SUCCESS;
|
||||
}
|
||||
|
||||
std::vector<size_t> DependencyResolver::resolveDependencies() {
|
||||
for (size_t i = 0; i < graph.size(); i++) {
|
||||
if (std::find(seen.begin(), seen.end(), i) == seen.end() && graph[i].empty() == false) {
|
||||
resolveDependency(i, graph[i]);
|
||||
}
|
||||
}
|
||||
if (loopDeteckted) {
|
||||
return {};
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
void DependencyResolver::resolveDependency(size_t nodeId, const std::vector<size_t> &edges) {
|
||||
seen.push_back(nodeId);
|
||||
for (auto &edgeId : edges) {
|
||||
if (std::find(resolved.begin(), resolved.end(), edgeId) == resolved.end()) {
|
||||
if (std::find(seen.begin(), seen.end(), edgeId) != seen.end()) {
|
||||
loopDeteckted = true;
|
||||
} else {
|
||||
resolveDependency(edgeId, graph[edgeId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
resolved.push_back(nodeId);
|
||||
}
|
||||
} // namespace NEO
|
||||
73
shared/source/compiler_interface/external_functions.h
Normal file
73
shared/source/compiler_interface/external_functions.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/utilities/arrayref.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#pragma once
|
||||
namespace NEO {
|
||||
struct KernelDescriptor;
|
||||
|
||||
enum ExternalFunctionResolveError : uint32_t {
|
||||
RESOLVE_SUCCESS = 0,
|
||||
ERROR_EXTERNAL_FUNCTION_INFO_MISSING,
|
||||
ERROR_KERNEL_DESCRIPTOR_MISSING,
|
||||
ERROR_LOOP_DETECKTED
|
||||
};
|
||||
|
||||
struct ExternalFunctionInfo {
|
||||
std::string functionName;
|
||||
uint8_t barrierCount;
|
||||
uint16_t numGrfRequired;
|
||||
uint8_t simdSize;
|
||||
};
|
||||
|
||||
struct ExternalFunctionUsageKernel {
|
||||
std::string usedFuncName;
|
||||
std::string kernelName;
|
||||
};
|
||||
|
||||
struct ExternalFunctionUsageExtFunc {
|
||||
std::string usedFuncName;
|
||||
std::string callerFuncName;
|
||||
};
|
||||
|
||||
using ExternalFunctionInfosT = std::vector<ExternalFunctionInfo *>;
|
||||
using KernelDependenciesT = std::vector<const ExternalFunctionUsageKernel *>;
|
||||
using FunctionDependenciesT = std::vector<const ExternalFunctionUsageExtFunc *>;
|
||||
using KernelDescriptorMapT = std::unordered_map<std::string, KernelDescriptor *>;
|
||||
using FuncNameToIdMapT = std::unordered_map<std::string, size_t>;
|
||||
using DependenciesT = std::vector<std::vector<size_t>>;
|
||||
using CalledByT = std::vector<std::vector<size_t>>;
|
||||
|
||||
class DependencyResolver {
|
||||
public:
|
||||
DependencyResolver(const std::vector<std::vector<size_t>> &graph) : graph(graph) {}
|
||||
std::vector<size_t> resolveDependencies();
|
||||
inline bool hasLoop() { return loopDeteckted; }
|
||||
|
||||
protected:
|
||||
void resolveDependency(size_t nodeId, const std::vector<size_t> &edges);
|
||||
std::vector<size_t> seen;
|
||||
std::vector<size_t> resolved;
|
||||
const std::vector<std::vector<size_t>> &graph;
|
||||
bool loopDeteckted = false;
|
||||
};
|
||||
|
||||
uint32_t resolveBarrierCount(ExternalFunctionInfosT externalFunctionInfos, KernelDependenciesT kernelDependencies,
|
||||
FunctionDependenciesT funcDependencies, KernelDescriptorMapT &nameToKernelDescriptor);
|
||||
|
||||
uint32_t getExtFuncDependencies(FuncNameToIdMapT &funcNameToId, FunctionDependenciesT funcDependencies, size_t numExternalFuncs,
|
||||
DependenciesT &outDependencies, CalledByT &outCalledBy);
|
||||
|
||||
uint32_t resolveExtFuncDependencies(ExternalFunctionInfosT externalFunctionInfos, FuncNameToIdMapT &funcNameToId, FunctionDependenciesT funcDependencies);
|
||||
|
||||
uint32_t resolveKernelDependencies(ExternalFunctionInfosT externalFunctionInfos, FuncNameToIdMapT &funcNameToId, KernelDependenciesT kernelDependencies, KernelDescriptorMapT &nameToKernelDescriptor);
|
||||
|
||||
} // namespace NEO
|
||||
@@ -19,10 +19,12 @@
|
||||
#include "shared/source/kernel/kernel_descriptor.h"
|
||||
#include "shared/source/memory_manager/graphics_allocation.h"
|
||||
#include "shared/source/memory_manager/memory_manager.h"
|
||||
#include "shared/source/program/program_info.h"
|
||||
|
||||
#include "RelocationInfo.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace NEO {
|
||||
|
||||
@@ -169,55 +171,24 @@ void LinkerInput::addElfTextSegmentRelocation(RelocationInfo relocationInfo, uin
|
||||
}
|
||||
|
||||
void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> &elf, const SectionNameToSegmentIdMap &nameToSegmentId) {
|
||||
for (auto &reloc : elf.getRelocations()) {
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = reloc.offset;
|
||||
relocationInfo.symbolName = reloc.symbolName;
|
||||
|
||||
switch (reloc.relocType) {
|
||||
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_64):
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
break;
|
||||
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_32):
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
break;
|
||||
default: // Zebin relocation type
|
||||
relocationInfo.type = reloc.relocType < uint32_t(NEO::LinkerInput::RelocationInfo::Type::RelocTypeMax)
|
||||
? static_cast<NEO::LinkerInput::RelocationInfo::Type>(reloc.relocType)
|
||||
: NEO::LinkerInput::RelocationInfo::Type::Unknown;
|
||||
break;
|
||||
}
|
||||
auto name = elf.getSectionName(reloc.targetSectionIndex);
|
||||
ConstStringRef nameRef(name);
|
||||
|
||||
if (nameRef.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
|
||||
auto kernelName = name.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
|
||||
auto segmentIdIter = nameToSegmentId.find(kernelName);
|
||||
if (segmentIdIter != nameToSegmentId.end()) {
|
||||
this->addElfTextSegmentRelocation(relocationInfo, segmentIdIter->second);
|
||||
}
|
||||
} else if (nameRef.startsWith(NEO::Elf::SpecialSectionNames::data.data())) {
|
||||
auto symbolSectionName = elf.getSectionName(reloc.symbolSectionIndex);
|
||||
auto symbolSegment = getSegmentForSection(symbolSectionName);
|
||||
auto relocationSegment = getSegmentForSection(nameRef);
|
||||
if (symbolSegment != NEO::SegmentType::Unknown &&
|
||||
(relocationSegment == NEO::SegmentType::GlobalConstants || relocationSegment == NEO::SegmentType::GlobalVariables)) {
|
||||
relocationInfo.relocationSegment = relocationSegment;
|
||||
this->addDataRelocationInfo(relocationInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
symbols.reserve(elf.getSymbols().size());
|
||||
|
||||
for (auto &symbol : elf.getSymbols()) {
|
||||
auto bind = elf.extractSymbolBind(symbol);
|
||||
auto type = elf.extractSymbolType(symbol);
|
||||
|
||||
if (type == Elf::SYMBOL_TABLE_TYPE::STT_FUNC) {
|
||||
SymbolInfo symbolInfo;
|
||||
symbolInfo.offset = static_cast<uint32_t>(symbol.value);
|
||||
symbolInfo.size = static_cast<uint32_t>(symbol.size);
|
||||
symbolInfo.bind = static_cast<SymbolBind>(bind);
|
||||
|
||||
extFuncSymbols.push_back({elf.getSymbolName(symbol.name), symbolInfo});
|
||||
}
|
||||
|
||||
if (bind == Elf::SYMBOL_TABLE_BIND::STB_GLOBAL) {
|
||||
SymbolInfo symbolInfo;
|
||||
symbolInfo.offset = static_cast<uint32_t>(symbol.value);
|
||||
symbolInfo.size = static_cast<uint32_t>(symbol.size);
|
||||
auto type = elf.extractSymbolType(symbol);
|
||||
|
||||
auto symbolSectionName = elf.getSectionName(symbol.shndx);
|
||||
auto symbolSegment = getSegmentForSection(symbolSectionName);
|
||||
@@ -247,6 +218,67 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64>
|
||||
symbols.insert({elf.getSymbolName(symbol.name), symbolInfo});
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &reloc : elf.getRelocations()) {
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = reloc.offset;
|
||||
relocationInfo.symbolName = reloc.symbolName;
|
||||
|
||||
switch (reloc.relocType) {
|
||||
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_64):
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
break;
|
||||
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_32):
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
break;
|
||||
default: // Zebin relocation type
|
||||
relocationInfo.type = reloc.relocType < uint32_t(NEO::LinkerInput::RelocationInfo::Type::RelocTypeMax)
|
||||
? static_cast<NEO::LinkerInput::RelocationInfo::Type>(reloc.relocType)
|
||||
: NEO::LinkerInput::RelocationInfo::Type::Unknown;
|
||||
break;
|
||||
}
|
||||
auto name = elf.getSectionName(reloc.targetSectionIndex);
|
||||
ConstStringRef nameRef(name);
|
||||
|
||||
if (nameRef.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
|
||||
auto kernelName = name.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
|
||||
auto segmentIdIter = nameToSegmentId.find(kernelName);
|
||||
if (segmentIdIter != nameToSegmentId.end()) {
|
||||
this->addElfTextSegmentRelocation(relocationInfo, segmentIdIter->second);
|
||||
parseRelocationForExtFuncUsage(relocationInfo, kernelName);
|
||||
}
|
||||
} else if (nameRef.startsWith(NEO::Elf::SpecialSectionNames::data.data())) {
|
||||
auto symbolSectionName = elf.getSectionName(reloc.symbolSectionIndex);
|
||||
auto symbolSegment = getSegmentForSection(symbolSectionName);
|
||||
auto relocationSegment = getSegmentForSection(nameRef);
|
||||
if (symbolSegment != NEO::SegmentType::Unknown &&
|
||||
(relocationSegment == NEO::SegmentType::GlobalConstants || relocationSegment == NEO::SegmentType::GlobalVariables)) {
|
||||
relocationInfo.relocationSegment = relocationSegment;
|
||||
this->addDataRelocationInfo(relocationInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerInput::parseRelocationForExtFuncUsage(RelocationInfo relocInfo, std::string kernelName) {
|
||||
auto extFuncSymIt = std::find_if(extFuncSymbols.begin(), extFuncSymbols.end(), [relocInfo](auto &pair) {
|
||||
return pair.first == relocInfo.symbolName;
|
||||
});
|
||||
if (extFuncSymIt != extFuncSymbols.end()) {
|
||||
if (kernelName == Elf::SectionsNamesZebin::externalFunctions.str()) {
|
||||
auto callerIt = std::find_if(extFuncSymbols.begin(), extFuncSymbols.end(), [relocInfo](auto &pair) {
|
||||
auto &symbol = pair.second;
|
||||
return relocInfo.offset >= symbol.offset && relocInfo.offset < symbol.offset + symbol.size;
|
||||
});
|
||||
if (callerIt == extFuncSymbols.end()) {
|
||||
this->valid = false;
|
||||
return;
|
||||
}
|
||||
extFunDependencies.push_back({relocInfo.symbolName, callerIt->first});
|
||||
} else {
|
||||
kernelDependencies.push_back({relocInfo.symbolName, kernelName});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings) {
|
||||
@@ -471,6 +503,29 @@ void Linker::applyDebugDataRelocations(const NEO::Elf::Elf<NEO::Elf::EI_CLASS_64
|
||||
}
|
||||
}
|
||||
|
||||
bool Linker::resolveExternalFunctions(const KernelDescriptorsT &kernelDescriptors, std::vector<ExternalFunctionInfo> &externalFunctions) {
|
||||
ExternalFunctionInfosT externalFunctionsPtrs;
|
||||
FunctionDependenciesT functionDependenciesPtrs;
|
||||
KernelDependenciesT kernelDependenciesPtrs;
|
||||
KernelDescriptorMapT nameToKernelDescriptor;
|
||||
|
||||
auto toPtrVec = [](auto &inVec, auto &outPtrVec) {
|
||||
outPtrVec.resize(inVec.size());
|
||||
for (size_t i = 0; i < inVec.size(); i++) {
|
||||
outPtrVec[i] = &inVec[i];
|
||||
}
|
||||
};
|
||||
toPtrVec(externalFunctions, externalFunctionsPtrs);
|
||||
toPtrVec(data.getFunctionDependencies(), functionDependenciesPtrs);
|
||||
toPtrVec(data.getKernelDependencies(), kernelDependenciesPtrs);
|
||||
for (auto &kd : kernelDescriptors) {
|
||||
nameToKernelDescriptor[kd->kernelMetadata.kernelName] = kd;
|
||||
}
|
||||
|
||||
auto error = NEO::resolveBarrierCount(externalFunctionsPtrs, kernelDependenciesPtrs, functionDependenciesPtrs, nameToKernelDescriptor);
|
||||
return (error == RESOLVE_SUCCESS) ? true : false;
|
||||
}
|
||||
|
||||
void Linker::resolveImplicitArgs(const KernelDescriptorsT &kernelDescriptors, Device *pDevice) {
|
||||
for (auto i = 0u; i < kernelDescriptors.size(); i++) {
|
||||
UNRECOVERABLE_IF(!kernelDescriptors[i]);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "shared/source/compiler_interface/external_functions.h"
|
||||
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
||||
|
||||
#include <cstdint>
|
||||
@@ -34,6 +35,10 @@ enum class LinkingStatus : uint32_t {
|
||||
LinkedFully,
|
||||
LinkedPartially
|
||||
};
|
||||
enum class SymbolBind : uint8_t {
|
||||
Local,
|
||||
Global
|
||||
};
|
||||
|
||||
inline const char *asString(SegmentType segment) {
|
||||
switch (segment) {
|
||||
@@ -52,6 +57,7 @@ struct SymbolInfo {
|
||||
uint32_t offset = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t size = std::numeric_limits<uint32_t>::max();
|
||||
SegmentType segment = SegmentType::Unknown;
|
||||
SymbolBind bind = SymbolBind::Local;
|
||||
};
|
||||
|
||||
struct LinkerInput {
|
||||
@@ -91,6 +97,7 @@ struct LinkerInput {
|
||||
Type type = Type::Unknown;
|
||||
SegmentType relocationSegment = SegmentType::Unknown;
|
||||
};
|
||||
|
||||
using SectionNameToSegmentIdMap = std::unordered_map<std::string, uint32_t>;
|
||||
using Relocations = std::vector<RelocationInfo>;
|
||||
using SymbolMap = std::unordered_map<std::string, SymbolInfo>;
|
||||
@@ -142,12 +149,25 @@ struct LinkerInput {
|
||||
|
||||
bool undefinedSymbolsAllowed = false;
|
||||
|
||||
const std::vector<ExternalFunctionUsageKernel> &getKernelDependencies() const {
|
||||
return kernelDependencies;
|
||||
}
|
||||
|
||||
const std::vector<ExternalFunctionUsageExtFunc> &getFunctionDependencies() const {
|
||||
return extFunDependencies;
|
||||
}
|
||||
|
||||
protected:
|
||||
void parseRelocationForExtFuncUsage(RelocationInfo relocInfo, std::string kernelName);
|
||||
|
||||
Traits traits;
|
||||
SymbolMap symbols;
|
||||
RelocationsPerInstSegment relocations;
|
||||
Relocations dataRelocations;
|
||||
std::vector<std::pair<std::string, SymbolInfo>> extFuncSymbols;
|
||||
int32_t exportedFunctionsSegmentId = -1;
|
||||
std::vector<ExternalFunctionUsageKernel> kernelDependencies;
|
||||
std::vector<ExternalFunctionUsageExtFunc> extFunDependencies;
|
||||
bool valid = true;
|
||||
};
|
||||
|
||||
@@ -181,6 +201,7 @@ struct Linker {
|
||||
using PatchableSegments = std::vector<PatchableSegment>;
|
||||
using UnresolvedExternals = std::vector<UnresolvedExternal>;
|
||||
using KernelDescriptorsT = std::vector<KernelDescriptor *>;
|
||||
using ExternalFunctionsT = std::vector<ExternalFunctionInfo>;
|
||||
|
||||
Linker(const LinkerInput &data)
|
||||
: data(data) {
|
||||
@@ -188,7 +209,8 @@ struct Linker {
|
||||
|
||||
LinkingStatus link(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo, const SegmentInfo &exportedFunctionsSegInfo, const SegmentInfo &globalStringsSegInfo,
|
||||
GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg, const PatchableSegments &instructionsSegments,
|
||||
UnresolvedExternals &outUnresolvedExternals, Device *pDevice, const void *constantsInitData, const void *variablesInitData, const KernelDescriptorsT &kernelDescriptors) {
|
||||
UnresolvedExternals &outUnresolvedExternals, Device *pDevice, const void *constantsInitData, const void *variablesInitData,
|
||||
const KernelDescriptorsT &kernelDescriptors, ExternalFunctionsT &externalFunctions) {
|
||||
bool success = data.isValid();
|
||||
auto initialUnresolvedExternalsCount = outUnresolvedExternals.size();
|
||||
success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo, globalStringsSegInfo);
|
||||
@@ -203,6 +225,10 @@ struct Linker {
|
||||
if (initialUnresolvedExternalsCount < outUnresolvedExternals.size()) {
|
||||
return LinkingStatus::LinkedPartially;
|
||||
}
|
||||
success = resolveExternalFunctions(kernelDescriptors, externalFunctions);
|
||||
if (!success) {
|
||||
return LinkingStatus::Error;
|
||||
}
|
||||
return LinkingStatus::LinkedFully;
|
||||
}
|
||||
static void patchAddress(void *relocAddress, const RelocatedSymbol &symbol, const RelocationInfo &relocation);
|
||||
@@ -228,6 +254,7 @@ struct Linker {
|
||||
std::vector<UnresolvedExternal> &outUnresolvedExternals, Device *pDevice,
|
||||
const void *constantsInitData, const void *variablesInitData);
|
||||
|
||||
bool resolveExternalFunctions(const KernelDescriptorsT &kernelDescriptors, std::vector<ExternalFunctionInfo> &externalFunctions);
|
||||
void resolveImplicitArgs(const KernelDescriptorsT &kernelDescriptors, Device *pDevice);
|
||||
void resolveBuiltins(Device *pDevice, UnresolvedExternals &outUnresolvedExternals, const std::vector<PatchableSegment> &instructionsSegments);
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ static constexpr ConstStringRef zeInfo = ".ze_info";
|
||||
static constexpr ConstStringRef gtpinInfo = ".gtpin_info";
|
||||
static constexpr ConstStringRef noteIntelGT = ".note.intelgt.compat";
|
||||
static constexpr ConstStringRef vIsaAsmPrefix = ".visaasm.";
|
||||
static constexpr ConstStringRef externalFunctions = "Intel_Symbol_Table_Void_Program";
|
||||
} // namespace SectionsNamesZebin
|
||||
|
||||
static constexpr ConstStringRef IntelGtNoteOwnerName = "IntelGT";
|
||||
@@ -158,6 +159,8 @@ namespace Tags {
|
||||
static constexpr ConstStringRef kernels("kernels");
|
||||
static constexpr ConstStringRef version("version");
|
||||
static constexpr ConstStringRef globalHostAccessTable("global_host_access_table");
|
||||
static constexpr ConstStringRef functions("functions");
|
||||
|
||||
namespace Kernel {
|
||||
static constexpr ConstStringRef name("name");
|
||||
static constexpr ConstStringRef executionEnv("execution_env");
|
||||
@@ -279,10 +282,18 @@ static constexpr ConstStringRef hasNonKernelArgStore("has_non_kernel_arg_store")
|
||||
static constexpr ConstStringRef hasNonKernelArgAtomic("has_non_kernel_arg_atomic");
|
||||
} // namespace ExperimentalProperties
|
||||
} // namespace Kernel
|
||||
|
||||
namespace GlobalHostAccessTable {
|
||||
static constexpr ConstStringRef deviceName("device_name");
|
||||
static constexpr ConstStringRef hostName("host_name");
|
||||
} // namespace GlobalHostAccessTable
|
||||
|
||||
namespace Function {
|
||||
static constexpr ConstStringRef name("name");
|
||||
static constexpr ConstStringRef executionEnv("execution_env");
|
||||
using namespace Kernel::ExecutionEnv;
|
||||
} // namespace Function
|
||||
|
||||
} // namespace Tags
|
||||
|
||||
namespace Types {
|
||||
@@ -540,6 +551,12 @@ struct globalHostAccessTableT {
|
||||
std::string hostName;
|
||||
};
|
||||
} // namespace GlobalHostAccessTable
|
||||
|
||||
namespace Function {
|
||||
namespace ExecutionEnv {
|
||||
using namespace Kernel::ExecutionEnv;
|
||||
}
|
||||
} // namespace Function
|
||||
} // namespace Types
|
||||
|
||||
} // namespace ZebinKernelMetadata
|
||||
|
||||
@@ -1238,6 +1238,38 @@ NEO::DecodeError populateZeInfoVersion(NEO::Elf::ZebinKernelMetadata::Types::Ver
|
||||
return NEO::DecodeError::Success;
|
||||
}
|
||||
|
||||
NEO::DecodeError populateExternalFunctionsMetadata(NEO::ProgramInfo &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &functionNd, std::string &outErrReason, std::string &outWarning) {
|
||||
ConstStringRef functionName;
|
||||
NEO::Elf::ZebinKernelMetadata::Types::Function::ExecutionEnv::ExecutionEnvBaseT execEnv = {};
|
||||
bool isValid = true;
|
||||
|
||||
for (const auto &functionMetadataNd : yamlParser.createChildrenRange(functionNd)) {
|
||||
auto key = yamlParser.readKey(functionMetadataNd);
|
||||
if (NEO::Elf::ZebinKernelMetadata::Tags::Function::name == key) {
|
||||
functionName = yamlParser.readValueNoQuotes(functionMetadataNd);
|
||||
} else if (NEO::Elf::ZebinKernelMetadata::Tags::Function::executionEnv == key) {
|
||||
auto execEnvErr = readZeInfoExecutionEnvironment(yamlParser, functionMetadataNd, execEnv, "external functions", outErrReason, outWarning);
|
||||
if (execEnvErr != DecodeError::Success) {
|
||||
isValid = false;
|
||||
}
|
||||
} else {
|
||||
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + yamlParser.readKey(functionMetadataNd).str() + "\" in context of : external functions\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
NEO::ExternalFunctionInfo extFunInfo;
|
||||
extFunInfo.functionName = functionName.str();
|
||||
extFunInfo.barrierCount = static_cast<uint8_t>(execEnv.barrierCount);
|
||||
extFunInfo.numGrfRequired = static_cast<uint16_t>(execEnv.grfCount);
|
||||
extFunInfo.simdSize = static_cast<uint8_t>(execEnv.simdSize);
|
||||
dst.externalFunctions.push_back(extFunInfo);
|
||||
return DecodeError::Success;
|
||||
} else {
|
||||
return DecodeError::InvalidBinary;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo &dst, const SingleDeviceBinary &src, std::string &outErrReason, std::string &outWarning) {
|
||||
auto elf = Elf::decodeElf<Elf::EI_CLASS_64>(src.deviceBinary, outErrReason, outWarning);
|
||||
@@ -1299,17 +1331,17 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
|
||||
UniqueNode kernelsSectionNodes;
|
||||
UniqueNode versionSectionNodes;
|
||||
UniqueNode globalHostAccessTableNodes;
|
||||
UniqueNode functionsSectionNodes;
|
||||
for (const auto &globalScopeNd : yamlParser.createChildrenRange(*yamlParser.getRoot())) {
|
||||
auto key = yamlParser.readKey(globalScopeNd);
|
||||
if (NEO::Elf::ZebinKernelMetadata::Tags::kernels == key) {
|
||||
kernelsSectionNodes.push_back(&globalScopeNd);
|
||||
continue;
|
||||
} else if (NEO::Elf::ZebinKernelMetadata::Tags::version == key) {
|
||||
versionSectionNodes.push_back(&globalScopeNd);
|
||||
continue;
|
||||
} else if (NEO::Elf::ZebinKernelMetadata::Tags::globalHostAccessTable == key) {
|
||||
globalHostAccessTableNodes.push_back(&globalScopeNd);
|
||||
continue;
|
||||
} else if (NEO::Elf::ZebinKernelMetadata::Tags::functions == key) {
|
||||
functionsSectionNodes.push_back(&globalScopeNd);
|
||||
} else {
|
||||
outWarning.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Unknown entry \"" + yamlParser.readKey(globalScopeNd).str() + "\" in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + "\n");
|
||||
}
|
||||
@@ -1368,6 +1400,20 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
|
||||
}
|
||||
}
|
||||
|
||||
if (functionsSectionNodes.size() > 1U) {
|
||||
outErrReason.append("DeviceBinaryFormat::Zebin::" + NEO::Elf::SectionsNamesZebin::zeInfo.str() + " : Expected at most one " + NEO::Elf::ZebinKernelMetadata::Tags::functions.str() + " entry in global scope of " + NEO::Elf::SectionsNamesZebin::zeInfo.str() + ", got : " + std::to_string(functionsSectionNodes.size()) + "\n");
|
||||
return DecodeError::InvalidBinary;
|
||||
}
|
||||
|
||||
if (false == functionsSectionNodes.empty()) {
|
||||
for (const auto &functionNd : yamlParser.createChildrenRange(*functionsSectionNodes[0])) {
|
||||
auto zeInfoErr = populateExternalFunctionsMetadata(dst, yamlParser, functionNd, outErrReason, outWarning);
|
||||
if (DecodeError::Success != zeInfoErr) {
|
||||
return zeInfoErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DecodeError::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,4 +117,6 @@ NEO::DecodeError populateKernelDescriptor(NEO::ProgramInfo &dst, NEO::Elf::Elf<N
|
||||
|
||||
NEO::DecodeError populateZeInfoVersion(NEO::Elf::ZebinKernelMetadata::Types::Version &dst,
|
||||
NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &versionNd, std::string &outErrReason, std::string &outWarning);
|
||||
|
||||
NEO::DecodeError populateExternalFunctionsMetadata(NEO::ProgramInfo &dst, NEO::Yaml::YamlParser &yamlParser, const NEO::Yaml::Node &functionNd, std::string &outErrReason, std::string &outWarning);
|
||||
} // namespace NEO
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/source/compiler_interface/external_functions.h"
|
||||
#include "shared/source/compiler_interface/linker.h"
|
||||
|
||||
#include <cstddef>
|
||||
@@ -42,6 +43,7 @@ struct ProgramInfo {
|
||||
std::unique_ptr<LinkerInput> linkerInput;
|
||||
std::unordered_map<std::string, std::string> globalsDeviceToHostNameMap;
|
||||
|
||||
std::vector<ExternalFunctionInfo> externalFunctions;
|
||||
std::vector<KernelInfo *> kernelInfos;
|
||||
Elf::Elf<Elf::EI_CLASS_64> decodedElf;
|
||||
uint32_t grfSize = 32U;
|
||||
|
||||
Reference in New Issue
Block a user