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 
21 namespace {
22 
23 // Common Parameter Positions
24 static const int kInstCommonParamInstIdx = 0;
25 static const int kInstCommonParamCnt = 1;
26 
27 // Indices of operands in SPIR-V instructions
28 static const int kEntryPointExecutionModelInIdx = 0;
29 static const int kEntryPointFunctionIdInIdx = 1;
30 
31 }  // anonymous namespace
32 
33 namespace spvtools {
34 namespace opt {
35 
MovePreludeCode(BasicBlock::iterator ref_inst_itr,UptrVectorIterator<BasicBlock> ref_block_itr,std::unique_ptr<BasicBlock> * new_blk_ptr)36 void InstrumentPass::MovePreludeCode(
37     BasicBlock::iterator ref_inst_itr,
38     UptrVectorIterator<BasicBlock> ref_block_itr,
39     std::unique_ptr<BasicBlock>* new_blk_ptr) {
40   same_block_pre_.clear();
41   same_block_post_.clear();
42   // Initialize new block. Reuse label from original block.
43   new_blk_ptr->reset(new BasicBlock(std::move(ref_block_itr->GetLabel())));
44   // Move contents of original ref block up to ref instruction.
45   for (auto cii = ref_block_itr->begin(); cii != ref_inst_itr;
46        cii = ref_block_itr->begin()) {
47     Instruction* inst = &*cii;
48     inst->RemoveFromList();
49     std::unique_ptr<Instruction> mv_ptr(inst);
50     // Remember same-block ops for possible regeneration.
51     if (IsSameBlockOp(&*mv_ptr)) {
52       auto* sb_inst_ptr = mv_ptr.get();
53       same_block_pre_[mv_ptr->result_id()] = sb_inst_ptr;
54     }
55     (*new_blk_ptr)->AddInstruction(std::move(mv_ptr));
56   }
57 }
58 
MovePostludeCode(UptrVectorIterator<BasicBlock> ref_block_itr,std::unique_ptr<BasicBlock> * new_blk_ptr)59 void InstrumentPass::MovePostludeCode(
60     UptrVectorIterator<BasicBlock> ref_block_itr,
61     std::unique_ptr<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 
GenUintCastCode(uint32_t val_id,InstructionBuilder * builder)91 uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
92                                          InstructionBuilder* builder) {
93   // Cast value to 32-bit unsigned if necessary
94   if (get_def_use_mgr()->GetDef(val_id)->type_id() == GetUintId())
95     return val_id;
96   return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_id)->result_id();
97 }
98 
GenDebugOutputFieldCode(uint32_t base_offset_id,uint32_t field_offset,uint32_t field_value_id,InstructionBuilder * builder)99 void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
100                                              uint32_t field_offset,
101                                              uint32_t field_value_id,
102                                              InstructionBuilder* builder) {
103   // Cast value to 32-bit unsigned if necessary
104   uint32_t val_id = GenUintCastCode(field_value_id, builder);
105   // Store value
106   Instruction* data_idx_inst =
107       builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id,
108                            builder->GetUintConstantId(field_offset));
109   uint32_t buf_id = GetOutputBufferId();
110   uint32_t buf_uint_ptr_id = GetOutputBufferUintPtrId();
111   Instruction* achain_inst =
112       builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
113                             builder->GetUintConstantId(kDebugOutputDataOffset),
114                             data_idx_inst->result_id());
115   (void)builder->AddBinaryOp(0, SpvOpStore, achain_inst->result_id(), val_id);
116 }
117 
GenCommonStreamWriteCode(uint32_t record_sz,uint32_t inst_id,uint32_t stage_idx,uint32_t base_offset_id,InstructionBuilder * builder)118 void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
119                                               uint32_t inst_id,
120                                               uint32_t stage_idx,
121                                               uint32_t base_offset_id,
122                                               InstructionBuilder* builder) {
123   // Store record size
124   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
125                           builder->GetUintConstantId(record_sz), builder);
126   // Store Shader Id
127   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
128                           builder->GetUintConstantId(shader_id_), builder);
129   // Store Instruction Idx
130   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
131                           builder);
132   // Store Stage Idx
133   GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
134                           builder->GetUintConstantId(stage_idx), builder);
135 }
136 
GenFragCoordEltDebugOutputCode(uint32_t base_offset_id,uint32_t uint_frag_coord_id,uint32_t element,InstructionBuilder * builder)137 void InstrumentPass::GenFragCoordEltDebugOutputCode(
138     uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
139     InstructionBuilder* builder) {
140   Instruction* element_val_inst = builder->AddIdLiteralOp(
141       GetUintId(), SpvOpCompositeExtract, uint_frag_coord_id, element);
142   GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
143                           element_val_inst->result_id(), builder);
144 }
145 
GenBuiltinOutputCode(uint32_t builtin_id,uint32_t builtin_off,uint32_t base_offset_id,InstructionBuilder * builder)146 void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
147                                           uint32_t builtin_off,
148                                           uint32_t base_offset_id,
149                                           InstructionBuilder* builder) {
150   // Load and store builtin
151   Instruction* load_inst =
152       builder->AddUnaryOp(GetUintId(), SpvOpLoad, builtin_id);
153   GenDebugOutputFieldCode(base_offset_id, builtin_off, load_inst->result_id(),
154                           builder);
155 }
156 
GenUintNullOutputCode(uint32_t field_off,uint32_t base_offset_id,InstructionBuilder * builder)157 void InstrumentPass::GenUintNullOutputCode(uint32_t field_off,
158                                            uint32_t base_offset_id,
159                                            InstructionBuilder* builder) {
160   GenDebugOutputFieldCode(base_offset_id, field_off,
161                           builder->GetNullId(GetUintId()), builder);
162 }
163 
GenStageStreamWriteCode(uint32_t stage_idx,uint32_t base_offset_id,InstructionBuilder * builder)164 void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
165                                              uint32_t base_offset_id,
166                                              InstructionBuilder* builder) {
167   // TODO(greg-lunarg): Add support for all stages
168   switch (stage_idx) {
169     case SpvExecutionModelVertex: {
170       // Load and store VertexId and InstanceId
171       GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexId),
172                            kInstVertOutVertexId, base_offset_id, builder);
173       GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceId),
174                            kInstVertOutInstanceId, base_offset_id, builder);
175     } break;
176     case SpvExecutionModelGLCompute: {
177       // Load and store GlobalInvocationId. Second word is unused; store zero.
178       GenBuiltinOutputCode(
179           context()->GetBuiltinVarId(SpvBuiltInGlobalInvocationId),
180           kInstCompOutGlobalInvocationId, base_offset_id, builder);
181       GenUintNullOutputCode(kInstCompOutUnused, base_offset_id, builder);
182     } break;
183     case SpvExecutionModelGeometry: {
184       // Load and store PrimitiveId and InvocationId.
185       GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInPrimitiveId),
186                            kInstGeomOutPrimitiveId, base_offset_id, builder);
187       GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInvocationId),
188                            kInstGeomOutInvocationId, base_offset_id, builder);
189     } break;
190     case SpvExecutionModelTessellationControl:
191     case SpvExecutionModelTessellationEvaluation: {
192       // Load and store InvocationId. Second word is unused; store zero.
193       GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInvocationId),
194                            kInstTessOutInvocationId, base_offset_id, builder);
195       GenUintNullOutputCode(kInstTessOutUnused, base_offset_id, builder);
196     } break;
197     case SpvExecutionModelFragment: {
198       // Load FragCoord and convert to Uint
199       Instruction* frag_coord_inst =
200           builder->AddUnaryOp(GetVec4FloatId(), SpvOpLoad,
201                               context()->GetBuiltinVarId(SpvBuiltInFragCoord));
202       Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
203           GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
204       for (uint32_t u = 0; u < 2u; ++u)
205         GenFragCoordEltDebugOutputCode(
206             base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
207     } break;
208     default: { assert(false && "unsupported stage"); } break;
209   }
210 }
211 
GenDebugStreamWrite(uint32_t instruction_idx,uint32_t stage_idx,const std::vector<uint32_t> & validation_ids,InstructionBuilder * builder)212 void InstrumentPass::GenDebugStreamWrite(
213     uint32_t instruction_idx, uint32_t stage_idx,
214     const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
215   // Call debug output function. Pass func_idx, instruction_idx and
216   // validation ids as args.
217   uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
218   uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt);
219   std::vector<uint32_t> args = {output_func_id,
220                                 builder->GetUintConstantId(instruction_idx)};
221   (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
222   (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
223 }
224 
IsSameBlockOp(const Instruction * inst) const225 bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
226   return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
227 }
228 
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,std::unique_ptr<BasicBlock> * block_ptr)229 void InstrumentPass::CloneSameBlockOps(
230     std::unique_ptr<Instruction>* inst,
231     std::unordered_map<uint32_t, uint32_t>* same_blk_post,
232     std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
233     std::unique_ptr<BasicBlock>* block_ptr) {
234   (*inst)->ForEachInId(
235       [&same_blk_post, &same_blk_pre, &block_ptr, this](uint32_t* iid) {
236         const auto map_itr = (*same_blk_post).find(*iid);
237         if (map_itr == (*same_blk_post).end()) {
238           const auto map_itr2 = (*same_blk_pre).find(*iid);
239           if (map_itr2 != (*same_blk_pre).end()) {
240             // Clone pre-call same-block ops, map result id.
241             const Instruction* in_inst = map_itr2->second;
242             std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
243             CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
244             const uint32_t rid = sb_inst->result_id();
245             const uint32_t nid = this->TakeNextId();
246             get_decoration_mgr()->CloneDecorations(rid, nid);
247             sb_inst->SetResultId(nid);
248             (*same_blk_post)[rid] = nid;
249             *iid = nid;
250             (*block_ptr)->AddInstruction(std::move(sb_inst));
251           }
252         } else {
253           // Reset same-block op operand.
254           *iid = map_itr->second;
255         }
256       });
257 }
258 
UpdateSucceedingPhis(std::vector<std::unique_ptr<BasicBlock>> & new_blocks)259 void InstrumentPass::UpdateSucceedingPhis(
260     std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
261   const auto first_blk = new_blocks.begin();
262   const auto last_blk = new_blocks.end() - 1;
263   const uint32_t first_id = (*first_blk)->id();
264   const uint32_t last_id = (*last_blk)->id();
265   const BasicBlock& const_last_block = *last_blk->get();
266   const_last_block.ForEachSuccessorLabel(
267       [&first_id, &last_id, this](const uint32_t succ) {
268         BasicBlock* sbp = this->id2block_[succ];
269         sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
270           bool changed = false;
271           phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
272             if (*id == first_id) {
273               *id = last_id;
274               changed = true;
275             }
276           });
277           if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
278         });
279       });
280 }
281 
282 // Return id for output buffer uint ptr type
GetOutputBufferUintPtrId()283 uint32_t InstrumentPass::GetOutputBufferUintPtrId() {
284   if (output_buffer_uint_ptr_id_ == 0) {
285     output_buffer_uint_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
286         GetUintId(), SpvStorageClassStorageBuffer);
287   }
288   return output_buffer_uint_ptr_id_;
289 }
290 
GetOutputBufferBinding()291 uint32_t InstrumentPass::GetOutputBufferBinding() {
292   switch (validation_id_) {
293     case kInstValidationIdBindless:
294       return kDebugOutputBindingStream;
295     default:
296       assert(false && "unexpected validation id");
297   }
298   return 0;
299 }
300 
301 // Return id for output buffer
GetOutputBufferId()302 uint32_t InstrumentPass::GetOutputBufferId() {
303   if (output_buffer_id_ == 0) {
304     // If not created yet, create one
305     analysis::DecorationManager* deco_mgr = get_decoration_mgr();
306     analysis::TypeManager* type_mgr = context()->get_type_mgr();
307     analysis::Integer uint_ty(32, false);
308     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
309     analysis::RuntimeArray uint_rarr_ty(reg_uint_ty);
310     analysis::Type* reg_uint_rarr_ty =
311         type_mgr->GetRegisteredType(&uint_rarr_ty);
312     analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty});
313     analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty);
314     uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty);
315     deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
316     deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
317                                   SpvDecorationOffset, 0);
318     deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
319                                   SpvDecorationOffset, 4);
320     uint32_t obufTyPtrId_ =
321         type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer);
322     output_buffer_id_ = TakeNextId();
323     std::unique_ptr<Instruction> newVarOp(new Instruction(
324         context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_,
325         {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
326           {SpvStorageClassStorageBuffer}}}));
327     context()->AddGlobalValue(std::move(newVarOp));
328     deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet,
329                                desc_set_);
330     deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
331                                GetOutputBufferBinding());
332     // Look for storage buffer extension. If none, create one.
333     if (!get_feature_mgr()->HasExtension(
334             kSPV_KHR_storage_buffer_storage_class)) {
335       const std::string ext_name("SPV_KHR_storage_buffer_storage_class");
336       const auto num_chars = ext_name.size();
337       // Compute num words, accommodate the terminating null character.
338       const auto num_words = (num_chars + 1 + 3) / 4;
339       std::vector<uint32_t> ext_words(num_words, 0u);
340       std::memcpy(ext_words.data(), ext_name.data(), num_chars);
341       context()->AddExtension(std::unique_ptr<Instruction>(
342           new Instruction(context(), SpvOpExtension, 0u, 0u,
343                           {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
344     }
345   }
346   return output_buffer_id_;
347 }
348 
GetVec4FloatId()349 uint32_t InstrumentPass::GetVec4FloatId() {
350   if (v4float_id_ == 0) {
351     analysis::TypeManager* type_mgr = context()->get_type_mgr();
352     analysis::Float float_ty(32);
353     analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
354     analysis::Vector v4float_ty(reg_float_ty, 4);
355     analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
356     v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
357   }
358   return v4float_id_;
359 }
360 
GetUintId()361 uint32_t InstrumentPass::GetUintId() {
362   if (uint_id_ == 0) {
363     analysis::TypeManager* type_mgr = context()->get_type_mgr();
364     analysis::Integer uint_ty(32, false);
365     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
366     uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
367   }
368   return uint_id_;
369 }
370 
GetVec4UintId()371 uint32_t InstrumentPass::GetVec4UintId() {
372   if (v4uint_id_ == 0) {
373     analysis::TypeManager* type_mgr = context()->get_type_mgr();
374     analysis::Integer uint_ty(32, false);
375     analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
376     analysis::Vector v4uint_ty(reg_uint_ty, 4);
377     analysis::Type* reg_v4uint_ty = type_mgr->GetRegisteredType(&v4uint_ty);
378     v4uint_id_ = type_mgr->GetTypeInstruction(reg_v4uint_ty);
379   }
380   return v4uint_id_;
381 }
382 
GetBoolId()383 uint32_t InstrumentPass::GetBoolId() {
384   if (bool_id_ == 0) {
385     analysis::TypeManager* type_mgr = context()->get_type_mgr();
386     analysis::Bool bool_ty;
387     analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
388     bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
389   }
390   return bool_id_;
391 }
392 
GetVoidId()393 uint32_t InstrumentPass::GetVoidId() {
394   if (void_id_ == 0) {
395     analysis::TypeManager* type_mgr = context()->get_type_mgr();
396     analysis::Void void_ty;
397     analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
398     void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
399   }
400   return void_id_;
401 }
402 
GetStreamWriteFunctionId(uint32_t stage_idx,uint32_t val_spec_param_cnt)403 uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
404                                                   uint32_t val_spec_param_cnt) {
405   // Total param count is common params plus validation-specific
406   // params
407   uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
408   if (output_func_id_ == 0) {
409     // Create function
410     output_func_id_ = TakeNextId();
411     analysis::TypeManager* type_mgr = context()->get_type_mgr();
412     std::vector<const analysis::Type*> param_types;
413     for (uint32_t c = 0; c < param_cnt; ++c)
414       param_types.push_back(type_mgr->GetType(GetUintId()));
415     analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
416     analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
417     std::unique_ptr<Instruction> func_inst(new Instruction(
418         get_module()->context(), SpvOpFunction, GetVoidId(), output_func_id_,
419         {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
420           {SpvFunctionControlMaskNone}},
421          {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
422           {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
423     get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
424     std::unique_ptr<Function> output_func =
425         MakeUnique<Function>(std::move(func_inst));
426     // Add parameters
427     std::vector<uint32_t> param_vec;
428     for (uint32_t c = 0; c < param_cnt; ++c) {
429       uint32_t pid = TakeNextId();
430       param_vec.push_back(pid);
431       std::unique_ptr<Instruction> param_inst(
432           new Instruction(get_module()->context(), SpvOpFunctionParameter,
433                           GetUintId(), pid, {}));
434       get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
435       output_func->AddParameter(std::move(param_inst));
436     }
437     // Create first block
438     uint32_t test_blk_id = TakeNextId();
439     std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
440     std::unique_ptr<BasicBlock> new_blk_ptr =
441         MakeUnique<BasicBlock>(std::move(test_label));
442     InstructionBuilder builder(
443         context(), &*new_blk_ptr,
444         IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
445     // Gen test if debug output buffer size will not be exceeded.
446     uint32_t obuf_record_sz = kInstStageOutCnt + val_spec_param_cnt;
447     uint32_t buf_id = GetOutputBufferId();
448     uint32_t buf_uint_ptr_id = GetOutputBufferUintPtrId();
449     Instruction* obuf_curr_sz_ac_inst =
450         builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
451                             builder.GetUintConstantId(kDebugOutputSizeOffset));
452     // Fetch the current debug buffer written size atomically, adding the
453     // size of the record to be written.
454     uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
455     uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone);
456     uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation);
457     Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
458         GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
459         scope_invok_id, mask_none_id, obuf_record_sz_id);
460     uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
461     // Compute new written size
462     Instruction* obuf_new_sz_inst =
463         builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id,
464                             builder.GetUintConstantId(obuf_record_sz));
465     // Fetch the data bound
466     Instruction* obuf_bnd_inst =
467         builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
468                                GetOutputBufferId(), kDebugOutputDataOffset);
469     // Test that new written size is less than or equal to debug output
470     // data bound
471     Instruction* obuf_safe_inst = builder.AddBinaryOp(
472         GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(),
473         obuf_bnd_inst->result_id());
474     uint32_t merge_blk_id = TakeNextId();
475     uint32_t write_blk_id = TakeNextId();
476     std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
477     std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
478     (void)builder.AddConditionalBranch(obuf_safe_inst->result_id(),
479                                        write_blk_id, merge_blk_id, merge_blk_id,
480                                        SpvSelectionControlMaskNone);
481     // Close safety test block and gen write block
482     new_blk_ptr->SetParent(&*output_func);
483     output_func->AddBasicBlock(std::move(new_blk_ptr));
484     new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
485     builder.SetInsertPoint(&*new_blk_ptr);
486     // Generate common and stage-specific debug record members
487     GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx],
488                              stage_idx, obuf_curr_sz_id, &builder);
489     GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
490     // Gen writes of validation specific data
491     for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
492       GenDebugOutputFieldCode(obuf_curr_sz_id, kInstStageOutCnt + i,
493                               param_vec[kInstCommonParamCnt + i], &builder);
494     }
495     // Close write block and gen merge block
496     (void)builder.AddBranch(merge_blk_id);
497     new_blk_ptr->SetParent(&*output_func);
498     output_func->AddBasicBlock(std::move(new_blk_ptr));
499     new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
500     builder.SetInsertPoint(&*new_blk_ptr);
501     // Close merge block and function and add function to module
502     (void)builder.AddNullaryOp(0, SpvOpReturn);
503     new_blk_ptr->SetParent(&*output_func);
504     output_func->AddBasicBlock(std::move(new_blk_ptr));
505     std::unique_ptr<Instruction> func_end_inst(
506         new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
507     get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
508     output_func->SetFunctionEnd(std::move(func_end_inst));
509     context()->AddFunction(std::move(output_func));
510     output_func_param_cnt_ = param_cnt;
511   }
512   assert(param_cnt == output_func_param_cnt_ && "bad arg count");
513   return output_func_id_;
514 }
515 
InstrumentFunction(Function * func,uint32_t stage_idx,InstProcessFunction & pfn)516 bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
517                                         InstProcessFunction& pfn) {
518   bool modified = false;
519   // Compute function index
520   uint32_t function_idx = 0;
521   for (auto fii = get_module()->begin(); fii != get_module()->end(); ++fii) {
522     if (&*fii == func) break;
523     ++function_idx;
524   }
525   std::vector<std::unique_ptr<BasicBlock>> new_blks;
526   // Start count after function instruction
527   uint32_t instruction_idx = funcIdx2offset_[function_idx] + 1;
528   // Using block iterators here because of block erasures and insertions.
529   for (auto bi = func->begin(); bi != func->end(); ++bi) {
530     // Count block's label
531     ++instruction_idx;
532     for (auto ii = bi->begin(); ii != bi->end(); ++instruction_idx) {
533       // Bump instruction count if debug instructions
534       instruction_idx += static_cast<uint32_t>(ii->dbg_line_insts().size());
535       // Generate instrumentation if warranted
536       pfn(ii, bi, instruction_idx, stage_idx, &new_blks);
537       if (new_blks.size() == 0) {
538         ++ii;
539         continue;
540       }
541       // If there are new blocks we know there will always be two or
542       // more, so update succeeding phis with label of new last block.
543       size_t newBlocksSize = new_blks.size();
544       assert(newBlocksSize > 1);
545       UpdateSucceedingPhis(new_blks);
546       // Replace original block with new block(s)
547       bi = bi.Erase();
548       for (auto& bb : new_blks) {
549         bb->SetParent(func);
550       }
551       bi = bi.InsertBefore(&new_blks);
552       // Reset block iterator to last new block
553       for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
554       modified = true;
555       // Restart instrumenting at beginning of last new block,
556       // but skip over any new phi or copy instruction.
557       ii = bi->begin();
558       if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii;
559       new_blks.clear();
560     }
561   }
562   return modified;
563 }
564 
InstProcessCallTreeFromRoots(InstProcessFunction & pfn,std::queue<uint32_t> * roots,uint32_t stage_idx)565 bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
566                                                   std::queue<uint32_t>* roots,
567                                                   uint32_t stage_idx) {
568   bool modified = false;
569   std::unordered_set<uint32_t> done;
570   // Process all functions from roots
571   while (!roots->empty()) {
572     const uint32_t fi = roots->front();
573     roots->pop();
574     if (done.insert(fi).second) {
575       Function* fn = id2function_.at(fi);
576       // Add calls first so we don't add new output function
577       context()->AddCalls(fn, roots);
578       modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
579     }
580   }
581   return modified;
582 }
583 
InstProcessEntryPointCallTree(InstProcessFunction & pfn)584 bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
585   // Make sure all entry points have the same execution model. Do not
586   // instrument if they do not.
587   // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
588   // can contain entry points with different execution models, although
589   // such modules will likely be rare as GLSL and HLSL are geared toward
590   // one model per module. In such cases we will need
591   // to clone any functions which are in the call trees of entrypoints
592   // with differing execution models.
593   uint32_t ecnt = 0;
594   uint32_t stage = SpvExecutionModelMax;
595   for (auto& e : get_module()->entry_points()) {
596     if (ecnt == 0)
597       stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
598     else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) != stage)
599       return false;
600     ++ecnt;
601   }
602   // Only supporting vertex, fragment and compute shaders at the moment.
603   // TODO(greg-lunarg): Handle all stages.
604   if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment &&
605       stage != SpvExecutionModelGeometry &&
606       stage != SpvExecutionModelGLCompute &&
607       stage != SpvExecutionModelTessellationControl &&
608       stage != SpvExecutionModelTessellationEvaluation)
609     return false;
610   // Add together the roots of all entry points
611   std::queue<uint32_t> roots;
612   for (auto& e : get_module()->entry_points()) {
613     roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
614   }
615   bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage);
616   return modified;
617 }
618 
InitializeInstrument()619 void InstrumentPass::InitializeInstrument() {
620   output_buffer_id_ = 0;
621   output_buffer_uint_ptr_id_ = 0;
622   output_func_id_ = 0;
623   output_func_param_cnt_ = 0;
624   v4float_id_ = 0;
625   uint_id_ = 0;
626   v4uint_id_ = 0;
627   bool_id_ = 0;
628   void_id_ = 0;
629 
630   // clear collections
631   id2function_.clear();
632   id2block_.clear();
633 
634   // Initialize function and block maps.
635   for (auto& fn : *get_module()) {
636     id2function_[fn.result_id()] = &fn;
637     for (auto& blk : fn) {
638       id2block_[blk.id()] = &blk;
639     }
640   }
641 
642   // Calculate instruction offset of first function
643   uint32_t pre_func_size = 0;
644   Module* module = get_module();
645   for (auto& i : context()->capabilities()) {
646     (void)i;
647     ++pre_func_size;
648   }
649   for (auto& i : module->extensions()) {
650     (void)i;
651     ++pre_func_size;
652   }
653   for (auto& i : module->ext_inst_imports()) {
654     (void)i;
655     ++pre_func_size;
656   }
657   ++pre_func_size;  // memory_model
658   for (auto& i : module->entry_points()) {
659     (void)i;
660     ++pre_func_size;
661   }
662   for (auto& i : module->execution_modes()) {
663     (void)i;
664     ++pre_func_size;
665   }
666   for (auto& i : module->debugs1()) {
667     (void)i;
668     ++pre_func_size;
669   }
670   for (auto& i : module->debugs2()) {
671     (void)i;
672     ++pre_func_size;
673   }
674   for (auto& i : module->debugs3()) {
675     (void)i;
676     ++pre_func_size;
677   }
678   for (auto& i : module->annotations()) {
679     (void)i;
680     ++pre_func_size;
681   }
682   for (auto& i : module->types_values()) {
683     pre_func_size += 1;
684     pre_func_size += static_cast<uint32_t>(i.dbg_line_insts().size());
685   }
686   funcIdx2offset_[0] = pre_func_size;
687 
688   // Set instruction offsets for all other functions.
689   uint32_t func_idx = 1;
690   auto prev_fn = get_module()->begin();
691   auto curr_fn = prev_fn;
692   for (++curr_fn; curr_fn != get_module()->end(); ++curr_fn) {
693     // Count function and end instructions
694     uint32_t func_size = 2;
695     for (auto& blk : *prev_fn) {
696       // Count label
697       func_size += 1;
698       for (auto& inst : blk) {
699         func_size += 1;
700         func_size += static_cast<uint32_t>(inst.dbg_line_insts().size());
701       }
702     }
703     funcIdx2offset_[func_idx] = func_size;
704     ++prev_fn;
705     ++func_idx;
706   }
707 }
708 
709 }  // namespace opt
710 }  // namespace spvtools
711