Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1 | // Copyright (c) 2018 The Khronos Group Inc. |
| 2 | // Copyright (c) 2018 Valve Corporation |
| 3 | // Copyright (c) 2018 LunarG Inc. |
| 4 | // |
| 5 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | // you may not use this file except in compliance with the License. |
| 7 | // You may obtain a copy of the License at |
| 8 | // |
| 9 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | // |
| 11 | // Unless required by applicable law or agreed to in writing, software |
| 12 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | // See the License for the specific language governing permissions and |
| 15 | // limitations under the License. |
| 16 | |
| 17 | #include "instrument_pass.h" |
| 18 | |
| 19 | #include "source/cfa.h" |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 20 | #include "source/spirv_constant.h" |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 21 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 22 | namespace spvtools { |
| 23 | namespace opt { |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 24 | namespace { |
| 25 | // Common Parameter Positions |
| 26 | constexpr int kInstCommonParamInstIdx = 0; |
| 27 | constexpr int kInstCommonParamCnt = 1; |
| 28 | // Indices of operands in SPIR-V instructions |
| 29 | constexpr int kEntryPointFunctionIdInIdx = 1; |
| 30 | } // namespace |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 31 | |
| 32 | void 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 | |
| 55 | void InstrumentPass::MovePostludeCode( |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 56 | UptrVectorIterator<BasicBlock> ref_block_itr, BasicBlock* new_blk_ptr) { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 57 | // 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 74 | new_blk_ptr->AddInstruction(std::move(mv_inst)); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 75 | } |
| 76 | } |
| 77 | |
| 78 | std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 79 | 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 | |
| 86 | std::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 | |
| 104 | std::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 | |
| 111 | std::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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 126 | } |
| 127 | |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 128 | std::unique_ptr<Instruction> InstrumentPass::NewName( |
| 129 | uint32_t id, const std::string& name_str) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 130 | return MakeUnique<Instruction>( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 131 | context(), spv::Op::OpName, 0, 0, |
| 132 | std::initializer_list<Operand>{ |
| 133 | {SPV_OPERAND_TYPE_ID, {id}}, |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 134 | {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | std::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 | |
| 159 | std::unique_ptr<Instruction> InstrumentPass::NewMemberName( |
| 160 | uint32_t id, uint32_t member_index, const std::string& name_str) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 161 | return MakeUnique<Instruction>( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 162 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 166 | {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 169 | uint32_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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 181 | return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpSConvert, val_id) |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 182 | ->result_id(); |
| 183 | else |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 184 | return builder->AddUnaryOp(val_32b_reg_ty_id, spv::Op::OpUConvert, val_id) |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 185 | ->result_id(); |
| 186 | } |
| 187 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 188 | uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id, |
| 189 | InstructionBuilder* builder) { |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 190 | // 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 197 | return builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast, val_32b_id) |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 198 | ->result_id(); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | void 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 208 | Instruction* data_idx_inst = builder->AddIAdd( |
| 209 | GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset)); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 210 | uint32_t buf_id = GetOutputBufferId(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 211 | uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 212 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | void 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 | |
| 238 | void InstrumentPass::GenFragCoordEltDebugOutputCode( |
| 239 | uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element, |
| 240 | InstructionBuilder* builder) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 241 | Instruction* element_val_inst = |
| 242 | builder->AddCompositeExtract(GetUintId(), uint_frag_coord_id, {element}); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 243 | GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element, |
| 244 | element_val_inst->result_id(), builder); |
| 245 | } |
| 246 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 247 | uint32_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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 251 | Instruction* load_inst = builder->AddLoad(type_id, var_id); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 252 | return load_inst->result_id(); |
| 253 | } |
| 254 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 255 | void 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 260 | uint32_t load_id = GenVarLoad(builtin_id, builder); |
| 261 | GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | void 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 268 | switch (spv::ExecutionModel(stage_idx)) { |
| 269 | case spv::ExecutionModel::Vertex: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 270 | // Load and store VertexId and InstanceId |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 271 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 272 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)), |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 273 | kInstVertOutVertexIndex, base_offset_id, builder); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 274 | GenBuiltinOutputCode(context()->GetBuiltinInputVarId( |
| 275 | uint32_t(spv::BuiltIn::InstanceIndex)), |
| 276 | kInstVertOutInstanceIndex, base_offset_id, builder); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 277 | } break; |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 278 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 283 | // Load and store GlobalInvocationId. |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 284 | uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t( |
| 285 | spv::BuiltIn::GlobalInvocationId)), |
| 286 | builder); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 287 | 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 Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 293 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 299 | } break; |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 300 | case spv::ExecutionModel::Geometry: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 301 | // Load and store PrimitiveId and InvocationId. |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 302 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 303 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 304 | kInstGeomOutPrimitiveId, base_offset_id, builder); |
| 305 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 306 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 307 | kInstGeomOutInvocationId, base_offset_id, builder); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 308 | } break; |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 309 | case spv::ExecutionModel::TessellationControl: { |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 310 | // Load and store InvocationId and PrimitiveId |
| 311 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 312 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 313 | kInstTessCtlOutInvocationId, base_offset_id, builder); |
| 314 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 315 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 316 | kInstTessCtlOutPrimitiveId, base_offset_id, builder); |
| 317 | } break; |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 318 | case spv::ExecutionModel::TessellationEvaluation: { |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 319 | // Load and store PrimitiveId and TessCoord.uv |
| 320 | GenBuiltinOutputCode( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 321 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 322 | kInstTessEvalOutPrimitiveId, base_offset_id, builder); |
| 323 | uint32_t load_id = GenVarLoad( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 324 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)), |
| 325 | builder); |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 326 | Instruction* uvec3_cast_inst = |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 327 | builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id); |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 328 | uint32_t uvec3_cast_id = uvec3_cast_inst->result_id(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 329 | Instruction* u_inst = |
| 330 | builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {0}); |
| 331 | Instruction* v_inst = |
| 332 | builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {1}); |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 333 | GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU, |
| 334 | u_inst->result_id(), builder); |
| 335 | GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV, |
| 336 | v_inst->result_id(), builder); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 337 | } break; |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 338 | case spv::ExecutionModel::Fragment: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 339 | // Load FragCoord and convert to Uint |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 340 | Instruction* frag_coord_inst = builder->AddLoad( |
| 341 | GetVec4FloatId(), |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 342 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord))); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 343 | Instruction* uint_frag_coord_inst = builder->AddUnaryOp( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 344 | GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id()); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 345 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 349 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 355 | // Load and store LaunchIdNV. |
| 356 | uint32_t launch_id = GenVarLoad( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 357 | context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)), |
| 358 | builder); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 359 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 365 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 372 | default: { assert(false && "unsupported stage"); } break; |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | void 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 382 | std::vector<uint32_t> args = {builder->GetUintConstantId(instruction_idx)}; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 383 | (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end()); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 384 | (void)builder->AddFunctionCall( |
| 385 | GetVoidId(), GetStreamWriteFunctionId(stage_idx, val_id_cnt), args); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 386 | } |
| 387 | |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 388 | bool 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 396 | uint32_t InstrumentPass::GenDebugDirectRead( |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 397 | const std::vector<uint32_t>& offset_ids, InstructionBuilder* builder) { |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 398 | // Call debug input function. Pass func_idx and offset ids as args. |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 399 | 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 | |
| 404 | uint32_t InstrumentPass::GenReadFunctionCall( |
| 405 | uint32_t func_id, const std::vector<uint32_t>& func_call_args, |
| 406 | InstructionBuilder* ref_builder) { |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 407 | // If optimizing direct reads and the call has already been generated, |
| 408 | // use its result |
| 409 | if (opt_direct_reads_) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 410 | uint32_t res_id = call2id_[func_call_args]; |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 411 | if (res_id != 0) return res_id; |
| 412 | } |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 413 | // 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 Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 417 | InstructionBuilder builder(ref_builder->GetContext(), |
| 418 | &*ref_builder->GetInsertPoint(), |
| 419 | ref_builder->GetPreservedAnalysis()); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 420 | bool insert_in_first_block = opt_direct_reads_ && AllConstant(func_call_args); |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 421 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 426 | builder.AddFunctionCall(GetUintId(), func_id, func_call_args) |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 427 | ->result_id(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 428 | if (insert_in_first_block) call2id_[func_call_args] = res_id; |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 429 | return res_id; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 430 | } |
| 431 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 432 | bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const { |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 433 | return inst->opcode() == spv::Op::OpSampledImage || |
| 434 | inst->opcode() == spv::Op::OpImage; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 435 | } |
| 436 | |
| 437 | void 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 441 | BasicBlock* block_ptr) { |
Ben Clayton | d552f63 | 2019-11-18 11:18:41 +0000 | [diff] [blame] | 442 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 472 | } |
| 473 | |
| 474 | void 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 Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 497 | uint32_t InstrumentPass::GetOutputBufferPtrId() { |
| 498 | if (output_buffer_ptr_id_ == 0) { |
| 499 | output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 500 | GetUintId(), spv::StorageClass::StorageBuffer); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 501 | } |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 502 | return output_buffer_ptr_id_; |
| 503 | } |
| 504 | |
| 505 | uint32_t InstrumentPass::GetInputBufferTypeId() { |
| 506 | return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id() |
| 507 | : GetUintId(); |
| 508 | } |
| 509 | |
| 510 | uint32_t InstrumentPass::GetInputBufferPtrId() { |
| 511 | if (input_buffer_ptr_id_ == 0) { |
| 512 | input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 513 | GetInputBufferTypeId(), spv::StorageClass::StorageBuffer); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 514 | } |
| 515 | return input_buffer_ptr_id_; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 516 | } |
| 517 | |
| 518 | uint32_t InstrumentPass::GetOutputBufferBinding() { |
| 519 | switch (validation_id_) { |
| 520 | case kInstValidationIdBindless: |
| 521 | return kDebugOutputBindingStream; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 522 | case kInstValidationIdBuffAddr: |
| 523 | return kDebugOutputBindingStream; |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 524 | case kInstValidationIdDebugPrintf: |
| 525 | return kDebugOutputPrintfStream; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 526 | default: |
| 527 | assert(false && "unexpected validation id"); |
| 528 | } |
| 529 | return 0; |
| 530 | } |
| 531 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 532 | uint32_t InstrumentPass::GetInputBufferBinding() { |
| 533 | switch (validation_id_) { |
| 534 | case kInstValidationIdBindless: |
| 535 | return kDebugInputBindingBindless; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 536 | case kInstValidationIdBuffAddr: |
| 537 | return kDebugInputBindingBuffAddr; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 538 | default: |
| 539 | assert(false && "unexpected validation id"); |
| 540 | } |
| 541 | return 0; |
| 542 | } |
| 543 | |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 544 | analysis::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 | |
| 551 | analysis::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 | |
| 559 | analysis::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 | |
| 567 | analysis::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 | |
| 576 | analysis::RuntimeArray* InstrumentPass::GetUintXRuntimeArrayType( |
| 577 | uint32_t width, analysis::RuntimeArray** rarr_ty) { |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 578 | if (*rarr_ty == nullptr) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 579 | *rarr_ty = GetRuntimeArray(GetInteger(width, false)); |
| 580 | uint32_t uint_arr_ty_id = |
| 581 | context()->get_type_mgr()->GetTypeInstruction(*rarr_ty); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 582 | // 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 588 | assert(get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 && |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 589 | "used RuntimeArray type returned"); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 590 | get_decoration_mgr()->AddDecorationVal( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 591 | uint_arr_ty_id, uint32_t(spv::Decoration::ArrayStride), width / 8u); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 592 | } |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 593 | return *rarr_ty; |
| 594 | } |
| 595 | |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 596 | analysis::RuntimeArray* InstrumentPass::GetUintRuntimeArrayType( |
| 597 | uint32_t width) { |
| 598 | analysis::RuntimeArray** rarr_ty = |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 599 | (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_; |
| 600 | return GetUintXRuntimeArrayType(width, rarr_ty); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 601 | } |
| 602 | |
| 603 | void InstrumentPass::AddStorageBufferExt() { |
| 604 | if (storage_buffer_ext_defined_) return; |
| 605 | if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) { |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 606 | context()->AddExtension("SPV_KHR_storage_buffer_storage_class"); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 607 | } |
| 608 | storage_buffer_ext_defined_ = true; |
| 609 | } |
| 610 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 611 | // Return id for output buffer |
| 612 | uint32_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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 617 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 621 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 630 | deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block)); |
| 631 | deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset, |
| 632 | uint32_t(spv::Decoration::Offset), 0); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 633 | deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset, |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 634 | uint32_t(spv::Decoration::Offset), 4); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 635 | deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset, |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 636 | uint32_t(spv::Decoration::Offset), 8); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 637 | uint32_t obufTyPtrId_ = |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 638 | type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 639 | output_buffer_id_ = TakeNextId(); |
| 640 | std::unique_ptr<Instruction> newVarOp(new Instruction( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 641 | context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_, |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 642 | {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 643 | {uint32_t(spv::StorageClass::StorageBuffer)}}})); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 644 | context()->AddGlobalValue(std::move(newVarOp)); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 645 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 654 | GetOutputBufferBinding()); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 655 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 662 | } |
| 663 | } |
| 664 | return output_buffer_id_; |
| 665 | } |
| 666 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 667 | uint32_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 Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 672 | uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u; |
| 673 | analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 674 | analysis::Struct* reg_buf_ty = GetStruct({reg_uint_rarr_ty}); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 675 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 684 | deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block)); |
| 685 | deco_mgr->AddMemberDecoration(ibufTyId, 0, |
| 686 | uint32_t(spv::Decoration::Offset), 0); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 687 | uint32_t ibufTyPtrId_ = |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 688 | type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 689 | input_buffer_id_ = TakeNextId(); |
| 690 | std::unique_ptr<Instruction> newVarOp(new Instruction( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 691 | context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_, |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 692 | {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 693 | {uint32_t(spv::StorageClass::StorageBuffer)}}})); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 694 | context()->AddGlobalValue(std::move(newVarOp)); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 695 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 702 | 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 Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 715 | uint32_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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 725 | uint32_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 | |
| 737 | uint32_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 Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 747 | uint32_t InstrumentPass::GetUint64Id() { |
| 748 | if (uint64_id_ == 0) { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 749 | analysis::TypeManager* type_mgr = context()->get_type_mgr(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 750 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 753 | } |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 754 | return uint64_id_; |
| 755 | } |
| 756 | |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 757 | uint32_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 Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 767 | uint32_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 | |
| 777 | uint32_t InstrumentPass::GetVec4UintId() { |
| 778 | if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 779 | return v4uint_id_; |
| 780 | } |
| 781 | |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 782 | uint32_t InstrumentPass::GetVec3UintId() { |
| 783 | if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u); |
| 784 | return v3uint_id_; |
| 785 | } |
| 786 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 787 | uint32_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 | |
| 797 | uint32_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 | |
| 807 | uint32_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 Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 812 | if (param2output_func_id_[param_cnt] == 0) { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 813 | // Create function |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 814 | param2output_func_id_[param_cnt] = TakeNextId(); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 815 | analysis::TypeManager* type_mgr = context()->get_type_mgr(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 816 | |
| 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 824 | // Create first block |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 825 | auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId())); |
| 826 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 827 | 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 Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 831 | uint32_t val_spec_offset = kInstStageOutCnt; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 832 | uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 833 | uint32_t buf_id = GetOutputBufferId(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 834 | uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 835 | Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain( |
| 836 | buf_uint_ptr_id, buf_id, |
| 837 | {builder.GetUintConstantId(kDebugOutputSizeOffset)}); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 838 | // 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 841 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 845 | Instruction* obuf_curr_sz_inst = builder.AddQuadOp( |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 846 | GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(), |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 847 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 851 | builder.AddIAdd(GetUintId(), obuf_curr_sz_id, |
| 852 | builder.GetUintConstantId(obuf_record_sz)); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 853 | // Fetch the data bound |
| 854 | Instruction* obuf_bnd_inst = |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 855 | builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength, |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 856 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 860 | GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(), |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 861 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 866 | (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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 869 | // Close safety test block and gen write block |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 870 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 874 | GenCommonStreamWriteCode(obuf_record_sz, param_ids[kInstCommonParamInstIdx], |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 875 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 879 | GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 880 | param_ids[kInstCommonParamCnt + i], &builder); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 881 | } |
| 882 | // Close write block and gen merge block |
| 883 | (void)builder.AddBranch(merge_blk_id); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 884 | 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 888 | (void)builder.AddNullaryOp(0, spv::Op::OpReturn); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 889 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 890 | output_func->AddBasicBlock(std::move(new_blk_ptr)); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 891 | output_func->SetFunctionEnd(EndFunction()); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 892 | context()->AddFunction(std::move(output_func)); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 893 | |
| 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 899 | } |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 900 | return param2output_func_id_[param_cnt]; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 901 | } |
| 902 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 903 | uint32_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 Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 906 | // Create input function for param_cnt. |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 907 | func_id = TakeNextId(); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 908 | analysis::Integer* uint_type = GetInteger(32, false); |
| 909 | std::vector<const analysis::Type*> param_types(param_cnt, uint_type); |
| 910 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 911 | std::unique_ptr<Function> input_func = |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 912 | StartFunction(func_id, uint_type, param_types); |
| 913 | std::vector<uint32_t> param_ids = AddParameters(*input_func, param_types); |
| 914 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 915 | // Create block |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 916 | auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId())); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 917 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 923 | uint32_t ibuf_type_id = GetInputBufferTypeId(); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 924 | uint32_t buf_id = GetInputBufferId(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 925 | uint32_t buf_ptr_id = GetInputBufferPtrId(); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 926 | 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 Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 930 | offset_id = param_ids[0]; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 931 | } else { |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 932 | if (ibuf_type_id != GetUintId()) { |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 933 | last_value_id = |
| 934 | builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id) |
| 935 | ->result_id(); |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 936 | } |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 937 | offset_id = builder.AddIAdd(GetUintId(), last_value_id, param_ids[p]) |
| 938 | ->result_id(); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 939 | } |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 940 | 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 945 | } |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 946 | (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, last_value_id); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 947 | // Close block and function and add function to module |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 948 | input_func->AddBasicBlock(std::move(new_blk_ptr)); |
Ben Clayton | 1669665 | 2023-02-06 14:45:50 +0000 | [diff] [blame^] | 949 | input_func->SetFunctionEnd(EndFunction()); |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 950 | context()->AddFunction(std::move(input_func)); |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 951 | |
| 952 | std::string name("direct_read_"); |
| 953 | name += std::to_string(param_cnt); |
| 954 | context()->AddDebug2Inst(NewGlobalName(func_id, name)); |
| 955 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 956 | param2input_func_id_[param_cnt] = func_id; |
| 957 | return func_id; |
| 958 | } |
| 959 | |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 960 | void 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 983 | bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx, |
| 984 | InstProcessFunction& pfn) { |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 985 | curr_func_ = func; |
| 986 | call2id_.clear(); |
| 987 | bool first_block_split = false; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 988 | bool modified = false; |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 989 | // Apply instrumentation function to each instruction. |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 990 | // Using block iterators here because of block erasures and insertions. |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 991 | std::vector<std::unique_ptr<BasicBlock>> new_blks; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 992 | for (auto bi = func->begin(); bi != func->end(); ++bi) { |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 993 | for (auto ii = bi->begin(); ii != bi->end();) { |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 994 | // 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 998 | if (ii->opcode() != spv::Op::OpVariable) { |
Alexis Hetu | 3eb4dd8 | 2020-10-29 21:37:20 -0400 | [diff] [blame] | 999 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1006 | if (new_blks.size() == 0) { |
| 1007 | ++ii; |
| 1008 | continue; |
| 1009 | } |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1010 | // Add new blocks to label id map |
| 1011 | for (auto& blk : new_blks) id2block_[blk->id()] = &*blk; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1012 | // 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 1029 | if (ii->opcode() == spv::Op::OpPhi || |
| 1030 | ii->opcode() == spv::Op::OpCopyObject) |
| 1031 | ++ii; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1032 | new_blks.clear(); |
| 1033 | } |
| 1034 | } |
| 1035 | return modified; |
| 1036 | } |
| 1037 | |
| 1038 | bool 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1043 | // Don't process input and output functions |
| 1044 | for (auto& ifn : param2input_func_id_) done.insert(ifn.second); |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 1045 | for (auto& ofn : param2output_func_id_) done.insert(ofn.second); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1046 | // 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 | |
| 1060 | bool 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 1069 | spv::ExecutionModel stage = context()->GetStage(); |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1070 | // Check for supported stages |
Nicolas Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 1071 | 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 Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1087 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1091 | return false; |
Ben Clayton | 0b54f13 | 2020-01-06 13:38:54 +0000 | [diff] [blame] | 1092 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1093 | // 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 Capens | 84c9c45 | 2022-11-18 14:11:05 +0000 | [diff] [blame] | 1098 | bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage)); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1099 | return modified; |
| 1100 | } |
| 1101 | |
| 1102 | void InstrumentPass::InitializeInstrument() { |
| 1103 | output_buffer_id_ = 0; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1104 | output_buffer_ptr_id_ = 0; |
| 1105 | input_buffer_ptr_id_ = 0; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1106 | input_buffer_id_ = 0; |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 1107 | float_id_ = 0; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1108 | v4float_id_ = 0; |
| 1109 | uint_id_ = 0; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1110 | uint64_id_ = 0; |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 1111 | uint8_id_ = 0; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1112 | v4uint_id_ = 0; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1113 | v3uint_id_ = 0; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1114 | bool_id_ = 0; |
| 1115 | void_id_ = 0; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1116 | storage_buffer_ext_defined_ = false; |
Ben Clayton | d0f684e | 2019-08-30 22:36:08 +0100 | [diff] [blame] | 1117 | uint32_rarr_ty_ = nullptr; |
| 1118 | uint64_rarr_ty_ = nullptr; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1119 | |
| 1120 | // clear collections |
| 1121 | id2function_.clear(); |
| 1122 | id2block_.clear(); |
| 1123 | |
Alexis Hetu | b8a7746 | 2020-03-27 07:59:09 -0400 | [diff] [blame] | 1124 | // clear maps |
| 1125 | param2input_func_id_.clear(); |
| 1126 | param2output_func_id_.clear(); |
| 1127 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1128 | // 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 Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1136 | // Remember original instruction offsets |
| 1137 | uint32_t module_offset = 0; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1138 | Module* module = get_module(); |
| 1139 | for (auto& i : context()->capabilities()) { |
| 1140 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1141 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1142 | } |
| 1143 | for (auto& i : module->extensions()) { |
| 1144 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1145 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1146 | } |
| 1147 | for (auto& i : module->ext_inst_imports()) { |
| 1148 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1149 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1150 | } |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1151 | ++module_offset; // memory_model |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1152 | for (auto& i : module->entry_points()) { |
| 1153 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1154 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1155 | } |
| 1156 | for (auto& i : module->execution_modes()) { |
| 1157 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1158 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1159 | } |
| 1160 | for (auto& i : module->debugs1()) { |
| 1161 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1162 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1163 | } |
| 1164 | for (auto& i : module->debugs2()) { |
| 1165 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1166 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1167 | } |
| 1168 | for (auto& i : module->debugs3()) { |
| 1169 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1170 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1171 | } |
Ben Clayton | dc6b76a | 2020-02-24 14:53:40 +0000 | [diff] [blame] | 1172 | for (auto& i : module->ext_inst_debuginfo()) { |
| 1173 | (void)i; |
| 1174 | ++module_offset; |
| 1175 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1176 | for (auto& i : module->annotations()) { |
| 1177 | (void)i; |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1178 | ++module_offset; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1179 | } |
| 1180 | for (auto& i : module->types_values()) { |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1181 | module_offset += 1; |
| 1182 | module_offset += static_cast<uint32_t>(i.dbg_line_insts().size()); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1183 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1184 | |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1185 | 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 Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1192 | // Count label |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1193 | module_offset += 1; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1194 | for (auto& inst : blk) { |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1195 | module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size()); |
| 1196 | uid2offset_[inst.unique_id()] = module_offset; |
| 1197 | module_offset += 1; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1198 | } |
| 1199 | } |
Ben Clayton | b73b760 | 2019-07-29 13:56:13 +0100 | [diff] [blame] | 1200 | // Count function end instruction |
| 1201 | module_offset += 1; |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1202 | } |
| 1203 | } |
| 1204 | |
| 1205 | } // namespace opt |
| 1206 | } // namespace spvtools |