blob: 6645a2e3f6c65bce3b84a0e72e9c2f7cf2d64bd5 [file] [log] [blame]
Chris Forbescc5697f2019-01-30 11:54:08 -08001// 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"
Ben Claytonb73b7602019-07-29 13:56:13 +010020#include "source/spirv_constant.h"
Chris Forbescc5697f2019-01-30 11:54:08 -080021
22namespace {
23
24// Common Parameter Positions
25static const int kInstCommonParamInstIdx = 0;
26static const int kInstCommonParamCnt = 1;
27
28// Indices of operands in SPIR-V instructions
29static const int kEntryPointExecutionModelInIdx = 0;
30static const int kEntryPointFunctionIdInIdx = 1;
31
32} // anonymous namespace
33
34namespace spvtools {
35namespace opt {
36
37void 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
60void InstrumentPass::MovePostludeCode(
Ben Claytonb73b7602019-07-29 13:56:13 +010061 UptrVectorIterator<BasicBlock> ref_block_itr, BasicBlock* new_blk_ptr) {
Chris Forbescc5697f2019-01-30 11:54:08 -080062 // 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 }
Ben Claytonb73b7602019-07-29 13:56:13 +010080 new_blk_ptr->AddInstruction(std::move(mv_inst));
Chris Forbescc5697f2019-01-30 11:54:08 -080081 }
82}
83
84std::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
91uint32_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
99void 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();
Ben Claytonb73b7602019-07-29 13:56:13 +0100110 uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800111 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
118void 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
137void 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
Ben Claytonb73b7602019-07-29 13:56:13 +0100146uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
147 InstructionBuilder* builder) {
148 Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
149 uint32_t type_id = GetPointeeTypeId(var_inst);
150 Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id);
151 return load_inst->result_id();
152}
153
Chris Forbescc5697f2019-01-30 11:54:08 -0800154void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
155 uint32_t builtin_off,
156 uint32_t base_offset_id,
157 InstructionBuilder* builder) {
158 // Load and store builtin
Ben Claytonb73b7602019-07-29 13:56:13 +0100159 uint32_t load_id = GenVarLoad(builtin_id, builder);
160 GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800161}
162
163void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
164 uint32_t base_offset_id,
165 InstructionBuilder* builder) {
166 // TODO(greg-lunarg): Add support for all stages
167 switch (stage_idx) {
168 case SpvExecutionModelVertex: {
169 // Load and store VertexId and InstanceId
Ben Claytonb73b7602019-07-29 13:56:13 +0100170 GenBuiltinOutputCode(
171 context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex),
172 kInstVertOutVertexIndex, base_offset_id, builder);
173 GenBuiltinOutputCode(
174 context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex),
175 kInstVertOutInstanceIndex, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800176 } break;
177 case SpvExecutionModelGLCompute: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100178 // Load and store GlobalInvocationId.
179 uint32_t load_id = GenVarLoad(
180 context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId),
181 builder);
182 Instruction* x_inst = builder->AddIdLiteralOp(
183 GetUintId(), SpvOpCompositeExtract, load_id, 0);
184 Instruction* y_inst = builder->AddIdLiteralOp(
185 GetUintId(), SpvOpCompositeExtract, load_id, 1);
186 Instruction* z_inst = builder->AddIdLiteralOp(
187 GetUintId(), SpvOpCompositeExtract, load_id, 2);
188 if (version_ == 1) {
189 // For version 1 format, as a stopgap, pack uvec3 into first word:
190 // x << 21 | y << 10 | z. Second word is unused. (DEPRECATED)
191 Instruction* x_shft_inst = builder->AddBinaryOp(
192 GetUintId(), SpvOpShiftLeftLogical, x_inst->result_id(),
193 builder->GetUintConstantId(21));
194 Instruction* y_shft_inst = builder->AddBinaryOp(
195 GetUintId(), SpvOpShiftLeftLogical, y_inst->result_id(),
196 builder->GetUintConstantId(10));
197 Instruction* x_or_y_inst = builder->AddBinaryOp(
198 GetUintId(), SpvOpBitwiseOr, x_shft_inst->result_id(),
199 y_shft_inst->result_id());
200 Instruction* x_or_y_or_z_inst =
201 builder->AddBinaryOp(GetUintId(), SpvOpBitwiseOr,
202 x_or_y_inst->result_id(), z_inst->result_id());
203 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationId,
204 x_or_y_or_z_inst->result_id(), builder);
205 } else {
206 // For version 2 format, write all three words
207 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
208 x_inst->result_id(), builder);
209 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
210 y_inst->result_id(), builder);
211 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
212 z_inst->result_id(), builder);
213 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800214 } break;
215 case SpvExecutionModelGeometry: {
216 // Load and store PrimitiveId and InvocationId.
Ben Claytonb73b7602019-07-29 13:56:13 +0100217 GenBuiltinOutputCode(
218 context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
219 kInstGeomOutPrimitiveId, base_offset_id, builder);
220 GenBuiltinOutputCode(
221 context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
222 kInstGeomOutInvocationId, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800223 } break;
Ben Claytonb73b7602019-07-29 13:56:13 +0100224 case SpvExecutionModelTessellationControl: {
225 // Load and store InvocationId and PrimitiveId
226 GenBuiltinOutputCode(
227 context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
228 kInstTessCtlOutInvocationId, base_offset_id, builder);
229 GenBuiltinOutputCode(
230 context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
231 kInstTessCtlOutPrimitiveId, base_offset_id, builder);
232 } break;
Chris Forbescc5697f2019-01-30 11:54:08 -0800233 case SpvExecutionModelTessellationEvaluation: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100234 if (version_ == 1) {
235 // For format version 1, load and store InvocationId.
236 GenBuiltinOutputCode(
237 context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
238 kInstTessOutInvocationId, base_offset_id, builder);
239 } else {
240 // For format version 2, load and store PrimitiveId and TessCoord.uv
241 GenBuiltinOutputCode(
242 context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
243 kInstTessEvalOutPrimitiveId, base_offset_id, builder);
244 uint32_t load_id = GenVarLoad(
245 context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder);
246 Instruction* u_inst = builder->AddIdLiteralOp(
247 GetUintId(), SpvOpCompositeExtract, load_id, 0);
248 Instruction* v_inst = builder->AddIdLiteralOp(
249 GetUintId(), SpvOpCompositeExtract, load_id, 1);
250 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
251 u_inst->result_id(), builder);
252 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
253 v_inst->result_id(), builder);
254 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800255 } break;
256 case SpvExecutionModelFragment: {
257 // Load FragCoord and convert to Uint
Ben Claytonb73b7602019-07-29 13:56:13 +0100258 Instruction* frag_coord_inst = builder->AddUnaryOp(
259 GetVec4FloatId(), SpvOpLoad,
260 context()->GetBuiltinInputVarId(SpvBuiltInFragCoord));
Chris Forbescc5697f2019-01-30 11:54:08 -0800261 Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
262 GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
263 for (uint32_t u = 0; u < 2u; ++u)
264 GenFragCoordEltDebugOutputCode(
265 base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
266 } break;
Ben Claytonb73b7602019-07-29 13:56:13 +0100267 case SpvExecutionModelRayGenerationNV:
268 case SpvExecutionModelIntersectionNV:
269 case SpvExecutionModelAnyHitNV:
270 case SpvExecutionModelClosestHitNV:
271 case SpvExecutionModelMissNV:
272 case SpvExecutionModelCallableNV: {
273 // Load and store LaunchIdNV.
274 uint32_t launch_id = GenVarLoad(
275 context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder);
276 Instruction* x_launch_inst = builder->AddIdLiteralOp(
277 GetUintId(), SpvOpCompositeExtract, launch_id, 0);
278 Instruction* y_launch_inst = builder->AddIdLiteralOp(
279 GetUintId(), SpvOpCompositeExtract, launch_id, 1);
280 Instruction* z_launch_inst = builder->AddIdLiteralOp(
281 GetUintId(), SpvOpCompositeExtract, launch_id, 2);
282 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
283 x_launch_inst->result_id(), builder);
284 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
285 y_launch_inst->result_id(), builder);
286 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
287 z_launch_inst->result_id(), builder);
288 } break;
Chris Forbescc5697f2019-01-30 11:54:08 -0800289 default: { assert(false && "unsupported stage"); } break;
290 }
291}
292
293void InstrumentPass::GenDebugStreamWrite(
294 uint32_t instruction_idx, uint32_t stage_idx,
295 const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
296 // Call debug output function. Pass func_idx, instruction_idx and
297 // validation ids as args.
298 uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
299 uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt);
300 std::vector<uint32_t> args = {output_func_id,
301 builder->GetUintConstantId(instruction_idx)};
302 (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
303 (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
304}
305
Ben Claytonb73b7602019-07-29 13:56:13 +0100306uint32_t InstrumentPass::GenDebugDirectRead(
307 const std::vector<uint32_t>& offset_ids, InstructionBuilder* builder) {
308 // Call debug input function. Pass func_idx and offset ids as args.
309 uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
310 uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
311 std::vector<uint32_t> args = {input_func_id};
312 (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end());
313 return builder->AddNaryOp(GetUintId(), SpvOpFunctionCall, args)->result_id();
314}
315
Chris Forbescc5697f2019-01-30 11:54:08 -0800316bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
317 return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
318}
319
320void InstrumentPass::CloneSameBlockOps(
321 std::unique_ptr<Instruction>* inst,
322 std::unordered_map<uint32_t, uint32_t>* same_blk_post,
323 std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
Ben Claytonb73b7602019-07-29 13:56:13 +0100324 BasicBlock* block_ptr) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800325 (*inst)->ForEachInId(
326 [&same_blk_post, &same_blk_pre, &block_ptr, this](uint32_t* iid) {
327 const auto map_itr = (*same_blk_post).find(*iid);
328 if (map_itr == (*same_blk_post).end()) {
329 const auto map_itr2 = (*same_blk_pre).find(*iid);
330 if (map_itr2 != (*same_blk_pre).end()) {
331 // Clone pre-call same-block ops, map result id.
332 const Instruction* in_inst = map_itr2->second;
333 std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
334 CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
335 const uint32_t rid = sb_inst->result_id();
336 const uint32_t nid = this->TakeNextId();
337 get_decoration_mgr()->CloneDecorations(rid, nid);
338 sb_inst->SetResultId(nid);
339 (*same_blk_post)[rid] = nid;
340 *iid = nid;
Ben Claytonb73b7602019-07-29 13:56:13 +0100341 block_ptr->AddInstruction(std::move(sb_inst));
Chris Forbescc5697f2019-01-30 11:54:08 -0800342 }
343 } else {
344 // Reset same-block op operand.
345 *iid = map_itr->second;
346 }
347 });
348}
349
350void InstrumentPass::UpdateSucceedingPhis(
351 std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
352 const auto first_blk = new_blocks.begin();
353 const auto last_blk = new_blocks.end() - 1;
354 const uint32_t first_id = (*first_blk)->id();
355 const uint32_t last_id = (*last_blk)->id();
356 const BasicBlock& const_last_block = *last_blk->get();
357 const_last_block.ForEachSuccessorLabel(
358 [&first_id, &last_id, this](const uint32_t succ) {
359 BasicBlock* sbp = this->id2block_[succ];
360 sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
361 bool changed = false;
362 phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
363 if (*id == first_id) {
364 *id = last_id;
365 changed = true;
366 }
367 });
368 if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
369 });
370 });
371}
372
373// Return id for output buffer uint ptr type
Ben Claytonb73b7602019-07-29 13:56:13 +0100374uint32_t InstrumentPass::GetBufferUintPtrId() {
375 if (buffer_uint_ptr_id_ == 0) {
376 buffer_uint_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
Chris Forbescc5697f2019-01-30 11:54:08 -0800377 GetUintId(), SpvStorageClassStorageBuffer);
378 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100379 return buffer_uint_ptr_id_;
Chris Forbescc5697f2019-01-30 11:54:08 -0800380}
381
382uint32_t InstrumentPass::GetOutputBufferBinding() {
383 switch (validation_id_) {
384 case kInstValidationIdBindless:
385 return kDebugOutputBindingStream;
386 default:
387 assert(false && "unexpected validation id");
388 }
389 return 0;
390}
391
Ben Claytonb73b7602019-07-29 13:56:13 +0100392uint32_t InstrumentPass::GetInputBufferBinding() {
393 switch (validation_id_) {
394 case kInstValidationIdBindless:
395 return kDebugInputBindingBindless;
396 default:
397 assert(false && "unexpected validation id");
398 }
399 return 0;
400}
401
402analysis::Type* InstrumentPass::GetUintRuntimeArrayType(
403 analysis::DecorationManager* deco_mgr, analysis::TypeManager* type_mgr) {
404 if (uint_rarr_ty_ == nullptr) {
405 analysis::Integer uint_ty(32, false);
406 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
407 analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty);
408 uint_rarr_ty_ = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp);
409 uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(uint_rarr_ty_);
410 // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
411 // a block, and will therefore be decorated with an ArrayStride. Therefore
412 // the undecorated type returned here will not be pre-existing and can
413 // safely be decorated. Since this type is now decorated, it is out of
414 // sync with the TypeManager and therefore the TypeManager must be
415 // invalidated after this pass.
416 assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
417 "used RuntimeArray type returned");
418 deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u);
419 }
420 return uint_rarr_ty_;
421}
422
423void InstrumentPass::AddStorageBufferExt() {
424 if (storage_buffer_ext_defined_) return;
425 if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
426 const std::string ext_name("SPV_KHR_storage_buffer_storage_class");
427 const auto num_chars = ext_name.size();
428 // Compute num words, accommodate the terminating null character.
429 const auto num_words = (num_chars + 1 + 3) / 4;
430 std::vector<uint32_t> ext_words(num_words, 0u);
431 std::memcpy(ext_words.data(), ext_name.data(), num_chars);
432 context()->AddExtension(std::unique_ptr<Instruction>(
433 new Instruction(context(), SpvOpExtension, 0u, 0u,
434 {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
435 }
436 storage_buffer_ext_defined_ = true;
437}
438
Chris Forbescc5697f2019-01-30 11:54:08 -0800439// Return id for output buffer
440uint32_t InstrumentPass::GetOutputBufferId() {
441 if (output_buffer_id_ == 0) {
442 // If not created yet, create one
443 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
444 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytonb73b7602019-07-29 13:56:13 +0100445 analysis::Type* reg_uint_rarr_ty =
446 GetUintRuntimeArrayType(deco_mgr, type_mgr);
Chris Forbescc5697f2019-01-30 11:54:08 -0800447 analysis::Integer uint_ty(32, false);
448 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
Ben Claytonb73b7602019-07-29 13:56:13 +0100449 analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty});
450 analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
451 uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
452 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
453 // must be a block, and will therefore be decorated with Block. Therefore
454 // the undecorated type returned here will not be pre-existing and can
455 // safely be decorated. Since this type is now decorated, it is out of
456 // sync with the TypeManager and therefore the TypeManager must be
457 // invalidated after this pass.
458 assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
459 "used struct type returned");
Chris Forbescc5697f2019-01-30 11:54:08 -0800460 deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
461 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
462 SpvDecorationOffset, 0);
463 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
464 SpvDecorationOffset, 4);
465 uint32_t obufTyPtrId_ =
466 type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer);
467 output_buffer_id_ = TakeNextId();
468 std::unique_ptr<Instruction> newVarOp(new Instruction(
469 context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_,
470 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
471 {SpvStorageClassStorageBuffer}}}));
472 context()->AddGlobalValue(std::move(newVarOp));
473 deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet,
474 desc_set_);
475 deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
476 GetOutputBufferBinding());
Ben Claytonb73b7602019-07-29 13:56:13 +0100477 AddStorageBufferExt();
478 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
479 // Add the new buffer to all entry points.
480 for (auto& entry : get_module()->entry_points()) {
481 entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
482 context()->AnalyzeUses(&entry);
483 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800484 }
485 }
486 return output_buffer_id_;
487}
488
Ben Claytonb73b7602019-07-29 13:56:13 +0100489uint32_t InstrumentPass::GetInputBufferId() {
490 if (input_buffer_id_ == 0) {
491 // If not created yet, create one
492 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
493 analysis::TypeManager* type_mgr = context()->get_type_mgr();
494 analysis::Type* reg_uint_rarr_ty =
495 GetUintRuntimeArrayType(deco_mgr, type_mgr);
496 analysis::Struct buf_ty({reg_uint_rarr_ty});
497 analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
498 uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
499 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
500 // must be a block, and will therefore be decorated with Block. Therefore
501 // the undecorated type returned here will not be pre-existing and can
502 // safely be decorated. Since this type is now decorated, it is out of
503 // sync with the TypeManager and therefore the TypeManager must be
504 // invalidated after this pass.
505 assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
506 "used struct type returned");
507 deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock);
508 deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0);
509 uint32_t ibufTyPtrId_ =
510 type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer);
511 input_buffer_id_ = TakeNextId();
512 std::unique_ptr<Instruction> newVarOp(new Instruction(
513 context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_,
514 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
515 {SpvStorageClassStorageBuffer}}}));
516 context()->AddGlobalValue(std::move(newVarOp));
517 deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet,
518 desc_set_);
519 deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding,
520 GetInputBufferBinding());
521 AddStorageBufferExt();
522 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
523 // Add the new buffer to all entry points.
524 for (auto& entry : get_module()->entry_points()) {
525 entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
526 context()->AnalyzeUses(&entry);
527 }
528 }
529 }
530 return input_buffer_id_;
531}
532
Chris Forbescc5697f2019-01-30 11:54:08 -0800533uint32_t InstrumentPass::GetVec4FloatId() {
534 if (v4float_id_ == 0) {
535 analysis::TypeManager* type_mgr = context()->get_type_mgr();
536 analysis::Float float_ty(32);
537 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
538 analysis::Vector v4float_ty(reg_float_ty, 4);
539 analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
540 v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
541 }
542 return v4float_id_;
543}
544
545uint32_t InstrumentPass::GetUintId() {
546 if (uint_id_ == 0) {
547 analysis::TypeManager* type_mgr = context()->get_type_mgr();
548 analysis::Integer uint_ty(32, false);
549 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
550 uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
551 }
552 return uint_id_;
553}
554
555uint32_t InstrumentPass::GetVec4UintId() {
556 if (v4uint_id_ == 0) {
557 analysis::TypeManager* type_mgr = context()->get_type_mgr();
558 analysis::Integer uint_ty(32, false);
559 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
560 analysis::Vector v4uint_ty(reg_uint_ty, 4);
561 analysis::Type* reg_v4uint_ty = type_mgr->GetRegisteredType(&v4uint_ty);
562 v4uint_id_ = type_mgr->GetTypeInstruction(reg_v4uint_ty);
563 }
564 return v4uint_id_;
565}
566
567uint32_t InstrumentPass::GetBoolId() {
568 if (bool_id_ == 0) {
569 analysis::TypeManager* type_mgr = context()->get_type_mgr();
570 analysis::Bool bool_ty;
571 analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
572 bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
573 }
574 return bool_id_;
575}
576
577uint32_t InstrumentPass::GetVoidId() {
578 if (void_id_ == 0) {
579 analysis::TypeManager* type_mgr = context()->get_type_mgr();
580 analysis::Void void_ty;
581 analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
582 void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
583 }
584 return void_id_;
585}
586
587uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
588 uint32_t val_spec_param_cnt) {
589 // Total param count is common params plus validation-specific
590 // params
591 uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
592 if (output_func_id_ == 0) {
593 // Create function
594 output_func_id_ = TakeNextId();
595 analysis::TypeManager* type_mgr = context()->get_type_mgr();
596 std::vector<const analysis::Type*> param_types;
597 for (uint32_t c = 0; c < param_cnt; ++c)
598 param_types.push_back(type_mgr->GetType(GetUintId()));
599 analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
600 analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
601 std::unique_ptr<Instruction> func_inst(new Instruction(
602 get_module()->context(), SpvOpFunction, GetVoidId(), output_func_id_,
603 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
604 {SpvFunctionControlMaskNone}},
605 {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
606 {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
607 get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
608 std::unique_ptr<Function> output_func =
609 MakeUnique<Function>(std::move(func_inst));
610 // Add parameters
611 std::vector<uint32_t> param_vec;
612 for (uint32_t c = 0; c < param_cnt; ++c) {
613 uint32_t pid = TakeNextId();
614 param_vec.push_back(pid);
615 std::unique_ptr<Instruction> param_inst(
616 new Instruction(get_module()->context(), SpvOpFunctionParameter,
617 GetUintId(), pid, {}));
618 get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
619 output_func->AddParameter(std::move(param_inst));
620 }
621 // Create first block
622 uint32_t test_blk_id = TakeNextId();
623 std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
624 std::unique_ptr<BasicBlock> new_blk_ptr =
625 MakeUnique<BasicBlock>(std::move(test_label));
626 InstructionBuilder builder(
627 context(), &*new_blk_ptr,
628 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
629 // Gen test if debug output buffer size will not be exceeded.
Ben Claytonb73b7602019-07-29 13:56:13 +0100630 uint32_t val_spec_offset =
631 (version_ == 1) ? kInstStageOutCnt : kInst2StageOutCnt;
632 uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
Chris Forbescc5697f2019-01-30 11:54:08 -0800633 uint32_t buf_id = GetOutputBufferId();
Ben Claytonb73b7602019-07-29 13:56:13 +0100634 uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800635 Instruction* obuf_curr_sz_ac_inst =
636 builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
637 builder.GetUintConstantId(kDebugOutputSizeOffset));
638 // Fetch the current debug buffer written size atomically, adding the
639 // size of the record to be written.
640 uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
641 uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone);
642 uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation);
643 Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
644 GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
645 scope_invok_id, mask_none_id, obuf_record_sz_id);
646 uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
647 // Compute new written size
648 Instruction* obuf_new_sz_inst =
649 builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id,
650 builder.GetUintConstantId(obuf_record_sz));
651 // Fetch the data bound
652 Instruction* obuf_bnd_inst =
653 builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
654 GetOutputBufferId(), kDebugOutputDataOffset);
655 // Test that new written size is less than or equal to debug output
656 // data bound
657 Instruction* obuf_safe_inst = builder.AddBinaryOp(
658 GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(),
659 obuf_bnd_inst->result_id());
660 uint32_t merge_blk_id = TakeNextId();
661 uint32_t write_blk_id = TakeNextId();
662 std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
663 std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
664 (void)builder.AddConditionalBranch(obuf_safe_inst->result_id(),
665 write_blk_id, merge_blk_id, merge_blk_id,
666 SpvSelectionControlMaskNone);
667 // Close safety test block and gen write block
668 new_blk_ptr->SetParent(&*output_func);
669 output_func->AddBasicBlock(std::move(new_blk_ptr));
670 new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
671 builder.SetInsertPoint(&*new_blk_ptr);
672 // Generate common and stage-specific debug record members
673 GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx],
674 stage_idx, obuf_curr_sz_id, &builder);
675 GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
676 // Gen writes of validation specific data
677 for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100678 GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
Chris Forbescc5697f2019-01-30 11:54:08 -0800679 param_vec[kInstCommonParamCnt + i], &builder);
680 }
681 // Close write block and gen merge block
682 (void)builder.AddBranch(merge_blk_id);
683 new_blk_ptr->SetParent(&*output_func);
684 output_func->AddBasicBlock(std::move(new_blk_ptr));
685 new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
686 builder.SetInsertPoint(&*new_blk_ptr);
687 // Close merge block and function and add function to module
688 (void)builder.AddNullaryOp(0, SpvOpReturn);
689 new_blk_ptr->SetParent(&*output_func);
690 output_func->AddBasicBlock(std::move(new_blk_ptr));
691 std::unique_ptr<Instruction> func_end_inst(
692 new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
693 get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
694 output_func->SetFunctionEnd(std::move(func_end_inst));
695 context()->AddFunction(std::move(output_func));
696 output_func_param_cnt_ = param_cnt;
697 }
698 assert(param_cnt == output_func_param_cnt_ && "bad arg count");
699 return output_func_id_;
700}
701
Ben Claytonb73b7602019-07-29 13:56:13 +0100702uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
703 uint32_t func_id = param2input_func_id_[param_cnt];
704 if (func_id != 0) return func_id;
705 // Create input function for param_cnt
706 func_id = TakeNextId();
707 analysis::TypeManager* type_mgr = context()->get_type_mgr();
708 std::vector<const analysis::Type*> param_types;
709 for (uint32_t c = 0; c < param_cnt; ++c)
710 param_types.push_back(type_mgr->GetType(GetUintId()));
711 analysis::Function func_ty(type_mgr->GetType(GetUintId()), param_types);
712 analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
713 std::unique_ptr<Instruction> func_inst(new Instruction(
714 get_module()->context(), SpvOpFunction, GetUintId(), func_id,
715 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
716 {SpvFunctionControlMaskNone}},
717 {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
718 {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
719 get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
720 std::unique_ptr<Function> input_func =
721 MakeUnique<Function>(std::move(func_inst));
722 // Add parameters
723 std::vector<uint32_t> param_vec;
724 for (uint32_t c = 0; c < param_cnt; ++c) {
725 uint32_t pid = TakeNextId();
726 param_vec.push_back(pid);
727 std::unique_ptr<Instruction> param_inst(new Instruction(
728 get_module()->context(), SpvOpFunctionParameter, GetUintId(), pid, {}));
729 get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
730 input_func->AddParameter(std::move(param_inst));
731 }
732 // Create block
733 uint32_t blk_id = TakeNextId();
734 std::unique_ptr<Instruction> blk_label(NewLabel(blk_id));
735 std::unique_ptr<BasicBlock> new_blk_ptr =
736 MakeUnique<BasicBlock>(std::move(blk_label));
737 InstructionBuilder builder(
738 context(), &*new_blk_ptr,
739 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
740 // For each offset parameter, generate new offset with parameter, adding last
741 // loaded value if it exists, and load value from input buffer at new offset.
742 // Return last loaded value.
743 uint32_t buf_id = GetInputBufferId();
744 uint32_t buf_uint_ptr_id = GetBufferUintPtrId();
745 uint32_t last_value_id = 0;
746 for (uint32_t p = 0; p < param_cnt; ++p) {
747 uint32_t offset_id;
748 if (p == 0) {
749 offset_id = param_vec[0];
750 } else {
751 Instruction* offset_inst = builder.AddBinaryOp(
752 GetUintId(), SpvOpIAdd, last_value_id, param_vec[p]);
753 offset_id = offset_inst->result_id();
754 }
755 Instruction* ac_inst = builder.AddTernaryOp(
756 buf_uint_ptr_id, SpvOpAccessChain, buf_id,
757 builder.GetUintConstantId(kDebugInputDataOffset), offset_id);
758 Instruction* load_inst =
759 builder.AddUnaryOp(GetUintId(), SpvOpLoad, ac_inst->result_id());
760 last_value_id = load_inst->result_id();
761 }
762 (void)builder.AddInstruction(MakeUnique<Instruction>(
763 context(), SpvOpReturnValue, 0, 0,
764 std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {last_value_id}}}));
765 // Close block and function and add function to module
766 new_blk_ptr->SetParent(&*input_func);
767 input_func->AddBasicBlock(std::move(new_blk_ptr));
768 std::unique_ptr<Instruction> func_end_inst(
769 new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
770 get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
771 input_func->SetFunctionEnd(std::move(func_end_inst));
772 context()->AddFunction(std::move(input_func));
773 param2input_func_id_[param_cnt] = func_id;
774 return func_id;
775}
776
Chris Forbescc5697f2019-01-30 11:54:08 -0800777bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
778 InstProcessFunction& pfn) {
779 bool modified = false;
780 // Compute function index
781 uint32_t function_idx = 0;
782 for (auto fii = get_module()->begin(); fii != get_module()->end(); ++fii) {
783 if (&*fii == func) break;
784 ++function_idx;
785 }
786 std::vector<std::unique_ptr<BasicBlock>> new_blks;
Chris Forbescc5697f2019-01-30 11:54:08 -0800787 // Using block iterators here because of block erasures and insertions.
788 for (auto bi = func->begin(); bi != func->end(); ++bi) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100789 for (auto ii = bi->begin(); ii != bi->end();) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800790 // Generate instrumentation if warranted
Ben Claytonb73b7602019-07-29 13:56:13 +0100791 pfn(ii, bi, stage_idx, &new_blks);
Chris Forbescc5697f2019-01-30 11:54:08 -0800792 if (new_blks.size() == 0) {
793 ++ii;
794 continue;
795 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100796 // Add new blocks to label id map
797 for (auto& blk : new_blks) id2block_[blk->id()] = &*blk;
Chris Forbescc5697f2019-01-30 11:54:08 -0800798 // If there are new blocks we know there will always be two or
799 // more, so update succeeding phis with label of new last block.
800 size_t newBlocksSize = new_blks.size();
801 assert(newBlocksSize > 1);
802 UpdateSucceedingPhis(new_blks);
803 // Replace original block with new block(s)
804 bi = bi.Erase();
805 for (auto& bb : new_blks) {
806 bb->SetParent(func);
807 }
808 bi = bi.InsertBefore(&new_blks);
809 // Reset block iterator to last new block
810 for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
811 modified = true;
812 // Restart instrumenting at beginning of last new block,
813 // but skip over any new phi or copy instruction.
814 ii = bi->begin();
815 if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii;
816 new_blks.clear();
817 }
818 }
819 return modified;
820}
821
822bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
823 std::queue<uint32_t>* roots,
824 uint32_t stage_idx) {
825 bool modified = false;
826 std::unordered_set<uint32_t> done;
Ben Claytonb73b7602019-07-29 13:56:13 +0100827 // Don't process input and output functions
828 for (auto& ifn : param2input_func_id_) done.insert(ifn.second);
829 if (output_func_id_ != 0) done.insert(output_func_id_);
Chris Forbescc5697f2019-01-30 11:54:08 -0800830 // Process all functions from roots
831 while (!roots->empty()) {
832 const uint32_t fi = roots->front();
833 roots->pop();
834 if (done.insert(fi).second) {
835 Function* fn = id2function_.at(fi);
836 // Add calls first so we don't add new output function
837 context()->AddCalls(fn, roots);
838 modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
839 }
840 }
841 return modified;
842}
843
844bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
845 // Make sure all entry points have the same execution model. Do not
846 // instrument if they do not.
847 // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
848 // can contain entry points with different execution models, although
849 // such modules will likely be rare as GLSL and HLSL are geared toward
850 // one model per module. In such cases we will need
851 // to clone any functions which are in the call trees of entrypoints
852 // with differing execution models.
853 uint32_t ecnt = 0;
854 uint32_t stage = SpvExecutionModelMax;
855 for (auto& e : get_module()->entry_points()) {
856 if (ecnt == 0)
857 stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
858 else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) != stage)
859 return false;
860 ++ecnt;
861 }
862 // Only supporting vertex, fragment and compute shaders at the moment.
863 // TODO(greg-lunarg): Handle all stages.
864 if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment &&
865 stage != SpvExecutionModelGeometry &&
866 stage != SpvExecutionModelGLCompute &&
867 stage != SpvExecutionModelTessellationControl &&
Ben Claytonb73b7602019-07-29 13:56:13 +0100868 stage != SpvExecutionModelTessellationEvaluation &&
869 stage != SpvExecutionModelRayGenerationNV &&
870 stage != SpvExecutionModelIntersectionNV &&
871 stage != SpvExecutionModelAnyHitNV &&
872 stage != SpvExecutionModelClosestHitNV &&
873 stage != SpvExecutionModelMissNV && stage != SpvExecutionModelCallableNV)
Chris Forbescc5697f2019-01-30 11:54:08 -0800874 return false;
875 // Add together the roots of all entry points
876 std::queue<uint32_t> roots;
877 for (auto& e : get_module()->entry_points()) {
878 roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
879 }
880 bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage);
881 return modified;
882}
883
884void InstrumentPass::InitializeInstrument() {
885 output_buffer_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +0100886 buffer_uint_ptr_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -0800887 output_func_id_ = 0;
888 output_func_param_cnt_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +0100889 input_buffer_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -0800890 v4float_id_ = 0;
891 uint_id_ = 0;
892 v4uint_id_ = 0;
893 bool_id_ = 0;
894 void_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +0100895 storage_buffer_ext_defined_ = false;
896 uint_rarr_ty_ = nullptr;
Chris Forbescc5697f2019-01-30 11:54:08 -0800897
898 // clear collections
899 id2function_.clear();
900 id2block_.clear();
901
902 // Initialize function and block maps.
903 for (auto& fn : *get_module()) {
904 id2function_[fn.result_id()] = &fn;
905 for (auto& blk : fn) {
906 id2block_[blk.id()] = &blk;
907 }
908 }
909
Ben Claytonb73b7602019-07-29 13:56:13 +0100910 // Remember original instruction offsets
911 uint32_t module_offset = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -0800912 Module* module = get_module();
913 for (auto& i : context()->capabilities()) {
914 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100915 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800916 }
917 for (auto& i : module->extensions()) {
918 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100919 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800920 }
921 for (auto& i : module->ext_inst_imports()) {
922 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100923 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800924 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100925 ++module_offset; // memory_model
Chris Forbescc5697f2019-01-30 11:54:08 -0800926 for (auto& i : module->entry_points()) {
927 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100928 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800929 }
930 for (auto& i : module->execution_modes()) {
931 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100932 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800933 }
934 for (auto& i : module->debugs1()) {
935 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100936 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800937 }
938 for (auto& i : module->debugs2()) {
939 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100940 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800941 }
942 for (auto& i : module->debugs3()) {
943 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100944 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800945 }
946 for (auto& i : module->annotations()) {
947 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +0100948 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -0800949 }
950 for (auto& i : module->types_values()) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100951 module_offset += 1;
952 module_offset += static_cast<uint32_t>(i.dbg_line_insts().size());
Chris Forbescc5697f2019-01-30 11:54:08 -0800953 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800954
Ben Claytonb73b7602019-07-29 13:56:13 +0100955 auto curr_fn = get_module()->begin();
956 for (; curr_fn != get_module()->end(); ++curr_fn) {
957 // Count function instruction
958 module_offset += 1;
959 curr_fn->ForEachParam(
960 [&module_offset](const Instruction*) { module_offset += 1; }, true);
961 for (auto& blk : *curr_fn) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800962 // Count label
Ben Claytonb73b7602019-07-29 13:56:13 +0100963 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -0800964 for (auto& inst : blk) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100965 module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size());
966 uid2offset_[inst.unique_id()] = module_offset;
967 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -0800968 }
969 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100970 // Count function end instruction
971 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -0800972 }
973}
974
975} // namespace opt
976} // namespace spvtools