blob: c6e405051d68a8d5dda659c9f222ceabdf19f191 [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 // Move contents of original ref block.
58 for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end();
59 cii = ref_block_itr->begin()) {
60 Instruction* inst = &*cii;
61 inst->RemoveFromList();
62 std::unique_ptr<Instruction> mv_inst(inst);
63 // Regenerate any same-block instruction that has not been seen in the
64 // current block.
65 if (same_block_pre_.size() > 0) {
66 CloneSameBlockOps(&mv_inst, &same_block_post_, &same_block_pre_,
67 new_blk_ptr);
68 // Remember same-block ops in this block.
69 if (IsSameBlockOp(&*mv_inst)) {
70 const uint32_t rid = mv_inst->result_id();
71 same_block_post_[rid] = rid;
72 }
73 }
Ben Claytonb73b7602019-07-29 13:56:13 +010074 new_blk_ptr->AddInstruction(std::move(mv_inst));
Chris Forbescc5697f2019-01-30 11:54:08 -080075 }
76}
77
78std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
Ben Clayton16696652023-02-06 14:45:50 +000079 auto new_label =
80 MakeUnique<Instruction>(context(), spv::Op::OpLabel, 0, label_id,
81 std::initializer_list<Operand>{});
82 get_def_use_mgr()->AnalyzeInstDefUse(&*new_label);
83 return new_label;
84}
85
86std::unique_ptr<Function> InstrumentPass::StartFunction(
87 uint32_t func_id, const analysis::Type* return_type,
88 const std::vector<const analysis::Type*>& param_types) {
89 analysis::TypeManager* type_mgr = context()->get_type_mgr();
90 analysis::Function* func_type = GetFunction(return_type, param_types);
91
92 const std::vector<Operand> operands{
93 {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
94 {uint32_t(spv::FunctionControlMask::MaskNone)}},
95 {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {type_mgr->GetId(func_type)}},
96 };
97 auto func_inst =
98 MakeUnique<Instruction>(context(), spv::Op::OpFunction,
99 type_mgr->GetId(return_type), func_id, operands);
100 get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
101 return MakeUnique<Function>(std::move(func_inst));
102}
103
104std::unique_ptr<Instruction> InstrumentPass::EndFunction() {
105 auto end = MakeUnique<Instruction>(context(), spv::Op::OpFunctionEnd, 0, 0,
106 std::initializer_list<Operand>{});
107 get_def_use_mgr()->AnalyzeInstDefUse(end.get());
108 return end;
109}
110
111std::vector<uint32_t> InstrumentPass::AddParameters(
112 Function& func, const std::vector<const analysis::Type*>& param_types) {
113 std::vector<uint32_t> param_ids;
114 param_ids.reserve(param_types.size());
115 for (const analysis::Type* param : param_types) {
116 uint32_t pid = TakeNextId();
117 param_ids.push_back(pid);
118 auto param_inst =
119 MakeUnique<Instruction>(context(), spv::Op::OpFunctionParameter,
120 context()->get_type_mgr()->GetId(param), pid,
121 std::initializer_list<Operand>{});
122 get_def_use_mgr()->AnalyzeInstDefUse(param_inst.get());
123 func.AddParameter(std::move(param_inst));
124 }
125 return param_ids;
Chris Forbescc5697f2019-01-30 11:54:08 -0800126}
127
Nicolas Capens84c9c452022-11-18 14:11:05 +0000128std::unique_ptr<Instruction> InstrumentPass::NewName(
129 uint32_t id, const std::string& name_str) {
Ben Clayton16696652023-02-06 14:45:50 +0000130 return MakeUnique<Instruction>(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000131 context(), spv::Op::OpName, 0, 0,
132 std::initializer_list<Operand>{
133 {SPV_OPERAND_TYPE_ID, {id}},
Ben Clayton16696652023-02-06 14:45:50 +0000134 {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
Nicolas Capens84c9c452022-11-18 14:11:05 +0000135}
136
137std::unique_ptr<Instruction> InstrumentPass::NewGlobalName(
138 uint32_t id, const std::string& name_str) {
139 std::string prefixed_name;
140 switch (validation_id_) {
141 case kInstValidationIdBindless:
142 prefixed_name = "inst_bindless_";
143 break;
144 case kInstValidationIdBuffAddr:
145 prefixed_name = "inst_buff_addr_";
146 break;
147 case kInstValidationIdDebugPrintf:
148 prefixed_name = "inst_printf_";
149 break;
150 default:
151 assert(false); // add new instrumentation pass here
152 prefixed_name = "inst_pass_";
153 break;
154 }
155 prefixed_name += name_str;
156 return NewName(id, prefixed_name);
157}
158
159std::unique_ptr<Instruction> InstrumentPass::NewMemberName(
160 uint32_t id, uint32_t member_index, const std::string& name_str) {
Ben Clayton16696652023-02-06 14:45:50 +0000161 return MakeUnique<Instruction>(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000162 context(), spv::Op::OpMemberName, 0, 0,
163 std::initializer_list<Operand>{
164 {SPV_OPERAND_TYPE_ID, {id}},
165 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
Ben Clayton16696652023-02-06 14:45:50 +0000166 {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
Nicolas Capens84c9c452022-11-18 14:11:05 +0000167}
168
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400169uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id,
170 InstructionBuilder* builder) {
171 // Convert integer value to 32-bit if necessary
172 analysis::TypeManager* type_mgr = context()->get_type_mgr();
173 uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_id)->type_id();
174 analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
175 if (val_ty->width() == 32) return val_id;
176 bool is_signed = val_ty->IsSigned();
177 analysis::Integer val_32b_ty(32, is_signed);
178 analysis::Type* val_32b_reg_ty = type_mgr->GetRegisteredType(&val_32b_ty);
179 uint32_t val_32b_reg_ty_id = type_mgr->GetId(val_32b_reg_ty);
180 if (is_signed)
Nicolas Capens84c9c452022-11-18 14:11:05 +0000181 return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpSConvert, val_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400182 ->result_id();
183 else
Nicolas Capens84c9c452022-11-18 14:11:05 +0000184 return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpUConvert, val_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400185 ->result_id();
186}
187
Chris Forbescc5697f2019-01-30 11:54:08 -0800188uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
189 InstructionBuilder* builder) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400190 // Convert value to 32-bit if necessary
191 uint32_t val_32b_id = Gen32BitCvtCode(val_id, builder);
192 // Cast value to unsigned if necessary
193 analysis::TypeManager* type_mgr = context()->get_type_mgr();
194 uint32_t val_ty_id = get_def_use_mgr()->GetDef(val_32b_id)->type_id();
195 analysis::Integer* val_ty = type_mgr->GetType(val_ty_id)->AsInteger();
196 if (!val_ty->IsSigned()) return val_32b_id;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000197 return builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast, val_32b_id)
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400198 ->result_id();
Chris Forbescc5697f2019-01-30 11:54:08 -0800199}
200
201void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
202 uint32_t field_offset,
203 uint32_t field_value_id,
204 InstructionBuilder* builder) {
205 // Cast value to 32-bit unsigned if necessary
206 uint32_t val_id = GenUintCastCode(field_value_id, builder);
207 // Store value
Ben Clayton16696652023-02-06 14:45:50 +0000208 Instruction* data_idx_inst = builder->AddIAdd(
209 GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset));
Chris Forbescc5697f2019-01-30 11:54:08 -0800210 uint32_t buf_id = GetOutputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100211 uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Ben Clayton16696652023-02-06 14:45:50 +0000212 Instruction* achain_inst = builder->AddAccessChain(
213 buf_uint_ptr_id, buf_id,
214 {builder->GetUintConstantId(kDebugOutputDataOffset),
215 data_idx_inst->result_id()});
216 (void)builder->AddStore(achain_inst->result_id(), val_id);
Chris Forbescc5697f2019-01-30 11:54:08 -0800217}
218
219void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
220 uint32_t inst_id,
221 uint32_t stage_idx,
222 uint32_t base_offset_id,
223 InstructionBuilder* builder) {
224 // Store record size
225 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
226 builder->GetUintConstantId(record_sz), builder);
227 // Store Shader Id
228 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
229 builder->GetUintConstantId(shader_id_), builder);
230 // Store Instruction Idx
231 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
232 builder);
233 // Store Stage Idx
234 GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
235 builder->GetUintConstantId(stage_idx), builder);
236}
237
238void InstrumentPass::GenFragCoordEltDebugOutputCode(
239 uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
240 InstructionBuilder* builder) {
Ben Clayton16696652023-02-06 14:45:50 +0000241 Instruction* element_val_inst =
242 builder->AddCompositeExtract(GetUintId(), uint_frag_coord_id, {element});
Chris Forbescc5697f2019-01-30 11:54:08 -0800243 GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
244 element_val_inst->result_id(), builder);
245}
246
Ben Claytonb73b7602019-07-29 13:56:13 +0100247uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
248 InstructionBuilder* builder) {
249 Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
250 uint32_t type_id = GetPointeeTypeId(var_inst);
Ben Clayton16696652023-02-06 14:45:50 +0000251 Instruction* load_inst = builder->AddLoad(type_id, var_id);
Ben Claytonb73b7602019-07-29 13:56:13 +0100252 return load_inst->result_id();
253}
254
Chris Forbescc5697f2019-01-30 11:54:08 -0800255void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
256 uint32_t builtin_off,
257 uint32_t base_offset_id,
258 InstructionBuilder* builder) {
259 // Load and store builtin
Ben Claytonb73b7602019-07-29 13:56:13 +0100260 uint32_t load_id = GenVarLoad(builtin_id, builder);
261 GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800262}
263
264void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
265 uint32_t base_offset_id,
266 InstructionBuilder* builder) {
267 // TODO(greg-lunarg): Add support for all stages
Nicolas Capens84c9c452022-11-18 14:11:05 +0000268 switch (spv::ExecutionModel(stage_idx)) {
269 case spv::ExecutionModel::Vertex: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800270 // Load and store VertexId and InstanceId
Ben Claytonb73b7602019-07-29 13:56:13 +0100271 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000272 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100273 kInstVertOutVertexIndex, base_offset_id, builder);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000274 GenBuiltinOutputCode(context()->GetBuiltinInputVarId(
275 uint32_t(spv::BuiltIn::InstanceIndex)),
276 kInstVertOutInstanceIndex, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800277 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000278 case spv::ExecutionModel::GLCompute:
279 case spv::ExecutionModel::TaskNV:
280 case spv::ExecutionModel::MeshNV:
281 case spv::ExecutionModel::TaskEXT:
282 case spv::ExecutionModel::MeshEXT: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100283 // Load and store GlobalInvocationId.
Nicolas Capens84c9c452022-11-18 14:11:05 +0000284 uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t(
285 spv::BuiltIn::GlobalInvocationId)),
286 builder);
Ben Clayton16696652023-02-06 14:45:50 +0000287 Instruction* x_inst =
288 builder->AddCompositeExtract(GetUintId(), load_id, {0});
289 Instruction* y_inst =
290 builder->AddCompositeExtract(GetUintId(), load_id, {1});
291 Instruction* z_inst =
292 builder->AddCompositeExtract(GetUintId(), load_id, {2});
Ben Clayton0b54f132020-01-06 13:38:54 +0000293 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
294 x_inst->result_id(), builder);
295 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
296 y_inst->result_id(), builder);
297 GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
298 z_inst->result_id(), builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800299 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000300 case spv::ExecutionModel::Geometry: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800301 // Load and store PrimitiveId and InvocationId.
Ben Claytonb73b7602019-07-29 13:56:13 +0100302 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000303 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100304 kInstGeomOutPrimitiveId, base_offset_id, builder);
305 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000306 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100307 kInstGeomOutInvocationId, base_offset_id, builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800308 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000309 case spv::ExecutionModel::TessellationControl: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100310 // Load and store InvocationId and PrimitiveId
311 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000312 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100313 kInstTessCtlOutInvocationId, base_offset_id, builder);
314 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000315 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Claytonb73b7602019-07-29 13:56:13 +0100316 kInstTessCtlOutPrimitiveId, base_offset_id, builder);
317 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000318 case spv::ExecutionModel::TessellationEvaluation: {
Ben Clayton0b54f132020-01-06 13:38:54 +0000319 // Load and store PrimitiveId and TessCoord.uv
320 GenBuiltinOutputCode(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000321 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)),
Ben Clayton0b54f132020-01-06 13:38:54 +0000322 kInstTessEvalOutPrimitiveId, base_offset_id, builder);
323 uint32_t load_id = GenVarLoad(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000324 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)),
325 builder);
Ben Clayton0b54f132020-01-06 13:38:54 +0000326 Instruction* uvec3_cast_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000327 builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id);
Ben Clayton0b54f132020-01-06 13:38:54 +0000328 uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
Ben Clayton16696652023-02-06 14:45:50 +0000329 Instruction* u_inst =
330 builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {0});
331 Instruction* v_inst =
332 builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {1});
Ben Clayton0b54f132020-01-06 13:38:54 +0000333 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
334 u_inst->result_id(), builder);
335 GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
336 v_inst->result_id(), builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800337 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000338 case spv::ExecutionModel::Fragment: {
Chris Forbescc5697f2019-01-30 11:54:08 -0800339 // Load FragCoord and convert to Uint
Ben Clayton16696652023-02-06 14:45:50 +0000340 Instruction* frag_coord_inst = builder->AddLoad(
341 GetVec4FloatId(),
Nicolas Capens84c9c452022-11-18 14:11:05 +0000342 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord)));
Chris Forbescc5697f2019-01-30 11:54:08 -0800343 Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000344 GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id());
Chris Forbescc5697f2019-01-30 11:54:08 -0800345 for (uint32_t u = 0; u < 2u; ++u)
346 GenFragCoordEltDebugOutputCode(
347 base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
348 } break;
Nicolas Capens84c9c452022-11-18 14:11:05 +0000349 case spv::ExecutionModel::RayGenerationNV:
350 case spv::ExecutionModel::IntersectionNV:
351 case spv::ExecutionModel::AnyHitNV:
352 case spv::ExecutionModel::ClosestHitNV:
353 case spv::ExecutionModel::MissNV:
354 case spv::ExecutionModel::CallableNV: {
Ben Claytonb73b7602019-07-29 13:56:13 +0100355 // Load and store LaunchIdNV.
356 uint32_t launch_id = GenVarLoad(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000357 context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)),
358 builder);
Ben Clayton16696652023-02-06 14:45:50 +0000359 Instruction* x_launch_inst =
360 builder->AddCompositeExtract(GetUintId(), launch_id, {0});
361 Instruction* y_launch_inst =
362 builder->AddCompositeExtract(GetUintId(), launch_id, {1});
363 Instruction* z_launch_inst =
364 builder->AddCompositeExtract(GetUintId(), launch_id, {2});
Ben Claytonb73b7602019-07-29 13:56:13 +0100365 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
366 x_launch_inst->result_id(), builder);
367 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
368 y_launch_inst->result_id(), builder);
369 GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
370 z_launch_inst->result_id(), builder);
371 } break;
Chris Forbescc5697f2019-01-30 11:54:08 -0800372 default: { assert(false && "unsupported stage"); } break;
373 }
374}
375
376void InstrumentPass::GenDebugStreamWrite(
377 uint32_t instruction_idx, uint32_t stage_idx,
378 const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
379 // Call debug output function. Pass func_idx, instruction_idx and
380 // validation ids as args.
381 uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
Ben Clayton16696652023-02-06 14:45:50 +0000382 std::vector<uint32_t> args = {builder->GetUintConstantId(instruction_idx)};
Chris Forbescc5697f2019-01-30 11:54:08 -0800383 (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
Ben Clayton16696652023-02-06 14:45:50 +0000384 (void)builder->AddFunctionCall(
385 GetVoidId(), GetStreamWriteFunctionId(stage_idx, val_id_cnt), args);
Chris Forbescc5697f2019-01-30 11:54:08 -0800386}
387
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400388bool InstrumentPass::AllConstant(const std::vector<uint32_t>& ids) {
389 for (auto& id : ids) {
390 Instruction* id_inst = context()->get_def_use_mgr()->GetDef(id);
391 if (!spvOpcodeIsConstant(id_inst->opcode())) return false;
392 }
393 return true;
394}
395
Ben Claytonb73b7602019-07-29 13:56:13 +0100396uint32_t InstrumentPass::GenDebugDirectRead(
Ben Clayton16696652023-02-06 14:45:50 +0000397 const std::vector<uint32_t>& offset_ids, InstructionBuilder* builder) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100398 // Call debug input function. Pass func_idx and offset ids as args.
Ben Clayton16696652023-02-06 14:45:50 +0000399 const uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
400 const uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
401 return GenReadFunctionCall(input_func_id, offset_ids, builder);
402}
403
404uint32_t InstrumentPass::GenReadFunctionCall(
405 uint32_t func_id, const std::vector<uint32_t>& func_call_args,
406 InstructionBuilder* ref_builder) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400407 // If optimizing direct reads and the call has already been generated,
408 // use its result
409 if (opt_direct_reads_) {
Ben Clayton16696652023-02-06 14:45:50 +0000410 uint32_t res_id = call2id_[func_call_args];
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400411 if (res_id != 0) return res_id;
412 }
Ben Clayton16696652023-02-06 14:45:50 +0000413 // If the function arguments are all constants, the call can be moved to the
414 // first block of the function where its result can be reused. One example
415 // where this is profitable is for uniform buffer references, of which there
416 // are often many.
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400417 InstructionBuilder builder(ref_builder->GetContext(),
418 &*ref_builder->GetInsertPoint(),
419 ref_builder->GetPreservedAnalysis());
Ben Clayton16696652023-02-06 14:45:50 +0000420 bool insert_in_first_block = opt_direct_reads_ && AllConstant(func_call_args);
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400421 if (insert_in_first_block) {
422 Instruction* insert_before = &*curr_func_->begin()->tail();
423 builder.SetInsertPoint(insert_before);
424 }
425 uint32_t res_id =
Ben Clayton16696652023-02-06 14:45:50 +0000426 builder.AddFunctionCall(GetUintId(), func_id, func_call_args)
Nicolas Capens84c9c452022-11-18 14:11:05 +0000427 ->result_id();
Ben Clayton16696652023-02-06 14:45:50 +0000428 if (insert_in_first_block) call2id_[func_call_args] = res_id;
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400429 return res_id;
Ben Claytonb73b7602019-07-29 13:56:13 +0100430}
431
Chris Forbescc5697f2019-01-30 11:54:08 -0800432bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
Nicolas Capens84c9c452022-11-18 14:11:05 +0000433 return inst->opcode() == spv::Op::OpSampledImage ||
434 inst->opcode() == spv::Op::OpImage;
Chris Forbescc5697f2019-01-30 11:54:08 -0800435}
436
437void InstrumentPass::CloneSameBlockOps(
438 std::unique_ptr<Instruction>* inst,
439 std::unordered_map<uint32_t, uint32_t>* same_blk_post,
440 std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
Ben Claytonb73b7602019-07-29 13:56:13 +0100441 BasicBlock* block_ptr) {
Ben Claytond552f632019-11-18 11:18:41 +0000442 bool changed = false;
443 (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed,
444 this](uint32_t* iid) {
445 const auto map_itr = (*same_blk_post).find(*iid);
446 if (map_itr == (*same_blk_post).end()) {
447 const auto map_itr2 = (*same_blk_pre).find(*iid);
448 if (map_itr2 != (*same_blk_pre).end()) {
449 // Clone pre-call same-block ops, map result id.
450 const Instruction* in_inst = map_itr2->second;
451 std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
452 const uint32_t rid = sb_inst->result_id();
453 const uint32_t nid = this->TakeNextId();
454 get_decoration_mgr()->CloneDecorations(rid, nid);
455 sb_inst->SetResultId(nid);
456 get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst);
457 (*same_blk_post)[rid] = nid;
458 *iid = nid;
459 changed = true;
460 CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
461 block_ptr->AddInstruction(std::move(sb_inst));
462 }
463 } else {
464 // Reset same-block op operand if necessary
465 if (*iid != map_itr->second) {
466 *iid = map_itr->second;
467 changed = true;
468 }
469 }
470 });
471 if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst);
Chris Forbescc5697f2019-01-30 11:54:08 -0800472}
473
474void InstrumentPass::UpdateSucceedingPhis(
475 std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
476 const auto first_blk = new_blocks.begin();
477 const auto last_blk = new_blocks.end() - 1;
478 const uint32_t first_id = (*first_blk)->id();
479 const uint32_t last_id = (*last_blk)->id();
480 const BasicBlock& const_last_block = *last_blk->get();
481 const_last_block.ForEachSuccessorLabel(
482 [&first_id, &last_id, this](const uint32_t succ) {
483 BasicBlock* sbp = this->id2block_[succ];
484 sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
485 bool changed = false;
486 phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
487 if (*id == first_id) {
488 *id = last_id;
489 changed = true;
490 }
491 });
492 if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
493 });
494 });
495}
496
Ben Claytond0f684e2019-08-30 22:36:08 +0100497uint32_t InstrumentPass::GetOutputBufferPtrId() {
498 if (output_buffer_ptr_id_ == 0) {
499 output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000500 GetUintId(), spv::StorageClass::StorageBuffer);
Chris Forbescc5697f2019-01-30 11:54:08 -0800501 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100502 return output_buffer_ptr_id_;
503}
504
505uint32_t InstrumentPass::GetInputBufferTypeId() {
506 return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id()
507 : GetUintId();
508}
509
510uint32_t InstrumentPass::GetInputBufferPtrId() {
511 if (input_buffer_ptr_id_ == 0) {
512 input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000513 GetInputBufferTypeId(), spv::StorageClass::StorageBuffer);
Ben Claytond0f684e2019-08-30 22:36:08 +0100514 }
515 return input_buffer_ptr_id_;
Chris Forbescc5697f2019-01-30 11:54:08 -0800516}
517
518uint32_t InstrumentPass::GetOutputBufferBinding() {
519 switch (validation_id_) {
520 case kInstValidationIdBindless:
521 return kDebugOutputBindingStream;
Ben Claytond0f684e2019-08-30 22:36:08 +0100522 case kInstValidationIdBuffAddr:
523 return kDebugOutputBindingStream;
Alexis Hetub8a77462020-03-27 07:59:09 -0400524 case kInstValidationIdDebugPrintf:
525 return kDebugOutputPrintfStream;
Chris Forbescc5697f2019-01-30 11:54:08 -0800526 default:
527 assert(false && "unexpected validation id");
528 }
529 return 0;
530}
531
Ben Claytonb73b7602019-07-29 13:56:13 +0100532uint32_t InstrumentPass::GetInputBufferBinding() {
533 switch (validation_id_) {
534 case kInstValidationIdBindless:
535 return kDebugInputBindingBindless;
Ben Claytond0f684e2019-08-30 22:36:08 +0100536 case kInstValidationIdBuffAddr:
537 return kDebugInputBindingBuffAddr;
Ben Claytonb73b7602019-07-29 13:56:13 +0100538 default:
539 assert(false && "unexpected validation id");
540 }
541 return 0;
542}
543
Ben Clayton16696652023-02-06 14:45:50 +0000544analysis::Integer* InstrumentPass::GetInteger(uint32_t width, bool is_signed) {
545 analysis::Integer i(width, is_signed);
546 analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&i);
547 assert(type && type->AsInteger());
548 return type->AsInteger();
549}
550
551analysis::Struct* InstrumentPass::GetStruct(
552 const std::vector<const analysis::Type*>& fields) {
553 analysis::Struct s(fields);
554 analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&s);
555 assert(type && type->AsStruct());
556 return type->AsStruct();
557}
558
559analysis::RuntimeArray* InstrumentPass::GetRuntimeArray(
560 const analysis::Type* element) {
561 analysis::RuntimeArray r(element);
562 analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&r);
563 assert(type && type->AsRuntimeArray());
564 return type->AsRuntimeArray();
565}
566
567analysis::Function* InstrumentPass::GetFunction(
568 const analysis::Type* return_val,
569 const std::vector<const analysis::Type*>& args) {
570 analysis::Function func(return_val, args);
571 analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&func);
572 assert(type && type->AsFunction());
573 return type->AsFunction();
574}
575
576analysis::RuntimeArray* InstrumentPass::GetUintXRuntimeArrayType(
577 uint32_t width, analysis::RuntimeArray** rarr_ty) {
Ben Claytond0f684e2019-08-30 22:36:08 +0100578 if (*rarr_ty == nullptr) {
Ben Clayton16696652023-02-06 14:45:50 +0000579 *rarr_ty = GetRuntimeArray(GetInteger(width, false));
580 uint32_t uint_arr_ty_id =
581 context()->get_type_mgr()->GetTypeInstruction(*rarr_ty);
Ben Claytonb73b7602019-07-29 13:56:13 +0100582 // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
583 // a block, and will therefore be decorated with an ArrayStride. Therefore
584 // the undecorated type returned here will not be pre-existing and can
585 // safely be decorated. Since this type is now decorated, it is out of
586 // sync with the TypeManager and therefore the TypeManager must be
587 // invalidated after this pass.
Ben Clayton16696652023-02-06 14:45:50 +0000588 assert(get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
Ben Claytonb73b7602019-07-29 13:56:13 +0100589 "used RuntimeArray type returned");
Ben Clayton16696652023-02-06 14:45:50 +0000590 get_decoration_mgr()->AddDecorationVal(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000591 uint_arr_ty_id, uint32_t(spv::Decoration::ArrayStride), width / 8u);
Ben Claytonb73b7602019-07-29 13:56:13 +0100592 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100593 return *rarr_ty;
594}
595
Ben Clayton16696652023-02-06 14:45:50 +0000596analysis::RuntimeArray* InstrumentPass::GetUintRuntimeArrayType(
597 uint32_t width) {
598 analysis::RuntimeArray** rarr_ty =
Ben Claytond0f684e2019-08-30 22:36:08 +0100599 (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_;
600 return GetUintXRuntimeArrayType(width, rarr_ty);
Ben Claytonb73b7602019-07-29 13:56:13 +0100601}
602
603void InstrumentPass::AddStorageBufferExt() {
604 if (storage_buffer_ext_defined_) return;
605 if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
Ben Claytond0f684e2019-08-30 22:36:08 +0100606 context()->AddExtension("SPV_KHR_storage_buffer_storage_class");
Ben Claytonb73b7602019-07-29 13:56:13 +0100607 }
608 storage_buffer_ext_defined_ = true;
609}
610
Chris Forbescc5697f2019-01-30 11:54:08 -0800611// Return id for output buffer
612uint32_t InstrumentPass::GetOutputBufferId() {
613 if (output_buffer_id_ == 0) {
614 // If not created yet, create one
615 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
616 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Clayton16696652023-02-06 14:45:50 +0000617 analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
618 analysis::Integer* reg_uint_ty = GetInteger(32, false);
619 analysis::Type* reg_buf_ty =
620 GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
Ben Claytonb73b7602019-07-29 13:56:13 +0100621 uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
622 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
623 // must be a block, and will therefore be decorated with Block. Therefore
624 // the undecorated type returned here will not be pre-existing and can
625 // safely be decorated. Since this type is now decorated, it is out of
626 // sync with the TypeManager and therefore the TypeManager must be
627 // invalidated after this pass.
628 assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
629 "used struct type returned");
Nicolas Capens84c9c452022-11-18 14:11:05 +0000630 deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
631 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
632 uint32_t(spv::Decoration::Offset), 0);
Chris Forbescc5697f2019-01-30 11:54:08 -0800633 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000634 uint32_t(spv::Decoration::Offset), 4);
Chris Forbescc5697f2019-01-30 11:54:08 -0800635 deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000636 uint32_t(spv::Decoration::Offset), 8);
Chris Forbescc5697f2019-01-30 11:54:08 -0800637 uint32_t obufTyPtrId_ =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000638 type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
Chris Forbescc5697f2019-01-30 11:54:08 -0800639 output_buffer_id_ = TakeNextId();
640 std::unique_ptr<Instruction> newVarOp(new Instruction(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000641 context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
Chris Forbescc5697f2019-01-30 11:54:08 -0800642 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000643 {uint32_t(spv::StorageClass::StorageBuffer)}}}));
Chris Forbescc5697f2019-01-30 11:54:08 -0800644 context()->AddGlobalValue(std::move(newVarOp));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000645 context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
646 context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
647 context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
648 context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
649 context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
650 deco_mgr->AddDecorationVal(
651 output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
652 deco_mgr->AddDecorationVal(output_buffer_id_,
653 uint32_t(spv::Decoration::Binding),
Chris Forbescc5697f2019-01-30 11:54:08 -0800654 GetOutputBufferBinding());
Ben Claytonb73b7602019-07-29 13:56:13 +0100655 AddStorageBufferExt();
656 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
657 // Add the new buffer to all entry points.
658 for (auto& entry : get_module()->entry_points()) {
659 entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
660 context()->AnalyzeUses(&entry);
661 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800662 }
663 }
664 return output_buffer_id_;
665}
666
Ben Claytonb73b7602019-07-29 13:56:13 +0100667uint32_t InstrumentPass::GetInputBufferId() {
668 if (input_buffer_id_ == 0) {
669 // If not created yet, create one
670 analysis::DecorationManager* deco_mgr = get_decoration_mgr();
671 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytond0f684e2019-08-30 22:36:08 +0100672 uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u;
673 analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width);
Ben Clayton16696652023-02-06 14:45:50 +0000674 analysis::Struct* reg_buf_ty = GetStruct({reg_uint_rarr_ty});
Ben Claytonb73b7602019-07-29 13:56:13 +0100675 uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
676 // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
677 // must be a block, and will therefore be decorated with Block. Therefore
678 // the undecorated type returned here will not be pre-existing and can
679 // safely be decorated. Since this type is now decorated, it is out of
680 // sync with the TypeManager and therefore the TypeManager must be
681 // invalidated after this pass.
682 assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
683 "used struct type returned");
Nicolas Capens84c9c452022-11-18 14:11:05 +0000684 deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block));
685 deco_mgr->AddMemberDecoration(ibufTyId, 0,
686 uint32_t(spv::Decoration::Offset), 0);
Ben Claytonb73b7602019-07-29 13:56:13 +0100687 uint32_t ibufTyPtrId_ =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000688 type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer);
Ben Claytonb73b7602019-07-29 13:56:13 +0100689 input_buffer_id_ = TakeNextId();
690 std::unique_ptr<Instruction> newVarOp(new Instruction(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000691 context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_,
Ben Claytonb73b7602019-07-29 13:56:13 +0100692 {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
Nicolas Capens84c9c452022-11-18 14:11:05 +0000693 {uint32_t(spv::StorageClass::StorageBuffer)}}}));
Ben Claytonb73b7602019-07-29 13:56:13 +0100694 context()->AddGlobalValue(std::move(newVarOp));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000695 context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer"));
696 context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data"));
697 context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
698 deco_mgr->AddDecorationVal(
699 input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
700 deco_mgr->AddDecorationVal(input_buffer_id_,
701 uint32_t(spv::Decoration::Binding),
Ben Claytonb73b7602019-07-29 13:56:13 +0100702 GetInputBufferBinding());
703 AddStorageBufferExt();
704 if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
705 // Add the new buffer to all entry points.
706 for (auto& entry : get_module()->entry_points()) {
707 entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
708 context()->AnalyzeUses(&entry);
709 }
710 }
711 }
712 return input_buffer_id_;
713}
714
Alexis Hetub8a77462020-03-27 07:59:09 -0400715uint32_t InstrumentPass::GetFloatId() {
716 if (float_id_ == 0) {
717 analysis::TypeManager* type_mgr = context()->get_type_mgr();
718 analysis::Float float_ty(32);
719 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
720 float_id_ = type_mgr->GetTypeInstruction(reg_float_ty);
721 }
722 return float_id_;
723}
724
Chris Forbescc5697f2019-01-30 11:54:08 -0800725uint32_t InstrumentPass::GetVec4FloatId() {
726 if (v4float_id_ == 0) {
727 analysis::TypeManager* type_mgr = context()->get_type_mgr();
728 analysis::Float float_ty(32);
729 analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
730 analysis::Vector v4float_ty(reg_float_ty, 4);
731 analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
732 v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
733 }
734 return v4float_id_;
735}
736
737uint32_t InstrumentPass::GetUintId() {
738 if (uint_id_ == 0) {
739 analysis::TypeManager* type_mgr = context()->get_type_mgr();
740 analysis::Integer uint_ty(32, false);
741 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
742 uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
743 }
744 return uint_id_;
745}
746
Ben Claytond0f684e2019-08-30 22:36:08 +0100747uint32_t InstrumentPass::GetUint64Id() {
748 if (uint64_id_ == 0) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800749 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Claytond0f684e2019-08-30 22:36:08 +0100750 analysis::Integer uint64_ty(64, false);
751 analysis::Type* reg_uint64_ty = type_mgr->GetRegisteredType(&uint64_ty);
752 uint64_id_ = type_mgr->GetTypeInstruction(reg_uint64_ty);
Chris Forbescc5697f2019-01-30 11:54:08 -0800753 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100754 return uint64_id_;
755}
756
Alexis Hetub8a77462020-03-27 07:59:09 -0400757uint32_t InstrumentPass::GetUint8Id() {
758 if (uint8_id_ == 0) {
759 analysis::TypeManager* type_mgr = context()->get_type_mgr();
760 analysis::Integer uint8_ty(8, false);
761 analysis::Type* reg_uint8_ty = type_mgr->GetRegisteredType(&uint8_ty);
762 uint8_id_ = type_mgr->GetTypeInstruction(reg_uint8_ty);
763 }
764 return uint8_id_;
765}
766
Ben Claytond0f684e2019-08-30 22:36:08 +0100767uint32_t InstrumentPass::GetVecUintId(uint32_t len) {
768 analysis::TypeManager* type_mgr = context()->get_type_mgr();
769 analysis::Integer uint_ty(32, false);
770 analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
771 analysis::Vector v_uint_ty(reg_uint_ty, len);
772 analysis::Type* reg_v_uint_ty = type_mgr->GetRegisteredType(&v_uint_ty);
773 uint32_t v_uint_id = type_mgr->GetTypeInstruction(reg_v_uint_ty);
774 return v_uint_id;
775}
776
777uint32_t InstrumentPass::GetVec4UintId() {
778 if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u);
Chris Forbescc5697f2019-01-30 11:54:08 -0800779 return v4uint_id_;
780}
781
Ben Claytond0f684e2019-08-30 22:36:08 +0100782uint32_t InstrumentPass::GetVec3UintId() {
783 if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u);
784 return v3uint_id_;
785}
786
Chris Forbescc5697f2019-01-30 11:54:08 -0800787uint32_t InstrumentPass::GetBoolId() {
788 if (bool_id_ == 0) {
789 analysis::TypeManager* type_mgr = context()->get_type_mgr();
790 analysis::Bool bool_ty;
791 analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
792 bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
793 }
794 return bool_id_;
795}
796
797uint32_t InstrumentPass::GetVoidId() {
798 if (void_id_ == 0) {
799 analysis::TypeManager* type_mgr = context()->get_type_mgr();
800 analysis::Void void_ty;
801 analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
802 void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
803 }
804 return void_id_;
805}
806
807uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
808 uint32_t val_spec_param_cnt) {
809 // Total param count is common params plus validation-specific
810 // params
811 uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
Alexis Hetub8a77462020-03-27 07:59:09 -0400812 if (param2output_func_id_[param_cnt] == 0) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800813 // Create function
Alexis Hetub8a77462020-03-27 07:59:09 -0400814 param2output_func_id_[param_cnt] = TakeNextId();
Chris Forbescc5697f2019-01-30 11:54:08 -0800815 analysis::TypeManager* type_mgr = context()->get_type_mgr();
Ben Clayton16696652023-02-06 14:45:50 +0000816
817 const std::vector<const analysis::Type*> param_types(param_cnt,
818 GetInteger(32, false));
819 std::unique_ptr<Function> output_func = StartFunction(
820 param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types);
821
822 std::vector<uint32_t> param_ids = AddParameters(*output_func, param_types);
823
Chris Forbescc5697f2019-01-30 11:54:08 -0800824 // Create first block
Ben Clayton16696652023-02-06 14:45:50 +0000825 auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
826
Chris Forbescc5697f2019-01-30 11:54:08 -0800827 InstructionBuilder builder(
828 context(), &*new_blk_ptr,
829 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
830 // Gen test if debug output buffer size will not be exceeded.
Ben Clayton0b54f132020-01-06 13:38:54 +0000831 uint32_t val_spec_offset = kInstStageOutCnt;
Ben Claytonb73b7602019-07-29 13:56:13 +0100832 uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
Chris Forbescc5697f2019-01-30 11:54:08 -0800833 uint32_t buf_id = GetOutputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100834 uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
Ben Clayton16696652023-02-06 14:45:50 +0000835 Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain(
836 buf_uint_ptr_id, buf_id,
837 {builder.GetUintConstantId(kDebugOutputSizeOffset)});
Chris Forbescc5697f2019-01-30 11:54:08 -0800838 // Fetch the current debug buffer written size atomically, adding the
839 // size of the record to be written.
840 uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
Nicolas Capens84c9c452022-11-18 14:11:05 +0000841 uint32_t mask_none_id =
842 builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
843 uint32_t scope_invok_id =
844 builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
Chris Forbescc5697f2019-01-30 11:54:08 -0800845 Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000846 GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
Chris Forbescc5697f2019-01-30 11:54:08 -0800847 scope_invok_id, mask_none_id, obuf_record_sz_id);
848 uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
849 // Compute new written size
850 Instruction* obuf_new_sz_inst =
Ben Clayton16696652023-02-06 14:45:50 +0000851 builder.AddIAdd(GetUintId(), obuf_curr_sz_id,
852 builder.GetUintConstantId(obuf_record_sz));
Chris Forbescc5697f2019-01-30 11:54:08 -0800853 // Fetch the data bound
854 Instruction* obuf_bnd_inst =
Nicolas Capens84c9c452022-11-18 14:11:05 +0000855 builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
Chris Forbescc5697f2019-01-30 11:54:08 -0800856 GetOutputBufferId(), kDebugOutputDataOffset);
857 // Test that new written size is less than or equal to debug output
858 // data bound
859 Instruction* obuf_safe_inst = builder.AddBinaryOp(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000860 GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
Chris Forbescc5697f2019-01-30 11:54:08 -0800861 obuf_bnd_inst->result_id());
862 uint32_t merge_blk_id = TakeNextId();
863 uint32_t write_blk_id = TakeNextId();
864 std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
865 std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000866 (void)builder.AddConditionalBranch(
867 obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
868 uint32_t(spv::SelectionControlMask::MaskNone));
Chris Forbescc5697f2019-01-30 11:54:08 -0800869 // Close safety test block and gen write block
Chris Forbescc5697f2019-01-30 11:54:08 -0800870 output_func->AddBasicBlock(std::move(new_blk_ptr));
871 new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
872 builder.SetInsertPoint(&*new_blk_ptr);
873 // Generate common and stage-specific debug record members
Ben Clayton16696652023-02-06 14:45:50 +0000874 GenCommonStreamWriteCode(obuf_record_sz, param_ids[kInstCommonParamInstIdx],
Chris Forbescc5697f2019-01-30 11:54:08 -0800875 stage_idx, obuf_curr_sz_id, &builder);
876 GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
877 // Gen writes of validation specific data
878 for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100879 GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
Ben Clayton16696652023-02-06 14:45:50 +0000880 param_ids[kInstCommonParamCnt + i], &builder);
Chris Forbescc5697f2019-01-30 11:54:08 -0800881 }
882 // Close write block and gen merge block
883 (void)builder.AddBranch(merge_blk_id);
Chris Forbescc5697f2019-01-30 11:54:08 -0800884 output_func->AddBasicBlock(std::move(new_blk_ptr));
885 new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
886 builder.SetInsertPoint(&*new_blk_ptr);
887 // Close merge block and function and add function to module
Nicolas Capens84c9c452022-11-18 14:11:05 +0000888 (void)builder.AddNullaryOp(0, spv::Op::OpReturn);
Ben Clayton16696652023-02-06 14:45:50 +0000889
Chris Forbescc5697f2019-01-30 11:54:08 -0800890 output_func->AddBasicBlock(std::move(new_blk_ptr));
Ben Clayton16696652023-02-06 14:45:50 +0000891 output_func->SetFunctionEnd(EndFunction());
Chris Forbescc5697f2019-01-30 11:54:08 -0800892 context()->AddFunction(std::move(output_func));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000893
894 std::string name("stream_write_");
895 name += std::to_string(param_cnt);
896
897 context()->AddDebug2Inst(
898 NewGlobalName(param2output_func_id_[param_cnt], name));
Chris Forbescc5697f2019-01-30 11:54:08 -0800899 }
Alexis Hetub8a77462020-03-27 07:59:09 -0400900 return param2output_func_id_[param_cnt];
Chris Forbescc5697f2019-01-30 11:54:08 -0800901}
902
Ben Claytonb73b7602019-07-29 13:56:13 +0100903uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
904 uint32_t func_id = param2input_func_id_[param_cnt];
905 if (func_id != 0) return func_id;
Ben Claytond0f684e2019-08-30 22:36:08 +0100906 // Create input function for param_cnt.
Ben Claytonb73b7602019-07-29 13:56:13 +0100907 func_id = TakeNextId();
Ben Clayton16696652023-02-06 14:45:50 +0000908 analysis::Integer* uint_type = GetInteger(32, false);
909 std::vector<const analysis::Type*> param_types(param_cnt, uint_type);
910
Ben Claytonb73b7602019-07-29 13:56:13 +0100911 std::unique_ptr<Function> input_func =
Ben Clayton16696652023-02-06 14:45:50 +0000912 StartFunction(func_id, uint_type, param_types);
913 std::vector<uint32_t> param_ids = AddParameters(*input_func, param_types);
914
Ben Claytonb73b7602019-07-29 13:56:13 +0100915 // Create block
Ben Clayton16696652023-02-06 14:45:50 +0000916 auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
Ben Claytonb73b7602019-07-29 13:56:13 +0100917 InstructionBuilder builder(
918 context(), &*new_blk_ptr,
919 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
920 // For each offset parameter, generate new offset with parameter, adding last
921 // loaded value if it exists, and load value from input buffer at new offset.
922 // Return last loaded value.
Ben Clayton16696652023-02-06 14:45:50 +0000923 uint32_t ibuf_type_id = GetInputBufferTypeId();
Ben Claytonb73b7602019-07-29 13:56:13 +0100924 uint32_t buf_id = GetInputBufferId();
Ben Claytond0f684e2019-08-30 22:36:08 +0100925 uint32_t buf_ptr_id = GetInputBufferPtrId();
Ben Claytonb73b7602019-07-29 13:56:13 +0100926 uint32_t last_value_id = 0;
927 for (uint32_t p = 0; p < param_cnt; ++p) {
928 uint32_t offset_id;
929 if (p == 0) {
Ben Clayton16696652023-02-06 14:45:50 +0000930 offset_id = param_ids[0];
Ben Claytonb73b7602019-07-29 13:56:13 +0100931 } else {
Ben Claytond0f684e2019-08-30 22:36:08 +0100932 if (ibuf_type_id != GetUintId()) {
Ben Clayton16696652023-02-06 14:45:50 +0000933 last_value_id =
934 builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id)
935 ->result_id();
Ben Claytond0f684e2019-08-30 22:36:08 +0100936 }
Ben Clayton16696652023-02-06 14:45:50 +0000937 offset_id = builder.AddIAdd(GetUintId(), last_value_id, param_ids[p])
938 ->result_id();
Ben Claytonb73b7602019-07-29 13:56:13 +0100939 }
Ben Clayton16696652023-02-06 14:45:50 +0000940 Instruction* ac_inst = builder.AddAccessChain(
941 buf_ptr_id, buf_id,
942 {builder.GetUintConstantId(kDebugInputDataOffset), offset_id});
943 last_value_id =
944 builder.AddLoad(ibuf_type_id, ac_inst->result_id())->result_id();
Ben Claytonb73b7602019-07-29 13:56:13 +0100945 }
Ben Clayton16696652023-02-06 14:45:50 +0000946 (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, last_value_id);
Ben Claytonb73b7602019-07-29 13:56:13 +0100947 // Close block and function and add function to module
Ben Claytonb73b7602019-07-29 13:56:13 +0100948 input_func->AddBasicBlock(std::move(new_blk_ptr));
Ben Clayton16696652023-02-06 14:45:50 +0000949 input_func->SetFunctionEnd(EndFunction());
Ben Claytonb73b7602019-07-29 13:56:13 +0100950 context()->AddFunction(std::move(input_func));
Nicolas Capens84c9c452022-11-18 14:11:05 +0000951
952 std::string name("direct_read_");
953 name += std::to_string(param_cnt);
954 context()->AddDebug2Inst(NewGlobalName(func_id, name));
955
Ben Claytonb73b7602019-07-29 13:56:13 +0100956 param2input_func_id_[param_cnt] = func_id;
957 return func_id;
958}
959
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400960void InstrumentPass::SplitBlock(
961 BasicBlock::iterator inst_itr, UptrVectorIterator<BasicBlock> block_itr,
962 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
963 // Make sure def/use analysis is done before we start moving instructions
964 // out of function
965 (void)get_def_use_mgr();
966 // Move original block's preceding instructions into first new block
967 std::unique_ptr<BasicBlock> first_blk_ptr;
968 MovePreludeCode(inst_itr, block_itr, &first_blk_ptr);
969 InstructionBuilder builder(
970 context(), &*first_blk_ptr,
971 IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
972 uint32_t split_blk_id = TakeNextId();
973 std::unique_ptr<Instruction> split_label(NewLabel(split_blk_id));
974 (void)builder.AddBranch(split_blk_id);
975 new_blocks->push_back(std::move(first_blk_ptr));
976 // Move remaining instructions into split block and add to new blocks
977 std::unique_ptr<BasicBlock> split_blk_ptr(
978 new BasicBlock(std::move(split_label)));
979 MovePostludeCode(block_itr, &*split_blk_ptr);
980 new_blocks->push_back(std::move(split_blk_ptr));
981}
982
Chris Forbescc5697f2019-01-30 11:54:08 -0800983bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
984 InstProcessFunction& pfn) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400985 curr_func_ = func;
986 call2id_.clear();
987 bool first_block_split = false;
Chris Forbescc5697f2019-01-30 11:54:08 -0800988 bool modified = false;
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400989 // Apply instrumentation function to each instruction.
Chris Forbescc5697f2019-01-30 11:54:08 -0800990 // Using block iterators here because of block erasures and insertions.
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400991 std::vector<std::unique_ptr<BasicBlock>> new_blks;
Chris Forbescc5697f2019-01-30 11:54:08 -0800992 for (auto bi = func->begin(); bi != func->end(); ++bi) {
Ben Claytonb73b7602019-07-29 13:56:13 +0100993 for (auto ii = bi->begin(); ii != bi->end();) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400994 // Split all executable instructions out of first block into a following
995 // block. This will allow function calls to be inserted into the first
996 // block without interfering with the instrumentation algorithm.
997 if (opt_direct_reads_ && !first_block_split) {
Nicolas Capens84c9c452022-11-18 14:11:05 +0000998 if (ii->opcode() != spv::Op::OpVariable) {
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400999 SplitBlock(ii, bi, &new_blks);
1000 first_block_split = true;
1001 }
1002 } else {
1003 pfn(ii, bi, stage_idx, &new_blks);
1004 }
1005 // If no new code, continue
Chris Forbescc5697f2019-01-30 11:54:08 -08001006 if (new_blks.size() == 0) {
1007 ++ii;
1008 continue;
1009 }
Ben Claytonb73b7602019-07-29 13:56:13 +01001010 // Add new blocks to label id map
1011 for (auto& blk : new_blks) id2block_[blk->id()] = &*blk;
Chris Forbescc5697f2019-01-30 11:54:08 -08001012 // If there are new blocks we know there will always be two or
1013 // more, so update succeeding phis with label of new last block.
1014 size_t newBlocksSize = new_blks.size();
1015 assert(newBlocksSize > 1);
1016 UpdateSucceedingPhis(new_blks);
1017 // Replace original block with new block(s)
1018 bi = bi.Erase();
1019 for (auto& bb : new_blks) {
1020 bb->SetParent(func);
1021 }
1022 bi = bi.InsertBefore(&new_blks);
1023 // Reset block iterator to last new block
1024 for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
1025 modified = true;
1026 // Restart instrumenting at beginning of last new block,
1027 // but skip over any new phi or copy instruction.
1028 ii = bi->begin();
Nicolas Capens84c9c452022-11-18 14:11:05 +00001029 if (ii->opcode() == spv::Op::OpPhi ||
1030 ii->opcode() == spv::Op::OpCopyObject)
1031 ++ii;
Chris Forbescc5697f2019-01-30 11:54:08 -08001032 new_blks.clear();
1033 }
1034 }
1035 return modified;
1036}
1037
1038bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
1039 std::queue<uint32_t>* roots,
1040 uint32_t stage_idx) {
1041 bool modified = false;
1042 std::unordered_set<uint32_t> done;
Ben Claytonb73b7602019-07-29 13:56:13 +01001043 // Don't process input and output functions
1044 for (auto& ifn : param2input_func_id_) done.insert(ifn.second);
Alexis Hetub8a77462020-03-27 07:59:09 -04001045 for (auto& ofn : param2output_func_id_) done.insert(ofn.second);
Chris Forbescc5697f2019-01-30 11:54:08 -08001046 // Process all functions from roots
1047 while (!roots->empty()) {
1048 const uint32_t fi = roots->front();
1049 roots->pop();
1050 if (done.insert(fi).second) {
1051 Function* fn = id2function_.at(fi);
1052 // Add calls first so we don't add new output function
1053 context()->AddCalls(fn, roots);
1054 modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
1055 }
1056 }
1057 return modified;
1058}
1059
1060bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
1061 // Make sure all entry points have the same execution model. Do not
1062 // instrument if they do not.
1063 // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
1064 // can contain entry points with different execution models, although
1065 // such modules will likely be rare as GLSL and HLSL are geared toward
1066 // one model per module. In such cases we will need
1067 // to clone any functions which are in the call trees of entrypoints
1068 // with differing execution models.
Nicolas Capens84c9c452022-11-18 14:11:05 +00001069 spv::ExecutionModel stage = context()->GetStage();
Ben Clayton0b54f132020-01-06 13:38:54 +00001070 // Check for supported stages
Nicolas Capens84c9c452022-11-18 14:11:05 +00001071 if (stage != spv::ExecutionModel::Vertex &&
1072 stage != spv::ExecutionModel::Fragment &&
1073 stage != spv::ExecutionModel::Geometry &&
1074 stage != spv::ExecutionModel::GLCompute &&
1075 stage != spv::ExecutionModel::TessellationControl &&
1076 stage != spv::ExecutionModel::TessellationEvaluation &&
1077 stage != spv::ExecutionModel::TaskNV &&
1078 stage != spv::ExecutionModel::MeshNV &&
1079 stage != spv::ExecutionModel::RayGenerationNV &&
1080 stage != spv::ExecutionModel::IntersectionNV &&
1081 stage != spv::ExecutionModel::AnyHitNV &&
1082 stage != spv::ExecutionModel::ClosestHitNV &&
1083 stage != spv::ExecutionModel::MissNV &&
1084 stage != spv::ExecutionModel::CallableNV &&
1085 stage != spv::ExecutionModel::TaskEXT &&
1086 stage != spv::ExecutionModel::MeshEXT) {
Ben Clayton0b54f132020-01-06 13:38:54 +00001087 if (consumer()) {
1088 std::string message = "Stage not supported by instrumentation";
1089 consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
1090 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001091 return false;
Ben Clayton0b54f132020-01-06 13:38:54 +00001092 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001093 // Add together the roots of all entry points
1094 std::queue<uint32_t> roots;
1095 for (auto& e : get_module()->entry_points()) {
1096 roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
1097 }
Nicolas Capens84c9c452022-11-18 14:11:05 +00001098 bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage));
Chris Forbescc5697f2019-01-30 11:54:08 -08001099 return modified;
1100}
1101
1102void InstrumentPass::InitializeInstrument() {
1103 output_buffer_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001104 output_buffer_ptr_id_ = 0;
1105 input_buffer_ptr_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +01001106 input_buffer_id_ = 0;
Alexis Hetub8a77462020-03-27 07:59:09 -04001107 float_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001108 v4float_id_ = 0;
1109 uint_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001110 uint64_id_ = 0;
Alexis Hetub8a77462020-03-27 07:59:09 -04001111 uint8_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001112 v4uint_id_ = 0;
Ben Claytond0f684e2019-08-30 22:36:08 +01001113 v3uint_id_ = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001114 bool_id_ = 0;
1115 void_id_ = 0;
Ben Claytonb73b7602019-07-29 13:56:13 +01001116 storage_buffer_ext_defined_ = false;
Ben Claytond0f684e2019-08-30 22:36:08 +01001117 uint32_rarr_ty_ = nullptr;
1118 uint64_rarr_ty_ = nullptr;
Chris Forbescc5697f2019-01-30 11:54:08 -08001119
1120 // clear collections
1121 id2function_.clear();
1122 id2block_.clear();
1123
Alexis Hetub8a77462020-03-27 07:59:09 -04001124 // clear maps
1125 param2input_func_id_.clear();
1126 param2output_func_id_.clear();
1127
Chris Forbescc5697f2019-01-30 11:54:08 -08001128 // Initialize function and block maps.
1129 for (auto& fn : *get_module()) {
1130 id2function_[fn.result_id()] = &fn;
1131 for (auto& blk : fn) {
1132 id2block_[blk.id()] = &blk;
1133 }
1134 }
1135
Ben Claytonb73b7602019-07-29 13:56:13 +01001136 // Remember original instruction offsets
1137 uint32_t module_offset = 0;
Chris Forbescc5697f2019-01-30 11:54:08 -08001138 Module* module = get_module();
1139 for (auto& i : context()->capabilities()) {
1140 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001141 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001142 }
1143 for (auto& i : module->extensions()) {
1144 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001145 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001146 }
1147 for (auto& i : module->ext_inst_imports()) {
1148 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001149 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001150 }
Ben Claytonb73b7602019-07-29 13:56:13 +01001151 ++module_offset; // memory_model
Chris Forbescc5697f2019-01-30 11:54:08 -08001152 for (auto& i : module->entry_points()) {
1153 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001154 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001155 }
1156 for (auto& i : module->execution_modes()) {
1157 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001158 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001159 }
1160 for (auto& i : module->debugs1()) {
1161 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001162 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001163 }
1164 for (auto& i : module->debugs2()) {
1165 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001166 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001167 }
1168 for (auto& i : module->debugs3()) {
1169 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001170 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001171 }
Ben Claytondc6b76a2020-02-24 14:53:40 +00001172 for (auto& i : module->ext_inst_debuginfo()) {
1173 (void)i;
1174 ++module_offset;
1175 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001176 for (auto& i : module->annotations()) {
1177 (void)i;
Ben Claytonb73b7602019-07-29 13:56:13 +01001178 ++module_offset;
Chris Forbescc5697f2019-01-30 11:54:08 -08001179 }
1180 for (auto& i : module->types_values()) {
Ben Claytonb73b7602019-07-29 13:56:13 +01001181 module_offset += 1;
1182 module_offset += static_cast<uint32_t>(i.dbg_line_insts().size());
Chris Forbescc5697f2019-01-30 11:54:08 -08001183 }
Chris Forbescc5697f2019-01-30 11:54:08 -08001184
Ben Claytonb73b7602019-07-29 13:56:13 +01001185 auto curr_fn = get_module()->begin();
1186 for (; curr_fn != get_module()->end(); ++curr_fn) {
1187 // Count function instruction
1188 module_offset += 1;
1189 curr_fn->ForEachParam(
1190 [&module_offset](const Instruction*) { module_offset += 1; }, true);
1191 for (auto& blk : *curr_fn) {
Chris Forbescc5697f2019-01-30 11:54:08 -08001192 // Count label
Ben Claytonb73b7602019-07-29 13:56:13 +01001193 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001194 for (auto& inst : blk) {
Ben Claytonb73b7602019-07-29 13:56:13 +01001195 module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size());
1196 uid2offset_[inst.unique_id()] = module_offset;
1197 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001198 }
1199 }
Ben Claytonb73b7602019-07-29 13:56:13 +01001200 // Count function end instruction
1201 module_offset += 1;
Chris Forbescc5697f2019-01-30 11:54:08 -08001202 }
1203}
1204
1205} // namespace opt
1206} // namespace spvtools