instrument_pass.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  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 "instrument_pass.h"
  17. #include "source/cfa.h"
  18. #include "source/spirv_constant.h"
  19. namespace {
  20. // Common Parameter Positions
  21. static const int kInstCommonParamInstIdx = 0;
  22. static const int kInstCommonParamCnt = 1;
  23. // Indices of operands in SPIR-V instructions
  24. static const int kEntryPointExecutionModelInIdx = 0;
  25. static const int kEntryPointFunctionIdInIdx = 1;
  26. } // anonymous namespace
  27. namespace spvtools {
  28. namespace opt {
  29. void InstrumentPass::MovePreludeCode(
  30. BasicBlock::iterator ref_inst_itr,
  31. UptrVectorIterator<BasicBlock> ref_block_itr,
  32. std::unique_ptr<BasicBlock>* new_blk_ptr) {
  33. same_block_pre_.clear();
  34. same_block_post_.clear();
  35. // Initialize new block. Reuse label from original block.
  36. new_blk_ptr->reset(new BasicBlock(std::move(ref_block_itr->GetLabel())));
  37. // Move contents of original ref block up to ref instruction.
  38. for (auto cii = ref_block_itr->begin(); cii != ref_inst_itr;
  39. cii = ref_block_itr->begin()) {
  40. Instruction* inst = &*cii;
  41. inst->RemoveFromList();
  42. std::unique_ptr<Instruction> mv_ptr(inst);
  43. // Remember same-block ops for possible regeneration.
  44. if (IsSameBlockOp(&*mv_ptr)) {
  45. auto* sb_inst_ptr = mv_ptr.get();
  46. same_block_pre_[mv_ptr->result_id()] = sb_inst_ptr;
  47. }
  48. (*new_blk_ptr)->AddInstruction(std::move(mv_ptr));
  49. }
  50. }
  51. void InstrumentPass::MovePostludeCode(
  52. UptrVectorIterator<BasicBlock> ref_block_itr, BasicBlock* new_blk_ptr) {
  53. // new_blk_ptr->reset(new BasicBlock(NewLabel(ref_block_itr->id())));
  54. // Move contents of original ref block.
  55. for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end();
  56. cii = ref_block_itr->begin()) {
  57. Instruction* inst = &*cii;
  58. inst->RemoveFromList();
  59. std::unique_ptr<Instruction> mv_inst(inst);
  60. // Regenerate any same-block instruction that has not been seen in the
  61. // current block.
  62. if (same_block_pre_.size() > 0) {
  63. CloneSameBlockOps(&mv_inst, &same_block_post_, &same_block_pre_,
  64. new_blk_ptr);
  65. // Remember same-block ops in this block.
  66. if (IsSameBlockOp(&*mv_inst)) {
  67. const uint32_t rid = mv_inst->result_id();
  68. same_block_post_[rid] = rid;
  69. }
  70. }
  71. new_blk_ptr->AddInstruction(std::move(mv_inst));
  72. }
  73. }
  74. std::unique_ptr<Instruction> InstrumentPass::NewLabel(uint32_t label_id) {
  75. std::unique_ptr<Instruction> newLabel(
  76. new Instruction(context(), SpvOpLabel, 0, label_id, {}));
  77. get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel);
  78. return newLabel;
  79. }
  80. uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id,
  81. InstructionBuilder* builder) {
  82. // Cast value to 32-bit unsigned if necessary
  83. if (get_def_use_mgr()->GetDef(val_id)->type_id() == GetUintId())
  84. return val_id;
  85. return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_id)->result_id();
  86. }
  87. void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
  88. uint32_t field_offset,
  89. uint32_t field_value_id,
  90. InstructionBuilder* builder) {
  91. // Cast value to 32-bit unsigned if necessary
  92. uint32_t val_id = GenUintCastCode(field_value_id, builder);
  93. // Store value
  94. Instruction* data_idx_inst =
  95. builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id,
  96. builder->GetUintConstantId(field_offset));
  97. uint32_t buf_id = GetOutputBufferId();
  98. uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  99. Instruction* achain_inst =
  100. builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  101. builder->GetUintConstantId(kDebugOutputDataOffset),
  102. data_idx_inst->result_id());
  103. (void)builder->AddBinaryOp(0, SpvOpStore, achain_inst->result_id(), val_id);
  104. }
  105. void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz,
  106. uint32_t inst_id,
  107. uint32_t stage_idx,
  108. uint32_t base_offset_id,
  109. InstructionBuilder* builder) {
  110. // Store record size
  111. GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize,
  112. builder->GetUintConstantId(record_sz), builder);
  113. // Store Shader Id
  114. GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId,
  115. builder->GetUintConstantId(shader_id_), builder);
  116. // Store Instruction Idx
  117. GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id,
  118. builder);
  119. // Store Stage Idx
  120. GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx,
  121. builder->GetUintConstantId(stage_idx), builder);
  122. }
  123. void InstrumentPass::GenFragCoordEltDebugOutputCode(
  124. uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element,
  125. InstructionBuilder* builder) {
  126. Instruction* element_val_inst = builder->AddIdLiteralOp(
  127. GetUintId(), SpvOpCompositeExtract, uint_frag_coord_id, element);
  128. GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element,
  129. element_val_inst->result_id(), builder);
  130. }
  131. uint32_t InstrumentPass::GenVarLoad(uint32_t var_id,
  132. InstructionBuilder* builder) {
  133. Instruction* var_inst = get_def_use_mgr()->GetDef(var_id);
  134. uint32_t type_id = GetPointeeTypeId(var_inst);
  135. Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id);
  136. return load_inst->result_id();
  137. }
  138. void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id,
  139. uint32_t builtin_off,
  140. uint32_t base_offset_id,
  141. InstructionBuilder* builder) {
  142. // Load and store builtin
  143. uint32_t load_id = GenVarLoad(builtin_id, builder);
  144. GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder);
  145. }
  146. void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
  147. uint32_t base_offset_id,
  148. InstructionBuilder* builder) {
  149. // TODO(greg-lunarg): Add support for all stages
  150. switch (stage_idx) {
  151. case SpvExecutionModelVertex: {
  152. // Load and store VertexId and InstanceId
  153. GenBuiltinOutputCode(
  154. context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex),
  155. kInstVertOutVertexIndex, base_offset_id, builder);
  156. GenBuiltinOutputCode(
  157. context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex),
  158. kInstVertOutInstanceIndex, base_offset_id, builder);
  159. } break;
  160. case SpvExecutionModelGLCompute: {
  161. // Load and store GlobalInvocationId.
  162. uint32_t load_id = GenVarLoad(
  163. context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId),
  164. builder);
  165. Instruction* x_inst = builder->AddIdLiteralOp(
  166. GetUintId(), SpvOpCompositeExtract, load_id, 0);
  167. Instruction* y_inst = builder->AddIdLiteralOp(
  168. GetUintId(), SpvOpCompositeExtract, load_id, 1);
  169. Instruction* z_inst = builder->AddIdLiteralOp(
  170. GetUintId(), SpvOpCompositeExtract, load_id, 2);
  171. GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX,
  172. x_inst->result_id(), builder);
  173. GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY,
  174. y_inst->result_id(), builder);
  175. GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ,
  176. z_inst->result_id(), builder);
  177. } break;
  178. case SpvExecutionModelGeometry: {
  179. // Load and store PrimitiveId and InvocationId.
  180. GenBuiltinOutputCode(
  181. context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
  182. kInstGeomOutPrimitiveId, base_offset_id, builder);
  183. GenBuiltinOutputCode(
  184. context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
  185. kInstGeomOutInvocationId, base_offset_id, builder);
  186. } break;
  187. case SpvExecutionModelTessellationControl: {
  188. // Load and store InvocationId and PrimitiveId
  189. GenBuiltinOutputCode(
  190. context()->GetBuiltinInputVarId(SpvBuiltInInvocationId),
  191. kInstTessCtlOutInvocationId, base_offset_id, builder);
  192. GenBuiltinOutputCode(
  193. context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
  194. kInstTessCtlOutPrimitiveId, base_offset_id, builder);
  195. } break;
  196. case SpvExecutionModelTessellationEvaluation: {
  197. // Load and store PrimitiveId and TessCoord.uv
  198. GenBuiltinOutputCode(
  199. context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId),
  200. kInstTessEvalOutPrimitiveId, base_offset_id, builder);
  201. uint32_t load_id = GenVarLoad(
  202. context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder);
  203. Instruction* uvec3_cast_inst =
  204. builder->AddUnaryOp(GetVec3UintId(), SpvOpBitcast, load_id);
  205. uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
  206. Instruction* u_inst = builder->AddIdLiteralOp(
  207. GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 0);
  208. Instruction* v_inst = builder->AddIdLiteralOp(
  209. GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 1);
  210. GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU,
  211. u_inst->result_id(), builder);
  212. GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV,
  213. v_inst->result_id(), builder);
  214. } break;
  215. case SpvExecutionModelFragment: {
  216. // Load FragCoord and convert to Uint
  217. Instruction* frag_coord_inst = builder->AddUnaryOp(
  218. GetVec4FloatId(), SpvOpLoad,
  219. context()->GetBuiltinInputVarId(SpvBuiltInFragCoord));
  220. Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
  221. GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
  222. for (uint32_t u = 0; u < 2u; ++u)
  223. GenFragCoordEltDebugOutputCode(
  224. base_offset_id, uint_frag_coord_inst->result_id(), u, builder);
  225. } break;
  226. case SpvExecutionModelRayGenerationNV:
  227. case SpvExecutionModelIntersectionNV:
  228. case SpvExecutionModelAnyHitNV:
  229. case SpvExecutionModelClosestHitNV:
  230. case SpvExecutionModelMissNV:
  231. case SpvExecutionModelCallableNV: {
  232. // Load and store LaunchIdNV.
  233. uint32_t launch_id = GenVarLoad(
  234. context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder);
  235. Instruction* x_launch_inst = builder->AddIdLiteralOp(
  236. GetUintId(), SpvOpCompositeExtract, launch_id, 0);
  237. Instruction* y_launch_inst = builder->AddIdLiteralOp(
  238. GetUintId(), SpvOpCompositeExtract, launch_id, 1);
  239. Instruction* z_launch_inst = builder->AddIdLiteralOp(
  240. GetUintId(), SpvOpCompositeExtract, launch_id, 2);
  241. GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX,
  242. x_launch_inst->result_id(), builder);
  243. GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY,
  244. y_launch_inst->result_id(), builder);
  245. GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
  246. z_launch_inst->result_id(), builder);
  247. } break;
  248. default: { assert(false && "unsupported stage"); } break;
  249. }
  250. }
  251. void InstrumentPass::GenDebugStreamWrite(
  252. uint32_t instruction_idx, uint32_t stage_idx,
  253. const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
  254. // Call debug output function. Pass func_idx, instruction_idx and
  255. // validation ids as args.
  256. uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
  257. uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt);
  258. std::vector<uint32_t> args = {output_func_id,
  259. builder->GetUintConstantId(instruction_idx)};
  260. (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
  261. (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args);
  262. }
  263. uint32_t InstrumentPass::GenDebugDirectRead(
  264. const std::vector<uint32_t>& offset_ids, InstructionBuilder* builder) {
  265. // Call debug input function. Pass func_idx and offset ids as args.
  266. uint32_t off_id_cnt = static_cast<uint32_t>(offset_ids.size());
  267. uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt);
  268. std::vector<uint32_t> args = {input_func_id};
  269. (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end());
  270. return builder->AddNaryOp(GetUintId(), SpvOpFunctionCall, args)->result_id();
  271. }
  272. bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const {
  273. return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
  274. }
  275. void InstrumentPass::CloneSameBlockOps(
  276. std::unique_ptr<Instruction>* inst,
  277. std::unordered_map<uint32_t, uint32_t>* same_blk_post,
  278. std::unordered_map<uint32_t, Instruction*>* same_blk_pre,
  279. BasicBlock* block_ptr) {
  280. bool changed = false;
  281. (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed,
  282. this](uint32_t* iid) {
  283. const auto map_itr = (*same_blk_post).find(*iid);
  284. if (map_itr == (*same_blk_post).end()) {
  285. const auto map_itr2 = (*same_blk_pre).find(*iid);
  286. if (map_itr2 != (*same_blk_pre).end()) {
  287. // Clone pre-call same-block ops, map result id.
  288. const Instruction* in_inst = map_itr2->second;
  289. std::unique_ptr<Instruction> sb_inst(in_inst->Clone(context()));
  290. const uint32_t rid = sb_inst->result_id();
  291. const uint32_t nid = this->TakeNextId();
  292. get_decoration_mgr()->CloneDecorations(rid, nid);
  293. sb_inst->SetResultId(nid);
  294. get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst);
  295. (*same_blk_post)[rid] = nid;
  296. *iid = nid;
  297. changed = true;
  298. CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr);
  299. block_ptr->AddInstruction(std::move(sb_inst));
  300. }
  301. } else {
  302. // Reset same-block op operand if necessary
  303. if (*iid != map_itr->second) {
  304. *iid = map_itr->second;
  305. changed = true;
  306. }
  307. }
  308. });
  309. if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst);
  310. }
  311. void InstrumentPass::UpdateSucceedingPhis(
  312. std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
  313. const auto first_blk = new_blocks.begin();
  314. const auto last_blk = new_blocks.end() - 1;
  315. const uint32_t first_id = (*first_blk)->id();
  316. const uint32_t last_id = (*last_blk)->id();
  317. const BasicBlock& const_last_block = *last_blk->get();
  318. const_last_block.ForEachSuccessorLabel(
  319. [&first_id, &last_id, this](const uint32_t succ) {
  320. BasicBlock* sbp = this->id2block_[succ];
  321. sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) {
  322. bool changed = false;
  323. phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) {
  324. if (*id == first_id) {
  325. *id = last_id;
  326. changed = true;
  327. }
  328. });
  329. if (changed) get_def_use_mgr()->AnalyzeInstUse(phi);
  330. });
  331. });
  332. }
  333. uint32_t InstrumentPass::GetOutputBufferPtrId() {
  334. if (output_buffer_ptr_id_ == 0) {
  335. output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
  336. GetUintId(), SpvStorageClassStorageBuffer);
  337. }
  338. return output_buffer_ptr_id_;
  339. }
  340. uint32_t InstrumentPass::GetInputBufferTypeId() {
  341. return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id()
  342. : GetUintId();
  343. }
  344. uint32_t InstrumentPass::GetInputBufferPtrId() {
  345. if (input_buffer_ptr_id_ == 0) {
  346. input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
  347. GetInputBufferTypeId(), SpvStorageClassStorageBuffer);
  348. }
  349. return input_buffer_ptr_id_;
  350. }
  351. uint32_t InstrumentPass::GetOutputBufferBinding() {
  352. switch (validation_id_) {
  353. case kInstValidationIdBindless:
  354. return kDebugOutputBindingStream;
  355. case kInstValidationIdBuffAddr:
  356. return kDebugOutputBindingStream;
  357. case kInstValidationIdDebugPrintf:
  358. return kDebugOutputPrintfStream;
  359. default:
  360. assert(false && "unexpected validation id");
  361. }
  362. return 0;
  363. }
  364. uint32_t InstrumentPass::GetInputBufferBinding() {
  365. switch (validation_id_) {
  366. case kInstValidationIdBindless:
  367. return kDebugInputBindingBindless;
  368. case kInstValidationIdBuffAddr:
  369. return kDebugInputBindingBuffAddr;
  370. default:
  371. assert(false && "unexpected validation id");
  372. }
  373. return 0;
  374. }
  375. analysis::Type* InstrumentPass::GetUintXRuntimeArrayType(
  376. uint32_t width, analysis::Type** rarr_ty) {
  377. if (*rarr_ty == nullptr) {
  378. analysis::DecorationManager* deco_mgr = get_decoration_mgr();
  379. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  380. analysis::Integer uint_ty(width, false);
  381. analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
  382. analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty);
  383. *rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp);
  384. uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(*rarr_ty);
  385. // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of
  386. // a block, and will therefore be decorated with an ArrayStride. Therefore
  387. // the undecorated type returned here will not be pre-existing and can
  388. // safely be decorated. Since this type is now decorated, it is out of
  389. // sync with the TypeManager and therefore the TypeManager must be
  390. // invalidated after this pass.
  391. assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 &&
  392. "used RuntimeArray type returned");
  393. deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride,
  394. width / 8u);
  395. }
  396. return *rarr_ty;
  397. }
  398. analysis::Type* InstrumentPass::GetUintRuntimeArrayType(uint32_t width) {
  399. analysis::Type** rarr_ty =
  400. (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_;
  401. return GetUintXRuntimeArrayType(width, rarr_ty);
  402. }
  403. void InstrumentPass::AddStorageBufferExt() {
  404. if (storage_buffer_ext_defined_) return;
  405. if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) {
  406. context()->AddExtension("SPV_KHR_storage_buffer_storage_class");
  407. }
  408. storage_buffer_ext_defined_ = true;
  409. }
  410. // Return id for output buffer
  411. uint32_t InstrumentPass::GetOutputBufferId() {
  412. if (output_buffer_id_ == 0) {
  413. // If not created yet, create one
  414. analysis::DecorationManager* deco_mgr = get_decoration_mgr();
  415. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  416. analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
  417. analysis::Integer uint_ty(32, false);
  418. analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
  419. analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty});
  420. analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
  421. uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
  422. // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
  423. // must be a block, and will therefore be decorated with Block. Therefore
  424. // the undecorated type returned here will not be pre-existing and can
  425. // safely be decorated. Since this type is now decorated, it is out of
  426. // sync with the TypeManager and therefore the TypeManager must be
  427. // invalidated after this pass.
  428. assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
  429. "used struct type returned");
  430. deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock);
  431. deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
  432. SpvDecorationOffset, 0);
  433. deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
  434. SpvDecorationOffset, 4);
  435. uint32_t obufTyPtrId_ =
  436. type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer);
  437. output_buffer_id_ = TakeNextId();
  438. std::unique_ptr<Instruction> newVarOp(new Instruction(
  439. context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_,
  440. {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  441. {SpvStorageClassStorageBuffer}}}));
  442. context()->AddGlobalValue(std::move(newVarOp));
  443. deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet,
  444. desc_set_);
  445. deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding,
  446. GetOutputBufferBinding());
  447. AddStorageBufferExt();
  448. if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  449. // Add the new buffer to all entry points.
  450. for (auto& entry : get_module()->entry_points()) {
  451. entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
  452. context()->AnalyzeUses(&entry);
  453. }
  454. }
  455. }
  456. return output_buffer_id_;
  457. }
  458. uint32_t InstrumentPass::GetInputBufferId() {
  459. if (input_buffer_id_ == 0) {
  460. // If not created yet, create one
  461. analysis::DecorationManager* deco_mgr = get_decoration_mgr();
  462. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  463. uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u;
  464. analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width);
  465. analysis::Struct buf_ty({reg_uint_rarr_ty});
  466. analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
  467. uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
  468. // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
  469. // must be a block, and will therefore be decorated with Block. Therefore
  470. // the undecorated type returned here will not be pre-existing and can
  471. // safely be decorated. Since this type is now decorated, it is out of
  472. // sync with the TypeManager and therefore the TypeManager must be
  473. // invalidated after this pass.
  474. assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 &&
  475. "used struct type returned");
  476. deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock);
  477. deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0);
  478. uint32_t ibufTyPtrId_ =
  479. type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer);
  480. input_buffer_id_ = TakeNextId();
  481. std::unique_ptr<Instruction> newVarOp(new Instruction(
  482. context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_,
  483. {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  484. {SpvStorageClassStorageBuffer}}}));
  485. context()->AddGlobalValue(std::move(newVarOp));
  486. deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet,
  487. desc_set_);
  488. deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding,
  489. GetInputBufferBinding());
  490. AddStorageBufferExt();
  491. if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  492. // Add the new buffer to all entry points.
  493. for (auto& entry : get_module()->entry_points()) {
  494. entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
  495. context()->AnalyzeUses(&entry);
  496. }
  497. }
  498. }
  499. return input_buffer_id_;
  500. }
  501. uint32_t InstrumentPass::GetFloatId() {
  502. if (float_id_ == 0) {
  503. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  504. analysis::Float float_ty(32);
  505. analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
  506. float_id_ = type_mgr->GetTypeInstruction(reg_float_ty);
  507. }
  508. return float_id_;
  509. }
  510. uint32_t InstrumentPass::GetVec4FloatId() {
  511. if (v4float_id_ == 0) {
  512. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  513. analysis::Float float_ty(32);
  514. analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
  515. analysis::Vector v4float_ty(reg_float_ty, 4);
  516. analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty);
  517. v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty);
  518. }
  519. return v4float_id_;
  520. }
  521. uint32_t InstrumentPass::GetUintId() {
  522. if (uint_id_ == 0) {
  523. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  524. analysis::Integer uint_ty(32, false);
  525. analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
  526. uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty);
  527. }
  528. return uint_id_;
  529. }
  530. uint32_t InstrumentPass::GetUint64Id() {
  531. if (uint64_id_ == 0) {
  532. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  533. analysis::Integer uint64_ty(64, false);
  534. analysis::Type* reg_uint64_ty = type_mgr->GetRegisteredType(&uint64_ty);
  535. uint64_id_ = type_mgr->GetTypeInstruction(reg_uint64_ty);
  536. }
  537. return uint64_id_;
  538. }
  539. uint32_t InstrumentPass::GetUint8Id() {
  540. if (uint8_id_ == 0) {
  541. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  542. analysis::Integer uint8_ty(8, false);
  543. analysis::Type* reg_uint8_ty = type_mgr->GetRegisteredType(&uint8_ty);
  544. uint8_id_ = type_mgr->GetTypeInstruction(reg_uint8_ty);
  545. }
  546. return uint8_id_;
  547. }
  548. uint32_t InstrumentPass::GetVecUintId(uint32_t len) {
  549. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  550. analysis::Integer uint_ty(32, false);
  551. analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
  552. analysis::Vector v_uint_ty(reg_uint_ty, len);
  553. analysis::Type* reg_v_uint_ty = type_mgr->GetRegisteredType(&v_uint_ty);
  554. uint32_t v_uint_id = type_mgr->GetTypeInstruction(reg_v_uint_ty);
  555. return v_uint_id;
  556. }
  557. uint32_t InstrumentPass::GetVec4UintId() {
  558. if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u);
  559. return v4uint_id_;
  560. }
  561. uint32_t InstrumentPass::GetVec3UintId() {
  562. if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u);
  563. return v3uint_id_;
  564. }
  565. uint32_t InstrumentPass::GetBoolId() {
  566. if (bool_id_ == 0) {
  567. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  568. analysis::Bool bool_ty;
  569. analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty);
  570. bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty);
  571. }
  572. return bool_id_;
  573. }
  574. uint32_t InstrumentPass::GetVoidId() {
  575. if (void_id_ == 0) {
  576. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  577. analysis::Void void_ty;
  578. analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty);
  579. void_id_ = type_mgr->GetTypeInstruction(reg_void_ty);
  580. }
  581. return void_id_;
  582. }
  583. uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx,
  584. uint32_t val_spec_param_cnt) {
  585. // Total param count is common params plus validation-specific
  586. // params
  587. uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt;
  588. if (param2output_func_id_[param_cnt] == 0) {
  589. // Create function
  590. param2output_func_id_[param_cnt] = TakeNextId();
  591. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  592. std::vector<const analysis::Type*> param_types;
  593. for (uint32_t c = 0; c < param_cnt; ++c)
  594. param_types.push_back(type_mgr->GetType(GetUintId()));
  595. analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
  596. analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  597. std::unique_ptr<Instruction> func_inst(
  598. new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
  599. param2output_func_id_[param_cnt],
  600. {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  601. {SpvFunctionControlMaskNone}},
  602. {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  603. {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  604. get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  605. std::unique_ptr<Function> output_func =
  606. MakeUnique<Function>(std::move(func_inst));
  607. // Add parameters
  608. std::vector<uint32_t> param_vec;
  609. for (uint32_t c = 0; c < param_cnt; ++c) {
  610. uint32_t pid = TakeNextId();
  611. param_vec.push_back(pid);
  612. std::unique_ptr<Instruction> param_inst(
  613. new Instruction(get_module()->context(), SpvOpFunctionParameter,
  614. GetUintId(), pid, {}));
  615. get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
  616. output_func->AddParameter(std::move(param_inst));
  617. }
  618. // Create first block
  619. uint32_t test_blk_id = TakeNextId();
  620. std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
  621. std::unique_ptr<BasicBlock> new_blk_ptr =
  622. MakeUnique<BasicBlock>(std::move(test_label));
  623. InstructionBuilder builder(
  624. context(), &*new_blk_ptr,
  625. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  626. // Gen test if debug output buffer size will not be exceeded.
  627. uint32_t val_spec_offset = kInstStageOutCnt;
  628. uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt;
  629. uint32_t buf_id = GetOutputBufferId();
  630. uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  631. Instruction* obuf_curr_sz_ac_inst =
  632. builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  633. builder.GetUintConstantId(kDebugOutputSizeOffset));
  634. // Fetch the current debug buffer written size atomically, adding the
  635. // size of the record to be written.
  636. uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
  637. uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone);
  638. uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation);
  639. Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
  640. GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
  641. scope_invok_id, mask_none_id, obuf_record_sz_id);
  642. uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
  643. // Compute new written size
  644. Instruction* obuf_new_sz_inst =
  645. builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id,
  646. builder.GetUintConstantId(obuf_record_sz));
  647. // Fetch the data bound
  648. Instruction* obuf_bnd_inst =
  649. builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
  650. GetOutputBufferId(), kDebugOutputDataOffset);
  651. // Test that new written size is less than or equal to debug output
  652. // data bound
  653. Instruction* obuf_safe_inst = builder.AddBinaryOp(
  654. GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(),
  655. obuf_bnd_inst->result_id());
  656. uint32_t merge_blk_id = TakeNextId();
  657. uint32_t write_blk_id = TakeNextId();
  658. std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
  659. std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
  660. (void)builder.AddConditionalBranch(obuf_safe_inst->result_id(),
  661. write_blk_id, merge_blk_id, merge_blk_id,
  662. SpvSelectionControlMaskNone);
  663. // Close safety test block and gen write block
  664. new_blk_ptr->SetParent(&*output_func);
  665. output_func->AddBasicBlock(std::move(new_blk_ptr));
  666. new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
  667. builder.SetInsertPoint(&*new_blk_ptr);
  668. // Generate common and stage-specific debug record members
  669. GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx],
  670. stage_idx, obuf_curr_sz_id, &builder);
  671. GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder);
  672. // Gen writes of validation specific data
  673. for (uint32_t i = 0; i < val_spec_param_cnt; ++i) {
  674. GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
  675. param_vec[kInstCommonParamCnt + i], &builder);
  676. }
  677. // Close write block and gen merge block
  678. (void)builder.AddBranch(merge_blk_id);
  679. new_blk_ptr->SetParent(&*output_func);
  680. output_func->AddBasicBlock(std::move(new_blk_ptr));
  681. new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
  682. builder.SetInsertPoint(&*new_blk_ptr);
  683. // Close merge block and function and add function to module
  684. (void)builder.AddNullaryOp(0, SpvOpReturn);
  685. new_blk_ptr->SetParent(&*output_func);
  686. output_func->AddBasicBlock(std::move(new_blk_ptr));
  687. std::unique_ptr<Instruction> func_end_inst(
  688. new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  689. get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  690. output_func->SetFunctionEnd(std::move(func_end_inst));
  691. context()->AddFunction(std::move(output_func));
  692. }
  693. return param2output_func_id_[param_cnt];
  694. }
  695. uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) {
  696. uint32_t func_id = param2input_func_id_[param_cnt];
  697. if (func_id != 0) return func_id;
  698. // Create input function for param_cnt.
  699. func_id = TakeNextId();
  700. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  701. std::vector<const analysis::Type*> param_types;
  702. for (uint32_t c = 0; c < param_cnt; ++c)
  703. param_types.push_back(type_mgr->GetType(GetUintId()));
  704. uint32_t ibuf_type_id = GetInputBufferTypeId();
  705. analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), param_types);
  706. analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  707. std::unique_ptr<Instruction> func_inst(new Instruction(
  708. get_module()->context(), SpvOpFunction, ibuf_type_id, func_id,
  709. {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  710. {SpvFunctionControlMaskNone}},
  711. {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  712. {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  713. get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  714. std::unique_ptr<Function> input_func =
  715. MakeUnique<Function>(std::move(func_inst));
  716. // Add parameters
  717. std::vector<uint32_t> param_vec;
  718. for (uint32_t c = 0; c < param_cnt; ++c) {
  719. uint32_t pid = TakeNextId();
  720. param_vec.push_back(pid);
  721. std::unique_ptr<Instruction> param_inst(new Instruction(
  722. get_module()->context(), SpvOpFunctionParameter, GetUintId(), pid, {}));
  723. get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
  724. input_func->AddParameter(std::move(param_inst));
  725. }
  726. // Create block
  727. uint32_t blk_id = TakeNextId();
  728. std::unique_ptr<Instruction> blk_label(NewLabel(blk_id));
  729. std::unique_ptr<BasicBlock> new_blk_ptr =
  730. MakeUnique<BasicBlock>(std::move(blk_label));
  731. InstructionBuilder builder(
  732. context(), &*new_blk_ptr,
  733. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  734. // For each offset parameter, generate new offset with parameter, adding last
  735. // loaded value if it exists, and load value from input buffer at new offset.
  736. // Return last loaded value.
  737. uint32_t buf_id = GetInputBufferId();
  738. uint32_t buf_ptr_id = GetInputBufferPtrId();
  739. uint32_t last_value_id = 0;
  740. for (uint32_t p = 0; p < param_cnt; ++p) {
  741. uint32_t offset_id;
  742. if (p == 0) {
  743. offset_id = param_vec[0];
  744. } else {
  745. if (ibuf_type_id != GetUintId()) {
  746. Instruction* ucvt_inst =
  747. builder.AddUnaryOp(GetUintId(), SpvOpUConvert, last_value_id);
  748. last_value_id = ucvt_inst->result_id();
  749. }
  750. Instruction* offset_inst = builder.AddBinaryOp(
  751. GetUintId(), SpvOpIAdd, last_value_id, param_vec[p]);
  752. offset_id = offset_inst->result_id();
  753. }
  754. Instruction* ac_inst = builder.AddTernaryOp(
  755. buf_ptr_id, SpvOpAccessChain, buf_id,
  756. builder.GetUintConstantId(kDebugInputDataOffset), offset_id);
  757. Instruction* load_inst =
  758. builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, ac_inst->result_id());
  759. last_value_id = load_inst->result_id();
  760. }
  761. (void)builder.AddInstruction(MakeUnique<Instruction>(
  762. context(), SpvOpReturnValue, 0, 0,
  763. std::initializer_list<Operand>{{SPV_OPERAND_TYPE_ID, {last_value_id}}}));
  764. // Close block and function and add function to module
  765. new_blk_ptr->SetParent(&*input_func);
  766. input_func->AddBasicBlock(std::move(new_blk_ptr));
  767. std::unique_ptr<Instruction> func_end_inst(
  768. new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  769. get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  770. input_func->SetFunctionEnd(std::move(func_end_inst));
  771. context()->AddFunction(std::move(input_func));
  772. param2input_func_id_[param_cnt] = func_id;
  773. return func_id;
  774. }
  775. bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx,
  776. InstProcessFunction& pfn) {
  777. bool modified = false;
  778. // Compute function index
  779. uint32_t function_idx = 0;
  780. for (auto fii = get_module()->begin(); fii != get_module()->end(); ++fii) {
  781. if (&*fii == func) break;
  782. ++function_idx;
  783. }
  784. std::vector<std::unique_ptr<BasicBlock>> new_blks;
  785. // Using block iterators here because of block erasures and insertions.
  786. for (auto bi = func->begin(); bi != func->end(); ++bi) {
  787. for (auto ii = bi->begin(); ii != bi->end();) {
  788. // Generate instrumentation if warranted
  789. pfn(ii, bi, stage_idx, &new_blks);
  790. if (new_blks.size() == 0) {
  791. ++ii;
  792. continue;
  793. }
  794. // Add new blocks to label id map
  795. for (auto& blk : new_blks) id2block_[blk->id()] = &*blk;
  796. // If there are new blocks we know there will always be two or
  797. // more, so update succeeding phis with label of new last block.
  798. size_t newBlocksSize = new_blks.size();
  799. assert(newBlocksSize > 1);
  800. UpdateSucceedingPhis(new_blks);
  801. // Replace original block with new block(s)
  802. bi = bi.Erase();
  803. for (auto& bb : new_blks) {
  804. bb->SetParent(func);
  805. }
  806. bi = bi.InsertBefore(&new_blks);
  807. // Reset block iterator to last new block
  808. for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi;
  809. modified = true;
  810. // Restart instrumenting at beginning of last new block,
  811. // but skip over any new phi or copy instruction.
  812. ii = bi->begin();
  813. if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii;
  814. new_blks.clear();
  815. }
  816. }
  817. return modified;
  818. }
  819. bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn,
  820. std::queue<uint32_t>* roots,
  821. uint32_t stage_idx) {
  822. bool modified = false;
  823. std::unordered_set<uint32_t> done;
  824. // Don't process input and output functions
  825. for (auto& ifn : param2input_func_id_) done.insert(ifn.second);
  826. for (auto& ofn : param2output_func_id_) done.insert(ofn.second);
  827. // Process all functions from roots
  828. while (!roots->empty()) {
  829. const uint32_t fi = roots->front();
  830. roots->pop();
  831. if (done.insert(fi).second) {
  832. Function* fn = id2function_.at(fi);
  833. // Add calls first so we don't add new output function
  834. context()->AddCalls(fn, roots);
  835. modified = InstrumentFunction(fn, stage_idx, pfn) || modified;
  836. }
  837. }
  838. return modified;
  839. }
  840. bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) {
  841. // Check that format version 2 requested
  842. if (version_ != 2u) {
  843. if (consumer()) {
  844. std::string message = "Unsupported instrumentation format requested";
  845. consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  846. }
  847. return false;
  848. }
  849. // Make sure all entry points have the same execution model. Do not
  850. // instrument if they do not.
  851. // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module
  852. // can contain entry points with different execution models, although
  853. // such modules will likely be rare as GLSL and HLSL are geared toward
  854. // one model per module. In such cases we will need
  855. // to clone any functions which are in the call trees of entrypoints
  856. // with differing execution models.
  857. uint32_t ecnt = 0;
  858. uint32_t stage = SpvExecutionModelMax;
  859. for (auto& e : get_module()->entry_points()) {
  860. if (ecnt == 0)
  861. stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
  862. else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) !=
  863. stage) {
  864. if (consumer()) {
  865. std::string message = "Mixed stage shader module not supported";
  866. consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  867. }
  868. return false;
  869. }
  870. ++ecnt;
  871. }
  872. // Check for supported stages
  873. if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment &&
  874. stage != SpvExecutionModelGeometry &&
  875. stage != SpvExecutionModelGLCompute &&
  876. stage != SpvExecutionModelTessellationControl &&
  877. stage != SpvExecutionModelTessellationEvaluation &&
  878. stage != SpvExecutionModelRayGenerationNV &&
  879. stage != SpvExecutionModelIntersectionNV &&
  880. stage != SpvExecutionModelAnyHitNV &&
  881. stage != SpvExecutionModelClosestHitNV &&
  882. stage != SpvExecutionModelMissNV &&
  883. stage != SpvExecutionModelCallableNV) {
  884. if (consumer()) {
  885. std::string message = "Stage not supported by instrumentation";
  886. consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  887. }
  888. return false;
  889. }
  890. // Add together the roots of all entry points
  891. std::queue<uint32_t> roots;
  892. for (auto& e : get_module()->entry_points()) {
  893. roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
  894. }
  895. bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage);
  896. return modified;
  897. }
  898. void InstrumentPass::InitializeInstrument() {
  899. output_buffer_id_ = 0;
  900. output_buffer_ptr_id_ = 0;
  901. input_buffer_ptr_id_ = 0;
  902. input_buffer_id_ = 0;
  903. float_id_ = 0;
  904. v4float_id_ = 0;
  905. uint_id_ = 0;
  906. uint64_id_ = 0;
  907. uint8_id_ = 0;
  908. v4uint_id_ = 0;
  909. v3uint_id_ = 0;
  910. bool_id_ = 0;
  911. void_id_ = 0;
  912. storage_buffer_ext_defined_ = false;
  913. uint32_rarr_ty_ = nullptr;
  914. uint64_rarr_ty_ = nullptr;
  915. // clear collections
  916. id2function_.clear();
  917. id2block_.clear();
  918. // clear maps
  919. param2input_func_id_.clear();
  920. param2output_func_id_.clear();
  921. // Initialize function and block maps.
  922. for (auto& fn : *get_module()) {
  923. id2function_[fn.result_id()] = &fn;
  924. for (auto& blk : fn) {
  925. id2block_[blk.id()] = &blk;
  926. }
  927. }
  928. // Remember original instruction offsets
  929. uint32_t module_offset = 0;
  930. Module* module = get_module();
  931. for (auto& i : context()->capabilities()) {
  932. (void)i;
  933. ++module_offset;
  934. }
  935. for (auto& i : module->extensions()) {
  936. (void)i;
  937. ++module_offset;
  938. }
  939. for (auto& i : module->ext_inst_imports()) {
  940. (void)i;
  941. ++module_offset;
  942. }
  943. ++module_offset; // memory_model
  944. for (auto& i : module->entry_points()) {
  945. (void)i;
  946. ++module_offset;
  947. }
  948. for (auto& i : module->execution_modes()) {
  949. (void)i;
  950. ++module_offset;
  951. }
  952. for (auto& i : module->debugs1()) {
  953. (void)i;
  954. ++module_offset;
  955. }
  956. for (auto& i : module->debugs2()) {
  957. (void)i;
  958. ++module_offset;
  959. }
  960. for (auto& i : module->debugs3()) {
  961. (void)i;
  962. ++module_offset;
  963. }
  964. for (auto& i : module->ext_inst_debuginfo()) {
  965. (void)i;
  966. ++module_offset;
  967. }
  968. for (auto& i : module->annotations()) {
  969. (void)i;
  970. ++module_offset;
  971. }
  972. for (auto& i : module->types_values()) {
  973. module_offset += 1;
  974. module_offset += static_cast<uint32_t>(i.dbg_line_insts().size());
  975. }
  976. auto curr_fn = get_module()->begin();
  977. for (; curr_fn != get_module()->end(); ++curr_fn) {
  978. // Count function instruction
  979. module_offset += 1;
  980. curr_fn->ForEachParam(
  981. [&module_offset](const Instruction*) { module_offset += 1; }, true);
  982. for (auto& blk : *curr_fn) {
  983. // Count label
  984. module_offset += 1;
  985. for (auto& inst : blk) {
  986. module_offset += static_cast<uint32_t>(inst.dbg_line_insts().size());
  987. uid2offset_[inst.unique_id()] = module_offset;
  988. module_offset += 1;
  989. }
  990. }
  991. // Count function end instruction
  992. module_offset += 1;
  993. }
  994. }
  995. } // namespace opt
  996. } // namespace spvtools