instrument_pass.cpp 47 KB

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