diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 02ed4cfc5..66aafc117 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2022.2-dev", "SPIRV-Tools v2022.2-dev da9e2f0400ece7d68b44d7c7126cac808dfcf5c3" +"v2022.2-dev", "SPIRV-Tools v2022.2-dev 6bc813fb765b20ce28c8e6e8c5e6592e227dbf8c" diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index fdb2e648f..2273e85df 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -896,6 +896,10 @@ Optimizer::PassToken CreateConvertToSampledImagePass( const std::vector& descriptor_set_binding_pairs); +// Creates a remove-dont-inline pass to remove the |DontInline| function control +// from every function in the module. This is useful if you want the inliner to +// inline these functions some reason. +Optimizer::PassToken CreateRemoveDontInlinePass(); } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp index 5099b477a..5f8550276 100644 --- a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp @@ -172,7 +172,8 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(Instruction* instr) { if (folded_inst != nullptr) { // We do not want to change the body of the function by adding new // instructions. When folding we can only generate new constants. - assert(folded_inst->IsConstant() && + assert((folded_inst->IsConstant() || + IsSpecConstantInst(folded_inst->opcode())) && "CCP is only interested in constant values."); uint32_t new_val = ComputeLatticeMeet(instr, folded_inst->result_id()); values_[instr->result_id()] = new_val; diff --git a/3rdparty/spirv-tools/source/opt/compact_ids_pass.cpp b/3rdparty/spirv-tools/source/opt/compact_ids_pass.cpp index 8815b8c65..70848d79b 100644 --- a/3rdparty/spirv-tools/source/opt/compact_ids_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/compact_ids_pass.cpp @@ -86,7 +86,8 @@ Pass::Status CompactIdsPass::Process() { }, true); - if (modified) { + if (context()->module()->id_bound() != result_id_mapping.size() + 1) { + modified = true; context()->module()->SetIdBound( static_cast(result_id_mapping.size() + 1)); // There are ids in the feature manager that could now be invalid diff --git a/3rdparty/spirv-tools/source/opt/folding_rules.cpp b/3rdparty/spirv-tools/source/opt/folding_rules.cpp index 4904f1862..c879a0c50 100644 --- a/3rdparty/spirv-tools/source/opt/folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/folding_rules.cpp @@ -2368,7 +2368,7 @@ FoldingRule VectorShuffleFeedingShuffle() { // fold. return false; } - } else { + } else if (component_index != undef_literal) { if (new_feeder_id == 0) { // First time through, save the id of the operand the element comes // from. @@ -2382,7 +2382,7 @@ FoldingRule VectorShuffleFeedingShuffle() { component_index -= feeder_op0_length; } - if (!feeder_is_op0) { + if (!feeder_is_op0 && component_index != undef_literal) { component_index += op0_length; } } diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 330093e45..ec2c8ea27 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -521,6 +521,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateAmdExtToKhrPass()); } else if (pass_name == "interpolate-fixup") { RegisterPass(CreateInterpolateFixupPass()); + } else if (pass_name == "remove-dont-inline") { + RegisterPass(CreateRemoveDontInlinePass()); } else if (pass_name == "convert-to-sampled-image") { if (pass_args.size() > 0) { auto descriptor_set_binding_pairs = @@ -1009,4 +1011,8 @@ Optimizer::PassToken CreateConvertToSampledImagePass( MakeUnique(descriptor_set_binding_pairs)); } +Optimizer::PassToken CreateRemoveDontInlinePass() { + return MakeUnique( + MakeUnique()); +} } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index d51c306e7..26739cdc8 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -64,6 +64,7 @@ #include "source/opt/reduce_load_size.h" #include "source/opt/redundancy_elimination.h" #include "source/opt/relax_float_ops_pass.h" +#include "source/opt/remove_dontinline_pass.h" #include "source/opt/remove_duplicates_pass.h" #include "source/opt/remove_unused_interface_variables_pass.h" #include "source/opt/replace_desc_array_access_using_var_index.h" diff --git a/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.cpp b/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.cpp new file mode 100644 index 000000000..4dd1cd4f2 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.cpp @@ -0,0 +1,49 @@ +// 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/remove_dontinline_pass.h" + +namespace spvtools { +namespace opt { + +Pass::Status RemoveDontInline::Process() { + bool modified = false; + modified = ClearDontInlineFunctionControl(); + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); +} + +bool RemoveDontInline::ClearDontInlineFunctionControl() { + bool modified = false; + for (auto& func : *get_module()) { + ClearDontInlineFunctionControl(&func); + } + return modified; +} + +bool RemoveDontInline::ClearDontInlineFunctionControl(Function* function) { + constexpr uint32_t kFunctionControlInOperandIdx = 0; + Instruction* function_inst = &function->DefInst(); + uint32_t function_control = + function_inst->GetSingleWordInOperand(kFunctionControlInOperandIdx); + + if ((function_control & SpvFunctionControlDontInlineMask) == 0) { + return false; + } + function_control &= ~SpvFunctionControlDontInlineMask; + function_inst->SetInOperand(kFunctionControlInOperandIdx, {function_control}); + return true; +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.h b/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.h new file mode 100644 index 000000000..162431991 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/remove_dontinline_pass.h @@ -0,0 +1,42 @@ +// 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_REMOVE_DONTINLINE_PASS_H_ +#define SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_ + +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// See optimizer.hpp for documentation. +class RemoveDontInline : public Pass { + public: + const char* name() const override { return "remove-dont-inline"; } + Status Process() override; + + private: + // Clears the DontInline function control from every function in the module. + // Returns true of a change was made. + bool ClearDontInlineFunctionControl(); + + // Clears the DontInline function control from |function|. + // Returns true of a change was made. + bool ClearDontInlineFunctionControl(Function* function); +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_ diff --git a/3rdparty/spirv-tools/source/val/validate_annotation.cpp b/3rdparty/spirv-tools/source/val/validate_annotation.cpp index 0614e1620..a27cf165e 100644 --- a/3rdparty/spirv-tools/source/val/validate_annotation.cpp +++ b/3rdparty/spirv-tools/source/val/validate_annotation.cpp @@ -326,17 +326,20 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, SpvDecoration dec, case SpvDecorationLocation: case SpvDecorationComponent: // Location is used for input, output and ray tracing stages. - if (sc == SpvStorageClassStorageBuffer || - sc == SpvStorageClassUniform || - sc == SpvStorageClassUniformConstant || - sc == SpvStorageClassWorkgroup || sc == SpvStorageClassPrivate || - sc == SpvStorageClassFunction) { + if (sc != SpvStorageClassInput && sc != SpvStorageClassOutput && + sc != SpvStorageClassRayPayloadKHR && + sc != SpvStorageClassIncomingRayPayloadKHR && + sc != SpvStorageClassHitAttributeKHR && + sc != SpvStorageClassCallableDataKHR && + sc != SpvStorageClassIncomingCallableDataKHR && + sc != SpvStorageClassShaderRecordBufferKHR) { return _.diag(SPV_ERROR_INVALID_ID, target) << LogStringForDecoration(dec) << " decoration must not be applied to this storage class"; } break; case SpvDecorationIndex: + // Langauge from SPIR-V definition of Index if (sc != SpvStorageClassOutput) { return fail(0) << "must be in the Output storage class"; } @@ -346,8 +349,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, SpvDecoration dec, if (sc != SpvStorageClassStorageBuffer && sc != SpvStorageClassUniform && sc != SpvStorageClassUniformConstant) { - return fail(0) << "must be in the StorageBuffer, Uniform, or " - "UniformConstant storage class"; + return fail(6491) << "must be in the StorageBuffer, Uniform, or " + "UniformConstant storage class"; } break; case SpvDecorationInputAttachmentIndex: diff --git a/3rdparty/spirv-tools/source/val/validate_image.cpp b/3rdparty/spirv-tools/source/val/validate_image.cpp index b12d1e820..c06f34172 100644 --- a/3rdparty/spirv-tools/source/val/validate_image.cpp +++ b/3rdparty/spirv-tools/source/val/validate_image.cpp @@ -869,13 +869,21 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { if (info.dim == SpvDimSubpassData) { if (info.sampled != 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Dim SubpassData requires Sampled to be 2"; + << _.VkErrorID(6214) << "Dim SubpassData requires Sampled to be 2"; } if (info.format != SpvImageFormatUnknown) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Dim SubpassData requires format Unknown"; } + + if (spvIsVulkanEnv(target_env)) { + if (info.arrayed != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(6214) + << "Dim SubpassData requires Arrayed to be 0"; + } + } } // Format and Access Qualifier are also checked elsewhere. @@ -1268,6 +1276,27 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +// Validates anything OpImage*Dref* instruction +spv_result_t ValidateImageDref(ValidationState_t& _, const Instruction* inst, + const ImageTypeInfo& info) { + const uint32_t dref_type = _.GetOperandTypeId(inst, 4); + if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Dref to be of 32-bit float type"; + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (info.dim == SpvDim3D) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4777) + << "In Vulkan, OpImage*Dref* instructions must not use images " + "with a 3D Dim"; + } + } + + return SPV_SUCCESS; +} + spv_result_t ValidateImageDrefLod(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); @@ -1325,11 +1354,7 @@ spv_result_t ValidateImageDrefLod(ValidationState_t& _, << " components, but given only " << actual_coord_size; } - const uint32_t dref_type = _.GetOperandTypeId(inst, 4); - if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Dref to be of 32-bit float type"; - } + if (spv_result_t result = ValidateImageDref(_, inst, info)) return result; if (spv_result_t result = ValidateImageOperands(_, inst, info, /* word_index = */ 7)) @@ -1464,7 +1489,8 @@ spv_result_t ValidateImageGather(ValidationState_t& _, if (info.dim != SpvDim2D && info.dim != SpvDimCube && info.dim != SpvDimRect) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Image 'Dim' cannot be Cube"; + << _.VkErrorID(4777) + << "Expected Image 'Dim' to be 2D, Cube, or Rect"; } const uint32_t coord_type = _.GetOperandTypeId(inst, 3); @@ -1500,11 +1526,7 @@ spv_result_t ValidateImageGather(ValidationState_t& _, } else { assert(opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather); - const uint32_t dref_type = _.GetOperandTypeId(inst, 4); - if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Dref to be of 32-bit float type"; - } + if (spv_result_t result = ValidateImageDref(_, inst, info)) return result; } if (spv_result_t result = diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index 4f3d9cdb7..3cadcfaa8 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -519,20 +519,21 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } - // Vulkan 14.5.1: Check type of PushConstant variables. - // Vulkan 14.5.2: Check type of UniformConstant and Uniform variables. if (spvIsVulkanEnv(_.context()->target_env)) { + // Vulkan Push Constant Interface section: Check type of PushConstant + // variables. if (storage_class == SpvStorageClassPushConstant) { - if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) { + if (pointee->opcode() != SpvOpTypeStruct) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "PushConstant OpVariable '" << _.getIdName(inst->id()) << "' has illegal type.\n" - << "From Vulkan spec, section 14.5.1:\n" - << "Such variables must be typed as OpTypeStruct, " - << "or an array of this type"; + << "From Vulkan spec, Push Constant Interface section:\n" + << "Such variables must be typed as OpTypeStruct"; } } + // Vulkan Descriptor Set Interface: Check type of UniformConstant and + // Uniform variables. if (storage_class == SpvStorageClassUniformConstant) { if (!IsAllowedTypeOrArrayOfSame( _, pointee, @@ -667,7 +668,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) { if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable, '" << _.getIdName(inst->id()) + << _.VkErrorID(4680) << "OpVariable, '" + << _.getIdName(inst->id()) << "', is attempting to create memory for an illegal type, " << "OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only " << "appear as the final member of an OpTypeStruct, thus cannot " @@ -679,6 +681,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class != SpvStorageClassUniform && storage_class != SpvStorageClassUniformConstant) { return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4680) << "For Vulkan with RuntimeDescriptorArrayEXT, a variable " << "containing OpTypeRuntimeArray must have storage class of " << "StorageBuffer, Uniform, or UniformConstant."; @@ -692,25 +695,30 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { // as BufferBlock. if (value_type && value_type->opcode() == SpvOpTypeStruct) { if (DoesStructContainRTA(_, value_type)) { - if (storage_class == SpvStorageClassStorageBuffer) { + if (storage_class == SpvStorageClassStorageBuffer || + storage_class == SpvStorageClassPhysicalStorageBuffer) { if (!_.HasDecoration(value_id, SpvDecorationBlock)) { return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4680) << "For Vulkan, an OpTypeStruct variable containing an " << "OpTypeRuntimeArray must be decorated with Block if it " - << "has storage class StorageBuffer."; + << "has storage class StorageBuffer or " + "PhysicalStorageBuffer."; } } else if (storage_class == SpvStorageClassUniform) { if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) { return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4680) << "For Vulkan, an OpTypeStruct variable containing an " << "OpTypeRuntimeArray must be decorated with BufferBlock " << "if it has storage class Uniform."; } } else { return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4680) << "For Vulkan, OpTypeStruct variables containing " << "OpTypeRuntimeArray must have storage class of " - << "StorageBuffer or Uniform."; + << "StorageBuffer, PhysicalStorageBuffer, or Uniform."; } } } diff --git a/3rdparty/spirv-tools/source/val/validate_type.cpp b/3rdparty/spirv-tools/source/val/validate_type.cpp index 4376b52c6..2aded6165 100644 --- a/3rdparty/spirv-tools/source/val/validate_type.cpp +++ b/3rdparty/spirv-tools/source/val/validate_type.cpp @@ -228,8 +228,8 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { if (spvIsVulkanEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeArray Element Type '" << _.getIdName(element_type_id) - << "' is not valid in " + << _.VkErrorID(4680) << "OpTypeArray Element Type '" + << _.getIdName(element_type_id) << "' is not valid in " << spvLogStringForEnv(_.context()->target_env) << " environments."; } @@ -298,7 +298,7 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, if (spvIsVulkanEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeRuntimeArray Element Type '" + << _.VkErrorID(4680) << "OpTypeRuntimeArray Element Type '" << _.getIdName(element_id) << "' is not valid in " << spvLogStringForEnv(_.context()->target_env) << " environments."; } @@ -373,7 +373,8 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { member_type_index == inst->operands().size() - 1; if (!is_last_member) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "In " << spvLogStringForEnv(_.context()->target_env) + << _.VkErrorID(4680) << "In " + << spvLogStringForEnv(_.context()->target_env) << ", OpTypeRuntimeArray must only be used for the last member " "of an OpTypeStruct"; } diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index 6c170760f..bc2b6ae5f 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -1862,6 +1862,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4677: return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); + case 4680: + return VUID_WRAP( VUID-StandaloneSpirv-OpTypeRuntimeArray-04680); case 4682: return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682); case 6426: @@ -1884,6 +1886,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733); case 4734: return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734); + case 4777: + return VUID_WRAP(VUID-StandaloneSpirv-OpImage-04777); case 4780: return VUID_WRAP(VUID-StandaloneSpirv-Result-04780); case 4915: @@ -1896,6 +1900,10 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Location-04918); case 4919: return VUID_WRAP(VUID-StandaloneSpirv-Location-04919); + case 6214: + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214); + case 6491: + return VUID_WRAP(VUID-StandaloneSpirv-DescriptorSet-06491); default: return ""; // unknown id }