inline_pass.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. // Copyright (c) 2017 The Khronos Group Inc.
  2. // Copyright (c) 2017 Valve Corporation
  3. // Copyright (c) 2017 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 "source/opt/inline_pass.h"
  17. #include <unordered_set>
  18. #include <utility>
  19. #include "source/cfa.h"
  20. #include "source/opt/reflect.h"
  21. #include "source/util/make_unique.h"
  22. namespace spvtools {
  23. namespace opt {
  24. namespace {
  25. // Indices of operands in SPIR-V instructions
  26. constexpr int kSpvFunctionCallFunctionId = 2;
  27. constexpr int kSpvFunctionCallArgumentId = 3;
  28. constexpr int kSpvReturnValueId = 0;
  29. constexpr int kSpvDebugDeclareVarInIdx = 3;
  30. constexpr int kSpvAccessChainBaseInIdx = 0;
  31. } // namespace
  32. uint32_t InlinePass::AddPointerToType(uint32_t type_id,
  33. spv::StorageClass storage_class) {
  34. uint32_t resultId = context()->TakeNextId();
  35. if (resultId == 0) {
  36. return resultId;
  37. }
  38. std::unique_ptr<Instruction> type_inst(
  39. new Instruction(context(), spv::Op::OpTypePointer, 0, resultId,
  40. {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
  41. {uint32_t(storage_class)}},
  42. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {type_id}}}));
  43. context()->AddType(std::move(type_inst));
  44. analysis::Type* pointeeTy;
  45. std::unique_ptr<analysis::Pointer> pointerTy;
  46. std::tie(pointeeTy, pointerTy) =
  47. context()->get_type_mgr()->GetTypeAndPointerType(
  48. type_id, spv::StorageClass::Function);
  49. context()->get_type_mgr()->RegisterType(resultId, *pointerTy);
  50. return resultId;
  51. }
  52. void InlinePass::AddBranch(uint32_t label_id,
  53. std::unique_ptr<BasicBlock>* block_ptr) {
  54. std::unique_ptr<Instruction> newBranch(
  55. new Instruction(context(), spv::Op::OpBranch, 0, 0,
  56. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
  57. (*block_ptr)->AddInstruction(std::move(newBranch));
  58. }
  59. void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
  60. uint32_t false_id,
  61. std::unique_ptr<BasicBlock>* block_ptr) {
  62. std::unique_ptr<Instruction> newBranch(
  63. new Instruction(context(), spv::Op::OpBranchConditional, 0, 0,
  64. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
  65. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
  66. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
  67. (*block_ptr)->AddInstruction(std::move(newBranch));
  68. }
  69. void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
  70. std::unique_ptr<BasicBlock>* block_ptr) {
  71. std::unique_ptr<Instruction> newLoopMerge(new Instruction(
  72. context(), spv::Op::OpLoopMerge, 0, 0,
  73. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
  74. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
  75. {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {0}}}));
  76. (*block_ptr)->AddInstruction(std::move(newLoopMerge));
  77. }
  78. void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
  79. std::unique_ptr<BasicBlock>* block_ptr,
  80. const Instruction* line_inst,
  81. const DebugScope& dbg_scope) {
  82. std::unique_ptr<Instruction> newStore(
  83. new Instruction(context(), spv::Op::OpStore, 0, 0,
  84. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
  85. {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
  86. if (line_inst != nullptr) {
  87. newStore->AddDebugLine(line_inst);
  88. }
  89. newStore->SetDebugScope(dbg_scope);
  90. (*block_ptr)->AddInstruction(std::move(newStore));
  91. }
  92. void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
  93. std::unique_ptr<BasicBlock>* block_ptr,
  94. const Instruction* line_inst,
  95. const DebugScope& dbg_scope) {
  96. std::unique_ptr<Instruction> newLoad(
  97. new Instruction(context(), spv::Op::OpLoad, type_id, resultId,
  98. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}}));
  99. if (line_inst != nullptr) {
  100. newLoad->AddDebugLine(line_inst);
  101. }
  102. newLoad->SetDebugScope(dbg_scope);
  103. (*block_ptr)->AddInstruction(std::move(newLoad));
  104. }
  105. std::unique_ptr<Instruction> InlinePass::NewLabel(uint32_t label_id) {
  106. std::unique_ptr<Instruction> newLabel(
  107. new Instruction(context(), spv::Op::OpLabel, 0, label_id, {}));
  108. return newLabel;
  109. }
  110. uint32_t InlinePass::GetFalseId() {
  111. if (false_id_ != 0) return false_id_;
  112. false_id_ = get_module()->GetGlobalValue(spv::Op::OpConstantFalse);
  113. if (false_id_ != 0) return false_id_;
  114. uint32_t boolId = get_module()->GetGlobalValue(spv::Op::OpTypeBool);
  115. if (boolId == 0) {
  116. boolId = context()->TakeNextId();
  117. if (boolId == 0) {
  118. return 0;
  119. }
  120. get_module()->AddGlobalValue(spv::Op::OpTypeBool, boolId, 0);
  121. }
  122. false_id_ = context()->TakeNextId();
  123. if (false_id_ == 0) {
  124. return 0;
  125. }
  126. get_module()->AddGlobalValue(spv::Op::OpConstantFalse, false_id_, boolId);
  127. return false_id_;
  128. }
  129. void InlinePass::MapParams(
  130. Function* calleeFn, BasicBlock::iterator call_inst_itr,
  131. std::unordered_map<uint32_t, uint32_t>* callee2caller) {
  132. int param_idx = 0;
  133. calleeFn->ForEachParam(
  134. [&call_inst_itr, &param_idx, &callee2caller](const Instruction* cpi) {
  135. const uint32_t pid = cpi->result_id();
  136. (*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand(
  137. kSpvFunctionCallArgumentId + param_idx);
  138. ++param_idx;
  139. });
  140. }
  141. bool InlinePass::CloneAndMapLocals(
  142. Function* calleeFn, std::vector<std::unique_ptr<Instruction>>* new_vars,
  143. std::unordered_map<uint32_t, uint32_t>* callee2caller,
  144. analysis::DebugInlinedAtContext* inlined_at_ctx) {
  145. auto callee_block_itr = calleeFn->begin();
  146. auto callee_var_itr = callee_block_itr->begin();
  147. while (callee_var_itr->opcode() == spv::Op::OpVariable ||
  148. callee_var_itr->GetCommonDebugOpcode() ==
  149. CommonDebugInfoDebugDeclare) {
  150. if (callee_var_itr->opcode() != spv::Op::OpVariable) {
  151. ++callee_var_itr;
  152. continue;
  153. }
  154. std::unique_ptr<Instruction> var_inst(callee_var_itr->Clone(context()));
  155. uint32_t newId = context()->TakeNextId();
  156. if (newId == 0) {
  157. return false;
  158. }
  159. get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId);
  160. var_inst->SetResultId(newId);
  161. var_inst->UpdateDebugInlinedAt(
  162. context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
  163. callee_var_itr->GetDebugInlinedAt(), inlined_at_ctx));
  164. (*callee2caller)[callee_var_itr->result_id()] = newId;
  165. new_vars->push_back(std::move(var_inst));
  166. ++callee_var_itr;
  167. }
  168. return true;
  169. }
  170. uint32_t InlinePass::CreateReturnVar(
  171. Function* calleeFn, std::vector<std::unique_ptr<Instruction>>* new_vars) {
  172. uint32_t returnVarId = 0;
  173. const uint32_t calleeTypeId = calleeFn->type_id();
  174. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  175. assert(type_mgr->GetType(calleeTypeId)->AsVoid() == nullptr &&
  176. "Cannot create a return variable of type void.");
  177. // Find or create ptr to callee return type.
  178. uint32_t returnVarTypeId =
  179. type_mgr->FindPointerToType(calleeTypeId, spv::StorageClass::Function);
  180. if (returnVarTypeId == 0) {
  181. returnVarTypeId =
  182. AddPointerToType(calleeTypeId, spv::StorageClass::Function);
  183. if (returnVarTypeId == 0) {
  184. return 0;
  185. }
  186. }
  187. // Add return var to new function scope variables.
  188. returnVarId = context()->TakeNextId();
  189. if (returnVarId == 0) {
  190. return 0;
  191. }
  192. std::unique_ptr<Instruction> var_inst(new Instruction(
  193. context(), spv::Op::OpVariable, returnVarTypeId, returnVarId,
  194. {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
  195. {(uint32_t)spv::StorageClass::Function}}}));
  196. new_vars->push_back(std::move(var_inst));
  197. get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId);
  198. // Decorate the return var with AliasedPointer if the storage class of the
  199. // pointee type is PhysicalStorageBuffer.
  200. auto const pointee_type =
  201. type_mgr->GetType(returnVarTypeId)->AsPointer()->pointee_type();
  202. if (pointee_type->AsPointer() != nullptr) {
  203. if (pointee_type->AsPointer()->storage_class() ==
  204. spv::StorageClass::PhysicalStorageBuffer) {
  205. get_decoration_mgr()->AddDecoration(
  206. returnVarId, uint32_t(spv::Decoration::AliasedPointer));
  207. }
  208. }
  209. return returnVarId;
  210. }
  211. bool InlinePass::IsSameBlockOp(const Instruction* inst) const {
  212. return inst->opcode() == spv::Op::OpSampledImage ||
  213. inst->opcode() == spv::Op::OpImage;
  214. }
  215. bool InlinePass::CloneSameBlockOps(
  216. std::unique_ptr<Instruction>* inst,
  217. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  218. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  219. std::unique_ptr<BasicBlock>* block_ptr) {
  220. return (*inst)->WhileEachInId([&postCallSB, &preCallSB, &block_ptr,
  221. this](uint32_t* iid) {
  222. const auto mapItr = (*postCallSB).find(*iid);
  223. if (mapItr == (*postCallSB).end()) {
  224. const auto mapItr2 = (*preCallSB).find(*iid);
  225. if (mapItr2 != (*preCallSB).end()) {
  226. // Clone pre-call same-block ops, map result id.
  227. const Instruction* inInst = mapItr2->second;
  228. std::unique_ptr<Instruction> sb_inst(inInst->Clone(context()));
  229. if (!CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr)) {
  230. return false;
  231. }
  232. const uint32_t rid = sb_inst->result_id();
  233. const uint32_t nid = context()->TakeNextId();
  234. if (nid == 0) {
  235. return false;
  236. }
  237. get_decoration_mgr()->CloneDecorations(rid, nid);
  238. sb_inst->SetResultId(nid);
  239. (*postCallSB)[rid] = nid;
  240. *iid = nid;
  241. (*block_ptr)->AddInstruction(std::move(sb_inst));
  242. }
  243. } else {
  244. // Reset same-block op operand.
  245. *iid = mapItr->second;
  246. }
  247. return true;
  248. });
  249. }
  250. void InlinePass::MoveInstsBeforeEntryBlock(
  251. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  252. BasicBlock* new_blk_ptr, BasicBlock::iterator call_inst_itr,
  253. UptrVectorIterator<BasicBlock> call_block_itr) {
  254. for (auto cii = call_block_itr->begin(); cii != call_inst_itr;
  255. cii = call_block_itr->begin()) {
  256. Instruction* inst = &*cii;
  257. inst->RemoveFromList();
  258. std::unique_ptr<Instruction> cp_inst(inst);
  259. // Remember same-block ops for possible regeneration.
  260. if (IsSameBlockOp(&*cp_inst)) {
  261. auto* sb_inst_ptr = cp_inst.get();
  262. (*preCallSB)[cp_inst->result_id()] = sb_inst_ptr;
  263. }
  264. new_blk_ptr->AddInstruction(std::move(cp_inst));
  265. }
  266. }
  267. std::unique_ptr<BasicBlock> InlinePass::AddGuardBlock(
  268. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  269. std::unordered_map<uint32_t, uint32_t>* callee2caller,
  270. std::unique_ptr<BasicBlock> new_blk_ptr, uint32_t entry_blk_label_id) {
  271. const auto guard_block_id = context()->TakeNextId();
  272. if (guard_block_id == 0) {
  273. return nullptr;
  274. }
  275. AddBranch(guard_block_id, &new_blk_ptr);
  276. new_blocks->push_back(std::move(new_blk_ptr));
  277. // Start the next block.
  278. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(guard_block_id));
  279. // Reset the mapping of the callee's entry block to point to
  280. // the guard block. Do this so we can fix up phis later on to
  281. // satisfy dominance.
  282. (*callee2caller)[entry_blk_label_id] = guard_block_id;
  283. return new_blk_ptr;
  284. }
  285. InstructionList::iterator InlinePass::AddStoresForVariableInitializers(
  286. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  287. analysis::DebugInlinedAtContext* inlined_at_ctx,
  288. std::unique_ptr<BasicBlock>* new_blk_ptr,
  289. UptrVectorIterator<BasicBlock> callee_first_block_itr) {
  290. auto callee_itr = callee_first_block_itr->begin();
  291. while (callee_itr->opcode() == spv::Op::OpVariable ||
  292. callee_itr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
  293. if (callee_itr->opcode() == spv::Op::OpVariable &&
  294. callee_itr->NumInOperands() == 2) {
  295. assert(callee2caller.count(callee_itr->result_id()) &&
  296. "Expected the variable to have already been mapped.");
  297. uint32_t new_var_id = callee2caller.at(callee_itr->result_id());
  298. // The initializer must be a constant or global value. No mapped
  299. // should be used.
  300. uint32_t val_id = callee_itr->GetSingleWordInOperand(1);
  301. AddStore(new_var_id, val_id, new_blk_ptr, callee_itr->dbg_line_inst(),
  302. context()->get_debug_info_mgr()->BuildDebugScope(
  303. callee_itr->GetDebugScope(), inlined_at_ctx));
  304. }
  305. if (callee_itr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
  306. InlineSingleInstruction(
  307. callee2caller, new_blk_ptr->get(), &*callee_itr,
  308. context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
  309. callee_itr->GetDebugScope().GetInlinedAt(), inlined_at_ctx));
  310. }
  311. ++callee_itr;
  312. }
  313. return callee_itr;
  314. }
  315. bool InlinePass::InlineSingleInstruction(
  316. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  317. BasicBlock* new_blk_ptr, const Instruction* inst, uint32_t dbg_inlined_at) {
  318. // If we have return, it must be at the end of the callee. We will handle
  319. // it at the end.
  320. if (inst->opcode() == spv::Op::OpReturnValue ||
  321. inst->opcode() == spv::Op::OpReturn)
  322. return true;
  323. // Copy callee instruction and remap all input Ids.
  324. std::unique_ptr<Instruction> cp_inst(inst->Clone(context()));
  325. cp_inst->ForEachInId([&callee2caller](uint32_t* iid) {
  326. const auto mapItr = callee2caller.find(*iid);
  327. if (mapItr != callee2caller.end()) {
  328. *iid = mapItr->second;
  329. }
  330. });
  331. // If result id is non-zero, remap it.
  332. const uint32_t rid = cp_inst->result_id();
  333. if (rid != 0) {
  334. const auto mapItr = callee2caller.find(rid);
  335. if (mapItr == callee2caller.end()) {
  336. return false;
  337. }
  338. uint32_t nid = mapItr->second;
  339. cp_inst->SetResultId(nid);
  340. get_decoration_mgr()->CloneDecorations(rid, nid);
  341. }
  342. cp_inst->UpdateDebugInlinedAt(dbg_inlined_at);
  343. new_blk_ptr->AddInstruction(std::move(cp_inst));
  344. return true;
  345. }
  346. std::unique_ptr<BasicBlock> InlinePass::InlineReturn(
  347. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  348. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  349. std::unique_ptr<BasicBlock> new_blk_ptr,
  350. analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
  351. const Instruction* inst, uint32_t returnVarId) {
  352. // Store return value to return variable.
  353. if (inst->opcode() == spv::Op::OpReturnValue) {
  354. assert(returnVarId != 0);
  355. uint32_t valId = inst->GetInOperand(kSpvReturnValueId).words[0];
  356. const auto mapItr = callee2caller.find(valId);
  357. if (mapItr != callee2caller.end()) {
  358. valId = mapItr->second;
  359. }
  360. AddStore(returnVarId, valId, &new_blk_ptr, inst->dbg_line_inst(),
  361. context()->get_debug_info_mgr()->BuildDebugScope(
  362. inst->GetDebugScope(), inlined_at_ctx));
  363. }
  364. uint32_t returnLabelId = 0;
  365. for (auto callee_block_itr = calleeFn->begin();
  366. callee_block_itr != calleeFn->end(); ++callee_block_itr) {
  367. if (spvOpcodeIsAbort(callee_block_itr->tail()->opcode())) {
  368. returnLabelId = context()->TakeNextId();
  369. break;
  370. }
  371. }
  372. if (returnLabelId == 0) return new_blk_ptr;
  373. if (inst->opcode() == spv::Op::OpReturn ||
  374. inst->opcode() == spv::Op::OpReturnValue)
  375. AddBranch(returnLabelId, &new_blk_ptr);
  376. new_blocks->push_back(std::move(new_blk_ptr));
  377. return MakeUnique<BasicBlock>(NewLabel(returnLabelId));
  378. }
  379. bool InlinePass::InlineEntryBlock(
  380. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  381. std::unique_ptr<BasicBlock>* new_blk_ptr,
  382. UptrVectorIterator<BasicBlock> callee_first_block,
  383. analysis::DebugInlinedAtContext* inlined_at_ctx) {
  384. auto callee_inst_itr = AddStoresForVariableInitializers(
  385. callee2caller, inlined_at_ctx, new_blk_ptr, callee_first_block);
  386. while (callee_inst_itr != callee_first_block->end()) {
  387. // Don't inline function definition links, the calling function is not a
  388. // definition.
  389. if (callee_inst_itr->GetShader100DebugOpcode() ==
  390. NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
  391. ++callee_inst_itr;
  392. continue;
  393. }
  394. if (!InlineSingleInstruction(
  395. callee2caller, new_blk_ptr->get(), &*callee_inst_itr,
  396. context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
  397. callee_inst_itr->GetDebugScope().GetInlinedAt(),
  398. inlined_at_ctx))) {
  399. return false;
  400. }
  401. ++callee_inst_itr;
  402. }
  403. return true;
  404. }
  405. std::unique_ptr<BasicBlock> InlinePass::InlineBasicBlocks(
  406. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  407. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  408. std::unique_ptr<BasicBlock> new_blk_ptr,
  409. analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn) {
  410. auto callee_block_itr = calleeFn->begin();
  411. ++callee_block_itr;
  412. while (callee_block_itr != calleeFn->end()) {
  413. new_blocks->push_back(std::move(new_blk_ptr));
  414. const auto mapItr =
  415. callee2caller.find(callee_block_itr->GetLabelInst()->result_id());
  416. if (mapItr == callee2caller.end()) return nullptr;
  417. new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(mapItr->second));
  418. auto tail_inst_itr = callee_block_itr->end();
  419. for (auto inst_itr = callee_block_itr->begin(); inst_itr != tail_inst_itr;
  420. ++inst_itr) {
  421. // Don't inline function definition links, the calling function is not a
  422. // definition
  423. if (inst_itr->GetShader100DebugOpcode() ==
  424. NonSemanticShaderDebugInfo100DebugFunctionDefinition)
  425. continue;
  426. if (!InlineSingleInstruction(
  427. callee2caller, new_blk_ptr.get(), &*inst_itr,
  428. context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
  429. inst_itr->GetDebugScope().GetInlinedAt(), inlined_at_ctx))) {
  430. return nullptr;
  431. }
  432. }
  433. ++callee_block_itr;
  434. }
  435. return new_blk_ptr;
  436. }
  437. bool InlinePass::MoveCallerInstsAfterFunctionCall(
  438. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  439. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  440. std::unique_ptr<BasicBlock>* new_blk_ptr,
  441. BasicBlock::iterator call_inst_itr, bool multiBlocks) {
  442. // Copy remaining instructions from caller block.
  443. for (Instruction* inst = call_inst_itr->NextNode(); inst;
  444. inst = call_inst_itr->NextNode()) {
  445. inst->RemoveFromList();
  446. std::unique_ptr<Instruction> cp_inst(inst);
  447. // If multiple blocks generated, regenerate any same-block
  448. // instruction that has not been seen in this last block.
  449. if (multiBlocks) {
  450. if (!CloneSameBlockOps(&cp_inst, postCallSB, preCallSB, new_blk_ptr)) {
  451. return false;
  452. }
  453. // Remember same-block ops in this block.
  454. if (IsSameBlockOp(&*cp_inst)) {
  455. const uint32_t rid = cp_inst->result_id();
  456. (*postCallSB)[rid] = rid;
  457. }
  458. }
  459. new_blk_ptr->get()->AddInstruction(std::move(cp_inst));
  460. }
  461. return true;
  462. }
  463. void InlinePass::MoveLoopMergeInstToFirstBlock(
  464. std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  465. // Move the OpLoopMerge from the last block back to the first, where
  466. // it belongs.
  467. auto& first = new_blocks->front();
  468. auto& last = new_blocks->back();
  469. assert(first != last);
  470. // Insert a modified copy of the loop merge into the first block.
  471. auto loop_merge_itr = last->tail();
  472. --loop_merge_itr;
  473. assert(loop_merge_itr->opcode() == spv::Op::OpLoopMerge);
  474. std::unique_ptr<Instruction> cp_inst(loop_merge_itr->Clone(context()));
  475. first->tail().InsertBefore(std::move(cp_inst));
  476. // Remove the loop merge from the last block.
  477. loop_merge_itr->RemoveFromList();
  478. delete &*loop_merge_itr;
  479. }
  480. void InlinePass::UpdateSingleBlockLoopContinueTarget(
  481. uint32_t new_id, std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  482. auto& header = new_blocks->front();
  483. auto* merge_inst = header->GetLoopMergeInst();
  484. // The back-edge block is split at the branch to create a new back-edge
  485. // block. The old block is modified to branch to the new block. The loop
  486. // merge instruction is updated to declare the new block as the continue
  487. // target. This has the effect of changing the loop from being a large
  488. // continue construct and an empty loop construct to being a loop with a loop
  489. // construct and a trivial continue construct. This change is made to satisfy
  490. // structural dominance.
  491. // Add the new basic block.
  492. std::unique_ptr<BasicBlock> new_block =
  493. MakeUnique<BasicBlock>(NewLabel(new_id));
  494. auto& old_backedge = new_blocks->back();
  495. auto old_branch = old_backedge->tail();
  496. // Move the old back edge into the new block.
  497. std::unique_ptr<Instruction> br(&*old_branch);
  498. new_block->AddInstruction(std::move(br));
  499. // Add a branch to the new block from the old back-edge block.
  500. AddBranch(new_id, &old_backedge);
  501. new_blocks->push_back(std::move(new_block));
  502. // Update the loop's continue target to the new block.
  503. merge_inst->SetInOperand(1u, {new_id});
  504. }
  505. bool InlinePass::GenInlineCode(
  506. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  507. std::vector<std::unique_ptr<Instruction>>* new_vars,
  508. BasicBlock::iterator call_inst_itr,
  509. UptrVectorIterator<BasicBlock> call_block_itr) {
  510. // Map from all ids in the callee to their equivalent id in the caller
  511. // as callee instructions are copied into caller.
  512. std::unordered_map<uint32_t, uint32_t> callee2caller;
  513. // Pre-call same-block insts
  514. std::unordered_map<uint32_t, Instruction*> preCallSB;
  515. // Post-call same-block op ids
  516. std::unordered_map<uint32_t, uint32_t> postCallSB;
  517. analysis::DebugInlinedAtContext inlined_at_ctx(&*call_inst_itr);
  518. // Invalidate the def-use chains. They are not kept up to date while
  519. // inlining. However, certain calls try to keep them up-to-date if they are
  520. // valid. These operations can fail.
  521. context()->InvalidateAnalyses(IRContext::kAnalysisDefUse);
  522. // If the caller is a loop header and the callee has multiple blocks, then the
  523. // normal inlining logic will place the OpLoopMerge in the last of several
  524. // blocks in the loop. Instead, it should be placed at the end of the first
  525. // block. We'll wait to move the OpLoopMerge until the end of the regular
  526. // inlining logic, and only if necessary.
  527. bool caller_is_loop_header = call_block_itr->GetLoopMergeInst() != nullptr;
  528. // Single-trip loop continue block
  529. std::unique_ptr<BasicBlock> single_trip_loop_cont_blk;
  530. Function* calleeFn = id2function_[call_inst_itr->GetSingleWordOperand(
  531. kSpvFunctionCallFunctionId)];
  532. // Map parameters to actual arguments.
  533. MapParams(calleeFn, call_inst_itr, &callee2caller);
  534. // Define caller local variables for all callee variables and create map to
  535. // them.
  536. if (!CloneAndMapLocals(calleeFn, new_vars, &callee2caller, &inlined_at_ctx)) {
  537. return false;
  538. }
  539. // First block needs to use label of original block
  540. // but map callee label in case of phi reference.
  541. uint32_t entry_blk_label_id = calleeFn->begin()->GetLabelInst()->result_id();
  542. callee2caller[entry_blk_label_id] = call_block_itr->id();
  543. std::unique_ptr<BasicBlock> new_blk_ptr =
  544. MakeUnique<BasicBlock>(NewLabel(call_block_itr->id()));
  545. // Move instructions of original caller block up to call instruction.
  546. MoveInstsBeforeEntryBlock(&preCallSB, new_blk_ptr.get(), call_inst_itr,
  547. call_block_itr);
  548. if (caller_is_loop_header &&
  549. (*(calleeFn->begin())).GetMergeInst() != nullptr) {
  550. // We can't place both the caller's merge instruction and
  551. // another merge instruction in the same block. So split the
  552. // calling block. Insert an unconditional branch to a new guard
  553. // block. Later, once we know the ID of the last block, we
  554. // will move the caller's OpLoopMerge from the last generated
  555. // block into the first block. We also wait to avoid
  556. // invalidating various iterators.
  557. new_blk_ptr = AddGuardBlock(new_blocks, &callee2caller,
  558. std::move(new_blk_ptr), entry_blk_label_id);
  559. if (new_blk_ptr == nullptr) return false;
  560. }
  561. // Create return var if needed.
  562. const uint32_t calleeTypeId = calleeFn->type_id();
  563. uint32_t returnVarId = 0;
  564. analysis::Type* calleeType = context()->get_type_mgr()->GetType(calleeTypeId);
  565. if (calleeType->AsVoid() == nullptr) {
  566. returnVarId = CreateReturnVar(calleeFn, new_vars);
  567. if (returnVarId == 0) {
  568. return false;
  569. }
  570. }
  571. calleeFn->WhileEachInst([&callee2caller, this](const Instruction* cpi) {
  572. // Create set of callee result ids. Used to detect forward references
  573. const uint32_t rid = cpi->result_id();
  574. if (rid != 0 && callee2caller.find(rid) == callee2caller.end()) {
  575. const uint32_t nid = context()->TakeNextId();
  576. if (nid == 0) return false;
  577. callee2caller[rid] = nid;
  578. }
  579. return true;
  580. });
  581. // Inline DebugClare instructions in the callee's header.
  582. calleeFn->ForEachDebugInstructionsInHeader(
  583. [&new_blk_ptr, &callee2caller, &inlined_at_ctx, this](Instruction* inst) {
  584. InlineSingleInstruction(
  585. callee2caller, new_blk_ptr.get(), inst,
  586. context()->get_debug_info_mgr()->BuildDebugInlinedAtChain(
  587. inst->GetDebugScope().GetInlinedAt(), &inlined_at_ctx));
  588. });
  589. // Inline the entry block of the callee function.
  590. if (!InlineEntryBlock(callee2caller, &new_blk_ptr, calleeFn->begin(),
  591. &inlined_at_ctx)) {
  592. return false;
  593. }
  594. // Inline blocks of the callee function other than the entry block.
  595. new_blk_ptr =
  596. InlineBasicBlocks(new_blocks, callee2caller, std::move(new_blk_ptr),
  597. &inlined_at_ctx, calleeFn);
  598. if (new_blk_ptr == nullptr) return false;
  599. new_blk_ptr = InlineReturn(callee2caller, new_blocks, std::move(new_blk_ptr),
  600. &inlined_at_ctx, calleeFn,
  601. &*(calleeFn->tail()->tail()), returnVarId);
  602. // Load return value into result id of call, if it exists.
  603. if (returnVarId != 0) {
  604. const uint32_t resId = call_inst_itr->result_id();
  605. assert(resId != 0);
  606. AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr,
  607. call_inst_itr->dbg_line_inst(), call_inst_itr->GetDebugScope());
  608. }
  609. // Move instructions of original caller block after call instruction.
  610. if (!MoveCallerInstsAfterFunctionCall(&preCallSB, &postCallSB, &new_blk_ptr,
  611. call_inst_itr,
  612. calleeFn->begin() != calleeFn->end()))
  613. return false;
  614. // Finalize inline code.
  615. new_blocks->push_back(std::move(new_blk_ptr));
  616. if (caller_is_loop_header && (new_blocks->size() > 1)) {
  617. MoveLoopMergeInstToFirstBlock(new_blocks);
  618. // If the loop was a single basic block previously, update it's structure.
  619. auto& header = new_blocks->front();
  620. auto* merge_inst = header->GetLoopMergeInst();
  621. if (merge_inst->GetSingleWordInOperand(1u) == header->id()) {
  622. auto new_id = context()->TakeNextId();
  623. if (new_id == 0) return false;
  624. UpdateSingleBlockLoopContinueTarget(new_id, new_blocks);
  625. }
  626. }
  627. // Update block map given replacement blocks.
  628. for (auto& blk : *new_blocks) {
  629. id2block_[blk->id()] = &*blk;
  630. }
  631. // We need to kill the name and decorations for the call, which will be
  632. // deleted.
  633. context()->KillNamesAndDecorates(&*call_inst_itr);
  634. return true;
  635. }
  636. bool InlinePass::IsInlinableFunctionCall(const Instruction* inst) {
  637. if (inst->opcode() != spv::Op::OpFunctionCall) return false;
  638. const uint32_t calleeFnId =
  639. inst->GetSingleWordOperand(kSpvFunctionCallFunctionId);
  640. const auto ci = inlinable_.find(calleeFnId);
  641. if (ci == inlinable_.cend()) return false;
  642. if (early_return_funcs_.find(calleeFnId) != early_return_funcs_.end()) {
  643. // We rely on the merge-return pass to handle the early return case
  644. // in advance.
  645. std::string message =
  646. "The function '" + id2function_[calleeFnId]->DefInst().PrettyPrint() +
  647. "' could not be inlined because the return instruction "
  648. "is not at the end of the function. This could be fixed by "
  649. "running merge-return before inlining.";
  650. consumer()(SPV_MSG_WARNING, "", {0, 0, 0}, message.c_str());
  651. return false;
  652. }
  653. return true;
  654. }
  655. void InlinePass::UpdateSucceedingPhis(
  656. std::vector<std::unique_ptr<BasicBlock>>& new_blocks) {
  657. const auto firstBlk = new_blocks.begin();
  658. const auto lastBlk = new_blocks.end() - 1;
  659. const uint32_t firstId = (*firstBlk)->id();
  660. const uint32_t lastId = (*lastBlk)->id();
  661. const BasicBlock& const_last_block = *lastBlk->get();
  662. const_last_block.ForEachSuccessorLabel(
  663. [&firstId, &lastId, this](const uint32_t succ) {
  664. BasicBlock* sbp = this->id2block_[succ];
  665. sbp->ForEachPhiInst([&firstId, &lastId](Instruction* phi) {
  666. phi->ForEachInId([&firstId, &lastId](uint32_t* id) {
  667. if (*id == firstId) *id = lastId;
  668. });
  669. });
  670. });
  671. }
  672. bool InlinePass::HasNoReturnInLoop(Function* func) {
  673. // If control not structured, do not do loop/return analysis
  674. // TODO: Analyze returns in non-structured control flow
  675. if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
  676. return false;
  677. const auto structured_analysis = context()->GetStructuredCFGAnalysis();
  678. // Search for returns in structured construct.
  679. bool return_in_loop = false;
  680. for (auto& blk : *func) {
  681. auto terminal_ii = blk.cend();
  682. --terminal_ii;
  683. if (spvOpcodeIsReturn(terminal_ii->opcode()) &&
  684. structured_analysis->ContainingLoop(blk.id()) != 0) {
  685. return_in_loop = true;
  686. break;
  687. }
  688. }
  689. return !return_in_loop;
  690. }
  691. void InlinePass::AnalyzeReturns(Function* func) {
  692. // Analyze functions without a return in loop.
  693. if (HasNoReturnInLoop(func)) {
  694. no_return_in_loop_.insert(func->result_id());
  695. }
  696. // Analyze functions with a return before its tail basic block.
  697. for (auto& blk : *func) {
  698. auto terminal_ii = blk.cend();
  699. --terminal_ii;
  700. if (spvOpcodeIsReturn(terminal_ii->opcode()) && &blk != func->tail()) {
  701. early_return_funcs_.insert(func->result_id());
  702. break;
  703. }
  704. }
  705. }
  706. bool InlinePass::IsInlinableFunction(Function* func) {
  707. // We can only inline a function if it has blocks.
  708. if (func->cbegin() == func->cend()) return false;
  709. // Do not inline functions with DontInline flag.
  710. if (func->control_mask() & uint32_t(spv::FunctionControlMask::DontInline)) {
  711. return false;
  712. }
  713. // Do not inline functions with returns in loops. Currently early return
  714. // functions are inlined by wrapping them in a one trip loop and implementing
  715. // the returns as a branch to the loop's merge block. However, this can only
  716. // done validly if the return was not in a loop in the original function.
  717. // Also remember functions with multiple (early) returns.
  718. AnalyzeReturns(func);
  719. if (no_return_in_loop_.find(func->result_id()) == no_return_in_loop_.cend()) {
  720. return false;
  721. }
  722. if (func->IsRecursive()) {
  723. return false;
  724. }
  725. // Do not inline functions with an abort instruction if they are called from a
  726. // continue construct. If it is inlined into a continue construct the backedge
  727. // will no longer post-dominate the continue target, which is invalid. An
  728. // `OpUnreachable` is acceptable because it will not change post-dominance if
  729. // it is statically unreachable.
  730. bool func_is_called_from_continue =
  731. funcs_called_from_continue_.count(func->result_id()) != 0;
  732. if (func_is_called_from_continue && ContainsAbortOtherThanUnreachable(func)) {
  733. return false;
  734. }
  735. return true;
  736. }
  737. bool InlinePass::ContainsAbortOtherThanUnreachable(Function* func) const {
  738. return !func->WhileEachInst([](Instruction* inst) {
  739. return inst->opcode() == spv::Op::OpUnreachable ||
  740. !spvOpcodeIsAbort(inst->opcode());
  741. });
  742. }
  743. void InlinePass::InitializeInline() {
  744. false_id_ = 0;
  745. // clear collections
  746. id2function_.clear();
  747. id2block_.clear();
  748. inlinable_.clear();
  749. no_return_in_loop_.clear();
  750. early_return_funcs_.clear();
  751. funcs_called_from_continue_ =
  752. context()->GetStructuredCFGAnalysis()->FindFuncsCalledFromContinue();
  753. for (auto& fn : *get_module()) {
  754. // Initialize function and block maps.
  755. id2function_[fn.result_id()] = &fn;
  756. for (auto& blk : fn) {
  757. id2block_[blk.id()] = &blk;
  758. }
  759. // Compute inlinability
  760. if (IsInlinableFunction(&fn)) inlinable_.insert(fn.result_id());
  761. }
  762. }
  763. InlinePass::InlinePass() {}
  764. void InlinePass::FixDebugDeclares(Function* func) {
  765. std::map<uint32_t, Instruction*> access_chains;
  766. std::vector<Instruction*> debug_declare_insts;
  767. func->ForEachInst([&access_chains, &debug_declare_insts](Instruction* inst) {
  768. if (inst->opcode() == spv::Op::OpAccessChain) {
  769. access_chains[inst->result_id()] = inst;
  770. }
  771. if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
  772. debug_declare_insts.push_back(inst);
  773. }
  774. });
  775. for (auto& inst : debug_declare_insts) {
  776. FixDebugDeclare(inst, access_chains);
  777. }
  778. }
  779. void InlinePass::FixDebugDeclare(
  780. Instruction* dbg_declare_inst,
  781. const std::map<uint32_t, Instruction*>& access_chains) {
  782. do {
  783. uint32_t var_id =
  784. dbg_declare_inst->GetSingleWordInOperand(kSpvDebugDeclareVarInIdx);
  785. // The def-use chains are not kept up to date while inlining, so we need to
  786. // get the variable by traversing the functions.
  787. auto it = access_chains.find(var_id);
  788. if (it == access_chains.end()) {
  789. return;
  790. }
  791. Instruction* access_chain = it->second;
  792. // If the variable id in the debug declare is an access chain, it is
  793. // invalid. it needs to be fixed up. The debug declare will be updated so
  794. // that its Var operand becomes the base of the access chain. The indexes of
  795. // the access chain are prepended before the indexes of the debug declare.
  796. std::vector<Operand> operands;
  797. for (int i = 0; i < kSpvDebugDeclareVarInIdx; i++) {
  798. operands.push_back(dbg_declare_inst->GetInOperand(i));
  799. }
  800. uint32_t access_chain_base =
  801. access_chain->GetSingleWordInOperand(kSpvAccessChainBaseInIdx);
  802. operands.push_back(Operand(SPV_OPERAND_TYPE_ID, {access_chain_base}));
  803. operands.push_back(
  804. dbg_declare_inst->GetInOperand(kSpvDebugDeclareVarInIdx + 1));
  805. for (uint32_t i = kSpvAccessChainBaseInIdx + 1;
  806. i < access_chain->NumInOperands(); ++i) {
  807. operands.push_back(access_chain->GetInOperand(i));
  808. }
  809. for (uint32_t i = kSpvDebugDeclareVarInIdx + 2;
  810. i < dbg_declare_inst->NumInOperands(); ++i) {
  811. operands.push_back(dbg_declare_inst->GetInOperand(i));
  812. }
  813. dbg_declare_inst->SetInOperands(std::move(operands));
  814. } while (true);
  815. }
  816. } // namespace opt
  817. } // namespace spvtools