inst_debug_printf_pass.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. // Copyright (c) 2020 The Khronos Group Inc.
  2. // Copyright (c) 2020 Valve Corporation
  3. // Copyright (c) 2020 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. #include "inst_debug_printf_pass.h"
  17. #include "source/spirv_constant.h"
  18. #include "source/util/string_utils.h"
  19. #include "spirv/unified1/NonSemanticDebugPrintf.h"
  20. namespace spvtools {
  21. namespace opt {
  22. void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst,
  23. std::vector<uint32_t>* val_ids,
  24. InstructionBuilder* builder) {
  25. uint32_t val_ty_id = val_inst->type_id();
  26. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  27. analysis::Type* val_ty = type_mgr->GetType(val_ty_id);
  28. switch (val_ty->kind()) {
  29. case analysis::Type::kVector: {
  30. analysis::Vector* v_ty = val_ty->AsVector();
  31. const analysis::Type* c_ty = v_ty->element_type();
  32. uint32_t c_ty_id = type_mgr->GetId(c_ty);
  33. for (uint32_t c = 0; c < v_ty->element_count(); ++c) {
  34. Instruction* c_inst =
  35. builder->AddCompositeExtract(c_ty_id, val_inst->result_id(), {c});
  36. GenOutputValues(c_inst, val_ids, builder);
  37. }
  38. return;
  39. }
  40. case analysis::Type::kBool: {
  41. // Select between uint32 zero or one
  42. uint32_t zero_id = builder->GetUintConstantId(0);
  43. uint32_t one_id = builder->GetUintConstantId(1);
  44. Instruction* sel_inst = builder->AddSelect(
  45. GetUintId(), val_inst->result_id(), one_id, zero_id);
  46. val_ids->push_back(sel_inst->result_id());
  47. return;
  48. }
  49. case analysis::Type::kFloat: {
  50. analysis::Float* f_ty = val_ty->AsFloat();
  51. switch (f_ty->width()) {
  52. case 16: {
  53. // Convert float16 to float32 and recurse
  54. Instruction* f32_inst = builder->AddUnaryOp(
  55. GetFloatId(), spv::Op::OpFConvert, val_inst->result_id());
  56. GenOutputValues(f32_inst, val_ids, builder);
  57. return;
  58. }
  59. case 64: {
  60. // Bitcast float64 to uint64 and recurse
  61. Instruction* ui64_inst = builder->AddUnaryOp(
  62. GetUint64Id(), spv::Op::OpBitcast, val_inst->result_id());
  63. GenOutputValues(ui64_inst, val_ids, builder);
  64. return;
  65. }
  66. case 32: {
  67. // Bitcase float32 to uint32
  68. Instruction* bc_inst = builder->AddUnaryOp(
  69. GetUintId(), spv::Op::OpBitcast, val_inst->result_id());
  70. val_ids->push_back(bc_inst->result_id());
  71. return;
  72. }
  73. default:
  74. assert(false && "unsupported float width");
  75. return;
  76. }
  77. }
  78. case analysis::Type::kInteger: {
  79. analysis::Integer* i_ty = val_ty->AsInteger();
  80. switch (i_ty->width()) {
  81. case 64: {
  82. Instruction* ui64_inst = val_inst;
  83. if (i_ty->IsSigned()) {
  84. // Bitcast sint64 to uint64
  85. ui64_inst = builder->AddUnaryOp(GetUint64Id(), spv::Op::OpBitcast,
  86. val_inst->result_id());
  87. }
  88. // Break uint64 into 2x uint32
  89. Instruction* lo_ui64_inst = builder->AddUnaryOp(
  90. GetUintId(), spv::Op::OpUConvert, ui64_inst->result_id());
  91. Instruction* rshift_ui64_inst = builder->AddBinaryOp(
  92. GetUint64Id(), spv::Op::OpShiftRightLogical,
  93. ui64_inst->result_id(), builder->GetUintConstantId(32));
  94. Instruction* hi_ui64_inst = builder->AddUnaryOp(
  95. GetUintId(), spv::Op::OpUConvert, rshift_ui64_inst->result_id());
  96. val_ids->push_back(lo_ui64_inst->result_id());
  97. val_ids->push_back(hi_ui64_inst->result_id());
  98. return;
  99. }
  100. case 8: {
  101. Instruction* ui8_inst = val_inst;
  102. if (i_ty->IsSigned()) {
  103. // Bitcast sint8 to uint8
  104. ui8_inst = builder->AddUnaryOp(GetUint8Id(), spv::Op::OpBitcast,
  105. val_inst->result_id());
  106. }
  107. // Convert uint8 to uint32
  108. Instruction* ui32_inst = builder->AddUnaryOp(
  109. GetUintId(), spv::Op::OpUConvert, ui8_inst->result_id());
  110. val_ids->push_back(ui32_inst->result_id());
  111. return;
  112. }
  113. case 32: {
  114. Instruction* ui32_inst = val_inst;
  115. if (i_ty->IsSigned()) {
  116. // Bitcast sint32 to uint32
  117. ui32_inst = builder->AddUnaryOp(GetUintId(), spv::Op::OpBitcast,
  118. val_inst->result_id());
  119. }
  120. // uint32 needs no further processing
  121. val_ids->push_back(ui32_inst->result_id());
  122. return;
  123. }
  124. default:
  125. // TODO(greg-lunarg): Support non-32-bit int
  126. assert(false && "unsupported int width");
  127. return;
  128. }
  129. }
  130. default:
  131. assert(false && "unsupported type");
  132. return;
  133. }
  134. }
  135. void InstDebugPrintfPass::GenOutputCode(
  136. Instruction* printf_inst,
  137. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  138. BasicBlock* back_blk_ptr = &*new_blocks->back();
  139. InstructionBuilder builder(
  140. context(), back_blk_ptr,
  141. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  142. // Gen debug printf record validation-specific values. The format string
  143. // will have its id written. Vectors will need to be broken down into
  144. // component values. float16 will need to be converted to float32. Pointer
  145. // and uint64 will need to be converted to two uint32 values. float32 will
  146. // need to be bitcast to uint32. int32 will need to be bitcast to uint32.
  147. std::vector<uint32_t> val_ids;
  148. bool is_first_operand = false;
  149. printf_inst->ForEachInId(
  150. [&is_first_operand, &val_ids, &builder, this](const uint32_t* iid) {
  151. // skip set operand
  152. if (!is_first_operand) {
  153. is_first_operand = true;
  154. return;
  155. }
  156. Instruction* opnd_inst = get_def_use_mgr()->GetDef(*iid);
  157. if (opnd_inst->opcode() == spv::Op::OpString) {
  158. uint32_t string_id_id = builder.GetUintConstantId(*iid);
  159. val_ids.push_back(string_id_id);
  160. } else {
  161. GenOutputValues(opnd_inst, &val_ids, &builder);
  162. }
  163. });
  164. GenDebugStreamWrite(
  165. builder.GetUintConstantId(shader_id_),
  166. builder.GetUintConstantId(uid2offset_[printf_inst->unique_id()]), val_ids,
  167. &builder);
  168. context()->KillInst(printf_inst);
  169. }
  170. void InstDebugPrintfPass::GenDebugPrintfCode(
  171. BasicBlock::iterator ref_inst_itr,
  172. UptrVectorIterator<BasicBlock> ref_block_itr,
  173. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  174. // If not DebugPrintf OpExtInst, return.
  175. Instruction* printf_inst = &*ref_inst_itr;
  176. if (printf_inst->opcode() != spv::Op::OpExtInst) return;
  177. if (printf_inst->GetSingleWordInOperand(0) != ext_inst_printf_id_) return;
  178. if (printf_inst->GetSingleWordInOperand(1) !=
  179. NonSemanticDebugPrintfDebugPrintf)
  180. return;
  181. // Initialize DefUse manager before dismantling module
  182. (void)get_def_use_mgr();
  183. // Move original block's preceding instructions into first new block
  184. std::unique_ptr<BasicBlock> new_blk_ptr;
  185. MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
  186. new_blocks->push_back(std::move(new_blk_ptr));
  187. // Generate instructions to output printf args to printf buffer
  188. GenOutputCode(printf_inst, new_blocks);
  189. // Caller expects at least two blocks with last block containing remaining
  190. // code, so end block after instrumentation, create remainder block, and
  191. // branch to it
  192. uint32_t rem_blk_id = TakeNextId();
  193. std::unique_ptr<Instruction> rem_label(NewLabel(rem_blk_id));
  194. BasicBlock* back_blk_ptr = &*new_blocks->back();
  195. InstructionBuilder builder(
  196. context(), back_blk_ptr,
  197. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  198. (void)builder.AddBranch(rem_blk_id);
  199. // Gen remainder block
  200. new_blk_ptr.reset(new BasicBlock(std::move(rem_label)));
  201. builder.SetInsertPoint(&*new_blk_ptr);
  202. // Move original block's remaining code into remainder block and add
  203. // to new blocks
  204. MovePostludeCode(ref_block_itr, &*new_blk_ptr);
  205. new_blocks->push_back(std::move(new_blk_ptr));
  206. }
  207. // Return id for output buffer
  208. uint32_t InstDebugPrintfPass::GetOutputBufferId() {
  209. if (output_buffer_id_ == 0) {
  210. // If not created yet, create one
  211. analysis::DecorationManager* deco_mgr = get_decoration_mgr();
  212. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  213. analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
  214. analysis::Integer* reg_uint_ty = GetInteger(32, false);
  215. analysis::Type* reg_buf_ty =
  216. GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
  217. uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
  218. // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
  219. // must be a block, and will therefore be decorated with Block. Therefore
  220. // the undecorated type returned here will not be pre-existing and can
  221. // safely be decorated. Since this type is now decorated, it is out of
  222. // sync with the TypeManager and therefore the TypeManager must be
  223. // invalidated after this pass.
  224. assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
  225. "used struct type returned");
  226. deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
  227. deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
  228. uint32_t(spv::Decoration::Offset), 0);
  229. deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
  230. uint32_t(spv::Decoration::Offset), 4);
  231. deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
  232. uint32_t(spv::Decoration::Offset), 8);
  233. uint32_t obufTyPtrId_ =
  234. type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
  235. output_buffer_id_ = TakeNextId();
  236. std::unique_ptr<Instruction> newVarOp(new Instruction(
  237. context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
  238. {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  239. {uint32_t(spv::StorageClass::StorageBuffer)}}}));
  240. context()->AddGlobalValue(std::move(newVarOp));
  241. context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
  242. context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
  243. context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
  244. context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
  245. context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
  246. deco_mgr->AddDecorationVal(
  247. output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
  248. deco_mgr->AddDecorationVal(output_buffer_id_,
  249. uint32_t(spv::Decoration::Binding),
  250. GetOutputBufferBinding());
  251. AddStorageBufferExt();
  252. if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  253. // Add the new buffer to all entry points.
  254. for (auto& entry : get_module()->entry_points()) {
  255. entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
  256. context()->AnalyzeUses(&entry);
  257. }
  258. }
  259. }
  260. return output_buffer_id_;
  261. }
  262. uint32_t InstDebugPrintfPass::GetOutputBufferPtrId() {
  263. if (output_buffer_ptr_id_ == 0) {
  264. output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
  265. GetUintId(), spv::StorageClass::StorageBuffer);
  266. }
  267. return output_buffer_ptr_id_;
  268. }
  269. uint32_t InstDebugPrintfPass::GetOutputBufferBinding() {
  270. return kDebugOutputPrintfStream;
  271. }
  272. void InstDebugPrintfPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
  273. uint32_t field_offset,
  274. uint32_t field_value_id,
  275. InstructionBuilder* builder) {
  276. // Cast value to 32-bit unsigned if necessary
  277. uint32_t val_id = GenUintCastCode(field_value_id, builder);
  278. // Store value
  279. Instruction* data_idx_inst = builder->AddIAdd(
  280. GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset));
  281. uint32_t buf_id = GetOutputBufferId();
  282. uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  283. Instruction* achain_inst = builder->AddAccessChain(
  284. buf_uint_ptr_id, buf_id,
  285. {builder->GetUintConstantId(kDebugOutputDataOffset),
  286. data_idx_inst->result_id()});
  287. (void)builder->AddStore(achain_inst->result_id(), val_id);
  288. }
  289. uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) {
  290. enum {
  291. kShaderId = 0,
  292. kInstructionIndex = 1,
  293. kFirstParam = 2,
  294. };
  295. // Total param count is common params plus validation-specific
  296. // params
  297. if (param2output_func_id_[param_cnt] == 0) {
  298. // Create function
  299. param2output_func_id_[param_cnt] = TakeNextId();
  300. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  301. const analysis::Type* uint_type = GetInteger(32, false);
  302. std::vector<const analysis::Type*> param_types(kFirstParam + param_cnt,
  303. uint_type);
  304. std::unique_ptr<Function> output_func = StartFunction(
  305. param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types);
  306. std::vector<uint32_t> param_ids = AddParameters(*output_func, param_types);
  307. // Create first block
  308. auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
  309. InstructionBuilder builder(
  310. context(), &*new_blk_ptr,
  311. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  312. // Gen test if debug output buffer size will not be exceeded.
  313. const uint32_t first_param_offset = kInstCommonOutInstructionIdx + 1;
  314. const uint32_t obuf_record_sz = first_param_offset + param_cnt;
  315. const uint32_t buf_id = GetOutputBufferId();
  316. const uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  317. Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain(
  318. buf_uint_ptr_id, buf_id,
  319. {builder.GetUintConstantId(kDebugOutputSizeOffset)});
  320. // Fetch the current debug buffer written size atomically, adding the
  321. // size of the record to be written.
  322. uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
  323. uint32_t mask_none_id =
  324. builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
  325. uint32_t scope_invok_id =
  326. builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
  327. Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
  328. GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
  329. scope_invok_id, mask_none_id, obuf_record_sz_id);
  330. uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
  331. // Compute new written size
  332. Instruction* obuf_new_sz_inst =
  333. builder.AddIAdd(GetUintId(), obuf_curr_sz_id,
  334. builder.GetUintConstantId(obuf_record_sz));
  335. // Fetch the data bound
  336. Instruction* obuf_bnd_inst =
  337. builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
  338. GetOutputBufferId(), kDebugOutputDataOffset);
  339. // Test that new written size is less than or equal to debug output
  340. // data bound
  341. Instruction* obuf_safe_inst = builder.AddBinaryOp(
  342. GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
  343. obuf_bnd_inst->result_id());
  344. uint32_t merge_blk_id = TakeNextId();
  345. uint32_t write_blk_id = TakeNextId();
  346. std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
  347. std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
  348. (void)builder.AddConditionalBranch(
  349. obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
  350. uint32_t(spv::SelectionControlMask::MaskNone));
  351. // Close safety test block and gen write block
  352. output_func->AddBasicBlock(std::move(new_blk_ptr));
  353. new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
  354. builder.SetInsertPoint(&*new_blk_ptr);
  355. // Generate common and stage-specific debug record members
  356. GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutSize,
  357. builder.GetUintConstantId(obuf_record_sz),
  358. &builder);
  359. // Store Shader Id
  360. GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutShaderId,
  361. param_ids[kShaderId], &builder);
  362. // Store Instruction Idx
  363. GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutInstructionIdx,
  364. param_ids[kInstructionIndex], &builder);
  365. // Gen writes of validation specific data
  366. for (uint32_t i = 0; i < param_cnt; ++i) {
  367. GenDebugOutputFieldCode(obuf_curr_sz_id, first_param_offset + i,
  368. param_ids[kFirstParam + i], &builder);
  369. }
  370. // Close write block and gen merge block
  371. (void)builder.AddBranch(merge_blk_id);
  372. output_func->AddBasicBlock(std::move(new_blk_ptr));
  373. new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
  374. builder.SetInsertPoint(&*new_blk_ptr);
  375. // Close merge block and function and add function to module
  376. (void)builder.AddNullaryOp(0, spv::Op::OpReturn);
  377. output_func->AddBasicBlock(std::move(new_blk_ptr));
  378. output_func->SetFunctionEnd(EndFunction());
  379. context()->AddFunction(std::move(output_func));
  380. std::string name("stream_write_");
  381. name += std::to_string(param_cnt);
  382. context()->AddDebug2Inst(
  383. NewGlobalName(param2output_func_id_[param_cnt], name));
  384. }
  385. return param2output_func_id_[param_cnt];
  386. }
  387. void InstDebugPrintfPass::GenDebugStreamWrite(
  388. uint32_t shader_id, uint32_t instruction_idx_id,
  389. const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
  390. // Call debug output function. Pass func_idx, instruction_idx and
  391. // validation ids as args.
  392. uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
  393. std::vector<uint32_t> args = {shader_id, instruction_idx_id};
  394. (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
  395. (void)builder->AddFunctionCall(GetVoidId(),
  396. GetStreamWriteFunctionId(val_id_cnt), args);
  397. }
  398. std::unique_ptr<Instruction> InstDebugPrintfPass::NewGlobalName(
  399. uint32_t id, const std::string& name_str) {
  400. std::string prefixed_name{"inst_printf_"};
  401. prefixed_name += name_str;
  402. return NewName(id, prefixed_name);
  403. }
  404. std::unique_ptr<Instruction> InstDebugPrintfPass::NewMemberName(
  405. uint32_t id, uint32_t member_index, const std::string& name_str) {
  406. return MakeUnique<Instruction>(
  407. context(), spv::Op::OpMemberName, 0, 0,
  408. std::initializer_list<Operand>{
  409. {SPV_OPERAND_TYPE_ID, {id}},
  410. {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
  411. {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
  412. }
  413. void InstDebugPrintfPass::InitializeInstDebugPrintf() {
  414. // Initialize base class
  415. InitializeInstrument();
  416. output_buffer_id_ = 0;
  417. output_buffer_ptr_id_ = 0;
  418. }
  419. Pass::Status InstDebugPrintfPass::ProcessImpl() {
  420. // Perform printf instrumentation on each entry point function in module
  421. InstProcessFunction pfn =
  422. [this](BasicBlock::iterator ref_inst_itr,
  423. UptrVectorIterator<BasicBlock> ref_block_itr,
  424. [[maybe_unused]] uint32_t stage_idx,
  425. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  426. return GenDebugPrintfCode(ref_inst_itr, ref_block_itr, new_blocks);
  427. };
  428. (void)InstProcessEntryPointCallTree(pfn);
  429. // Remove DebugPrintf OpExtInstImport instruction
  430. Instruction* ext_inst_import_inst =
  431. get_def_use_mgr()->GetDef(ext_inst_printf_id_);
  432. context()->KillInst(ext_inst_import_inst);
  433. // If no remaining non-semantic instruction sets, remove non-semantic debug
  434. // info extension from module and feature manager
  435. bool non_sem_set_seen = false;
  436. for (auto c_itr = context()->module()->ext_inst_import_begin();
  437. c_itr != context()->module()->ext_inst_import_end(); ++c_itr) {
  438. const std::string set_name = c_itr->GetInOperand(0).AsString();
  439. if (spvtools::utils::starts_with(set_name, "NonSemantic.")) {
  440. non_sem_set_seen = true;
  441. break;
  442. }
  443. }
  444. if (!non_sem_set_seen) {
  445. context()->RemoveExtension(kSPV_KHR_non_semantic_info);
  446. }
  447. return Status::SuccessWithChange;
  448. }
  449. Pass::Status InstDebugPrintfPass::Process() {
  450. ext_inst_printf_id_ =
  451. get_module()->GetExtInstImportId("NonSemantic.DebugPrintf");
  452. if (ext_inst_printf_id_ == 0) return Status::SuccessWithoutChange;
  453. InitializeInstDebugPrintf();
  454. return ProcessImpl();
  455. }
  456. } // namespace opt
  457. } // namespace spvtools