blob: 441d943f700e04278e5df13852c29a17dc86646e [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
Chris Forbescc5697f2019-01-30 11:54:08 -080022namespace spvtools {
23namespace opt {
Nicolas Capens84c9c452022-11-18 14:11:05 +000024namespace {
25// Common Parameter Positions
26constexpr int kInstCommonParamInstIdx = 0;
27constexpr int kInstCommonParamCnt = 1;
28// Indices of operands in SPIR-V instructions
29constexpr int kEntryPointFunctionIdInIdx = 1;
30} // namespace
Chris Forbescc5697f2019-01-30 11:54:08 -080031
32void InstrumentPass::MovePreludeCode(
33 BasicBlock::iterator ref_inst_itr,
34 UptrVectorIterator<BasicBlock> ref_block_itr,
35 std::unique_ptr<BasicBlock>* new_blk_ptr) {
36 same_block_pre_.clear();
37 same_block_post_.clear();
38 // Initialize new block. Reuse label from original block.
39 new_blk_ptr->reset(new BasicBlock(std::move(ref_block_itr->GetLabel())));
40 // Move contents of original ref block up to ref instruction.
41 for (auto cii = ref_block_itr->begin(); cii != ref_inst_itr;
42 cii = ref_block_itr->begin()) {
43 Instruction* inst = &*cii;
44 inst->RemoveFromList();
45 std::unique_ptr<Instruction> mv_ptr(inst);
46 // Remember same-block ops for possible regeneration.
47 if (IsSameBlockOp(&*mv_ptr)) {
48 auto* sb_inst_ptr = mv_ptr.get();
49 same_block_pre_[mv_ptr->result_id()] = sb_inst_ptr;
50 }
51 (*new_blk_ptr)->AddInstruction(std::move(mv_ptr));
52 }
53}
54
55void InstrumentPass::MovePostludeCode(
Ben Claytonb73b7602019-07-29 13:56:13 +010056 UptrVectorIterator<BasicBlock> ref_block_itr, BasicBlock* new_blk_ptr) {
Chris Forbescc5697f2019-01-30 11:54:08 -080057 // new_blk_ptr->reset(new BasicBlock(NewLabel(ref_block_itr->id())));
58 // Move contents of original ref block.
59 for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end();
60 cii = ref_block_itr->begin()) {
61 Instruction* inst = &*cii;
62 inst->RemoveFromList();
63 std::unique_ptr<Instruction> mv_inst(inst);
64 // Regenerate any same-block instruction that has not been seen in the
65 // current block.
66 if (same_block_pre_.size() > 0) {
67 CloneSameBlockOps(&mv_inst, &same_block_post_, &same_block_pre_,
68 new_blk_ptr);
69 // Remember same-block ops in this block.
70 if (IsSameBlockOp(&*mv_inst)) {
71 const uint32_t rid = mv_inst->result_id();
72 same_block_post_[rid] = rid;
73 }
74 }
Ben Claytonb73b7602019-07-29 13:56:13 +010075 new_blk_ptr->AddInstruction(std::move(mv_inst));
Chris Forbescc5697f2019-01-30 11:54:08 -080076 }
77}
78
79std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
80 std::unique_ptr<Instruction> newLabel(
Nicolas Capens84c9c452022-11-18 14:11:05 +000081 new Instruction(context(), spv::Op::OpLabel, 0, label_id, {}));
Chris Forbescc5697f2019-01-30 11:54:08 -080082 get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel);
83 return newLabel;
84}
85
Nicolas Capens84c9c452022-11-18 14:11:05 +000086std::unique_ptr<Instruction> InstrumentPass::NewName(
87 uint32_t id, const std::string& name_str) {
88 std::unique_ptr<Instruction> new_name(new Instruction(
89 context(), spv::Op::OpName, 0, 0,
90 std::initializer_list<Operand>{
91 {SPV_OPERAND_TYPE_ID, {id}},
92 {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
93
94 return new_name;
95}
96
97std::unique_ptr<Instruction> InstrumentPass::NewGlobalName(
98 uint32_t id, const std::string& name_str) {
99 std::string prefixed_name;
100 switch (validation_id_) {
101 case kInstValidationIdBindless:
102 prefixed_name = "inst_bindless_";
103 break;
104 case kInstValidationIdBuffAddr:
105 prefixed_name = "inst_buff_addr_";
106 break;
107 case kInstValidationIdDebugPrintf:
108 prefixed_name = "inst_printf_";
109 break;
110 default:
111 assert(false); // add new instrumentation pass here
112 prefixed_name = "inst_pass_";
113 break;
114 }
115 prefixed_name += name_str;
116 return NewName(id, prefixed_name);
117}
118
119std::unique_ptr<Instruction> InstrumentPass::NewMemberName(
120 uint32_t id, uint32_t member_index, const std::string& name_str) {
121 std::unique_ptr<Instruction> new_name(new Instruction(
122 context(), spv::Op::OpMemberName, 0, 0,
123 std::initializer_list<Operand>{
124 {SPV_OPERAND_TYPE_ID, {id}},
125 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
126 {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}));
127
128 return new_name;
129}
130
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400131uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
132 InstructionBuilder* builder) {
133 // Convert integer value to 32-bit if necessary
134 analysis::TypeManager* type_mgr = context()->get_type_mgr();
135 uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_id)->type_id();
136 analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
137 if (val_ty->width() == 32) return val_id;
138 bool is_signed = val_ty->IsSigned();
139 analysis::Integer val_32b_ty(32, is_signed);
140 analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty);
141 uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty);
142 if (is_signed)
Nicolas Capens84c9c452022-11-18 14:11:05 +0000143 return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpSConvert, val_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400144 ->result_id();
145 else
Nicolas Capens84c9c452022-11-18 14:11:05 +0000146 return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpUConvert, val_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400147 ->result_id();
148}
149
Chris Forbescc5697f2019-01-30 11:54:08 -0800150uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
151 InstructionBuilder* builder) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400152 // Convert value to 32-bit if necessary
153 uint32_t val_32b_id = Gen32BitCvtCode(val_id, builder);
154 // Cast value to unsigned if necessary
155 analysis::TypeManager* type_mgr = context()->get_type_mgr();
156 uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id();
157 analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
158 if (!val_ty->IsSigned()) return val_32b_id;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000159 return builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast, val_32b_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400160 ->result_id();
Chris Forbescc5697f2019-01-30 11:54:08 -0800161}
162
163void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
164 uint32_t field_offset,
165 uint32_t field_value_id,
166 InstructionBuilder* builder) {
167 // Cast value to 32-bit unsigned if necessary
168 uint32_t val_id = GenUintCastCode(field_value_id, builder);
169 // Store value
170 Instruction* data_idx_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000171 builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, base_offset_id,
Chris Forbescc5697f2019-01-30 11:54:08 -0800172 builder->GetUintConstantId(field_offset));
173 uint32_t buf_id = GetOutputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100174 uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800175 Instruction* achain_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000176 builder->AddTernaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id,
Chris Forbescc5697f2019-01-30 11:54:08 -0800177 builder->GetUintConstantId(kDebugOutputDataOffset),
178 data_idx_inst->result_id());
Nicolas Capens84c9c452022-11-18 14:11:05 +0000179 (void)builder->AddBinaryOp(0, spv::Op::OpStore, achain_inst->result_id(),
180 val_id);
Chris Forbescc5697f2019-01-30 11:54:08 -0800181}
182
183void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
184 uint32_t inst_id,
185 uint32_t stage_idx,
186 uint32_t base_offset_id,
187 InstructionBuilder* builder) {
188 // Store record size
189 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
190 builder->GetUintConstantId(record_sz), builder);
191 // Store Shader Id
192 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
193 builder->GetUintConstantId(shader_id_), builder);
194 // Store Instruction Idx
195 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
196 builder);
197 // Store Stage Idx
198 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
199 builder->GetUintConstantId(stage_idx), builder);
200}
201
202void InstrumentPass::GenFragCoordEltDebugOutputCode(
203 uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
204 InstructionBuilder* builder) {
205 Instruction* element_val_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000206 GetUintId(), spv::Op::OpCompositeExtract, uint_frag_coord_id, element);
Chris Forbescc5697f2019-01-30 11:54:08 -0800207 GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
208 element_val_inst->result_id(), builder);
209}
210
Ben Claytonb73b7602019-07-29 13:56:13 +0100211uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
212 InstructionBuilder* builder) {
213 Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
214 uint32_t type_id = GetPointeeTypeId(var_inst);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000215 Instruction* load_inst =
216 builder->AddUnaryOp(type_id, spv::Op::OpLoad, var_id);
Ben Claytonb73b7602019-07-29 13:56:13 +0100217 return load_inst->result_id();
218}
219
Chris Forbescc5697f2019-01-30 11:54:08 -0800220void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
221 uint32_t builtin_off,
222 uint32_t base_offset_id,
223 InstructionBuilder* builder) {
224 // Load and store builtin
Ben Claytonb73b7602019-07-29 13:56:13 +0100225 uint32_t load_id = GenVarLoad(builtin_id, builder);
226 GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800227}
228
229void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
230 uint32_t base_offset_id,
231 InstructionBuilder* builder) {
232 // TODO(greg-lunarg): Add support for all stages
Nicolas Capens84c9c452022-11-18 14:11:05 +0000233 switch (spv::ExecutionModel(stage_idx)) {
234 case spv::ExecutionModel::Vertex: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800235 // Load and store VertexId and InstanceId
Ben Claytonb73b7602019-07-29 13:56:13 +0100236 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000237 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100238 kInstVertOutVertexIndex, base_offset_id, builder);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000239 GenBuiltinOutputCode(context()->GetBuiltinInputVarId(
240 uint32_t(spv::BuiltIn::InstanceIndex)),
241 kInstVertOutInstanceIndex, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800242 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000243 case spv::ExecutionModel::GLCompute:
244 case spv::ExecutionModel::TaskNV:
245 case spv::ExecutionModel::MeshNV:
246 case spv::ExecutionModel::TaskEXT:
247 case spv::ExecutionModel::MeshEXT: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100248 // Load and store GlobalInvocationId.
Nicolas Capens84c9c452022-11-18 14:11:05 +0000249 uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t(
250 spv::BuiltIn::GlobalInvocationId)),
251 builder);
Ben Claytonb73b7602019-07-29 13:56:13 +0100252 Instruction* x_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000253 GetUintId(), spv::Op::OpCompositeExtract, load_id, 0);
Ben Claytonb73b7602019-07-29 13:56:13 +0100254 Instruction* y_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000255 GetUintId(), spv::Op::OpCompositeExtract, load_id, 1);
Ben Claytonb73b7602019-07-29 13:56:13 +0100256 Instruction* z_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000257 GetUintId(), spv::Op::OpCompositeExtract, load_id, 2);
Ben Clayton0b54f132020-01-06 13:38:54 +0000258 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
259 x_inst->result_id(), builder);
260 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
261 y_inst->result_id(), builder);
262 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
263 z_inst->result_id(), builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800264 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000265 case spv::ExecutionModel::Geometry: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800266 // Load and store PrimitiveId and InvocationId.
Ben Claytonb73b7602019-07-29 13:56:13 +0100267 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000268 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100269 kInstGeomOutPrimitiveId, base_offset_id, builder);
270 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000271 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100272 kInstGeomOutInvocationId, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800273 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000274 case spv::ExecutionModel::TessellationControl: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100275 // Load and store InvocationId and PrimitiveId
276 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000277 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100278 kInstTessCtlOutInvocationId, base_offset_id, builder);
279 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000280 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100281 kInstTessCtlOutPrimitiveId, base_offset_id, builder);
282 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000283 case spv::ExecutionModel::TessellationEvaluation: {
Ben Clayton0b54f132020-01-06 13:38:54 +0000284 // Load and store PrimitiveId and TessCoord.uv
285 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000286 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Clayton0b54f132020-01-06 13:38:54 +0000287 kInstTessEvalOutPrimitiveId, base_offset_id, builder);
288 uint32_t load_id = GenVarLoad(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000289 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)),
290 builder);
Ben Clayton0b54f132020-01-06 13:38:54 +0000291 Instruction* uvec3_cast_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000292 builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id);
Ben Clayton0b54f132020-01-06 13:38:54 +0000293 uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
294 Instruction* u_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000295 GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 0);
Ben Clayton0b54f132020-01-06 13:38:54 +0000296 Instruction* v_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000297 GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 1);
Ben Clayton0b54f132020-01-06 13:38:54 +0000298 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
299 u_inst->result_id(), builder);
300 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
301 v_inst->result_id(), builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800302 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000303 case spv::ExecutionModel::Fragment: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800304 // Load FragCoord and convert to Uint
Ben Claytonb73b7602019-07-29 13:56:13 +0100305 Instruction* frag_coord_inst = builder->AddUnaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000306 GetVec4FloatId(), spv::Op::OpLoad,
307 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord)));
Chris Forbescc5697f2019-01-30 11:54:08 -0800308 Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000309 GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id());
Chris Forbescc5697f2019-01-30 11:54:08 -0800310 for (uint32_t u = 0; u < 2u; ++u)
311 GenFragCoordEltDebugOutputCode(
312 base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
313 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000314 case spv::ExecutionModel::RayGenerationNV:
315 case spv::ExecutionModel::IntersectionNV:
316 case spv::ExecutionModel::AnyHitNV:
317 case spv::ExecutionModel::ClosestHitNV:
318 case spv::ExecutionModel::MissNV:
319 case spv::ExecutionModel::CallableNV: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100320 // Load and store LaunchIdNV.
321 uint32_t launch_id = GenVarLoad(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000322 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)),
323 builder);
Ben Claytonb73b7602019-07-29 13:56:13 +0100324 Instruction* x_launch_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000325 GetUintId(), spv::Op::OpCompositeExtract, launch_id, 0);
Ben Claytonb73b7602019-07-29 13:56:13 +0100326 Instruction* y_launch_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000327 GetUintId(), spv::Op::OpCompositeExtract, launch_id, 1);
Ben Claytonb73b7602019-07-29 13:56:13 +0100328 Instruction* z_launch_inst = builder->AddIdLiteralOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000329 GetUintId(), spv::Op::OpCompositeExtract, launch_id, 2);
Ben Claytonb73b7602019-07-29 13:56:13 +0100330 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
331 x_launch_inst->result_id(), builder);
332 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
333 y_launch_inst->result_id(), builder);
334 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
335 z_launch_inst->result_id(), builder);
336 } break;
Chris Forbescc5697f2019-01-30 11:54:08 -0800337 default: { assert(false && "unsupported stage"); } break;
338 }
339}
340
341void InstrumentPass::GenDebugStreamWrite(
342 uint32_t instruction_idx, uint32_t stage_idx,
343 const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
344 // Call debug output function. Pass func_idx, instruction_idx and
345 // validation ids as args.
346 uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
347 uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt);
348 std::vector<uint32_t> args = {output_func_id,
349 builder->GetUintConstantId(instruction_idx)};
350 (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
Nicolas Capens84c9c452022-11-18 14:11:05 +0000351 (void)builder->AddNaryOp(GetVoidId(), spv::Op::OpFunctionCall, args);
Chris Forbescc5697f2019-01-30 11:54:08 -0800352}
353
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400354bool InstrumentPass::AllConstant(const std::vector<uint32_t>& ids) {
355 for (auto& id : ids) {
356 Instruction* id_inst = context()->get_def_use_mgr()->GetDef(id);
357 if (!spvOpcodeIsConstant(id_inst->opcode())) return false;
358 }
359 return true;
360}
361
Ben Claytonb73b7602019-07-29 13:56:13 +0100362uint32_t InstrumentPass::GenDebugDirectRead(
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400363 const std::vector<uint32_t>& offset_ids, InstructionBuilder* ref_builder) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100364 // Call debug input function. Pass func_idx and offset ids as args.
365 uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
366 uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
367 std::vector<uint32_t> args = {input_func_id};
368 (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end());
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400369 // If optimizing direct reads and the call has already been generated,
370 // use its result
371 if (opt_direct_reads_) {
372 uint32_t res_id = call2id_[args];
373 if (res_id != 0) return res_id;
374 }
375 // If the offsets are all constants, the call can be moved to the first block
376 // of the function where its result can be reused. One example where this is
377 // profitable is for uniform buffer references, of which there are often many.
378 InstructionBuilder builder(ref_builder->GetContext(),
379 &*ref_builder->GetInsertPoint(),
380 ref_builder->GetPreservedAnalysis());
381 bool insert_in_first_block = opt_direct_reads_ && AllConstant(offset_ids);
382 if (insert_in_first_block) {
383 Instruction* insert_before = &*curr_func_->begin()->tail();
384 builder.SetInsertPoint(insert_before);
385 }
386 uint32_t res_id =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000387 builder.AddNaryOp(GetUintId(), spv::Op::OpFunctionCall, args)
388 ->result_id();
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400389 if (insert_in_first_block) call2id_[args] = res_id;
390 return res_id;
Ben Claytonb73b7602019-07-29 13:56:13 +0100391}
392
Chris Forbescc5697f2019-01-30 11:54:08 -0800393bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
Nicolas Capens84c9c452022-11-18 14:11:05 +0000394 return inst->opcode() == spv::Op::OpSampledImage ||
395 inst->opcode() == spv::Op::OpImage;
Chris Forbescc5697f2019-01-30 11:54:08 -0800396}
397
398void InstrumentPass::CloneSameBlockOps(
399 std::unique_ptr<Instruction>* inst,
400 std::unordered_map<uint32_t, uint32_t>* same_blk_post,
401 std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
Ben Claytonb73b7602019-07-29 13:56:13 +0100402 BasicBlock* block_ptr) {
Ben Claytond552f632019-11-18 11:18:41 +0000403 bool changed = false;
404 (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed,
405 this](uint32_t* iid) {
406 const auto map_itr = (*same_blk_post).find(*iid);
407 if (map_itr == (*same_blk_post).end()) {
408 const auto map_itr2 = (*same_blk_pre).find(*iid);
409 if (map_itr2 != (*same_blk_pre).end()) {
410 // Clone pre-call same-block ops, map result id.
411 const Instruction* in_inst = map_itr2->second;
412 std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
413 const uint32_t rid = sb_inst->result_id();
414 const uint32_t nid = this->TakeNextId();
415 get_decoration_mgr()->CloneDecorations(rid, nid);
416 sb_inst->SetResultId(nid);
417 get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst);
418 (*same_blk_post)[rid] = nid;
419 *iid = nid;
420 changed = true;
421 CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
422 block_ptr->AddInstruction(std::move(sb_inst));
423 }
424 } else {
425 // Reset same-block op operand if necessary
426 if (*iid != map_itr->second) {
427 *iid = map_itr->second;
428 changed = true;
429 }
430 }
431 });
432 if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst);
Chris Forbescc5697f2019-01-30 11:54:08 -0800433}
434
435void InstrumentPass::UpdateSucceedingPhis(
436 std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
437 const auto first_blk = new_blocks.begin();
438 const auto last_blk = new_blocks.end() - 1;
439 const uint32_t first_id = (*first_blk)->id();
440 const uint32_t last_id = (*last_blk)->id();
441 const BasicBlock& const_last_block = *last_blk->get();
442 const_last_block.ForEachSuccessorLabel(
443 [&first_id, &last_id, this](const uint32_t succ) {
444 BasicBlock* sbp = this->id2block_[succ];
445 sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
446 bool changed = false;
447 phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
448 if (*id == first_id) {
449 *id = last_id;
450 changed = true;
451 }
452 });
453 if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
454 });
455 });
456}
457
Ben Claytond0f684e2019-08-30 22:36:08 +0100458uint32_t InstrumentPass::GetOutputBufferPtrId() {
459 if (output_buffer_ptr_id_ == 0) {
460 output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000461 GetUintId(), spv::StorageClass::StorageBuffer);
Chris Forbescc5697f2019-01-30 11:54:08 -0800462 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100463 return output_buffer_ptr_id_;
464}
465
466uint32_t InstrumentPass::GetInputBufferTypeId() {
467 return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id()
468 : GetUintId();
469}
470
471uint32_t InstrumentPass::GetInputBufferPtrId() {
472 if (input_buffer_ptr_id_ == 0) {
473 input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000474 GetInputBufferTypeId(), spv::StorageClass::StorageBuffer);
Ben Claytond0f684e2019-08-30 22:36:08 +0100475 }
476 return input_buffer_ptr_id_;
Chris Forbescc5697f2019-01-30 11:54:08 -0800477}
478
479uint32_t InstrumentPass::GetOutputBufferBinding() {
480 switch (validation_id_) {
481 case kInstValidationIdBindless:
482 return kDebugOutputBindingStream;
Ben Claytond0f684e2019-08-30 22:36:08 +0100483 case kInstValidationIdBuffAddr:
484 return kDebugOutputBindingStream;
Alexis Hetub8a77462020-03-27 07:59:09 -0400485 case kInstValidationIdDebugPrintf:
486 return kDebugOutputPrintfStream;
Chris Forbescc5697f2019-01-30 11:54:08 -0800487 default:
488 assert(false && "unexpected validation id");
489 }
490 return 0;
491}
492
Ben Claytonb73b7602019-07-29 13:56:13 +0100493uint32_t InstrumentPass::GetInputBufferBinding() {
494 switch (validation_id_) {
495 case kInstValidationIdBindless:
496 return kDebugInputBindingBindless;
Ben Claytond0f684e2019-08-30 22:36:08 +0100497 case kInstValidationIdBuffAddr:
498 return kDebugInputBindingBuffAddr;
Ben Claytonb73b7602019-07-29 13:56:13 +0100499 default:
500 assert(false && "unexpected validation id");
501 }
502 return 0;
503}
504
Ben Claytond0f684e2019-08-30 22:36:08 +0100505analysis::Type* InstrumentPass::GetUintXRuntimeArrayType(
506 uint32_t width, analysis::Type** rarr_ty) {
507 if (*rarr_ty == nullptr) {
508 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
509 analysis::TypeManager* type_mgr = context()->get_type_mgr();
510 analysis::Integer uint_ty(width, false);
Ben Claytonb73b7602019-07-29 13:56:13 +0100511 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
512 analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty);
Ben Claytond0f684e2019-08-30 22:36:08 +0100513 *rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp);
514 uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(*rarr_ty);
Ben Claytonb73b7602019-07-29 13:56:13 +0100515 // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
516 // a block, and will therefore be decorated with an ArrayStride. Therefore
517 // the undecorated type returned here will not be pre-existing and can
518 // safely be decorated. Since this type is now decorated, it is out of
519 // sync with the TypeManager and therefore the TypeManager must be
520 // invalidated after this pass.
521 assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
522 "used RuntimeArray type returned");
Nicolas Capens84c9c452022-11-18 14:11:05 +0000523 deco_mgr->AddDecorationVal(
524 uint_arr_ty_id, uint32_t(spv::Decoration::ArrayStride), width / 8u);
Ben Claytonb73b7602019-07-29 13:56:13 +0100525 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100526 return *rarr_ty;
527}
528
529analysis::Type* InstrumentPass::GetUintRuntimeArrayType(uint32_t width) {
530 analysis::Type** rarr_ty =
531 (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_;
532 return GetUintXRuntimeArrayType(width, rarr_ty);
Ben Claytonb73b7602019-07-29 13:56:13 +0100533}
534
535void InstrumentPass::AddStorageBufferExt() {
536 if (storage_buffer_ext_defined_) return;
537 if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
Ben Claytond0f684e2019-08-30 22:36:08 +0100538 context()->AddExtension("SPV_KHR_storage_buffer_storage_class");
Ben Claytonb73b7602019-07-29 13:56:13 +0100539 }
540 storage_buffer_ext_defined_ = true;
541}
542
Chris Forbescc5697f2019-01-30 11:54:08 -0800543// Return id for output buffer
544uint32_t InstrumentPass::GetOutputBufferId() {
545 if (output_buffer_id_ == 0) {
546 // If not created yet, create one
547 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
548 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytond0f684e2019-08-30 22:36:08 +0100549 analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
Chris Forbescc5697f2019-01-30 11:54:08 -0800550 analysis::Integer uint_ty(32, false);
551 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000552 analysis::Struct buf_ty({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
Ben Claytonb73b7602019-07-29 13:56:13 +0100553 analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
554 uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
555 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
556 // must be a block, and will therefore be decorated with Block. Therefore
557 // the undecorated type returned here will not be pre-existing and can
558 // safely be decorated. Since this type is now decorated, it is out of
559 // sync with the TypeManager and therefore the TypeManager must be
560 // invalidated after this pass.
561 assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
562 "used struct type returned");
Nicolas Capens84c9c452022-11-18 14:11:05 +0000563 deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
564 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
565 uint32_t(spv::Decoration::Offset), 0);
Chris Forbescc5697f2019-01-30 11:54:08 -0800566 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000567 uint32_t(spv::Decoration::Offset), 4);
Chris Forbescc5697f2019-01-30 11:54:08 -0800568 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000569 uint32_t(spv::Decoration::Offset), 8);
Chris Forbescc5697f2019-01-30 11:54:08 -0800570 uint32_t obufTyPtrId_ =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000571 type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
Chris Forbescc5697f2019-01-30 11:54:08 -0800572 output_buffer_id_ = TakeNextId();
573 std::unique_ptr<Instruction> newVarOp(new Instruction(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000574 context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
Chris Forbescc5697f2019-01-30 11:54:08 -0800575 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000576 {uint32_t(spv::StorageClass::StorageBuffer)}}}));
Chris Forbescc5697f2019-01-30 11:54:08 -0800577 context()->AddGlobalValue(std::move(newVarOp));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000578 context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
579 context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
580 context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
581 context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
582 context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
583 deco_mgr->AddDecorationVal(
584 output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
585 deco_mgr->AddDecorationVal(output_buffer_id_,
586 uint32_t(spv::Decoration::Binding),
Chris Forbescc5697f2019-01-30 11:54:08 -0800587 GetOutputBufferBinding());
Ben Claytonb73b7602019-07-29 13:56:13 +0100588 AddStorageBufferExt();
589 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
590 // Add the new buffer to all entry points.
591 for (auto& entry : get_module()->entry_points()) {
592 entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
593 context()->AnalyzeUses(&entry);
594 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800595 }
596 }
597 return output_buffer_id_;
598}
599
Ben Claytonb73b7602019-07-29 13:56:13 +0100600uint32_t InstrumentPass::GetInputBufferId() {
601 if (input_buffer_id_ == 0) {
602 // If not created yet, create one
603 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
604 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytond0f684e2019-08-30 22:36:08 +0100605 uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u;
606 analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width);
Ben Claytonb73b7602019-07-29 13:56:13 +0100607 analysis::Struct buf_ty({reg_uint_rarr_ty});
608 analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
609 uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
610 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
611 // must be a block, and will therefore be decorated with Block. Therefore
612 // the undecorated type returned here will not be pre-existing and can
613 // safely be decorated. Since this type is now decorated, it is out of
614 // sync with the TypeManager and therefore the TypeManager must be
615 // invalidated after this pass.
616 assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
617 "used struct type returned");
Nicolas Capens84c9c452022-11-18 14:11:05 +0000618 deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block));
619 deco_mgr->AddMemberDecoration(ibufTyId, 0,
620 uint32_t(spv::Decoration::Offset), 0);
Ben Claytonb73b7602019-07-29 13:56:13 +0100621 uint32_t ibufTyPtrId_ =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000622 type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer);
Ben Claytonb73b7602019-07-29 13:56:13 +0100623 input_buffer_id_ = TakeNextId();
624 std::unique_ptr<Instruction> newVarOp(new Instruction(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000625 context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_,
Ben Claytonb73b7602019-07-29 13:56:13 +0100626 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000627 {uint32_t(spv::StorageClass::StorageBuffer)}}}));
Ben Claytonb73b7602019-07-29 13:56:13 +0100628 context()->AddGlobalValue(std::move(newVarOp));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000629 context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer"));
630 context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data"));
631 context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
632 deco_mgr->AddDecorationVal(
633 input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
634 deco_mgr->AddDecorationVal(input_buffer_id_,
635 uint32_t(spv::Decoration::Binding),
Ben Claytonb73b7602019-07-29 13:56:13 +0100636 GetInputBufferBinding());
637 AddStorageBufferExt();
638 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
639 // Add the new buffer to all entry points.
640 for (auto& entry : get_module()->entry_points()) {
641 entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
642 context()->AnalyzeUses(&entry);
643 }
644 }
645 }
646 return input_buffer_id_;
647}
648
Alexis Hetub8a77462020-03-27 07:59:09 -0400649uint32_t InstrumentPass::GetFloatId() {
650 if (float_id_ == 0) {
651 analysis::TypeManager* type_mgr = context()->get_type_mgr();
652 analysis::Float float_ty(32);
653 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
654 float_id_ = type_mgr->GetTypeInstruction(reg_float_ty);
655 }
656 return float_id_;
657}
658
Chris Forbescc5697f2019-01-30 11:54:08 -0800659uint32_t InstrumentPass::GetVec4FloatId() {
660 if (v4float_id_ == 0) {
661 analysis::TypeManager* type_mgr = context()->get_type_mgr();
662 analysis::Float float_ty(32);
663 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
664 analysis::Vector v4float_ty(reg_float_ty, 4);
665 analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
666 v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
667 }
668 return v4float_id_;
669}
670
671uint32_t InstrumentPass::GetUintId() {
672 if (uint_id_ == 0) {
673 analysis::TypeManager* type_mgr = context()->get_type_mgr();
674 analysis::Integer uint_ty(32, false);
675 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
676 uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
677 }
678 return uint_id_;
679}
680
Ben Claytond0f684e2019-08-30 22:36:08 +0100681uint32_t InstrumentPass::GetUint64Id() {
682 if (uint64_id_ == 0) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800683 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytond0f684e2019-08-30 22:36:08 +0100684 analysis::Integer uint64_ty(64, false);
685 analysis::Type* reg_uint64_ty = type_mgr->GetRegisteredType(&uint64_ty);
686 uint64_id_ = type_mgr->GetTypeInstruction(reg_uint64_ty);
Chris Forbescc5697f2019-01-30 11:54:08 -0800687 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100688 return uint64_id_;
689}
690
Alexis Hetub8a77462020-03-27 07:59:09 -0400691uint32_t InstrumentPass::GetUint8Id() {
692 if (uint8_id_ == 0) {
693 analysis::TypeManager* type_mgr = context()->get_type_mgr();
694 analysis::Integer uint8_ty(8, false);
695 analysis::Type* reg_uint8_ty = type_mgr->GetRegisteredType(&uint8_ty);
696 uint8_id_ = type_mgr->GetTypeInstruction(reg_uint8_ty);
697 }
698 return uint8_id_;
699}
700
Ben Claytond0f684e2019-08-30 22:36:08 +0100701uint32_t InstrumentPass::GetVecUintId(uint32_t len) {
702 analysis::TypeManager* type_mgr = context()->get_type_mgr();
703 analysis::Integer uint_ty(32, false);
704 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
705 analysis::Vector v_uint_ty(reg_uint_ty, len);
706 analysis::Type* reg_v_uint_ty = type_mgr->GetRegisteredType(&v_uint_ty);
707 uint32_t v_uint_id = type_mgr->GetTypeInstruction(reg_v_uint_ty);
708 return v_uint_id;
709}
710
711uint32_t InstrumentPass::GetVec4UintId() {
712 if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u);
Chris Forbescc5697f2019-01-30 11:54:08 -0800713 return v4uint_id_;
714}
715
Ben Claytond0f684e2019-08-30 22:36:08 +0100716uint32_t InstrumentPass::GetVec3UintId() {
717 if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u);
718 return v3uint_id_;
719}
720
Chris Forbescc5697f2019-01-30 11:54:08 -0800721uint32_t InstrumentPass::GetBoolId() {
722 if (bool_id_ == 0) {
723 analysis::TypeManager* type_mgr = context()->get_type_mgr();
724 analysis::Bool bool_ty;
725 analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
726 bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
727 }
728 return bool_id_;
729}
730
731uint32_t InstrumentPass::GetVoidId() {
732 if (void_id_ == 0) {
733 analysis::TypeManager* type_mgr = context()->get_type_mgr();
734 analysis::Void void_ty;
735 analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
736 void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
737 }
738 return void_id_;
739}
740
741uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
742 uint32_t val_spec_param_cnt) {
743 // Total param count is common params plus validation-specific
744 // params
745 uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
Alexis Hetub8a77462020-03-27 07:59:09 -0400746 if (param2output_func_id_[param_cnt] == 0) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800747 // Create function
Alexis Hetub8a77462020-03-27 07:59:09 -0400748 param2output_func_id_[param_cnt] = TakeNextId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800749 analysis::TypeManager* type_mgr = context()->get_type_mgr();
750 std::vector<const analysis::Type*> param_types;
751 for (uint32_t c = 0; c < param_cnt; ++c)
752 param_types.push_back(type_mgr->GetType(GetUintId()));
753 analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
754 analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
Alexis Hetub8a77462020-03-27 07:59:09 -0400755 std::unique_ptr<Instruction> func_inst(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000756 new Instruction(get_module()->context(), spv::Op::OpFunction,
757 GetVoidId(), param2output_func_id_[param_cnt],
Alexis Hetub8a77462020-03-27 07:59:09 -0400758 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000759 {uint32_t(spv::FunctionControlMask::MaskNone)}},
Alexis Hetub8a77462020-03-27 07:59:09 -0400760 {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
761 {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
Chris Forbescc5697f2019-01-30 11:54:08 -0800762 get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
763 std::unique_ptr<Function> output_func =
764 MakeUnique<Function>(std::move(func_inst));
765 // Add parameters
766 std::vector<uint32_t> param_vec;
767 for (uint32_t c = 0; c < param_cnt; ++c) {
768 uint32_t pid = TakeNextId();
769 param_vec.push_back(pid);
770 std::unique_ptr<Instruction> param_inst(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000771 new Instruction(get_module()->context(), spv::Op::OpFunctionParameter,
Chris Forbescc5697f2019-01-30 11:54:08 -0800772 GetUintId(), pid, {}));
773 get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
774 output_func->AddParameter(std::move(param_inst));
775 }
776 // Create first block
777 uint32_t test_blk_id = TakeNextId();
778 std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
779 std::unique_ptr<BasicBlock> new_blk_ptr =
780 MakeUnique<BasicBlock>(std::move(test_label));
781 InstructionBuilder builder(
782 context(), &*new_blk_ptr,
783 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
784 // Gen test if debug output buffer size will not be exceeded.
Ben Clayton0b54f132020-01-06 13:38:54 +0000785 uint32_t val_spec_offset = kInstStageOutCnt;
Ben Claytonb73b7602019-07-29 13:56:13 +0100786 uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
Chris Forbescc5697f2019-01-30 11:54:08 -0800787 uint32_t buf_id = GetOutputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100788 uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800789 Instruction* obuf_curr_sz_ac_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000790 builder.AddBinaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id,
Chris Forbescc5697f2019-01-30 11:54:08 -0800791 builder.GetUintConstantId(kDebugOutputSizeOffset));
792 // Fetch the current debug buffer written size atomically, adding the
793 // size of the record to be written.
794 uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000795 uint32_t mask_none_id =
796 builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
797 uint32_t scope_invok_id =
798 builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
Chris Forbescc5697f2019-01-30 11:54:08 -0800799 Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000800 GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
Chris Forbescc5697f2019-01-30 11:54:08 -0800801 scope_invok_id, mask_none_id, obuf_record_sz_id);
802 uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
803 // Compute new written size
804 Instruction* obuf_new_sz_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000805 builder.AddBinaryOp(GetUintId(), spv::Op::OpIAdd, obuf_curr_sz_id,
Chris Forbescc5697f2019-01-30 11:54:08 -0800806 builder.GetUintConstantId(obuf_record_sz));
807 // Fetch the data bound
808 Instruction* obuf_bnd_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000809 builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
Chris Forbescc5697f2019-01-30 11:54:08 -0800810 GetOutputBufferId(), kDebugOutputDataOffset);
811 // Test that new written size is less than or equal to debug output
812 // data bound
813 Instruction* obuf_safe_inst = builder.AddBinaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000814 GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
Chris Forbescc5697f2019-01-30 11:54:08 -0800815 obuf_bnd_inst->result_id());
816 uint32_t merge_blk_id = TakeNextId();
817 uint32_t write_blk_id = TakeNextId();
818 std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
819 std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000820 (void)builder.AddConditionalBranch(
821 obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
822 uint32_t(spv::SelectionControlMask::MaskNone));
Chris Forbescc5697f2019-01-30 11:54:08 -0800823 // Close safety test block and gen write block
Chris Forbescc5697f2019-01-30 11:54:08 -0800824 output_func->AddBasicBlock(std::move(new_blk_ptr));
825 new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
826 builder.SetInsertPoint(&*new_blk_ptr);
827 // Generate common and stage-specific debug record members
828 GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx],
829 stage_idx, obuf_curr_sz_id, &builder);
830 GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
831 // Gen writes of validation specific data
832 for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100833 GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
Chris Forbescc5697f2019-01-30 11:54:08 -0800834 param_vec[kInstCommonParamCnt + i], &builder);
835 }
836 // Close write block and gen merge block
837 (void)builder.AddBranch(merge_blk_id);
Chris Forbescc5697f2019-01-30 11:54:08 -0800838 output_func->AddBasicBlock(std::move(new_blk_ptr));
839 new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
840 builder.SetInsertPoint(&*new_blk_ptr);
841 // Close merge block and function and add function to module
Nicolas Capens84c9c452022-11-18 14:11:05 +0000842 (void)builder.AddNullaryOp(0, spv::Op::OpReturn);
Chris Forbescc5697f2019-01-30 11:54:08 -0800843 output_func->AddBasicBlock(std::move(new_blk_ptr));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000844 std::unique_ptr<Instruction> func_end_inst(new Instruction(
845 get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
Chris Forbescc5697f2019-01-30 11:54:08 -0800846 get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
847 output_func->SetFunctionEnd(std::move(func_end_inst));
848 context()->AddFunction(std::move(output_func));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000849
850 std::string name("stream_write_");
851 name += std::to_string(param_cnt);
852
853 context()->AddDebug2Inst(
854 NewGlobalName(param2output_func_id_[param_cnt], name));
Chris Forbescc5697f2019-01-30 11:54:08 -0800855 }
Alexis Hetub8a77462020-03-27 07:59:09 -0400856 return param2output_func_id_[param_cnt];
Chris Forbescc5697f2019-01-30 11:54:08 -0800857}
858
Ben Claytonb73b7602019-07-29 13:56:13 +0100859uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
860 uint32_t func_id = param2input_func_id_[param_cnt];
861 if (func_id != 0) return func_id;
Ben Claytond0f684e2019-08-30 22:36:08 +0100862 // Create input function for param_cnt.
Ben Claytonb73b7602019-07-29 13:56:13 +0100863 func_id = TakeNextId();
864 analysis::TypeManager* type_mgr = context()->get_type_mgr();
865 std::vector<const analysis::Type*> param_types;
866 for (uint32_t c = 0; c < param_cnt; ++c)
867 param_types.push_back(type_mgr->GetType(GetUintId()));
Ben Claytond0f684e2019-08-30 22:36:08 +0100868 uint32_t ibuf_type_id = GetInputBufferTypeId();
869 analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), param_types);
Ben Claytonb73b7602019-07-29 13:56:13 +0100870 analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
871 std::unique_ptr<Instruction> func_inst(new Instruction(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000872 get_module()->context(), spv::Op::OpFunction, ibuf_type_id, func_id,
Ben Claytonb73b7602019-07-29 13:56:13 +0100873 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000874 {uint32_t(spv::FunctionControlMask::MaskNone)}},
Ben Claytonb73b7602019-07-29 13:56:13 +0100875 {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
876 {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
877 get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
878 std::unique_ptr<Function> input_func =
879 MakeUnique<Function>(std::move(func_inst));
880 // Add parameters
881 std::vector<uint32_t> param_vec;
882 for (uint32_t c = 0; c < param_cnt; ++c) {
883 uint32_t pid = TakeNextId();
884 param_vec.push_back(pid);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000885 std::unique_ptr<Instruction> param_inst(
886 new Instruction(get_module()->context(), spv::Op::OpFunctionParameter,
887 GetUintId(), pid, {}));
Ben Claytonb73b7602019-07-29 13:56:13 +0100888 get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
889 input_func->AddParameter(std::move(param_inst));
890 }
891 // Create block
892 uint32_t blk_id = TakeNextId();
893 std::unique_ptr<Instruction> blk_label(NewLabel(blk_id));
894 std::unique_ptr<BasicBlock> new_blk_ptr =
895 MakeUnique<BasicBlock>(std::move(blk_label));
896 InstructionBuilder builder(
897 context(), &*new_blk_ptr,
898 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
899 // For each offset parameter, generate new offset with parameter, adding last
900 // loaded value if it exists, and load value from input buffer at new offset.
901 // Return last loaded value.
902 uint32_t buf_id = GetInputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100903 uint32_t buf_ptr_id = GetInputBufferPtrId();
Ben Claytonb73b7602019-07-29 13:56:13 +0100904 uint32_t last_value_id = 0;
905 for (uint32_t p = 0; p < param_cnt; ++p) {
906 uint32_t offset_id;
907 if (p == 0) {
908 offset_id = param_vec[0];
909 } else {
Ben Claytond0f684e2019-08-30 22:36:08 +0100910 if (ibuf_type_id != GetUintId()) {
911 Instruction* ucvt_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000912 builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id);
Ben Claytond0f684e2019-08-30 22:36:08 +0100913 last_value_id = ucvt_inst->result_id();
914 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100915 Instruction* offset_inst = builder.AddBinaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000916 GetUintId(), spv::Op::OpIAdd, last_value_id, param_vec[p]);
Ben Claytonb73b7602019-07-29 13:56:13 +0100917 offset_id = offset_inst->result_id();
918 }
919 Instruction* ac_inst = builder.AddTernaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000920 buf_ptr_id, spv::Op::OpAccessChain, buf_id,
Ben Claytonb73b7602019-07-29 13:56:13 +0100921 builder.GetUintConstantId(kDebugInputDataOffset), offset_id);
922 Instruction* load_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000923 builder.AddUnaryOp(ibuf_type_id, spv::Op::OpLoad, ac_inst->result_id());
Ben Claytonb73b7602019-07-29 13:56:13 +0100924 last_value_id = load_inst->result_id();
925 }
926 (void)builder.AddInstruction(MakeUnique<Instruction>(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000927 context(), spv::Op::OpReturnValue, 0, 0,
Ben Claytonb73b7602019-07-29 13:56:13 +0100928 std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {last_value_id}}}));
929 // Close block and function and add function to module
Ben Claytonb73b7602019-07-29 13:56:13 +0100930 input_func->AddBasicBlock(std::move(new_blk_ptr));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000931 std::unique_ptr<Instruction> func_end_inst(new Instruction(
932 get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {}));
Ben Claytonb73b7602019-07-29 13:56:13 +0100933 get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
934 input_func->SetFunctionEnd(std::move(func_end_inst));
935 context()->AddFunction(std::move(input_func));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000936
937 std::string name("direct_read_");
938 name += std::to_string(param_cnt);
939 context()->AddDebug2Inst(NewGlobalName(func_id, name));
940
Ben Claytonb73b7602019-07-29 13:56:13 +0100941 param2input_func_id_[param_cnt] = func_id;
942 return func_id;
943}
944
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400945void InstrumentPass::SplitBlock(
946 BasicBlock::iterator inst_itr, UptrVectorIterator<BasicBlock> block_itr,
947 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
948 // Make sure def/use analysis is done before we start moving instructions
949 // out of function
950 (void)get_def_use_mgr();
951 // Move original block's preceding instructions into first new block
952 std::unique_ptr<BasicBlock> first_blk_ptr;
953 MovePreludeCode(inst_itr, block_itr, &first_blk_ptr);
954 InstructionBuilder builder(
955 context(), &*first_blk_ptr,
956 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
957 uint32_t split_blk_id = TakeNextId();
958 std::unique_ptr<Instruction> split_label(NewLabel(split_blk_id));
959 (void)builder.AddBranch(split_blk_id);
960 new_blocks->push_back(std::move(first_blk_ptr));
961 // Move remaining instructions into split block and add to new blocks
962 std::unique_ptr<BasicBlock> split_blk_ptr(
963 new BasicBlock(std::move(split_label)));
964 MovePostludeCode(block_itr, &*split_blk_ptr);
965 new_blocks->push_back(std::move(split_blk_ptr));
966}
967
Chris Forbescc5697f2019-01-30 11:54:08 -0800968bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
969 InstProcessFunction& pfn) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400970 curr_func_ = func;
971 call2id_.clear();
972 bool first_block_split = false;
Chris Forbescc5697f2019-01-30 11:54:08 -0800973 bool modified = false;
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400974 // Apply instrumentation function to each instruction.
Chris Forbescc5697f2019-01-30 11:54:08 -0800975 // Using block iterators here because of block erasures and insertions.
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400976 std::vector<std::unique_ptr<BasicBlock>> new_blks;
Chris Forbescc5697f2019-01-30 11:54:08 -0800977 for (auto bi = func->begin(); bi != func->end(); ++bi) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100978 for (auto ii = bi->begin(); ii != bi->end();) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400979 // Split all executable instructions out of first block into a following
980 // block. This will allow function calls to be inserted into the first
981 // block without interfering with the instrumentation algorithm.
982 if (opt_direct_reads_ && !first_block_split) {
Nicolas Capens84c9c452022-11-18 14:11:05 +0000983 if (ii->opcode() != spv::Op::OpVariable) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400984 SplitBlock(ii, bi, &new_blks);
985 first_block_split = true;
986 }
987 } else {
988 pfn(ii, bi, stage_idx, &new_blks);
989 }
990 // If no new code, continue
Chris Forbescc5697f2019-01-30 11:54:08 -0800991 if (new_blks.size() == 0) {
992 ++ii;
993 continue;
994 }
Ben Claytonb73b7602019-07-29 13:56:13 +0100995 // Add new blocks to label id map
996 for (auto& blk : new_blks) id2block_[blk->id()] = &*blk;
Chris Forbescc5697f2019-01-30 11:54:08 -0800997 // If there are new blocks we know there will always be two or
998 // more, so update succeeding phis with label of new last block.
999 size_t newBlocksSize = new_blks.size();
1000 assert(newBlocksSize > 1);
1001 UpdateSucceedingPhis(new_blks);
1002 // Replace original block with new block(s)
1003 bi = bi.Erase();
1004 for (auto& bb : new_blks) {
1005 bb->SetParent(func);
1006 }
1007 bi = bi.InsertBefore(&new_blks);
1008 // Reset block iterator to last new block
1009 for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
1010 modified = true;
1011 // Restart instrumenting at beginning of last new block,
1012 // but skip over any new phi or copy instruction.
1013 ii = bi->begin();
Nicolas Capens84c9c452022-11-18 14:11:05 +00001014 if (ii->opcode() == spv::Op::OpPhi ||
1015 ii->opcode() == spv::Op::OpCopyObject)
1016 ++ii;
Chris Forbescc5697f2019-01-30 11:54:08 -08001017 new_blks.clear();
1018 }
1019 }
1020 return modified;
1021}
1022
1023bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
1024 std::queue<uint32_t>* roots,
1025 uint32_t stage_idx) {
1026 bool modified = false;
1027 std::unordered_set<uint32_t> done;
Ben Claytonb73b7602019-07-29 13:56:13 +01001028 // Don't process input and output functions
1029 for (auto& ifn : param2input_func_id_) done.insert(ifn.second);
Alexis Hetub8a77462020-03-27 07:59:09 -04001030 for (auto& ofn : param2output_func_id_) done.insert(ofn.second);
Chris Forbescc5697f2019-01-30 11:54:08 -08001031 // Process all functions from roots
1032 while (!roots->empty()) {
1033 const uint32_t fi = roots->front();
1034 roots->pop();
1035 if (done.insert(fi).second) {
1036 Function* fn = id2function_.at(fi);
1037 // Add calls first so we don't add new output function
1038 context()->AddCalls(fn, roots);
1039 modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
1040 }
1041 }
1042 return modified;
1043}
1044
1045bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
1046 // Make sure all entry points have the same execution model. Do not
1047 // instrument if they do not.
1048 // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
1049 // can contain entry points with different execution models, although
1050 // such modules will likely be rare as GLSL and HLSL are geared toward
1051 // one model per module. In such cases we will need
1052 // to clone any functions which are in the call trees of entrypoints
1053 // with differing execution models.
Nicolas Capens84c9c452022-11-18 14:11:05 +00001054 spv::ExecutionModel stage = context()->GetStage();
Ben Clayton0b54f132020-01-06 13:38:54 +00001055 // Check for supported stages
Nicolas Capens84c9c452022-11-18 14:11:05 +00001056 if (stage != spv::ExecutionModel::Vertex &&
1057 stage != spv::ExecutionModel::Fragment &&
1058 stage != spv::ExecutionModel::Geometry &&
1059 stage != spv::ExecutionModel::GLCompute &&
1060 stage != spv::ExecutionModel::TessellationControl &&
1061 stage != spv::ExecutionModel::TessellationEvaluation &&
1062 stage != spv::ExecutionModel::TaskNV &&
1063 stage != spv::ExecutionModel::MeshNV &&
1064 stage != spv::ExecutionModel::RayGenerationNV &&
1065 stage != spv::ExecutionModel::IntersectionNV &&
1066 stage != spv::ExecutionModel::AnyHitNV &&
1067 stage != spv::ExecutionModel::ClosestHitNV &&
1068 stage != spv::ExecutionModel::MissNV &&
1069 stage != spv::ExecutionModel::CallableNV &&
1070 stage != spv::ExecutionModel::TaskEXT &&
1071 stage != spv::ExecutionModel::MeshEXT) {
Ben Clayton0b54f132020-01-06 13:38:54 +00001072 if (consumer()) {
1073 std::string message = "Stage not supported by instrumentation";
1074 consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
1075 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001076 return false;
Ben Clayton0b54f132020-01-06 13:38:54 +00001077 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001078 // Add together the roots of all entry points
1079 std::queue<uint32_t> roots;
1080 for (auto& e : get_module()->entry_points()) {
1081 roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
1082 }
Nicolas Capens84c9c452022-11-18 14:11:05 +00001083 bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage));
Chris Forbescc5697f2019-01-30 11:54:08 -08001084 return modified;
1085}
1086
1087void InstrumentPass::InitializeInstrument() {
1088 output_buffer_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001089 output_buffer_ptr_id_ = 0;
1090 input_buffer_ptr_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +01001091 input_buffer_id_ = 0;
Alexis Hetub8a77462020-03-27 07:59:09 -04001092 float_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001093 v4float_id_ = 0;
1094 uint_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001095 uint64_id_ = 0;
Alexis Hetub8a77462020-03-27 07:59:09 -04001096 uint8_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001097 v4uint_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001098 v3uint_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001099 bool_id_ = 0;
1100 void_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +01001101 storage_buffer_ext_defined_ = false;
Ben Claytond0f684e2019-08-30 22:36:08 +01001102 uint32_rarr_ty_ = nullptr;
1103 uint64_rarr_ty_ = nullptr;
Chris Forbescc5697f2019-01-30 11:54:08 -08001104
1105 // clear collections
1106 id2function_.clear();
1107 id2block_.clear();
1108
Alexis Hetub8a77462020-03-27 07:59:09 -04001109 // clear maps
1110 param2input_func_id_.clear();
1111 param2output_func_id_.clear();
1112
Chris Forbescc5697f2019-01-30 11:54:08 -08001113 // Initialize function and block maps.
1114 for (auto& fn : *get_module()) {
1115 id2function_[fn.result_id()] = &fn;
1116 for (auto& blk : fn) {
1117 id2block_[blk.id()] = &blk;
1118 }
1119 }
1120
Ben Claytonb73b7602019-07-29 13:56:13 +01001121 // Remember original instruction offsets
1122 uint32_t module_offset = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001123 Module* module = get_module();
1124 for (auto& i : context()->capabilities()) {
1125 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001126 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001127 }
1128 for (auto& i : module->extensions()) {
1129 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001130 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001131 }
1132 for (auto& i : module->ext_inst_imports()) {
1133 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001134 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001135 }
Ben Claytonb73b7602019-07-29 13:56:13 +01001136 ++module_offset; // memory_model
Chris Forbescc5697f2019-01-30 11:54:08 -08001137 for (auto& i : module->entry_points()) {
1138 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001139 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001140 }
1141 for (auto& i : module->execution_modes()) {
1142 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001143 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001144 }
1145 for (auto& i : module->debugs1()) {
1146 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001147 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001148 }
1149 for (auto& i : module->debugs2()) {
1150 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001151 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001152 }
1153 for (auto& i : module->debugs3()) {
1154 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001155 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001156 }
Ben Claytondc6b76a2020-02-24 14:53:40 +00001157 for (auto& i : module->ext_inst_debuginfo()) {
1158 (void)i;
1159 ++module_offset;
1160 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001161 for (auto& i : module->annotations()) {
1162 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001163 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001164 }
1165 for (auto& i : module->types_values()) {
Ben Claytonb73b7602019-07-29 13:56:13 +01001166 module_offset += 1;
1167 module_offset += static_cast<uint32_t>(i.dbg_line_insts().size());
Chris Forbescc5697f2019-01-30 11:54:08 -08001168 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001169
Ben Claytonb73b7602019-07-29 13:56:13 +01001170 auto curr_fn = get_module()->begin();
1171 for (; curr_fn != get_module()->end(); ++curr_fn) {
1172 // Count function instruction
1173 module_offset += 1;
1174 curr_fn->ForEachParam(
1175 [&module_offset](const Instruction*) { module_offset += 1; }, true);
1176 for (auto& blk : *curr_fn) {
Chris Forbescc5697f2019-01-30 11:54:08 -08001177 // Count label
Ben Claytonb73b7602019-07-29 13:56:13 +01001178 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001179 for (auto& inst : blk) {
Ben Claytonb73b7602019-07-29 13:56:13 +01001180 module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size());
1181 uid2offset_[inst.unique_id()] = module_offset;
1182 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001183 }
1184 }
Ben Claytonb73b7602019-07-29 13:56:13 +01001185 // Count function end instruction
1186 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001187 }
1188}
1189
1190} // namespace opt
1191} // namespace spvtools