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_INSTRUMENT_PASS_H_
18 #define LIBSPIRV_OPT_INSTRUMENT_PASS_H_
19 
20 #include <list>
21 #include <memory>
22 #include <vector>
23 
24 #include "source/opt/ir_builder.h"
25 #include "source/opt/pass.h"
26 #include "spirv-tools/instrument.hpp"
27 
28 // This is a base class to assist in the creation of passes which instrument
29 // shader modules. More specifically, passes which replace instructions with a
30 // larger and more capable set of instructions. Commonly, these new
31 // instructions will add testing of operands and execute different
32 // instructions depending on the outcome, including outputting of debug
33 // information into a buffer created especially for that purpose.
34 //
35 // This class contains helper functions to create an InstProcessFunction,
36 // which is the heart of any derived class implementing a specific
37 // instrumentation pass. It takes an instruction as an argument, decides
38 // if it should be instrumented, and generates code to replace it. This class
39 // also supplies function InstProcessEntryPointCallTree which applies the
40 // InstProcessFunction to every reachable instruction in a module and replaces
41 // the instruction with new instructions if generated.
42 //
43 // Chief among the helper functions are output code generation functions,
44 // used to generate code in the shader which writes data to output buffers
45 // associated with that validation. Currently one such function,
46 // GenDebugStreamWrite, exists. Other such functions may be added in the
47 // future. Each is accompanied by documentation describing the format of
48 // its output buffer.
49 //
50 // A validation pass may read or write multiple buffers. All such buffers
51 // are located in a single debug descriptor set whose index is passed at the
52 // creation of the instrumentation pass. The bindings of the buffers used by
53 // a validation pass are permanantly assigned and fixed and documented by
54 // the kDebugOutput* static consts.
55 
56 namespace spvtools {
57 namespace opt {
58 
59 // Validation Ids
60 // These are used to identify the general validation being done and map to
61 // its output buffers.
62 static const uint32_t kInstValidationIdBindless = 0;
63 
64 class InstrumentPass : public Pass {
65   using cbb_ptr = const BasicBlock*;
66 
67  public:
68   using InstProcessFunction = std::function<void(
69       BasicBlock::iterator, UptrVectorIterator<BasicBlock>, uint32_t, uint32_t,
70       std::vector<std::unique_ptr<BasicBlock>>*)>;
71 
72   ~InstrumentPass() override = default;
73 
GetPreservedAnalyses()74   IRContext::Analysis GetPreservedAnalyses() override {
75     return IRContext::kAnalysisDefUse |
76            IRContext::kAnalysisInstrToBlockMapping |
77            IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
78            IRContext::kAnalysisNameMap | IRContext::kAnalysisBuiltinVarId;
79   }
80 
81  protected:
82   // Create instrumentation pass which utilizes descriptor set |desc_set|
83   // for debug input and output buffers and writes |shader_id| into debug
84   // output records.
InstrumentPass(uint32_t desc_set,uint32_t shader_id,uint32_t validation_id)85   InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id)
86       : Pass(),
87         desc_set_(desc_set),
88         shader_id_(shader_id),
89         validation_id_(validation_id) {}
90 
91   // Initialize state for instrumentation of module by |validation_id|.
92   void InitializeInstrument();
93 
94   // Call |pfn| on all instructions in all functions in the call tree of the
95   // entry points in |module|. If code is generated for an instruction, replace
96   // the instruction's block with the new blocks that are generated. Continue
97   // processing at the top of the last new block.
98   bool InstProcessEntryPointCallTree(InstProcessFunction& pfn);
99 
100   // Move all code in |ref_block_itr| preceding the instruction |ref_inst_itr|
101   // to be instrumented into block |new_blk_ptr|.
102   void MovePreludeCode(BasicBlock::iterator ref_inst_itr,
103                        UptrVectorIterator<BasicBlock> ref_block_itr,
104                        std::unique_ptr<BasicBlock>* new_blk_ptr);
105 
106   // Move all code in |ref_block_itr| succeeding the instruction |ref_inst_itr|
107   // to be instrumented into block |new_blk_ptr|.
108   void MovePostludeCode(UptrVectorIterator<BasicBlock> ref_block_itr,
109                         std::unique_ptr<BasicBlock>* new_blk_ptr);
110 
111   // Generate instructions in |builder| which will atomically fetch and
112   // increment the size of the debug output buffer stream of the current
113   // validation and write a record to the end of the stream, if enough space
114   // in the buffer remains. The record will contain the index of the function
115   // and instruction within that function |func_idx, instruction_idx| which
116   // generated the record. It will also contain additional information to
117   // identify the instance of the shader, depending on the stage |stage_idx|
118   // of the shader. Finally, the record will contain validation-specific
119   // data contained in |validation_ids| which will identify the validation
120   // error as well as the values involved in the error.
121   //
122   // The output buffer binding written to by the code generated by the function
123   // is determined by the validation id specified when each specific
124   // instrumentation pass is created.
125   //
126   // The output buffer is a sequence of 32-bit values with the following
127   // format (where all elements are unsigned 32-bit unless otherwise noted):
128   //
129   //     Size
130   //     Record0
131   //     Record1
132   //     Record2
133   //     ...
134   //
135   // Size is the number of 32-bit values that have been written or
136   // attempted to be written to the output buffer, excluding the Size. It is
137   // initialized to 0. If the size of attempts to write the buffer exceeds
138   // the actual size of the buffer, it is possible that this field can exceed
139   // the actual size of the buffer.
140   //
141   // Each Record* is a variable-length sequence of 32-bit values with the
142   // following format defined using static const offsets in the .cpp file:
143   //
144   //     Record Size
145   //     Shader ID
146   //     Instruction Index
147   //     Stage
148   //     Stage-specific Word 0
149   //     Stage-specific Word 1
150   //     Validation Error Code
151   //     Validation-specific Word 0
152   //     Validation-specific Word 1
153   //     Validation-specific Word 2
154   //     ...
155   //
156   // Each record consists of three subsections: members common across all
157   // validation, members specific to the stage, and members specific to a
158   // validation.
159   //
160   // The Record Size is the number of 32-bit words in the record, including
161   // the Record Size word.
162   //
163   // Shader ID is a value that identifies which shader has generated the
164   // validation error. It is passed when the instrumentation pass is created.
165   //
166   // The Instruction Index is the position of the instruction within the
167   // SPIR-V file which is in error.
168   //
169   // The Stage is the pipeline stage which has generated the error as defined
170   // by the SpvExecutionModel_ enumeration. This is used to interpret the
171   // following Stage-specific words.
172   //
173   // The Stage-specific Words identify which invocation of the shader generated
174   // the error. Every stage will write two words, although in some cases the
175   // second word is unused and so zero is written. Vertex shaders will write
176   // the Vertex and Instance ID. Fragment shaders will write FragCoord.xy.
177   // Compute shaders will write the Global Invocation ID and zero (unused).
178   // Both tesselation shaders will write the Invocation Id and zero (unused).
179   // The geometry shader will write the Primitive ID and Invocation ID.
180   //
181   // The Validation Error Code specifies the exact error which has occurred.
182   // These are enumerated with the kInstError* static consts. This allows
183   // multiple validation layers to use the same, single output buffer.
184   //
185   // The Validation-specific Words are a validation-specific number of 32-bit
186   // words which give further information on the validation error that
187   // occurred. These are documented further in each file containing the
188   // validation-specific class which derives from this base class.
189   //
190   // Because the code that is generated checks against the size of the buffer
191   // before writing, the size of the debug out buffer can be used by the
192   // validation layer to control the number of error records that are written.
193   void GenDebugStreamWrite(uint32_t instruction_idx, uint32_t stage_idx,
194                            const std::vector<uint32_t>& validation_ids,
195                            InstructionBuilder* builder);
196 
197   // Generate code to cast |value_id| to unsigned, if needed. Return
198   // an id to the unsigned equivalent.
199   uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder);
200 
201   // Return new label.
202   std::unique_ptr<Instruction> NewLabel(uint32_t label_id);
203 
204   // Return id for 32-bit unsigned type
205   uint32_t GetUintId();
206 
207   // Return id for 32-bit unsigned type
208   uint32_t GetBoolId();
209 
210   // Return id for void type
211   uint32_t GetVoidId();
212 
213   // Return id for output buffer uint type
214   uint32_t GetOutputBufferUintPtrId();
215 
216   // Return binding for output buffer for current validation.
217   uint32_t GetOutputBufferBinding();
218 
219   // Return id for debug output buffer
220   uint32_t GetOutputBufferId();
221 
222   // Return id for v4float type
223   uint32_t GetVec4FloatId();
224 
225   // Return id for v4uint type
226   uint32_t GetVec4UintId();
227 
228   // Return id for output function. Define if it doesn't exist with
229   // |val_spec_arg_cnt| validation-specific uint32 arguments.
230   uint32_t GetStreamWriteFunctionId(uint32_t stage_idx,
231                                     uint32_t val_spec_param_cnt);
232 
233   // Apply instrumentation function |pfn| to every instruction in |func|.
234   // If code is generated for an instruction, replace the instruction's
235   // block with the new blocks that are generated. Continue processing at the
236   // top of the last new block.
237   bool InstrumentFunction(Function* func, uint32_t stage_idx,
238                           InstProcessFunction& pfn);
239 
240   // Call |pfn| on all functions in the call tree of the function
241   // ids in |roots|.
242   bool InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
243                                     std::queue<uint32_t>* roots,
244                                     uint32_t stage_idx);
245 
246   // Gen code into |builder| to write |field_value_id| into debug output
247   // buffer at |base_offset_id| + |field_offset|.
248   void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset,
249                                uint32_t field_value_id,
250                                InstructionBuilder* builder);
251 
252   // Generate instructions into |builder| which will write the members
253   // of the debug output record common for all stages and validations at
254   // |base_off|.
255   void GenCommonStreamWriteCode(uint32_t record_sz, uint32_t instruction_idx,
256                                 uint32_t stage_idx, uint32_t base_off,
257                                 InstructionBuilder* builder);
258 
259   // Generate instructions into |builder| which will write
260   // |uint_frag_coord_id| at |component| of the record at |base_offset_id| of
261   // the debug output buffer .
262   void GenFragCoordEltDebugOutputCode(uint32_t base_offset_id,
263                                       uint32_t uint_frag_coord_id,
264                                       uint32_t component,
265                                       InstructionBuilder* builder);
266 
267   // Generate instructions into |builder| which will load the uint |builtin_id|
268   // and write it into the debug output buffer at |base_off| + |builtin_off|.
269   void GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off,
270                             uint32_t base_off, InstructionBuilder* builder);
271 
272   // Generate instructions into |builder| which will write a uint null into
273   // the debug output buffer at |base_off| + |builtin_off|.
274   void GenUintNullOutputCode(uint32_t field_off, uint32_t base_off,
275                              InstructionBuilder* builder);
276 
277   // Generate instructions into |builder| which will write the |stage_idx|-
278   // specific members of the debug output stream at |base_off|.
279   void GenStageStreamWriteCode(uint32_t stage_idx, uint32_t base_off,
280                                InstructionBuilder* builder);
281 
282   // Return true if instruction must be in the same block that its result
283   // is used.
284   bool IsSameBlockOp(const Instruction* inst) const;
285 
286   // Clone operands which must be in same block as consumer instructions.
287   // Look in same_blk_pre for instructions that need cloning. Look in
288   // same_blk_post for instructions already cloned. Add cloned instruction
289   // to same_blk_post.
290   void CloneSameBlockOps(
291       std::unique_ptr<Instruction>* inst,
292       std::unordered_map<uint32_t, uint32_t>* same_blk_post,
293       std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
294       std::unique_ptr<BasicBlock>* block_ptr);
295 
296   // Update phis in succeeding blocks to point to new last block
297   void UpdateSucceedingPhis(
298       std::vector<std::unique_ptr<BasicBlock>>& new_blocks);
299 
300   // Debug descriptor set index
301   uint32_t desc_set_;
302 
303   // Shader module ID written into output record
304   uint32_t shader_id_;
305 
306   // Map from function id to function pointer.
307   std::unordered_map<uint32_t, Function*> id2function_;
308 
309   // Map from block's label id to block. TODO(dnovillo): This is superfluous wrt
310   // CFG. It has functionality not present in CFG. Consolidate.
311   std::unordered_map<uint32_t, BasicBlock*> id2block_;
312 
313   // Map from function's position index to the offset of its first instruction
314   std::unordered_map<uint32_t, uint32_t> funcIdx2offset_;
315 
316   // result id for OpConstantFalse
317   uint32_t validation_id_;
318 
319   // id for output buffer variable
320   uint32_t output_buffer_id_;
321 
322   // type id for output buffer element
323   uint32_t output_buffer_uint_ptr_id_;
324 
325   // id for debug output function
326   uint32_t output_func_id_;
327 
328   // param count for output function
329   uint32_t output_func_param_cnt_;
330 
331   // id for v4float type
332   uint32_t v4float_id_;
333 
334   // id for v4float type
335   uint32_t v4uint_id_;
336 
337   // id for 32-bit unsigned type
338   uint32_t uint_id_;
339 
340   // id for bool type
341   uint32_t bool_id_;
342 
343   // id for void type
344   uint32_t void_id_;
345 
346   // Pre-instrumentation same-block insts
347   std::unordered_map<uint32_t, Instruction*> same_block_pre_;
348 
349   // Post-instrumentation same-block op ids
350   std::unordered_map<uint32_t, uint32_t> same_block_post_;
351 };
352 
353 }  // namespace opt
354 }  // namespace spvtools
355 
356 #endif  // LIBSPIRV_OPT_INSTRUMENT_PASS_H_
357