inst_bindless_check_pass.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. #include "inst_bindless_check_pass.h"
  17. namespace {
  18. // Input Operand Indices
  19. static const int kSpvImageSampleImageIdInIdx = 0;
  20. static const int kSpvSampledImageImageIdInIdx = 0;
  21. static const int kSpvSampledImageSamplerIdInIdx = 1;
  22. static const int kSpvImageSampledImageIdInIdx = 0;
  23. static const int kSpvLoadPtrIdInIdx = 0;
  24. static const int kSpvAccessChainBaseIdInIdx = 0;
  25. static const int kSpvAccessChainIndex0IdInIdx = 1;
  26. static const int kSpvTypePointerTypeIdInIdx = 1;
  27. static const int kSpvTypeArrayLengthIdInIdx = 1;
  28. static const int kSpvConstantValueInIdx = 0;
  29. static const int kSpvVariableStorageClassInIdx = 0;
  30. } // anonymous namespace
  31. namespace spvtools {
  32. namespace opt {
  33. uint32_t InstBindlessCheckPass::GenDebugReadLength(
  34. uint32_t var_id, InstructionBuilder* builder) {
  35. uint32_t desc_set_idx =
  36. var2desc_set_[var_id] + kDebugInputBindlessOffsetLengths;
  37. uint32_t desc_set_idx_id = builder->GetUintConstantId(desc_set_idx);
  38. uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]);
  39. return GenDebugDirectRead({desc_set_idx_id, binding_idx_id}, builder);
  40. }
  41. uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id,
  42. uint32_t desc_idx_id,
  43. InstructionBuilder* builder) {
  44. uint32_t desc_set_base_id =
  45. builder->GetUintConstantId(kDebugInputBindlessInitOffset);
  46. uint32_t desc_set_idx_id = builder->GetUintConstantId(var2desc_set_[var_id]);
  47. uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]);
  48. uint32_t u_desc_idx_id = GenUintCastCode(desc_idx_id, builder);
  49. return GenDebugDirectRead(
  50. {desc_set_base_id, desc_set_idx_id, binding_idx_id, u_desc_idx_id},
  51. builder);
  52. }
  53. uint32_t InstBindlessCheckPass::CloneOriginalReference(
  54. ref_analysis* ref, InstructionBuilder* builder) {
  55. // If original is image based, start by cloning descriptor load
  56. uint32_t new_image_id = 0;
  57. if (ref->desc_load_id != 0) {
  58. Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
  59. Instruction* new_load_inst = builder->AddLoad(
  60. desc_load_inst->type_id(),
  61. desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
  62. uid2offset_[new_load_inst->unique_id()] =
  63. uid2offset_[desc_load_inst->unique_id()];
  64. uint32_t new_load_id = new_load_inst->result_id();
  65. get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(),
  66. new_load_id);
  67. new_image_id = new_load_id;
  68. // Clone Image/SampledImage with new load, if needed
  69. if (ref->image_id != 0) {
  70. Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
  71. if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
  72. Instruction* new_image_inst = builder->AddBinaryOp(
  73. image_inst->type_id(), SpvOpSampledImage, new_load_id,
  74. image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
  75. uid2offset_[new_image_inst->unique_id()] =
  76. uid2offset_[image_inst->unique_id()];
  77. new_image_id = new_image_inst->result_id();
  78. } else {
  79. assert(image_inst->opcode() == SpvOp::SpvOpImage &&
  80. "expecting OpImage");
  81. Instruction* new_image_inst =
  82. builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id);
  83. uid2offset_[new_image_inst->unique_id()] =
  84. uid2offset_[image_inst->unique_id()];
  85. new_image_id = new_image_inst->result_id();
  86. }
  87. get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id);
  88. }
  89. }
  90. // Clone original reference
  91. std::unique_ptr<Instruction> new_ref_inst(ref->ref_inst->Clone(context()));
  92. uint32_t ref_result_id = ref->ref_inst->result_id();
  93. uint32_t new_ref_id = 0;
  94. if (ref_result_id != 0) {
  95. new_ref_id = TakeNextId();
  96. new_ref_inst->SetResultId(new_ref_id);
  97. }
  98. // Update new ref with new image if created
  99. if (new_image_id != 0)
  100. new_ref_inst->SetInOperand(kSpvImageSampleImageIdInIdx, {new_image_id});
  101. // Register new reference and add to new block
  102. Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst));
  103. uid2offset_[added_inst->unique_id()] =
  104. uid2offset_[ref->ref_inst->unique_id()];
  105. if (new_ref_id != 0)
  106. get_decoration_mgr()->CloneDecorations(ref_result_id, new_ref_id);
  107. return new_ref_id;
  108. }
  109. uint32_t InstBindlessCheckPass::GetImageId(Instruction* inst) {
  110. switch (inst->opcode()) {
  111. case SpvOp::SpvOpImageSampleImplicitLod:
  112. case SpvOp::SpvOpImageSampleExplicitLod:
  113. case SpvOp::SpvOpImageSampleDrefImplicitLod:
  114. case SpvOp::SpvOpImageSampleDrefExplicitLod:
  115. case SpvOp::SpvOpImageSampleProjImplicitLod:
  116. case SpvOp::SpvOpImageSampleProjExplicitLod:
  117. case SpvOp::SpvOpImageSampleProjDrefImplicitLod:
  118. case SpvOp::SpvOpImageSampleProjDrefExplicitLod:
  119. case SpvOp::SpvOpImageGather:
  120. case SpvOp::SpvOpImageDrefGather:
  121. case SpvOp::SpvOpImageQueryLod:
  122. case SpvOp::SpvOpImageSparseSampleImplicitLod:
  123. case SpvOp::SpvOpImageSparseSampleExplicitLod:
  124. case SpvOp::SpvOpImageSparseSampleDrefImplicitLod:
  125. case SpvOp::SpvOpImageSparseSampleDrefExplicitLod:
  126. case SpvOp::SpvOpImageSparseSampleProjImplicitLod:
  127. case SpvOp::SpvOpImageSparseSampleProjExplicitLod:
  128. case SpvOp::SpvOpImageSparseSampleProjDrefImplicitLod:
  129. case SpvOp::SpvOpImageSparseSampleProjDrefExplicitLod:
  130. case SpvOp::SpvOpImageSparseGather:
  131. case SpvOp::SpvOpImageSparseDrefGather:
  132. case SpvOp::SpvOpImageFetch:
  133. case SpvOp::SpvOpImageRead:
  134. case SpvOp::SpvOpImageQueryFormat:
  135. case SpvOp::SpvOpImageQueryOrder:
  136. case SpvOp::SpvOpImageQuerySizeLod:
  137. case SpvOp::SpvOpImageQuerySize:
  138. case SpvOp::SpvOpImageQueryLevels:
  139. case SpvOp::SpvOpImageQuerySamples:
  140. case SpvOp::SpvOpImageSparseFetch:
  141. case SpvOp::SpvOpImageSparseRead:
  142. case SpvOp::SpvOpImageWrite:
  143. return inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
  144. default:
  145. break;
  146. }
  147. return 0;
  148. }
  149. Instruction* InstBindlessCheckPass::GetDescriptorTypeInst(
  150. Instruction* var_inst) {
  151. uint32_t var_type_id = var_inst->type_id();
  152. Instruction* var_type_inst = get_def_use_mgr()->GetDef(var_type_id);
  153. uint32_t desc_type_id =
  154. var_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx);
  155. return get_def_use_mgr()->GetDef(desc_type_id);
  156. }
  157. bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
  158. ref_analysis* ref) {
  159. ref->ref_inst = ref_inst;
  160. if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) {
  161. ref->desc_load_id = 0;
  162. ref->ptr_id = ref_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
  163. Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
  164. if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return false;
  165. ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx);
  166. Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
  167. if (var_inst->opcode() != SpvOp::SpvOpVariable) return false;
  168. uint32_t storage_class =
  169. var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx);
  170. switch (storage_class) {
  171. case SpvStorageClassUniform:
  172. case SpvStorageClassUniformConstant:
  173. case SpvStorageClassStorageBuffer:
  174. break;
  175. default:
  176. return false;
  177. break;
  178. }
  179. Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst);
  180. switch (desc_type_inst->opcode()) {
  181. case SpvOpTypeArray:
  182. case SpvOpTypeRuntimeArray:
  183. // A load through a descriptor array will have at least 3 operands. We
  184. // do not want to instrument loads of descriptors here which are part of
  185. // an image-based reference.
  186. if (ptr_inst->NumInOperands() < 3) return false;
  187. ref->index_id =
  188. ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx);
  189. break;
  190. default:
  191. ref->index_id = 0;
  192. break;
  193. }
  194. return true;
  195. }
  196. // Reference is not load or store. If not an image-based reference, return.
  197. ref->image_id = GetImageId(ref_inst);
  198. if (ref->image_id == 0) return false;
  199. Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
  200. Instruction* desc_load_inst = nullptr;
  201. if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
  202. ref->desc_load_id =
  203. image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
  204. desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
  205. } else if (image_inst->opcode() == SpvOp::SpvOpImage) {
  206. ref->desc_load_id =
  207. image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
  208. desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
  209. } else {
  210. ref->desc_load_id = ref->image_id;
  211. desc_load_inst = image_inst;
  212. ref->image_id = 0;
  213. }
  214. if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
  215. // TODO(greg-lunarg): Handle additional possibilities?
  216. return false;
  217. }
  218. ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
  219. Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
  220. if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
  221. ref->index_id = 0;
  222. ref->var_id = ref->ptr_id;
  223. } else if (ptr_inst->opcode() == SpvOp::SpvOpAccessChain) {
  224. if (ptr_inst->NumInOperands() != 2) {
  225. assert(false && "unexpected bindless index number");
  226. return false;
  227. }
  228. ref->index_id =
  229. ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx);
  230. ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx);
  231. Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
  232. if (var_inst->opcode() != SpvOpVariable) {
  233. assert(false && "unexpected bindless base");
  234. return false;
  235. }
  236. } else {
  237. // TODO(greg-lunarg): Handle additional possibilities?
  238. return false;
  239. }
  240. return true;
  241. }
  242. void InstBindlessCheckPass::GenCheckCode(
  243. uint32_t check_id, uint32_t error_id, uint32_t length_id,
  244. uint32_t stage_idx, ref_analysis* ref,
  245. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  246. BasicBlock* back_blk_ptr = &*new_blocks->back();
  247. InstructionBuilder builder(
  248. context(), back_blk_ptr,
  249. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  250. // Gen conditional branch on check_id. Valid branch generates original
  251. // reference. Invalid generates debug output and zero result (if needed).
  252. uint32_t merge_blk_id = TakeNextId();
  253. uint32_t valid_blk_id = TakeNextId();
  254. uint32_t invalid_blk_id = TakeNextId();
  255. std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
  256. std::unique_ptr<Instruction> valid_label(NewLabel(valid_blk_id));
  257. std::unique_ptr<Instruction> invalid_label(NewLabel(invalid_blk_id));
  258. (void)builder.AddConditionalBranch(check_id, valid_blk_id, invalid_blk_id,
  259. merge_blk_id, SpvSelectionControlMaskNone);
  260. // Gen valid bounds branch
  261. std::unique_ptr<BasicBlock> new_blk_ptr(
  262. new BasicBlock(std::move(valid_label)));
  263. builder.SetInsertPoint(&*new_blk_ptr);
  264. uint32_t new_ref_id = CloneOriginalReference(ref, &builder);
  265. (void)builder.AddBranch(merge_blk_id);
  266. new_blocks->push_back(std::move(new_blk_ptr));
  267. // Gen invalid block
  268. new_blk_ptr.reset(new BasicBlock(std::move(invalid_label)));
  269. builder.SetInsertPoint(&*new_blk_ptr);
  270. uint32_t u_index_id = GenUintCastCode(ref->index_id, &builder);
  271. GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
  272. {error_id, u_index_id, length_id}, &builder);
  273. // Remember last invalid block id
  274. uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id();
  275. // Gen zero for invalid reference
  276. uint32_t ref_type_id = ref->ref_inst->type_id();
  277. (void)builder.AddBranch(merge_blk_id);
  278. new_blocks->push_back(std::move(new_blk_ptr));
  279. // Gen merge block
  280. new_blk_ptr.reset(new BasicBlock(std::move(merge_label)));
  281. builder.SetInsertPoint(&*new_blk_ptr);
  282. // Gen phi of new reference and zero, if necessary, and replace the
  283. // result id of the original reference with that of the Phi. Kill original
  284. // reference.
  285. if (new_ref_id != 0) {
  286. Instruction* phi_inst = builder.AddPhi(
  287. ref_type_id, {new_ref_id, valid_blk_id, GetNullId(ref_type_id),
  288. last_invalid_blk_id});
  289. context()->ReplaceAllUsesWith(ref->ref_inst->result_id(),
  290. phi_inst->result_id());
  291. }
  292. new_blocks->push_back(std::move(new_blk_ptr));
  293. context()->KillInst(ref->ref_inst);
  294. }
  295. void InstBindlessCheckPass::GenBoundsCheckCode(
  296. BasicBlock::iterator ref_inst_itr,
  297. UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
  298. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  299. // Look for reference through indexed descriptor. If found, analyze and
  300. // save components. If not, return.
  301. ref_analysis ref;
  302. if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
  303. Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
  304. if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return;
  305. // If index and bound both compile-time constants and index < bound,
  306. // return without changing
  307. Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id);
  308. Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst);
  309. uint32_t length_id = 0;
  310. if (desc_type_inst->opcode() == SpvOpTypeArray) {
  311. length_id =
  312. desc_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx);
  313. Instruction* index_inst = get_def_use_mgr()->GetDef(ref.index_id);
  314. Instruction* length_inst = get_def_use_mgr()->GetDef(length_id);
  315. if (index_inst->opcode() == SpvOpConstant &&
  316. length_inst->opcode() == SpvOpConstant &&
  317. index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) <
  318. length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx))
  319. return;
  320. } else if (!input_length_enabled_ ||
  321. desc_type_inst->opcode() != SpvOpTypeRuntimeArray) {
  322. return;
  323. }
  324. // Move original block's preceding instructions into first new block
  325. std::unique_ptr<BasicBlock> new_blk_ptr;
  326. MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
  327. InstructionBuilder builder(
  328. context(), &*new_blk_ptr,
  329. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  330. new_blocks->push_back(std::move(new_blk_ptr));
  331. uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBounds);
  332. // If length id not yet set, descriptor array is runtime size so
  333. // generate load of length from stage's debug input buffer.
  334. if (length_id == 0) {
  335. assert(desc_type_inst->opcode() == SpvOpTypeRuntimeArray &&
  336. "unexpected bindless type");
  337. length_id = GenDebugReadLength(ref.var_id, &builder);
  338. }
  339. // Generate full runtime bounds test code with true branch
  340. // being full reference and false branch being debug output and zero
  341. // for the referenced value.
  342. Instruction* ult_inst =
  343. builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref.index_id, length_id);
  344. GenCheckCode(ult_inst->result_id(), error_id, length_id, stage_idx, &ref,
  345. new_blocks);
  346. // Move original block's remaining code into remainder/merge block and add
  347. // to new blocks
  348. BasicBlock* back_blk_ptr = &*new_blocks->back();
  349. MovePostludeCode(ref_block_itr, back_blk_ptr);
  350. }
  351. void InstBindlessCheckPass::GenInitCheckCode(
  352. BasicBlock::iterator ref_inst_itr,
  353. UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
  354. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  355. // Look for reference through descriptor. If not, return.
  356. ref_analysis ref;
  357. if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
  358. // Move original block's preceding instructions into first new block
  359. std::unique_ptr<BasicBlock> new_blk_ptr;
  360. MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
  361. InstructionBuilder builder(
  362. context(), &*new_blk_ptr,
  363. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  364. new_blocks->push_back(std::move(new_blk_ptr));
  365. // Read initialization status from debug input buffer. If index id not yet
  366. // set, binding is single descriptor, so set index to constant 0.
  367. uint32_t zero_id = builder.GetUintConstantId(0u);
  368. if (ref.index_id == 0) ref.index_id = zero_id;
  369. uint32_t init_id = GenDebugReadInit(ref.var_id, ref.index_id, &builder);
  370. // Generate full runtime non-zero init test code with true branch
  371. // being full reference and false branch being debug output and zero
  372. // for the referenced value.
  373. Instruction* uneq_inst =
  374. builder.AddBinaryOp(GetBoolId(), SpvOpINotEqual, init_id, zero_id);
  375. uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessUninit);
  376. GenCheckCode(uneq_inst->result_id(), error_id, zero_id, stage_idx, &ref,
  377. new_blocks);
  378. // Move original block's remaining code into remainder/merge block and add
  379. // to new blocks
  380. BasicBlock* back_blk_ptr = &*new_blocks->back();
  381. MovePostludeCode(ref_block_itr, back_blk_ptr);
  382. }
  383. void InstBindlessCheckPass::InitializeInstBindlessCheck() {
  384. // Initialize base class
  385. InitializeInstrument();
  386. // If runtime array length support enabled, create variable mappings. Length
  387. // support is always enabled if descriptor init check is enabled.
  388. if (input_length_enabled_)
  389. for (auto& anno : get_module()->annotations())
  390. if (anno.opcode() == SpvOpDecorate) {
  391. if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
  392. var2desc_set_[anno.GetSingleWordInOperand(0u)] =
  393. anno.GetSingleWordInOperand(2u);
  394. else if (anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)
  395. var2binding_[anno.GetSingleWordInOperand(0u)] =
  396. anno.GetSingleWordInOperand(2u);
  397. }
  398. }
  399. Pass::Status InstBindlessCheckPass::ProcessImpl() {
  400. // Perform bindless bounds check on each entry point function in module
  401. InstProcessFunction pfn =
  402. [this](BasicBlock::iterator ref_inst_itr,
  403. UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
  404. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  405. return GenBoundsCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
  406. new_blocks);
  407. };
  408. bool modified = InstProcessEntryPointCallTree(pfn);
  409. if (input_init_enabled_) {
  410. // Perform descriptor initialization check on each entry point function in
  411. // module
  412. pfn = [this](BasicBlock::iterator ref_inst_itr,
  413. UptrVectorIterator<BasicBlock> ref_block_itr,
  414. uint32_t stage_idx,
  415. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  416. return GenInitCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
  417. new_blocks);
  418. };
  419. modified |= InstProcessEntryPointCallTree(pfn);
  420. }
  421. return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
  422. }
  423. Pass::Status InstBindlessCheckPass::Process() {
  424. InitializeInstBindlessCheck();
  425. return ProcessImpl();
  426. }
  427. } // namespace opt
  428. } // namespace spvtools