instrument_pass.cpp 43 KB

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