#include "source/table2.h"
#include <algorithm>
#include <array>
#include <cstring>
#include "source/extensions.h"
#include "source/latest_version_spirv_header.h"
#include "source/spirv_constant.h"
#include "source/spirv_target_env.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace {
constexpr inline IndexRange IR(uint32_t first, uint32_t count) {
return IndexRange{first, count};
}
struct NameIndex {
IndexRange name;
uint32_t index;
};
struct NameValue {
IndexRange name;
uint32_t value;
};
IndexRange OperandNameRangeForKind(spv_operand_type_t type);
IndexRange OperandByValueRangeForKind(spv_operand_type_t type);
IndexRange ExtInstNameRangeForKind(spv_ext_inst_type_t type);
IndexRange ExtInstByValueRangeForKind(spv_ext_inst_type_t type);
IndexRange ExtensionToIndexRange(Extension extension);
#include "core_tables_body.inc"
const char* getChars(IndexRange ir) {
assert(ir.first() < sizeof(kStrings));
return ir.apply(kStrings).data();
}
}
utils::Span<const spv_operand_type_t> OperandDesc::operands() const {
return operands_range.apply(kOperandSpans);
}
utils::Span<const char> OperandDesc::name() const {
return name_range.apply(kStrings);
}
utils::Span<const IndexRange> OperandDesc::aliases() const {
return name_range.apply(kAliasSpans);
}
utils::Span<const spv::Capability> OperandDesc::capabilities() const {
return capabilities_range.apply(kCapabilitySpans);
}
utils::Span<const spvtools::Extension> OperandDesc::extensions() const {
return extensions_range.apply(kExtensionSpans);
}
utils::Span<const spv_operand_type_t> InstructionDesc::operands() const {
return operands_range.apply(kOperandSpans);
}
utils::Span<const char> InstructionDesc::name() const {
return name_range.apply(kStrings);
}
utils::Span<const IndexRange> InstructionDesc::aliases() const {
return name_range.apply(kAliasSpans);
}
utils::Span<const spv::Capability> InstructionDesc::capabilities() const {
return capabilities_range.apply(kCapabilitySpans);
}
utils::Span<const spvtools::Extension> InstructionDesc::extensions() const {
return extensions_range.apply(kExtensionSpans);
}
utils::Span<const spv_operand_type_t> ExtInstDesc::operands() const {
return operands_range.apply(kOperandSpans);
}
utils::Span<const char> ExtInstDesc::name() const {
return name_range.apply(kStrings);
}
utils::Span<const spv::Capability> ExtInstDesc::capabilities() const {
return capabilities_range.apply(kCapabilitySpans);
}
spv_result_t LookupOpcode(spv::Op opcode, const InstructionDesc** desc) {
const InstructionDesc needle(opcode);
auto where = std::lower_bound(
kInstructionDesc.begin(), kInstructionDesc.end(), needle,
[&](const InstructionDesc& lhs, const InstructionDesc& rhs) {
return uint32_t(lhs.opcode) < uint32_t(rhs.opcode);
});
if (where != kInstructionDesc.end() && where->opcode == opcode) {
*desc = &*where;
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
spv_result_t LookupOpcode(const char* name, const InstructionDesc** desc) {
const auto kSentinel = uint32_t(-1);
const NameIndex needle{{}, kSentinel};
auto less = [&](const NameIndex& lhs, const NameIndex& rhs) {
const char* lhs_chars = lhs.index == kSentinel ? name : getChars(lhs.name);
const char* rhs_chars = rhs.index == kSentinel ? name : getChars(rhs.name);
return std::strcmp(lhs_chars, rhs_chars) < 0;
};
auto where = std::lower_bound(kInstructionNames.begin(),
kInstructionNames.end(), needle, less);
if (where != kInstructionNames.end() &&
std::strcmp(getChars(where->name), name) == 0) {
*desc = &kInstructionDesc[where->index];
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
namespace {
template <typename KEY_TYPE>
spv_result_t LookupOpcodeForEnvInternal(spv_target_env env, KEY_TYPE key,
const InstructionDesc** desc) {
const InstructionDesc* desc_proxy;
auto status = LookupOpcode(key, &desc_proxy);
if (status != SPV_SUCCESS) {
return status;
}
const auto& entry = *desc_proxy;
const auto version = spvVersionForTargetEnv(env);
if ((version >= entry.minVersion && version <= entry.lastVersion) ||
entry.extensions_range.count() > 0 ||
entry.capabilities_range.count() > 0) {
*desc = desc_proxy;
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
}
spv_result_t LookupOpcodeForEnv(spv_target_env env, const char* name,
const InstructionDesc** desc) {
return LookupOpcodeForEnvInternal(env, name, desc);
}
spv_result_t LookupOpcodeForEnv(spv_target_env env, spv::Op opcode,
const InstructionDesc** desc) {
return LookupOpcodeForEnvInternal(env, opcode, desc);
}
spv_result_t LookupOperand(spv_operand_type_t type, uint32_t value,
const OperandDesc** desc) {
auto ir = OperandByValueRangeForKind(type);
if (ir.empty()) {
return SPV_ERROR_INVALID_LOOKUP;
}
auto span = ir.apply(kOperandsByValue.data());
const OperandDesc needle{value};
auto where =
std::lower_bound(span.begin(), span.end(), needle,
[&](const OperandDesc& lhs, const OperandDesc& rhs) {
return lhs.value < rhs.value;
});
if (where != span.end() && where->value == value) {
*desc = &*where;
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
spv_result_t LookupOperand(spv_operand_type_t type, const char* name,
size_t name_len, const OperandDesc** desc) {
auto ir = OperandNameRangeForKind(type);
if (ir.empty()) {
return SPV_ERROR_INVALID_LOOKUP;
}
auto span = ir.apply(kOperandNames.data());
const auto kSentinel = uint32_t(-1);
const NameIndex needle{{}, kSentinel};
auto less = [&](const NameIndex& lhs, const NameIndex& rhs) {
const char* lhs_chars = lhs.index == kSentinel ? name : getChars(lhs.name);
const char* rhs_chars = rhs.index == kSentinel ? name : getChars(rhs.name);
const auto content_cmp = std::strncmp(lhs_chars, rhs_chars, name_len);
if (content_cmp != 0) {
return content_cmp < 0;
}
const auto lhs_len =
lhs.index == kSentinel ? name_len : lhs.name.count() - 1;
const auto rhs_len =
rhs.index == kSentinel ? name_len : rhs.name.count() - 1;
return lhs_len < rhs_len;
};
auto where = std::lower_bound(span.begin(), span.end(), needle, less);
if (where != span.end() && where->name.count() - 1 == name_len &&
std::strncmp(getChars(where->name), name, name_len) == 0) {
*desc = &kOperandsByValue[where->index];
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
spv_result_t LookupExtInst(spv_ext_inst_type_t type, const char* name,
const ExtInstDesc** desc) {
auto ir = ExtInstNameRangeForKind(type);
if (ir.empty()) {
return SPV_ERROR_INVALID_LOOKUP;
}
auto span = ir.apply(kExtInstNames.data());
const auto kSentinel = uint32_t(-1);
const NameIndex needle{{}, kSentinel};
auto less = [&](const NameIndex& lhs, const NameIndex& rhs) {
const char* lhs_chars = lhs.index == kSentinel ? name : getChars(lhs.name);
const char* rhs_chars = rhs.index == kSentinel ? name : getChars(rhs.name);
return std::strcmp(lhs_chars, rhs_chars) < 0;
};
auto where = std::lower_bound(span.begin(), span.end(), needle, less);
if (where != span.end() && std::strcmp(getChars(where->name), name) == 0) {
*desc = &kExtInstByValue[where->index];
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
spv_result_t LookupExtInst(spv_ext_inst_type_t type, uint32_t value,
const ExtInstDesc** desc) {
auto ir = ExtInstByValueRangeForKind(type);
if (ir.empty()) {
return SPV_ERROR_INVALID_LOOKUP;
}
auto span = ir.apply(kExtInstByValue.data());
const ExtInstDesc needle(value);
auto where =
std::lower_bound(span.begin(), span.end(), needle,
[&](const ExtInstDesc& lhs, const ExtInstDesc& rhs) {
return lhs.value < rhs.value;
});
if (where != span.end() && where->value == value) {
*desc = &*where;
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_LOOKUP;
}
const char* ExtensionToString(Extension extension) {
return getChars(ExtensionToIndexRange(extension));
}
bool GetExtensionFromString(const char* name, Extension* extension) {
const auto kSentinel = uint32_t(-1);
const NameValue needle{{}, kSentinel};
auto less = [&](const NameValue& lhs, const NameValue& rhs) {
const char* lhs_chars = lhs.value == kSentinel ? name : getChars(lhs.name);
const char* rhs_chars = rhs.value == kSentinel ? name : getChars(rhs.name);
return std::strcmp(lhs_chars, rhs_chars) < 0;
};
auto where = std::lower_bound(kExtensionNames.begin(), kExtensionNames.end(),
needle, less);
if (where != kExtensionNames.end() &&
std::strcmp(getChars(where->name), name) == 0) {
*extension = static_cast<Extension>(where->value);
return true;
}
return false;
}
const char* StorageClassToString(spv::StorageClass value) {
switch (value) {
case spv::StorageClass::UniformConstant:
return "UniformConstant";
case spv::StorageClass::Input:
return "Input";
case spv::StorageClass::Uniform:
return "Uniform";
case spv::StorageClass::Output:
return "Output";
case spv::StorageClass::Workgroup:
return "Workgroup";
case spv::StorageClass::CrossWorkgroup:
return "CrossWorkgroup";
case spv::StorageClass::Private:
return "Private";
case spv::StorageClass::Function:
return "Function";
case spv::StorageClass::Generic:
return "Generic";
case spv::StorageClass::PushConstant:
return "PushConstant";
case spv::StorageClass::AtomicCounter:
return "AtomicCounter";
case spv::StorageClass::Image:
return "Image";
case spv::StorageClass::StorageBuffer:
return "StorageBuffer";
case spv::StorageClass::TileImageEXT:
return "TileImageEXT";
case spv::StorageClass::TileAttachmentQCOM:
return "TileAttachmentQCOM";
case spv::StorageClass::NodePayloadAMDX:
return "NodePayloadAMDX";
case spv::StorageClass::CallableDataKHR:
return "CallableDataKHR";
case spv::StorageClass::IncomingCallableDataKHR:
return "IncomingCallableDataKHR";
case spv::StorageClass::RayPayloadKHR:
return "RayPayloadKHR";
case spv::StorageClass::HitAttributeKHR:
return "HitAttributeKHR";
case spv::StorageClass::IncomingRayPayloadKHR:
return "IncomingRayPayloadKHR";
case spv::StorageClass::ShaderRecordBufferKHR:
return "ShaderRecordBufferKHR";
case spv::StorageClass::PhysicalStorageBuffer:
return "PhysicalStorageBuffer";
case spv::StorageClass::HitObjectAttributeNV:
return "HitObjectAttributeNV";
case spv::StorageClass::TaskPayloadWorkgroupEXT:
return "TaskPayloadWorkgroupEXT";
case spv::StorageClass::CodeSectionINTEL:
return "CodeSectionINTEL";
case spv::StorageClass::DeviceOnlyINTEL:
return "DeviceOnlyINTEL";
case spv::StorageClass::HostOnlyINTEL:
return "HostOnlyINTEL";
default:
return "Unknown";
}
}
}