SPIRV-Tools/source/opt/inst_bindless_check_pass.h
Jeremy Gebben daee1e7d34
instrument: Combine descriptor length and init state checking (#5274)
Simplify what we add to user code by moving most of it into a function
that checks both that the descriptor index is in bounds and the
initialization state. Move error logging into this function as
well.

Remove many options to turn off parts of the instrumentation,
because there were far too many permutations to keep working and
test properly.

Combine Buffer and TexBuffer error checking. This requires that VVL
set the length of TexBuffers in the descriptor input state, rather
than relying on the instrumentation code to call OpImageQuerySize.
Since the error log includes the descriptor set and binding numbers
we can use a single OOB error code rather than having 4 per-type
error codes.

Since the error codes are getting renumbered, make them start at 1
rather than 0 so it is easier to determine if the error code was
actually set by the instrumentation.
2023-06-22 09:39:49 -06:00

138 lines
5.4 KiB
C++

// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG 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.
#ifndef LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_
#define LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_
#include "instrument_pass.h"
namespace spvtools {
namespace opt {
// This class/pass is designed to support the bindless (descriptor indexing)
// GPU-assisted validation layer of
// https://github.com/KhronosGroup/Vulkan-ValidationLayers. Its internal and
// external design may change as the layer evolves.
class InstBindlessCheckPass : public InstrumentPass {
public:
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id)
: InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, true) {}
~InstBindlessCheckPass() override = default;
// See optimizer.hpp for pass user documentation.
Status Process() override;
const char* name() const override { return "inst-bindless-check-pass"; }
private:
void GenDescCheckCode(BasicBlock::iterator ref_inst_itr,
UptrVectorIterator<BasicBlock> ref_block_itr,
uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
void SetupInputBufferIds();
uint32_t GenDescCheckFunctionId();
uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx,
uint32_t var_id, uint32_t index_id,
uint32_t byte_offset, InstructionBuilder* builder);
// Analysis data for descriptor reference components, generated by
// AnalyzeDescriptorReference. It is necessary and sufficient for further
// analysis and regeneration of the reference.
typedef struct RefAnalysis {
uint32_t desc_load_id{0};
uint32_t image_id{0};
uint32_t load_id{0};
uint32_t ptr_id{0};
uint32_t var_id{0};
uint32_t set{0};
uint32_t binding{0};
uint32_t desc_idx_id{0};
uint32_t strg_class{0};
Instruction* ref_inst{nullptr};
} RefAnalysis;
// Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major|
// for matrix type, or for vector type if vector is |in_matrix|.
uint32_t ByteSize(uint32_t ty_id, uint32_t matrix_stride, bool col_major,
bool in_matrix);
// Return stride of type |ty_id| with decoration |stride_deco|. Return 0
// if not found
uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco);
// Generate index of last byte referenced by buffer reference |ref|
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 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 necessary.
uint32_t CloneOriginalReference(RefAnalysis* ref,
InstructionBuilder* builder);
// If |inst| references through an image, return the id of the image it
// references through. Else return 0.
uint32_t GetImageId(Instruction* inst);
// Get pointee type inst of pointer value |ptr_inst|.
Instruction* GetPointeeTypeInst(Instruction* ptr_inst);
// Analyze descriptor reference |ref_inst| and save components into |ref|.
// Return true if |ref_inst| is a descriptor reference, false otherwise.
bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref);
// Generate instrumentation code for generic test result |check_id|, starting
// with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|.
// Generate conditional branch to a valid or invalid branch. Generate valid
// block which does original reference |ref|. Generate invalid block which
// writes debug error output utilizing |ref|, |error_id|, |length_id| and
// |stage_idx|. Generate merge block for valid and invalid branches. Kill
// original reference.
void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t offset_id,
uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
// Initialize state for instrumenting bindless checking
void InitializeInstBindlessCheck();
// Apply GenDescIdxCheckCode to every instruction in module. Then apply
// GenDescInitCheckCode to every instruction in module.
Pass::Status ProcessImpl();
// Mapping from variable to descriptor set
std::unordered_map<uint32_t, uint32_t> var2desc_set_;
// Mapping from variable to binding
std::unordered_map<uint32_t, uint32_t> var2binding_;
uint32_t desc_check_func_id_{0};
uint32_t desc_set_type_id_{0};
uint32_t desc_set_ptr_id_{0};
uint32_t input_buffer_struct_id_{0};
uint32_t input_buffer_ptr_id_{0};
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_