aboutsummaryrefslogtreecommitdiff
path: root/third_party/SPIRV-Tools/source/opt/inst_bindless_check_pass.h
blob: 243cba7671bd615fe4048f656d7218fe55c5fa3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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 shader_id)
      : InstrumentPass(0, shader_id, true, 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);

  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, 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 check_desc_func_id_{0};
};

}  // namespace opt
}  // namespace spvtools

#endif  // LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_