// Copyright (c) 2017 Google Inc. // // 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 <algorithm> #include <cassert> #include <string> #include <tuple> #include <unordered_map> #include <unordered_set> #include <utility> #include <vector> #include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/spirv_validator_options.h" #include "source/util/string_utils.h" #include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { namespace val { namespace { // Distinguish between row and column major matrix layouts. enum MatrixLayout { … }; // A functor for hashing a pair of integers. struct PairHash { … }; // Struct member layout attributes that are inherited through arrays. struct LayoutConstraints { … }; // A type for mapping (struct id, member id) to layout constraints. MemberConstraints; // Returns the array stride of the given array type. uint32_t GetArrayStride(uint32_t array_id, ValidationState_t& vstate) { … } // Returns true if the given structure type has a Block decoration. bool isBlock(uint32_t struct_id, ValidationState_t& vstate) { … } // Returns true if the given ID has the Import LinkageAttributes decoration. bool hasImportLinkageAttribute(uint32_t id, ValidationState_t& vstate) { … } // Returns a vector of all members of a structure. std::vector<uint32_t> getStructMembers(uint32_t struct_id, ValidationState_t& vstate) { … } // Returns a vector of all members of a structure that have specific type. std::vector<uint32_t> getStructMembers(uint32_t struct_id, spv::Op type, ValidationState_t& vstate) { … } // Returns whether the given structure is missing Offset decoration for any // member. Handles also nested structures. bool isMissingOffsetInStruct(uint32_t struct_id, ValidationState_t& vstate) { … } // Rounds x up to the next alignment. Assumes alignment is a power of two. uint32_t align(uint32_t x, uint32_t alignment) { … } // Returns base alignment of struct member. If |roundUp| is true, also // ensure that structs, arrays, and matrices are aligned at least to a // multiple of 16 bytes. (That is, when roundUp is true, this function // returns the *extended* alignment as it's called by the Vulkan spec.) uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, const LayoutConstraints& inherited, MemberConstraints& constraints, ValidationState_t& vstate) { … } // Returns scalar alignment of a type. uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) { … } // Returns size of a struct member. Doesn't include padding at the end of struct // or array. Assumes that in the struct case, all members have offsets. uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited, MemberConstraints& constraints, ValidationState_t& vstate) { … } // A member is defined to improperly straddle if either of the following are // true: // - It is a vector with total size less than or equal to 16 bytes, and has // Offset decorations placing its first byte at F and its last byte at L, where // floor(F / 16) != floor(L / 16). // - It is a vector with total size greater than 16 bytes and has its Offset // decorations placing its first byte at a non-integer multiple of 16. bool hasImproperStraddle(uint32_t id, uint32_t offset, const LayoutConstraints& inherited, MemberConstraints& constraints, ValidationState_t& vstate) { … } // Returns true if |offset| satsifies an alignment to |alignment|. In the case // of |alignment| of zero, the |offset| must also be zero. bool IsAlignedTo(uint32_t offset, uint32_t alignment) { … } // Returns SPV_SUCCESS if the given struct satisfies standard layout rules for // Block or BufferBlocks in Vulkan. Otherwise emits a diagnostic and returns // something other than SPV_SUCCESS. Matrices inherit the specified column // or row major-ness. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, const char* decoration_str, bool blockRules, bool scalar_block_layout, uint32_t incoming_offset, MemberConstraints& constraints, ValidationState_t& vstate) { … } // Returns true if variable or structure id has given decoration. Handles also // nested structures. bool hasDecoration(uint32_t id, spv::Decoration decoration, ValidationState_t& vstate) { … } // Returns true if all ids of given type have a specified decoration. bool checkForRequiredDecoration(uint32_t struct_id, std::function<bool(spv::Decoration)> checker, spv::Op type, ValidationState_t& vstate) { … } spv_result_t CheckLinkageAttrOfFunctions(ValidationState_t& vstate) { … } // Checks whether an imported variable is initialized by this module. spv_result_t CheckImportedVariableInitialization(ValidationState_t& vstate) { … } // Checks whether a builtin variable is valid. spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) { … } // Checks whether proper decorations have been applied to the entry points. spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { … } // Load |constraints| with all the member constraints for structs contained // within the given array type. void ComputeMemberConstraintsForArray(MemberConstraints* constraints, uint32_t array_id, const LayoutConstraints& inherited, ValidationState_t& vstate); // Load |constraints| with all the member constraints for the given struct, // and all its contained structs. void ComputeMemberConstraintsForStruct(MemberConstraints* constraints, uint32_t struct_id, const LayoutConstraints& inherited, ValidationState_t& vstate) { … } void ComputeMemberConstraintsForArray(MemberConstraints* constraints, uint32_t array_id, const LayoutConstraints& inherited, ValidationState_t& vstate) { … } spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { … } // Returns true if |decoration| cannot be applied to the same id more than once. bool AtMostOncePerId(spv::Decoration decoration) { … } // Returns true if |decoration| cannot be applied to the same member more than // once. bool AtMostOncePerMember(spv::Decoration decoration) { … } spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { … } spv_result_t CheckVulkanMemoryModelDeprecatedDecorations( ValidationState_t& vstate) { … } // Returns SPV_SUCCESS if validation rules are satisfied for FPRoundingMode // decorations. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } // Returns SPV_SUCCESS if validation rules are satisfied for the NonWritable // decoration. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. The |inst| parameter is the object being decorated. This must // be called after TypePass and AnnotateCheckDecorationsOfBuffers are called. spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } // Returns SPV_SUCCESS if validation rules are satisfied for Uniform or // UniformId decorations. Otherwise emits a diagnostic and returns something // other than SPV_SUCCESS. Assumes each decoration on a group has been // propagated down to the group members. The |inst| parameter is the object // being decorated. spv_result_t CheckUniformDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } // Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or // NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns // something other than SPV_SUCCESS. Assumes each decoration on a group has been // propagated down to the group members. spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } // Returns SPV_SUCCESS if validation rules are satisfied for the Component // decoration. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. spv_result_t CheckComponentDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } // Returns SPV_SUCCESS if validation rules are satisfied for the Block // decoration. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. spv_result_t CheckBlockDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } spv_result_t CheckLocationDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } spv_result_t CheckRelaxPrecisionDecoration(ValidationState_t& vstate, const Instruction& inst, const Decoration& decoration) { … } #define PASS_OR_BAIL_AT_LINE(X, LINE) … #define PASS_OR_BAIL(X) … // Check rules for decorations where we start from the decoration rather // than the decorated object. Assumes each decoration on a group have been // propagated down to the group members. spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) { … } } // namespace spv_result_t ValidateDecorations(ValidationState_t& vstate) { … } } // namespace val } // namespace spvtools