1 // Copyright (c) 2018 The Khronos Group Inc. 2 // Copyright (c) 2018 Valve Corporation 3 // Copyright (c) 2018 LunarG Inc. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #ifndef LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ 18 #define LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ 19 20 #include "instrument_pass.h" 21 22 namespace spvtools { 23 namespace opt { 24 25 // This class/pass is designed to support the bindless (descriptor indexing) 26 // GPU-assisted validation layer of 27 // https://github.com/KhronosGroup/Vulkan-ValidationLayers. Its internal and 28 // external design may change as the layer evolves. 29 class InstBindlessCheckPass : public InstrumentPass { 30 public: InstBindlessCheckPass(uint32_t shader_id)31 InstBindlessCheckPass(uint32_t shader_id) 32 : InstrumentPass(0, shader_id, true, true) {} 33 34 ~InstBindlessCheckPass() override = default; 35 36 // See optimizer.hpp for pass user documentation. 37 Status Process() override; 38 name()39 const char* name() const override { return "inst-bindless-check-pass"; } 40 41 private: 42 void GenDescCheckCode(BasicBlock::iterator ref_inst_itr, 43 UptrVectorIterator<BasicBlock> ref_block_itr, 44 uint32_t stage_idx, 45 std::vector<std::unique_ptr<BasicBlock>>* new_blocks); 46 47 uint32_t GenDescCheckFunctionId(); 48 49 uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx, 50 uint32_t var_id, uint32_t index_id, 51 uint32_t byte_offset, InstructionBuilder* builder); 52 53 // Analysis data for descriptor reference components, generated by 54 // AnalyzeDescriptorReference. It is necessary and sufficient for further 55 // analysis and regeneration of the reference. 56 typedef struct RefAnalysis { 57 uint32_t desc_load_id{0}; 58 uint32_t image_id{0}; 59 uint32_t load_id{0}; 60 uint32_t ptr_id{0}; 61 uint32_t var_id{0}; 62 uint32_t set{0}; 63 uint32_t binding{0}; 64 uint32_t desc_idx_id{0}; 65 uint32_t strg_class{0}; 66 Instruction* ref_inst{nullptr}; 67 } RefAnalysis; 68 69 // Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major| 70 // for matrix type, or for vector type if vector is |in_matrix|. 71 uint32_t ByteSize(uint32_t ty_id, uint32_t matrix_stride, bool col_major, 72 bool in_matrix); 73 74 // Return stride of type |ty_id| with decoration |stride_deco|. Return 0 75 // if not found 76 uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco); 77 78 // Generate index of last byte referenced by buffer reference |ref| 79 uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder); 80 81 // Clone original image computation starting at |image_id| into |builder|. 82 // This may generate more than one instruction if necessary. 83 uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder); 84 85 // Clone original original reference encapsulated by |ref| into |builder|. 86 // This may generate more than one instruction if necessary. 87 uint32_t CloneOriginalReference(RefAnalysis* ref, 88 InstructionBuilder* builder); 89 90 // If |inst| references through an image, return the id of the image it 91 // references through. Else return 0. 92 uint32_t GetImageId(Instruction* inst); 93 94 // Get pointee type inst of pointer value |ptr_inst|. 95 Instruction* GetPointeeTypeInst(Instruction* ptr_inst); 96 97 // Analyze descriptor reference |ref_inst| and save components into |ref|. 98 // Return true if |ref_inst| is a descriptor reference, false otherwise. 99 bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref); 100 101 // Generate instrumentation code for generic test result |check_id|, starting 102 // with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|. 103 // Generate conditional branch to a valid or invalid branch. Generate valid 104 // block which does original reference |ref|. Generate invalid block which 105 // writes debug error output utilizing |ref|, |error_id|, |length_id| and 106 // |stage_idx|. Generate merge block for valid and invalid branches. Kill 107 // original reference. 108 void GenCheckCode(uint32_t check_id, RefAnalysis* ref, 109 std::vector<std::unique_ptr<BasicBlock>>* new_blocks); 110 111 // Initialize state for instrumenting bindless checking 112 void InitializeInstBindlessCheck(); 113 114 // Apply GenDescIdxCheckCode to every instruction in module. Then apply 115 // GenDescInitCheckCode to every instruction in module. 116 Pass::Status ProcessImpl(); 117 118 // Mapping from variable to descriptor set 119 std::unordered_map<uint32_t, uint32_t> var2desc_set_; 120 121 // Mapping from variable to binding 122 std::unordered_map<uint32_t, uint32_t> var2binding_; 123 124 uint32_t check_desc_func_id_{0}; 125 }; 126 127 } // namespace opt 128 } // namespace spvtools 129 130 #endif // LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ 131