mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
Fix endianness of string literals (#4622)
* Fix endianness of string literals To get correct and consistent encoding and decoding of string literals on big-endian platforms, use spvtools::utils::MakeString and MakeVector (or wrapper functions) consistently for handling string literals. - add variant of MakeVector that encodes a string literal into an existing vector of words - add variants of MakeString - add a wrapper spvDecodeLiteralStringOperand in source/ - fix wrapper Operand::AsString to use MakeString (source/opt) - remove Operand::AsCString as broken and unused - add a variant of GetOperandAs for string literals (source/val) ... and apply those wrappers throughout the code. Fixes #149 * Extend round trip test for StringLiterals to flip word order In the encoding/decoding roundtrip tests for string literals, include a case that flips byte order in words after encoding and then checks for successful decoding. That is, on a little-endian host flip to big-endian byte order and then decode, and vice versa. * BinaryParseTest.InstructionWithStringOperand: also flip byte order Test binary parsing of string operands both with the host's and with the reversed byte order.
This commit is contained in:
parent
b162ede0de
commit
1ed847f438
@ -33,6 +33,7 @@
|
|||||||
#include "source/operand.h"
|
#include "source/operand.h"
|
||||||
#include "source/spirv_constant.h"
|
#include "source/spirv_constant.h"
|
||||||
#include "source/spirv_endian.h"
|
#include "source/spirv_endian.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
|
spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
|
||||||
const spv_endianness_t endian,
|
const spv_endianness_t endian,
|
||||||
@ -62,6 +63,15 @@ spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
|
|||||||
return SPV_SUCCESS;
|
return SPV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
|
||||||
|
const uint16_t operand_index) {
|
||||||
|
assert(operand_index < inst.num_operands);
|
||||||
|
const spv_parsed_operand_t& operand = inst.operands[operand_index];
|
||||||
|
|
||||||
|
return spvtools::utils::MakeString(inst.words + operand.offset,
|
||||||
|
operand.num_words);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// A SPIR-V binary parser. A parser instance communicates detailed parse
|
// A SPIR-V binary parser. A parser instance communicates detailed parse
|
||||||
@ -577,27 +587,18 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
|||||||
|
|
||||||
case SPV_OPERAND_TYPE_LITERAL_STRING:
|
case SPV_OPERAND_TYPE_LITERAL_STRING:
|
||||||
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
|
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
|
||||||
convert_operand_endianness = false;
|
const size_t max_words = _.num_words - _.word_index;
|
||||||
const char* string =
|
std::string string =
|
||||||
reinterpret_cast<const char*>(_.words + _.word_index);
|
spvtools::utils::MakeString(_.words + _.word_index, max_words, false);
|
||||||
// Compute the length of the string, but make sure we don't run off the
|
|
||||||
// end of the input.
|
if (string.length() == max_words * 4)
|
||||||
const size_t remaining_input_bytes =
|
|
||||||
sizeof(uint32_t) * (_.num_words - _.word_index);
|
|
||||||
const size_t string_num_content_bytes =
|
|
||||||
spv_strnlen_s(string, remaining_input_bytes);
|
|
||||||
// If there was no terminating null byte, then that's an end-of-input
|
|
||||||
// error.
|
|
||||||
if (string_num_content_bytes == remaining_input_bytes)
|
|
||||||
return exhaustedInputDiagnostic(inst_offset, opcode, type);
|
return exhaustedInputDiagnostic(inst_offset, opcode, type);
|
||||||
// Account for null in the word length, so add 1 for null, then add 3 to
|
|
||||||
// make sure we round up. The following is equivalent to:
|
|
||||||
// (string_num_content_bytes + 1 + 3) / 4
|
|
||||||
const size_t string_num_words = string_num_content_bytes / 4 + 1;
|
|
||||||
// Make sure we can record the word count without overflow.
|
// Make sure we can record the word count without overflow.
|
||||||
//
|
//
|
||||||
// This error can't currently be triggered because of validity
|
// This error can't currently be triggered because of validity
|
||||||
// checks elsewhere.
|
// checks elsewhere.
|
||||||
|
const size_t string_num_words = string.length() / 4 + 1;
|
||||||
if (string_num_words > std::numeric_limits<uint16_t>::max()) {
|
if (string_num_words > std::numeric_limits<uint16_t>::max()) {
|
||||||
return diagnostic() << "Literal string is longer than "
|
return diagnostic() << "Literal string is longer than "
|
||||||
<< std::numeric_limits<uint16_t>::max()
|
<< std::numeric_limits<uint16_t>::max()
|
||||||
@ -611,7 +612,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
|||||||
// There is only one string literal argument to OpExtInstImport,
|
// There is only one string literal argument to OpExtInstImport,
|
||||||
// so it's sufficient to guard this just on the opcode.
|
// so it's sufficient to guard this just on the opcode.
|
||||||
const spv_ext_inst_type_t ext_inst_type =
|
const spv_ext_inst_type_t ext_inst_type =
|
||||||
spvExtInstImportTypeGet(string);
|
spvExtInstImportTypeGet(string.c_str());
|
||||||
if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
|
if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
|
||||||
return diagnostic()
|
return diagnostic()
|
||||||
<< "Invalid extended instruction import '" << string << "'";
|
<< "Invalid extended instruction import '" << string << "'";
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#ifndef SOURCE_BINARY_H_
|
#ifndef SOURCE_BINARY_H_
|
||||||
#define SOURCE_BINARY_H_
|
#define SOURCE_BINARY_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "source/spirv_definition.h"
|
#include "source/spirv_definition.h"
|
||||||
#include "spirv-tools/libspirv.h"
|
#include "spirv-tools/libspirv.h"
|
||||||
|
|
||||||
@ -33,4 +35,9 @@ spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
|
|||||||
// replacement for C11's strnlen_s which might not exist in all environments.
|
// replacement for C11's strnlen_s which might not exist in all environments.
|
||||||
size_t spv_strnlen_s(const char* str, size_t strsz);
|
size_t spv_strnlen_s(const char* str, size_t strsz);
|
||||||
|
|
||||||
|
// Decode the string literal operand with index operand_index from instruction
|
||||||
|
// inst.
|
||||||
|
std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
|
||||||
|
const uint16_t operand_index);
|
||||||
|
|
||||||
#endif // SOURCE_BINARY_H_
|
#endif // SOURCE_BINARY_H_
|
||||||
|
@ -283,13 +283,11 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst,
|
|||||||
case SPV_OPERAND_TYPE_LITERAL_STRING: {
|
case SPV_OPERAND_TYPE_LITERAL_STRING: {
|
||||||
stream_ << "\"";
|
stream_ << "\"";
|
||||||
SetGreen();
|
SetGreen();
|
||||||
// Strings are always little-endian, and null-terminated.
|
|
||||||
// Write out the characters, escaping as needed, and without copying
|
std::string str = spvDecodeLiteralStringOperand(inst, operand_index);
|
||||||
// the entire string.
|
for (char const& c : str) {
|
||||||
auto c_str = reinterpret_cast<const char*>(inst.words + operand.offset);
|
if (c == '"' || c == '\\') stream_ << '\\';
|
||||||
for (auto p = c_str; *p; ++p) {
|
stream_ << c;
|
||||||
if (*p == '"' || *p == '\\') stream_ << '\\';
|
|
||||||
stream_ << *p;
|
|
||||||
}
|
}
|
||||||
ResetColor();
|
ResetColor();
|
||||||
stream_ << '"';
|
stream_ << '"';
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "source/binary.h"
|
||||||
#include "source/enum_string_mapping.h"
|
#include "source/enum_string_mapping.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
@ -30,8 +31,9 @@ std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
|
|||||||
const auto& operand = inst->operands[0];
|
const auto& operand = inst->operands[0];
|
||||||
assert(operand.type == SPV_OPERAND_TYPE_LITERAL_STRING);
|
assert(operand.type == SPV_OPERAND_TYPE_LITERAL_STRING);
|
||||||
assert(inst->num_words > operand.offset);
|
assert(inst->num_words > operand.offset);
|
||||||
|
(void)operand; /* No unused variables in release builds. */
|
||||||
|
|
||||||
return reinterpret_cast<const char*>(inst->words + operand.offset);
|
return spvDecodeLiteralStringOperand(*inst, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExtensionSetToString(const ExtensionSet& extensions) {
|
std::string ExtensionSetToString(const ExtensionSet& extensions) {
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "source/spirv_constant.h"
|
#include "source/spirv_constant.h"
|
||||||
#include "source/spirv_target_env.h"
|
#include "source/spirv_target_env.h"
|
||||||
#include "source/util/make_unique.h"
|
#include "source/util/make_unique.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
#include "spirv-tools/libspirv.hpp"
|
#include "spirv-tools/libspirv.hpp"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
@ -282,16 +283,15 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
|
|||||||
memory_model_inst->Clone(linked_context)));
|
memory_model_inst->Clone(linked_context)));
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
std::vector<std::pair<uint32_t, const char*>> entry_points;
|
std::vector<std::pair<uint32_t, std::string>> entry_points;
|
||||||
for (const auto& module : input_modules)
|
for (const auto& module : input_modules)
|
||||||
for (const auto& inst : module->entry_points()) {
|
for (const auto& inst : module->entry_points()) {
|
||||||
const uint32_t model = inst.GetSingleWordInOperand(0);
|
const uint32_t model = inst.GetSingleWordInOperand(0);
|
||||||
const char* const name =
|
const std::string name = inst.GetInOperand(2).AsString();
|
||||||
reinterpret_cast<const char*>(inst.GetInOperand(2).words.data());
|
|
||||||
const auto i = std::find_if(
|
const auto i = std::find_if(
|
||||||
entry_points.begin(), entry_points.end(),
|
entry_points.begin(), entry_points.end(),
|
||||||
[model, name](const std::pair<uint32_t, const char*>& v) {
|
[model, name](const std::pair<uint32_t, std::string>& v) {
|
||||||
return v.first == model && strcmp(name, v.second) == 0;
|
return v.first == model && v.second == name;
|
||||||
});
|
});
|
||||||
if (i != entry_points.end()) {
|
if (i != entry_points.end()) {
|
||||||
spv_operand_desc desc = nullptr;
|
spv_operand_desc desc = nullptr;
|
||||||
@ -334,11 +334,8 @@ spv_result_t MergeModules(const MessageConsumer& consumer,
|
|||||||
// OpModuleProcessed instruction about the linking step.
|
// OpModuleProcessed instruction about the linking step.
|
||||||
if (linked_module->version() >= 0x10100) {
|
if (linked_module->version() >= 0x10100) {
|
||||||
const std::string processed_string("Linked by SPIR-V Tools Linker");
|
const std::string processed_string("Linked by SPIR-V Tools Linker");
|
||||||
const auto num_chars = processed_string.size();
|
std::vector<uint32_t> processed_words =
|
||||||
// Compute num words, accommodate the terminating null character.
|
spvtools::utils::MakeVector(processed_string);
|
||||||
const auto num_words = (num_chars + 1 + 3) / 4;
|
|
||||||
std::vector<uint32_t> processed_words(num_words, 0u);
|
|
||||||
std::memcpy(processed_words.data(), processed_string.data(), num_chars);
|
|
||||||
linked_module->AddDebug3Inst(std::unique_ptr<Instruction>(
|
linked_module->AddDebug3Inst(std::unique_ptr<Instruction>(
|
||||||
new Instruction(linked_context, SpvOpModuleProcessed, 0u, 0u,
|
new Instruction(linked_context, SpvOpModuleProcessed, 0u, 0u,
|
||||||
{{SPV_OPERAND_TYPE_LITERAL_STRING, processed_words}})));
|
{{SPV_OPERAND_TYPE_LITERAL_STRING, processed_words}})));
|
||||||
@ -414,8 +411,7 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
|
|||||||
const uint32_t type = decoration.GetSingleWordInOperand(3u);
|
const uint32_t type = decoration.GetSingleWordInOperand(3u);
|
||||||
|
|
||||||
LinkageSymbolInfo symbol_info;
|
LinkageSymbolInfo symbol_info;
|
||||||
symbol_info.name =
|
symbol_info.name = decoration.GetInOperand(2u).AsString();
|
||||||
reinterpret_cast<const char*>(decoration.GetInOperand(2u).words.data());
|
|
||||||
symbol_info.id = id;
|
symbol_info.id = id;
|
||||||
symbol_info.type_id = 0u;
|
symbol_info.type_id = 0u;
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "spirv-tools/libspirv.h"
|
#include "source/binary.h"
|
||||||
|
|
||||||
#include "source/latest_version_spirv_header.h"
|
#include "source/latest_version_spirv_header.h"
|
||||||
#include "source/parsed_operand.h"
|
#include "source/parsed_operand.h"
|
||||||
|
#include "spirv-tools/libspirv.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace {
|
namespace {
|
||||||
@ -172,7 +172,7 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
|
|||||||
const auto result_id = inst.result_id;
|
const auto result_id = inst.result_id;
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
case SpvOpName:
|
case SpvOpName:
|
||||||
SaveName(inst.words[1], reinterpret_cast<const char*>(inst.words + 2));
|
SaveName(inst.words[1], spvDecodeLiteralStringOperand(inst, 1));
|
||||||
break;
|
break;
|
||||||
case SpvOpDecorate:
|
case SpvOpDecorate:
|
||||||
// Decorations come after OpName. So OpName will take precedence over
|
// Decorations come after OpName. So OpName will take precedence over
|
||||||
@ -274,9 +274,8 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
|
|||||||
SaveName(result_id, "Queue");
|
SaveName(result_id, "Queue");
|
||||||
break;
|
break;
|
||||||
case SpvOpTypeOpaque:
|
case SpvOpTypeOpaque:
|
||||||
SaveName(result_id,
|
SaveName(result_id, std::string("Opaque_") +
|
||||||
std::string("Opaque_") +
|
Sanitize(spvDecodeLiteralStringOperand(inst, 1)));
|
||||||
Sanitize(reinterpret_cast<const char*>(inst.words + 2)));
|
|
||||||
break;
|
break;
|
||||||
case SpvOpTypePipeStorage:
|
case SpvOpTypePipeStorage:
|
||||||
SaveName(result_id, "PipeStorage");
|
SaveName(result_id, "PipeStorage");
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "source/opt/iterator.h"
|
#include "source/opt/iterator.h"
|
||||||
#include "source/opt/reflect.h"
|
#include "source/opt/reflect.h"
|
||||||
#include "source/spirv_constant.h"
|
#include "source/spirv_constant.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -146,8 +147,7 @@ void AggressiveDCEPass::AddStores(Function* func, uint32_t ptrId) {
|
|||||||
bool AggressiveDCEPass::AllExtensionsSupported() const {
|
bool AggressiveDCEPass::AllExtensionsSupported() const {
|
||||||
// If any extension not in allowlist, return false
|
// If any extension not in allowlist, return false
|
||||||
for (auto& ei : get_module()->extensions()) {
|
for (auto& ei : get_module()->extensions()) {
|
||||||
const char* extName =
|
const std::string extName = ei.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
|
|
||||||
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -156,11 +156,9 @@ bool AggressiveDCEPass::AllExtensionsSupported() const {
|
|||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
assert(inst.opcode() == SpvOpExtInstImport &&
|
assert(inst.opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
|
extension_name != "NonSemantic.Shader.DebugInfo.100") {
|
||||||
0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
|
|
||||||
32)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -935,8 +935,7 @@ Pass::Status AmdExtensionToKhrPass::Process() {
|
|||||||
std::vector<Instruction*> to_be_killed;
|
std::vector<Instruction*> to_be_killed;
|
||||||
for (Instruction& inst : context()->module()->extensions()) {
|
for (Instruction& inst : context()->module()->extensions()) {
|
||||||
if (inst.opcode() == SpvOpExtension) {
|
if (inst.opcode() == SpvOpExtension) {
|
||||||
if (ext_to_remove.count(reinterpret_cast<const char*>(
|
if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
|
||||||
&(inst.GetInOperand(0).words[0]))) != 0) {
|
|
||||||
to_be_killed.push_back(&inst);
|
to_be_killed.push_back(&inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -944,8 +943,7 @@ Pass::Status AmdExtensionToKhrPass::Process() {
|
|||||||
|
|
||||||
for (Instruction& inst : context()->ext_inst_imports()) {
|
for (Instruction& inst : context()->ext_inst_imports()) {
|
||||||
if (inst.opcode() == SpvOpExtInstImport) {
|
if (inst.opcode() == SpvOpExtInstImport) {
|
||||||
if (ext_to_remove.count(reinterpret_cast<const char*>(
|
if (ext_to_remove.count(inst.GetInOperand(0).AsString()) != 0) {
|
||||||
&(inst.GetInOperand(0).words[0]))) != 0) {
|
|
||||||
to_be_killed.push_back(&inst);
|
to_be_killed.push_back(&inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,7 @@ void FeatureManager::AddExtension(Instruction* ext) {
|
|||||||
assert(ext->opcode() == SpvOpExtension &&
|
assert(ext->opcode() == SpvOpExtension &&
|
||||||
"Expecting an extension instruction.");
|
"Expecting an extension instruction.");
|
||||||
|
|
||||||
const std::string name =
|
const std::string name = ext->GetInOperand(0u).AsString();
|
||||||
reinterpret_cast<const char*>(ext->GetInOperand(0u).words.data());
|
|
||||||
Extension extension;
|
Extension extension;
|
||||||
if (GetExtensionFromString(name.c_str(), &extension)) {
|
if (GetExtensionFromString(name.c_str(), &extension)) {
|
||||||
extensions_.Add(extension);
|
extensions_.Add(extension);
|
||||||
|
@ -559,21 +559,17 @@ uint32_t GraphicsRobustAccessPass::GetGlslInsts() {
|
|||||||
if (module_status_.glsl_insts_id == 0) {
|
if (module_status_.glsl_insts_id == 0) {
|
||||||
// This string serves double-duty as raw data for a string and for a vector
|
// This string serves double-duty as raw data for a string and for a vector
|
||||||
// of 32-bit words
|
// of 32-bit words
|
||||||
const char glsl[] = "GLSL.std.450\0\0\0\0";
|
const char glsl[] = "GLSL.std.450";
|
||||||
const size_t glsl_str_byte_len = 16;
|
|
||||||
// Use an existing import if we can.
|
// Use an existing import if we can.
|
||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
const auto& name_words = inst.GetInOperand(0).words;
|
if (inst.GetInOperand(0).AsString() == glsl) {
|
||||||
if (0 == std::strncmp(reinterpret_cast<const char*>(name_words.data()),
|
|
||||||
glsl, glsl_str_byte_len)) {
|
|
||||||
module_status_.glsl_insts_id = inst.result_id();
|
module_status_.glsl_insts_id = inst.result_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (module_status_.glsl_insts_id == 0) {
|
if (module_status_.glsl_insts_id == 0) {
|
||||||
// Make a new import instruction.
|
// Make a new import instruction.
|
||||||
module_status_.glsl_insts_id = TakeNextId();
|
module_status_.glsl_insts_id = TakeNextId();
|
||||||
std::vector<uint32_t> words(glsl_str_byte_len / sizeof(uint32_t));
|
std::vector<uint32_t> words = spvtools::utils::MakeVector(glsl);
|
||||||
std::memcpy(words.data(), glsl, glsl_str_byte_len);
|
|
||||||
auto import_inst = MakeUnique<Instruction>(
|
auto import_inst = MakeUnique<Instruction>(
|
||||||
context(), SpvOpExtInstImport, 0, module_status_.glsl_insts_id,
|
context(), SpvOpExtInstImport, 0, module_status_.glsl_insts_id,
|
||||||
std::initializer_list<Operand>{
|
std::initializer_list<Operand>{
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "inst_debug_printf_pass.h"
|
#include "inst_debug_printf_pass.h"
|
||||||
|
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
#include "spirv/unified1/NonSemanticDebugPrintf.h"
|
#include "spirv/unified1/NonSemanticDebugPrintf.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
@ -231,10 +232,8 @@ Pass::Status InstDebugPrintfPass::ProcessImpl() {
|
|||||||
bool non_sem_set_seen = false;
|
bool non_sem_set_seen = false;
|
||||||
for (auto c_itr = context()->module()->ext_inst_import_begin();
|
for (auto c_itr = context()->module()->ext_inst_import_begin();
|
||||||
c_itr != context()->module()->ext_inst_import_end(); ++c_itr) {
|
c_itr != context()->module()->ext_inst_import_end(); ++c_itr) {
|
||||||
const char* set_name =
|
const std::string set_name = c_itr->GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&c_itr->GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(set_name, "NonSemantic.")) {
|
||||||
const char* non_sem_str = "NonSemantic.";
|
|
||||||
if (!strncmp(set_name, non_sem_str, strlen(non_sem_str))) {
|
|
||||||
non_sem_set_seen = true;
|
non_sem_set_seen = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -242,9 +241,8 @@ Pass::Status InstDebugPrintfPass::ProcessImpl() {
|
|||||||
if (!non_sem_set_seen) {
|
if (!non_sem_set_seen) {
|
||||||
for (auto c_itr = context()->module()->extension_begin();
|
for (auto c_itr = context()->module()->extension_begin();
|
||||||
c_itr != context()->module()->extension_end(); ++c_itr) {
|
c_itr != context()->module()->extension_end(); ++c_itr) {
|
||||||
const char* ext_name =
|
const std::string ext_name = c_itr->GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&c_itr->GetInOperand(0).words[0]);
|
if (ext_name == "SPV_KHR_non_semantic_info") {
|
||||||
if (!strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
|
|
||||||
context()->KillInst(&*c_itr);
|
context()->KillInst(&*c_itr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "NonSemanticShaderDebugInfo100.h"
|
#include "NonSemanticShaderDebugInfo100.h"
|
||||||
#include "OpenCLDebugInfo100.h"
|
#include "OpenCLDebugInfo100.h"
|
||||||
|
#include "source/binary.h"
|
||||||
#include "source/common_debug_info.h"
|
#include "source/common_debug_info.h"
|
||||||
#include "source/latest_version_glsl_std_450_header.h"
|
#include "source/latest_version_glsl_std_450_header.h"
|
||||||
#include "source/latest_version_spirv_header.h"
|
#include "source/latest_version_spirv_header.h"
|
||||||
@ -32,6 +33,7 @@
|
|||||||
#include "source/opt/reflect.h"
|
#include "source/opt/reflect.h"
|
||||||
#include "source/util/ilist_node.h"
|
#include "source/util/ilist_node.h"
|
||||||
#include "source/util/small_vector.h"
|
#include "source/util/small_vector.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
#include "spirv-tools/libspirv.h"
|
#include "spirv-tools/libspirv.h"
|
||||||
|
|
||||||
const uint32_t kNoDebugScope = 0;
|
const uint32_t kNoDebugScope = 0;
|
||||||
@ -85,14 +87,11 @@ struct Operand {
|
|||||||
spv_operand_type_t type; // Type of this logical operand.
|
spv_operand_type_t type; // Type of this logical operand.
|
||||||
OperandData words; // Binary segments of this logical operand.
|
OperandData words; // Binary segments of this logical operand.
|
||||||
|
|
||||||
// Returns a string operand as a C-style string.
|
|
||||||
const char* AsCString() const {
|
|
||||||
assert(type == SPV_OPERAND_TYPE_LITERAL_STRING);
|
|
||||||
return reinterpret_cast<const char*>(words.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a string operand as a std::string.
|
// Returns a string operand as a std::string.
|
||||||
std::string AsString() const { return AsCString(); }
|
std::string AsString() const {
|
||||||
|
assert(type == SPV_OPERAND_TYPE_LITERAL_STRING);
|
||||||
|
return spvtools::utils::MakeString(words);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a literal integer operand as a uint64_t
|
// Returns a literal integer operand as a uint64_t
|
||||||
uint64_t AsLiteralUint64() const {
|
uint64_t AsLiteralUint64() const {
|
||||||
|
@ -623,9 +623,8 @@ void IRContext::AddCombinatorsForCapability(uint32_t capability) {
|
|||||||
void IRContext::AddCombinatorsForExtension(Instruction* extension) {
|
void IRContext::AddCombinatorsForExtension(Instruction* extension) {
|
||||||
assert(extension->opcode() == SpvOpExtInstImport &&
|
assert(extension->opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = extension->GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&extension->GetInOperand(0).words[0]);
|
if (extension_name == "GLSL.std.450") {
|
||||||
if (!strcmp(extension_name, "GLSL.std.450")) {
|
|
||||||
combinator_ops_[extension->result_id()] = {GLSLstd450Round,
|
combinator_ops_[extension->result_id()] = {GLSLstd450Round,
|
||||||
GLSLstd450RoundEven,
|
GLSLstd450RoundEven,
|
||||||
GLSLstd450Trunc,
|
GLSLstd450Trunc,
|
||||||
@ -944,11 +943,11 @@ void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
|
|||||||
|
|
||||||
uint32_t line_number = 0;
|
uint32_t line_number = 0;
|
||||||
uint32_t col_number = 0;
|
uint32_t col_number = 0;
|
||||||
char* source = nullptr;
|
std::string source;
|
||||||
if (line_inst != nullptr) {
|
if (line_inst != nullptr) {
|
||||||
Instruction* file_name =
|
Instruction* file_name =
|
||||||
get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
|
get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
|
||||||
source = reinterpret_cast<char*>(&file_name->GetInOperand(0).words[0]);
|
source = file_name->GetInOperand(0).AsString();
|
||||||
|
|
||||||
// Get the line number and column number.
|
// Get the line number and column number.
|
||||||
line_number = line_inst->GetSingleWordInOperand(1);
|
line_number = line_inst->GetSingleWordInOperand(1);
|
||||||
@ -957,7 +956,7 @@ void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
|
|||||||
|
|
||||||
message +=
|
message +=
|
||||||
"\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
|
"\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
|
||||||
consumer()(SPV_MSG_ERROR, source, {line_number, col_number, 0},
|
consumer()(SPV_MSG_ERROR, source.c_str(), {line_number, col_number, 0},
|
||||||
message.c_str());
|
message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "source/opt/type_manager.h"
|
#include "source/opt/type_manager.h"
|
||||||
#include "source/opt/value_number_table.h"
|
#include "source/opt/value_number_table.h"
|
||||||
#include "source/util/make_unique.h"
|
#include "source/util/make_unique.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -1032,11 +1033,7 @@ void IRContext::AddCapability(std::unique_ptr<Instruction>&& c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRContext::AddExtension(const std::string& ext_name) {
|
void IRContext::AddExtension(const std::string& ext_name) {
|
||||||
const auto num_chars = ext_name.size();
|
std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(ext_name);
|
||||||
// Compute num words, accommodate the terminating null character.
|
|
||||||
const auto num_words = (num_chars + 1 + 3) / 4;
|
|
||||||
std::vector<uint32_t> ext_words(num_words, 0u);
|
|
||||||
std::memcpy(ext_words.data(), ext_name.data(), num_chars);
|
|
||||||
AddExtension(std::unique_ptr<Instruction>(
|
AddExtension(std::unique_ptr<Instruction>(
|
||||||
new Instruction(this, SpvOpExtension, 0u, 0u,
|
new Instruction(this, SpvOpExtension, 0u, 0u,
|
||||||
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
||||||
@ -1053,11 +1050,7 @@ void IRContext::AddExtension(std::unique_ptr<Instruction>&& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRContext::AddExtInstImport(const std::string& name) {
|
void IRContext::AddExtInstImport(const std::string& name) {
|
||||||
const auto num_chars = name.size();
|
std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(name);
|
||||||
// Compute num words, accommodate the terminating null character.
|
|
||||||
const auto num_words = (num_chars + 1 + 3) / 4;
|
|
||||||
std::vector<uint32_t> ext_words(num_words, 0u);
|
|
||||||
std::memcpy(ext_words.data(), name.data(), num_chars);
|
|
||||||
AddExtInstImport(std::unique_ptr<Instruction>(
|
AddExtInstImport(std::unique_ptr<Instruction>(
|
||||||
new Instruction(this, SpvOpExtInstImport, 0u, TakeNextId(),
|
new Instruction(this, SpvOpExtInstImport, 0u, TakeNextId(),
|
||||||
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
{{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "ir_builder.h"
|
#include "ir_builder.h"
|
||||||
#include "ir_context.h"
|
#include "ir_context.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -328,8 +329,7 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
|
|||||||
return false;
|
return false;
|
||||||
// If any extension not in allowlist, return false
|
// If any extension not in allowlist, return false
|
||||||
for (auto& ei : get_module()->extensions()) {
|
for (auto& ei : get_module()->extensions()) {
|
||||||
const char* extName =
|
const std::string extName = ei.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
|
|
||||||
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -339,11 +339,9 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
|
|||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
assert(inst.opcode() == SpvOpExtInstImport &&
|
assert(inst.opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
|
extension_name != "NonSemantic.Shader.DebugInfo.100") {
|
||||||
0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
|
|
||||||
32)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "source/opt/iterator.h"
|
#include "source/opt/iterator.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -183,8 +184,7 @@ void LocalSingleBlockLoadStoreElimPass::Initialize() {
|
|||||||
bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
|
bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
|
||||||
// If any extension not in allowlist, return false
|
// If any extension not in allowlist, return false
|
||||||
for (auto& ei : get_module()->extensions()) {
|
for (auto& ei : get_module()->extensions()) {
|
||||||
const char* extName =
|
const std::string extName = ei.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
|
|
||||||
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -194,11 +194,9 @@ bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
|
|||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
assert(inst.opcode() == SpvOpExtInstImport &&
|
assert(inst.opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
|
extension_name != "NonSemantic.Shader.DebugInfo.100") {
|
||||||
0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
|
|
||||||
32)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "source/cfa.h"
|
#include "source/cfa.h"
|
||||||
#include "source/latest_version_glsl_std_450_header.h"
|
#include "source/latest_version_glsl_std_450_header.h"
|
||||||
#include "source/opt/iterator.h"
|
#include "source/opt/iterator.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -48,8 +49,7 @@ bool LocalSingleStoreElimPass::LocalSingleStoreElim(Function* func) {
|
|||||||
bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
|
bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
|
||||||
// If any extension not in allowlist, return false
|
// If any extension not in allowlist, return false
|
||||||
for (auto& ei : get_module()->extensions()) {
|
for (auto& ei : get_module()->extensions()) {
|
||||||
const char* extName =
|
const std::string extName = ei.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
|
|
||||||
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -59,11 +59,9 @@ bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
|
|||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
assert(inst.opcode() == SpvOpExtInstImport &&
|
assert(inst.opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(extension_name, "NonSemantic.") &&
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12) &&
|
extension_name != "NonSemantic.Shader.DebugInfo.100") {
|
||||||
0 != std::strncmp(extension_name, "NonSemantic.Shader.DebugInfo.100",
|
|
||||||
32)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,9 +260,7 @@ bool Module::HasExplicitCapability(uint32_t cap) {
|
|||||||
|
|
||||||
uint32_t Module::GetExtInstImportId(const char* extstr) {
|
uint32_t Module::GetExtInstImportId(const char* extstr) {
|
||||||
for (auto& ei : ext_inst_imports_)
|
for (auto& ei : ext_inst_imports_)
|
||||||
if (!strcmp(extstr,
|
if (!ei.GetInOperand(0).AsString().compare(extstr)) return ei.result_id();
|
||||||
reinterpret_cast<const char*>(&(ei.GetInOperand(0).words[0]))))
|
|
||||||
return ei.result_id();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,9 +72,8 @@ bool RemoveDuplicatesPass::RemoveDuplicatesExtInstImports() const {
|
|||||||
|
|
||||||
std::unordered_map<std::string, SpvId> ext_inst_imports;
|
std::unordered_map<std::string, SpvId> ext_inst_imports;
|
||||||
for (auto* i = &*context()->ext_inst_import_begin(); i;) {
|
for (auto* i = &*context()->ext_inst_import_begin(); i;) {
|
||||||
auto res = ext_inst_imports.emplace(
|
auto res = ext_inst_imports.emplace(i->GetInOperand(0u).AsString(),
|
||||||
reinterpret_cast<const char*>(i->GetInOperand(0u).words.data()),
|
i->result_id());
|
||||||
i->result_id());
|
|
||||||
if (res.second) {
|
if (res.second) {
|
||||||
// Never seen before, keep it.
|
// Never seen before, keep it.
|
||||||
i = i->NextNode();
|
i = i->NextNode();
|
||||||
|
@ -112,8 +112,7 @@ bool ReplaceInvalidOpcodePass::RewriteFunction(Function* function,
|
|||||||
}
|
}
|
||||||
Instruction* file_name =
|
Instruction* file_name =
|
||||||
context()->get_def_use_mgr()->GetDef(file_name_id);
|
context()->get_def_use_mgr()->GetDef(file_name_id);
|
||||||
const char* source = reinterpret_cast<const char*>(
|
const std::string source = file_name->GetInOperand(0).AsString();
|
||||||
&file_name->GetInOperand(0).words[0]);
|
|
||||||
|
|
||||||
// Get the line number and column number.
|
// Get the line number and column number.
|
||||||
uint32_t line_number =
|
uint32_t line_number =
|
||||||
@ -121,7 +120,7 @@ bool ReplaceInvalidOpcodePass::RewriteFunction(Function* function,
|
|||||||
uint32_t col_number = last_line_dbg_inst->GetSingleWordInOperand(2);
|
uint32_t col_number = last_line_dbg_inst->GetSingleWordInOperand(2);
|
||||||
|
|
||||||
// Replace the instruction.
|
// Replace the instruction.
|
||||||
ReplaceInstruction(inst, source, line_number, col_number);
|
ReplaceInstruction(inst, source.c_str(), line_number, col_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "source/opt/strip_debug_info_pass.h"
|
#include "source/opt/strip_debug_info_pass.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -21,9 +22,8 @@ namespace opt {
|
|||||||
Pass::Status StripDebugInfoPass::Process() {
|
Pass::Status StripDebugInfoPass::Process() {
|
||||||
bool uses_non_semantic_info = false;
|
bool uses_non_semantic_info = false;
|
||||||
for (auto& inst : context()->module()->extensions()) {
|
for (auto& inst : context()->module()->extensions()) {
|
||||||
const char* ext_name =
|
const std::string ext_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (ext_name == "SPV_KHR_non_semantic_info") {
|
||||||
if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
|
|
||||||
uses_non_semantic_info = true;
|
uses_non_semantic_info = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,9 +46,10 @@ Pass::Status StripDebugInfoPass::Process() {
|
|||||||
if (use->opcode() == SpvOpExtInst) {
|
if (use->opcode() == SpvOpExtInst) {
|
||||||
auto ext_inst_set =
|
auto ext_inst_set =
|
||||||
def_use->GetDef(use->GetSingleWordInOperand(0u));
|
def_use->GetDef(use->GetSingleWordInOperand(0u));
|
||||||
const char* extension_name = reinterpret_cast<const char*>(
|
const std::string extension_name =
|
||||||
&ext_inst_set->GetInOperand(0).words[0]);
|
ext_inst_set->GetInOperand(0).AsString();
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) {
|
if (spvtools::utils::starts_with(extension_name,
|
||||||
|
"NonSemantic.")) {
|
||||||
// found a non-semantic use, return false as we cannot
|
// found a non-semantic use, return false as we cannot
|
||||||
// remove this OpString
|
// remove this OpString
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "source/opt/instruction.h"
|
#include "source/opt/instruction.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -60,14 +61,13 @@ Pass::Status StripReflectInfoPass::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& inst : context()->module()->extensions()) {
|
for (auto& inst : context()->module()->extensions()) {
|
||||||
const char* ext_name =
|
const std::string ext_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (ext_name == "SPV_GOOGLE_hlsl_functionality1") {
|
||||||
if (0 == std::strcmp(ext_name, "SPV_GOOGLE_hlsl_functionality1")) {
|
|
||||||
to_remove.push_back(&inst);
|
to_remove.push_back(&inst);
|
||||||
} else if (!other_uses_for_decorate_string &&
|
} else if (!other_uses_for_decorate_string &&
|
||||||
0 == std::strcmp(ext_name, "SPV_GOOGLE_decorate_string")) {
|
ext_name == "SPV_GOOGLE_decorate_string") {
|
||||||
to_remove.push_back(&inst);
|
to_remove.push_back(&inst);
|
||||||
} else if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) {
|
} else if (ext_name == "SPV_KHR_non_semantic_info") {
|
||||||
to_remove.push_back(&inst);
|
to_remove.push_back(&inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,9 +84,8 @@ Pass::Status StripReflectInfoPass::Process() {
|
|||||||
for (auto& inst : context()->module()->ext_inst_imports()) {
|
for (auto& inst : context()->module()->ext_inst_imports()) {
|
||||||
assert(inst.opcode() == SpvOpExtInstImport &&
|
assert(inst.opcode() == SpvOpExtInstImport &&
|
||||||
"Expecting an import of an extension's instruction set.");
|
"Expecting an import of an extension's instruction set.");
|
||||||
const char* extension_name =
|
const std::string extension_name = inst.GetInOperand(0).AsString();
|
||||||
reinterpret_cast<const char*>(&inst.GetInOperand(0).words[0]);
|
if (spvtools::utils::starts_with(extension_name, "NonSemantic.")) {
|
||||||
if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) {
|
|
||||||
non_semantic_sets.insert(inst.result_id());
|
non_semantic_sets.insert(inst.result_id());
|
||||||
to_remove.push_back(&inst);
|
to_remove.push_back(&inst);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "source/opt/log.h"
|
#include "source/opt/log.h"
|
||||||
#include "source/opt/reflect.h"
|
#include "source/opt/reflect.h"
|
||||||
#include "source/util/make_unique.h"
|
#include "source/util/make_unique.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -349,11 +350,8 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) {
|
|||||||
}
|
}
|
||||||
case Type::kOpaque: {
|
case Type::kOpaque: {
|
||||||
const Opaque* opaque = type->AsOpaque();
|
const Opaque* opaque = type->AsOpaque();
|
||||||
size_t size = opaque->name().size();
|
|
||||||
// Convert to null-terminated packed UTF-8 string.
|
// Convert to null-terminated packed UTF-8 string.
|
||||||
std::vector<uint32_t> words(size / 4 + 1, 0);
|
std::vector<uint32_t> words = spvtools::utils::MakeVector(opaque->name());
|
||||||
char* dst = reinterpret_cast<char*>(words.data());
|
|
||||||
strncpy(dst, opaque->name().c_str(), size);
|
|
||||||
typeInst = MakeUnique<Instruction>(
|
typeInst = MakeUnique<Instruction>(
|
||||||
context(), SpvOpTypeOpaque, 0, id,
|
context(), SpvOpTypeOpaque, 0, id,
|
||||||
std::initializer_list<Operand>{
|
std::initializer_list<Operand>{
|
||||||
@ -781,8 +779,7 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case SpvOpTypeOpaque: {
|
case SpvOpTypeOpaque: {
|
||||||
const uint32_t* data = inst.GetInOperand(0).words.data();
|
type = new Opaque(inst.GetInOperand(0).AsString());
|
||||||
type = new Opaque(reinterpret_cast<const char*>(data));
|
|
||||||
} break;
|
} break;
|
||||||
case SpvOpTypePointer: {
|
case SpvOpTypePointer: {
|
||||||
uint32_t pointee_type_id = inst.GetSingleWordInOperand(1);
|
uint32_t pointee_type_id = inst.GetSingleWordInOperand(1);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
#include "source/spirv_constant.h"
|
#include "source/spirv_constant.h"
|
||||||
#include "source/util/make_unique.h"
|
#include "source/util/make_unique.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace opt {
|
namespace opt {
|
||||||
@ -58,9 +59,7 @@ void UpgradeMemoryModel::UpgradeMemoryModelInstruction() {
|
|||||||
std::initializer_list<Operand>{
|
std::initializer_list<Operand>{
|
||||||
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityVulkanMemoryModelKHR}}}));
|
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityVulkanMemoryModelKHR}}}));
|
||||||
const std::string extension = "SPV_KHR_vulkan_memory_model";
|
const std::string extension = "SPV_KHR_vulkan_memory_model";
|
||||||
std::vector<uint32_t> words(extension.size() / 4 + 1, 0);
|
std::vector<uint32_t> words = spvtools::utils::MakeVector(extension);
|
||||||
char* dst = reinterpret_cast<char*>(words.data());
|
|
||||||
strncpy(dst, extension.c_str(), extension.size());
|
|
||||||
context()->AddExtension(
|
context()->AddExtension(
|
||||||
MakeUnique<Instruction>(context(), SpvOpExtension, 0, 0,
|
MakeUnique<Instruction>(context(), SpvOpExtension, 0, 0,
|
||||||
std::initializer_list<Operand>{
|
std::initializer_list<Operand>{
|
||||||
@ -85,8 +84,7 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
|||||||
if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) {
|
if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) {
|
||||||
auto import =
|
auto import =
|
||||||
get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
|
get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
|
||||||
if (reinterpret_cast<char*>(import->GetInOperand(0u).words.data()) ==
|
if (import->GetInOperand(0u).AsString() == "GLSL.std.450") {
|
||||||
std::string("GLSL.std.450")) {
|
|
||||||
UpgradeExtInst(inst);
|
UpgradeExtInst(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "source/util/bitutils.h"
|
#include "source/util/bitutils.h"
|
||||||
#include "source/util/hex_float.h"
|
#include "source/util/hex_float.h"
|
||||||
#include "source/util/parse_number.h"
|
#include "source/util/parse_number.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace {
|
namespace {
|
||||||
@ -307,14 +308,8 @@ spv_result_t AssemblyContext::binaryEncodeString(const char* value,
|
|||||||
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
|
<< SPV_LIMIT_INSTRUCTION_WORD_COUNT_MAX << " words.";
|
||||||
}
|
}
|
||||||
|
|
||||||
pInst->words.resize(newWordCount);
|
pInst->words.reserve(newWordCount);
|
||||||
|
spvtools::utils::AppendToVector(value, &pInst->words);
|
||||||
// Make sure all the bytes in the last word are 0, in case we only
|
|
||||||
// write a partial word at the end.
|
|
||||||
pInst->words.back() = 0;
|
|
||||||
|
|
||||||
char* dest = (char*)&pInst->words[oldWordCount];
|
|
||||||
strncpy(dest, value, length + 1);
|
|
||||||
|
|
||||||
return SPV_SUCCESS;
|
return SPV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#define SOURCE_UTIL_STRING_UTILS_H_
|
#define SOURCE_UTIL_STRING_UTILS_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -44,9 +46,10 @@ std::string CardinalToOrdinal(size_t cardinal);
|
|||||||
// string will be empty.
|
// string will be empty.
|
||||||
std::pair<std::string, std::string> SplitFlagArgs(const std::string& flag);
|
std::pair<std::string, std::string> SplitFlagArgs(const std::string& flag);
|
||||||
|
|
||||||
// Encodes a string as a sequence of words, using the SPIR-V encoding.
|
// Encodes a string as a sequence of words, using the SPIR-V encoding, appending
|
||||||
inline std::vector<uint32_t> MakeVector(std::string input) {
|
// to an existing vector.
|
||||||
std::vector<uint32_t> result;
|
inline void AppendToVector(const std::string& input,
|
||||||
|
std::vector<uint32_t>* result) {
|
||||||
uint32_t word = 0;
|
uint32_t word = 0;
|
||||||
size_t num_bytes = input.size();
|
size_t num_bytes = input.size();
|
||||||
// SPIR-V strings are null-terminated. The byte_index == num_bytes
|
// SPIR-V strings are null-terminated. The byte_index == num_bytes
|
||||||
@ -56,24 +59,36 @@ inline std::vector<uint32_t> MakeVector(std::string input) {
|
|||||||
(byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0));
|
(byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0));
|
||||||
word |= (new_byte << (8 * (byte_index % sizeof(uint32_t))));
|
word |= (new_byte << (8 * (byte_index % sizeof(uint32_t))));
|
||||||
if (3 == (byte_index % sizeof(uint32_t))) {
|
if (3 == (byte_index % sizeof(uint32_t))) {
|
||||||
result.push_back(word);
|
result->push_back(word);
|
||||||
word = 0;
|
word = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Emit a trailing partial word.
|
// Emit a trailing partial word.
|
||||||
if ((num_bytes + 1) % sizeof(uint32_t)) {
|
if ((num_bytes + 1) % sizeof(uint32_t)) {
|
||||||
result.push_back(word);
|
result->push_back(word);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a string as a sequence of words, using the SPIR-V encoding.
|
||||||
|
inline std::vector<uint32_t> MakeVector(const std::string& input) {
|
||||||
|
std::vector<uint32_t> result;
|
||||||
|
AppendToVector(input, &result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode a string from a sequence of words, using the SPIR-V encoding.
|
// Decode a string from a sequence of words between first and last, using the
|
||||||
template <class VectorType>
|
// SPIR-V encoding. Assert that a terminating 0-byte was found (unless
|
||||||
inline std::string MakeString(const VectorType& words) {
|
// assert_found_terminating_null is passed as false).
|
||||||
|
template <class InputIt>
|
||||||
|
inline std::string MakeString(InputIt first, InputIt last,
|
||||||
|
bool assert_found_terminating_null = true) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
constexpr size_t kCharsPerWord = sizeof(*first);
|
||||||
|
static_assert(kCharsPerWord == 4, "expect 4-byte word");
|
||||||
|
|
||||||
for (uint32_t word : words) {
|
for (InputIt pos = first; pos != last; ++pos) {
|
||||||
for (int byte_index = 0; byte_index < 4; byte_index++) {
|
uint32_t word = *pos;
|
||||||
|
for (size_t byte_index = 0; byte_index < kCharsPerWord; byte_index++) {
|
||||||
uint32_t extracted_word = (word >> (8 * byte_index)) & 0xFF;
|
uint32_t extracted_word = (word >> (8 * byte_index)) & 0xFF;
|
||||||
char c = static_cast<char>(extracted_word);
|
char c = static_cast<char>(extracted_word);
|
||||||
if (c == 0) {
|
if (c == 0) {
|
||||||
@ -82,9 +97,33 @@ inline std::string MakeString(const VectorType& words) {
|
|||||||
result += c;
|
result += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(false && "Did not find terminating null for the string.");
|
assert(!assert_found_terminating_null &&
|
||||||
|
"Did not find terminating null for the string.");
|
||||||
|
(void)assert_found_terminating_null; /* No unused parameters in release
|
||||||
|
builds. */
|
||||||
return result;
|
return result;
|
||||||
} // namespace utils
|
}
|
||||||
|
|
||||||
|
// Decode a string from a sequence of words in a vector, using the SPIR-V
|
||||||
|
// encoding.
|
||||||
|
template <class VectorType>
|
||||||
|
inline std::string MakeString(const VectorType& words,
|
||||||
|
bool assert_found_terminating_null = true) {
|
||||||
|
return MakeString(words.cbegin(), words.cend(),
|
||||||
|
assert_found_terminating_null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a string from array words, consuming up to count words, using the
|
||||||
|
// SPIR-V encoding.
|
||||||
|
inline std::string MakeString(const uint32_t* words, size_t num_words,
|
||||||
|
bool assert_found_terminating_null = true) {
|
||||||
|
return MakeString(words, words + num_words, assert_found_terminating_null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if str starts with prefix (only included since C++20)
|
||||||
|
inline bool starts_with(const std::string& str, const char* prefix) {
|
||||||
|
return 0 == str.compare(0, std::strlen(prefix), prefix);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "source/binary.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace val {
|
namespace val {
|
||||||
|
|
||||||
@ -41,5 +44,12 @@ bool operator==(const Instruction& lhs, uint32_t rhs) {
|
|||||||
return lhs.id() == rhs;
|
return lhs.id() == rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string Instruction::GetOperandAs<std::string>(size_t index) const {
|
||||||
|
const spv_parsed_operand_t& o = operands_.at(index);
|
||||||
|
assert(o.offset + o.num_words <= inst_.num_words);
|
||||||
|
return spvtools::utils::MakeString(words_.data() + o.offset, o.num_words);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace val
|
} // namespace val
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
@ -133,6 +133,9 @@ bool operator<(const Instruction& lhs, uint32_t rhs);
|
|||||||
bool operator==(const Instruction& lhs, const Instruction& rhs);
|
bool operator==(const Instruction& lhs, const Instruction& rhs);
|
||||||
bool operator==(const Instruction& lhs, uint32_t rhs);
|
bool operator==(const Instruction& lhs, uint32_t rhs);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string Instruction::GetOperandAs<std::string>(size_t index) const;
|
||||||
|
|
||||||
} // namespace val
|
} // namespace val
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
|
||||||
|
@ -219,9 +219,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
|
|||||||
if (inst->opcode() == SpvOpEntryPoint) {
|
if (inst->opcode() == SpvOpEntryPoint) {
|
||||||
const auto entry_point = inst->GetOperandAs<uint32_t>(1);
|
const auto entry_point = inst->GetOperandAs<uint32_t>(1);
|
||||||
const auto execution_model = inst->GetOperandAs<SpvExecutionModel>(0);
|
const auto execution_model = inst->GetOperandAs<SpvExecutionModel>(0);
|
||||||
const char* str = reinterpret_cast<const char*>(
|
const std::string desc_name = inst->GetOperandAs<std::string>(2);
|
||||||
inst->words().data() + inst->operand(2).offset);
|
|
||||||
const std::string desc_name(str);
|
|
||||||
|
|
||||||
ValidationState_t::EntryPointDescription desc;
|
ValidationState_t::EntryPointDescription desc;
|
||||||
desc.name = desc_name;
|
desc.name = desc_name;
|
||||||
@ -237,9 +235,8 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
|
|||||||
for (const Instruction* check_inst : visited_entry_points) {
|
for (const Instruction* check_inst : visited_entry_points) {
|
||||||
const auto check_execution_model =
|
const auto check_execution_model =
|
||||||
check_inst->GetOperandAs<SpvExecutionModel>(0);
|
check_inst->GetOperandAs<SpvExecutionModel>(0);
|
||||||
const char* check_str = reinterpret_cast<const char*>(
|
const std::string check_name =
|
||||||
check_inst->words().data() + inst->operand(2).offset);
|
check_inst->GetOperandAs<std::string>(2);
|
||||||
const std::string check_name(check_str);
|
|
||||||
|
|
||||||
if (desc_name == check_name &&
|
if (desc_name == check_name &&
|
||||||
execution_model == check_execution_model) {
|
execution_model == check_execution_model) {
|
||||||
|
@ -21,11 +21,13 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "source/binary.h"
|
||||||
#include "source/diagnostic.h"
|
#include "source/diagnostic.h"
|
||||||
#include "source/opcode.h"
|
#include "source/opcode.h"
|
||||||
#include "source/spirv_constant.h"
|
#include "source/spirv_constant.h"
|
||||||
#include "source/spirv_target_env.h"
|
#include "source/spirv_target_env.h"
|
||||||
#include "source/spirv_validator_options.h"
|
#include "source/spirv_validator_options.h"
|
||||||
|
#include "source/util/string_utils.h"
|
||||||
#include "source/val/validate_scopes.h"
|
#include "source/val/validate_scopes.h"
|
||||||
#include "source/val/validation_state.h"
|
#include "source/val/validation_state.h"
|
||||||
|
|
||||||
@ -798,8 +800,8 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
|
|||||||
// targeted by an OpEntryPoint instruction
|
// targeted by an OpEntryPoint instruction
|
||||||
for (auto& decoration : vstate.id_decorations(entry_point)) {
|
for (auto& decoration : vstate.id_decorations(entry_point)) {
|
||||||
if (SpvDecorationLinkageAttributes == decoration.dec_type()) {
|
if (SpvDecorationLinkageAttributes == decoration.dec_type()) {
|
||||||
const char* linkage_name =
|
const std::string linkage_name =
|
||||||
reinterpret_cast<const char*>(&decoration.params()[0]);
|
spvtools::utils::MakeString(decoration.params());
|
||||||
return vstate.diag(SPV_ERROR_INVALID_BINARY,
|
return vstate.diag(SPV_ERROR_INVALID_BINARY,
|
||||||
vstate.FindDef(entry_point))
|
vstate.FindDef(entry_point))
|
||||||
<< "The LinkageAttributes Decoration (Linkage name: "
|
<< "The LinkageAttributes Decoration (Linkage name: "
|
||||||
|
@ -280,8 +280,7 @@ spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _,
|
|||||||
return _.diag(SPV_ERROR_INVALID_ID, inst) << "Name must be an OpString";
|
return _.diag(SPV_ERROR_INVALID_ID, inst) << "Name must be an OpString";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string name_str = reinterpret_cast<const char*>(
|
const std::string name_str = name->GetOperandAs<std::string>(1);
|
||||||
name->words().data() + name->operands()[1].offset);
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto& desc : _.entry_point_descriptions(kernel_id)) {
|
for (auto& desc : _.entry_point_descriptions(kernel_id)) {
|
||||||
if (name_str == desc.name) {
|
if (name_str == desc.name) {
|
||||||
@ -741,8 +740,7 @@ spv_result_t ValidateExtInstImport(ValidationState_t& _,
|
|||||||
const Instruction* inst) {
|
const Instruction* inst) {
|
||||||
const auto name_id = 1;
|
const auto name_id = 1;
|
||||||
if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
|
if (!_.HasExtension(kSPV_KHR_non_semantic_info)) {
|
||||||
const std::string name(reinterpret_cast<const char*>(
|
const std::string name = inst->GetOperandAs<std::string>(name_id);
|
||||||
inst->words().data() + inst->operands()[name_id].offset));
|
|
||||||
if (name.find("NonSemantic.") == 0) {
|
if (name.find("NonSemantic.") == 0) {
|
||||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
<< "NonSemantic extended instruction sets cannot be declared "
|
<< "NonSemantic extended instruction sets cannot be declared "
|
||||||
@ -774,7 +772,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|||||||
assert(import_inst);
|
assert(import_inst);
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
|
ss << import_inst->GetOperandAs<std::string>(1);
|
||||||
ss << " ";
|
ss << " ";
|
||||||
ss << desc->name;
|
ss << desc->name;
|
||||||
|
|
||||||
@ -3264,8 +3262,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|||||||
}
|
}
|
||||||
} else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
|
} else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) {
|
||||||
auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2));
|
auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2));
|
||||||
const std::string name(reinterpret_cast<const char*>(
|
const std::string name = import_inst->GetOperandAs<std::string>(1);
|
||||||
import_inst->words().data() + import_inst->operands()[1].offset));
|
|
||||||
const std::string reflection = "NonSemantic.ClspvReflection.";
|
const std::string reflection = "NonSemantic.ClspvReflection.";
|
||||||
char* end_ptr;
|
char* end_ptr;
|
||||||
auto version_string = name.substr(reflection.size());
|
auto version_string = name.substr(reflection.size());
|
||||||
|
@ -497,15 +497,13 @@ void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
|
|||||||
switch (inst->opcode()) {
|
switch (inst->opcode()) {
|
||||||
case SpvOpName: {
|
case SpvOpName: {
|
||||||
const auto target = inst->GetOperandAs<uint32_t>(0);
|
const auto target = inst->GetOperandAs<uint32_t>(0);
|
||||||
const auto* str = reinterpret_cast<const char*>(inst->words().data() +
|
const std::string str = inst->GetOperandAs<std::string>(1);
|
||||||
inst->operand(1).offset);
|
|
||||||
AssignNameToId(target, str);
|
AssignNameToId(target, str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SpvOpMemberName: {
|
case SpvOpMemberName: {
|
||||||
const auto target = inst->GetOperandAs<uint32_t>(0);
|
const auto target = inst->GetOperandAs<uint32_t>(0);
|
||||||
const auto* str = reinterpret_cast<const char*>(inst->words().data() +
|
const std::string str = inst->GetOperandAs<std::string>(2);
|
||||||
inst->operand(2).offset);
|
|
||||||
AssignNameToId(target, str);
|
AssignNameToId(target, str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -203,16 +203,7 @@ class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> {
|
|||||||
void Parse(const SpirvVector& words, spv_result_t expected_result,
|
void Parse(const SpirvVector& words, spv_result_t expected_result,
|
||||||
bool flip_words = false) {
|
bool flip_words = false) {
|
||||||
SpirvVector flipped_words(words);
|
SpirvVector flipped_words(words);
|
||||||
SCOPED_TRACE(flip_words ? "Flipped Endianness" : "Normal Endianness");
|
MaybeFlipWords(flip_words, flipped_words.begin(), flipped_words.end());
|
||||||
if (flip_words) {
|
|
||||||
std::transform(flipped_words.begin(), flipped_words.end(),
|
|
||||||
flipped_words.begin(), [](const uint32_t raw_word) {
|
|
||||||
return spvFixWord(raw_word,
|
|
||||||
I32_ENDIAN_HOST == I32_ENDIAN_BIG
|
|
||||||
? SPV_ENDIANNESS_LITTLE
|
|
||||||
: SPV_ENDIANNESS_BIG);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
EXPECT_EQ(expected_result,
|
EXPECT_EQ(expected_result,
|
||||||
spvBinaryParse(ScopedContext().context, &client_,
|
spvBinaryParse(ScopedContext().context, &client_,
|
||||||
flipped_words.data(), flipped_words.size(),
|
flipped_words.data(), flipped_words.size(),
|
||||||
@ -486,27 +477,27 @@ TEST_F(BinaryParseTest, EarlyReturnWithTwoPassingCallbacks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BinaryParseTest, InstructionWithStringOperand) {
|
TEST_F(BinaryParseTest, InstructionWithStringOperand) {
|
||||||
const std::string str =
|
for (bool endian_swap : kSwapEndians) {
|
||||||
"the future is already here, it's just not evenly distributed";
|
const std::string str =
|
||||||
const auto str_words = MakeVector(str);
|
"the future is already here, it's just not evenly distributed";
|
||||||
const auto instruction = MakeInstruction(SpvOpName, {99}, str_words);
|
const auto str_words = MakeVector(str);
|
||||||
const auto words = Concatenate({ExpectedHeaderForBound(100), instruction});
|
const auto instruction = MakeInstruction(SpvOpName, {99}, str_words);
|
||||||
InSequence calls_expected_in_specific_order;
|
const auto words = Concatenate({ExpectedHeaderForBound(100), instruction});
|
||||||
EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS));
|
InSequence calls_expected_in_specific_order;
|
||||||
const auto operands = std::vector<spv_parsed_operand_t>{
|
EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS));
|
||||||
MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID),
|
const auto operands = std::vector<spv_parsed_operand_t>{
|
||||||
MakeLiteralStringOperand(2, static_cast<uint16_t>(str_words.size()))};
|
MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID),
|
||||||
EXPECT_CALL(client_,
|
MakeLiteralStringOperand(2, static_cast<uint16_t>(str_words.size()))};
|
||||||
Instruction(ParsedInstruction(spv_parsed_instruction_t{
|
EXPECT_CALL(client_, Instruction(ParsedInstruction(spv_parsed_instruction_t{
|
||||||
instruction.data(), static_cast<uint16_t>(instruction.size()),
|
instruction.data(),
|
||||||
SpvOpName, SPV_EXT_INST_TYPE_NONE, 0 /*type id*/,
|
static_cast<uint16_t>(instruction.size()),
|
||||||
0 /* No result id for OpName*/, operands.data(),
|
SpvOpName, SPV_EXT_INST_TYPE_NONE, 0 /*type id*/,
|
||||||
static_cast<uint16_t>(operands.size())})))
|
0 /* No result id for OpName*/, operands.data(),
|
||||||
.WillOnce(Return(SPV_SUCCESS));
|
static_cast<uint16_t>(operands.size())})))
|
||||||
// Since we are actually checking the output, don't test the
|
.WillOnce(Return(SPV_SUCCESS));
|
||||||
// endian-swapped version.
|
Parse(words, SPV_SUCCESS, endian_swap);
|
||||||
Parse(words, SPV_SUCCESS, false);
|
EXPECT_EQ(nullptr, diagnostic_);
|
||||||
EXPECT_EQ(nullptr, diagnostic_);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for non-zero values for the result_id and ext_inst_type members
|
// Checks for non-zero values for the result_id and ext_inst_type members
|
||||||
|
@ -27,8 +27,15 @@ using ::testing::Eq;
|
|||||||
using RoundTripLiteralsTest =
|
using RoundTripLiteralsTest =
|
||||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
|
spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
|
||||||
|
|
||||||
|
static const bool kSwapEndians[] = {false, true};
|
||||||
|
|
||||||
TEST_P(RoundTripLiteralsTest, Sample) {
|
TEST_P(RoundTripLiteralsTest, Sample) {
|
||||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(GetParam()), Eq(GetParam()));
|
for (bool endian_swap : kSwapEndians) {
|
||||||
|
EXPECT_THAT(
|
||||||
|
EncodeAndDecodeSuccessfully(GetParam(), SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||||
|
SPV_ENV_UNIVERSAL_1_0, endian_swap),
|
||||||
|
Eq(GetParam()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -58,8 +65,12 @@ using RoundTripSpecialCaseLiteralsTest = spvtest::TextToBinaryTestBase<
|
|||||||
// Test case where the generated disassembly is not the same as the
|
// Test case where the generated disassembly is not the same as the
|
||||||
// assembly passed in.
|
// assembly passed in.
|
||||||
TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) {
|
TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) {
|
||||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam())),
|
for (bool endian_swap : kSwapEndians) {
|
||||||
Eq(std::get<1>(GetParam())));
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam()),
|
||||||
|
SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||||
|
SPV_ENV_UNIVERSAL_1_0, endian_swap),
|
||||||
|
Eq(std::get<1>(GetParam())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -62,12 +62,6 @@ TEST(InstructionTest, CreateWithOpcodeAndNoOperands) {
|
|||||||
EXPECT_EQ(inst.end(), inst.begin());
|
EXPECT_EQ(inst.end(), inst.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(InstructionTest, OperandAsCString) {
|
|
||||||
Operand::OperandData abcde{0x64636261, 0x65};
|
|
||||||
Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
|
|
||||||
EXPECT_STREQ("abcde", operand.AsCString());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(InstructionTest, OperandAsString) {
|
TEST(InstructionTest, OperandAsString) {
|
||||||
Operand::OperandData abcde{0x64636261, 0x65};
|
Operand::OperandData abcde{0x64636261, 0x65};
|
||||||
Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
|
Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#ifndef TEST_TEST_FIXTURE_H_
|
#ifndef TEST_TEST_FIXTURE_H_
|
||||||
#define TEST_TEST_FIXTURE_H_
|
#define TEST_TEST_FIXTURE_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -91,12 +92,26 @@ class TextToBinaryTestBase : public T {
|
|||||||
return diagnostic->error;
|
return diagnostic->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Potentially flip the words in the binary representation to the other
|
||||||
|
// endianness
|
||||||
|
template <class It>
|
||||||
|
void MaybeFlipWords(bool flip_words, It begin, It end) {
|
||||||
|
SCOPED_TRACE(flip_words ? "Flipped Endianness" : "Normal Endianness");
|
||||||
|
if (flip_words) {
|
||||||
|
std::transform(begin, end, begin, [](const uint32_t raw_word) {
|
||||||
|
return spvFixWord(raw_word, I32_ENDIAN_HOST == I32_ENDIAN_BIG
|
||||||
|
? SPV_ENDIANNESS_LITTLE
|
||||||
|
: SPV_ENDIANNESS_BIG);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Encodes SPIR-V text into binary and then decodes the binary using
|
// Encodes SPIR-V text into binary and then decodes the binary using
|
||||||
// given options. Returns the decoded text.
|
// given options. Returns the decoded text.
|
||||||
std::string EncodeAndDecodeSuccessfully(
|
std::string EncodeAndDecodeSuccessfully(
|
||||||
const std::string& txt,
|
const std::string& txt,
|
||||||
uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
|
uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
|
spv_target_env env = SPV_ENV_UNIVERSAL_1_0, bool flip_words = false) {
|
||||||
DestroyBinary();
|
DestroyBinary();
|
||||||
DestroyDiagnostic();
|
DestroyDiagnostic();
|
||||||
ScopedContext context(env);
|
ScopedContext context(env);
|
||||||
@ -110,6 +125,8 @@ class TextToBinaryTestBase : public T {
|
|||||||
EXPECT_EQ(SPV_SUCCESS, error);
|
EXPECT_EQ(SPV_SUCCESS, error);
|
||||||
if (!binary) return "";
|
if (!binary) return "";
|
||||||
|
|
||||||
|
MaybeFlipWords(flip_words, binary->code, binary->code + binary->wordCount);
|
||||||
|
|
||||||
spv_text decoded_text;
|
spv_text decoded_text;
|
||||||
error = spvBinaryToText(context.context, binary->code, binary->wordCount,
|
error = spvBinaryToText(context.context, binary->code, binary->wordCount,
|
||||||
disassemble_options, &decoded_text, &diagnostic);
|
disassemble_options, &decoded_text, &diagnostic);
|
||||||
|
Loading…
Reference in New Issue
Block a user