instrument_pass.cpp 49 KB

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