• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "instrument_pass.h"
18 
19 #include "source/cfa.h"
20 #include "source/spirv_constant.h"
21 
22 namespace {
23 
24 // Common Parameter Positions
25 static const int kInstCommonParamInstIdx = 0;
26 static const int kInstCommonParamCnt = 1;
27 
28 // Indices of operands in SPIR-V instructions
29 static const int kEntryPointExecutionModelInIdx = 0;
30 static const int kEntryPointFunctionIdInIdx = 1;
31 
32 }  // anonymous namespace
33 
34 namespace spvtools {
35 namespace opt {
36 
MovePreludeCode(BasicBlock::iterator ref_inst_itr,UptrVectorIterator<BasicBlock> ref_block_itr,std::unique_ptr<BasicBlock> * new_blk_ptr)37 void InstrumentPass::MovePreludeCode(
38     BasicBlock::iterator ref_inst_itr,
39     UptrVectorIterator<BasicBlock> ref_block_itr,
40     std::unique_ptr<BasicBlock>* new_blk_ptr) {
41   same_block_pre_.clear();
42   same_block_post_.clear();
43   // Initialize new block. Reuse label from original block.
44   new_blk_ptr->reset(new BasicBlock(std::move(ref_block_itr->GetLabel())));
45   // Move contents of original ref block up to ref instruction.
46   for (auto cii = ref_block_itr->begin(); cii != ref_inst_itr;
47        cii = ref_block_itr->begin()) {
48     Instruction* inst = &*cii;
49     inst->RemoveFromList();
50     std::unique_ptr<Instruction> mv_ptr(inst);
51     // Remember same-block ops for possible regeneration.
52     if (IsSameBlockOp(&*mv_ptr)) {
53       auto* sb_inst_ptr = mv_ptr.get();
54       same_block_pre_[mv_ptr->result_id()] = sb_inst_ptr;
55     }
56     (*new_blk_ptr)->AddInstruction(std::move(mv_ptr));
57   }
58 }
59 
MovePostludeCode(UptrVectorIterator<BasicBlock> ref_block_itr,BasicBlock * new_blk_ptr)60 void InstrumentPass::MovePostludeCode(
61     UptrVectorIterator<BasicBlock> ref_block_itr, BasicBlock* new_blk_ptr) {
62   // new_blk_ptr->reset(new BasicBlock(NewLabel(ref_block_itr->id())));
63   // Move contents of original ref block.
64   for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end();
65        cii = ref_block_itr->begin()) {
66     Instruction* inst = &*cii;
67     inst->RemoveFromList();
68     std::unique_ptr<Instruction> mv_inst(inst);
69     // Regenerate any same-block instruction that has not been seen in the
70     // current block.
71     if (same_block_pre_.size() > 0) {
72       CloneSameBlockOps(&mv_inst, &same_block_post_, &same_block_pre_,
73                         new_blk_ptr);
74       // Remember same-block ops in this block.
75       if (IsSameBlockOp(&*mv_inst)) {
76         const uint32_t rid = mv_inst->result_id();
77         same_block_post_[rid] = rid;
78       }
79     }
80     new_blk_ptr->AddInstruction(std::move(mv_inst));
81   }
82 }
83 
NewLabel(uint32_t label_id)84 std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
85   std::unique_ptr<Instruction> newLabel(
86       new Instruction(context(), SpvOpLabel, 0, label_id, {}));
87   get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel);
88   return newLabel;
89 }
90 
NewName(uint32_t id,const std::string & name_str)91 std::unique_ptr<Instruction> InstrumentPass::NewName(
92     uint32_t id, const std::string& name_str) {
93   std::unique_ptr<Instruction> new_name(new Instruction(
94       context(), SpvOpName, 0, 0,
95       std::initializer_list<Operand>{
96           {SPV_OPERAND_TYPE_ID, {id}},
97           {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
98 
99   return new_name;
100 }
101 
NewGlobalName(uint32_t id,const std::string & name_str)102 std::unique_ptr<Instruction> InstrumentPass::NewGlobalName(
103     uint32_t id, const std::string& name_str) {
104   std::string prefixed_name;
105   switch (validation_id_) {
106     case kInstValidationIdBindless:
107       prefixed_name = "inst_bindless_";
108       break;
109     case kInstValidationIdBuffAddr:
110       prefixed_name = "inst_buff_addr_";
111       break;
112     case kInstValidationIdDebugPrintf:
113       prefixed_name = "inst_printf_";
114       break;
115     default:
116       assert(false);  // add new instrumentation pass here
117       prefixed_name = "inst_pass_";
118       break;
119   }
120   prefixed_name += name_str;
121   return NewName(id, prefixed_name);
122 }
123 
NewMemberName(uint32_t id,uint32_t member_index,const std::string & name_str)124 std::unique_ptr<Instruction> InstrumentPass::NewMemberName(
125     uint32_t id, uint32_t member_index, const std::string& name_str) {
126   std::unique_ptr<Instruction> new_name(new Instruction(
127       context(), SpvOpMemberName, 0, 0,
128       std::initializer_list<Operand>{
129           {SPV_OPERAND_TYPE_ID, {id}},
130           {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
131           {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
132 
133   return new_name;
134 }
135 
Gen32BitCvtCode(uint32_t val_id,InstructionBuilder * builder)136 uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
137                                          InstructionBuilder* builder) {
138   // Convert integer value to 32-bit if necessary
139   analysis::TypeManager* type_mgr = context()->get_type_mgr();
140   uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_id)->type_id();
141   analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
142   if (val_ty->width() == 32) return val_id;
143   bool is_signed = val_ty->IsSigned();
144   analysis::Integer val_32b_ty(32, is_signed);
145   analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty);
146   uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty);
147   if (is_signed)
148     return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpSConvert, val_id)
149         ->result_id();
150   else
151     return builder->AddUnaryOp(val_32b_reg_ty_id, SpvOpUConvert, val_id)
152         ->result_id();
153 }
154 
GenUintCastCode(uint32_t val_id,InstructionBuilder * builder)155 uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
156                                          InstructionBuilder* builder) {
157   // Convert value to 32-bit if necessary
158   uint32_t val_32b_id = Gen32BitCvtCode(val_id, builder);
159   // Cast value to unsigned if necessary
160   analysis::TypeManager* type_mgr = context()->get_type_mgr();
161   uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id();
162   analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
163   if (!val_ty->IsSigned()) return val_32b_id;
164   return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_32b_id)
165       ->result_id();
166 }
167 
GenDebugOutputFieldCode(uint32_t base_offset_id,uint32_t field_offset,uint32_t field_value_id,InstructionBuilder * builder)168 void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
169                                              uint32_t field_offset,
170                                              uint32_t field_value_id,
171                                              InstructionBuilder* builder) {
172   // Cast value to 32-bit unsigned if necessary
173   uint32_t val_id = GenUintCastCode(field_value_id, builder);
174   // Store value
175   Instruction* data_idx_inst =
176       builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id,
177                            builder->GetUintConstantId(field_offset));
178   uint32_t buf_id = GetOutputBufferId();
179   uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
180   Instruction* achain_inst =
181       builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
182                             builder->GetUintConstantId(kDebugOutputDataOffset),
183                             data_idx_inst->result_id());
184   (void)builder->AddBinaryOp(0, SpvOpStore, achain_inst->result_id(), val_id);
185 }
186 
GenCommonStreamWriteCode(uint32_t record_sz,uint32_t inst_id,uint32_t stage_idx,uint32_t base_offset_id,InstructionBuilder * builder)187 void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
188                                               uint32_t inst_id,
189                                               uint32_t stage_idx,
190                                               uint32_t base_offset_id,
191                                               InstructionBuilder* builder) {
192   // Store record size
193   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
194                           builder->GetUintConstantId(record_sz), builder);
195   // Store Shader Id
196   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
197                           builder->GetUintConstantId(shader_id_), builder);
198   // Store Instruction Idx
199   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
200                           builder);
201   // Store Stage Idx
202   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
203                           builder->GetUintConstantId(stage_idx), builder);
204 }
205 
GenFragCoordEltDebugOutputCode(uint32_t base_offset_id,uint32_t uint_frag_coord_id,uint32_t element,InstructionBuilder * builder)206 void InstrumentPass::GenFragCoordEltDebugOutputCode(
207     uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
208     InstructionBuilder* builder) {
209   Instruction* element_val_inst = builder->AddIdLiteralOp(
210       GetUintId(), SpvOpCompositeExtract, uint_frag_coord_id, element);
211   GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
212                           element_val_inst->result_id(), builder);
213 }
214 
GenVarLoad(uint32_t var_id,InstructionBuilder * builder)215 uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
216                                     InstructionBuilder* builder) {
217   Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
218   uint32_t type_id = GetPointeeTypeId(var_inst);
219   Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id);
220   return load_inst->result_id();
221 }
222 
GenBuiltinOutputCode(uint32_t builtin_id,uint32_t builtin_off,uint32_t base_offset_id,InstructionBuilder * builder)223 void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
224                                           uint32_t builtin_off,
225                                           uint32_t base_offset_id,
226                                           InstructionBuilder* builder) {
227   // Load and store builtin
228   uint32_t load_id = GenVarLoad(builtin_id, builder);
229   GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
230 }
231 
GenStageStreamWriteCode(uint32_t stage_idx,uint32_t base_offset_id,InstructionBuilder * builder)232 void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
233                                              uint32_t base_offset_id,
234                                              InstructionBuilder* builder) {
235   // TODO(greg-lunarg): Add support for all stages
236   switch (stage_idx) {
237     case SpvExecutionModelVertex: {
238       // Load and store VertexId and InstanceId
239       GenBuiltinOutputCode(
240           context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex),
241           kInstVertOutVertexIndex, base_offset_id, builder);
242       GenBuiltinOutputCode(
243           context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex),
244           kInstVertOutInstanceIndex, base_offset_id, builder);
245     } break;
246     case SpvExecutionModelGLCompute:
247     case SpvExecutionModelTaskNV:
248     case SpvExecutionModelMeshNV:
249     case SpvExecutionModelTaskEXT:
250     case SpvExecutionModelMeshEXT: {
251       // Load and store GlobalInvocationId.
252       uint32_t load_id = GenVarLoad(
253           context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId),
254           builder);
255       Instruction* x_inst = builder->AddIdLiteralOp(
256           GetUintId(), SpvOpCompositeExtract, load_id, 0);
257       Instruction* y_inst = builder->AddIdLiteralOp(
258           GetUintId(), SpvOpCompositeExtract, load_id, 1);
259       Instruction* z_inst = builder->AddIdLiteralOp(
260           GetUintId(), SpvOpCompositeExtract, load_id, 2);
261       GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
262                               x_inst->result_id(), builder);
263       GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
264                               y_inst->result_id(), builder);
265       GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
266                               z_inst->result_id(), builder);
267     } break;
268     case SpvExecutionModelGeometry: {
269       // Load and store PrimitiveId and InvocationId.
270       GenBuiltinOutputCode(
271           context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
272           kInstGeomOutPrimitiveId, base_offset_id, builder);
273       GenBuiltinOutputCode(
274           context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
275           kInstGeomOutInvocationId, base_offset_id, builder);
276     } break;
277     case SpvExecutionModelTessellationControl: {
278       // Load and store InvocationId and PrimitiveId
279       GenBuiltinOutputCode(
280           context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
281           kInstTessCtlOutInvocationId, base_offset_id, builder);
282       GenBuiltinOutputCode(
283           context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
284           kInstTessCtlOutPrimitiveId, base_offset_id, builder);
285     } break;
286     case SpvExecutionModelTessellationEvaluation: {
287       // Load and store PrimitiveId and TessCoord.uv
288       GenBuiltinOutputCode(
289           context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
290           kInstTessEvalOutPrimitiveId, base_offset_id, builder);
291       uint32_t load_id = GenVarLoad(
292           context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder);
293       Instruction* uvec3_cast_inst =
294           builder->AddUnaryOp(GetVec3UintId(), SpvOpBitcast, load_id);
295       uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
296       Instruction* u_inst = builder->AddIdLiteralOp(
297           GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 0);
298       Instruction* v_inst = builder->AddIdLiteralOp(
299           GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 1);
300       GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
301                               u_inst->result_id(), builder);
302       GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
303                               v_inst->result_id(), builder);
304     } break;
305     case SpvExecutionModelFragment: {
306       // Load FragCoord and convert to Uint
307       Instruction* frag_coord_inst = builder->AddUnaryOp(
308           GetVec4FloatId(), SpvOpLoad,
309           context()->GetBuiltinInputVarId(SpvBuiltInFragCoord));
310       Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
311           GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
312       for (uint32_t u = 0; u < 2u; ++u)
313         GenFragCoordEltDebugOutputCode(
314             base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
315     } break;
316     case SpvExecutionModelRayGenerationNV:
317     case SpvExecutionModelIntersectionNV:
318     case SpvExecutionModelAnyHitNV:
319     case SpvExecutionModelClosestHitNV:
320     case SpvExecutionModelMissNV:
321     case SpvExecutionModelCallableNV: {
322       // Load and store LaunchIdNV.
323       uint32_t launch_id = GenVarLoad(
324           context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder);
325       Instruction* x_launch_inst = builder->AddIdLiteralOp(
326           GetUintId(), SpvOpCompositeExtract, launch_id, 0);
327       Instruction* y_launch_inst = builder->AddIdLiteralOp(
328           GetUintId(), SpvOpCompositeExtract, launch_id, 1);
329       Instruction* z_launch_inst = builder->AddIdLiteralOp(
330           GetUintId(), SpvOpCompositeExtract, launch_id, 2);
331       GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
332                               x_launch_inst->result_id(), builder);
333       GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
334                               y_launch_inst->result_id(), builder);
335       GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
336                               z_launch_inst->result_id(), builder);
337     } break;
338     default: { assert(false && "unsupported stage"); } break;
339   }
340 }
341 
GenDebugStreamWrite(uint32_t instruction_idx,uint32_t stage_idx,const std::vector<uint32_t> & validation_ids,InstructionBuilder * builder)342 void InstrumentPass::GenDebugStreamWrite(
343     uint32_t instruction_idx, uint32_t stage_idx,
344     const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
345   // Call debug output function. Pass func_idx, instruction_idx and
346   // validation ids as args.
347   uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
348   uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt);
349   std::vector<uint32_t> args = {output_func_id,
350                                 builder->GetUintConstantId(instruction_idx)};
351   (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
352   (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
353 }
354 
AllConstant(const std::vector<uint32_t> & ids)355 bool InstrumentPass::AllConstant(const std::vector<uint32_t>& ids) {
356   for (auto& id : ids) {
357     Instruction* id_inst = context()->get_def_use_mgr()->GetDef(id);
358     if (!spvOpcodeIsConstant(id_inst->opcode())) return false;
359   }
360   return true;
361 }
362 
GenDebugDirectRead(const std::vector<uint32_t> & offset_ids,InstructionBuilder * ref_builder)363 uint32_t InstrumentPass::GenDebugDirectRead(
364     const std::vector<uint32_t>& offset_ids, InstructionBuilder* ref_builder) {
365   // Call debug input function. Pass func_idx and offset ids as args.
366   uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
367   uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
368   std::vector<uint32_t> args = {input_func_id};
369   (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end());
370   // If optimizing direct reads and the call has already been generated,
371   // use its result
372   if (opt_direct_reads_) {
373     uint32_t res_id = call2id_[args];
374     if (res_id != 0) return res_id;
375   }
376   // If the offsets are all constants, the call can be moved to the first block
377   // of the function where its result can be reused. One example where this is
378   // profitable is for uniform buffer references, of which there are often many.
379   InstructionBuilder builder(ref_builder->GetContext(),
380                              &*ref_builder->GetInsertPoint(),
381                              ref_builder->GetPreservedAnalysis());
382   bool insert_in_first_block = opt_direct_reads_ && AllConstant(offset_ids);
383   if (insert_in_first_block) {
384     Instruction* insert_before = &*curr_func_->begin()->tail();
385     builder.SetInsertPoint(insert_before);
386   }
387   uint32_t res_id =
388       builder.AddNaryOp(GetUintId(), SpvOpFunctionCall, args)->result_id();
389   if (insert_in_first_block) call2id_[args] = res_id;
390   return res_id;
391 }
392 
IsSameBlockOp(const Instruction * inst) const393 bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
394   return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
395 }
396 
CloneSameBlockOps(std::unique_ptr<Instruction> * inst,std::unordered_map<uint32_t,uint32_t> * same_blk_post,std::unordered_map<uint32_t,Instruction * > * same_blk_pre,BasicBlock * block_ptr)397 void InstrumentPass::CloneSameBlockOps(
398     std::unique_ptr<Instruction>* inst,
399     std::unordered_map<uint32_t, uint32_t>* same_blk_post,
400     std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
401     BasicBlock* block_ptr) {
402   bool changed = false;
403   (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed,
404                         this](uint32_t* iid) {
405     const auto map_itr = (*same_blk_post).find(*iid);
406     if (map_itr == (*same_blk_post).end()) {
407       const auto map_itr2 = (*same_blk_pre).find(*iid);
408       if (map_itr2 != (*same_blk_pre).end()) {
409         // Clone pre-call same-block ops, map result id.
410         const Instruction* in_inst = map_itr2->second;
411         std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
412         const uint32_t rid = sb_inst->result_id();
413         const uint32_t nid = this->TakeNextId();
414         get_decoration_mgr()->CloneDecorations(rid, nid);
415         sb_inst->SetResultId(nid);
416         get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst);
417         (*same_blk_post)[rid] = nid;
418         *iid = nid;
419         changed = true;
420         CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
421         block_ptr->AddInstruction(std::move(sb_inst));
422       }
423     } else {
424       // Reset same-block op operand if necessary
425       if (*iid != map_itr->second) {
426         *iid = map_itr->second;
427         changed = true;
428       }
429     }
430   });
431   if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst);
432 }
433 
UpdateSucceedingPhis(std::vector<std::unique_ptr<BasicBlock>> & new_blocks)434 void InstrumentPass::UpdateSucceedingPhis(
435     std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
436   const auto first_blk = new_blocks.begin();
437   const auto last_blk = new_blocks.end() - 1;
438   const uint32_t first_id = (*first_blk)->id();
439   const uint32_t last_id = (*last_blk)->id();
440   const BasicBlock& const_last_block = *last_blk->get();
441   const_last_block.ForEachSuccessorLabel(
442       [&first_id, &last_id, this](const uint32_t succ) {
443         BasicBlock* sbp = this->id2block_[succ];
444         sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
445           bool changed = false;
446           phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
447             if (*id == first_id) {
448               *id = last_id;
449               changed = true;
450             }
451           });
452           if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
453         });
454       });
455 }
456 
GetOutputBufferPtrId()457 uint32_t InstrumentPass::GetOutputBufferPtrId() {
458   if (output_buffer_ptr_id_ == 0) {
459     output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
460         GetUintId(), SpvStorageClassStorageBuffer);
461   }
462   return output_buffer_ptr_id_;
463 }
464 
GetInputBufferTypeId()465 uint32_t InstrumentPass::GetInputBufferTypeId() {
466   return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id()
467                                                        : GetUintId();
468 }
469 
GetInputBufferPtrId()470 uint32_t InstrumentPass::GetInputBufferPtrId() {
471   if (input_buffer_ptr_id_ == 0) {
472     input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
473         GetInputBufferTypeId(), SpvStorageClassStorageBuffer);
474   }
475   return input_buffer_ptr_id_;
476 }
477 
GetOutputBufferBinding()478 uint32_t InstrumentPass::GetOutputBufferBinding() {
479   switch (validation_id_) {
480     case kInstValidationIdBindless:
481       return kDebugOutputBindingStream;
482     case kInstValidationIdBuffAddr:
483       return kDebugOutputBindingStream;
484     case kInstValidationIdDebugPrintf:
485       return kDebugOutputPrintfStream;
486     default:
487       assert(false && "unexpected validation id");
488   }
489   return 0;
490 }
491 
GetInputBufferBinding()492 uint32_t InstrumentPass::GetInputBufferBinding() {
493   switch (validation_id_) {
494     case kInstValidationIdBindless:
495       return kDebugInputBindingBindless;
496     case kInstValidationIdBuffAddr:
497       return kDebugInputBindingBuffAddr;
498     default:
499       assert(false && "unexpected validation id");
500   }
501   return 0;
502 }
503 
GetUintXRuntimeArrayType(uint32_t width,analysis::Type ** rarr_ty)504 analysis::Type* InstrumentPass::GetUintXRuntimeArrayType(
505     uint32_t width, analysis::Type** rarr_ty) {
506   if (*rarr_ty == nullptr) {
507     analysis::DecorationManager* deco_mgr = get_decoration_mgr();
508     analysis::TypeManager* type_mgr = context()->get_type_mgr();
509     analysis::Integer uint_ty(width, false);
510     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
511     analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty);
512     *rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp);
513     uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(*rarr_ty);
514     // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
515     // a block, and will therefore be decorated with an ArrayStride. Therefore
516     // the undecorated type returned here will not be pre-existing and can
517     // safely be decorated. Since this type is now decorated, it is out of
518     // sync with the TypeManager and therefore the TypeManager must be
519     // invalidated after this pass.
520     assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
521            "used RuntimeArray type returned");
522     deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride,
523                                width / 8u);
524   }
525   return *rarr_ty;
526 }
527 
GetUintRuntimeArrayType(uint32_t width)528 analysis::Type* InstrumentPass::GetUintRuntimeArrayType(uint32_t width) {
529   analysis::Type** rarr_ty =
530       (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_;
531   return GetUintXRuntimeArrayType(width, rarr_ty);
532 }
533 
AddStorageBufferExt()534 void InstrumentPass::AddStorageBufferExt() {
535   if (storage_buffer_ext_defined_) return;
536   if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
537     context()->AddExtension("SPV_KHR_storage_buffer_storage_class");
538   }
539   storage_buffer_ext_defined_ = true;
540 }
541 
542 // Return id for output buffer
GetOutputBufferId()543 uint32_t InstrumentPass::GetOutputBufferId() {
544   if (output_buffer_id_ == 0) {
545     // If not created yet, create one
546     analysis::DecorationManager* deco_mgr = get_decoration_mgr();
547     analysis::TypeManager* type_mgr = context()->get_type_mgr();
548     analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
549     analysis::Integer uint_ty(32, false);
550     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
551     analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty});
552     analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
553     uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
554     // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
555     // must be a block, and will therefore be decorated with Block. Therefore
556     // the undecorated type returned here will not be pre-existing and can
557     // safely be decorated. Since this type is now decorated, it is out of
558     // sync with the TypeManager and therefore the TypeManager must be
559     // invalidated after this pass.
560     assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
561            "used struct type returned");
562     deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
563     deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
564                                   SpvDecorationOffset, 0);
565     deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
566                                   SpvDecorationOffset, 4);
567     uint32_t obufTyPtrId_ =
568         type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer);
569     output_buffer_id_ = TakeNextId();
570     std::unique_ptr<Instruction> newVarOp(new Instruction(
571         context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_,
572         {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
573           {SpvStorageClassStorageBuffer}}}));
574     context()->AddGlobalValue(std::move(newVarOp));
575     context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
576     context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "written_count"));
577     context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "data"));
578     context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
579     deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet,
580                                desc_set_);
581     deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
582                                GetOutputBufferBinding());
583     AddStorageBufferExt();
584     if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
585       // Add the new buffer to all entry points.
586       for (auto& entry : get_module()->entry_points()) {
587         entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
588         context()->AnalyzeUses(&entry);
589       }
590     }
591   }
592   return output_buffer_id_;
593 }
594 
GetInputBufferId()595 uint32_t InstrumentPass::GetInputBufferId() {
596   if (input_buffer_id_ == 0) {
597     // If not created yet, create one
598     analysis::DecorationManager* deco_mgr = get_decoration_mgr();
599     analysis::TypeManager* type_mgr = context()->get_type_mgr();
600     uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u;
601     analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width);
602     analysis::Struct buf_ty({reg_uint_rarr_ty});
603     analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
604     uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
605     // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
606     // must be a block, and will therefore be decorated with Block. Therefore
607     // the undecorated type returned here will not be pre-existing and can
608     // safely be decorated. Since this type is now decorated, it is out of
609     // sync with the TypeManager and therefore the TypeManager must be
610     // invalidated after this pass.
611     assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
612            "used struct type returned");
613     deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock);
614     deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0);
615     uint32_t ibufTyPtrId_ =
616         type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer);
617     input_buffer_id_ = TakeNextId();
618     std::unique_ptr<Instruction> newVarOp(new Instruction(
619         context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_,
620         {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
621           {SpvStorageClassStorageBuffer}}}));
622     context()->AddGlobalValue(std::move(newVarOp));
623     context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer"));
624     context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data"));
625     context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
626     deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet,
627                                desc_set_);
628     deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding,
629                                GetInputBufferBinding());
630     AddStorageBufferExt();
631     if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
632       // Add the new buffer to all entry points.
633       for (auto& entry : get_module()->entry_points()) {
634         entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
635         context()->AnalyzeUses(&entry);
636       }
637     }
638   }
639   return input_buffer_id_;
640 }
641 
GetFloatId()642 uint32_t InstrumentPass::GetFloatId() {
643   if (float_id_ == 0) {
644     analysis::TypeManager* type_mgr = context()->get_type_mgr();
645     analysis::Float float_ty(32);
646     analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
647     float_id_ = type_mgr->GetTypeInstruction(reg_float_ty);
648   }
649   return float_id_;
650 }
651 
GetVec4FloatId()652 uint32_t InstrumentPass::GetVec4FloatId() {
653   if (v4float_id_ == 0) {
654     analysis::TypeManager* type_mgr = context()->get_type_mgr();
655     analysis::Float float_ty(32);
656     analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
657     analysis::Vector v4float_ty(reg_float_ty, 4);
658     analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
659     v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
660   }
661   return v4float_id_;
662 }
663 
GetUintId()664 uint32_t InstrumentPass::GetUintId() {
665   if (uint_id_ == 0) {
666     analysis::TypeManager* type_mgr = context()->get_type_mgr();
667     analysis::Integer uint_ty(32, false);
668     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
669     uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
670   }
671   return uint_id_;
672 }
673 
GetUint64Id()674 uint32_t InstrumentPass::GetUint64Id() {
675   if (uint64_id_ == 0) {
676     analysis::TypeManager* type_mgr = context()->get_type_mgr();
677     analysis::Integer uint64_ty(64, false);
678     analysis::Type* reg_uint64_ty = type_mgr->GetRegisteredType(&uint64_ty);
679     uint64_id_ = type_mgr->GetTypeInstruction(reg_uint64_ty);
680   }
681   return uint64_id_;
682 }
683 
GetUint8Id()684 uint32_t InstrumentPass::GetUint8Id() {
685   if (uint8_id_ == 0) {
686     analysis::TypeManager* type_mgr = context()->get_type_mgr();
687     analysis::Integer uint8_ty(8, false);
688     analysis::Type* reg_uint8_ty = type_mgr->GetRegisteredType(&uint8_ty);
689     uint8_id_ = type_mgr->GetTypeInstruction(reg_uint8_ty);
690   }
691   return uint8_id_;
692 }
693 
GetVecUintId(uint32_t len)694 uint32_t InstrumentPass::GetVecUintId(uint32_t len) {
695   analysis::TypeManager* type_mgr = context()->get_type_mgr();
696   analysis::Integer uint_ty(32, false);
697   analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
698   analysis::Vector v_uint_ty(reg_uint_ty, len);
699   analysis::Type* reg_v_uint_ty = type_mgr->GetRegisteredType(&v_uint_ty);
700   uint32_t v_uint_id = type_mgr->GetTypeInstruction(reg_v_uint_ty);
701   return v_uint_id;
702 }
703 
GetVec4UintId()704 uint32_t InstrumentPass::GetVec4UintId() {
705   if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u);
706   return v4uint_id_;
707 }
708 
GetVec3UintId()709 uint32_t InstrumentPass::GetVec3UintId() {
710   if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u);
711   return v3uint_id_;
712 }
713 
GetBoolId()714 uint32_t InstrumentPass::GetBoolId() {
715   if (bool_id_ == 0) {
716     analysis::TypeManager* type_mgr = context()->get_type_mgr();
717     analysis::Bool bool_ty;
718     analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
719     bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
720   }
721   return bool_id_;
722 }
723 
GetVoidId()724 uint32_t InstrumentPass::GetVoidId() {
725   if (void_id_ == 0) {
726     analysis::TypeManager* type_mgr = context()->get_type_mgr();
727     analysis::Void void_ty;
728     analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
729     void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
730   }
731   return void_id_;
732 }
733 
GetStreamWriteFunctionId(uint32_t stage_idx,uint32_t val_spec_param_cnt)734 uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
735                                                   uint32_t val_spec_param_cnt) {
736   // Total param count is common params plus validation-specific
737   // params
738   uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
739   if (param2output_func_id_[param_cnt] == 0) {
740     // Create function
741     param2output_func_id_[param_cnt] = TakeNextId();
742     analysis::TypeManager* type_mgr = context()->get_type_mgr();
743     std::vector<const analysis::Type*> param_types;
744     for (uint32_t c = 0; c < param_cnt; ++c)
745       param_types.push_back(type_mgr->GetType(GetUintId()));
746     analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
747     analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
748     std::unique_ptr<Instruction> func_inst(
749         new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
750                         param2output_func_id_[param_cnt],
751                         {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
752                           {SpvFunctionControlMaskNone}},
753                          {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
754                           {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
755     get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
756     std::unique_ptr<Function> output_func =
757         MakeUnique<Function>(std::move(func_inst));
758     // Add parameters
759     std::vector<uint32_t> param_vec;
760     for (uint32_t c = 0; c < param_cnt; ++c) {
761       uint32_t pid = TakeNextId();
762       param_vec.push_back(pid);
763       std::unique_ptr<Instruction> param_inst(
764           new Instruction(get_module()->context(), SpvOpFunctionParameter,
765                           GetUintId(), pid, {}));
766       get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
767       output_func->AddParameter(std::move(param_inst));
768     }
769     // Create first block
770     uint32_t test_blk_id = TakeNextId();
771     std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
772     std::unique_ptr<BasicBlock> new_blk_ptr =
773         MakeUnique<BasicBlock>(std::move(test_label));
774     InstructionBuilder builder(
775         context(), &*new_blk_ptr,
776         IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
777     // Gen test if debug output buffer size will not be exceeded.
778     uint32_t val_spec_offset = kInstStageOutCnt;
779     uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
780     uint32_t buf_id = GetOutputBufferId();
781     uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
782     Instruction* obuf_curr_sz_ac_inst =
783         builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
784                             builder.GetUintConstantId(kDebugOutputSizeOffset));
785     // Fetch the current debug buffer written size atomically, adding the
786     // size of the record to be written.
787     uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
788     uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone);
789     uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation);
790     Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
791         GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
792         scope_invok_id, mask_none_id, obuf_record_sz_id);
793     uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
794     // Compute new written size
795     Instruction* obuf_new_sz_inst =
796         builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id,
797                             builder.GetUintConstantId(obuf_record_sz));
798     // Fetch the data bound
799     Instruction* obuf_bnd_inst =
800         builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
801                                GetOutputBufferId(), kDebugOutputDataOffset);
802     // Test that new written size is less than or equal to debug output
803     // data bound
804     Instruction* obuf_safe_inst = builder.AddBinaryOp(
805         GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(),
806         obuf_bnd_inst->result_id());
807     uint32_t merge_blk_id = TakeNextId();
808     uint32_t write_blk_id = TakeNextId();
809     std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
810     std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
811     (void)builder.AddConditionalBranch(obuf_safe_inst->result_id(),
812                                        write_blk_id, merge_blk_id, merge_blk_id,
813                                        SpvSelectionControlMaskNone);
814     // Close safety test block and gen write block
815     output_func->AddBasicBlock(std::move(new_blk_ptr));
816     new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
817     builder.SetInsertPoint(&*new_blk_ptr);
818     // Generate common and stage-specific debug record members
819     GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx],
820                              stage_idx, obuf_curr_sz_id, &builder);
821     GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
822     // Gen writes of validation specific data
823     for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
824       GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
825                               param_vec[kInstCommonParamCnt + i], &builder);
826     }
827     // Close write block and gen merge block
828     (void)builder.AddBranch(merge_blk_id);
829     output_func->AddBasicBlock(std::move(new_blk_ptr));
830     new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
831     builder.SetInsertPoint(&*new_blk_ptr);
832     // Close merge block and function and add function to module
833     (void)builder.AddNullaryOp(0, SpvOpReturn);
834     output_func->AddBasicBlock(std::move(new_blk_ptr));
835     std::unique_ptr<Instruction> func_end_inst(
836         new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
837     get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
838     output_func->SetFunctionEnd(std::move(func_end_inst));
839     context()->AddFunction(std::move(output_func));
840 
841     std::string name("stream_write_");
842     name += std::to_string(param_cnt);
843 
844     context()->AddDebug2Inst(
845         NewGlobalName(param2output_func_id_[param_cnt], name));
846   }
847   return param2output_func_id_[param_cnt];
848 }
849 
GetDirectReadFunctionId(uint32_t param_cnt)850 uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
851   uint32_t func_id = param2input_func_id_[param_cnt];
852   if (func_id != 0) return func_id;
853   // Create input function for param_cnt.
854   func_id = TakeNextId();
855   analysis::TypeManager* type_mgr = context()->get_type_mgr();
856   std::vector<const analysis::Type*> param_types;
857   for (uint32_t c = 0; c < param_cnt; ++c)
858     param_types.push_back(type_mgr->GetType(GetUintId()));
859   uint32_t ibuf_type_id = GetInputBufferTypeId();
860   analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), param_types);
861   analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
862   std::unique_ptr<Instruction> func_inst(new Instruction(
863       get_module()->context(), SpvOpFunction, ibuf_type_id, func_id,
864       {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
865         {SpvFunctionControlMaskNone}},
866        {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
867         {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
868   get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
869   std::unique_ptr<Function> input_func =
870       MakeUnique<Function>(std::move(func_inst));
871   // Add parameters
872   std::vector<uint32_t> param_vec;
873   for (uint32_t c = 0; c < param_cnt; ++c) {
874     uint32_t pid = TakeNextId();
875     param_vec.push_back(pid);
876     std::unique_ptr<Instruction> param_inst(new Instruction(
877         get_module()->context(), SpvOpFunctionParameter, GetUintId(), pid, {}));
878     get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
879     input_func->AddParameter(std::move(param_inst));
880   }
881   // Create block
882   uint32_t blk_id = TakeNextId();
883   std::unique_ptr<Instruction> blk_label(NewLabel(blk_id));
884   std::unique_ptr<BasicBlock> new_blk_ptr =
885       MakeUnique<BasicBlock>(std::move(blk_label));
886   InstructionBuilder builder(
887       context(), &*new_blk_ptr,
888       IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
889   // For each offset parameter, generate new offset with parameter, adding last
890   // loaded value if it exists, and load value from input buffer at new offset.
891   // Return last loaded value.
892   uint32_t buf_id = GetInputBufferId();
893   uint32_t buf_ptr_id = GetInputBufferPtrId();
894   uint32_t last_value_id = 0;
895   for (uint32_t p = 0; p < param_cnt; ++p) {
896     uint32_t offset_id;
897     if (p == 0) {
898       offset_id = param_vec[0];
899     } else {
900       if (ibuf_type_id != GetUintId()) {
901         Instruction* ucvt_inst =
902             builder.AddUnaryOp(GetUintId(), SpvOpUConvert, last_value_id);
903         last_value_id = ucvt_inst->result_id();
904       }
905       Instruction* offset_inst = builder.AddBinaryOp(
906           GetUintId(), SpvOpIAdd, last_value_id, param_vec[p]);
907       offset_id = offset_inst->result_id();
908     }
909     Instruction* ac_inst = builder.AddTernaryOp(
910         buf_ptr_id, SpvOpAccessChain, buf_id,
911         builder.GetUintConstantId(kDebugInputDataOffset), offset_id);
912     Instruction* load_inst =
913         builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, ac_inst->result_id());
914     last_value_id = load_inst->result_id();
915   }
916   (void)builder.AddInstruction(MakeUnique<Instruction>(
917       context(), SpvOpReturnValue, 0, 0,
918       std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {last_value_id}}}));
919   // Close block and function and add function to module
920   input_func->AddBasicBlock(std::move(new_blk_ptr));
921   std::unique_ptr<Instruction> func_end_inst(
922       new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
923   get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
924   input_func->SetFunctionEnd(std::move(func_end_inst));
925   context()->AddFunction(std::move(input_func));
926 
927   std::string name("direct_read_");
928   name += std::to_string(param_cnt);
929   context()->AddDebug2Inst(NewGlobalName(func_id, name));
930 
931   param2input_func_id_[param_cnt] = func_id;
932   return func_id;
933 }
934 
SplitBlock(BasicBlock::iterator inst_itr,UptrVectorIterator<BasicBlock> block_itr,std::vector<std::unique_ptr<BasicBlock>> * new_blocks)935 void InstrumentPass::SplitBlock(
936     BasicBlock::iterator inst_itr, UptrVectorIterator<BasicBlock> block_itr,
937     std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
938   // Make sure def/use analysis is done before we start moving instructions
939   // out of function
940   (void)get_def_use_mgr();
941   // Move original block's preceding instructions into first new block
942   std::unique_ptr<BasicBlock> first_blk_ptr;
943   MovePreludeCode(inst_itr, block_itr, &first_blk_ptr);
944   InstructionBuilder builder(
945       context(), &*first_blk_ptr,
946       IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
947   uint32_t split_blk_id = TakeNextId();
948   std::unique_ptr<Instruction> split_label(NewLabel(split_blk_id));
949   (void)builder.AddBranch(split_blk_id);
950   new_blocks->push_back(std::move(first_blk_ptr));
951   // Move remaining instructions into split block and add to new blocks
952   std::unique_ptr<BasicBlock> split_blk_ptr(
953       new BasicBlock(std::move(split_label)));
954   MovePostludeCode(block_itr, &*split_blk_ptr);
955   new_blocks->push_back(std::move(split_blk_ptr));
956 }
957 
InstrumentFunction(Function * func,uint32_t stage_idx,InstProcessFunction & pfn)958 bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
959                                         InstProcessFunction& pfn) {
960   curr_func_ = func;
961   call2id_.clear();
962   bool first_block_split = false;
963   bool modified = false;
964   // Apply instrumentation function to each instruction.
965   // Using block iterators here because of block erasures and insertions.
966   std::vector<std::unique_ptr<BasicBlock>> new_blks;
967   for (auto bi = func->begin(); bi != func->end(); ++bi) {
968     for (auto ii = bi->begin(); ii != bi->end();) {
969       // Split all executable instructions out of first block into a following
970       // block. This will allow function calls to be inserted into the first
971       // block without interfering with the instrumentation algorithm.
972       if (opt_direct_reads_ && !first_block_split) {
973         if (ii->opcode() != SpvOpVariable) {
974           SplitBlock(ii, bi, &new_blks);
975           first_block_split = true;
976         }
977       } else {
978         pfn(ii, bi, stage_idx, &new_blks);
979       }
980       // If no new code, continue
981       if (new_blks.size() == 0) {
982         ++ii;
983         continue;
984       }
985       // Add new blocks to label id map
986       for (auto& blk : new_blks) id2block_[blk->id()] = &*blk;
987       // If there are new blocks we know there will always be two or
988       // more, so update succeeding phis with label of new last block.
989       size_t newBlocksSize = new_blks.size();
990       assert(newBlocksSize > 1);
991       UpdateSucceedingPhis(new_blks);
992       // Replace original block with new block(s)
993       bi = bi.Erase();
994       for (auto& bb : new_blks) {
995         bb->SetParent(func);
996       }
997       bi = bi.InsertBefore(&new_blks);
998       // Reset block iterator to last new block
999       for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
1000       modified = true;
1001       // Restart instrumenting at beginning of last new block,
1002       // but skip over any new phi or copy instruction.
1003       ii = bi->begin();
1004       if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii;
1005       new_blks.clear();
1006     }
1007   }
1008   return modified;
1009 }
1010 
InstProcessCallTreeFromRoots(InstProcessFunction & pfn,std::queue<uint32_t> * roots,uint32_t stage_idx)1011 bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
1012                                                   std::queue<uint32_t>* roots,
1013                                                   uint32_t stage_idx) {
1014   bool modified = false;
1015   std::unordered_set<uint32_t> done;
1016   // Don't process input and output functions
1017   for (auto& ifn : param2input_func_id_) done.insert(ifn.second);
1018   for (auto& ofn : param2output_func_id_) done.insert(ofn.second);
1019   // Process all functions from roots
1020   while (!roots->empty()) {
1021     const uint32_t fi = roots->front();
1022     roots->pop();
1023     if (done.insert(fi).second) {
1024       Function* fn = id2function_.at(fi);
1025       // Add calls first so we don't add new output function
1026       context()->AddCalls(fn, roots);
1027       modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
1028     }
1029   }
1030   return modified;
1031 }
1032 
InstProcessEntryPointCallTree(InstProcessFunction & pfn)1033 bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
1034   // Make sure all entry points have the same execution model. Do not
1035   // instrument if they do not.
1036   // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
1037   // can contain entry points with different execution models, although
1038   // such modules will likely be rare as GLSL and HLSL are geared toward
1039   // one model per module. In such cases we will need
1040   // to clone any functions which are in the call trees of entrypoints
1041   // with differing execution models.
1042   uint32_t ecnt = 0;
1043   uint32_t stage = SpvExecutionModelMax;
1044   for (auto& e : get_module()->entry_points()) {
1045     if (ecnt == 0)
1046       stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
1047     else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) !=
1048              stage) {
1049       if (consumer()) {
1050         std::string message = "Mixed stage shader module not supported";
1051         consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
1052       }
1053       return false;
1054     }
1055     ++ecnt;
1056   }
1057   // Check for supported stages
1058   if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment &&
1059       stage != SpvExecutionModelGeometry &&
1060       stage != SpvExecutionModelGLCompute &&
1061       stage != SpvExecutionModelTessellationControl &&
1062       stage != SpvExecutionModelTessellationEvaluation &&
1063       stage != SpvExecutionModelTaskNV && stage != SpvExecutionModelMeshNV &&
1064       stage != SpvExecutionModelRayGenerationNV &&
1065       stage != SpvExecutionModelIntersectionNV &&
1066       stage != SpvExecutionModelAnyHitNV &&
1067       stage != SpvExecutionModelClosestHitNV &&
1068       stage != SpvExecutionModelMissNV &&
1069       stage != SpvExecutionModelCallableNV &&
1070       stage != SpvExecutionModelTaskEXT && stage != SpvExecutionModelMeshEXT) {
1071     if (consumer()) {
1072       std::string message = "Stage not supported by instrumentation";
1073       consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
1074     }
1075     return false;
1076   }
1077   // Add together the roots of all entry points
1078   std::queue<uint32_t> roots;
1079   for (auto& e : get_module()->entry_points()) {
1080     roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
1081   }
1082   bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage);
1083   return modified;
1084 }
1085 
InitializeInstrument()1086 void InstrumentPass::InitializeInstrument() {
1087   output_buffer_id_ = 0;
1088   output_buffer_ptr_id_ = 0;
1089   input_buffer_ptr_id_ = 0;
1090   input_buffer_id_ = 0;
1091   float_id_ = 0;
1092   v4float_id_ = 0;
1093   uint_id_ = 0;
1094   uint64_id_ = 0;
1095   uint8_id_ = 0;
1096   v4uint_id_ = 0;
1097   v3uint_id_ = 0;
1098   bool_id_ = 0;
1099   void_id_ = 0;
1100   storage_buffer_ext_defined_ = false;
1101   uint32_rarr_ty_ = nullptr;
1102   uint64_rarr_ty_ = nullptr;
1103 
1104   // clear collections
1105   id2function_.clear();
1106   id2block_.clear();
1107 
1108   // clear maps
1109   param2input_func_id_.clear();
1110   param2output_func_id_.clear();
1111 
1112   // Initialize function and block maps.
1113   for (auto& fn : *get_module()) {
1114     id2function_[fn.result_id()] = &fn;
1115     for (auto& blk : fn) {
1116       id2block_[blk.id()] = &blk;
1117     }
1118   }
1119 
1120   // Remember original instruction offsets
1121   uint32_t module_offset = 0;
1122   Module* module = get_module();
1123   for (auto& i : context()->capabilities()) {
1124     (void)i;
1125     ++module_offset;
1126   }
1127   for (auto& i : module->extensions()) {
1128     (void)i;
1129     ++module_offset;
1130   }
1131   for (auto& i : module->ext_inst_imports()) {
1132     (void)i;
1133     ++module_offset;
1134   }
1135   ++module_offset;  // memory_model
1136   for (auto& i : module->entry_points()) {
1137     (void)i;
1138     ++module_offset;
1139   }
1140   for (auto& i : module->execution_modes()) {
1141     (void)i;
1142     ++module_offset;
1143   }
1144   for (auto& i : module->debugs1()) {
1145     (void)i;
1146     ++module_offset;
1147   }
1148   for (auto& i : module->debugs2()) {
1149     (void)i;
1150     ++module_offset;
1151   }
1152   for (auto& i : module->debugs3()) {
1153     (void)i;
1154     ++module_offset;
1155   }
1156   for (auto& i : module->ext_inst_debuginfo()) {
1157     (void)i;
1158     ++module_offset;
1159   }
1160   for (auto& i : module->annotations()) {
1161     (void)i;
1162     ++module_offset;
1163   }
1164   for (auto& i : module->types_values()) {
1165     module_offset += 1;
1166     module_offset += static_cast<uint32_t>(i.dbg_line_insts().size());
1167   }
1168 
1169   auto curr_fn = get_module()->begin();
1170   for (; curr_fn != get_module()->end(); ++curr_fn) {
1171     // Count function instruction
1172     module_offset += 1;
1173     curr_fn->ForEachParam(
1174         [&module_offset](const Instruction*) { module_offset += 1; }, true);
1175     for (auto& blk : *curr_fn) {
1176       // Count label
1177       module_offset += 1;
1178       for (auto& inst : blk) {
1179         module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size());
1180         uid2offset_[inst.unique_id()] = module_offset;
1181         module_offset += 1;
1182       }
1183     }
1184     // Count function end instruction
1185     module_offset += 1;
1186   }
1187 }
1188 
1189 }  // namespace opt
1190 }  // namespace spvtools
1191