diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index d14a7da24..fee17688d 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2021.5-dev", "SPIRV-Tools v2021.5-dev 4581f14cd481bad1e0d6292f0dd0a6e298c2ee18" +"v2022.2-dev", "SPIRV-Tools v2022.2-dev 2e9ea79f27f42b1ea49e66ce7ba0a5c1ab75ea81" diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h index 2c66ae998..811cb06a9 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.h +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.h @@ -483,6 +483,7 @@ SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString(void); // SPV_ENV_VULKAN_1_1 -> SPIR-V 1.3 // SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4 // SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5 +// SPV_ENV_VULKAN_1_3 -> SPIR-V 1.6 // Consult the description of API entry points for specific rules. typedef enum { SPV_ENV_UNIVERSAL_1_0, // SPIR-V 1.0 latest revision, no other restrictions. @@ -519,7 +520,9 @@ typedef enum { SPV_ENV_VULKAN_1_2, // Vulkan 1.2 latest revision. SPV_ENV_UNIVERSAL_1_6, // SPIR-V 1.6 latest revision, no other restrictions. - SPV_ENV_MAX // Keep this as the last enum value. + SPV_ENV_VULKAN_1_3, // Vulkan 1.3 latest revision. + + SPV_ENV_MAX // Keep this as the last enum value. } spv_target_env; // SPIR-V Validator can be parameterized with the following Universal Limits. @@ -558,7 +561,7 @@ SPIRV_TOOLS_EXPORT bool spvParseVulkanEnv(uint32_t vulkan_ver, // Creates a context object for most of the SPIRV-Tools API. // Returns null if env is invalid. // -// See specific API calls for how the target environment is interpeted +// See specific API calls for how the target environment is interpreted // (particularly assembly and validation). SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env); @@ -610,7 +613,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer( // set that option. // 2) Pointers that are pass as parameters to function calls do not have to // match the storage class of the formal parameter. -// 3) Pointers that are actaul parameters on function calls do not have to point +// 3) Pointers that are actual parameters on function calls do not have to point // to the same type pointed as the formal parameter. The types just need to // logically match. // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant @@ -636,7 +639,7 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout( // Records whether the validator should use "scalar" block layout rules. // Scalar layout rules are more permissive than relaxed block layout. // -// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is +// See Vulkan extension VK_EXT_scalar_block_layout. The scalar alignment is // defined as follows: // - scalar alignment of a scalar is the scalar size // - scalar alignment of a vector is the scalar alignment of its component diff --git a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp index 8dfb46b77..25eb8a1dc 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/libspirv.hpp @@ -36,7 +36,7 @@ class Context { public: // Constructs a context targeting the given environment |env|. // - // See specific API calls for how the target environment is interpeted + // See specific API calls for how the target environment is interpreted // (particularly assembly and validation). // // The constructed instance will have an empty message consumer, which just @@ -139,7 +139,7 @@ class ValidatorOptions { // set that option. // 2) Pointers that are pass as parameters to function calls do not have to // match the storage class of the formal parameter. - // 3) Pointers that are actaul parameters on function calls do not have to + // 3) Pointers that are actual parameters on function calls do not have to // point to the same type pointed as the formal parameter. The types just // need to logically match. // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index 5d173c111..fdb2e648f 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -43,7 +43,7 @@ class Optimizer { // consumed by the RegisterPass() method. Tokens are one-time objects that // only support move; copying is not allowed. struct PassToken { - struct Impl; // Opaque struct for holding inernal data. + struct Impl; // Opaque struct for holding internal data. PassToken(std::unique_ptr); @@ -227,7 +227,7 @@ Optimizer::PassToken CreateNullPass(); // Creates a strip-debug-info pass. // A strip-debug-info pass removes all debug instructions (as documented in -// Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized. +// Section 3.42.2 of the SPIR-V spec) of the SPIR-V module to be optimized. Optimizer::PassToken CreateStripDebugInfoPass(); // [Deprecated] This will create a strip-nonsemantic-info pass. See below. @@ -296,11 +296,11 @@ Optimizer::PassToken CreateFreezeSpecConstantValuePass(); // and can be changed in future. A spec constant is foldable if all of its // value(s) can be determined from the module. E.g., an integer spec constant // defined with OpSpecConstantOp instruction can be folded if its value won't -// change later. This pass will replace the original OpSpecContantOp instruction -// with an OpConstant instruction. When folding composite spec constants, -// new instructions may be inserted to define the components of the composite -// constant first, then the original spec constants will be replaced by -// OpConstantComposite instructions. +// change later. This pass will replace the original OpSpecConstantOp +// instruction with an OpConstant instruction. When folding composite spec +// constants, new instructions may be inserted to define the components of the +// composite constant first, then the original spec constants will be replaced +// by OpConstantComposite instructions. // // There are some operations not supported yet: // OpSConvert, OpFConvert, OpQuantizeToF16 and @@ -326,7 +326,7 @@ Optimizer::PassToken CreateUnifyConstantPass(); // Creates a eliminate-dead-constant pass. // A eliminate-dead-constant pass removes dead constants, including normal -// contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or +// constants defined by OpConstant, OpConstantComposite, OpConstantTrue, or // OpConstantFalse and spec constants defined by OpSpecConstant, // OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or // OpSpecConstantOp. @@ -390,7 +390,7 @@ Optimizer::PassToken CreateInlineOpaquePass(); // Only modules with relaxed logical addressing (see opt/instruction.h) are // currently processed. // -// This pass is most effective if preceeded by Inlining and +// This pass is most effective if preceded by Inlining and // LocalAccessChainConvert. This pass will reduce the work needed to be done // by LocalSingleStoreElim and LocalMultiStoreElim. // @@ -408,7 +408,7 @@ Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass(); // Note that some branches and blocks may be left to avoid creating invalid // control flow. Improving this is left to future work. // -// This pass is most effective when preceeded by passes which eliminate +// This pass is most effective when preceded by passes which eliminate // local loads and stores, effectively propagating constant values where // possible. Optimizer::PassToken CreateDeadBranchElimPass(); @@ -425,7 +425,7 @@ Optimizer::PassToken CreateDeadBranchElimPass(); // are currently processed. Currently modules with any extensions enabled are // not processed. This is left for future work. // -// This pass is most effective if preceeded by Inlining and +// This pass is most effective if preceded by Inlining and // LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim // will reduce the work that this pass has to do. Optimizer::PassToken CreateLocalMultiStoreElimPass(); @@ -630,7 +630,7 @@ Optimizer::PassToken CreateRedundancyEliminationPass(); Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit = 100); // Create a private to local pass. -// This pass looks for variables delcared in the private storage class that are +// This pass looks for variables declared in the private storage class that are // used in only one function. Those variables are moved to the function storage // class in the function that they are used. Optimizer::PassToken CreatePrivateToLocalPass(); @@ -835,6 +835,19 @@ Optimizer::PassToken CreateFixStorageClassPass(); // inclusive. Optimizer::PassToken CreateGraphicsRobustAccessPass(); +// Create a pass to spread Volatile semantics to variables with SMIDNV, +// WarpIDNV, SubgroupSize, SubgroupLocalInvocationId, SubgroupEqMask, +// SubgroupGeMask, SubgroupGtMask, SubgroupLeMask, or SubgroupLtMask BuiltIn +// decorations or OpLoad for them when the shader model is the ray generation, +// closest hit, miss, intersection, or callable. This pass can be used for +// VUID-StandaloneSpirv-VulkanMemoryModel-04678 and +// VUID-StandaloneSpirv-VulkanMemoryModel-04679 (See "Standalone SPIR-V +// Validation" section of Vulkan spec "Appendix A: Vulkan Environment for +// SPIR-V"). When the SPIR-V version is 1.6 or above, the pass also spreads +// the Volatile semantics to a variable with HelperInvocation BuiltIn decoration +// in the fragement shader. +Optimizer::PassToken CreateSpreadVolatileSemanticsPass(); + // Create a pass to replace a descriptor access using variable index. // This pass replaces every access using a variable index to array variable // |desc| that has a DescriptorSet and Binding decorations with a constant diff --git a/3rdparty/spirv-tools/source/binary.cpp b/3rdparty/spirv-tools/source/binary.cpp index bbaa2c2c7..24d32f8c4 100644 --- a/3rdparty/spirv-tools/source/binary.cpp +++ b/3rdparty/spirv-tools/source/binary.cpp @@ -215,7 +215,7 @@ class Parser { size_t word_index; // The current position in words. size_t instruction_count; // The count of processed instructions spv_endianness_t endian; // The endianness of the binary. - // Is the SPIR-V binary in a different endiannes from the host native + // Is the SPIR-V binary in a different endianness from the host native // endianness? bool requires_endian_conversion; diff --git a/3rdparty/spirv-tools/source/ext_inst.cpp b/3rdparty/spirv-tools/source/ext_inst.cpp index 37b423ee4..4e2795453 100644 --- a/3rdparty/spirv-tools/source/ext_inst.cpp +++ b/3rdparty/spirv-tools/source/ext_inst.cpp @@ -97,6 +97,7 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable, case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: *pExtInstTable = &kTable_1_0; return SPV_SUCCESS; default: diff --git a/3rdparty/spirv-tools/source/ext_inst.h b/3rdparty/spirv-tools/source/ext_inst.h index aff6e308c..4027f4c3c 100644 --- a/3rdparty/spirv-tools/source/ext_inst.h +++ b/3rdparty/spirv-tools/source/ext_inst.h @@ -27,7 +27,7 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type); // Returns true if the extended instruction set is debug info bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type); -// Finds the named extented instruction of the given type in the given extended +// Finds the named extended instruction of the given type in the given extended // instruction table. On success, returns SPV_SUCCESS and writes a handle of // the instruction entry into *entry. spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table, @@ -35,7 +35,7 @@ spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table, const char* name, spv_ext_inst_desc* entry); -// Finds the extented instruction of the given type in the given extended +// Finds the extended instruction of the given type in the given extended // instruction table by value. On success, returns SPV_SUCCESS and writes a // handle of the instruction entry into *entry. spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table, diff --git a/3rdparty/spirv-tools/source/link/linker.cpp b/3rdparty/spirv-tools/source/link/linker.cpp index 21cada709..76ce775d5 100644 --- a/3rdparty/spirv-tools/source/link/linker.cpp +++ b/3rdparty/spirv-tools/source/link/linker.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -87,10 +88,6 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer, // // |header| should not be null, |modules| should not be empty and pointers // should be non-null. |max_id_bound| should be strictly greater than 0. -// -// TODO(pierremoreau): What to do when binaries use different versions of -// SPIR-V? For now, use the max of all versions found in -// the input modules. spv_result_t GenerateHeader(const MessageConsumer& consumer, const std::vector& modules, uint32_t max_id_bound, opt::ModuleHeader* header); @@ -131,7 +128,7 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, // Remove linkage specific instructions, such as prototypes of imported // functions, declarations of imported variables, import (and export if -// necessary) linkage attribtes. +// necessary) linkage attributes. // // |linked_context| and |decoration_manager| should not be null, and the // 'RemoveDuplicatePass' should be run first. @@ -149,6 +146,15 @@ spv_result_t RemoveLinkageSpecificInstructions( spv_result_t VerifyIds(const MessageConsumer& consumer, opt::IRContext* linked_context); +// Verify that the universal limits are not crossed, and warn the user +// otherwise. +// +// TODO(pierremoreau): +// - Verify against the limits of the environment (e.g. Vulkan limits if +// consuming vulkan1.x) +spv_result_t VerifyLimits(const MessageConsumer& consumer, + const opt::IRContext& linked_context); + spv_result_t ShiftIdsInModules(const MessageConsumer& consumer, std::vector* modules, uint32_t* max_id_bound) { @@ -164,29 +170,31 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer, return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA) << "|max_id_bound| of ShiftIdsInModules should not be null."; - uint32_t id_bound = modules->front()->IdBound() - 1u; + const size_t id_bound = + std::accumulate(modules->begin(), modules->end(), static_cast(1), + [](const size_t& accumulation, opt::Module* module) { + return accumulation + module->IdBound() - 1u; + }); + if (id_bound > std::numeric_limits::max()) + return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA) + << "Too many IDs (" << id_bound + << "): combining all modules would overflow the 32-bit word of the " + "SPIR-V header."; + + *max_id_bound = static_cast(id_bound); + + uint32_t id_offset = modules->front()->IdBound() - 1u; for (auto module_iter = modules->begin() + 1; module_iter != modules->end(); ++module_iter) { Module* module = *module_iter; - module->ForEachInst([&id_bound](Instruction* insn) { - insn->ForEachId([&id_bound](uint32_t* id) { *id += id_bound; }); + module->ForEachInst([&id_offset](Instruction* insn) { + insn->ForEachId([&id_offset](uint32_t* id) { *id += id_offset; }); }); - id_bound += module->IdBound() - 1u; - if (id_bound > 0x3FFFFF) - return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID) - << "The limit of IDs, 4194303, was exceeded:" - << " " << id_bound << " is the current ID bound."; + id_offset += module->IdBound() - 1u; // Invalidate the DefUseManager module->context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse); } - ++id_bound; - if (id_bound > 0x3FFFFF) - return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_ID) - << "The limit of IDs, 4194303, was exceeded:" - << " " << id_bound << " is the current ID bound."; - - *max_id_bound = id_bound; return SPV_SUCCESS; } @@ -203,12 +211,22 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer, return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA) << "|max_id_bound| of GenerateHeader should not be null."; - uint32_t version = 0u; - for (const auto& module : modules) - version = std::max(version, module->version()); + const uint32_t linked_version = modules.front()->version(); + for (std::size_t i = 1; i < modules.size(); ++i) { + const uint32_t module_version = modules[i]->version(); + if (module_version != linked_version) + return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL) + << "Conflicting SPIR-V versions: " + << SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(linked_version) + << " (input modules 1 through " << i << ") vs " + << SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(module_version) + << " (input module " << (i + 1) << ")."; + } header->magic_number = SpvMagicNumber; - header->version = version; + header->version = linked_version; header->generator = SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_LINKER, 0); header->bound = max_id_bound; header->schema = 0u; @@ -244,44 +262,55 @@ spv_result_t MergeModules(const MessageConsumer& consumer, linked_module->AddExtInstImport( std::unique_ptr(inst.Clone(linked_context))); - do { - const Instruction* memory_model_inst = input_modules[0]->GetMemoryModel(); - if (memory_model_inst == nullptr) break; + const Instruction* linked_memory_model_inst = + input_modules.front()->GetMemoryModel(); + if (linked_memory_model_inst == nullptr) { + return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) + << "Input module 1 is lacking an OpMemoryModel instruction."; + } + const uint32_t linked_addressing_model = + linked_memory_model_inst->GetSingleWordOperand(0u); + const uint32_t linked_memory_model = + linked_memory_model_inst->GetSingleWordOperand(1u); - uint32_t addressing_model = memory_model_inst->GetSingleWordOperand(0u); - uint32_t memory_model = memory_model_inst->GetSingleWordOperand(1u); - for (const auto& module : input_modules) { - memory_model_inst = module->GetMemoryModel(); - if (memory_model_inst == nullptr) continue; + for (std::size_t i = 1; i < input_modules.size(); ++i) { + const Module* module = input_modules[i]; + const Instruction* memory_model_inst = module->GetMemoryModel(); + if (memory_model_inst == nullptr) + return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) + << "Input module " << (i + 1) + << " is lacking an OpMemoryModel instruction."; - if (addressing_model != memory_model_inst->GetSingleWordOperand(0u)) { - spv_operand_desc initial_desc = nullptr, current_desc = nullptr; - grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL, - addressing_model, &initial_desc); - grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL, - memory_model_inst->GetSingleWordOperand(0u), - ¤t_desc); - return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL) - << "Conflicting addressing models: " << initial_desc->name - << " vs " << current_desc->name << "."; - } - if (memory_model != memory_model_inst->GetSingleWordOperand(1u)) { - spv_operand_desc initial_desc = nullptr, current_desc = nullptr; - grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, memory_model, - &initial_desc); - grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, - memory_model_inst->GetSingleWordOperand(1u), - ¤t_desc); - return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL) - << "Conflicting memory models: " << initial_desc->name << " vs " - << current_desc->name << "."; - } + const uint32_t module_addressing_model = + memory_model_inst->GetSingleWordOperand(0u); + if (module_addressing_model != linked_addressing_model) { + spv_operand_desc linked_desc = nullptr, module_desc = nullptr; + grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL, + linked_addressing_model, &linked_desc); + grammar.lookupOperand(SPV_OPERAND_TYPE_ADDRESSING_MODEL, + module_addressing_model, &module_desc); + return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL) + << "Conflicting addressing models: " << linked_desc->name + << " (input modules 1 through " << i << ") vs " + << module_desc->name << " (input module " << (i + 1) << ")."; } - if (memory_model_inst != nullptr) - linked_module->SetMemoryModel(std::unique_ptr( - memory_model_inst->Clone(linked_context))); - } while (false); + const uint32_t module_memory_model = + memory_model_inst->GetSingleWordOperand(1u); + if (module_memory_model != linked_memory_model) { + spv_operand_desc linked_desc = nullptr, module_desc = nullptr; + grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, linked_memory_model, + &linked_desc); + grammar.lookupOperand(SPV_OPERAND_TYPE_MEMORY_MODEL, module_memory_model, + &module_desc); + return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL) + << "Conflicting memory models: " << linked_desc->name + << " (input modules 1 through " << i << ") vs " + << module_desc->name << " (input module " << (i + 1) << ")."; + } + } + linked_module->SetMemoryModel(std::unique_ptr( + linked_memory_model_inst->Clone(linked_context))); std::vector> entry_points; for (const auto& module : input_modules) @@ -332,7 +361,7 @@ spv_result_t MergeModules(const MessageConsumer& consumer, // If the generated module uses SPIR-V 1.1 or higher, add an // OpModuleProcessed instruction about the linking step. - if (linked_module->version() >= 0x10100) { + if (linked_module->version() >= SPV_SPIRV_VERSION_WORD(1, 1)) { const std::string processed_string("Linked by SPIR-V Tools Linker"); std::vector processed_words = spvtools::utils::MakeVector(processed_string); @@ -349,18 +378,12 @@ spv_result_t MergeModules(const MessageConsumer& consumer, // TODO(pierremoreau): Since the modules have not been validate, should we // expect SpvStorageClassFunction variables outside // functions? - uint32_t num_global_values = 0u; for (const auto& module : input_modules) { for (const auto& inst : module->types_values()) { linked_module->AddType( std::unique_ptr(inst.Clone(linked_context))); - num_global_values += inst.opcode() == SpvOpVariable; } } - if (num_global_values > 0xFFFF) - return DiagnosticStream(position, consumer, "", SPV_ERROR_INTERNAL) - << "The limit of global values, 65535, was exceeded;" - << " " << num_global_values << " global values were found."; // Process functions and their basic blocks for (const auto& module : input_modules) { @@ -632,6 +655,34 @@ spv_result_t VerifyIds(const MessageConsumer& consumer, return SPV_SUCCESS; } +spv_result_t VerifyLimits(const MessageConsumer& consumer, + const opt::IRContext& linked_context) { + spv_position_t position = {}; + + const uint32_t max_id_bound = linked_context.module()->id_bound(); + if (max_id_bound >= SPV_LIMIT_RESULT_ID_BOUND) + DiagnosticStream({0u, 0u, 4u}, consumer, "", SPV_WARNING) + << "The minimum limit of IDs, " << (SPV_LIMIT_RESULT_ID_BOUND - 1) + << ", was exceeded:" + << " " << max_id_bound << " is the current ID bound.\n" + << "The resulting module might not be supported by all " + "implementations."; + + size_t num_global_values = 0u; + for (const auto& inst : linked_context.module()->types_values()) { + num_global_values += inst.opcode() == SpvOpVariable; + } + if (num_global_values >= SPV_LIMIT_GLOBAL_VARIABLES_MAX) + DiagnosticStream(position, consumer, "", SPV_WARNING) + << "The minimum limit of global values, " + << (SPV_LIMIT_GLOBAL_VARIABLES_MAX - 1) << ", was exceeded;" + << " " << num_global_values << " global values were found.\n" + << "The resulting module might not be supported by all " + "implementations."; + + return SPV_SUCCESS; +} + } // namespace spv_result_t Link(const Context& context, @@ -756,7 +807,11 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, pass_res = manager.Run(&linked_context); if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 11: Output the module + // Phase 11: Warn if SPIR-V limits were exceeded + res = VerifyLimits(consumer, linked_context); + if (res != SPV_SUCCESS) return res; + + // Phase 12: Output the module linked_context.module()->ToBinary(linked_binary, true); return SPV_SUCCESS; diff --git a/3rdparty/spirv-tools/source/opcode.cpp b/3rdparty/spirv-tools/source/opcode.cpp index c96cde8d6..88085df7c 100644 --- a/3rdparty/spirv-tools/source/opcode.cpp +++ b/3rdparty/spirv-tools/source/opcode.cpp @@ -40,12 +40,12 @@ struct OpcodeDescPtrLen { static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries), kOpcodeTableEntries}; -// Represents a vendor tool entry in the SPIR-V XML Regsitry. +// Represents a vendor tool entry in the SPIR-V XML Registry. struct VendorTool { uint32_t value; const char* vendor; const char* tool; // Might be empty string. - const char* vendor_tool; // Combiantion of vendor and tool. + const char* vendor_tool; // Combination of vendor and tool. }; const VendorTool vendor_tools[] = { diff --git a/3rdparty/spirv-tools/source/opt/amd_ext_to_khr.h b/3rdparty/spirv-tools/source/opt/amd_ext_to_khr.h index fd3dab4e7..6a39d953a 100644 --- a/3rdparty/spirv-tools/source/opt/amd_ext_to_khr.h +++ b/3rdparty/spirv-tools/source/opt/amd_ext_to_khr.h @@ -23,7 +23,7 @@ namespace spvtools { namespace opt { // Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, and -// VK_AMD_shader_trinary_minmax with equivalant code using core instructions and +// VK_AMD_shader_trinary_minmax with equivalent code using core instructions and // capabilities. class AmdExtensionToKhrPass : public Pass { public: diff --git a/3rdparty/spirv-tools/source/opt/basic_block.h b/3rdparty/spirv-tools/source/opt/basic_block.h index 6741a50f2..dd3b2e287 100644 --- a/3rdparty/spirv-tools/source/opt/basic_block.h +++ b/3rdparty/spirv-tools/source/opt/basic_block.h @@ -83,7 +83,7 @@ class BasicBlock { const Instruction* GetMergeInst() const; Instruction* GetMergeInst(); - // Returns the OpLoopMerge instruciton in this basic block, if it exists. + // Returns the OpLoopMerge instruction in this basic block, if it exists. // Otherwise return null. May be used whenever tail() can be used. const Instruction* GetLoopMergeInst() const; Instruction* GetLoopMergeInst(); diff --git a/3rdparty/spirv-tools/source/opt/cfg.h b/3rdparty/spirv-tools/source/opt/cfg.h index f28068229..33412f180 100644 --- a/3rdparty/spirv-tools/source/opt/cfg.h +++ b/3rdparty/spirv-tools/source/opt/cfg.h @@ -30,7 +30,7 @@ class CFG { public: explicit CFG(Module* module); - // Return the list of predecesors for basic block with label |blkid|. + // Return the list of predecessors for basic block with label |blkid|. // TODO(dnovillo): Move this to BasicBlock. const std::vector& preds(uint32_t blk_id) const { assert(label2preds_.count(blk_id)); diff --git a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp index a9830a25b..249e11e56 100644 --- a/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/const_folding_rules.cpp @@ -550,7 +550,7 @@ ConstantFoldingRule FoldFAdd() { return FoldFPBinaryOp(FOLD_FPARITH_OP(+)); } ConstantFoldingRule FoldFMul() { return FoldFPBinaryOp(FOLD_FPARITH_OP(*)); } // Returns the constant that results from evaluating |numerator| / 0.0. Returns -// |nullptr| if the result could not be evalutated. +// |nullptr| if the result could not be evaluated. const analysis::Constant* FoldFPScalarDivideByZero( const analysis::Type* result_type, const analysis::Constant* numerator, analysis::ConstantManager* const_mgr) { @@ -1346,7 +1346,7 @@ void ConstantFoldingRules::AddFoldingRules() { FoldFPUnaryOp(FoldFTranscendentalUnary(std::log))); #ifdef __ANDROID__ - // Android NDK r15c tageting ABI 15 doesn't have full support for C++11 + // Android NDK r15c targeting ABI 15 doesn't have full support for C++11 // (no std::exp2/log2). ::exp2 is available from C99 but ::log2 isn't // available up until ABI 18 so we use a shim auto log2_shim = [](double v) -> double { return log(v) / log(2.0); }; diff --git a/3rdparty/spirv-tools/source/opt/constants.h b/3rdparty/spirv-tools/source/opt/constants.h index e25856bb6..d496d073a 100644 --- a/3rdparty/spirv-tools/source/opt/constants.h +++ b/3rdparty/spirv-tools/source/opt/constants.h @@ -541,7 +541,7 @@ class ConstantManager { // instruction at the end of the current module's types section. // // |type_id| is an optional argument for disambiguating equivalent types. If - // |type_id| is specified, the contant returned will have that type id. + // |type_id| is specified, the constant returned will have that type id. Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0, Module::inst_iterator* pos = nullptr); diff --git a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp index b127eabe9..4086e31ac 100644 --- a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp @@ -181,7 +181,7 @@ bool ConvertToHalfPass::ProcessPhi(Instruction* inst, uint32_t from_width, uint32_t to_width) { // Add converts of any float operands to to_width if they are of from_width. // If converting to 16, change type of phi to float16 equivalent and remember - // result id. Converts need to be added to preceeding blocks. + // result id. Converts need to be added to preceding blocks. uint32_t ocnt = 0; uint32_t* prev_idp; bool modified = false; diff --git a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h index c350bb2f0..198bad2dc 100644 --- a/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h +++ b/3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.h @@ -158,7 +158,7 @@ class DeadBranchElimPass : public MemPass { uint32_t cont_id, uint32_t header_id, uint32_t merge_id, std::unordered_set* blocks_with_back_edges); - // Returns true if there is a brach to the merge node of the selection + // Returns true if there is a branch to the merge node of the selection // construct |switch_header_id| that is inside a nested selection construct or // in the header of the nested selection construct. bool SwitchHasNestedBreak(uint32_t switch_header_id); diff --git a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp index 060e0d931..c1df6258b 100644 --- a/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/debug_info_manager.cpp @@ -149,7 +149,7 @@ void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id, // Create new constant directly into global value area, bypassing the // Constant manager. This is used when the DefUse or Constant managers // are invalid and cannot be regenerated due to the module being in an -// inconsistant state e.g. in the middle of significant modification +// inconsistent state e.g. in the middle of significant modification // such as inlining. Invalidate Constant and DefUse managers if used. uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) { uint32_t id = context->TakeNextId(); diff --git a/3rdparty/spirv-tools/source/opt/def_use_manager.h b/3rdparty/spirv-tools/source/opt/def_use_manager.h index d66575d31..a8dbbc60b 100644 --- a/3rdparty/spirv-tools/source/opt/def_use_manager.h +++ b/3rdparty/spirv-tools/source/opt/def_use_manager.h @@ -190,7 +190,7 @@ class DefUseManager { // Returns the annotation instrunctions which are a direct use of the given // |id|. This means when the decorations are applied through decoration // group(s), this function will just return the OpGroupDecorate - // instrcution(s) which refer to the given id as an operand. The OpDecorate + // instruction(s) which refer to the given id as an operand. The OpDecorate // instructions which decorate the decoration group will not be returned. std::vector GetAnnotations(uint32_t id) const; @@ -210,7 +210,7 @@ class DefUseManager { friend bool CompareAndPrintDifferences(const DefUseManager&, const DefUseManager&); - // If |inst| has not already been analysed, then analyses its defintion and + // If |inst| has not already been analysed, then analyses its definition and // uses. void UpdateDefUse(Instruction* inst); diff --git a/3rdparty/spirv-tools/source/opt/desc_sroa.cpp b/3rdparty/spirv-tools/source/opt/desc_sroa.cpp index 7263c1203..b130ca806 100644 --- a/3rdparty/spirv-tools/source/opt/desc_sroa.cpp +++ b/3rdparty/spirv-tools/source/opt/desc_sroa.cpp @@ -118,7 +118,7 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var, if (use->NumInOperands() == 2) { // We are not indexing into the replacement variable. We can replaces the - // access chain with the replacement varibale itself. + // access chain with the replacement variable itself. context()->ReplaceAllUsesWith(use->result_id(), replacement_var); context()->KillInst(use); return true; @@ -135,8 +135,8 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var, // Use the replacement variable as the base address. new_operands.push_back({SPV_OPERAND_TYPE_ID, {replacement_var}}); - // Drop the first index because it is consumed by the replacment, and copy the - // rest. + // Drop the first index because it is consumed by the replacement, and copy + // the rest. for (uint32_t i = 4; i < use->NumOperands(); i++) { new_operands.emplace_back(use->GetOperand(i)); } diff --git a/3rdparty/spirv-tools/source/opt/dominator_tree.cpp b/3rdparty/spirv-tools/source/opt/dominator_tree.cpp index 55287f444..d86de151e 100644 --- a/3rdparty/spirv-tools/source/opt/dominator_tree.cpp +++ b/3rdparty/spirv-tools/source/opt/dominator_tree.cpp @@ -48,7 +48,7 @@ namespace { // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode // SuccessorLambda - Lamdba matching the signature of 'const // std::vector*(const BBType *A)'. Will return a vector of the nodes -// succeding BasicBlock A. +// succeeding BasicBlock A. // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be // called on each node traversed AFTER their children. // PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be @@ -69,7 +69,7 @@ static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors, // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode // SuccessorLambda - Lamdba matching the signature of 'const // std::vector*(const BBType *A)'. Will return a vector of the nodes -// succeding BasicBlock A. +// succeeding BasicBlock A. // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be // called on each node traversed after their children. template diff --git a/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp b/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp index a24ba8f41..52aca5254 100644 --- a/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/eliminate_dead_members_pass.cpp @@ -38,7 +38,7 @@ Pass::Status EliminateDeadMembersPass::Process() { } void EliminateDeadMembersPass::FindLiveMembers() { - // Until we have implemented the rewritting of OpSpecConsantOp instructions, + // Until we have implemented the rewriting of OpSpecConsantOp instructions, // we have to mark them as fully used just to be safe. for (auto& inst : get_module()->types_values()) { if (inst.opcode() == SpvOpSpecConstantOp) { @@ -570,7 +570,7 @@ bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) { Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); switch (type_inst->opcode()) { case SpvOpTypeStruct: - // The type will have already been rewriten, so use the new member + // The type will have already been rewritten, so use the new member // index. type_id = type_inst->GetSingleWordInOperand(new_member_idx); break; diff --git a/3rdparty/spirv-tools/source/opt/fold.cpp b/3rdparty/spirv-tools/source/opt/fold.cpp index 6550fb4fd..b903da6a2 100644 --- a/3rdparty/spirv-tools/source/opt/fold.cpp +++ b/3rdparty/spirv-tools/source/opt/fold.cpp @@ -540,7 +540,7 @@ std::vector InstructionFolder::FoldVectors( // in 32-bit words here. The reason of not using FoldScalars() here // is that we do not create temporary null constants as components // when the vector operand is a NullConstant because Constant creation - // may need extra checks for the validity and that is not manageed in + // may need extra checks for the validity and that is not managed in // here. if (const analysis::ScalarConstant* scalar_component = vector_operand->GetComponents().at(d)->AsScalarConstant()) { diff --git a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp index 8ab717ea8..85f11fdea 100644 --- a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -115,7 +115,7 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp( Instruction* folded_inst = nullptr; assert(inst->GetInOperand(0).type == SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER && - "The first in-operand of OpSpecContantOp instruction must be of " + "The first in-operand of OpSpecConstantOp instruction must be of " "SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type"); switch (static_cast(inst->GetSingleWordInOperand(0))) { diff --git a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp index 336dcd83e..4652d72d5 100644 --- a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.cpp @@ -13,7 +13,7 @@ // limitations under the License. // This pass injects code in a graphics shader to implement guarantees -// satisfying Vulkan's robustBufferAcces rules. Robust access rules permit +// satisfying Vulkan's robustBufferAccess rules. Robust access rules permit // an out-of-bounds access to be redirected to an access of the same type // (load, store, etc.) but within the same root object. // @@ -74,7 +74,7 @@ // Pointers are always (correctly) typed and so the address and number of // consecutive locations are fully determined by the pointer. // -// - A pointer value orginates as one of few cases: +// - A pointer value originates as one of few cases: // // - OpVariable for an interface object or an array of them: image, // buffer (UBO or SSBO), sampler, sampled-image, push-constant, input @@ -958,7 +958,7 @@ spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer( constant_mgr->GetDefiningInstruction(component_0)->result_id(); // If the image is a cube array, then the last component of the queried - // size is the layer count. In the query, we have to accomodate folding + // size is the layer count. In the query, we have to accommodate folding // in the face index ranging from 0 through 5. The inclusive upper bound // on the third coordinate therefore is multiplied by 6. auto* query_size_including_faces = query_size; diff --git a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.h b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.h index 6fc692c13..8f4c9dc7d 100644 --- a/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.h +++ b/3rdparty/spirv-tools/source/opt/graphics_robust_access_pass.h @@ -111,7 +111,7 @@ class GraphicsRobustAccessPass : public Pass { Instruction* max, Instruction* where); // Returns a new instruction which evaluates to the length the runtime array - // referenced by the access chain at the specfied index. The instruction is + // referenced by the access chain at the specified index. The instruction is // inserted before the access chain instruction. Returns a null pointer in // some cases if assumptions are violated (rather than asserting out). opt::Instruction* MakeRuntimeArrayLengthInst(Instruction* access_chain, diff --git a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h index cd9618059..e6e6ef4f9 100644 --- a/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h +++ b/3rdparty/spirv-tools/source/opt/inst_bindless_check_pass.h @@ -147,11 +147,11 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder); // Clone original image computation starting at |image_id| into |builder|. - // This may generate more than one instruction if neccessary. + // This may generate more than one instruction if necessary. uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder); // Clone original original reference encapsulated by |ref| into |builder|. - // This may generate more than one instruction if neccessary. + // This may generate more than one instruction if necessary. uint32_t CloneOriginalReference(RefAnalysis* ref, InstructionBuilder* builder); diff --git a/3rdparty/spirv-tools/source/opt/instruction.h b/3rdparty/spirv-tools/source/opt/instruction.h index 57ee70734..f87f563a1 100644 --- a/3rdparty/spirv-tools/source/opt/instruction.h +++ b/3rdparty/spirv-tools/source/opt/instruction.h @@ -122,7 +122,7 @@ inline bool operator!=(const Operand& o1, const Operand& o2) { } // This structure is used to represent a DebugScope instruction from -// the OpenCL.100.DebugInfo extened instruction set. Note that we can +// the OpenCL.100.DebugInfo extended instruction set. Note that we can // ignore the result id of DebugScope instruction because it is not // used for anything. We do not keep it to reduce the size of // structure. diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.h b/3rdparty/spirv-tools/source/opt/instrument_pass.h index 12b939d4d..90c1dd47e 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.h +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.h @@ -50,7 +50,7 @@ // A validation pass may read or write multiple buffers. All such buffers // are located in a single debug descriptor set whose index is passed at the // creation of the instrumentation pass. The bindings of the buffers used by -// a validation pass are permanantly assigned and fixed and documented by +// a validation pass are permanently assigned and fixed and documented by // the kDebugOutput* static consts. namespace spvtools { @@ -179,8 +179,8 @@ class InstrumentPass : public Pass { // the error. Every stage will write a fixed number of words. Vertex shaders // will write the Vertex and Instance ID. Fragment shaders will write // FragCoord.xy. Compute shaders will write the GlobalInvocation ID. - // The tesselation eval shader will write the Primitive ID and TessCoords.uv. - // The tesselation control shader and geometry shader will write the + // The tessellation eval shader will write the Primitive ID and TessCoords.uv. + // The tessellation control shader and geometry shader will write the // Primitive ID and Invocation ID. // // The Validation Error Code specifies the exact error which has occurred. diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index 789184614..5b0beeb2a 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -106,7 +106,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { analyses_to_invalidate |= kAnalysisDebugInfo; } - // The dominator analysis hold the psuedo entry and exit nodes from the CFG. + // The dominator analysis hold the pseudo entry and exit nodes from the CFG. // Also if the CFG change the dominators many changed as well, so the // dominator analysis should be invalidated as well. if (analyses_to_invalidate & kAnalysisCFG) { diff --git a/3rdparty/spirv-tools/source/opt/ir_context.h b/3rdparty/spirv-tools/source/opt/ir_context.h index 7bef3054c..274dd14e2 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.h +++ b/3rdparty/spirv-tools/source/opt/ir_context.h @@ -302,7 +302,7 @@ class IRContext { } } - // Returns a pointer the decoration manager. If the decoration manger is + // Returns a pointer the decoration manager. If the decoration manager is // invalid, it is rebuilt first. analysis::DecorationManager* get_decoration_mgr() { if (!AreAnalysesValid(kAnalysisDecorations)) { @@ -385,7 +385,7 @@ class IRContext { // Deletes the instruction defining the given |id|. Returns true on // success, false if the given |id| is not defined at all. This method also - // erases the name, decorations, and defintion of |id|. + // erases the name, decorations, and definition of |id|. // // Pointers and iterators pointing to the deleted instructions become invalid. // However other pointers and iterators are still valid. @@ -802,7 +802,7 @@ class IRContext { // iterators to traverse instructions. std::unordered_map id_to_func_; - // A bitset indicating which analyes are currently valid. + // A bitset indicating which analyzes are currently valid. Analysis valid_analyses_; // Opcodes of shader capability core executable instructions diff --git a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h index 552062e52..a51660f10 100644 --- a/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h +++ b/3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h @@ -81,7 +81,7 @@ class LocalAccessChainConvertPass : public MemPass { std::vector* in_opnds); // Create a load/insert/store equivalent to a store of - // |valId| through (constant index) access chaing |ptrInst|. + // |valId| through (constant index) access chain |ptrInst|. // Append to |newInsts|. Returns true if successful. bool GenAccessChainStoreReplacement( const Instruction* ptrInst, uint32_t valId, diff --git a/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp b/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp index b5b563098..9bc495e51 100644 --- a/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_descriptor.cpp @@ -719,7 +719,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction, step_value = -step_value; } - // Find the inital value of the loop and make sure it is a constant integer. + // Find the initial value of the loop and make sure it is a constant integer. int64_t init_value = 0; if (!GetInductionInitValue(induction, &init_value)) return false; @@ -751,7 +751,7 @@ bool Loop::FindNumberOfIterations(const Instruction* induction, // We retrieve the number of iterations using the following formula, diff / // |step_value| where diff is calculated differently according to the // |condition| and uses the |condition_value| and |init_value|. If diff / -// |step_value| is NOT cleanly divisable then we add one to the sum. +// |step_value| is NOT cleanly divisible then we add one to the sum. int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value, int64_t init_value, int64_t step_value) const { int64_t diff = 0; @@ -795,7 +795,7 @@ int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value, // If the condition is not met to begin with the loop will never iterate. if (!(init_value >= condition_value)) return 0; - // We subract one to make it the same as SpvOpGreaterThan as it is + // We subtract one to make it the same as SpvOpGreaterThan as it is // functionally equivalent. diff = init_value - (condition_value - 1); diff --git a/3rdparty/spirv-tools/source/opt/loop_descriptor.h b/3rdparty/spirv-tools/source/opt/loop_descriptor.h index 4b4f8bc75..e88ff9363 100644 --- a/3rdparty/spirv-tools/source/opt/loop_descriptor.h +++ b/3rdparty/spirv-tools/source/opt/loop_descriptor.h @@ -395,7 +395,7 @@ class Loop { // Sets |merge| as the loop merge block. No checks are performed here. inline void SetMergeBlockImpl(BasicBlock* merge) { loop_merge_ = merge; } - // Each differnt loop |condition| affects how we calculate the number of + // Each different loop |condition| affects how we calculate the number of // iterations using the |condition_value|, |init_value|, and |step_values| of // the induction variable. This method will return the number of iterations in // a loop with those values for a given |condition|. diff --git a/3rdparty/spirv-tools/source/opt/loop_fission.cpp b/3rdparty/spirv-tools/source/opt/loop_fission.cpp index 0a4125dff..b4df8c621 100644 --- a/3rdparty/spirv-tools/source/opt/loop_fission.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_fission.cpp @@ -29,7 +29,7 @@ // 2 - For each loop in the list, group each instruction into a set of related // instructions by traversing each instructions users and operands recursively. // We stop if we encounter an instruction we have seen before or an instruction -// which we don't consider relevent (i.e OpLoopMerge). We then group these +// which we don't consider relevant (i.e OpLoopMerge). We then group these // groups into two different sets, one for the first loop and one for the // second. // diff --git a/3rdparty/spirv-tools/source/opt/loop_fission.h b/3rdparty/spirv-tools/source/opt/loop_fission.h index e7a59c185..9bc12c0fd 100644 --- a/3rdparty/spirv-tools/source/opt/loop_fission.h +++ b/3rdparty/spirv-tools/source/opt/loop_fission.h @@ -33,7 +33,7 @@ namespace opt { class LoopFissionPass : public Pass { public: - // Fuction used to determine if a given loop should be split. Takes register + // Function used to determine if a given loop should be split. Takes register // pressure region for that loop as a parameter and returns true if the loop // should be split. using FissionCriteriaFunction = diff --git a/3rdparty/spirv-tools/source/opt/loop_fusion.cpp b/3rdparty/spirv-tools/source/opt/loop_fusion.cpp index 07d171a0a..f3aab2837 100644 --- a/3rdparty/spirv-tools/source/opt/loop_fusion.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_fusion.cpp @@ -165,7 +165,7 @@ bool LoopFusion::AreCompatible() { // Check adjacency, |loop_0_| should come just before |loop_1_|. // There is always at least one block between loops, even if it's empty. - // We'll check at most 2 preceeding blocks. + // We'll check at most 2 preceding blocks. auto pre_header_1 = loop_1_->GetPreHeaderBlock(); @@ -712,7 +712,7 @@ void LoopFusion::Fuse() { ld->RemoveLoop(loop_1_); - // Kill unnessecary instructions and remove all empty blocks. + // Kill unnecessary instructions and remove all empty blocks. for (auto inst : instr_to_delete) { context_->KillInst(inst); } diff --git a/3rdparty/spirv-tools/source/opt/loop_fusion.h b/3rdparty/spirv-tools/source/opt/loop_fusion.h index d61d6783c..769da5f1a 100644 --- a/3rdparty/spirv-tools/source/opt/loop_fusion.h +++ b/3rdparty/spirv-tools/source/opt/loop_fusion.h @@ -40,7 +40,7 @@ class LoopFusion { // That means: // * they both have one induction variable // * they have the same upper and lower bounds - // - same inital value + // - same initial value // - same condition // * they have the same update step // * they are adjacent, with |loop_0| appearing before |loop_1| diff --git a/3rdparty/spirv-tools/source/opt/loop_fusion_pass.h b/3rdparty/spirv-tools/source/opt/loop_fusion_pass.h index 3a0be6000..9d5b7ccda 100644 --- a/3rdparty/spirv-tools/source/opt/loop_fusion_pass.h +++ b/3rdparty/spirv-tools/source/opt/loop_fusion_pass.h @@ -33,7 +33,7 @@ class LoopFusionPass : public Pass { // Processes the given |module|. Returns Status::Failure if errors occur when // processing. Returns the corresponding Status::Success if processing is - // succesful to indicate whether changes have been made to the modue. + // successful to indicate whether changes have been made to the module. Status Process() override; private: diff --git a/3rdparty/spirv-tools/source/opt/loop_peeling.h b/3rdparty/spirv-tools/source/opt/loop_peeling.h index 413f896f2..2a55fe44d 100644 --- a/3rdparty/spirv-tools/source/opt/loop_peeling.h +++ b/3rdparty/spirv-tools/source/opt/loop_peeling.h @@ -261,7 +261,7 @@ class LoopPeelingPass : public Pass { // Processes the given |module|. Returns Status::Failure if errors occur when // processing. Returns the corresponding Status::Success if processing is - // succesful to indicate whether changes have been made to the modue. + // successful to indicate whether changes have been made to the module. Pass::Status Process() override; private: diff --git a/3rdparty/spirv-tools/source/opt/loop_unroller.cpp b/3rdparty/spirv-tools/source/opt/loop_unroller.cpp index aff191feb..28ff07299 100644 --- a/3rdparty/spirv-tools/source/opt/loop_unroller.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_unroller.cpp @@ -163,7 +163,7 @@ struct LoopUnrollState { }; // This class implements the actual unrolling. It uses a LoopUnrollState to -// maintain the state of the unrolling inbetween steps. +// maintain the state of the unrolling in between steps. class LoopUnrollerUtilsImpl { public: using BasicBlockListTy = std::vector>; @@ -209,7 +209,7 @@ class LoopUnrollerUtilsImpl { // Add all blocks_to_add_ to function_ at the |insert_point|. void AddBlocksToFunction(const BasicBlock* insert_point); - // Duplicates the |old_loop|, cloning each body and remaping the ids without + // Duplicates the |old_loop|, cloning each body and remapping the ids without // removing instructions or changing relative structure. Result will be stored // in |new_loop|. void DuplicateLoop(Loop* old_loop, Loop* new_loop); @@ -241,7 +241,7 @@ class LoopUnrollerUtilsImpl { // Remap all the in |basic_block| to new IDs and keep the mapping of new ids // to old // ids. |loop| is used to identify special loop blocks (header, continue, - // ect). + // etc). void AssignNewResultIds(BasicBlock* basic_block); // Using the map built by AssignNewResultIds, replace the uses in |inst| @@ -320,7 +320,7 @@ class LoopUnrollerUtilsImpl { // and then be remapped at the end. std::vector loop_phi_instructions_; - // The number of loop iterations that the loop would preform pre-unroll. + // The number of loop iterations that the loop would perform pre-unroll. size_t number_of_loop_iterations_; // The amount that the loop steps each iteration. @@ -839,7 +839,7 @@ void LoopUnrollerUtilsImpl::DuplicateLoop(Loop* old_loop, Loop* new_loop) { new_loop->SetMergeBlock(new_merge); } -// Whenever the utility copies a block it stores it in a tempory buffer, this +// Whenever the utility copies a block it stores it in a temporary buffer, this // function adds the buffer into the Function. The blocks will be inserted // after the block |insert_point|. void LoopUnrollerUtilsImpl::AddBlocksToFunction( diff --git a/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.cpp b/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.cpp index d805ecf3c..1ee7e5e22 100644 --- a/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.cpp @@ -118,7 +118,7 @@ class LoopUnswitch { // Find a value that can be used to select the default path. // If none are possible, then it will just use 0. The value does not matter - // because this path will never be taken becaues the new switch outside of + // because this path will never be taken because the new switch outside of // the loop cannot select this path either. std::vector existing_values; for (uint32_t i = 2; i < switch_inst->NumInOperands(); i += 2) { diff --git a/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.h b/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.h index 3ecdd6116..4f7295d43 100644 --- a/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.h +++ b/3rdparty/spirv-tools/source/opt/loop_unswitch_pass.h @@ -30,7 +30,7 @@ class LoopUnswitchPass : public Pass { // Processes the given |module|. Returns Status::Failure if errors occur when // processing. Returns the corresponding Status::Success if processing is - // succesful to indicate whether changes have been made to the modue. + // successful to indicate whether changes have been made to the module. Pass::Status Process() override; private: diff --git a/3rdparty/spirv-tools/source/opt/loop_utils.h b/3rdparty/spirv-tools/source/opt/loop_utils.h index a4e61900b..70060fc4f 100644 --- a/3rdparty/spirv-tools/source/opt/loop_utils.h +++ b/3rdparty/spirv-tools/source/opt/loop_utils.h @@ -123,7 +123,7 @@ class LoopUtils { // Clone the |loop_| and make the new loop branch to the second loop on exit. Loop* CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result); - // Perfom a partial unroll of |loop| by given |factor|. This will copy the + // Perform a partial unroll of |loop| by given |factor|. This will copy the // body of the loop |factor| times. So a |factor| of one would give a new loop // with the original body plus one unrolled copy body. bool PartiallyUnroll(size_t factor); @@ -139,7 +139,7 @@ class LoopUtils { // 1. That the loop is in structured order. // 2. That the continue block is a branch to the header. // 3. That the only phi used in the loop is the induction variable. - // TODO(stephen@codeplay.com): This is a temporary mesure, after the loop is + // TODO(stephen@codeplay.com): This is a temporary measure, after the loop is // converted into LCSAA form and has a single entry and exit we can rewrite // the other phis. // 4. That this is an inner most loop, or that loops contained within this diff --git a/3rdparty/spirv-tools/source/opt/merge_return_pass.h b/3rdparty/spirv-tools/source/opt/merge_return_pass.h index 4096ce7dd..a35cf269f 100644 --- a/3rdparty/spirv-tools/source/opt/merge_return_pass.h +++ b/3rdparty/spirv-tools/source/opt/merge_return_pass.h @@ -247,7 +247,7 @@ class MergeReturnPass : public MemPass { // Add new phi nodes for any id that no longer dominate all of it uses. A phi // node is added to a block |bb| for an id if the id is defined between the - // original immediate dominator of |bb| and its new immidiate dominator. It + // original immediate dominator of |bb| and its new immediate dominator. It // is assumed that at this point there are no unreachable blocks in the // control flow graph. void AddNewPhiNodes(); @@ -273,7 +273,7 @@ class MergeReturnPass : public MemPass { void InsertAfterElement(BasicBlock* element, BasicBlock* new_element, std::list* list); - // Creates a single case switch around all of the exectuable code of the + // Creates a single case switch around all of the executable code of the // current function where the switch and case value are both zero and the // default is the merge block. Returns after the switch is executed. Sets // |final_return_block_|. diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index d8daf82c1..330093e45 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -324,6 +324,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateLocalAccessChainConvertPass()); } else if (pass_name == "replace-desc-array-access-using-var-index") { RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass()); + } else if (pass_name == "spread-volatile-semantics") { + RegisterPass(CreateSpreadVolatileSemanticsPass()); } else if (pass_name == "descriptor-scalar-replacement") { RegisterPass(CreateDescriptorScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { @@ -976,6 +978,11 @@ Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() { MakeUnique()); } +Optimizer::PassToken CreateSpreadVolatileSemanticsPass() { + return MakeUnique( + MakeUnique()); +} + Optimizer::PassToken CreateDescriptorScalarReplacementPass() { return MakeUnique( MakeUnique()); diff --git a/3rdparty/spirv-tools/source/opt/pass.h b/3rdparty/spirv-tools/source/opt/pass.h index a8c9c4b43..4a8ea674d 100644 --- a/3rdparty/spirv-tools/source/opt/pass.h +++ b/3rdparty/spirv-tools/source/opt/pass.h @@ -129,7 +129,7 @@ class Pass { // Processes the given |module|. Returns Status::Failure if errors occur when // processing. Returns the corresponding Status::Success if processing is - // succesful to indicate whether changes are made to the module. + // successful to indicate whether changes are made to the module. virtual Status Process() = 0; // Return the next available SSA id and increment it. diff --git a/3rdparty/spirv-tools/source/opt/pass_manager.h b/3rdparty/spirv-tools/source/opt/pass_manager.h index 9686dddc2..11961a330 100644 --- a/3rdparty/spirv-tools/source/opt/pass_manager.h +++ b/3rdparty/spirv-tools/source/opt/pass_manager.h @@ -54,7 +54,7 @@ class PassManager { // Adds an externally constructed pass. void AddPass(std::unique_ptr pass); // Uses the argument |args| to construct a pass instance of type |T|, and adds - // the pass instance to this pass manger. The pass added will use this pass + // the pass instance to this pass manager. The pass added will use this pass // manager's message consumer. template void AddPass(Args&&... args); @@ -70,7 +70,7 @@ class PassManager { // Runs all passes on the given |module|. Returns Status::Failure if errors // occur when processing using one of the registered passes. All passes // registered after the error-reporting pass will be skipped. Returns the - // corresponding Status::Success if processing is succesful to indicate + // corresponding Status::Success if processing is successful to indicate // whether changes are made to the module. // // After running all the passes, they are removed from the list. diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index 3266dbd05..d51c306e7 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -71,6 +71,7 @@ #include "source/opt/scalar_replacement_pass.h" #include "source/opt/set_spec_constant_default_value_pass.h" #include "source/opt/simplification_pass.h" +#include "source/opt/spread_volatile_semantics.h" #include "source/opt/ssa_rewrite_pass.h" #include "source/opt/strength_reduction_pass.h" #include "source/opt/strip_debug_info_pass.h" diff --git a/3rdparty/spirv-tools/source/opt/private_to_local_pass.h b/3rdparty/spirv-tools/source/opt/private_to_local_pass.h index c6127d67f..e96a965e9 100644 --- a/3rdparty/spirv-tools/source/opt/private_to_local_pass.h +++ b/3rdparty/spirv-tools/source/opt/private_to_local_pass.h @@ -44,7 +44,7 @@ class PrivateToLocalPass : public Pass { // class of |function|. Returns false if the variable could not be moved. bool MoveVariable(Instruction* variable, Function* function); - // |inst| is an instruction declaring a varible. If that variable is + // |inst| is an instruction declaring a variable. If that variable is // referenced in a single function and all of uses are valid as defined by // |IsValidUse|, then that function is returned. Otherwise, the return // value is |nullptr|. diff --git a/3rdparty/spirv-tools/source/opt/redundancy_elimination.h b/3rdparty/spirv-tools/source/opt/redundancy_elimination.h index 91809b5d5..40451f40e 100644 --- a/3rdparty/spirv-tools/source/opt/redundancy_elimination.h +++ b/3rdparty/spirv-tools/source/opt/redundancy_elimination.h @@ -41,7 +41,7 @@ class RedundancyEliminationPass : public LocalRedundancyEliminationPass { // in the function containing |bb|. // // |value_to_ids| is a map from value number to ids. If {vn, id} is in - // |value_to_ids| then vn is the value number of id, and the defintion of id + // |value_to_ids| then vn is the value number of id, and the definition of id // dominates |bb|. // // Returns true if at least one instruction is deleted. diff --git a/3rdparty/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h b/3rdparty/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h index e18222c85..0c97f7eb2 100644 --- a/3rdparty/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h +++ b/3rdparty/spirv-tools/source/opt/replace_desc_array_access_using_var_index.h @@ -47,7 +47,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass { } private: - // Replaces all acceses to |var| using variable indices with constant + // Replaces all accesses to |var| using variable indices with constant // elements of the array |var|. Creates switch-case statements to determine // the value of the variable index for all the possible cases. Returns // whether replacement is done or not. @@ -170,7 +170,7 @@ class ReplaceDescArrayAccessUsingVarIndex : public Pass { // Creates and adds an OpSwitch used for the selection of OpAccessChain whose // first Indexes operand is |access_chain_index_var_id|. The OpSwitch will be // added at the end of |parent_block|. It will jump to |default_id| for the - // default case and jumps to one of case blocks whoes ids are |case_block_ids| + // default case and jumps to one of case blocks whose ids are |case_block_ids| // if |access_chain_index_var_id| matches the case number. |merge_id| is the // merge block id. void AddSwitchForAccessChain( diff --git a/3rdparty/spirv-tools/source/opt/scalar_analysis.cpp b/3rdparty/spirv-tools/source/opt/scalar_analysis.cpp index 38555e649..2b0a824cf 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_analysis.cpp +++ b/3rdparty/spirv-tools/source/opt/scalar_analysis.cpp @@ -581,7 +581,7 @@ static void PushToString(T id, std::u32string* str) { // Implements the hashing of SENodes. size_t SENodeHash::operator()(const SENode* node) const { - // Concatinate the terms into a string which we can hash. + // Concatenate the terms into a string which we can hash. std::u32string hash_string{}; // Hashing the type as a string is safer than hashing the enum as the enum is diff --git a/3rdparty/spirv-tools/source/opt/scalar_analysis_nodes.h b/3rdparty/spirv-tools/source/opt/scalar_analysis_nodes.h index b0e3fefd6..91ce446f3 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_analysis_nodes.h +++ b/3rdparty/spirv-tools/source/opt/scalar_analysis_nodes.h @@ -167,7 +167,7 @@ class SENode { const ChildContainerType& GetChildren() const { return children_; } ChildContainerType& GetChildren() { return children_; } - // Return true if this node is a cant compute node. + // Return true if this node is a can't compute node. bool IsCantCompute() const { return GetType() == CanNotCompute; } // Implements a casting method for each type. diff --git a/3rdparty/spirv-tools/source/opt/scalar_analysis_simplification.cpp b/3rdparty/spirv-tools/source/opt/scalar_analysis_simplification.cpp index 9c81dbe98..3c1ecc082 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_analysis_simplification.cpp +++ b/3rdparty/spirv-tools/source/opt/scalar_analysis_simplification.cpp @@ -88,7 +88,7 @@ class SENodeSimplifyImpl { private: // Recursively descend through the graph to build up the accumulator objects - // which are used to flatten the graph. |child| is the node currenty being + // which are used to flatten the graph. |child| is the node currently being // traversed and the |negation| flag is used to signify that this operation // was preceded by a unary negative operation and as such the result should be // negated. diff --git a/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.cpp b/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.cpp new file mode 100644 index 000000000..17a4c725b --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.cpp @@ -0,0 +1,314 @@ +// Copyright (c) 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/spread_volatile_semantics.h" + +#include "source/opt/decoration_manager.h" +#include "source/opt/ir_builder.h" +#include "source/spirv_constant.h" + +namespace spvtools { +namespace opt { +namespace { + +const uint32_t kOpDecorateInOperandBuiltinDecoration = 2u; +const uint32_t kOpLoadInOperandMemoryOperands = 1u; +const uint32_t kOpEntryPointInOperandEntryPoint = 1u; +const uint32_t kOpEntryPointInOperandInterface = 3u; + +bool HasBuiltinDecoration(analysis::DecorationManager* decoration_manager, + uint32_t var_id, uint32_t built_in) { + return decoration_manager->FindDecoration( + var_id, SpvDecorationBuiltIn, [built_in](const Instruction& inst) { + return built_in == inst.GetSingleWordInOperand( + kOpDecorateInOperandBuiltinDecoration); + }); +} + +bool IsBuiltInForRayTracingVolatileSemantics(uint32_t built_in) { + switch (built_in) { + case SpvBuiltInSMIDNV: + case SpvBuiltInWarpIDNV: + case SpvBuiltInSubgroupSize: + case SpvBuiltInSubgroupLocalInvocationId: + case SpvBuiltInSubgroupEqMask: + case SpvBuiltInSubgroupGeMask: + case SpvBuiltInSubgroupGtMask: + case SpvBuiltInSubgroupLeMask: + case SpvBuiltInSubgroupLtMask: + return true; + default: + return false; + } +} + +bool HasBuiltinForRayTracingVolatileSemantics( + analysis::DecorationManager* decoration_manager, uint32_t var_id) { + return decoration_manager->FindDecoration( + var_id, SpvDecorationBuiltIn, [](const Instruction& inst) { + uint32_t built_in = + inst.GetSingleWordInOperand(kOpDecorateInOperandBuiltinDecoration); + return IsBuiltInForRayTracingVolatileSemantics(built_in); + }); +} + +bool HasVolatileDecoration(analysis::DecorationManager* decoration_manager, + uint32_t var_id) { + return decoration_manager->HasDecoration(var_id, SpvDecorationVolatile); +} + +bool HasOnlyEntryPointsAsFunctions(IRContext* context, Module* module) { + std::unordered_set entry_function_ids; + for (Instruction& entry_point : module->entry_points()) { + entry_function_ids.insert( + entry_point.GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint)); + } + for (auto& function : *module) { + if (entry_function_ids.find(function.result_id()) == + entry_function_ids.end()) { + std::string message( + "Functions of SPIR-V for spread-volatile-semantics pass input must " + "be inlined except entry points"); + message += "\n " + function.DefInst().PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + context->consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str()); + return false; + } + } + return true; +} + +} // namespace + +Pass::Status SpreadVolatileSemantics::Process() { + if (!HasOnlyEntryPointsAsFunctions(context(), get_module())) { + return Status::Failure; + } + + const bool is_vk_memory_model_enabled = + context()->get_feature_mgr()->HasCapability( + SpvCapabilityVulkanMemoryModel); + CollectTargetsForVolatileSemantics(is_vk_memory_model_enabled); + + // If VulkanMemoryModel capability is not enabled, we have to set Volatile + // decoration for interface variables instead of setting Volatile for load + // instructions. If an interface (or pointers to it) is used by two load + // instructions in two entry points and one must be volatile while another + // is not, we have to report an error for the conflict. + if (!is_vk_memory_model_enabled && + HasInterfaceInConflictOfVolatileSemantics()) { + return Status::Failure; + } + + return SpreadVolatileSemanticsToVariables(is_vk_memory_model_enabled); +} + +Pass::Status SpreadVolatileSemantics::SpreadVolatileSemanticsToVariables( + const bool is_vk_memory_model_enabled) { + Status status = Status::SuccessWithoutChange; + for (Instruction& var : context()->types_values()) { + auto entry_function_ids = + EntryFunctionsToSpreadVolatileSemanticsForVar(var.result_id()); + if (entry_function_ids.empty()) { + continue; + } + + if (is_vk_memory_model_enabled) { + SetVolatileForLoadsInEntries(&var, entry_function_ids); + } else { + DecorateVarWithVolatile(&var); + } + status = Status::SuccessWithChange; + } + return status; +} + +bool SpreadVolatileSemantics::IsTargetUsedByNonVolatileLoadInEntryPoint( + uint32_t var_id, Instruction* entry_point) { + uint32_t entry_function_id = + entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint); + return !VisitLoadsOfPointersToVariableInEntries( + var_id, + [](Instruction* load) { + // If it has a load without volatile memory operand, finish traversal + // and return false. + if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) { + return false; + } + uint32_t memory_operands = + load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands); + return (memory_operands & SpvMemoryAccessVolatileMask) != 0; + }, + {entry_function_id}); +} + +bool SpreadVolatileSemantics::HasInterfaceInConflictOfVolatileSemantics() { + for (Instruction& entry_point : get_module()->entry_points()) { + SpvExecutionModel execution_model = + static_cast(entry_point.GetSingleWordInOperand(0)); + for (uint32_t operand_index = kOpEntryPointInOperandInterface; + operand_index < entry_point.NumInOperands(); ++operand_index) { + uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index); + if (!EntryFunctionsToSpreadVolatileSemanticsForVar(var_id).empty() && + !IsTargetForVolatileSemantics(var_id, execution_model) && + IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) { + Instruction* inst = context()->get_def_use_mgr()->GetDef(var_id); + context()->EmitErrorMessage( + "Variable is a target for Volatile semantics for an entry point, " + "but it is not for another entry point", + inst); + return true; + } + } + } + return false; +} + +void SpreadVolatileSemantics::MarkVolatileSemanticsForVariable( + uint32_t var_id, Instruction* entry_point) { + uint32_t entry_function_id = + entry_point->GetSingleWordInOperand(kOpEntryPointInOperandEntryPoint); + auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id); + if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) { + var_ids_to_entry_fn_for_volatile_semantics_[var_id] = {entry_function_id}; + return; + } + itr->second.insert(entry_function_id); +} + +void SpreadVolatileSemantics::CollectTargetsForVolatileSemantics( + const bool is_vk_memory_model_enabled) { + for (Instruction& entry_point : get_module()->entry_points()) { + SpvExecutionModel execution_model = + static_cast(entry_point.GetSingleWordInOperand(0)); + for (uint32_t operand_index = kOpEntryPointInOperandInterface; + operand_index < entry_point.NumInOperands(); ++operand_index) { + uint32_t var_id = entry_point.GetSingleWordInOperand(operand_index); + if (!IsTargetForVolatileSemantics(var_id, execution_model)) { + continue; + } + if (is_vk_memory_model_enabled || + IsTargetUsedByNonVolatileLoadInEntryPoint(var_id, &entry_point)) { + MarkVolatileSemanticsForVariable(var_id, &entry_point); + } + } + } +} + +void SpreadVolatileSemantics::DecorateVarWithVolatile(Instruction* var) { + analysis::DecorationManager* decoration_manager = + context()->get_decoration_mgr(); + uint32_t var_id = var->result_id(); + if (HasVolatileDecoration(decoration_manager, var_id)) { + return; + } + get_decoration_mgr()->AddDecoration( + SpvOpDecorate, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {var_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvDecorationVolatile}}}); +} + +bool SpreadVolatileSemantics::VisitLoadsOfPointersToVariableInEntries( + uint32_t var_id, const std::function& handle_load, + const std::unordered_set& entry_function_ids) { + std::vector worklist({var_id}); + auto* def_use_mgr = context()->get_def_use_mgr(); + while (!worklist.empty()) { + uint32_t ptr_id = worklist.back(); + worklist.pop_back(); + bool finish_traversal = !def_use_mgr->WhileEachUser( + ptr_id, [this, &worklist, &ptr_id, handle_load, + &entry_function_ids](Instruction* user) { + BasicBlock* block = context()->get_instr_block(user); + if (block == nullptr || + entry_function_ids.find(block->GetParent()->result_id()) == + entry_function_ids.end()) { + return true; + } + + if (user->opcode() == SpvOpAccessChain || + user->opcode() == SpvOpInBoundsAccessChain || + user->opcode() == SpvOpPtrAccessChain || + user->opcode() == SpvOpInBoundsPtrAccessChain || + user->opcode() == SpvOpCopyObject) { + if (ptr_id == user->GetSingleWordInOperand(0)) + worklist.push_back(user->result_id()); + return true; + } + + if (user->opcode() != SpvOpLoad) { + return true; + } + + return handle_load(user); + }); + if (finish_traversal) return false; + } + return true; +} + +void SpreadVolatileSemantics::SetVolatileForLoadsInEntries( + Instruction* var, const std::unordered_set& entry_function_ids) { + // Set Volatile memory operand for all load instructions if they do not have + // it. + VisitLoadsOfPointersToVariableInEntries( + var->result_id(), + [](Instruction* load) { + if (load->NumInOperands() <= kOpLoadInOperandMemoryOperands) { + load->AddOperand( + {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessVolatileMask}}); + return true; + } + uint32_t memory_operands = + load->GetSingleWordInOperand(kOpLoadInOperandMemoryOperands); + memory_operands |= SpvMemoryAccessVolatileMask; + load->SetInOperand(kOpLoadInOperandMemoryOperands, {memory_operands}); + return true; + }, + entry_function_ids); +} + +bool SpreadVolatileSemantics::IsTargetForVolatileSemantics( + uint32_t var_id, SpvExecutionModel execution_model) { + analysis::DecorationManager* decoration_manager = + context()->get_decoration_mgr(); + if (execution_model == SpvExecutionModelFragment) { + return get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 6) && + HasBuiltinDecoration(decoration_manager, var_id, + SpvBuiltInHelperInvocation); + } + + if (execution_model == SpvExecutionModelIntersectionKHR || + execution_model == SpvExecutionModelIntersectionNV) { + if (HasBuiltinDecoration(decoration_manager, var_id, + SpvBuiltInRayTmaxKHR)) { + return true; + } + } + + switch (execution_model) { + case SpvExecutionModelRayGenerationKHR: + case SpvExecutionModelClosestHitKHR: + case SpvExecutionModelMissKHR: + case SpvExecutionModelCallableKHR: + case SpvExecutionModelIntersectionKHR: + return HasBuiltinForRayTracingVolatileSemantics(decoration_manager, + var_id); + default: + return false; + } +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.h b/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.h new file mode 100644 index 000000000..3d0a18394 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/spread_volatile_semantics.h @@ -0,0 +1,110 @@ +// Copyright (c) 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ +#define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ + +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// See optimizer.hpp for documentation. +class SpreadVolatileSemantics : public Pass { + public: + SpreadVolatileSemantics() {} + + const char* name() const override { return "spread-volatile-semantics"; } + + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations | + IRContext::kAnalysisInstrToBlockMapping; + } + + private: + // Iterates interface variables and spreads the Volatile semantics if it has + // load instructions for the Volatile semantics. + Pass::Status SpreadVolatileSemanticsToVariables( + const bool is_vk_memory_model_enabled); + + // Returns whether |var_id| is the result id of a target builtin variable for + // the volatile semantics for |execution_model| based on the Vulkan spec + // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or + // VUID-StandaloneSpirv-VulkanMemoryModel-04679. + bool IsTargetForVolatileSemantics(uint32_t var_id, + SpvExecutionModel execution_model); + + // Collects interface variables that need the volatile semantics. + // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is + // enabled. + void CollectTargetsForVolatileSemantics( + const bool is_vk_memory_model_enabled); + + // Reports an error if an interface variable is used by two entry points and + // it needs the Volatile decoration for one but not for another. Returns true + // if the error must be reported. + bool HasInterfaceInConflictOfVolatileSemantics(); + + // Returns whether the variable whose result is |var_id| is used by a + // non-volatile load or a pointer to it is used by a non-volatile load in + // |entry_point| or not. + bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id, + Instruction* entry_point); + + // Visits load instructions of pointers to variable whose result id is + // |var_id| if the load instructions are in entry points whose + // function id is one of |entry_function_ids|. |handle_load| is a function to + // do some actions for the load instructions. Finishes the traversal and + // returns false if |handle_load| returns false for a load instruction. + // Otherwise, returns true after running |handle_load| for all the load + // instructions. + bool VisitLoadsOfPointersToVariableInEntries( + uint32_t var_id, const std::function& handle_load, + const std::unordered_set& entry_function_ids); + + // Sets Memory Operands of OpLoad instructions that load |var| or pointers + // of |var| as Volatile if the function id of the OpLoad instruction is + // included in |entry_function_ids|. + void SetVolatileForLoadsInEntries( + Instruction* var, const std::unordered_set& entry_function_ids); + + // Adds OpDecorate Volatile for |var| if it does not exist. + void DecorateVarWithVolatile(Instruction* var); + + // Returns a set of entry function ids to spread the volatile semantics for + // the variable with the result id |var_id|. + std::unordered_set EntryFunctionsToSpreadVolatileSemanticsForVar( + uint32_t var_id) { + auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id); + if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {}; + return itr->second; + } + + // Specifies that we have to spread the volatile semantics for the + // variable with the result id |var_id| for the entry point |entry_point|. + void MarkVolatileSemanticsForVariable(uint32_t var_id, + Instruction* entry_point); + + // Result ids of variables to entry function ids for the volatile semantics + // spread. + std::unordered_map> + var_ids_to_entry_fn_for_volatile_semantics_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ diff --git a/3rdparty/spirv-tools/source/opt/unify_const_pass.cpp b/3rdparty/spirv-tools/source/opt/unify_const_pass.cpp index 227fd61da..6bfa11a5b 100644 --- a/3rdparty/spirv-tools/source/opt/unify_const_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/unify_const_pass.cpp @@ -151,7 +151,7 @@ Pass::Status UnifyConstantPass::Process() { // 'SpecId' decoration and all of them should be treated as unique. // 'SpecId' is not applicable to SpecConstants defined with // OpSpecConstant{Op|Composite}, their values are not necessary to be - // unique. When all the operands/compoents are the same between two + // unique. When all the operands/components are the same between two // OpSpecConstant{Op|Composite} results, their result values must be the // same so are unifiable. case SpvOp::SpvOpSpecConstantOp: diff --git a/3rdparty/spirv-tools/source/opt/vector_dce.h b/3rdparty/spirv-tools/source/opt/vector_dce.h index 4d30b926b..a55bda692 100644 --- a/3rdparty/spirv-tools/source/opt/vector_dce.h +++ b/3rdparty/spirv-tools/source/opt/vector_dce.h @@ -73,7 +73,7 @@ class VectorDCE : public MemPass { bool RewriteInstructions(Function* function, const LiveComponentMap& live_components); - // Makrs all DebugValue instructions that use |composite| for their values as + // Makes all DebugValue instructions that use |composite| for their values as // dead instructions by putting them into |dead_dbg_value|. void MarkDebugValueUsesAsDead(Instruction* composite, std::vector* dead_dbg_value); diff --git a/3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp b/3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp index da096e1eb..e72ed3514 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp +++ b/3rdparty/spirv-tools/source/reduce/remove_struct_member_reduction_opportunity.cpp @@ -153,7 +153,7 @@ void RemoveStructMemberReductionOpportunity::AdjustAccessedIndices( next_type = type_inst->GetSingleWordInOperand(0); break; case SpvOpTypeStruct: { - // Struct types are special becuase (a) we may need to adjust the index + // Struct types are special because (a) we may need to adjust the index // being used, if the struct type is the one from which we are removing // a member, and (b) the type encountered by following the current index // is dependent on the value of the index. diff --git a/3rdparty/spirv-tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp b/3rdparty/spirv-tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp index e72be625e..cd0c4e4d7 100644 --- a/3rdparty/spirv-tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp +++ b/3rdparty/spirv-tools/source/reduce/remove_unused_struct_member_reduction_opportunity_finder.cpp @@ -136,9 +136,9 @@ RemoveUnusedStructMemberReductionOpportunityFinder::GetAvailableOpportunities( } } - // We now know those struct indices that are unsed, and we make a reduction + // We now know those struct indices that are unused, and we make a reduction // opportunity for each of them. By mapping each relevant member index to the - // structs in which it is unsed, we will group all opportunities to remove + // structs in which it is unused, we will group all opportunities to remove // member k of a struct (for some k) together. This reduces the likelihood // that opportunities to remove members from the same struct will be adjacent, // which is good because such opportunities mutually disable one another. diff --git a/3rdparty/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp b/3rdparty/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp index dc20f689b..29fbe551a 100644 --- a/3rdparty/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp +++ b/3rdparty/spirv-tools/source/reduce/structured_construct_to_block_reduction_opportunity_finder.cpp @@ -96,7 +96,7 @@ StructuredConstructToBlockReductionOpportunityFinder::GetAvailableOpportunities( // This also means that we don't add a region. continue; } - // We have a reachable header block with a rechable merge that + // We have a reachable header block with a reachable merge that // postdominates the header: this means we have a new region. regions.emplace(&block, std::unordered_set()); } @@ -128,7 +128,7 @@ bool StructuredConstructToBlockReductionOpportunityFinder:: if (!block->WhileEachInst( [context, &header, ®ion](opt::Instruction* inst) -> bool { if (inst->result_id() == 0) { - // The instruction does not genreate a result id, thus it cannot + // The instruction does not generate a result id, thus it cannot // be referred to outside the region - this is fine. return true; } diff --git a/3rdparty/spirv-tools/source/spirv_definition.h b/3rdparty/spirv-tools/source/spirv_definition.h index 63a4ef0db..5dbd6ab20 100644 --- a/3rdparty/spirv-tools/source/spirv_definition.h +++ b/3rdparty/spirv-tools/source/spirv_definition.h @@ -27,7 +27,7 @@ typedef struct spv_header_t { uint32_t generator; uint32_t bound; uint32_t schema; // NOTE: Reserved - const uint32_t* instructions; // NOTE: Unfixed pointer to instruciton stream + const uint32_t* instructions; // NOTE: Unfixed pointer to instruction stream } spv_header_t; #endif // SOURCE_SPIRV_DEFINITION_H_ diff --git a/3rdparty/spirv-tools/source/spirv_endian.h b/3rdparty/spirv-tools/source/spirv_endian.h index c2540bec9..b4927f318 100644 --- a/3rdparty/spirv-tools/source/spirv_endian.h +++ b/3rdparty/spirv-tools/source/spirv_endian.h @@ -31,7 +31,7 @@ uint64_t spvFixDoubleWord(const uint32_t low, const uint32_t high, spv_result_t spvBinaryEndianness(const spv_const_binary binary, spv_endianness_t* endian); -// Returns true if the given endianness matches the host's native endiannes. +// Returns true if the given endianness matches the host's native endianness. bool spvIsHostEndian(spv_endianness_t endian); #endif // SOURCE_SPIRV_ENDIAN_H_ diff --git a/3rdparty/spirv-tools/source/spirv_target_env.cpp b/3rdparty/spirv-tools/source/spirv_target_env.cpp index 43d1c3ddf..9a0381742 100644 --- a/3rdparty/spirv-tools/source/spirv_target_env.cpp +++ b/3rdparty/spirv-tools/source/spirv_target_env.cpp @@ -74,6 +74,8 @@ const char* spvTargetEnvDescription(spv_target_env env) { return "SPIR-V 1.5 (under Vulkan 1.2 semantics)"; case SPV_ENV_UNIVERSAL_1_6: return "SPIR-V 1.6"; + case SPV_ENV_VULKAN_1_3: + return "SPIR-V 1.6 (under Vulkan 1.3 semantics)"; case SPV_ENV_MAX: assert(false && "Invalid target environment value."); break; @@ -116,6 +118,7 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_2: return SPV_SPIRV_VERSION_WORD(1, 5); case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: return SPV_SPIRV_VERSION_WORD(1, 6); case SPV_ENV_MAX: assert(false && "Invalid target environment value."); @@ -129,6 +132,7 @@ static const std::pair spvTargetEnvNameMap[] = { {"vulkan1.0", SPV_ENV_VULKAN_1_0}, {"vulkan1.1", SPV_ENV_VULKAN_1_1}, {"vulkan1.2", SPV_ENV_VULKAN_1_2}, + {"vulkan1.3", SPV_ENV_VULKAN_1_3}, {"spv1.0", SPV_ENV_UNIVERSAL_1_0}, {"spv1.1", SPV_ENV_UNIVERSAL_1_1}, {"spv1.2", SPV_ENV_UNIVERSAL_1_2}, @@ -182,7 +186,8 @@ static const VulkanEnv ordered_vulkan_envs[] = { {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)}, {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)}, {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)}, - {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}}; + {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}, + {SPV_ENV_VULKAN_1_3, VULKAN_VER(1, 3), SPIRV_VER(1, 6)}}; bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver, spv_target_env* env) { @@ -222,6 +227,7 @@ bool spvIsVulkanEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_1: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_VULKAN_1_2: + case SPV_ENV_VULKAN_1_3: return true; case SPV_ENV_WEBGPU_0: assert(false && "Deprecated target environment value."); @@ -251,6 +257,7 @@ bool spvIsOpenCLEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: return false; case SPV_ENV_OPENCL_1_2: case SPV_ENV_OPENCL_EMBEDDED_1_2: @@ -292,6 +299,7 @@ bool spvIsOpenGLEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: return false; case SPV_ENV_OPENGL_4_0: case SPV_ENV_OPENGL_4_1: @@ -330,6 +338,7 @@ bool spvIsValidEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: case SPV_ENV_OPENGL_4_0: case SPV_ENV_OPENGL_4_1: case SPV_ENV_OPENGL_4_2: @@ -365,7 +374,8 @@ std::string spvLogStringForEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_0: case SPV_ENV_VULKAN_1_1: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: - case SPV_ENV_VULKAN_1_2: { + case SPV_ENV_VULKAN_1_2: + case SPV_ENV_VULKAN_1_3: { return "Vulkan"; } case SPV_ENV_UNIVERSAL_1_0: diff --git a/3rdparty/spirv-tools/source/spirv_target_env.h b/3rdparty/spirv-tools/source/spirv_target_env.h index cc06deca7..f3b0c2f6f 100644 --- a/3rdparty/spirv-tools/source/spirv_target_env.h +++ b/3rdparty/spirv-tools/source/spirv_target_env.h @@ -40,7 +40,7 @@ std::string spvLogStringForEnv(spv_target_env env); // Returns a formatted list of all SPIR-V target environment names that // can be parsed by spvParseTargetEnv. -// |pad| is the number of space characters that the begining of each line +// |pad| is the number of space characters that the beginning of each line // except the first one will be padded with. // |wrap| is the max length of lines the user desires. Word-wrapping will // occur to satisfy this limit. diff --git a/3rdparty/spirv-tools/source/table.cpp b/3rdparty/spirv-tools/source/table.cpp index a87bbf28a..822cefebd 100644 --- a/3rdparty/spirv-tools/source/table.cpp +++ b/3rdparty/spirv-tools/source/table.cpp @@ -42,6 +42,7 @@ spv_context spvContextCreate(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: case SPV_ENV_UNIVERSAL_1_6: + case SPV_ENV_VULKAN_1_3: break; default: return nullptr; diff --git a/3rdparty/spirv-tools/source/util/bit_vector.h b/3rdparty/spirv-tools/source/util/bit_vector.h index 3e189cb10..826d62f02 100644 --- a/3rdparty/spirv-tools/source/util/bit_vector.h +++ b/3rdparty/spirv-tools/source/util/bit_vector.h @@ -32,7 +32,7 @@ class BitVector { enum { kInitialNumBits = 1024 }; public: - // Creates a bit vector contianing 0s. + // Creates a bit vector containing 0s. BitVector(uint32_t reserved_size = kInitialNumBits) : bits_((reserved_size - 1) / kBitContainerSize + 1, 0) {} diff --git a/3rdparty/spirv-tools/source/util/ilist.h b/3rdparty/spirv-tools/source/util/ilist.h index 9837b09b3..b7ecf01e1 100644 --- a/3rdparty/spirv-tools/source/util/ilist.h +++ b/3rdparty/spirv-tools/source/util/ilist.h @@ -59,7 +59,7 @@ class IntrusiveList { // Moves the contents of the given list to the list being constructed. IntrusiveList(IntrusiveList&&); - // Destorys the list. Note that the elements of the list will not be deleted, + // Destroys the list. Note that the elements of the list will not be deleted, // but they will be removed from the list. virtual ~IntrusiveList(); diff --git a/3rdparty/spirv-tools/source/util/parse_number.h b/3rdparty/spirv-tools/source/util/parse_number.h index 729aac54b..d0f2a09a3 100644 --- a/3rdparty/spirv-tools/source/util/parse_number.h +++ b/3rdparty/spirv-tools/source/util/parse_number.h @@ -220,7 +220,7 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber( std::function emit, std::string* error_msg); // Parses a floating point value of a given |type| from the given |text| and -// encodes the number by the given |emit| funciton. On success, returns +// encodes the number by the given |emit| function. On success, returns // EncodeNumberStatus::kSuccess and the parsed number will be consumed by the // given |emit| function word by word (least significant word first). On // failure, this function returns the error code of the encoding status and diff --git a/3rdparty/spirv-tools/source/util/small_vector.h b/3rdparty/spirv-tools/source/util/small_vector.h index f2c1147be..f1762a9f2 100644 --- a/3rdparty/spirv-tools/source/util/small_vector.h +++ b/3rdparty/spirv-tools/source/util/small_vector.h @@ -175,9 +175,12 @@ class SmallVector { return true; } +// Avoid infinite recursion from rewritten operators in C++20 +#if __cplusplus <= 201703L friend bool operator==(const std::vector& lhs, const SmallVector& rhs) { return rhs == lhs; } +#endif friend bool operator!=(const SmallVector& lhs, const std::vector& rhs) { return !(lhs == rhs); @@ -363,7 +366,7 @@ class SmallVector { } } - // Upate the size. + // Update the size. size_ += num_of_new_elements; return pos; } @@ -449,7 +452,7 @@ class SmallVector { T* small_data_; // The actual data used to store the array elements. It must never be used - // directly, but must only be accesed through |small_data_|. + // directly, but must only be accessed through |small_data_|. typename std::aligned_storage::value>::type buffer[small_size]; diff --git a/3rdparty/spirv-tools/source/util/timer.h b/3rdparty/spirv-tools/source/util/timer.h index fc4b747b9..080831196 100644 --- a/3rdparty/spirv-tools/source/util/timer.h +++ b/3rdparty/spirv-tools/source/util/timer.h @@ -206,16 +206,16 @@ class Timer { // Variable to save the result of clock_gettime(CLOCK_PROCESS_CPUTIME_ID) when // Timer::Stop() is called. It is used as the last status of CPU time. The - // resouce usage is measured by subtracting |cpu_before_| from it. + // resource usage is measured by subtracting |cpu_before_| from it. timespec cpu_after_; // Variable to save the result of clock_gettime(CLOCK_MONOTONIC) when // Timer::Stop() is called. It is used as the last status of WALL time. The - // resouce usage is measured by subtracting |wall_before_| from it. + // resource usage is measured by subtracting |wall_before_| from it. timespec wall_after_; // Variable to save the result of getrusage() when Timer::Stop() is called. It - // is used as the last status of USR time, SYS time, and RSS. Those resouce + // is used as the last status of USR time, SYS time, and RSS. Those resource // usages are measured by subtracting |usage_before_| from it. rusage usage_after_; diff --git a/3rdparty/spirv-tools/source/val/basic_block.h b/3rdparty/spirv-tools/source/val/basic_block.h index 5af4b9e4d..47cd06d07 100644 --- a/3rdparty/spirv-tools/source/val/basic_block.h +++ b/3rdparty/spirv-tools/source/val/basic_block.h @@ -84,26 +84,26 @@ class BasicBlock { type_.set(type); } - /// Sets the immedate dominator of this basic block + /// Sets the immediate dominator of this basic block /// /// @param[in] dom_block The dominator block void SetImmediateDominator(BasicBlock* dom_block); - /// Sets the immedate post dominator of this basic block + /// Sets the immediate post dominator of this basic block /// /// @param[in] pdom_block The post dominator block void SetImmediatePostDominator(BasicBlock* pdom_block); - /// Returns the immedate dominator of this basic block + /// Returns the immediate dominator of this basic block BasicBlock* immediate_dominator(); - /// Returns the immedate dominator of this basic block + /// Returns the immediate dominator of this basic block const BasicBlock* immediate_dominator() const; - /// Returns the immedate post dominator of this basic block + /// Returns the immediate post dominator of this basic block BasicBlock* immediate_post_dominator(); - /// Returns the immedate post dominator of this basic block + /// Returns the immediate post dominator of this basic block const BasicBlock* immediate_post_dominator() const; /// Returns the label instruction for the block, or nullptr if not set. diff --git a/3rdparty/spirv-tools/source/val/function.cpp b/3rdparty/spirv-tools/source/val/function.cpp index 9ad68e867..f3292b0e7 100644 --- a/3rdparty/spirv-tools/source/val/function.cpp +++ b/3rdparty/spirv-tools/source/val/function.cpp @@ -57,7 +57,7 @@ spv_result_t Function::RegisterFunctionParameter(uint32_t parameter_id, uint32_t type_id) { assert(current_block_ == nullptr && "RegisterFunctionParameter can only be called when parsing the binary " - "ouside of a block"); + "outside of a block"); // TODO(umar): Validate function parameter type order and count // TODO(umar): Use these variables to validate parameter type (void)parameter_id; @@ -130,7 +130,7 @@ spv_result_t Function::RegisterBlock(uint32_t block_id, bool is_definition) { undefined_blocks_.erase(block_id); current_block_ = &inserted_block->second; ordered_blocks_.push_back(current_block_); - } else if (success) { // Block doesn't exsist but this is not a definition + } else if (success) { // Block doesn't exist but this is not a definition undefined_blocks_.insert(block_id); } diff --git a/3rdparty/spirv-tools/source/val/function.h b/3rdparty/spirv-tools/source/val/function.h index 400bb6348..2fe30bdc8 100644 --- a/3rdparty/spirv-tools/source/val/function.h +++ b/3rdparty/spirv-tools/source/val/function.h @@ -73,8 +73,8 @@ class Function { /// Registers a variable in the current block /// - /// @param[in] type_id The type ID of the varaible - /// @param[in] id The ID of the varaible + /// @param[in] type_id The type ID of the variable + /// @param[in] id The ID of the variable /// @param[in] storage The storage of the variable /// @param[in] init_id The initializer ID of the variable /// @@ -197,10 +197,10 @@ class Function { /// been identified and dominators have been computed. int GetBlockDepth(BasicBlock* bb); - /// Prints a GraphViz digraph of the CFG of the current funciton + /// Prints a GraphViz digraph of the CFG of the current function void PrintDotGraph() const; - /// Prints a directed graph of the CFG of the current funciton + /// Prints a directed graph of the CFG of the current function void PrintBlocks() const; /// Registers execution model limitation such as "Feature X is only available @@ -285,7 +285,7 @@ class Function { /// The type of the return value uint32_t result_type_id_; - /// The control fo the funciton + /// The control fo the function SpvFunctionControlMask function_control_; /// The type of declaration of each function diff --git a/3rdparty/spirv-tools/source/val/validate.cpp b/3rdparty/spirv-tools/source/val/validate.cpp index 64df67ca2..ecc9fdb63 100644 --- a/3rdparty/spirv-tools/source/val/validate.cpp +++ b/3rdparty/spirv-tools/source/val/validate.cpp @@ -348,7 +348,7 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( } // Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi - // must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine. + // must only be preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine. if (auto error = ValidateAdjacency(*vstate)) return error; if (auto error = ValidateEntryPoints(*vstate)) return error; diff --git a/3rdparty/spirv-tools/source/val/validate.h b/3rdparty/spirv-tools/source/val/validate.h index 3fc183de8..cb1d05a57 100644 --- a/3rdparty/spirv-tools/source/val/validate.h +++ b/3rdparty/spirv-tools/source/val/validate.h @@ -70,7 +70,7 @@ spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _); /// /// This function will iterate over all instructions and check for any required /// predecessor and/or successor instructions. e.g. SpvOpPhi must only be -/// preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine. +/// preceded by SpvOpLabel, SpvOpPhi, or SpvOpLine. /// /// @param[in] _ the validation state of the module /// diff --git a/3rdparty/spirv-tools/source/val/validate_arithmetics.cpp b/3rdparty/spirv-tools/source/val/validate_arithmetics.cpp index 433330d74..bae9b5dca 100644 --- a/3rdparty/spirv-tools/source/val/validate_arithmetics.cpp +++ b/3rdparty/spirv-tools/source/val/validate_arithmetics.cpp @@ -155,7 +155,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { first_vector_num_components = num_components; } else if (num_components != first_vector_num_components) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected operands to have the same number of componenets: " + << "Expected operands to have the same number of components: " << spvOpcodeString(opcode); } } diff --git a/3rdparty/spirv-tools/source/val/validate_cfg.cpp b/3rdparty/spirv-tools/source/val/validate_cfg.cpp index 26b2e94a6..88abd7543 100644 --- a/3rdparty/spirv-tools/source/val/validate_cfg.cpp +++ b/3rdparty/spirv-tools/source/val/validate_cfg.cpp @@ -675,7 +675,7 @@ spv_result_t ValidateStructuredSelections( } else if (terminator->opcode() == SpvOpSwitch) { if (!merge) { return _.diag(SPV_ERROR_INVALID_CFG, terminator) - << "OpSwitch must be preceeded by an OpSelectionMerge " + << "OpSwitch must be preceded by an OpSelectionMerge " "instruction"; } // Mark the targets as seen. @@ -917,7 +917,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { } } } - // If we have structed control flow, check that no block has a control + // If we have structured control flow, check that no block has a control // flow nesting depth larger than the limit. if (_.HasCapability(SpvCapabilityShader)) { const int control_flow_nesting_depth_limit = diff --git a/3rdparty/spirv-tools/source/val/validate_decorations.cpp b/3rdparty/spirv-tools/source/val/validate_decorations.cpp index eb6109021..eb6caf0b0 100644 --- a/3rdparty/spirv-tools/source/val/validate_decorations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_decorations.cpp @@ -465,7 +465,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, return lhs.offset < rhs.offset; }); - // Now scan from lowest offest to highest offset. + // Now scan from lowest offset to highest offset. uint32_t nextValidOffset = 0; for (size_t ordered_member_idx = 0; ordered_member_idx < member_offsets.size(); ordered_member_idx++) { @@ -720,7 +720,7 @@ spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) { return SPV_SUCCESS; } -// Checks whether proper decorations have been appied to the entry points. +// Checks whether proper decorations have been applied to the entry points. spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { for (uint32_t entry_point : vstate.entry_points()) { const auto& descs = vstate.entry_point_descriptions(entry_point); diff --git a/3rdparty/spirv-tools/source/val/validate_extensions.cpp b/3rdparty/spirv-tools/source/val/validate_extensions.cpp index b9f8e3c50..01cbcd25c 100644 --- a/3rdparty/spirv-tools/source/val/validate_extensions.cpp +++ b/3rdparty/spirv-tools/source/val/validate_extensions.cpp @@ -129,7 +129,7 @@ spv_result_t ValidateUint32ConstantOperandForDebugInfo( } // True if the operand of a debug info instruction |inst| at |word_index| -// satisifies |expectation| that is given as a function. Otherwise, +// satisfies |expectation| that is given as a function. Otherwise, // returns false. bool DoesDebugInfoOperandMatchExpectation( const ValidationState_t& _, diff --git a/3rdparty/spirv-tools/source/val/validate_image.cpp b/3rdparty/spirv-tools/source/val/validate_image.cpp index 037fab69f..b12d1e820 100644 --- a/3rdparty/spirv-tools/source/val/validate_image.cpp +++ b/3rdparty/spirv-tools/source/val/validate_image.cpp @@ -260,7 +260,8 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask | SpvImageOperandsVolatileTexelKHRMask | SpvImageOperandsSignExtendMask | - SpvImageOperandsZeroExtendMask); + SpvImageOperandsZeroExtendMask | + SpvImageOperandsNontemporalMask); size_t expected_num_image_operand_words = spvtools::utils::CountSetBits(mask_bits_having_operands); if (mask & SpvImageOperandsGradMask) { @@ -502,7 +503,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, if (!_.IsIntVectorType(component_type) || _.GetDimension(component_type) != 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Image Operand ConstOffsets array componenets to be " + << "Expected Image Operand ConstOffsets array components to be " "int vectors of size 2"; } @@ -1043,7 +1044,7 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, << "Result from OpSampledImage instruction must not appear " "as operand for Op" << spvOpcodeString(static_cast(consumer_opcode)) - << ", since it is not specificed as taking an " + << ", since it is not specified as taking an " << "OpTypeSampledImage." << " Found result '" << _.getIdName(inst->id()) << "' as an operand of '" @@ -1672,7 +1673,7 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { << " components, but given only " << actual_coord_size; } - // TODO(atgoo@github.com) The spec doesn't explicitely say what the type + // TODO(atgoo@github.com) The spec doesn't explicitly say what the type // of texel should be. const uint32_t texel_type = _.GetOperandTypeId(inst, 2); if (!_.IsIntScalarOrVectorType(texel_type) && diff --git a/3rdparty/spirv-tools/source/val/validate_instruction.cpp b/3rdparty/spirv-tools/source/val/validate_instruction.cpp index dad98673b..3edf16379 100644 --- a/3rdparty/spirv-tools/source/val/validate_instruction.cpp +++ b/3rdparty/spirv-tools/source/val/validate_instruction.cpp @@ -297,7 +297,7 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { } // OpTerminateInvocation is special because it is enabled by Shader - // capability, but also requries a extension and/or version check. + // capability, but also requires an extension and/or version check. const bool capability_check_is_sufficient = inst->opcode() != SpvOpTerminateInvocation; @@ -406,7 +406,7 @@ spv_result_t LimitCheckSwitch(ValidationState_t& _, const Instruction* inst) { // The instruction syntax is as follows: // OpSwitch literal label literal label ... // literal,label pairs come after the first 2 operands. - // It is guaranteed at this point that num_operands is an even numner. + // It is guaranteed at this point that num_operands is an even number. size_t num_pairs = (inst->operands().size() - 2) / 2; const unsigned int num_pairs_limit = _.options()->universal_limits_.max_switch_branches; diff --git a/3rdparty/spirv-tools/source/val/validate_scopes.cpp b/3rdparty/spirv-tools/source/val/validate_scopes.cpp index 29ba58317..1c5f70a33 100644 --- a/3rdparty/spirv-tools/source/val/validate_scopes.cpp +++ b/3rdparty/spirv-tools/source/val/validate_scopes.cpp @@ -225,7 +225,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, << _.VkErrorID(4638) << spvOpcodeString(opcode) << ": in Vulkan environment, Memory Scope cannot be CrossDevice"; } - // Vulkan 1.0 specifc rules + // Vulkan 1.0 specific rules if (_.context()->target_env == SPV_ENV_VULKAN_1_0 && value != SpvScopeDevice && value != SpvScopeWorkgroup && value != SpvScopeInvocation) { @@ -234,7 +234,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, << ": in Vulkan 1.0 environment Memory Scope is limited to " << "Device, Workgroup and Invocation"; } - // Vulkan 1.1 specifc rules + // Vulkan 1.1 specific rules if ((_.context()->target_env == SPV_ENV_VULKAN_1_1 || _.context()->target_env == SPV_ENV_VULKAN_1_2) && value != SpvScopeDevice && value != SpvScopeWorkgroup && diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index c22826116..6f97321f2 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -175,7 +175,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx, } } - // LocalSizeId is only disallowed without maintainence4. + // LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4. switch (env) { case SPV_ENV_VULKAN_1_0: case SPV_ENV_VULKAN_1_1: @@ -498,7 +498,7 @@ spv_result_t ValidationState_t::RegisterFunctionEnd() { "inside of another function"); assert(in_block() == false && "RegisterFunctionParameter can only be called when parsing the binary " - "ouside of a block"); + "outside of a block"); current_function().RegisterFunctionEnd(); in_function_ = false; return SPV_SUCCESS; @@ -610,7 +610,7 @@ void ValidationState_t::RegisterStorageClassConsumer( if (message) { *message = errorVUID + - "in Vulkan evironment, Output Storage Class must not be " + "in Vulkan environment, Output Storage Class must not be " "used in GLCompute, RayGenerationKHR, IntersectionKHR, " "AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR " "execution models"; @@ -632,7 +632,7 @@ void ValidationState_t::RegisterStorageClassConsumer( if (message) { *message = errorVUID + - "in Vulkan evironment, Workgroup Storage Class is limited " + "in Vulkan environment, Workgroup Storage Class is limited " "to MeshNV, TaskNV, and GLCompute execution model"; } return false; @@ -1407,7 +1407,7 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return ""; } - // This large switch case is only searched when an error has occured. + // This large switch case is only searched when an error has occurred. // If an id is changed, the old case must be modified or removed. Each string // here is interpreted as being "implemented" diff --git a/3rdparty/spirv-tools/source/val/validation_state.h b/3rdparty/spirv-tools/source/val/validation_state.h index 2ddfa4a93..89834a0d1 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.h +++ b/3rdparty/spirv-tools/source/val/validation_state.h @@ -67,7 +67,7 @@ class ValidationState_t { bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width? bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width? bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration - // and its vaules to be used without + // and its values to be used without // requiring any capability // Allow functionalities enabled by VariablePointers capability. @@ -797,7 +797,7 @@ class ValidationState_t { /// IDs that are entry points, ie, arguments to OpEntryPoint. std::vector entry_points_; - /// Maps an entry point id to its desciptions. + /// Maps an entry point id to its descriptions. std::unordered_map> entry_point_descriptions_; @@ -844,7 +844,7 @@ class ValidationState_t { // have the same pointer size (for physical pointer types). uint32_t pointer_size_and_alignment_; - /// NOTE: See correspoding getter functions + /// NOTE: See corresponding getter functions bool in_function_; /// The state of optional features. These are determined by capabilities